1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2021 The OpenLDAP Foundation.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
10 *
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
14 */
15 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
16 * All rights reserved.
17 */
18
19 #include "portable.h"
20
21 #include <stdio.h>
22
23 #include <ac/stdlib.h>
24
25 #include <ac/socket.h>
26 #include <ac/string.h>
27 #include <ac/time.h>
28
29 #include "ldap-int.h"
30 #include "ldap_log.h"
31
32 /*
33 * ldap_search_ext - initiate an ldap search operation.
34 *
35 * Parameters:
36 *
37 * ld LDAP descriptor
38 * base DN of the base object
39 * scope the search scope - one of
40 * LDAP_SCOPE_BASE (baseObject),
41 * LDAP_SCOPE_ONELEVEL (oneLevel),
42 * LDAP_SCOPE_SUBTREE (subtree), or
43 * LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension
44 * filter a string containing the search filter
45 * (e.g., "(|(cn=bob)(sn=bob))")
46 * attrs list of attribute types to return for matches
47 * attrsonly 1 => attributes only 0 => attributes and values
48 *
49 * Example:
50 * char *attrs[] = { "mail", "title", 0 };
51 * ldap_search_ext( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
52 * attrs, attrsonly, sctrls, ctrls, timeout, sizelimit,
53 * &msgid );
54 */
55 int
ldap_search_ext(LDAP * ld,LDAP_CONST char * base,int scope,LDAP_CONST char * filter,char ** attrs,int attrsonly,LDAPControl ** sctrls,LDAPControl ** cctrls,struct timeval * timeout,int sizelimit,int * msgidp)56 ldap_search_ext(
57 LDAP *ld,
58 LDAP_CONST char *base,
59 int scope,
60 LDAP_CONST char *filter,
61 char **attrs,
62 int attrsonly,
63 LDAPControl **sctrls,
64 LDAPControl **cctrls,
65 struct timeval *timeout,
66 int sizelimit,
67 int *msgidp )
68 {
69 return ldap_pvt_search( ld, base, scope, filter, attrs,
70 attrsonly, sctrls, cctrls, timeout, sizelimit, -1, msgidp );
71 }
72
73 int
ldap_pvt_search(LDAP * ld,LDAP_CONST char * base,int scope,LDAP_CONST char * filter,char ** attrs,int attrsonly,LDAPControl ** sctrls,LDAPControl ** cctrls,struct timeval * timeout,int sizelimit,int deref,int * msgidp)74 ldap_pvt_search(
75 LDAP *ld,
76 LDAP_CONST char *base,
77 int scope,
78 LDAP_CONST char *filter,
79 char **attrs,
80 int attrsonly,
81 LDAPControl **sctrls,
82 LDAPControl **cctrls,
83 struct timeval *timeout,
84 int sizelimit,
85 int deref,
86 int *msgidp )
87 {
88 int rc;
89 BerElement *ber;
90 int timelimit;
91 ber_int_t id;
92
93 Debug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
94
95 assert( ld != NULL );
96 assert( LDAP_VALID( ld ) );
97
98 /* check client controls */
99 rc = ldap_int_client_controls( ld, cctrls );
100 if( rc != LDAP_SUCCESS ) return rc;
101
102 /*
103 * if timeout is provided, both tv_sec and tv_usec must
104 * not be zero
105 */
106 if( timeout != NULL ) {
107 if( timeout->tv_sec == 0 && timeout->tv_usec == 0 ) {
108 return LDAP_PARAM_ERROR;
109 }
110
111 /* timelimit must be non-zero if timeout is provided */
112 timelimit = timeout->tv_sec != 0 ? timeout->tv_sec : 1;
113
114 } else {
115 /* no timeout, no timelimit */
116 timelimit = -1;
117 }
118
119 ber = ldap_build_search_req( ld, base, scope, filter, attrs,
120 attrsonly, sctrls, cctrls, timelimit, sizelimit, deref, &id );
121
122 if ( ber == NULL ) {
123 return ld->ld_errno;
124 }
125
126
127 /* send the message */
128 *msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id );
129
130 if( *msgidp < 0 )
131 return ld->ld_errno;
132
133 return LDAP_SUCCESS;
134 }
135
136 int
ldap_search_ext_s(LDAP * ld,LDAP_CONST char * base,int scope,LDAP_CONST char * filter,char ** attrs,int attrsonly,LDAPControl ** sctrls,LDAPControl ** cctrls,struct timeval * timeout,int sizelimit,LDAPMessage ** res)137 ldap_search_ext_s(
138 LDAP *ld,
139 LDAP_CONST char *base,
140 int scope,
141 LDAP_CONST char *filter,
142 char **attrs,
143 int attrsonly,
144 LDAPControl **sctrls,
145 LDAPControl **cctrls,
146 struct timeval *timeout,
147 int sizelimit,
148 LDAPMessage **res )
149 {
150 return ldap_pvt_search_s( ld, base, scope, filter, attrs,
151 attrsonly, sctrls, cctrls, timeout, sizelimit, -1, res );
152 }
153
154 int
ldap_pvt_search_s(LDAP * ld,LDAP_CONST char * base,int scope,LDAP_CONST char * filter,char ** attrs,int attrsonly,LDAPControl ** sctrls,LDAPControl ** cctrls,struct timeval * timeout,int sizelimit,int deref,LDAPMessage ** res)155 ldap_pvt_search_s(
156 LDAP *ld,
157 LDAP_CONST char *base,
158 int scope,
159 LDAP_CONST char *filter,
160 char **attrs,
161 int attrsonly,
162 LDAPControl **sctrls,
163 LDAPControl **cctrls,
164 struct timeval *timeout,
165 int sizelimit,
166 int deref,
167 LDAPMessage **res )
168 {
169 int rc;
170 int msgid;
171
172 *res = NULL;
173
174 rc = ldap_pvt_search( ld, base, scope, filter, attrs, attrsonly,
175 sctrls, cctrls, timeout, sizelimit, deref, &msgid );
176
177 if ( rc != LDAP_SUCCESS ) {
178 return( rc );
179 }
180
181 rc = ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res );
182
183 if( rc <= 0 ) {
184 /* error(-1) or timeout(0) */
185 if ( ld->ld_errno == LDAP_TIMEOUT ) {
186 /* cleanup request */
187 (void) ldap_abandon( ld, msgid );
188 ld->ld_errno = LDAP_TIMEOUT;
189 }
190 return( ld->ld_errno );
191 }
192
193 if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_INTERMEDIATE ) {
194 return( ld->ld_errno );
195 }
196
197 return( ldap_result2error( ld, *res, 0 ) );
198 }
199
200 /*
201 * ldap_search - initiate an ldap search operation.
202 *
203 * Parameters:
204 *
205 * ld LDAP descriptor
206 * base DN of the base object
207 * scope the search scope - one of
208 * LDAP_SCOPE_BASE (baseObject),
209 * LDAP_SCOPE_ONELEVEL (oneLevel),
210 * LDAP_SCOPE_SUBTREE (subtree), or
211 * LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension
212 * filter a string containing the search filter
213 * (e.g., "(|(cn=bob)(sn=bob))")
214 * attrs list of attribute types to return for matches
215 * attrsonly 1 => attributes only 0 => attributes and values
216 *
217 * Example:
218 * char *attrs[] = { "mail", "title", 0 };
219 * msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
220 * attrs, attrsonly );
221 */
222 int
ldap_search(LDAP * ld,LDAP_CONST char * base,int scope,LDAP_CONST char * filter,char ** attrs,int attrsonly)223 ldap_search(
224 LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter,
225 char **attrs, int attrsonly )
226 {
227 BerElement *ber;
228 ber_int_t id;
229
230 Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
231
232 assert( ld != NULL );
233 assert( LDAP_VALID( ld ) );
234
235 ber = ldap_build_search_req( ld, base, scope, filter, attrs,
236 attrsonly, NULL, NULL, -1, -1, -1, &id );
237
238 if ( ber == NULL ) {
239 return( -1 );
240 }
241
242
243 /* send the message */
244 return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id ));
245 }
246
247
248 BerElement *
ldap_build_search_req(LDAP * ld,LDAP_CONST char * base,ber_int_t scope,LDAP_CONST char * filter,char ** attrs,ber_int_t attrsonly,LDAPControl ** sctrls,LDAPControl ** cctrls,ber_int_t timelimit,ber_int_t sizelimit,ber_int_t deref,ber_int_t * idp)249 ldap_build_search_req(
250 LDAP *ld,
251 LDAP_CONST char *base,
252 ber_int_t scope,
253 LDAP_CONST char *filter,
254 char **attrs,
255 ber_int_t attrsonly,
256 LDAPControl **sctrls,
257 LDAPControl **cctrls,
258 ber_int_t timelimit,
259 ber_int_t sizelimit,
260 ber_int_t deref,
261 ber_int_t *idp)
262 {
263 BerElement *ber;
264 int err;
265
266 /*
267 * Create the search request. It looks like this:
268 * SearchRequest := [APPLICATION 3] SEQUENCE {
269 * baseObject DistinguishedName,
270 * scope ENUMERATED {
271 * baseObject (0),
272 * singleLevel (1),
273 * wholeSubtree (2)
274 * },
275 * derefAliases ENUMERATED {
276 * neverDerefaliases (0),
277 * derefInSearching (1),
278 * derefFindingBaseObj (2),
279 * alwaysDerefAliases (3)
280 * },
281 * sizelimit INTEGER (0 .. 65535),
282 * timelimit INTEGER (0 .. 65535),
283 * attrsOnly BOOLEAN,
284 * filter Filter,
285 * attributes SEQUENCE OF AttributeType
286 * }
287 * wrapped in an ldap message.
288 */
289
290 /* create a message to send */
291 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
292 return( NULL );
293 }
294
295 if ( base == NULL ) {
296 /* no base provided, use session default base */
297 base = ld->ld_options.ldo_defbase;
298
299 if ( base == NULL ) {
300 /* no session default base, use top */
301 base = "";
302 }
303 }
304
305 LDAP_NEXT_MSGID( ld, *idp );
306 #ifdef LDAP_CONNECTIONLESS
307 if ( LDAP_IS_UDP(ld) ) {
308 struct sockaddr_storage sa = {0};
309 /* dummy, filled with ldo_peer in request.c */
310 err = ber_write( ber, (char *) &sa, sizeof( sa ), 0 );
311 }
312 if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
313 char *dn = ld->ld_options.ldo_cldapdn;
314 if (!dn) dn = "";
315 err = ber_printf( ber, "{ist{seeiib", *idp, dn,
316 LDAP_REQ_SEARCH, base, (ber_int_t) scope,
317 (deref < 0) ? ld->ld_deref : deref,
318 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
319 (timelimit < 0) ? ld->ld_timelimit : timelimit,
320 attrsonly );
321 } else
322 #endif
323 {
324 err = ber_printf( ber, "{it{seeiib", *idp,
325 LDAP_REQ_SEARCH, base, (ber_int_t) scope,
326 (deref < 0) ? ld->ld_deref : deref,
327 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
328 (timelimit < 0) ? ld->ld_timelimit : timelimit,
329 attrsonly );
330 }
331
332 if ( err == -1 ) {
333 ld->ld_errno = LDAP_ENCODING_ERROR;
334 ber_free( ber, 1 );
335 return( NULL );
336 }
337
338 if( filter == NULL ) {
339 filter = "(objectclass=*)";
340 }
341
342 err = ldap_pvt_put_filter( ber, filter );
343
344 if ( err == -1 ) {
345 ld->ld_errno = LDAP_FILTER_ERROR;
346 ber_free( ber, 1 );
347 return( NULL );
348 }
349
350 #ifdef LDAP_DEBUG
351 if ( ldap_debug & LDAP_DEBUG_ARGS ) {
352 char buf[ BUFSIZ ], *ptr = " *";
353
354 if ( attrs != NULL ) {
355 int i, len, rest = sizeof( buf );
356
357 for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) {
358 ptr = &buf[ sizeof( buf ) - rest ];
359 len = snprintf( ptr, rest, " %s", attrs[ i ] );
360 rest -= (len >= 0 ? len : (int) sizeof( buf ));
361 }
362
363 if ( rest <= 0 ) {
364 AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
365 "...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
366 }
367 ptr = buf;
368 }
369
370 Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr, 0,0 );
371 }
372 #endif /* LDAP_DEBUG */
373
374 if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
375 ld->ld_errno = LDAP_ENCODING_ERROR;
376 ber_free( ber, 1 );
377 return( NULL );
378 }
379
380 /* Put Server Controls */
381 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
382 ber_free( ber, 1 );
383 return( NULL );
384 }
385
386 if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
387 ld->ld_errno = LDAP_ENCODING_ERROR;
388 ber_free( ber, 1 );
389 return( NULL );
390 }
391
392 return( ber );
393 }
394
395 int
ldap_search_st(LDAP * ld,LDAP_CONST char * base,int scope,LDAP_CONST char * filter,char ** attrs,int attrsonly,struct timeval * timeout,LDAPMessage ** res)396 ldap_search_st(
397 LDAP *ld, LDAP_CONST char *base, int scope,
398 LDAP_CONST char *filter, char **attrs,
399 int attrsonly, struct timeval *timeout, LDAPMessage **res )
400 {
401 int msgid;
402
403 *res = NULL;
404
405 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
406 == -1 )
407 return( ld->ld_errno );
408
409 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res )
410 return( ld->ld_errno );
411
412 if ( ld->ld_errno == LDAP_TIMEOUT ) {
413 (void) ldap_abandon( ld, msgid );
414 ld->ld_errno = LDAP_TIMEOUT;
415 return( ld->ld_errno );
416 }
417
418 return( ldap_result2error( ld, *res, 0 ) );
419 }
420
421 int
ldap_search_s(LDAP * ld,LDAP_CONST char * base,int scope,LDAP_CONST char * filter,char ** attrs,int attrsonly,LDAPMessage ** res)422 ldap_search_s(
423 LDAP *ld,
424 LDAP_CONST char *base,
425 int scope,
426 LDAP_CONST char *filter,
427 char **attrs,
428 int attrsonly,
429 LDAPMessage **res )
430 {
431 int msgid;
432
433 *res = NULL;
434
435 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
436 == -1 )
437 return( ld->ld_errno );
438
439 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res )
440 return( ld->ld_errno );
441
442 return( ldap_result2error( ld, *res, 0 ) );
443 }
444
445 static char escape[128] = {
446 1, 1, 1, 1, 1, 1, 1, 1,
447 1, 1, 1, 1, 1, 1, 1, 1,
448 1, 1, 1, 1, 1, 1, 1, 1,
449 1, 1, 1, 1, 1, 1, 1, 1,
450
451 0, 0, 0, 0, 0, 0, 0, 0,
452 1, 1, 1, 0, 0, 0, 0, 0,
453 0, 0, 0, 0, 0, 0, 0, 0,
454 0, 0, 0, 0, 0, 0, 0, 0,
455
456 0, 0, 0, 0, 0, 0, 0, 0,
457 0, 0, 0, 0, 0, 0, 0, 0,
458 0, 0, 0, 0, 0, 0, 0, 0,
459 0, 0, 0, 0, 1, 0, 0, 0,
460
461 0, 0, 0, 0, 0, 0, 0, 0,
462 0, 0, 0, 0, 0, 0, 0, 0,
463 0, 0, 0, 0, 0, 0, 0, 0,
464 0, 0, 0, 0, 0, 0, 0, 1
465 };
466 #define NEEDFLTESCAPE(c) ((c) & 0x80 || escape[ (unsigned)(c) ])
467
468 /*
469 * compute the length of the escaped value
470 */
471 ber_len_t
ldap_bv2escaped_filter_value_len(struct berval * in)472 ldap_bv2escaped_filter_value_len( struct berval *in )
473 {
474 ber_len_t i, l;
475
476 assert( in != NULL );
477
478 if ( in->bv_len == 0 ) {
479 return 0;
480 }
481
482 for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
483 char c = in->bv_val[ i ];
484 if ( NEEDFLTESCAPE( c ) ) {
485 l += 2;
486 }
487 }
488
489 return l;
490 }
491
492 int
ldap_bv2escaped_filter_value(struct berval * in,struct berval * out)493 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
494 {
495 return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
496 }
497
498 int
ldap_bv2escaped_filter_value_x(struct berval * in,struct berval * out,int inplace,void * ctx)499 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
500 {
501 ber_len_t i, l;
502
503 assert( in != NULL );
504 assert( out != NULL );
505
506 BER_BVZERO( out );
507
508 if ( in->bv_len == 0 ) {
509 return 0;
510 }
511
512 /* assume we'll escape everything */
513 l = ldap_bv2escaped_filter_value_len( in );
514 if ( l == in->bv_len ) {
515 if ( inplace ) {
516 *out = *in;
517 } else {
518 ber_dupbv( out, in );
519 }
520 return 0;
521 }
522 out->bv_val = LDAP_MALLOCX( l + 1, ctx );
523 if ( out->bv_val == NULL ) {
524 return -1;
525 }
526
527 for ( i = 0; i < in->bv_len; i++ ) {
528 char c = in->bv_val[ i ];
529 if ( NEEDFLTESCAPE( c ) ) {
530 assert( out->bv_len < l - 2 );
531 out->bv_val[out->bv_len++] = '\\';
532 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
533 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
534
535 } else {
536 assert( out->bv_len < l );
537 out->bv_val[out->bv_len++] = c;
538 }
539 }
540
541 out->bv_val[out->bv_len] = '\0';
542
543 return 0;
544 }
545
546