|
|
1.1 root 1: /* ds_search.c - DSA search of the directory */
2:
3: #ifndef lint
4: static char *rcsid = "$Header: /f/osi/quipu/RCS/ds_search.c,v 7.5 90/07/09 14:45:51 mrose Exp $";
5: #endif
6:
7: /*
8: * $Header: /f/osi/quipu/RCS/ds_search.c,v 7.5 90/07/09 14:45:51 mrose Exp $
9: *
10: *
11: * $Log: ds_search.c,v $
12: * Revision 7.5 90/07/09 14:45:51 mrose
13: * sync
14: *
15: * Revision 7.4 90/04/18 08:49:46 mrose
16: * 6.2
17: *
18: * Revision 7.3 90/03/15 11:18:51 mrose
19: * quipu-sync
20: *
21: * Revision 7.2 90/01/11 23:55:52 mrose
22: * lint
23: *
24: * Revision 7.1 89/12/19 16:20:21 mrose
25: * sync
26: *
27: * Revision 7.0 89/11/23 22:17:16 mrose
28: * Release 6.0
29: *
30: */
31:
32: /*
33: * NOTICE
34: *
35: * Acquisition, use, and distribution of this module and related
36: * materials are subject to the restrictions of a license agreement.
37: * Consult the Preface in the User's Manual for the full terms of
38: * this agreement.
39: *
40: */
41:
42:
43: #include "quipu/util.h"
44: #include "quipu/entry.h"
45: #include "quipu/list.h" /* to get LSR # defs */
46: #include "quipu/ds_search.h"
47: #include "config.h"
48:
49: extern int encode_DAS_SearchArgumentData();
50: extern LLog * log_dsap;
51:
52: #ifndef NO_STATS
53: extern LLog * log_stat;
54: extern int dn_print ();
55: static PS filter_ps;
56: #endif
57:
58: static EntryInfo *filterentry();
59: static EntryInfo *filterchildren();
60: static test_avs();
61: static apply_search();
62: static substr_search();
63: static aux_substr_search();
64: static check_filteritem_presrch ();
65: static check_filter_presrch ();
66: static check_filterop_presrch ();
67: static check_filteritem ();
68: static check_filter ();
69: static check_filterop ();
70: struct ds_search_task * st_done ();
71: static search_refer ();
72: static do_alias ();
73: static do_base ();
74:
75: extern Entry database_root;
76: static int size;
77: static char qctx;
78: extern int search_level;
79: IFP approxfn();
80: IFP av_cmp_fn();
81:
82: #ifndef NBBY
83: #define NBBY 8
84: #endif
85: static int big_size = 0;
86: static int timelimit;
87: extern time_t time();
88: extern time_t timenow;
89: extern int admin_size;
90:
91: Attr_Sequence eis_select ();
92:
93: do_ds_search (arg, error, result, dnbind, target, local, refer, di_p,
94: dsp, quipu_ctx, tktime, entryonly)
95: register struct ds_search_arg *arg;
96: struct ds_search_result *result;
97: struct DSError *error;
98: DN dnbind;
99: DN target;
100: struct ds_search_task ** local,
101: ** refer;
102: struct di_block ** di_p;
103: char dsp;
104: char quipu_ctx;
105: time_t tktime;
106: char entryonly;
107: {
108: extern time_t admin_time;
109: int ismanager = FALSE;
110: int retval;
111: struct ds_search_task * st;
112: DN st_dn;
113:
114: qctx = quipu_ctx;
115:
116: if ((timelimit = tktime) == (time_t) 0) {
117: register int i;
118:
119: for (i = NBBY * sizeof timelimit - 1; i > 0; i--)
120: timelimit <<= 1, timelimit |= 1;
121: }
122:
123: if (!dsp)
124: ismanager = manager (dnbind);
125:
126: if (ismanager && big_size == 0) {
127: register int i;
128:
129: for (i = NBBY * sizeof big_size - 1; i > 0; i--)
130: big_size <<= 1, big_size |= 1;
131: }
132:
133: if (*local == NULL_ST) {
134: DLOG (log_dsap,LLOG_TRACE,("ds_search"));
135:
136: if (!dsp)
137: target = arg->sra_baseobject;
138:
139: /* Put local stuff straight into result structure (dangerous) */
140: result->srr_correlated = TRUE;
141: result->srr_un.srr_unit = (struct ds_search_unit *) calloc(1, sizeof(struct ds_search_unit));
142: result->CSR_cr = NULLCONTINUATIONREF;
143:
144: *local = st_alloc();
145: (*local)->st_baseobject = dn_cpy (target);
146: if ((*local)->st_entryonly = entryonly) /* assign */
147: (*local)->st_subset = SRA_BASEOBJECT;
148: else
149: (*local)->st_subset = arg->sra_subset;
150: (*local)->st_alias = NULLDN;
151: (*local)->st_save = NULL_ST;
152:
153: if (ismanager) {
154: if (((*local)->st_size = arg->sra_common.ca_servicecontrol.svc_sizelimit) == SVC_NOSIZELIMIT)
155: (*local)->st_size = big_size;
156: } else if (((*local)->st_size = MIN(admin_size,arg->sra_common.ca_servicecontrol.svc_sizelimit)) == SVC_NOSIZELIMIT)
157: (*local)->st_size = admin_size;
158:
159: (*local)->st_next = NULL_ST;
160:
161: result->CSR_entries = NULLENTRYINFO;
162:
163: #ifndef NO_STATS
164: if ((filter_ps = ps_alloc(str_open)) == NULLPS) {
165: st_comp_free (*local);
166: *local = NULL_ST;
167: return (DS_ERROR_LOCAL);
168: } if (str_setup (filter_ps,NULLCP, BUFSIZ, 0) == NOTOK) {
169: st_comp_free (*local);
170: *local = NULL_ST;
171: return (DS_ERROR_LOCAL);
172: }
173: #endif
174: if (check_filter_presrch (arg->sra_filter,error,target) != OK) {
175: #ifndef NO_STATS
176: ps_free (filter_ps);
177: #endif
178: st_comp_free (*local);
179: *local = NULL_ST;
180: return (DS_ERROR_REMOTE);
181: } else {
182: Entry entryptr;
183: #ifndef NO_STATS
184: *filter_ps->ps_ptr = 0;
185: switch ((*local)->st_subset) {
186: case SRA_ONELEVEL:
187: LLOG (log_stat, LLOG_TRACE, ("Search onelevel %s",filter_ps->ps_base));
188: break;
189: case SRA_WHOLESUBTREE:
190: LLOG (log_stat, LLOG_TRACE, ("Search subtree %s",filter_ps->ps_base));
191: break;
192: default:
193: LLOG (log_stat, LLOG_TRACE, ("Search base %s",filter_ps->ps_base));
194: break;
195: }
196: ps_free (filter_ps);
197: #endif
198: if ((arg->sra_subset == SRA_ONELEVEL) ||
199: (arg->sra_subset == SRA_WHOLESUBTREE))
200: {
201: switch(find_child_entry((*local)->st_baseobject,&(arg->sra_common),dnbind,NULLDNSEQ,FALSE,&(entryptr), error, di_p))
202: {
203: case DS_OK:
204: /* Filled out entryptr - carry on */
205: break;
206: case DS_CONTINUE:
207: /* Filled out di_p - what do we do with it ?? */
208: st_comp_free (*local);
209: *local = NULL_ST;
210: return(DS_CONTINUE);
211:
212: case DS_X500_ERROR:
213: /* Filled out error - what do we do with it ?? */
214: st_comp_free (*local);
215: *local = NULL_ST;
216: return(DS_X500_ERROR);
217: default:
218: /* SCREAM */
219: LLOG(log_dsap, LLOG_EXCEPTIONS, ("do_ds_search() - find_child_entry failed 1"));
220: st_comp_free (*local);
221: *local = NULL_ST;
222: return(DS_ERROR_LOCAL);
223: }
224: }
225: else
226: {
227: if ((arg->sra_subset == SRA_BASEOBJECT)
228: && ((*local)->st_baseobject == NULLDN)) {
229: error->dse_type = DSE_NAMEERROR;
230: error->ERR_NAME.DSE_na_problem = DSE_NA_NOSUCHOBJECT;
231: error->ERR_NAME.DSE_na_matched = NULLDN;
232: st_comp_free (*local);
233: *local = NULL_ST;
234: return (DS_ERROR_REMOTE);
235: }
236:
237: switch(find_entry((*local)->st_baseobject,&(arg->sra_common),dnbind,NULLDNSEQ,FALSE,&(entryptr), error, di_p))
238: {
239: case DS_OK:
240: /* Filled out entryptr - carry on */
241: break;
242: case DS_CONTINUE:
243: /* Filled out di_p - what do we do with it ?? */
244: st_comp_free (*local);
245: *local = NULL_ST;
246: return(DS_CONTINUE);
247:
248: case DS_X500_ERROR:
249: /* Filled out error - what do we do with it ?? */
250: st_comp_free (*local);
251: *local = NULL_ST;
252: return(DS_X500_ERROR);
253: default:
254: /* SCREAM */
255: LLOG(log_dsap, LLOG_EXCEPTIONS, ("do_ds_search() - find_entry failed 1"));
256: st_comp_free (*local);
257: *local = NULL_ST;
258: return(DS_ERROR_LOCAL);
259: }
260: }
261:
262: /* if no error and NOT SVC_OPT_DONTDEREFERENCEALIASES then */
263: /* the alias will have been derefeferenced -signified by */
264: /* NO_ERROR !!! */
265: if (error->dse_type == DSE_NOERROR) {
266: result->CSR_object = NULLDN;
267: result->CSR_common.cr_aliasdereferenced = FALSE;
268: } else {
269: result->CSR_common.cr_aliasdereferenced = TRUE;
270: result->CSR_object = get_copy_dn (entryptr);
271: }
272:
273: /* Strong authentication */
274: if ((retval = check_security_parms((caddr_t) arg,
275: encode_DAS_SearchArgumentData,
276: arg->sra_common.ca_security,
277: arg->sra_common.ca_sig, &dnbind)) != 0)
278: {
279: error->dse_type = DSE_SECURITYERROR;
280: error->ERR_SECURITY.DSE_sc_problem = retval;
281: st_comp_free (*local);
282: *local = NULL_ST;
283: return (DS_ERROR_REMOTE);
284: }
285:
286: /* one final check - will we allow such searched in this DSA ? */
287: if (arg->sra_subset == SRA_WHOLESUBTREE) {
288: DN dn;
289: int x = 0;
290: for (dn = (*local)->st_baseobject; dn!= NULLDN; dn=dn->dn_parent, x++)
291: ;
292: if ( x < search_level ) {
293: if ( ! ismanager ) {
294: /* Too high */
295: error->dse_type = DSE_SERVICEERROR;
296: error->ERR_SERVICE.DSE_sv_problem = DSE_SV_UNWILLINGTOPERFORM;
297: st_comp_free (*local);
298: *local = NULL_ST;
299: return (DS_ERROR_REMOTE);
300: }
301: }
302: if (entryptr->e_data != E_TYPE_CONSTRUCTOR) {
303: if ((*local)->st_baseobject != NULLDN) {
304: if ((result->CSR_entries = filterentry (arg,entryptr)) != NULLENTRYINFO)
305: (*local)->st_size--;
306: }
307: } else {
308: do_base (entryptr,local);
309: }
310: }
311: result->CSR_limitproblem = LSR_NOLIMITPROBLEM;
312: return (DS_SUSPEND); /* yup - we will take the search on */
313: }
314: } else {
315:
316: DN path;
317:
318: DLOG (log_dsap,LLOG_TRACE,("ds_search continuing"));
319:
320: size = (*local)->st_size;
321:
322: if ((*local)->st_alias == NULLDN)
323: path = (*local)->st_baseobject;
324: else
325: path = (*local)->st_alias;
326:
327: #ifdef HACK
328: /* Check we have not been here before... */
329: for ( st = (*local)->st_save; st != NULL_ST; st=st->st_next) {
330: if (st->st_alias == NULLDN)
331: st_dn = st->st_baseobject;
332: else
333: st_dn = st->st_alias;
334: if (dn_cmp (path, st_dn) == 0) {
335: LLOG (log_dsap,LLOG_TRACE,("local search - loop detected"));
336: break;
337: }
338: }
339: #else
340: st = NULL_ST;
341: #endif
342:
343: if ( (st == NULL_ST) &&
344: (apply_search (arg,error,result,local,refer,ismanager)) == NOTOK) {
345: st_free (local);
346: st_free (refer);
347: return (DS_ERROR_REMOTE);
348: }
349:
350: if (size < 0) {
351: st_free (local);
352: st_free (refer);
353: result -> CSR_limitproblem =
354: arg -> sra_common.ca_servicecontrol.svc_sizelimit
355: == SVC_NOSIZELIMIT
356: || arg -> sra_common.ca_servicecontrol.svc_sizelimit
357: > admin_size
358: ? LSR_ADMINSIZEEXCEEDED
359: : LSR_SIZELIMITEXCEEDED;
360: /* should fill out a POQ */
361: return (DS_OK);
362: }
363:
364: if (timelimit <= timenow) {
365: st_free (local);
366: st_free (refer);
367: result -> CSR_limitproblem =
368: arg -> sra_common.ca_servicecontrol.svc_timelimit
369: == SVC_NOTIMELIMIT
370: || arg -> sra_common.ca_servicecontrol.svc_timelimit
371: > admin_time
372: ? LSR_ADMINSIZEEXCEEDED
373: : LSR_TIMELIMITEXCEEDED;
374: /* should fill out a POQ */
375: return (DS_OK);
376: }
377:
378: if ((*local)->st_next == NULL_ST) {
379: st_free (local);
380: result->CSR_limitproblem = LSR_NOLIMITPROBLEM;
381: (void) dsa_search_control(arg,result);
382: return (DS_OK);
383: }
384:
385: (*local) = st_done(local);
386: (*local)->st_size = size;
387: return (DS_SUSPEND);
388: }
389:
390: }
391:
392: /*
393: * SEARCH TASK HANDLING
394: */
395:
396: st_comp_free (st)
397: struct ds_search_task *st;
398: {
399: dn_free (st->st_baseobject);
400: dn_free (st->st_alias);
401: if (st->st_save != NULL_ST)
402: st_free (&st->st_save);
403: free ((char *)st);
404: }
405:
406: st_free (st)
407: struct ds_search_task **st;
408: {
409: struct ds_search_task *next;
410:
411: for (; (*st) != NULL_ST; (*st) = next) {
412: next = (*st)->st_next;
413: st_comp_free (*st);
414: }
415: }
416:
417: struct ds_search_task * st_done (st)
418: struct ds_search_task **st;
419: {
420: struct ds_search_task *next;
421:
422: if ((next = (*st)->st_next) == NULL_ST)
423: return NULL_ST;
424: next->st_save = (*st);
425: (*st)->st_next = (*st)->st_save;
426: (*st)->st_save = NULL_ST;
427: return (next);
428: }
429:
430:
431:
432: /*
433: * CHECK FILTER BEFORE SEARCHING
434: */
435:
436:
437: static check_filter_presrch (fltr,error,dn)
438: register Filter fltr;
439: struct DSError *error;
440: DN dn;
441: {
442: DLOG (log_dsap,LLOG_DEBUG,("in check filter aux"));
443:
444: switch (fltr->flt_type) {
445: case FILTER_ITEM:
446: return (check_filteritem_presrch (&fltr->FUITEM,error,dn));
447: case FILTER_AND:
448: #ifndef NO_STATS
449: ps_print (filter_ps,"& ");
450: #endif
451: return(check_filterop_presrch (fltr->FUFILT,error,dn));
452: case FILTER_OR:
453: #ifndef NO_STATS
454: ps_print (filter_ps,"| ");
455: #endif
456: return(check_filterop_presrch (fltr->FUFILT,error,dn));
457: case FILTER_NOT:
458: #ifndef NO_STATS
459: ps_print (filter_ps,"! ");
460: #endif
461: return(check_filter_presrch (fltr->FUFILT,error,dn));
462: default:
463: LLOG (log_dsap,LLOG_EXCEPTIONS,("check_filter protocol error"));
464: error->dse_type = DSE_SERVICEERROR;
465: error->ERR_SERVICE.DSE_sv_problem = DSE_SV_UNWILLINGTOPERFORM;
466: return (NOTOK);
467: }
468: /* NOTREACHED */
469: }
470:
471: static check_filterop_presrch (fltr,error,dn)
472: register Filter fltr;
473: struct DSError * error;
474: DN dn;
475: {
476: register Filter ptr;
477: int i;
478:
479: #ifndef NO_STATS
480: ps_print (filter_ps,"(");
481: #endif
482: DLOG (log_dsap,LLOG_DEBUG,("in filter op aux"));
483: for (ptr=fltr; ptr!=NULLFILTER ; ptr=ptr->flt_next) {
484: i = check_filter_presrch (ptr,error,dn);
485: if (i != OK)
486: return (NOTOK);
487: }
488: #ifndef NO_STATS
489: ps_print (filter_ps,")");
490: #endif
491: return (OK);
492:
493: }
494:
495:
496: static check_filteritem_presrch (fitem,error,dn)
497: register struct filter_item *fitem;
498: struct DSError * error;
499: DN dn;
500: {
501: int av_acl, av_update, av_schema, av_syntax;
502: extern char chrcnv[];
503: extern char nochrcnv[];
504:
505: DLOG (log_dsap,LLOG_DEBUG,("search: check filter item aux"));
506: if (fitem == NULLFITEM) {
507: LLOG (log_dsap,LLOG_EXCEPTIONS,("check_filter_item protocol error (1)"));
508: error->dse_type = DSE_SERVICEERROR;
509: error->ERR_SERVICE.DSE_sv_problem = DSE_SV_UNWILLINGTOPERFORM;
510: return (NOTOK);
511: }
512:
513: switch ( fitem->fi_type) {
514: case FILTERITEM_APPROX:
515: if (fitem->UNAVA.ava_type == NULLTABLE_ATTR)
516: return (invalid_matching (fitem->UNAVA.ava_type,error,dn));
517:
518: if ( (fitem->fi_ifp = approxfn (fitem->UNAVA.ava_type->oa_syntax)) == NULLIFP)
519: /* approx not suported for this type */
520: /* so set it to equality */
521: fitem->fi_type = FILTERITEM_EQUALITY;
522: /* NO break - check equality is OK */
523:
524: case FILTERITEM_EQUALITY:
525: case FILTERITEM_GREATEROREQUAL:
526: case FILTERITEM_LESSOREQUAL:
527: if (fitem->UNAVA.ava_type == NULLTABLE_ATTR)
528: return (invalid_matching (fitem->UNAVA.ava_type,error,dn));
529:
530: if (fitem->fi_type != FILTERITEM_APPROX)
531: if ( (fitem->fi_ifp = av_cmp_fn (fitem->UNAVA.ava_type->oa_syntax)) == NULLIFP)
532: return (invalid_matching (fitem->UNAVA.ava_type,error,dn));
533:
534: av_acl = str2syntax ("acl");
535: av_schema = str2syntax ("schema");
536: av_update = str2syntax ("edbinfo");
537: av_syntax = fitem->UNAVA.ava_type->oa_syntax;
538:
539: if (( av_syntax == av_acl )
540: || (av_syntax == av_schema)
541: || (av_syntax == av_update))
542: return (invalid_matching (fitem->UNAVA.ava_type,error,dn));
543: break;
544: case FILTERITEM_SUBSTRINGS:
545: if (fitem->UNSUB.fi_sub_type == NULLTABLE_ATTR)
546: return (invalid_matching (fitem->UNSUB.fi_sub_type,error,dn));
547:
548: av_syntax = fitem->UNSUB.fi_sub_type->oa_syntax;
549:
550: if (! sub_string(av_syntax))
551: return (invalid_matching (fitem->UNSUB.fi_sub_type,error,dn));
552:
553: if ( case_exact_match (av_syntax) )
554: fitem->UNSUB.fi_sub_match = &nochrcnv[0];
555: else
556: fitem->UNSUB.fi_sub_match = &chrcnv[0];
557: case FILTERITEM_PRESENT:
558: break;
559: default:
560: LLOG (log_dsap,LLOG_EXCEPTIONS,("check_filter_item protocol error (2)"));
561: error->dse_type = DSE_SERVICEERROR;
562: error->ERR_SERVICE.DSE_sv_problem = DSE_SV_UNWILLINGTOPERFORM;
563: return (NOTOK);
564: }
565:
566: #ifndef NO_STATS
567: ps_print (filter_ps,"(");
568: switch ( fitem->fi_type) {
569: case FILTERITEM_APPROX:
570: AttrT_print (filter_ps,fitem->UNAVA.ava_type,EDBOUT);
571: ps_print (filter_ps,"~=");
572: AttrV_print (filter_ps,fitem->UNAVA.ava_value,EDBOUT);
573: break;
574: case FILTERITEM_EQUALITY:
575: AttrT_print (filter_ps,fitem->UNAVA.ava_type,EDBOUT);
576: ps_print (filter_ps,"=");
577: AttrV_print (filter_ps,fitem->UNAVA.ava_value,EDBOUT);
578: break;
579: case FILTERITEM_GREATEROREQUAL:
580: AttrT_print (filter_ps,fitem->UNAVA.ava_type,EDBOUT);
581: ps_print (filter_ps,">=");
582: AttrV_print (filter_ps,fitem->UNAVA.ava_value,EDBOUT);
583: break;
584: case FILTERITEM_LESSOREQUAL:
585: AttrT_print (filter_ps,fitem->UNAVA.ava_type,EDBOUT);
586: ps_print (filter_ps,"<=");
587: AttrV_print (filter_ps,fitem->UNAVA.ava_value,EDBOUT);
588: break;
589: case FILTERITEM_SUBSTRINGS:
590: AttrT_print (filter_ps,fitem->UNSUB.fi_sub_type,EDBOUT);
591: ps_print (filter_ps,"=");
592: avs_print_aux (filter_ps,fitem->UNSUB.fi_sub_initial,EDBOUT,"*");
593: ps_print (filter_ps,"*");
594: avs_print_aux (filter_ps,fitem->UNSUB.fi_sub_any,EDBOUT,"*");
595: ps_print (filter_ps,"*");
596: avs_print_aux (filter_ps,fitem->UNSUB.fi_sub_final,EDBOUT,"*");
597: break;
598: case FILTERITEM_PRESENT:
599: AttrT_print (filter_ps,fitem->UNTYPE,EDBOUT);
600: ps_print (filter_ps,"=*");
601: break;
602: }
603: ps_print (filter_ps,")");
604: #endif
605: return (OK);
606: }
607:
608: /* APPLY SEARCH TO ONE LEVEL */
609:
610: static apply_search (arg,error,result,local,refer,ismanager)
611: struct ds_search_arg *arg;
612: struct DSError *error;
613: struct ds_search_result *result;
614: struct ds_search_task **local,
615: **refer;
616: int ismanager;
617: {
618: Entry entryptr;
619: EntryInfo *einfo = NULLENTRYINFO;
620: struct di_block * di_tmp;
621:
622: if ((*local)->st_subset == SRA_BASEOBJECT)
623: {
624: if ((*local)->st_baseobject == NULLDN) {
625: LLOG (log_dsap,LLOG_NOTICE,("NULL Base in search ignored"));
626: /* to stop poisoning... */
627: return (DS_OK);
628: }
629: switch(find_entry((*local)->st_baseobject,&(arg->sra_common),NULLDN,NULLDNSEQ,FALSE,&(entryptr), error, &(di_tmp)))
630: {
631: case DS_OK:
632: /* Filled out entryptr - carry on */
633: break;
634: case DS_CONTINUE:
635: /* Filled out di_p - what do we do with it ?? */
636: subtask_refer(arg, local, refer, ismanager, di_tmp);
637: return(DS_OK);
638:
639: case DS_X500_ERROR:
640: /* Filled out error - what do we do with it ?? */
641: /* The only problem can be alias error etc */
642: /* to stop poisoning return OK */
643: log_ds_error (error);
644: ds_error_free (error);
645: return (DS_OK);
646: default:
647: /* SCREAM */
648: LLOG(log_dsap, LLOG_EXCEPTIONS, ("do_ds_search() - find_entry failed 2"));
649: return(DS_ERROR_LOCAL);
650: }
651: }
652: else
653: {
654: switch(find_child_entry((*local)->st_baseobject,&(arg->sra_common),NULLDN,NULLDNSEQ,FALSE,&(entryptr), error, &(di_tmp)))
655: {
656: case DS_OK:
657: /* Filled out entryptr - carry on */
658: break;
659: case DS_CONTINUE:
660: /* Filled out di_p - what do we do with it ?? */
661: subtask_refer(arg, local, refer, ismanager, di_tmp);
662: return(DS_OK);
663:
664: case DS_X500_ERROR:
665: /* Filled out error - what do we do with it ?? */
666: /* The only problem can be alias error etc */
667: /* to stop poisoning return OK */
668: log_ds_error (error);
669: return (DS_OK);
670: default:
671: /* SCREAM */
672: LLOG(log_dsap, LLOG_EXCEPTIONS, ("do_ds_search() - find_child_entry failed 2"));
673: return(DS_ERROR_LOCAL);
674: }
675:
676: if ((*local)->st_subset == SRA_WHOLESUBTREE) {
677: if (entryptr->e_data != E_TYPE_CONSTRUCTOR) {
678: if ((*local)->st_alias) {
679: if ((einfo = filterentry (arg,entryptr)) != NULLENTRYINFO) {
680: (*local)->st_size--;
681: if (result->CSR_entries == NULLENTRYINFO)
682: result->CSR_entries = einfo;
683: else
684: entryinfo_merge (result->CSR_entries,einfo);
685: }
686: }
687: } else {
688: do_base (entryptr,local);
689: }
690: }
691: }
692:
693: switch ((*local)->st_subset) {
694: case SRA_BASEOBJECT:
695: einfo = filterentry (arg,entryptr);
696: break;
697: case SRA_ONELEVEL:
698: case SRA_WHOLESUBTREE:
699: einfo = filterchildren (arg,entryptr,local,refer,(*local)->st_subset,ismanager);
700: break;
701: default:
702: LLOG (log_dsap,LLOG_EXCEPTIONS,("search protocol error"));
703: error->dse_type = DSE_SERVICEERROR;
704: error->ERR_SERVICE.DSE_sv_problem = DSE_SV_UNWILLINGTOPERFORM;
705: return (DS_X500_ERROR);
706: }
707:
708: if (einfo != NULLENTRYINFO)
709: if (result->CSR_entries == NULLENTRYINFO)
710: result->CSR_entries = einfo;
711: else
712: entryinfo_merge (result->CSR_entries,einfo);
713:
714: result->CSR_common.cr_requestor = NULLDN;
715: return (DS_OK);
716: }
717:
718: /*
719: * SEARCH CHILDREN
720: */
721:
722: static EntryInfo * filterchildren (arg,entryptr,local,refer,extent, ismanager)
723: struct ds_search_arg *arg;
724: Entry entryptr;
725: struct ds_search_task **local,
726: **refer;
727: int extent;
728: int ismanager;
729: {
730: EntryInfo *einfo = NULLENTRYINFO;
731: EntryInfo *eptr = NULLENTRYINFO;
732: register Entry ptr;
733: register Entry cptr;
734: struct ds_search_task * new_task;
735: register int tmp;
736: char domore = TRUE;
737:
738: DLOG (log_dsap,LLOG_DEBUG,("search: filter children"));
739:
740: if (entryptr == NULLENTRY)
741: return (NULLENTRYINFO);
742:
743: if (entryptr->e_leaf)
744: return (NULLENTRYINFO);
745:
746: if (check_acl (NULLDN, ACL_READ, entryptr->e_acl->ac_child, (*local)->st_baseobject) == NOTOK) {
747: return (NULLENTRYINFO);
748: }
749:
750: if (entryptr->e_alias != NULLDN) {
751: (void) do_alias (arg,entryptr,local);
752: return (NULLENTRYINFO);
753: }
754:
755: ptr = entryptr->e_child;
756:
757: if (((ptr != NULLENTRY) && (entryptr->e_allchildrenpresent == FALSE))
758: || (ptr == NULLENTRY)) {
759: search_refer (arg,entryptr,local,refer,ismanager);
760: return (NULLENTRYINFO);
761: }
762:
763: /* search everything at this level */
764: for (tmp=0; (ptr != NULLENTRY) && (size >= 0) ; ptr=ptr->e_sibling,tmp++) {
765:
766: if ((ptr->e_alias != NULLDN) &&
767: (do_alias (arg,ptr,local) == OK))
768: continue;
769:
770: eptr = filterentry (arg,ptr);
771:
772: if ((eptr != NULLENTRYINFO) && (size != -1))
773: if (einfo == NULLENTRYINFO)
774: einfo = eptr;
775: else
776: entryinfo_merge (einfo,eptr);
777:
778: if ( tmp > SEARCH_DELTA_SIZE ) {
779: if (timelimit <= (timenow = time ((time_t *)0)))
780: return (einfo);
781: tmp = 0;
782: domore = FALSE;
783: }
784: }
785:
786: if (size < 0)
787: return (einfo);
788:
789: if (domore)
790: /* Heuristic - should tailor it eventually */
791: domore = (tmp < (SEARCH_DELTA_SIZE / 5));
792:
793: if (extent == SRA_WHOLESUBTREE) {
794: /* search below - or make pointers */
795: ptr=entryptr->e_child;
796:
797: for (; (ptr != NULLENTRY) && (size >= 0) ; ptr=ptr->e_sibling) {
798:
799: if (ptr->e_leaf)
800: continue;
801:
802: if (domore) {
803: /* search one more level */
804: if (check_acl (NULLDN, ACL_READ, ptr->e_acl->ac_child, NULLDN) == NOTOK)
805: continue;
806:
807: cptr = ptr->e_child;
808:
809: if (((cptr != NULLENTRY) && (ptr->e_allchildrenpresent == FALSE))
810: || (cptr == NULLENTRY)) {
811: search_refer (arg,ptr,local,refer,ismanager);
812: continue;
813: }
814:
815: /* search everything at this level */
816: for (tmp=0; (cptr != NULLENTRY) && (size >= 0) ; cptr=cptr->e_sibling,tmp++) {
817:
818: if (cptr->e_leaf) {
819:
820: if ((cptr->e_alias != NULLDN) &&
821: (do_alias (arg,cptr,local) == OK))
822: continue;
823:
824: eptr = filterentry (arg,cptr);
825:
826: if ((eptr != NULLENTRYINFO) && (size != -1))
827: if (einfo == NULLENTRYINFO)
828: einfo = eptr;
829: else
830: entryinfo_merge (einfo,eptr);
831: } else {
832: new_task = st_alloc();
833: new_task->st_save = NULL_ST;
834: new_task->st_baseobject = get_copy_dn (cptr);
835: new_task->st_size = 0; /* fill in later */
836: new_task->st_alias = NULLDN;
837: new_task->st_subset = SRA_WHOLESUBTREE;
838: new_task->st_next = (*local)->st_next;
839: new_task->st_entryonly = FALSE;
840: (*local)->st_next = new_task;
841: }
842:
843: if ( tmp > SEARCH_DELTA_SIZE ) {
844: if (timelimit <= (timenow = time ((time_t *)0)))
845: return (einfo);
846: tmp = 0;
847: }
848: }
849: if (timelimit <= (timenow = time ((time_t *)0)))
850: return (einfo);
851:
852: dsa_wait (0); /* progress any other connections */
853: } else {
854: new_task = st_alloc();
855: new_task->st_save = NULL_ST;
856: new_task->st_baseobject = get_copy_dn (ptr);
857: new_task->st_size = 0; /* fill in later */
858: new_task->st_alias = NULLDN;
859: new_task->st_subset = SRA_WHOLESUBTREE;
860: new_task->st_next = (*local)->st_next;
861: new_task->st_entryonly = FALSE;
862: (*local)->st_next = new_task;
863: }
864: }
865: }
866:
867: return (einfo);
868: }
869:
870: /*
871: * HANDLE ALIASES AND REFERRALS
872: */
873:
874: static do_alias (arg,eptr,local)
875: struct ds_search_arg *arg;
876: Entry eptr;
877: struct ds_search_task **local;
878: {
879: struct ds_search_task *new_task;
880: struct ds_search_task *st;
881: DN st_dn;
882:
883: if ( ! arg->sra_searchaliases)
884: return NOTOK;
885:
886: DLOG (log_dsap,LLOG_DEBUG,("alias in search path"));
887:
888: /* Check we have not been here before... */
889: for ( st = (*local)->st_save; st != NULL_ST; st=st->st_next) {
890: if (st->st_alias == NULLDN)
891: st_dn = st->st_baseobject;
892: else
893: st_dn = st->st_alias;
894: if (dn_cmp (eptr->e_alias, st_dn) == 0) {
895: LLOG (log_dsap,LLOG_TRACE,("local search - loop detected"));
896: return OK;
897: }
898: }
899:
900: new_task = st_alloc();
901: new_task->st_save = NULL_ST;
902: new_task->st_baseobject = get_copy_dn (eptr);
903: new_task->st_size = 0; /* fill in later */
904: new_task->st_alias = dn_cpy(eptr->e_alias);
905: new_task->st_entryonly = FALSE;
906:
907: switch ((*local)->st_subset) {
908: case SRA_ONELEVEL:
909: new_task->st_entryonly = TRUE;
910: /* fall */
911: case SRA_BASEOBJECT:
912: new_task->st_subset = SRA_BASEOBJECT;
913: break;
914: case SRA_WHOLESUBTREE:
915: new_task->st_subset = SRA_WHOLESUBTREE;
916: break;
917: }
918:
919: new_task->st_next = (*local)->st_next;
920: (*local)->st_next = new_task;
921:
922: return (OK);
923: }
924:
925: static do_base (eptr,local)
926: Entry eptr;
927: struct ds_search_task **local;
928: {
929: struct ds_search_task *new_task;
930:
931: DLOG (log_dsap,LLOG_DEBUG,("Making baseobject search"));
932:
933: new_task = st_alloc();
934: new_task->st_save = NULL_ST;
935: new_task->st_baseobject = get_copy_dn (eptr);
936: new_task->st_size = 0; /* fill in later */
937: new_task->st_alias = NULLDN;
938: new_task->st_entryonly = TRUE; /* If is a subtree search we are breaking protocol here */
939: /* BUT... There is no other way to do it !!! */
940: new_task->st_subset = SRA_BASEOBJECT;
941: new_task->st_next = (*local)->st_next;
942: (*local)->st_next = new_task;
943: }
944:
945: static search_refer(arg,entryptr,local,refer,ismanager)
946: struct ds_search_arg *arg;
947: Entry entryptr;
948: struct ds_search_task **local,
949: **refer;
950: int ismanager;
951: {
952: struct ds_search_task * new_task;
953: struct DSError error;
954: struct di_block * di_tmp;
955: DN name;
956:
957: name = get_copy_dn (entryptr);
958:
959: switch(dsa_info_new(name, NULLDNSEQ, FALSE, entryptr, &(error), &(di_tmp)))
960: {
961: case DS_OK:
962: /* A di_block ready for use */
963: break;
964: case DS_CONTINUE:
965: /* A deferred di_block */
966: break;
967: case DS_X500_ERROR:
968: /* An error */
969: LLOG(log_dsap, LLOG_EXCEPTIONS, ("search_refer - dsa_info_new() generated x500 error"));
970: log_ds_error(&(error));
971: ds_error_free(&(error));
972: dn_free (name);
973: return;
974: default:
975: /* A local error - scream */
976: LLOG(log_dsap, LLOG_EXCEPTIONS, ("search_refer - dsa_info_new() failed"));
977: dn_free (name);
978: return;
979: }
980:
981: DLOG (log_dsap,LLOG_DEBUG,("referral in search path"));
982:
983: new_task = st_alloc();
984: new_task->st_save = NULL_ST;
985: new_task->st_baseobject = name;
986: new_task->st_subset = (*local)->st_subset;
987: new_task->st_alias = NULLDN;
988: new_task->st_entryonly = (*local)->st_entryonly;
989: if (ismanager) {
990: if ((new_task->st_size = arg->sra_common.ca_servicecontrol.svc_sizelimit) == SVC_NOSIZELIMIT)
991: new_task->st_size = big_size;
992: }
993: else
994: if ((new_task->st_size = MIN(admin_size,arg->sra_common.ca_servicecontrol.svc_sizelimit)) == SVC_NOSIZELIMIT)
995: new_task->st_size = admin_size;
996:
997: new_task->st_di = di_tmp;
998: new_task->st_next = *refer;
999: *refer = new_task;
1000: }
1001:
1002: /*
1003: * SEARCH ENTRY
1004: */
1005:
1006: static EntryInfo * filterentry (arg,entryptr)
1007: struct ds_search_arg *arg;
1008: register Entry entryptr;
1009: {
1010: register EntryInfo * einfo;
1011:
1012: DLOG (log_dsap,LLOG_DEBUG,("search: filter entry"));
1013:
1014: if (check_filter (arg->sra_filter,entryptr) != OK ) {
1015: DLOG (log_dsap,LLOG_DEBUG,("none found"));
1016: return (NULLENTRYINFO);
1017: }
1018:
1019: einfo = entryinfo_alloc ();
1020: einfo->ent_dn = get_copy_dn (entryptr);
1021:
1022: if (check_acl (NULLDN, ACL_READ, entryptr->e_acl->ac_entry, NULLDN) == NOTOK)
1023: return (NULLENTRYINFO);
1024:
1025: einfo->ent_attr = eis_select (arg->sra_eis, entryptr, NULLDN, qctx && arg->sra_eis.eis_allattributes);
1026:
1027: einfo->ent_iscopy = entryptr->e_data;
1028: einfo->ent_age = (time_t) 0;
1029: einfo->ent_next = NULLENTRYINFO;
1030: size--;
1031: return (einfo);
1032: }
1033:
1034: /*
1035: * TEST FILTER AGAINST SINGLE ENTRY
1036: */
1037:
1038: static check_filter (fltr,entryptr)
1039: register Filter fltr;
1040: register Entry entryptr;
1041: {
1042: register int i;
1043:
1044: DLOG (log_dsap,LLOG_DEBUG,("in check filter"));
1045: switch (fltr->flt_type) {
1046: case FILTER_ITEM:
1047: return (check_filteritem (&fltr->FUITEM,entryptr));
1048: case FILTER_AND:
1049: case FILTER_OR:
1050: return(check_filterop (fltr->FUFILT,entryptr,fltr->flt_type));
1051: case FILTER_NOT:
1052: if ((i=check_filter (fltr->FUFILT,entryptr)) == OK)
1053: return NOTOK;
1054: else if ( i == NOTOK )
1055: return OK;
1056: else
1057: return i;
1058: }
1059: /* NOTREACHED */
1060: }
1061:
1062: static check_filterop (fltr,entryptr,op)
1063: register Filter fltr;
1064: register Entry entryptr;
1065: int op;
1066: {
1067: register Filter ptr;
1068: int result;
1069:
1070: DLOG (log_dsap,LLOG_DEBUG,("in filter op"));
1071:
1072: /* effect of applying logical operator to zero operands */
1073: if (op == FILTER_OR)
1074: result = NOTOK;
1075: else
1076: result = OK;
1077:
1078: for (ptr=fltr; ptr!=NULLFILTER ; ptr=ptr->flt_next)
1079: switch (check_filter (ptr,entryptr)) {
1080: case MAYBE:
1081: /* Beware of 'Pathological NOT' here.
1082: * To comply with the December '88 X.500, should just drop through here.
1083: * For the security to work properly, also set result to MAYBE.
1084: */
1085: result = MAYBE;
1086: break;
1087: case OK:
1088: if (op == FILTER_OR) {
1089: DLOG (log_dsap,LLOG_DEBUG,("or ok"));
1090: return (OK);
1091: }
1092: break;
1093: case NOTOK:
1094: if (op == FILTER_AND) {
1095: DLOG (log_dsap,LLOG_DEBUG,("and not"));
1096: return (NOTOK);
1097: }
1098: break;
1099: case -2:
1100: default:
1101: return (-2);
1102: }
1103:
1104:
1105: return (result);
1106: }
1107:
1108: /*
1109: * CHECK FILTER ITEM AGAINST ENTRY
1110: */
1111:
1112: static check_filteritem (fitem,entryptr)
1113: register struct filter_item *fitem;
1114: register Entry entryptr;
1115: {
1116: register Attr_Sequence as;
1117: AttributeType at;
1118:
1119: DLOG (log_dsap,LLOG_DEBUG,("search: check filter item"));
1120:
1121: switch ( fitem->fi_type) {
1122: case FILTERITEM_APPROX:
1123: case FILTERITEM_EQUALITY:
1124: case FILTERITEM_GREATEROREQUAL:
1125: case FILTERITEM_LESSOREQUAL:
1126: at = fitem->UNAVA.ava_type;
1127: break;
1128: case FILTERITEM_SUBSTRINGS:
1129: at = fitem->UNSUB.fi_sub_type;
1130: break;
1131: case FILTERITEM_PRESENT:
1132: if ((as = as_find_type (entryptr->e_attributes, fitem->UNTYPE)) == NULLATTR)
1133: return NOTOK;
1134: else
1135: return OK;
1136: }
1137:
1138: if ((as = as_find_type (entryptr->e_attributes, at)) == NULLATTR)
1139: return MAYBE;
1140:
1141: if ( check_acl (NULLDN,ACL_COMPARE,as->attr_acl,NULLDN) != OK)
1142: return MAYBE;
1143:
1144: switch ( fitem->fi_type) {
1145: case FILTERITEM_SUBSTRINGS:
1146: return (substr_search (fitem,as->attr_value));
1147: case FILTERITEM_APPROX:
1148: return ((int)(*fitem->fi_ifp)(fitem,as->attr_value));
1149: default:
1150: return (test_avs (fitem,as->attr_value,fitem->fi_type));
1151: }
1152: /* NOTREACHED */
1153: }
1154:
1155: static test_avs (fitem,avs,mode)
1156: register struct filter_item *fitem;
1157: register AV_Sequence avs;
1158: register int mode;
1159: {
1160:
1161: for (; avs != NULLAV; avs=avs->avseq_next) {
1162: switch (((int)(*fitem->fi_ifp)(avs->avseq_av.av_struct, fitem->UNAVA.ava_value->av_struct))) {
1163: case 0:
1164: return (OK);
1165: case 1:
1166: if (mode == FILTERITEM_GREATEROREQUAL)
1167: return (OK);
1168: break;
1169: case -1:
1170: if (mode == FILTERITEM_LESSOREQUAL)
1171: return (OK);
1172: break;
1173: case 2:
1174: return (NOTOK);
1175: default:
1176: return (MAYBE);
1177: }
1178: }
1179: return (NOTOK);
1180: }
1181:
1182:
1183: /*
1184: * SUBSTRING MATCH
1185: */
1186:
1187: static substr_search (fitem,avs)
1188: register struct filter_item *fitem;
1189: register AV_Sequence avs;
1190: {
1191:
1192: for (; avs != NULLAV; avs=avs->avseq_next)
1193: if (aux_substr_search (fitem,avs,fitem->UNSUB.fi_sub_match) == OK)
1194: return (OK);
1195: return (NOTOK);
1196: }
1197:
1198:
1199:
1200: static aux_substr_search (fitem,avs,chrmatch)
1201: struct filter_item *fitem;
1202: AV_Sequence avs;
1203: char chrmatch [];
1204: {
1205: register AV_Sequence loopavs;
1206: register char * compstr;
1207: char * top;
1208: register char * temp;
1209: char * temp2;
1210: int offset;
1211:
1212: compstr = (char *)avs->avseq_av.av_struct;
1213: top = compstr;
1214: if (fitem->UNSUB.fi_sub_initial != NULLAV) {
1215: temp = (char *)fitem->UNSUB.fi_sub_initial->avseq_av.av_struct;
1216: do
1217: if (chrmatch[*compstr++] != chrmatch[*temp++]) {
1218: DLOG (log_dsap,LLOG_DEBUG,("initial failure (%s, %s)",top,(char *)fitem->UNSUB.fi_sub_initial->avseq_av.av_struct));
1219: return (NOTOK);
1220: }
1221: while (*temp != '\0') ;
1222: }
1223:
1224: for (loopavs=fitem->UNSUB.fi_sub_any; loopavs!=NULLAV; loopavs=loopavs->avseq_next, compstr += offset)
1225: if ((offset= attr_substr (compstr, &loopavs->avseq_av,chrmatch)) == -1) {
1226: DLOG (log_dsap,LLOG_DEBUG,("any failure (%s, %s)",top,(char *)loopavs->avseq_av.av_struct));
1227: return (NOTOK);
1228: }
1229:
1230: if (fitem->UNSUB.fi_sub_final != NULLAV) {
1231: temp = (char *)fitem->UNSUB.fi_sub_final->avseq_av.av_struct;
1232: temp2 = temp;
1233: while (*++compstr != '\0')
1234: ; /* NO-OP*/
1235:
1236: while (*temp++ != '\0')
1237: compstr--;
1238:
1239: if (compstr < top) {
1240: DLOG (log_dsap,LLOG_DEBUG,("final too long failure (%s,%s)",top,temp2));
1241: return (NOTOK);
1242: }
1243:
1244: temp = temp2;
1245: while (*compstr != '\0')
1246: if (chrmatch[*compstr++] != chrmatch[*temp++]) {
1247: /* free (top); */
1248: DLOG (log_dsap,LLOG_DEBUG,("final failure (%s, %s)",top,temp2));
1249: return (NOTOK);
1250: }
1251: }
1252: return (OK);
1253: }
1254:
1255: attr_substr (str1,av,chrmatch)
1256: register char * str1;
1257: AttributeValue av;
1258: char chrmatch[];
1259: {
1260: register char * str2;
1261: register int count;
1262: char * top;
1263: int found = 0;
1264: int slen;
1265:
1266: top = str1;
1267: str2 = (char *)av->av_struct;
1268:
1269: while (*str1 != '\0') {
1270: if (chrmatch[*str1++] == chrmatch[*str2]) {
1271: str2++;
1272: found = 1;
1273: break;
1274: }
1275: }
1276:
1277: if ( found == 0 )
1278: return (-1);
1279:
1280: slen = strlen (str2) + 1;
1281: for (count = 1; count < slen ; count ++) {
1282: if (*str1 == '\0')
1283: return (-1);
1284:
1285: if (chrmatch[*str1++] != chrmatch[*str2++]) {
1286: /* not found here, but may still be in the string !! */
1287: str1 -= count;
1288: str2 -= count + 1;
1289: while (*str1 != '\0') {
1290: if (chrmatch[*str1++] == chrmatch[*str2]) {
1291: str2++;
1292: break;
1293: }
1294: }
1295: count = 0; /* for loop ++ will make it 1 !!! */
1296: }
1297: }
1298: return (str1 - top);
1299: }
1300:
1301:
1302: subtask_refer(arg, local, refer, ismanager, di)
1303: struct ds_search_arg *arg;
1304: struct ds_search_task **local,
1305: **refer;
1306: int ismanager;
1307: struct di_block * di;
1308: {
1309: /* turn query into a referral */
1310: struct ds_search_task * new_task;
1311:
1312: new_task = st_alloc();
1313: new_task->st_save = NULL_ST;
1314: new_task->st_baseobject = dn_cpy ((*local)->st_baseobject);
1315: new_task->st_subset = (*local)->st_subset;
1316: new_task->st_alias = dn_cpy ((*local)->st_alias);
1317: new_task->st_entryonly = (*local)->st_entryonly;
1318:
1319: if (ismanager) {
1320: if ((new_task->st_size = arg->sra_common.ca_servicecontrol.svc_sizelimit) == SVC_NOSIZELIMIT)
1321: new_task->st_size = big_size;
1322: }
1323: else
1324: if ((new_task->st_size = MIN(admin_size,arg->sra_common.ca_servicecontrol.svc_sizelimit)) == SVC_NOSIZELIMIT)
1325: new_task->st_size = admin_size;
1326:
1327: new_task->st_di = di;
1328: new_task->st_next = *refer;
1329: *refer = new_task;
1330: }
1331:
1332: dsa_search_control (arg,result)
1333: struct ds_search_arg *arg;
1334: struct ds_search_result *result;
1335: {
1336: extern DN mydsadn;
1337: char buffer [LINESIZE];
1338: Attr_Sequence as;
1339: extern AttributeType at_control;
1340: int i;
1341:
1342: if (big_size == 0)
1343: for (i = NBBY * sizeof big_size - 1; i > 0; i--)
1344: big_size <<= 1, big_size |= 1;
1345:
1346: if ((arg->sra_eis.eis_allattributes) ||
1347: (arg->sra_eis.eis_infotypes == EIS_ATTRIBUTETYPESONLY))
1348: return FALSE;
1349:
1350: if (arg->sra_eis.eis_select == NULLATTR)
1351: return FALSE;
1352:
1353: if (arg->sra_eis.eis_select->attr_link != NULLATTR)
1354: return FALSE;
1355:
1356: if (AttrT_cmp (at_control,arg->sra_eis.eis_select->attr_type) != 0)
1357: return FALSE;
1358:
1359: if (result->CSR_entries)
1360: entryinfo_free (result->CSR_entries,0);
1361:
1362: (void) sprintf (buffer,"%d",big_size-size);
1363:
1364: as=as_comp_alloc();
1365: as->attr_acl = NULLACL_INFO;
1366: as->attr_type = at_control;
1367: as->attr_link = NULLATTR;
1368: if ((as->attr_value = str2avs (buffer,as->attr_type)) == NULLAV) {
1369: as_free (as);
1370: result->CSR_entries = NULLENTRYINFO;
1371: return FALSE;
1372: }
1373:
1374: result->CSR_entries = entryinfo_alloc ();
1375: result->CSR_entries->ent_dn = dn_cpy (mydsadn);
1376: result->CSR_entries->ent_next = NULLENTRYINFO;
1377: result->CSR_entries->ent_age = (time_t) 0;
1378: result->CSR_entries->ent_iscopy = TRUE;
1379: result->CSR_entries->ent_attr = as;
1380:
1381: return TRUE;
1382: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.