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