]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-search.c
ITS#8798 Fix swapped arguments
[openldap] / tests / progs / slapd-search.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2017 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 file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 /* ACKNOWLEDGEMENTS:
16  * This work was initially developed by Kurt Spanier for inclusion
17  * in OpenLDAP Software.
18  */
19
20 #include "portable.h"
21
22 #include <stdio.h>
23
24 #include "ac/stdlib.h"
25
26 #include "ac/ctype.h"
27 #include "ac/param.h"
28 #include "ac/socket.h"
29 #include "ac/string.h"
30 #include "ac/unistd.h"
31 #include "ac/wait.h"
32
33 #include "ldap.h"
34 #include "lutil.h"
35 #include "ldap_pvt.h"
36
37 #include "slapd-common.h"
38
39 #define LOOPS   100
40 #define RETRIES 0
41
42 static void
43 do_search( struct tester_conn_args *config,
44         char *sbase, int scope, char *filter, LDAP **ldp,
45         char **attrs, int noattrs, int nobind,
46         int innerloop, int force );
47
48 static void
49 do_random( struct tester_conn_args *config,
50         char *sbase, int scope, char *filter, char *attr,
51         char **attrs, int noattrs, int nobind, int force );
52
53 static void
54 usage( char *name, char opt )
55 {
56         if ( opt != '\0' ) {
57                 fprintf( stderr, "unknown/incorrect option \"%c\"\n", opt );
58         }
59
60         fprintf( stderr, "usage: %s " TESTER_COMMON_HELP
61                 "-b <searchbase> "
62                 "-s <scope> "
63                 "-f <searchfilter> "
64                 "[-a <attr>] "
65                 "[-A] "
66                 "[-F] "
67                 "[-N] "
68                 "[-S[S[S]]] "
69                 "[<attrs>] "
70                 "\n",
71                 name );
72         exit( EXIT_FAILURE );
73 }
74
75 /* -S: just send requests without reading responses
76  * -SS: send all requests asynchronous and immediately start reading responses
77  * -SSS: send all requests asynchronous; then read responses
78  */
79 static int swamp;
80
81 int
82 main( int argc, char **argv )
83 {
84         int             i;
85         char            *sbase = NULL;
86         int             scope = LDAP_SCOPE_SUBTREE;
87         char            *filter  = NULL;
88         char            *attr = NULL;
89         char            *srchattrs[] = { "cn", "sn", NULL };
90         char            **attrs = srchattrs;
91         int             force = 0;
92         int             noattrs = 0;
93         int             nobind = 0;
94         struct tester_conn_args *config;
95
96         config = tester_init( "slapd-search", TESTER_SEARCH );
97
98         /* by default, tolerate referrals and no such object */
99         tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
100
101         while ( ( i = getopt( argc, argv, TESTER_COMMON_OPTS "Aa:b:f:FNSs:T:" ) ) != EOF )
102         {
103                 switch ( i ) {
104                 case 'A':
105                         noattrs++;
106                         break;
107
108                 case 'N':
109                         nobind = TESTER_INIT_ONLY;
110                         break;
111
112                 case 'a':
113                         attr = strdup( optarg );
114                         break;
115
116                 case 'b':               /* file with search base */
117                         sbase = strdup( optarg );
118                         break;
119
120                 case 'f':               /* the search request */
121                         filter = strdup( optarg );
122                         break;
123
124                 case 'F':
125                         force++;
126                         break;
127
128                 case 'T':
129                         attrs = ldap_str2charray( optarg, "," );
130                         if ( attrs == NULL ) {
131                                 usage( argv[0], i );
132                         }
133                         break;
134
135                 case 'S':
136                         swamp++;
137                         break;
138
139                 case 's':
140                         scope = ldap_pvt_str2scope( optarg );
141                         if ( scope == -1 ) {
142                                 usage( argv[0], i );
143                         }
144                         break;
145
146                 default:
147                         if ( tester_config_opt( config, i, optarg ) == LDAP_SUCCESS ) {
148                                 break;
149                         }
150                         usage( argv[0], i );
151                         break;
152                 }
153         }
154
155         if (( sbase == NULL ) || ( filter == NULL ))
156                 usage( argv[0], 0 );
157
158         if ( *filter == '\0' ) {
159
160                 fprintf( stderr, "%s: invalid EMPTY search filter.\n",
161                                 argv[0] );
162                 exit( EXIT_FAILURE );
163
164         }
165
166         if ( argv[optind] != NULL ) {
167                 attrs = &argv[optind];
168         }
169
170         tester_config_finish( config );
171
172         for ( i = 0; i < config->outerloops; i++ ) {
173                 if ( attr != NULL ) {
174                         do_random( config,
175                                 sbase, scope, filter, attr,
176                                 attrs, noattrs, nobind, force );
177
178                 } else {
179                         do_search( config, sbase, scope, filter,
180                                 NULL, attrs, noattrs, nobind,
181                                 config->loops, force );
182                 }
183         }
184
185         exit( EXIT_SUCCESS );
186 }
187
188
189 static void
190 do_random( struct tester_conn_args *config,
191         char *sbase, int scope, char *filter, char *attr,
192         char **srchattrs, int noattrs, int nobind, int force )
193 {
194         LDAP    *ld = NULL;
195         int     i = 0, do_retry = config->retries;
196         char    *attrs[ 2 ];
197         int     rc = LDAP_SUCCESS;
198         int     nvalues = 0;
199         char    **values = NULL;
200         LDAPMessage *res = NULL, *e = NULL;
201
202         attrs[ 0 ] = attr;
203         attrs[ 1 ] = NULL;
204
205         tester_init_ld( &ld, config, nobind );
206
207         rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
208                 filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
209         switch ( rc ) {
210         case LDAP_SIZELIMIT_EXCEEDED:
211         case LDAP_TIMELIMIT_EXCEEDED:
212         case LDAP_SUCCESS:
213                 if ( ldap_count_entries( ld, res ) == 0 ) {
214                         if ( rc ) {
215                                 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
216                         }
217                         break;
218                 }
219
220                 for ( e = ldap_first_entry( ld, res ); e != NULL; e = ldap_next_entry( ld, e ) )
221                 {
222                         struct berval **v = ldap_get_values_len( ld, e, attr );
223
224                         if ( v != NULL ) {
225                                 int n = ldap_count_values_len( v );
226                                 int j;
227
228                                 values = realloc( values, ( nvalues + n + 1 )*sizeof( char * ) );
229                                 for ( j = 0; j < n; j++ ) {
230                                         values[ nvalues + j ] = strdup( v[ j ]->bv_val );
231                                 }
232                                 values[ nvalues + j ] = NULL;
233                                 nvalues += n;
234                                 ldap_value_free_len( v );
235                         }
236                 }
237
238                 ldap_msgfree( res );
239
240                 if ( !values ) {
241                         fprintf( stderr, "  PID=%ld - Search base=\"%s\" filter=\"%s\" got %d values.\n",
242                                 (long) pid, sbase, filter, nvalues );
243                         exit(EXIT_FAILURE);
244                 }
245
246                 if ( do_retry == config->retries ) {
247                         fprintf( stderr, "  PID=%ld - Search base=\"%s\" filter=\"%s\" got %d values.\n",
248                                 (long) pid, sbase, filter, nvalues );
249                 }
250
251                 for ( i = 0; i < config->loops; i++ ) {
252                         char    buf[ BUFSIZ ];
253 #if 0   /* use high-order bits for better randomness (Numerical Recipes in "C") */
254                         int     r = rand() % nvalues;
255 #endif
256                         int     r = ((double)nvalues)*rand()/(RAND_MAX + 1.0);
257
258                         snprintf( buf, sizeof( buf ), "(%s=%s)", attr, values[ r ] );
259
260                         do_search( config,
261                                 sbase, scope, buf, &ld,
262                                 srchattrs, noattrs, nobind,
263                                 1, force );
264                 }
265                 break;
266
267         default:
268                 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
269                 break;
270         }
271
272         fprintf( stderr, "  PID=%ld - Search done (%d).\n", (long) pid, rc );
273
274         if ( values ) {
275                 for ( i = 0; i < nvalues; i++ ) {
276                         free( values[i] );
277                 }
278                 free( values );
279         }
280
281         if ( ld != NULL ) {
282                 ldap_unbind_ext( ld, NULL, NULL );
283         }
284 }
285
286 static void
287 do_search( struct tester_conn_args *config,
288         char *sbase, int scope, char *filter, LDAP **ldp,
289         char **attrs, int noattrs, int nobind,
290         int innerloop, int force )
291 {
292         LDAP    *ld = ldp ? *ldp : NULL;
293         int     i = 0, do_retry = config->retries;
294         int     rc = LDAP_SUCCESS;
295         char    buf[ BUFSIZ ];
296         int             *msgids = NULL, active = 0;
297
298         /* make room for msgid */
299         if ( swamp > 1 ) {
300                 msgids = (int *)calloc( sizeof(int), innerloop );
301         }
302
303 retry:;
304         if ( ld == NULL ) {
305                 fprintf( stderr,
306                         "PID=%ld - Search(%d): "
307                         "base=\"%s\" scope=%s filter=\"%s\" "
308                         "attrs=%s%s.\n",
309                         (long) pid, innerloop,
310                         sbase, ldap_pvt_scope2str( scope ), filter,
311                         attrs[0], attrs[1] ? " (more...)" : "" );
312
313                 tester_init_ld( &ld, config, nobind );
314         }
315
316         if ( swamp > 1 ) {
317                 do {
318                         LDAPMessage *res = NULL;
319                         int j, msgid;
320
321                         if ( i < innerloop ) {
322                                 rc = ldap_search_ext( ld, sbase, scope,
323                                                 filter, NULL, noattrs, NULL, NULL,
324                                                 NULL, LDAP_NO_LIMIT, &msgids[i] );
325
326                                 active++;
327 #if 0
328                                 fprintf( stderr,
329                                         ">>> PID=%ld - Search maxloop=%d cnt=%d active=%d msgid=%d: "
330                                         "base=\"%s\" scope=%s filter=\"%s\"\n",
331                                         (long) pid, innerloop, i, active, msgids[i],
332                                         sbase, ldap_pvt_scope2str( scope ), filter );
333 #endif
334                                 i++;
335
336                                 if ( rc ) {
337                                         int first = tester_ignore_err( rc );
338                                         /* if ignore.. */
339                                         if ( first ) {
340                                                 /* only log if first occurrence */
341                                                 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
342                                                         tester_ldap_error( ld, "ldap_search_ext", NULL );
343                                                 }
344                                                 continue;
345                                         }
346                 
347                                         /* busy needs special handling */
348                                         snprintf( buf, sizeof( buf ),
349                                                 "base=\"%s\" filter=\"%s\"\n",
350                                                 sbase, filter );
351                                         tester_ldap_error( ld, "ldap_search_ext", buf );
352                                         if ( rc == LDAP_BUSY && do_retry > 0 ) {
353                                                 ldap_unbind_ext( ld, NULL, NULL );
354                                                 ld = NULL;
355                                                 do_retry--;
356                                                 goto retry;
357                                         }
358                                         break;
359                                 }
360
361                                 if ( swamp > 2 ) {
362                                         continue;
363                                 }
364                         }
365
366                         rc = ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res );
367                         switch ( rc ) {
368                         case -1:
369                                 /* gone really bad */
370                                 goto cleanup;
371         
372                         case 0:
373                                 /* timeout (impossible) */
374                                 break;
375         
376                         case LDAP_RES_SEARCH_ENTRY:
377                         case LDAP_RES_SEARCH_REFERENCE:
378                                 /* ignore */
379                                 break;
380         
381                         case LDAP_RES_SEARCH_RESULT:
382                                 /* just remove, no error checking (TODO?) */
383                                 msgid = ldap_msgid( res );
384                                 ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 );
385                                 res = NULL;
386
387                                 /* linear search, bah */
388                                 for ( j = 0; j < i; j++ ) {
389                                         if ( msgids[ j ] == msgid ) {
390                                                 msgids[ j ] = -1;
391                                                 active--;
392 #if 0
393                                                 fprintf( stderr,
394                                                         "<<< PID=%ld - SearchDone maxloop=%d cnt=%d active=%d msgid=%d: "
395                                                         "base=\"%s\" scope=%s filter=\"%s\"\n",
396                                                         (long) pid, innerloop, j, active, msgid,
397                                                         sbase, ldap_pvt_scope2str( scope ), filter );
398 #endif
399                                                 break;
400                                         }
401                                 }
402                                 break;
403
404                         default:
405                                 /* other messages unexpected */
406                                 fprintf( stderr,
407                                         "### PID=%ld - Search(%d): "
408                                         "base=\"%s\" scope=%s filter=\"%s\" "
409                                         "attrs=%s%s. unexpected response tag=%d\n",
410                                         (long) pid, innerloop,
411                                         sbase, ldap_pvt_scope2str( scope ), filter,
412                                         attrs[0], attrs[1] ? " (more...)" : "", rc );
413                                 break;
414                         }
415
416                         if ( res != NULL ) {
417                                 ldap_msgfree( res );
418                         }
419                 } while ( i < innerloop || active > 0 );
420
421         } else {
422                 for ( ; i < innerloop; i++ ) {
423                         LDAPMessage *res = NULL;
424
425                         if (swamp) {
426                                 int msgid;
427                                 rc = ldap_search_ext( ld, sbase, scope,
428                                                 filter, NULL, noattrs, NULL, NULL,
429                                                 NULL, LDAP_NO_LIMIT, &msgid );
430                                 if ( rc == LDAP_SUCCESS ) continue;
431                                 else break;
432                         }
433         
434                         rc = ldap_search_ext_s( ld, sbase, scope,
435                                         filter, attrs, noattrs, NULL, NULL,
436                                         NULL, LDAP_NO_LIMIT, &res );
437                         if ( res != NULL ) {
438                                 ldap_msgfree( res );
439                         }
440         
441                         if ( rc ) {
442                                 int first = tester_ignore_err( rc );
443                                 /* if ignore.. */
444                                 if ( first ) {
445                                         /* only log if first occurrence */
446                                         if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
447                                                 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
448                                         }
449                                         continue;
450                                 }
451         
452                                 /* busy needs special handling */
453                                 snprintf( buf, sizeof( buf ),
454                                         "base=\"%s\" filter=\"%s\"\n",
455                                         sbase, filter );
456                                 tester_ldap_error( ld, "ldap_search_ext_s", buf );
457                                 if ( rc == LDAP_BUSY && do_retry > 0 ) {
458                                         ldap_unbind_ext( ld, NULL, NULL );
459                                         ld = NULL;
460                                         do_retry--;
461                                         goto retry;
462                                 }
463                                 break;
464                         }
465                 }
466         }
467
468 cleanup:;
469         if ( msgids != NULL ) {
470                 free( msgids );
471         }
472
473         if ( ldp != NULL ) {
474                 *ldp = ld;
475
476         } else {
477                 fprintf( stderr, "  PID=%ld - Search done (%d).\n", (long) pid, rc );
478
479                 if ( ld != NULL ) {
480                         ldap_unbind_ext( ld, NULL, NULL );
481                 }
482         }
483 }