1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1998-2011 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 */ 55int 56ldap_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 73int 74ldap_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 136int 137ldap_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 154int 155ldap_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 */ 222int 223ldap_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 248BerElement * 249ldap_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 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 395int 396ldap_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 421int 422ldap_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 445static 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 */ 471ber_len_t 472ldap_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 492int 493ldap_bv2escaped_filter_value( struct berval *in, struct berval *out ) 494{ 495 return ldap_bv2escaped_filter_value_x( in, out, 0, NULL ); 496} 497 498int 499ldap_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