Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/ldap/libldap/search.c
4394 views
1
/* $OpenLDAP$ */
2
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3
*
4
* Copyright 1998-2024 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
*/
55
int
56
ldap_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
73
int
74
ldap_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
Debug0( LDAP_DEBUG_TRACE, "ldap_search_ext\n" );
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
136
int
137
ldap_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
154
int
155
ldap_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
*/
222
int
223
ldap_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
Debug0( LDAP_DEBUG_TRACE, "ldap_search\n" );
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
248
BerElement *
249
ldap_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_storage 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
Debug1( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr );
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
395
int
396
ldap_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
421
int
422
ldap_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
445
static 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
*/
471
ber_len_t
472
ldap_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
492
int
493
ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
494
{
495
return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
496
}
497
498
int
499
ldap_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