3 * Copyright (c) 1990 Regents of the University of Michigan.
6 * Redistribution and use in source and binary forms are permitted
7 * provided that this notice is preserved and that due credit is given
8 * to the University of Michigan at Ann Arbor. The name of the University
9 * may not be used to endorse or promote products derived from this
10 * software without specific prior written permission. This software
11 * is provided ``as is'' without express or implied warranty.
18 #include <ac/socket.h>
19 #include <ac/string.h>
21 #include <quipu/commonarg.h>
22 #include <quipu/attrvalue.h>
23 #include <quipu/ds_error.h>
24 #include <quipu/ds_search.h>
25 #include <quipu/dap2.h>
26 #include <quipu/dua.h>
29 #include "../../libraries/liblber/lber-int.h" /* get struct berelement */
33 static int get_filter( BerElement *ber, Filter *filt );
34 static int get_filter_list( BerElement *ber, Filter f );
35 static int get_substring_filter( BerElement *ber, Filter f );
38 #define SEARCHRESTAG (ldap_compat == 20 ? OLD_LDAP_RES_SEARCH_RESULT : LDAP_RES_SEARCH_RESULT)
40 #define SEARCHRESTAG LDAP_RES_SEARCH_RESULT
52 int sizelimit, timelimit;
55 struct ds_search_arg sa;
56 static CommonArgs common = default_common_args;
58 Debug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 );
61 * Parse the search request. It looks like this:
62 * SearchRequest := [APPLICATION 3] SEQUENCE {
63 * baseObject DistinguishedName,
69 * derefAliases ENUMERATED {
70 * neverDerefaliases (0),
71 * derefInSearching (1),
72 * derefFindingBaseObj (2),
73 * alwaysDerefAliases (3)
75 * sizelimit INTEGER (0 .. 65535),
76 * timelimit INTEGER (0 .. 65535),
79 * attributes SEQUENCE OF AttributeType
83 #if ISODEPACKAGE == IC
85 DAS_SearchArgument_INIT( &sa );
89 if ( ber_scanf( ber, "{aiiiib", &base, &sa.sra_subset, &deref,
90 &sizelimit, &timelimit, &attrsonly ) == LBER_ERROR ) {
91 send_ldap_msgresult( clientsb, SEARCHRESTAG, m,
92 LDAP_PROTOCOL_ERROR, NULL, "" );
96 sa.sra_baseobject = ldap_str2dn( base );
97 if ( sa.sra_baseobject == NULLDN && *base != '\0' ) {
99 send_ldap_msgresult( clientsb, SEARCHRESTAG, m,
100 LDAP_INVALID_DN_SYNTAX, NULL, "" );
105 sa.sra_common = common; /* struct copy */
106 sa.sra_searchaliases = (deref == LDAP_DEREF_SEARCHING ||
107 deref == LDAP_DEREF_ALWAYS);
108 if ( deref == LDAP_DEREF_NEVER || deref == LDAP_DEREF_SEARCHING )
109 sa.sra_common.ca_servicecontrol.svc_options |=
110 SVC_OPT_DONTDEREFERENCEALIAS;
112 sa.sra_common.ca_servicecontrol.svc_sizelimit = (sizelimit == 0 ?
113 SVC_NOSIZELIMIT : sizelimit);
115 sa.sra_common.ca_servicecontrol.svc_timelimit = (timelimit == 0 ?
116 SVC_NOTIMELIMIT : timelimit);
118 sa.sra_eis.eis_infotypes = (attrsonly ? EIS_ATTRIBUTETYPESONLY :
119 EIS_ATTRIBUTESANDVALUES);
122 if ( (err = get_filter( ber, &sa.sra_filter )) != 0 ) {
123 send_ldap_msgresult( clientsb, SEARCHRESTAG, m,
124 err, NULL, "Bad search filter" );
129 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
132 ps = ps_alloc( std_open );
133 std_setup( ps, stderr );
134 ps_print( ps, "Filter: " );
135 fi_print( ps, sa.sra_filter, EDBOUT );
136 ps_print( ps, "\n" );
141 /* attrs to return */
143 if ( ber_scanf( ber, "{v}}", &attrs ) == LBER_ERROR ) {
144 send_ldap_msgresult( clientsb, SEARCHRESTAG, m,
145 LDAP_PROTOCOL_ERROR, NULL, "" );
148 sa.sra_eis.eis_select = NULLATTR;
149 if ( attrs == NULL ) {
150 sa.sra_eis.eis_allattributes = 1;
155 sa.sra_eis.eis_allattributes = 0;
156 for ( i = 0; attrs[i] != NULL; i++ ) {
159 if ( (type = AttrT_new( attrs[i] )) == NULLAttrT ) {
160 Debug( LDAP_DEBUG_TRACE, "unknown attr (%s)\n",
165 as = as_comp_alloc();
166 as->attr_type = type;
167 as->attr_acl = NULLACL_INFO;
168 as->attr_link = NULLATTR;
169 as->attr_value = NULLAV;
171 sa.sra_eis.eis_select = as_merge( as,
172 sa.sra_eis.eis_select );
175 /* complain only if we know about none of the attrs */
176 if ( sa.sra_eis.eis_select == NULLATTR ) {
177 send_ldap_msgresult( clientsb, SEARCHRESTAG,
178 m, LDAP_UNDEFINED_TYPE, NULL, attrs[0] );
179 charlist_free( attrs );
183 charlist_free( attrs );
186 rc = initiate_dap_operation( OP_SEARCH, m, &sa );
188 #ifdef LDAP_CONNECTIONLESS
190 m->m_searchbase = sa.sra_baseobject;
192 #endif /* LDAP_CONNECTIONLESS */
193 dn_free( sa.sra_baseobject );
195 filter_free( sa.sra_filter );
196 as_free( sa.sra_eis.eis_select );
199 send_ldap_msgresult( clientsb, SEARCHRESTAG, m,
208 get_filter( BerElement *ber, Filter *filt )
210 unsigned long tag, len;
215 Debug( LDAP_DEBUG_TRACE, "get_filter\n", 0, 0, 0 );
218 * A filter looks like this coming in:
219 * Filter ::= CHOICE {
220 * and [0] SET OF Filter,
221 * or [1] SET OF Filter,
223 * equalityMatch [3] AttributeValueAssertion,
224 * substrings [4] SubstringFilter,
225 * greaterOrEqual [5] AttributeValueAssertion,
226 * lessOrEqual [6] AttributeValueAssertion,
227 * present [7] AttributeType,,
228 * approxMatch [8] AttributeValueAssertion
231 * SubstringFilter ::= SEQUENCE {
232 * type AttributeType,
233 * SEQUENCE OF CHOICE {
234 * initial [0] IA5String,
236 * final [2] IA5String
243 f->flt_next = NULLFILTER;
246 switch (tag = ber_peek_tag( ber, &len )) {
248 case OLD_LDAP_FILTER_EQUALITY:
250 case LDAP_FILTER_EQUALITY:
251 Debug( LDAP_DEBUG_ARGS, "EQUALITY\n", 0, 0, 0 );
252 f->flt_type = FILTER_ITEM;
253 f->FUITEM.fi_type = FILTERITEM_EQUALITY;
255 if ( ldap_compat == 30 )
256 (void) ber_skip_tag( ber, &len );
259 if ( (err = get_ava( ber, &f->FUITEM.UNAVA )) != 0 ) {
266 case OLD_LDAP_FILTER_SUBSTRINGS:
268 case LDAP_FILTER_SUBSTRINGS:
269 Debug( LDAP_DEBUG_ARGS, "SUBSTRINGS\n", 0, 0, 0 );
270 err = get_substring_filter( ber, f );
274 case OLD_LDAP_FILTER_GE:
277 Debug( LDAP_DEBUG_ARGS, "GE\n", 0, 0, 0 );
278 f->flt_type = FILTER_ITEM;
279 f->FUITEM.fi_type = FILTERITEM_GREATEROREQUAL;
281 if ( ldap_compat == 30 )
282 (void) ber_skip_tag( ber, &len );
284 if ( (err = get_ava( ber, &f->FUITEM.UNAVA )) != 0 ) {
291 case OLD_LDAP_FILTER_LE:
294 Debug( LDAP_DEBUG_ARGS, "LE\n", 0, 0, 0 );
295 f->flt_type = FILTER_ITEM;
296 f->FUITEM.fi_type = FILTERITEM_LESSOREQUAL;
298 if ( ldap_compat == 30 )
299 (void) ber_skip_tag( ber, &len );
302 if ( (err = get_ava( ber, &f->FUITEM.UNAVA )) != 0 ) {
309 case OLD_LDAP_FILTER_PRESENT:
312 case LDAP_FILTER_PRESENT_30:
314 case LDAP_FILTER_PRESENT:
315 Debug( LDAP_DEBUG_ARGS, "PRESENT\n", 0, 0, 0 );
316 f->flt_type = FILTER_ITEM;
317 f->FUITEM.fi_type = FILTERITEM_PRESENT;
318 len = sizeof(typestr);
320 if ( ldap_compat == 30 )
321 (void) ber_skip_tag( ber, &len );
324 if ( ber_scanf( ber, "s", typestr, &len ) == LBER_ERROR )
325 return( LDAP_PROTOCOL_ERROR );
326 if ( (f->FUITEM.UNTYPE = str2AttrT( typestr )) == NULLAttrT )
327 return( LDAP_UNDEFINED_TYPE );
331 case OLD_LDAP_FILTER_APPROX:
333 case LDAP_FILTER_APPROX:
334 Debug( LDAP_DEBUG_ARGS, "APPROX\n", 0, 0, 0 );
335 f->flt_type = FILTER_ITEM;
336 f->FUITEM.fi_type = FILTERITEM_APPROX;
338 if ( ldap_compat == 30 )
339 (void) ber_skip_tag( ber, &len );
342 if ( (err = get_ava( ber, &f->FUITEM.UNAVA )) != 0 ) {
349 case OLD_LDAP_FILTER_AND:
351 case LDAP_FILTER_AND:
352 Debug( LDAP_DEBUG_ARGS, "AND\n", 0, 0, 0 );
353 f->flt_type = FILTER_AND;
354 err = get_filter_list( ber, f );
358 case OLD_LDAP_FILTER_OR:
361 Debug( LDAP_DEBUG_ARGS, "OR\n", 0, 0, 0 );
362 f->flt_type = FILTER_OR;
363 err = get_filter_list( ber, f );
367 case OLD_LDAP_FILTER_NOT:
369 case LDAP_FILTER_NOT:
370 Debug( LDAP_DEBUG_ARGS, "NOT\n", 0, 0, 0 );
371 f->flt_type = FILTER_NOT;
372 (void) ber_skip_tag( ber, &len );
373 err = get_filter( ber, &f->FUFILT );
377 Debug( LDAP_DEBUG_ANY, "unknown filter type %lu\n", tag, 0, 0 );
379 return( LDAP_PROTOCOL_ERROR );
383 Debug( LDAP_DEBUG_TRACE, "end get_filter\n", 0, 0, 0 );
388 get_filter_list( BerElement *ber, Filter f )
392 unsigned long tag, len;
395 Debug( LDAP_DEBUG_TRACE, "get_filter_list\n", 0, 0, 0 );
398 if ( ldap_compat == 30 )
399 (void) ber_skip_tag( ber, &len );
401 f->FUFILT = tail = NULLFILTER;
402 for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
403 tag = ber_next_element( ber, &len, last ) ) {
404 if ( (err = get_filter( ber, &new )) != 0 )
407 if ( f->FUFILT == NULLFILTER ) {
410 tail->flt_next = new;
415 Debug( LDAP_DEBUG_TRACE, "end get_filter_list\n", 0, 0, 0 );
420 get_substring_filter( BerElement *ber, Filter f )
422 unsigned long tag, len;
426 AttributeValue value;
428 Debug( LDAP_DEBUG_TRACE, "get_substring_filter\n", 0, 0, 0 );
431 if ( ldap_compat == 30 )
432 (void) ber_skip_tag( ber, &len );
435 f->flt_type = FILTER_ITEM;
436 f->FUITEM.fi_type = FILTERITEM_SUBSTRINGS;
437 len = sizeof(typestr);
438 if ( ber_scanf( ber, "{s", typestr, &len ) == LBER_ERROR ) {
439 return( LDAP_PROTOCOL_ERROR );
441 if ( (type = str2AttrT( typestr )) == NULLAttrT ) {
442 return( LDAP_UNDEFINED_TYPE );
444 f->FUITEM.UNSUB.fi_sub_type = type;
445 f->FUITEM.UNSUB.fi_sub_initial = NULLAV;
446 f->FUITEM.UNSUB.fi_sub_any = NULLAV;
447 f->FUITEM.UNSUB.fi_sub_final = NULLAV;
448 for ( tag = ber_first_element( ber, &len, &last ); tag != LBER_DEFAULT;
449 tag = ber_next_element( ber, &len, last ) ) {
450 AV_Sequence avs, any_end;
453 if ( ldap_compat == 30 ) {
454 if ( ber_scanf( ber, "{a}", &valstr ) == LBER_ERROR ) {
455 return( LDAP_PROTOCOL_ERROR );
459 if ( ber_scanf( ber, "a", &valstr ) == LBER_ERROR ) {
460 return( LDAP_PROTOCOL_ERROR );
463 value = ldap_str2AttrV( valstr, type->oa_syntax );
466 if ( value == NULLAttrV ) {
467 return( LDAP_INVALID_SYNTAX );
470 if ( (avs = avs_comp_new( value )) == NULLAV )
471 return( LDAP_OPERATIONS_ERROR );
475 case OLD_LDAP_SUBSTRING_INITIAL:
478 case LDAP_SUBSTRING_INITIAL_30:
480 case LDAP_SUBSTRING_INITIAL:
481 Debug( LDAP_DEBUG_ARGS, " INITIAL\n", 0, 0, 0 );
482 if ( f->FUITEM.UNSUB.fi_sub_initial != NULLAV
483 && f->FUITEM.UNSUB.fi_sub_initial->avseq_next
485 return( LDAP_PROTOCOL_ERROR );
487 f->FUITEM.UNSUB.fi_sub_initial = avs;
491 case OLD_LDAP_SUBSTRING_ANY:
494 case LDAP_SUBSTRING_ANY_30:
496 case LDAP_SUBSTRING_ANY:
497 Debug( LDAP_DEBUG_ARGS, " ANY\n", 0, 0, 0 );
499 if (f->FUITEM.UNSUB.fi_sub_any != NULLAV) {
500 any_end->avseq_next = avs;
502 f->FUITEM.UNSUB.fi_sub_any = avs;
509 case OLD_LDAP_SUBSTRING_FINAL:
512 case LDAP_SUBSTRING_FINAL_30:
514 case LDAP_SUBSTRING_FINAL:
515 Debug( LDAP_DEBUG_ARGS, " FINAL\n", 0, 0, 0 );
516 if ( f->FUITEM.UNSUB.fi_sub_final != NULLAV
517 && f->FUITEM.UNSUB.fi_sub_final->avseq_next
519 return( LDAP_PROTOCOL_ERROR );
521 f->FUITEM.UNSUB.fi_sub_final = avs;
525 Debug( LDAP_DEBUG_ARGS, " unknown type\n", tag, 0, 0 );
526 return( LDAP_PROTOCOL_ERROR );
530 Debug( LDAP_DEBUG_TRACE, "end get_substring_filter\n", 0, 0, 0 );
538 struct ds_search_result *sr
545 Debug( LDAP_DEBUG_TRACE, "search_result\n", 0, 0, 0 );
549 if ( ! sr->srr_correlated ) {
550 Debug( LDAP_DEBUG_ARGS, "correlating results\n", 0, 0, 0 );
551 correlate_search_results( sr );
554 #ifdef LDAP_CONNECTIONLESS
556 if ((ber = der_alloc()) == NULL ) {
557 send_ldap_msgresult( sb, SEARCHRESTAG, m,
558 LDAP_OPERATIONS_ERROR, NULL, "der_alloc" );
561 if ( ber_printf( ber, "t{is{", LBER_SEQUENCE, m->m_msgid,
563 send_ldap_msgresult( sb, SEARCHRESTAG, m,
564 LDAP_OPERATIONS_ERROR, NULL, "ber_printf" );
570 for ( e = sr->CSR_entries; e != NULLENTRYINFO; e = e->ent_next ) {
571 Debug( LDAP_DEBUG_ARGS, "\tentry:\n", 0, 0, 0 );
573 #ifdef LDAP_CONNECTIONLESS
575 #endif /* LDAP_CONNECTIONLESS */
577 if ( (ber = der_alloc()) == NULL ) {
578 send_ldap_msgresult( sb, SEARCHRESTAG, m,
579 LDAP_OPERATIONS_ERROR, NULL, "der_alloc" );
584 if ( version == 1 ) {
585 if ( ber_printf( ber, "t{it{", OLD_LBER_SEQUENCE,
586 m->m_msgid, OLD_LDAP_RES_SEARCH_ENTRY ) == -1 ) {
587 send_ldap_msgresult( sb, SEARCHRESTAG, m,
588 LDAP_OPERATIONS_ERROR, NULL, "ber_printf" );
594 if ( ldap_compat == 30 ) {
595 if ( ber_printf( ber, "{it{{", m->m_msgid,
596 LDAP_RES_SEARCH_ENTRY ) == -1 ) {
597 send_ldap_msgresult( sb, SEARCHRESTAG, m,
598 LDAP_OPERATIONS_ERROR, NULL, "ber_printf" );
603 #ifdef LDAP_CONNECTIONLESS
605 rc = ber_printf( ber, "t{", LDAP_RES_SEARCH_ENTRY );
607 #endif /* LDAP_CONNECTIONLESS */
608 rc = ber_printf( ber, "{it{", m->m_msgid,
609 LDAP_RES_SEARCH_ENTRY );
612 send_ldap_msgresult( sb, SEARCHRESTAG, m,
613 LDAP_OPERATIONS_ERROR, NULL, "ber_printf" );
617 #ifdef LDAP_CONNECTIONLESS
619 rc = encode_dn( ber, e->ent_dn, m->m_searchbase );
620 #endif /* LDAP_CONNECTIONLESS */
622 rc = encode_dn( ber, e->ent_dn, NULLDN );
625 send_ldap_msgresult( sb, SEARCHRESTAG, m,
626 LDAP_OPERATIONS_ERROR, NULL, "encode_dn" );
630 if ( encode_attrs( ber, e->ent_attr ) == -1 ) {
631 send_ldap_msgresult( sb, SEARCHRESTAG, m,
632 LDAP_OPERATIONS_ERROR, NULL, "encode_attrs" );
637 if ( version == 1 ) {
638 if ( ber_printf( ber, "}}" ) == -1 ) {
639 send_ldap_msgresult( sb, SEARCHRESTAG, m,
640 LDAP_OPERATIONS_ERROR, NULL,
647 if ( ldap_compat == 30 ) {
648 if ( ber_printf( ber, "}}}" ) == -1 ) {
649 send_ldap_msgresult( sb, SEARCHRESTAG, m,
650 LDAP_OPERATIONS_ERROR, NULL,
656 #ifdef LDAP_CONNECTIONLESS
658 rc = ber_printf( ber, "}" );
660 #endif /* LDAP_CONNECTIONLESS */
661 rc = ber_printf( ber, "}}" );
664 send_ldap_msgresult( sb, SEARCHRESTAG, m,
665 LDAP_OPERATIONS_ERROR, NULL, "ber_printf 2" );
670 if ( ldap_debug & LDAP_DEBUG_BER )
671 trace_ber( 0, ber->ber_ptr - ber->ber_buf,
672 ber->ber_buf, stderr, 0, 0 );
675 #ifdef LDAP_CONNECTIONLESS
678 (void) ber_flush( sb, ber, 1 );
681 switch ( sr->CSR_limitproblem ) {
682 case LSR_NOLIMITPROBLEM:
685 case LSR_TIMELIMITEXCEEDED:
686 rc = LDAP_TIMELIMIT_EXCEEDED;
688 case LSR_SIZELIMITEXCEEDED:
689 case LSR_ADMINSIZEEXCEEDED:
690 rc = LDAP_SIZELIMIT_EXCEEDED;
694 Debug( LDAP_DEBUG_ARGS, "\tresult:\n", 0, 0, 0 );
696 #ifdef LDAP_CONNECTIONLESS
698 if ( ber_printf( ber, "t{ess}}}", SEARCHRESTAG, rc, "", "" )
700 send_ldap_msgresult( sb, SEARCHRESTAG, m,
701 LDAP_OPERATIONS_ERROR, NULL, "ber_printf" );
704 ber_pvt_sb_udp_set_dst( sb, &m->m_clientaddr );
706 if ( ber_flush( sb, ber, 1 ) != 0 ) {
707 send_ldap_msgresult( sb, SEARCHRESTAG, m,
708 LDAP_RESULTS_TOO_LARGE, NULL, "ber_flush" );
712 send_ldap_msgresult( sb, SEARCHRESTAG, m, rc, NULL, "" );