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