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