1 /* $NetBSD: search.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $ */ 2 3 /* OpenLDAP: pkg/ldap/libraries/libldap/search.c,v 1.76.2.9 2009/02/20 00:28:32 quanah Exp */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2009 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 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 return( ld->ld_errno ); 186 } 187 188 if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_INTERMEDIATE ) { 189 return( ld->ld_errno ); 190 } 191 192 return( ldap_result2error( ld, *res, 0 ) ); 193 } 194 195 /* 196 * ldap_search - initiate an ldap search operation. 197 * 198 * Parameters: 199 * 200 * ld LDAP descriptor 201 * base DN of the base object 202 * scope the search scope - one of 203 * LDAP_SCOPE_BASE (baseObject), 204 * LDAP_SCOPE_ONELEVEL (oneLevel), 205 * LDAP_SCOPE_SUBTREE (subtree), or 206 * LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension 207 * filter a string containing the search filter 208 * (e.g., "(|(cn=bob)(sn=bob))") 209 * attrs list of attribute types to return for matches 210 * attrsonly 1 => attributes only 0 => attributes and values 211 * 212 * Example: 213 * char *attrs[] = { "mail", "title", 0 }; 214 * msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob", 215 * attrs, attrsonly ); 216 */ 217 int 218 ldap_search( 219 LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter, 220 char **attrs, int attrsonly ) 221 { 222 BerElement *ber; 223 ber_int_t id; 224 225 Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 ); 226 227 assert( ld != NULL ); 228 assert( LDAP_VALID( ld ) ); 229 230 ber = ldap_build_search_req( ld, base, scope, filter, attrs, 231 attrsonly, NULL, NULL, -1, -1, -1, &id ); 232 233 if ( ber == NULL ) { 234 return( -1 ); 235 } 236 237 238 /* send the message */ 239 return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id )); 240 } 241 242 243 BerElement * 244 ldap_build_search_req( 245 LDAP *ld, 246 LDAP_CONST char *base, 247 ber_int_t scope, 248 LDAP_CONST char *filter, 249 char **attrs, 250 ber_int_t attrsonly, 251 LDAPControl **sctrls, 252 LDAPControl **cctrls, 253 ber_int_t timelimit, 254 ber_int_t sizelimit, 255 ber_int_t deref, 256 ber_int_t *idp) 257 { 258 BerElement *ber; 259 int err; 260 261 /* 262 * Create the search request. It looks like this: 263 * SearchRequest := [APPLICATION 3] SEQUENCE { 264 * baseObject DistinguishedName, 265 * scope ENUMERATED { 266 * baseObject (0), 267 * singleLevel (1), 268 * wholeSubtree (2) 269 * }, 270 * derefAliases ENUMERATED { 271 * neverDerefaliases (0), 272 * derefInSearching (1), 273 * derefFindingBaseObj (2), 274 * alwaysDerefAliases (3) 275 * }, 276 * sizelimit INTEGER (0 .. 65535), 277 * timelimit INTEGER (0 .. 65535), 278 * attrsOnly BOOLEAN, 279 * filter Filter, 280 * attributes SEQUENCE OF AttributeType 281 * } 282 * wrapped in an ldap message. 283 */ 284 285 /* create a message to send */ 286 if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) { 287 return( NULL ); 288 } 289 290 if ( base == NULL ) { 291 /* no base provided, use session default base */ 292 base = ld->ld_options.ldo_defbase; 293 294 if ( base == NULL ) { 295 /* no session default base, use top */ 296 base = ""; 297 } 298 } 299 300 LDAP_NEXT_MSGID( ld, *idp ); 301 #ifdef LDAP_CONNECTIONLESS 302 if ( LDAP_IS_UDP(ld) ) { 303 struct sockaddr sa = {0}; 304 /* dummy, filled with ldo_peer in request.c */ 305 err = ber_write( ber, &sa, sizeof( sa ), 0 ); 306 } 307 if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) { 308 char *dn = ld->ld_options.ldo_cldapdn; 309 if (!dn) dn = ""; 310 err = ber_printf( ber, "{ist{seeiib", *idp, dn, 311 LDAP_REQ_SEARCH, base, (ber_int_t) scope, 312 (deref < 0) ? ld->ld_deref : deref, 313 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit, 314 (timelimit < 0) ? ld->ld_timelimit : timelimit, 315 attrsonly ); 316 } else 317 #endif 318 { 319 err = ber_printf( ber, "{it{seeiib", *idp, 320 LDAP_REQ_SEARCH, base, (ber_int_t) scope, 321 (deref < 0) ? ld->ld_deref : deref, 322 (sizelimit < 0) ? ld->ld_sizelimit : sizelimit, 323 (timelimit < 0) ? ld->ld_timelimit : timelimit, 324 attrsonly ); 325 } 326 327 if ( err == -1 ) { 328 ld->ld_errno = LDAP_ENCODING_ERROR; 329 ber_free( ber, 1 ); 330 return( NULL ); 331 } 332 333 if( filter == NULL ) { 334 filter = "(objectclass=*)"; 335 } 336 337 err = ldap_pvt_put_filter( ber, filter ); 338 339 if ( err == -1 ) { 340 ld->ld_errno = LDAP_FILTER_ERROR; 341 ber_free( ber, 1 ); 342 return( NULL ); 343 } 344 345 #ifdef LDAP_DEBUG 346 if ( ldap_debug & LDAP_DEBUG_ARGS ) { 347 char buf[ BUFSIZ ], *ptr = " *"; 348 349 if ( attrs != NULL ) { 350 int i, len, rest = sizeof( buf ); 351 352 for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) { 353 ptr = &buf[ sizeof( buf ) - rest ]; 354 len = snprintf( ptr, rest, " %s", attrs[ i ] ); 355 rest -= (len >= 0 ? len : (int) sizeof( buf )); 356 } 357 358 if ( rest <= 0 ) { 359 AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ], 360 "...(truncated)", STRLENOF( "...(truncated)" ) + 1 ); 361 } 362 ptr = buf; 363 } 364 365 Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr, 0,0 ); 366 } 367 #endif /* LDAP_DEBUG */ 368 369 if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) { 370 ld->ld_errno = LDAP_ENCODING_ERROR; 371 ber_free( ber, 1 ); 372 return( NULL ); 373 } 374 375 /* Put Server Controls */ 376 if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) { 377 ber_free( ber, 1 ); 378 return( NULL ); 379 } 380 381 if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) { 382 ld->ld_errno = LDAP_ENCODING_ERROR; 383 ber_free( ber, 1 ); 384 return( NULL ); 385 } 386 387 return( ber ); 388 } 389 390 int 391 ldap_search_st( 392 LDAP *ld, LDAP_CONST char *base, int scope, 393 LDAP_CONST char *filter, char **attrs, 394 int attrsonly, struct timeval *timeout, LDAPMessage **res ) 395 { 396 int msgid; 397 398 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly )) 399 == -1 ) 400 return( ld->ld_errno ); 401 402 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res ) 403 return( ld->ld_errno ); 404 405 if ( ld->ld_errno == LDAP_TIMEOUT ) { 406 (void) ldap_abandon( ld, msgid ); 407 ld->ld_errno = LDAP_TIMEOUT; 408 return( ld->ld_errno ); 409 } 410 411 return( ldap_result2error( ld, *res, 0 ) ); 412 } 413 414 int 415 ldap_search_s( 416 LDAP *ld, 417 LDAP_CONST char *base, 418 int scope, 419 LDAP_CONST char *filter, 420 char **attrs, 421 int attrsonly, 422 LDAPMessage **res ) 423 { 424 int msgid; 425 426 if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly )) 427 == -1 ) 428 return( ld->ld_errno ); 429 430 if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res ) 431 return( ld->ld_errno ); 432 433 return( ldap_result2error( ld, *res, 0 ) ); 434 } 435 436 static char escape[128] = { 437 1, 1, 1, 1, 1, 1, 1, 1, 438 1, 1, 1, 1, 1, 1, 1, 1, 439 1, 1, 1, 1, 1, 1, 1, 1, 440 1, 1, 1, 1, 1, 1, 1, 1, 441 442 0, 0, 0, 0, 0, 0, 0, 0, 443 1, 1, 1, 0, 0, 0, 0, 0, 444 0, 0, 0, 0, 0, 0, 0, 0, 445 0, 0, 0, 0, 0, 0, 0, 0, 446 447 0, 0, 0, 0, 0, 0, 0, 0, 448 0, 0, 0, 0, 0, 0, 0, 0, 449 0, 0, 0, 0, 0, 0, 0, 0, 450 0, 0, 0, 0, 1, 0, 0, 0, 451 452 0, 0, 0, 0, 0, 0, 0, 0, 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, 1 456 }; 457 #define NEEDFLTESCAPE(c) ((c) & 0x80 || escape[ (unsigned)(c) ]) 458 459 /* 460 * compute the length of the escaped value 461 */ 462 ber_len_t 463 ldap_bv2escaped_filter_value_len( struct berval *in ) 464 { 465 ber_len_t i, l; 466 467 assert( in != NULL ); 468 469 if ( in->bv_len == 0 ) { 470 return 0; 471 } 472 473 for( l = 0, i = 0; i < in->bv_len; l++, i++ ) { 474 char c = in->bv_val[ i ]; 475 if ( NEEDFLTESCAPE( c ) ) { 476 l += 2; 477 } 478 } 479 480 return l; 481 } 482 483 int 484 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out ) 485 { 486 return ldap_bv2escaped_filter_value_x( in, out, 0, NULL ); 487 } 488 489 int 490 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx ) 491 { 492 ber_len_t i, l; 493 494 assert( in != NULL ); 495 assert( out != NULL ); 496 497 BER_BVZERO( out ); 498 499 if ( in->bv_len == 0 ) { 500 return 0; 501 } 502 503 /* assume we'll escape everything */ 504 l = ldap_bv2escaped_filter_value_len( in ); 505 if ( l == in->bv_len ) { 506 if ( inplace ) { 507 *out = *in; 508 } else { 509 ber_dupbv( out, in ); 510 } 511 return 0; 512 } 513 out->bv_val = LDAP_MALLOCX( l + 1, ctx ); 514 if ( out->bv_val == NULL ) { 515 return -1; 516 } 517 518 for ( i = 0; i < in->bv_len; i++ ) { 519 char c = in->bv_val[ i ]; 520 if ( NEEDFLTESCAPE( c ) ) { 521 assert( out->bv_len < l - 2 ); 522 out->bv_val[out->bv_len++] = '\\'; 523 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)]; 524 out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c]; 525 526 } else { 527 assert( out->bv_len < l ); 528 out->bv_val[out->bv_len++] = c; 529 } 530 } 531 532 out->bv_val[out->bv_len] = '\0'; 533 534 return 0; 535 } 536 537