dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libldap5 / sources / ldap / common / search.c
blob6cfc359de6a27c43ebb196ab7faccd1d28c7b6bb
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 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
40 #endif
42 #include "ldap-int.h"
44 static int nsldapi_timeval2ldaplimit( struct timeval *timeoutp,
45 int defaultvalue );
46 static int nsldapi_search( LDAP *ld, const char *base, int scope,
47 const char *filter, char **attrs, int attrsonly,
48 LDAPControl **serverctrls, LDAPControl **clientctrls,
49 int timelimit, int sizelimit, int *msgidp );
50 static char *find_right_paren( char *s );
51 static char *put_complex_filter( BerElement *ber, char *str,
52 ber_tag_t tag, int not );
53 static int unescape_filterval( char *str );
54 static int hexchar2int( char c );
55 static int is_valid_attr( char *a );
56 static int put_simple_filter( BerElement *ber, char *str );
57 static int put_substring_filter( BerElement *ber, char *type,
58 char *str );
59 static int put_filter_list( BerElement *ber, char *str );
60 static int nsldapi_search_s( LDAP *ld, const char *base, int scope,
61 const char *filter, char **attrs, int attrsonly,
62 LDAPControl **serverctrls, LDAPControl **clientctrls,
63 struct timeval *localtimeoutp, int timelimit, int sizelimit,
64 LDAPMessage **res );
67 * ldap_search - initiate an ldap search operation. Parameters:
69 * ld LDAP descriptor
70 * base DN of the base object
71 * scope the search scope - one of LDAP_SCOPE_BASE,
72 * LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
73 * filter a string containing the search filter
74 * (e.g., "(|(cn=bob)(sn=bob))")
75 * attrs list of attribute types to return for matches
76 * attrsonly 1 => attributes only 0 => attributes and values
78 * Example:
79 * char *attrs[] = { "mail", "title", 0 };
80 * msgid = ldap_search( ld, "c=us@o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
81 * attrs, attrsonly );
83 int
84 LDAP_CALL
85 ldap_search(
86 LDAP *ld,
87 const char *base,
88 int scope,
89 const char *filter,
90 char **attrs,
91 int attrsonly
94 int msgid;
96 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
98 if ( ldap_search_ext( ld, base, scope, filter, attrs, attrsonly, NULL,
99 NULL, NULL, -1, &msgid ) == LDAP_SUCCESS ) {
100 return( msgid );
101 } else {
102 return( -1 ); /* error is in ld handle */
108 * LDAPv3 extended search.
109 * Returns an LDAP error code.
112 LDAP_CALL
113 ldap_search_ext(
114 LDAP *ld,
115 const char *base,
116 int scope,
117 const char *filter,
118 char **attrs,
119 int attrsonly,
120 LDAPControl **serverctrls,
121 LDAPControl **clientctrls,
122 struct timeval *timeoutp, /* NULL means use ld->ld_timelimit */
123 int sizelimit,
124 int *msgidp
128 * It is an error to pass in a zero'd timeval.
130 if ( timeoutp != NULL && timeoutp->tv_sec == 0 &&
131 timeoutp->tv_usec == 0 ) {
132 if ( ld != NULL ) {
133 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
135 return( LDAP_PARAM_ERROR );
138 return( nsldapi_search( ld, base, scope, filter, attrs, attrsonly,
139 serverctrls, clientctrls,
140 nsldapi_timeval2ldaplimit( timeoutp, -1 ), sizelimit, msgidp ));
145 * Like ldap_search_ext() except an integer timelimit is passed instead of
146 * using the overloaded struct timeval *timeoutp.
148 static int
149 nsldapi_search(
150 LDAP *ld,
151 const char *base,
152 int scope,
153 const char *filter,
154 char **attrs,
155 int attrsonly,
156 LDAPControl **serverctrls,
157 LDAPControl **clientctrls,
158 int timelimit, /* -1 means use ld->ld_timelimit */
159 int sizelimit, /* -1 means use ld->ld_sizelimit */
160 int *msgidp
163 BerElement *ber;
164 int rc, rc_key;
165 unsigned long key; /* XXXmcs: memcache */
167 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
169 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
170 return( LDAP_PARAM_ERROR );
173 if ( base == NULL ) {
174 base = "";
177 if ( filter == NULL ) {
178 filter = "(objectclass=*)";
181 if ( msgidp == NULL || ( scope != LDAP_SCOPE_BASE
182 && scope != LDAP_SCOPE_ONELEVEL && scope != LDAP_SCOPE_SUBTREE )
183 || ( sizelimit < -1 )) {
184 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
185 return( LDAP_PARAM_ERROR );
187 LDAP_MUTEX_LOCK( ld, LDAP_MSGID_LOCK );
188 *msgidp = ++ld->ld_msgid;
189 LDAP_MUTEX_UNLOCK( ld, LDAP_MSGID_LOCK );
192 * XXXmcs: should use cache function pointers to hook in memcache
194 if ( ld->ld_memcache == NULL ) {
195 rc_key = LDAP_NOT_SUPPORTED;
196 } else if (( rc_key = ldap_memcache_createkey( ld, base, scope, filter,
197 attrs, attrsonly, serverctrls, clientctrls, &key)) == LDAP_SUCCESS
198 && ldap_memcache_result( ld, *msgidp, key ) == LDAP_SUCCESS ) {
199 return LDAP_SUCCESS;
202 /* check the cache */
203 if ( ld->ld_cache_on && ld->ld_cache_search != NULL ) {
204 LDAP_MUTEX_LOCK( ld, LDAP_CACHE_LOCK );
205 if ( (rc = (ld->ld_cache_search)( ld, *msgidp, LDAP_REQ_SEARCH,
206 base, scope, filter, attrs, attrsonly )) != 0 ) {
207 *msgidp = rc;
208 LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
209 return( LDAP_SUCCESS );
211 LDAP_MUTEX_UNLOCK( ld, LDAP_CACHE_LOCK );
214 /* caching off or did not find it in the cache - check the net */
215 if (( rc = nsldapi_build_search_req( ld, base, scope, filter, attrs,
216 attrsonly, serverctrls, clientctrls, timelimit, sizelimit,
217 *msgidp, &ber )) != LDAP_SUCCESS ) {
218 return( rc );
221 /* send the message */
222 rc = nsldapi_send_initial_request( ld, *msgidp, LDAP_REQ_SEARCH,
223 (char *) base, ber );
226 * XXXmcs: should use cache function pointers to hook in memcache
228 if ( (rc_key == LDAP_SUCCESS) && (rc >= 0) ) {
229 ldap_memcache_new( ld, rc, key, base );
232 *msgidp = rc;
233 return( rc < 0 ? LDAP_GET_LDERRNO( ld, NULL, NULL ) : LDAP_SUCCESS );
238 * Convert a non-NULL timeoutp to a value in seconds that is appropriate to
239 * send in an LDAP search request. If timeoutp is NULL, return defaultvalue.
241 static int
242 nsldapi_timeval2ldaplimit( struct timeval *timeoutp, int defaultvalue )
244 int timelimit;
246 if ( NULL == timeoutp ) {
247 timelimit = defaultvalue;
248 } else if ( timeoutp->tv_sec > 0 ) {
249 timelimit = timeoutp->tv_sec;
250 } else if ( timeoutp->tv_usec > 0 ) {
251 timelimit = 1; /* minimum we can express in LDAP */
252 } else {
254 * both tv_sec and tv_usec are less than one (zero?) so
255 * to maintain compatiblity with our "zero means no limit"
256 * convention we pass no limit to the server.
258 timelimit = 0; /* no limit */
261 return( timelimit );
265 /* returns an LDAP error code and also sets it in ld */
267 nsldapi_build_search_req(
268 LDAP *ld,
269 const char *base,
270 int scope,
271 const char *filter,
272 char **attrs,
273 int attrsonly,
274 LDAPControl **serverctrls,
275 LDAPControl **clientctrls, /* not used for anything yet */
276 int timelimit, /* if -1, ld->ld_timelimit is used */
277 int sizelimit, /* if -1, ld->ld_sizelimit is used */
278 int msgid,
279 BerElement **berp
282 BerElement *ber;
283 int err;
284 char *fdup;
287 * Create the search request. It looks like this:
288 * SearchRequest := [APPLICATION 3] SEQUENCE {
289 * baseObject DistinguishedName,
290 * scope ENUMERATED {
291 * baseObject (0),
292 * singleLevel (1),
293 * wholeSubtree (2)
294 * },
295 * derefAliases ENUMERATED {
296 * neverDerefaliases (0),
297 * derefInSearching (1),
298 * derefFindingBaseObj (2),
299 * alwaysDerefAliases (3)
300 * },
301 * sizelimit INTEGER (0 .. 65535),
302 * timelimit INTEGER (0 .. 65535),
303 * attrsOnly BOOLEAN,
304 * filter Filter,
305 * attributes SEQUENCE OF AttributeType
307 * wrapped in an ldap message.
310 /* create a message to send */
311 if (( err = nsldapi_alloc_ber_with_options( ld, &ber ))
312 != LDAP_SUCCESS ) {
313 return( err );
316 if ( base == NULL ) {
317 base = "";
320 if ( sizelimit == -1 ) {
321 sizelimit = ld->ld_sizelimit;
324 if ( timelimit == -1 ) {
325 timelimit = ld->ld_timelimit;
328 #ifdef CLDAP
329 if ( ld->ld_sbp->sb_naddr > 0 ) {
330 err = ber_printf( ber, "{ist{seeiib", msgid,
331 ld->ld_cldapdn, LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
332 sizelimit, timelimit, attrsonly );
333 } else {
334 #endif /* CLDAP */
335 err = ber_printf( ber, "{it{seeiib", msgid,
336 LDAP_REQ_SEARCH, base, scope, ld->ld_deref,
337 sizelimit, timelimit, attrsonly );
338 #ifdef CLDAP
340 #endif /* CLDAP */
342 if ( err == -1 ) {
343 LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
344 ber_free( ber, 1 );
345 return( LDAP_ENCODING_ERROR );
348 fdup = nsldapi_strdup( filter );
349 if (fdup == NULL) {
350 LDAP_SET_LDERRNO( ld, LDAP_NO_MEMORY, NULL, NULL );
351 ber_free( ber, 1 );
352 return( LDAP_NO_MEMORY );
354 err = ldap_put_filter( ber, fdup );
355 NSLDAPI_FREE( fdup );
357 if ( err == -1 ) {
358 LDAP_SET_LDERRNO( ld, LDAP_FILTER_ERROR, NULL, NULL );
359 ber_free( ber, 1 );
360 return( LDAP_FILTER_ERROR );
363 if ( ber_printf( ber, "{v}}", attrs ) == -1 ) {
364 LDAP_SET_LDERRNO( ld, LDAP_ENCODING_ERROR, NULL, NULL );
365 ber_free( ber, 1 );
366 return( LDAP_ENCODING_ERROR );
369 if ( (err = nsldapi_put_controls( ld, serverctrls, 1, ber ))
370 != LDAP_SUCCESS ) {
371 ber_free( ber, 1 );
372 return( err );
375 *berp = ber;
376 return( LDAP_SUCCESS );
379 static char *
380 find_right_paren( char *s )
382 int balance, escape;
384 balance = 1;
385 escape = 0;
386 while ( *s && balance ) {
387 if ( escape == 0 ) {
388 if ( *s == '(' )
389 balance++;
390 else if ( *s == ')' )
391 balance--;
393 if ( *s == '\\' && ! escape )
394 escape = 1;
395 else
396 escape = 0;
397 if ( balance )
398 s++;
401 return( *s ? s : NULL );
404 static char *
405 put_complex_filter(
406 BerElement *ber,
407 char *str,
408 ber_tag_t tag,
409 int not
412 char *next;
415 * We have (x(filter)...) with str sitting on
416 * the x. We have to find the paren matching
417 * the one before the x and put the intervening
418 * filters by calling put_filter_list().
421 /* put explicit tag */
422 if ( ber_printf( ber, "t{", tag ) == -1 )
423 return( NULL );
425 str++;
426 if ( (next = find_right_paren( str )) == NULL )
427 return( NULL );
429 *next = '\0';
430 if ( put_filter_list( ber, str ) == -1 )
431 return( NULL );
432 *next++ = ')';
434 /* flush explicit tagged thang */
435 if ( ber_printf( ber, "}" ) == -1 )
436 return( NULL );
438 return( next );
442 ldap_put_filter( BerElement *ber, char *str )
444 char *next;
445 int parens, balance, escape;
448 * A Filter looks like this:
449 * Filter ::= CHOICE {
450 * and [0] SET OF Filter,
451 * or [1] SET OF Filter,
452 * not [2] Filter,
453 * equalityMatch [3] AttributeValueAssertion,
454 * substrings [4] SubstringFilter,
455 * greaterOrEqual [5] AttributeValueAssertion,
456 * lessOrEqual [6] AttributeValueAssertion,
457 * present [7] AttributeType,,
458 * approxMatch [8] AttributeValueAssertion
461 * SubstringFilter ::= SEQUENCE {
462 * type AttributeType,
463 * SEQUENCE OF CHOICE {
464 * initial [0] IA5String,
465 * any [1] IA5String,
466 * final [2] IA5String
469 * Note: tags in a choice are always explicit
472 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
474 parens = 0;
475 while ( *str ) {
476 switch ( *str ) {
477 case '(':
478 str++;
479 parens++;
480 switch ( *str ) {
481 case '&':
482 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
483 0, 0, 0 );
485 if ( (str = put_complex_filter( ber, str,
486 LDAP_FILTER_AND, 0 )) == NULL )
487 return( -1 );
489 parens--;
490 break;
492 case '|':
493 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
494 0, 0, 0 );
496 if ( (str = put_complex_filter( ber, str,
497 LDAP_FILTER_OR, 0 )) == NULL )
498 return( -1 );
500 parens--;
501 break;
503 case '!':
504 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
505 0, 0, 0 );
507 if ( (str = put_complex_filter( ber, str,
508 LDAP_FILTER_NOT, 1 )) == NULL )
509 return( -1 );
511 parens--;
512 break;
514 default:
515 LDAPDebug( LDAP_DEBUG_TRACE,
516 "put_filter: simple\n", 0, 0, 0 );
518 balance = 1;
519 escape = 0;
520 next = str;
521 while ( *next && balance ) {
522 if ( escape == 0 ) {
523 if ( *next == '(' )
524 balance++;
525 else if ( *next == ')' )
526 balance--;
528 if ( *next == '\\' && ! escape )
529 escape = 1;
530 else
531 escape = 0;
532 if ( balance )
533 next++;
535 if ( balance != 0 )
536 return( -1 );
538 *next = '\0';
539 if ( put_simple_filter( ber, str ) == -1 ) {
540 return( -1 );
542 *next++ = ')';
543 str = next;
544 parens--;
545 break;
547 break;
549 case ')':
550 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0,
551 0 );
552 if ( ber_printf( ber, "]" ) == -1 )
553 return( -1 );
554 str++;
555 parens--;
556 break;
558 case ' ':
559 str++;
560 break;
562 default: /* assume it's a simple type=value filter */
563 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0,
564 0 );
565 next = strchr( str, '\0' );
566 if ( put_simple_filter( ber, str ) == -1 ) {
567 return( -1 );
569 str = next;
570 break;
574 return( parens ? -1 : 0 );
579 * Put a list of filters like this "(filter1)(filter2)..."
582 static int
583 put_filter_list( BerElement *ber, char *str )
585 char *next;
586 char save;
588 LDAPDebug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 );
590 while ( *str ) {
591 while ( *str && isspace( *str ) )
592 str++;
593 if ( *str == '\0' )
594 break;
596 if ( (next = find_right_paren( str + 1 )) == NULL )
597 return( -1 );
598 save = *++next;
600 /* now we have "(filter)" with str pointing to it */
601 *next = '\0';
602 if ( ldap_put_filter( ber, str ) == -1 )
603 return( -1 );
604 *next = save;
606 str = next;
609 return( 0 );
614 * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
615 * of a filter expression, 0 otherwise. A valid string may contain only
616 * letters, numbers, hyphens, semi-colons, colons and periods. examples:
617 * cn
618 * cn;lang-fr
619 * 1.2.3.4;binary;dynamic
620 * mail;dynamic
621 * cn:dn:1.2.3.4
623 * For compatibility with older servers, we also allow underscores in
624 * attribute types, even through they are not allowed by the LDAPv3 RFCs.
626 static int
627 is_valid_attr( char *a )
629 for ( ; *a; a++ ) {
630 if ( !isascii( *a ) ) {
631 return( 0 );
632 } else if ( !isalnum( *a ) ) {
633 switch ( *a ) {
634 case '-':
635 case '.':
636 case ';':
637 case ':':
638 case '_':
639 break; /* valid */
640 default:
641 return( 0 );
646 return( 1 );
649 static char *
650 find_star( char *s )
652 for ( ; *s; ++s ) {
653 switch ( *s ) {
654 case '*': return s;
655 case '\\':
656 ++s;
657 if ( hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0 ) ++s;
658 default: break;
661 return NULL;
664 static int
665 put_simple_filter( BerElement *ber, char *str )
667 char *s, *s2, *s3, filterop;
668 char *value;
669 ber_uint_t ftype;
670 int rc, len;
671 char *oid; /* for v3 extended filter */
672 int dnattr; /* for v3 extended filter */
674 LDAPDebug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 );
676 rc = -1; /* pessimistic */
678 if (( str = nsldapi_strdup( str )) == NULL ) {
679 return( rc );
682 if ( (s = strchr( str, '=' )) == NULL ) {
683 goto free_and_return;
685 value = s + 1;
686 *s-- = '\0';
687 filterop = *s;
688 if ( filterop == '<' || filterop == '>' || filterop == '~' ||
689 filterop == ':' ) {
690 *s = '\0';
693 if ( ! is_valid_attr( str ) ) {
694 goto free_and_return;
697 switch ( filterop ) {
698 case '<':
699 ftype = LDAP_FILTER_LE;
700 break;
701 case '>':
702 ftype = LDAP_FILTER_GE;
703 break;
704 case '~':
705 ftype = LDAP_FILTER_APPROX;
706 break;
707 case ':': /* extended filter - v3 only */
709 * extended filter looks like this:
711 * [type][':dn'][':'oid]':='value
713 * where one of type or :oid is required.
716 ftype = LDAP_FILTER_EXTENDED;
717 s2 = s3 = NULL;
718 if ( (s2 = strrchr( str, ':' )) == NULL ) {
719 goto free_and_return;
721 if ( strcasecmp( s2, ":dn" ) == 0 ) {
722 oid = NULL;
723 dnattr = 1;
724 *s2 = '\0';
725 } else {
726 oid = s2 + 1;
727 dnattr = 0;
728 *s2 = '\0';
729 if ( (s3 = strrchr( str, ':' )) != NULL ) {
730 if ( strcasecmp( s3, ":dn" ) == 0 ) {
731 dnattr = 1;
732 } else {
733 goto free_and_return;
735 *s3 = '\0';
738 if ( (rc = ber_printf( ber, "t{", ftype )) == -1 ) {
739 goto free_and_return;
741 if ( oid != NULL ) {
742 if ( (rc = ber_printf( ber, "ts", LDAP_TAG_MRA_OID,
743 oid )) == -1 ) {
744 goto free_and_return;
747 if ( *str != '\0' ) {
748 if ( (rc = ber_printf( ber, "ts",
749 LDAP_TAG_MRA_TYPE, str )) == -1 ) {
750 goto free_and_return;
753 if (( len = unescape_filterval( value )) < 0 ||
754 ( rc = ber_printf( ber, "totb}", LDAP_TAG_MRA_VALUE,
755 value, len, LDAP_TAG_MRA_DNATTRS, dnattr )) == -1 ) {
756 goto free_and_return;
758 rc = 0;
759 goto free_and_return;
760 /* break; */
761 default:
762 if ( find_star( value ) == NULL ) {
763 ftype = LDAP_FILTER_EQUALITY;
764 } else if ( strcmp( value, "*" ) == 0 ) {
765 ftype = LDAP_FILTER_PRESENT;
766 } else {
767 rc = put_substring_filter( ber, str, value );
768 goto free_and_return;
770 break;
773 if ( ftype == LDAP_FILTER_PRESENT ) {
774 rc = ber_printf( ber, "ts", ftype, str );
775 } else if (( len = unescape_filterval( value )) >= 0 ) {
776 rc = ber_printf( ber, "t{so}", ftype, str, value, len );
778 if ( rc != -1 ) {
779 rc = 0;
782 free_and_return:
783 NSLDAPI_FREE( str );
784 return( rc );
789 * Undo in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
790 * sequences within the null-terminated string 'val'. The resulting value
791 * may contain null characters.
793 * If 'val' contains invalid escape sequences we return -1.
794 * Otherwise the length of the unescaped value is returned.
796 static int
797 unescape_filterval( char *val )
799 int escape, firstdigit, ival;
800 char *s, *d;
802 escape = 0;
803 for ( s = d = val; *s; s++ ) {
804 if ( escape ) {
806 * first try LDAPv3 escape (hexadecimal) sequence
808 if (( ival = hexchar2int( *s )) < 0 ) {
809 if ( firstdigit ) {
811 * LDAPv2 (RFC1960) escape sequence
813 *d++ = *s;
814 escape = 0;
815 } else {
816 return(-1);
819 if ( firstdigit ) {
820 *d = ( ival<<4 );
821 firstdigit = 0;
822 } else {
823 *d++ |= ival;
824 escape = 0;
827 } else if ( *s != '\\' ) {
828 *d++ = *s;
829 escape = 0;
831 } else {
832 escape = 1;
833 firstdigit = 1;
837 return( d - val );
842 * convert character 'c' that represents a hexadecimal digit to an integer.
843 * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
844 * otherwise the converted value is returned.
846 static int
847 hexchar2int( char c )
849 if ( c >= '0' && c <= '9' ) {
850 return( c - '0' );
852 if ( c >= 'A' && c <= 'F' ) {
853 return( c - 'A' + 10 );
855 if ( c >= 'a' && c <= 'f' ) {
856 return( c - 'a' + 10 );
858 return( -1 );
861 static int
862 put_substring_filter( BerElement *ber, char *type, char *val )
864 char *nextstar, gotstar = 0;
865 ber_uint_t ftype;
866 int len;
868 LDAPDebug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type,
869 val, 0 );
871 if ( ber_printf( ber, "t{s{", LDAP_FILTER_SUBSTRINGS, type ) == -1 ) {
872 return( -1 );
875 for ( ; val != NULL; val = nextstar ) {
876 if ( (nextstar = find_star( val )) != NULL ) {
877 *nextstar++ = '\0';
880 if ( gotstar == 0 ) {
881 ftype = LDAP_SUBSTRING_INITIAL;
882 } else if ( nextstar == NULL ) {
883 ftype = LDAP_SUBSTRING_FINAL;
884 } else {
885 ftype = LDAP_SUBSTRING_ANY;
887 if ( *val != '\0' ) {
888 if (( len = unescape_filterval( val )) < 0 ||
889 ber_printf( ber, "to", ftype, val, len ) == -1 ) {
890 return( -1 );
894 gotstar = 1;
897 if ( ber_printf( ber, "}}" ) == -1 ) {
898 return( -1 );
901 return( 0 );
905 LDAP_CALL
906 ldap_search_st(
907 LDAP *ld,
908 const char *base,
909 int scope,
910 const char *filter,
911 char **attrs,
912 int attrsonly,
913 struct timeval *timeout,
914 LDAPMessage **res
917 return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly,
918 NULL, NULL, timeout, -1, -1, res ));
922 LDAP_CALL
923 ldap_search_s(
924 LDAP *ld,
925 const char *base,
926 int scope,
927 const char *filter,
928 char **attrs,
929 int attrsonly,
930 LDAPMessage **res
933 return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly,
934 NULL, NULL, NULL, -1, -1, res ));
937 int LDAP_CALL
938 ldap_search_ext_s(
939 LDAP *ld,
940 const char *base,
941 int scope,
942 const char *filter,
943 char **attrs,
944 int attrsonly,
945 LDAPControl **serverctrls,
946 LDAPControl **clientctrls,
947 struct timeval *timeoutp,
948 int sizelimit,
949 LDAPMessage **res
952 return( nsldapi_search_s( ld, base, scope, filter, attrs, attrsonly,
953 serverctrls, clientctrls, timeoutp,
954 nsldapi_timeval2ldaplimit( timeoutp, -1 ), sizelimit, res ));
958 static int
959 nsldapi_search_s(
960 LDAP *ld,
961 const char *base,
962 int scope,
963 const char *filter,
964 char **attrs,
965 int attrsonly,
966 LDAPControl **serverctrls,
967 LDAPControl **clientctrls,
968 struct timeval *localtimeoutp,
969 int timelimit, /* -1 means use ld->ld_timelimit */
970 int sizelimit, /* -1 means use ld->ld_sizelimit */
971 LDAPMessage **res
974 int err, msgid;
977 * It is an error to pass in a zero'd timeval.
979 if ( localtimeoutp != NULL && localtimeoutp->tv_sec == 0 &&
980 localtimeoutp->tv_usec == 0 ) {
981 if ( ld != NULL ) {
982 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
984 if ( res != NULL ) {
985 *res = NULL;
987 return( LDAP_PARAM_ERROR );
990 if (( err = nsldapi_search( ld, base, scope, filter, attrs, attrsonly,
991 serverctrls, clientctrls, timelimit, sizelimit, &msgid ))
992 != LDAP_SUCCESS ) {
993 if ( res != NULL ) {
994 *res = NULL;
996 return( err );
999 if ( ldap_result( ld, msgid, 1, localtimeoutp, res ) == -1 ) {
1001 * Error. ldap_result() sets *res to NULL for us.
1003 return( LDAP_GET_LDERRNO( ld, NULL, NULL ) );
1006 if ( LDAP_GET_LDERRNO( ld, NULL, NULL ) == LDAP_TIMEOUT ) {
1007 (void) ldap_abandon( ld, msgid );
1008 err = LDAP_TIMEOUT;
1009 LDAP_SET_LDERRNO( ld, err, NULL, NULL );
1010 if ( res != NULL ) {
1011 *res = NULL;
1013 return( err );
1016 return( ldap_result2error( ld, *res, 0 ) );