8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libldap5 / sources / ldap / common / search.c
blob1235234f8b35eba8dea95f95c226e3399853adbc
1 /*
2 * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 #pragma ident "%Z%%M% %I% %E% SMI"
9 /*
10 * The contents of this file are subject to the Netscape Public
11 * License Version 1.1 (the "License"); you may not use this file
12 * except in compliance with the License. You may obtain a copy of
13 * the License at http://www.mozilla.org/NPL/
15 * Software distributed under the License is distributed on an "AS
16 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17 * implied. See the License for the specific language governing
18 * rights and limitations under the License.
20 * The Original Code is Mozilla Communicator client code, released
21 * March 31, 1998.
23 * The Initial Developer of the Original Code is Netscape
24 * Communications Corporation. Portions created by Netscape are
25 * Copyright (C) 1998-1999 Netscape Communications Corporation. All
26 * Rights Reserved.
28 * Contributor(s):
31 * Copyright (c) 1990 Regents of the University of Michigan.
32 * All rights reserved.
35 * search.c
38 #if 0
39 #ifndef lint
40 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
41 #endif
42 #endif
44 #include "ldap-int.h"
46 static int nsldapi_timeval2ldaplimit( struct timeval *timeoutp,
47 int defaultvalue );
48 static int nsldapi_search( LDAP *ld, const char *base, int scope,
49 const char *filter, char **attrs, int attrsonly,
50 LDAPControl **serverctrls, LDAPControl **clientctrls,
51 int timelimit, int sizelimit, int *msgidp );
52 static char *find_right_paren( char *s );
53 static char *put_complex_filter( BerElement *ber, char *str,
54 ber_tag_t tag, int not );
55 static int unescape_filterval( char *str );
56 static int hexchar2int( char c );
57 static int is_valid_attr( char *a );
58 static int put_simple_filter( BerElement *ber, char *str );
59 static int put_substring_filter( BerElement *ber, char *type,
60 char *str );
61 static int put_filter_list( BerElement *ber, char *str );
62 static int nsldapi_search_s( LDAP *ld, const char *base, int scope,
63 const char *filter, char **attrs, int attrsonly,
64 LDAPControl **serverctrls, LDAPControl **clientctrls,
65 struct timeval *localtimeoutp, int timelimit, int sizelimit,
66 LDAPMessage **res );
69 * ldap_search - initiate an ldap search operation. Parameters:
71 * ld LDAP descriptor
72 * base DN of the base object
73 * scope the search scope - one of LDAP_SCOPE_BASE,
74 * LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
75 * filter a string containing the search filter
76 * (e.g., "(|(cn=bob)(sn=bob))")
77 * attrs list of attribute types to return for matches
78 * attrsonly 1 => attributes only 0 => attributes and values
80 * Example:
81 * char *attrs[] = { "mail", "title", 0 };
82 * msgid = ldap_search( ld, "c=us@o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
83 * attrs, attrsonly );
85 int
86 LDAP_CALL
87 ldap_search(
88 LDAP *ld,
89 const char *base,
90 int scope,
91 const char *filter,
92 char **attrs,
93 int attrsonly
96 int msgid;
98 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
100 if ( ldap_search_ext( ld, base, scope, filter, attrs, attrsonly, NULL,
101 NULL, NULL, -1, &msgid ) == LDAP_SUCCESS ) {
102 return( msgid );
103 } else {
104 return( -1 ); /* error is in ld handle */
110 * LDAPv3 extended search.
111 * Returns an LDAP error code.
114 LDAP_CALL
115 ldap_search_ext(
116 LDAP *ld,
117 const char *base,
118 int scope,
119 const char *filter,
120 char **attrs,
121 int attrsonly,
122 LDAPControl **serverctrls,
123 LDAPControl **clientctrls,
124 struct timeval *timeoutp, /* NULL means use ld->ld_timelimit */
125 int sizelimit,
126 int *msgidp
130 * It is an error to pass in a zero'd timeval.
132 if ( timeoutp != NULL && timeoutp->tv_sec == 0 &&
133 timeoutp->tv_usec == 0 ) {
134 if ( ld != NULL ) {
135 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
137 return( LDAP_PARAM_ERROR );
140 return( nsldapi_search( ld, base, scope, filter, attrs, attrsonly,
141 serverctrls, clientctrls,
142 nsldapi_timeval2ldaplimit( timeoutp, -1 ), sizelimit, msgidp ));
147 * Like ldap_search_ext() except an integer timelimit is passed instead of
148 * using the overloaded struct timeval *timeoutp.
150 static int
151 nsldapi_search(
152 LDAP *ld,
153 const char *base,
154 int scope,
155 const char *filter,
156 char **attrs,
157 int attrsonly,
158 LDAPControl **serverctrls,
159 LDAPControl **clientctrls,
160 int timelimit, /* -1 means use ld->ld_timelimit */
161 int sizelimit, /* -1 means use ld->ld_sizelimit */
162 int *msgidp
165 BerElement *ber;
166 int rc, rc_key;
167 unsigned long key; /* XXXmcs: memcache */
169 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
171 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
172 return( LDAP_PARAM_ERROR );
175 if ( base == NULL ) {
176 base = "";
179 if ( filter == NULL ) {
180 filter = "(objectclass=*)";
183 if ( msgidp == NULL || ( scope != LDAP_SCOPE_BASE
184 && scope != LDAP_SCOPE_ONELEVEL && scope != LDAP_SCOPE_SUBTREE )
185 || ( sizelimit < -1 )) {
186 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
187 return( LDAP_PARAM_ERROR );
189 LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
190 *msgidp = ++ld->ld_msgid;
191 LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
194 * XXXmcs: should use cache function pointers to hook in memcache
196 if ( ld->ld_memcache == NULL ) {
197 rc_key = LDAP_NOT_SUPPORTED;
198 } else if (( rc_key = ldap_memcache_createkey( ld, base, scope, filter,
199 attrs, attrsonly, serverctrls, clientctrls, &key)) == LDAP_SUCCESS
200 && ldap_memcache_result( ld, *msgidp, key ) == LDAP_SUCCESS ) {
201 return LDAP_SUCCESS;
204 /* check the cache */
205 if ( ld->ld_cache_on && ld->ld_cache_search != NULL ) {
206 LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
207 if ( (rc = (ld->ld_cache_search)( ld, *msgidp, LDAP_REQ_SEARCH,
208 base, scope, filter, attrs, attrsonly )) != 0 ) {
209 *msgidp = rc;
210 LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
211 return( LDAP_SUCCESS );
213 LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
216 /* caching off or did not find it in the cache - check the net */
217 if (( rc = nsldapi_build_search_req( ld, base, scope, filter, attrs,
218 attrsonly, serverctrls, clientctrls, timelimit, sizelimit,
219 *msgidp, &ber )) != LDAP_SUCCESS ) {
220 return( rc );
223 /* send the message */
224 rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_SEARCH,
225 (char *) base, ber );
228 * XXXmcs: should use cache function pointers to hook in memcache
230 if ( (rc_key == LDAP_SUCCESS) && (rc >= 0) ) {
231 ldap_memcache_new( ld, rc, key, base );
234 *msgidp = rc;
235 return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
240 * Convert a non-NULL timeoutp to a value in seconds that is appropriate to
241 * send in an LDAP search request. If timeoutp is NULL, return defaultvalue.
243 static int
244 nsldapi_timeval2ldaplimit( struct timeval *timeoutp, int defaultvalue )
246 int timelimit;
248 if ( NULL == timeoutp ) {
249 timelimit = defaultvalue;
250 } else if ( timeoutp->tv_sec > 0 ) {
251 timelimit = timeoutp->tv_sec;
252 } else if ( timeoutp->tv_usec > 0 ) {
253 timelimit = 1; /* minimum we can express in LDAP */
254 } else {
256 * both tv_sec and tv_usec are less than one (zero?) so
257 * to maintain compatiblity with our "zero means no limit"
258 * convention we pass no limit to the server.
260 timelimit = 0; /* no limit */
263 return( timelimit );
267 /* returns an LDAP error code and also sets it in ld */
269 nsldapi_build_search_req(
270 LDAP *ld,
271 const char *base,
272 int scope,
273 const char *filter,
274 char **attrs,
275 int attrsonly,
276 LDAPControl **serverctrls,
277 LDAPControl **clientctrls, /* not used for anything yet */
278 int timelimit, /* if -1, ld->ld_timelimit is used */
279 int sizelimit, /* if -1, ld->ld_sizelimit is used */
280 int msgid,
281 BerElement **berp
284 BerElement *ber;
285 int err;
286 char *fdup;
289 * Create the search request. It looks like this:
290 * SearchRequest := [APPLICATION 3] SEQUENCE {
291 * baseObject DistinguishedName,
292 * scope ENUMERATED {
293 * baseObject (0),
294 * singleLevel (1),
295 * wholeSubtree (2)
296 * },
297 * derefAliases ENUMERATED {
298 * neverDerefaliases (0),
299 * derefInSearching (1),
300 * derefFindingBaseObj (2),
301 * alwaysDerefAliases (3)
302 * },
303 * sizelimit INTEGER (0 .. 65535),
304 * timelimit INTEGER (0 .. 65535),
305 * attrsOnly BOOLEAN,
306 * filter Filter,
307 * attributes SEQUENCE OF AttributeType
309 * wrapped in an ldap message.
312 /* create a message to send */
313 if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
314 != LDAP_SUCCESS ) {
315 return( err );
318 if ( base == NULL ) {
319 base = "";
322 if ( sizelimit == -1 ) {
323 sizelimit = ld->ld_sizelimit;
326 if ( timelimit == -1 ) {
327 timelimit = ld->ld_timelimit;
330 #ifdef CLDAP
331 if ( ld->ld_sbp->sb_naddr > 0 ) {
332 err = ber_printf( ber, "{ist{seeiib", msgid,
333 ld->ld_cldapdn, LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
334 sizelimit, timelimit, attrsonly );
335 } else {
336 #endif /* CLDAP */
337 err = ber_printf( ber, "{it{seeiib", msgid,
338 LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
339 sizelimit, timelimit, attrsonly );
340 #ifdef CLDAP
342 #endif /* CLDAP */
344 if ( err == -1 ) {
345 LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
346 ber_free( ber, 1 );
347 return( LDAP_ENCODING_ERROR );
350 fdup = nsldapi_strdup( filter );
351 if (fdup == NULL) {
352 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
353 ber_free( ber, 1 );
354 return( LDAP_NO_MEMORY );
356 err = ldap_put_filter( ber, fdup );
357 NSLDAPI_FREE( fdup );
359 if ( err == -1 ) {
360 LDAP_SET_LDERRNO( ld, LDAP_FILTER_ERROR, NULL, NULL );
361 ber_free( ber, 1 );
362 return( LDAP_FILTER_ERROR );
365 if ( ber_printf( ber, "{v}}", attrs ) == -1 ) {
366 LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
367 ber_free( ber, 1 );
368 return( LDAP_ENCODING_ERROR );
371 if ( (err = nsldapi_put_controls( ld, serverctrls, 1, ber ))
372 != LDAP_SUCCESS ) {
373 ber_free( ber, 1 );
374 return( err );
377 *berp = ber;
378 return( LDAP_SUCCESS );
381 static char *
382 find_right_paren( char *s )
384 int balance, escape;
386 balance = 1;
387 escape = 0;
388 while ( *s && balance ) {
389 if ( escape == 0 ) {
390 if ( *s == '(' )
391 balance++;
392 else if ( *s == ')' )
393 balance--;
395 if ( *s == '\\' && ! escape )
396 escape = 1;
397 else
398 escape = 0;
399 if ( balance )
400 s++;
403 return( *s ? s : NULL );
406 static char *
407 put_complex_filter(
408 BerElement *ber,
409 char *str,
410 ber_tag_t tag,
411 int not
414 char *next;
417 * We have (x(filter)...) with str sitting on
418 * the x. We have to find the paren matching
419 * the one before the x and put the intervening
420 * filters by calling put_filter_list().
423 /* put explicit tag */
424 if ( ber_printf( ber, "t{", tag ) == -1 )
425 return( NULL );
427 str++;
428 if ( (next = find_right_paren( str )) == NULL )
429 return( NULL );
431 *next = '\0';
432 if ( put_filter_list( ber, str ) == -1 )
433 return( NULL );
434 *next++ = ')';
436 /* flush explicit tagged thang */
437 if ( ber_printf( ber, "}" ) == -1 )
438 return( NULL );
440 return( next );
444 ldap_put_filter( BerElement *ber, char *str )
446 char *next;
447 int parens, balance, escape;
450 * A Filter looks like this:
451 * Filter ::= CHOICE {
452 * and [0] SET OF Filter,
453 * or [1] SET OF Filter,
454 * not [2] Filter,
455 * equalityMatch [3] AttributeValueAssertion,
456 * substrings [4] SubstringFilter,
457 * greaterOrEqual [5] AttributeValueAssertion,
458 * lessOrEqual [6] AttributeValueAssertion,
459 * present [7] AttributeType,,
460 * approxMatch [8] AttributeValueAssertion
463 * SubstringFilter ::= SEQUENCE {
464 * type AttributeType,
465 * SEQUENCE OF CHOICE {
466 * initial [0] IA5String,
467 * any [1] IA5String,
468 * final [2] IA5String
471 * Note: tags in a choice are always explicit
474 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
476 parens = 0;
477 while ( *str ) {
478 switch ( *str ) {
479 case '(':
480 str++;
481 parens++;
482 switch ( *str ) {
483 case '&':
484 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
485 0, 0, 0 );
487 if ( (str = put_complex_filter( ber, str,
488 LDAP_FILTER_AND, 0 )) == NULL )
489 return( -1 );
491 parens--;
492 break;
494 case '|':
495 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
496 0, 0, 0 );
498 if ( (str = put_complex_filter( ber, str,
499 LDAP_FILTER_OR, 0 )) == NULL )
500 return( -1 );
502 parens--;
503 break;
505 case '!':
506 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
507 0, 0, 0 );
509 if ( (str = put_complex_filter( ber, str,
510 LDAP_FILTER_NOT, 1 )) == NULL )
511 return( -1 );
513 parens--;
514 break;
516 default:
517 LDAPDebug( LDAP_DEBUG_TRACE,
518 "put_filter: simple\n", 0, 0, 0 );
520 balance = 1;
521 escape = 0;
522 next = str;
523 while ( *next && balance ) {
524 if ( escape == 0 ) {
525 if ( *next == '(' )
526 balance++;
527 else if ( *next == ')' )
528 balance--;
530 if ( *next == '\\' && ! escape )
531 escape = 1;
532 else
533 escape = 0;
534 if ( balance )
535 next++;
537 if ( balance != 0 )
538 return( -1 );
540 *next = '\0';
541 if ( put_simple_filter( ber, str ) == -1 ) {
542 return( -1 );
544 *next++ = ')';
545 str = next;
546 parens--;
547 break;
549 break;
551 case ')':
552 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0,
553 0 );
554 if ( ber_printf( ber, "]" ) == -1 )
555 return( -1 );
556 str++;
557 parens--;
558 break;
560 case ' ':
561 str++;
562 break;
564 default: /* assume it's a simple type=value filter */
565 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0,
566 0 );
567 next = strchr( str, '\0' );
568 if ( put_simple_filter( ber, str ) == -1 ) {
569 return( -1 );
571 str = next;
572 break;
576 return( parens ? -1 : 0 );
581 * Put a list of filters like this "(filter1)(filter2)..."
584 static int
585 put_filter_list( BerElement *ber, char *str )
587 char *next;
588 char save;
590 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 );
592 while ( *str ) {
593 while ( *str && isspace( *str ) )
594 str++;
595 if ( *str == '\0' )
596 break;
598 if ( (next = find_right_paren( str + 1 )) == NULL )
599 return( -1 );
600 save = *++next;
602 /* now we have "(filter)" with str pointing to it */
603 *next = '\0';
604 if ( ldap_put_filter( ber, str ) == -1 )
605 return( -1 );
606 *next = save;
608 str = next;
611 return( 0 );
616 * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
617 * of a filter expression, 0 otherwise. A valid string may contain only
618 * letters, numbers, hyphens, semi-colons, colons and periods. examples:
619 * cn
620 * cn;lang-fr
621 * 1.2.3.4;binary;dynamic
622 * mail;dynamic
623 * cn:dn:1.2.3.4
625 * For compatibility with older servers, we also allow underscores in
626 * attribute types, even through they are not allowed by the LDAPv3 RFCs.
628 static int
629 is_valid_attr( char *a )
631 for ( ; *a; a++ ) {
632 if ( !isascii( *a ) ) {
633 return( 0 );
634 } else if ( !isalnum( *a ) ) {
635 switch ( *a ) {
636 case '-':
637 case '.':
638 case ';':
639 case ':':
640 case '_':
641 break; /* valid */
642 default:
643 return( 0 );
648 return( 1 );
651 static char *
652 find_star( char *s )
654 for ( ; *s; ++s ) {
655 switch ( *s ) {
656 case '*': return s;
657 case '\\':
658 ++s;
659 if ( hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0 ) ++s;
660 default: break;
663 return NULL;
666 static int
667 put_simple_filter( BerElement *ber, char *str )
669 char *s, *s2, *s3, filterop;
670 char *value;
671 ber_uint_t ftype;
672 int rc, len;
673 char *oid; /* for v3 extended filter */
674 int dnattr; /* for v3 extended filter */
676 LDAPDebug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 );
678 rc = -1; /* pessimistic */
680 if (( str = nsldapi_strdup( str )) == NULL ) {
681 return( rc );
684 if ( (s = strchr( str, '=' )) == NULL ) {
685 goto free_and_return;
687 value = s + 1;
688 *s-- = '\0';
689 filterop = *s;
690 if ( filterop == '<' || filterop == '>' || filterop == '~' ||
691 filterop == ':' ) {
692 *s = '\0';
695 if ( ! is_valid_attr( str ) ) {
696 goto free_and_return;
699 switch ( filterop ) {
700 case '<':
701 ftype = LDAP_FILTER_LE;
702 break;
703 case '>':
704 ftype = LDAP_FILTER_GE;
705 break;
706 case '~':
707 ftype = LDAP_FILTER_APPROX;
708 break;
709 case ':': /* extended filter - v3 only */
711 * extended filter looks like this:
713 * [type][':dn'][':'oid]':='value
715 * where one of type or :oid is required.
718 ftype = LDAP_FILTER_EXTENDED;
719 s2 = s3 = NULL;
720 if ( (s2 = strrchr( str, ':' )) == NULL ) {
721 goto free_and_return;
723 if ( strcasecmp( s2, ":dn" ) == 0 ) {
724 oid = NULL;
725 dnattr = 1;
726 *s2 = '\0';
727 } else {
728 oid = s2 + 1;
729 dnattr = 0;
730 *s2 = '\0';
731 if ( (s3 = strrchr( str, ':' )) != NULL ) {
732 if ( strcasecmp( s3, ":dn" ) == 0 ) {
733 dnattr = 1;
734 } else {
735 goto free_and_return;
737 *s3 = '\0';
740 if ( (rc = ber_printf( ber, "t{", ftype )) == -1 ) {
741 goto free_and_return;
743 if ( oid != NULL ) {
744 if ( (rc = ber_printf( ber, "ts", LDAP_TAG_MRA_OID,
745 oid )) == -1 ) {
746 goto free_and_return;
749 if ( *str != '\0' ) {
750 if ( (rc = ber_printf( ber, "ts",
751 LDAP_TAG_MRA_TYPE, str )) == -1 ) {
752 goto free_and_return;
755 if (( len = unescape_filterval( value )) < 0 ||
756 ( rc = ber_printf( ber, "totb}", LDAP_TAG_MRA_VALUE,
757 value, len, LDAP_TAG_MRA_DNATTRS, dnattr )) == -1 ) {
758 goto free_and_return;
760 rc = 0;
761 goto free_and_return;
762 /* break; */
763 default:
764 if ( find_star( value ) == NULL ) {
765 ftype = LDAP_FILTER_EQUALITY;
766 } else if ( strcmp( value, "*" ) == 0 ) {
767 ftype = LDAP_FILTER_PRESENT;
768 } else {
769 rc = put_substring_filter( ber, str, value );
770 goto free_and_return;
772 break;
775 if ( ftype == LDAP_FILTER_PRESENT ) {
776 rc = ber_printf( ber, "ts", ftype, str );
777 } else if (( len = unescape_filterval( value )) >= 0 ) {
778 rc = ber_printf( ber, "t{so}", ftype, str, value, len );
780 if ( rc != -1 ) {
781 rc = 0;
784 free_and_return:
785 NSLDAPI_FREE( str );
786 return( rc );
791 * Undo in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
792 * sequences within the null-terminated string 'val'. The resulting value
793 * may contain null characters.
795 * If 'val' contains invalid escape sequences we return -1.
796 * Otherwise the length of the unescaped value is returned.
798 static int
799 unescape_filterval( char *val )
801 int escape, firstdigit, ival;
802 char *s, *d;
804 escape = 0;
805 for ( s = d = val; *s; s++ ) {
806 if ( escape ) {
808 * first try LDAPv3 escape (hexadecimal) sequence
810 if (( ival = hexchar2int( *s )) < 0 ) {
811 if ( firstdigit ) {
813 * LDAPv2 (RFC1960) escape sequence
815 *d++ = *s;
816 escape = 0;
817 } else {
818 return(-1);
821 if ( firstdigit ) {
822 *d = ( ival<<4 );
823 firstdigit = 0;
824 } else {
825 *d++ |= ival;
826 escape = 0;
829 } else if ( *s != '\\' ) {
830 *d++ = *s;
831 escape = 0;
833 } else {
834 escape = 1;
835 firstdigit = 1;
839 return( d - val );
844 * convert character 'c' that represents a hexadecimal digit to an integer.
845 * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
846 * otherwise the converted value is returned.
848 static int
849 hexchar2int( char c )
851 if ( c >= '0' && c <= '9' ) {
852 return( c - '0' );
854 if ( c >= 'A' && c <= 'F' ) {
855 return( c - 'A' + 10 );
857 if ( c >= 'a' && c <= 'f' ) {
858 return( c - 'a' + 10 );
860 return( -1 );
863 static int
864 put_substring_filter( BerElement *ber, char *type, char *val )
866 char *nextstar, gotstar = 0;
867 ber_uint_t ftype;
868 int len;
870 LDAPDebug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type,
871 val, 0 );
873 if ( ber_printf( ber, "t{s{", LDAP_FILTER_SUBSTRINGS, type ) == -1 ) {
874 return( -1 );
877 for ( ; val != NULL; val = nextstar ) {
878 if ( (nextstar = find_star( val )) != NULL ) {
879 *nextstar++ = '\0';
882 if ( gotstar == 0 ) {
883 ftype = LDAP_SUBSTRING_INITIAL;
884 } else if ( nextstar == NULL ) {
885 ftype = LDAP_SUBSTRING_FINAL;
886 } else {
887 ftype = LDAP_SUBSTRING_ANY;
889 if ( *val != '\0' ) {
890 if (( len = unescape_filterval( val )) < 0 ||
891 ber_printf( ber, "to", ftype, val, len ) == -1 ) {
892 return( -1 );
896 gotstar = 1;
899 if ( ber_printf( ber, "}}" ) == -1 ) {
900 return( -1 );
903 return( 0 );
907 LDAP_CALL
908 ldap_search_st(
909 LDAP *ld,
910 const char *base,
911 int scope,
912 const char *filter,
913 char **attrs,
914 int attrsonly,
915 struct timeval *timeout,
916 LDAPMessage **res
919 return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly,
920 NULL, NULL, timeout, -1, -1, res ));
924 LDAP_CALL
925 ldap_search_s(
926 LDAP *ld,
927 const char *base,
928 int scope,
929 const char *filter,
930 char **attrs,
931 int attrsonly,
932 LDAPMessage **res
935 return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly,
936 NULL, NULL, NULL, -1, -1, res ));
939 int LDAP_CALL
940 ldap_search_ext_s(
941 LDAP *ld,
942 const char *base,
943 int scope,
944 const char *filter,
945 char **attrs,
946 int attrsonly,
947 LDAPControl **serverctrls,
948 LDAPControl **clientctrls,
949 struct timeval *timeoutp,
950 int sizelimit,
951 LDAPMessage **res
954 return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly,
955 serverctrls, clientctrls, timeoutp,
956 nsldapi_timeval2ldaplimit( timeoutp, -1 ), sizelimit, res ));
960 static int
961 nsldapi_search_s(
962 LDAP *ld,
963 const char *base,
964 int scope,
965 const char *filter,
966 char **attrs,
967 int attrsonly,
968 LDAPControl **serverctrls,
969 LDAPControl **clientctrls,
970 struct timeval *localtimeoutp,
971 int timelimit, /* -1 means use ld->ld_timelimit */
972 int sizelimit, /* -1 means use ld->ld_sizelimit */
973 LDAPMessage **res
976 int err, msgid;
979 * It is an error to pass in a zero'd timeval.
981 if ( localtimeoutp != NULL && localtimeoutp->tv_sec == 0 &&
982 localtimeoutp->tv_usec == 0 ) {
983 if ( ld != NULL ) {
984 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
986 if ( res != NULL ) {
987 *res = NULL;
989 return( LDAP_PARAM_ERROR );
992 if (( err = nsldapi_search( ld, base, scope, filter, attrs, attrsonly,
993 serverctrls, clientctrls, timelimit, sizelimit, &msgid ))
994 != LDAP_SUCCESS ) {
995 if ( res != NULL ) {
996 *res = NULL;
998 return( err );
1001 if ( ldap_result( ld, msgid, 1, localtimeoutp, res ) == -1 ) {
1003 * Error. ldap_result() sets *res to NULL for us.
1005 return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
1008 if ( LDAP_GET_LDERRNO( ld, NULL, NULL ) == LDAP_TIMEOUT ) {
1009 (void) ldap_abandon( ld, msgid );
1010 err = LDAP_TIMEOUT;
1011 LDAP_SET_LDERRNO( ld, err, NULL, NULL );
1012 if ( res != NULL ) {
1013 *res = NULL;
1015 return( err );
1018 return( ldap_result2error( ld, *res, 0 ) );