]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-tester.c
ITS#6003, #5916 fix ldap_back_entry_get_rw, no deref here
[openldap] / tests / progs / slapd-tester.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2009 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/dirent.h"
28 #include "ac/param.h"
29 #include "ac/socket.h"
30 #include "ac/string.h"
31 #include "ac/unistd.h"
32 #include "ac/wait.h"
33
34
35 #include "ldap_defaults.h"
36 #include "lutil.h"
37
38 #include "ldap.h"
39 #include "ldap_pvt.h"
40 #include "lber_pvt.h"
41 #include "slapd-common.h"
42
43 #define SEARCHCMD               "slapd-search"
44 #define READCMD                 "slapd-read"
45 #define ADDCMD                  "slapd-addel"
46 #define MODRDNCMD               "slapd-modrdn"
47 #define MODIFYCMD               "slapd-modify"
48 #define BINDCMD                 "slapd-bind"
49 #define MAXARGS                 100
50 #define MAXREQS                 5000
51 #define LOOPS                   100
52 #define OUTERLOOPS              "1"
53 #define RETRIES                 "0"
54
55 #define TSEARCHFILE             "do_search.0"
56 #define TREADFILE               "do_read.0"
57 #define TADDFILE                "do_add."
58 #define TMODRDNFILE             "do_modrdn.0"
59 #define TMODIFYFILE             "do_modify.0"
60 #define TBINDFILE               "do_bind.0"
61
62 static char *get_file_name( char *dirname, char *filename );
63 static int  get_search_filters( char *filename, char *filters[], char *attrs[], char *bases[], LDAPURLDesc *luds[] );
64 static int  get_read_entries( char *filename, char *entries[], char *filters[] );
65 static void fork_child( char *prog, char **args );
66 static void     wait4kids( int nkidval );
67
68 static int      maxkids = 20;
69 static int      nkids;
70
71 #ifdef HAVE_WINSOCK
72 static HANDLE   *children;
73 static char argbuf[BUFSIZ];
74 #define ArgDup(x) strdup(strcat(strcat(strcpy(argbuf,"\""),x),"\""))
75 #else
76 #define ArgDup(x) strdup(x)
77 #endif
78
79 static void
80 usage( char *name, char opt )
81 {
82         if ( opt ) {
83                 fprintf( stderr, "%s: unable to handle option \'%c\'\n\n",
84                         name, opt );
85         }
86
87         fprintf( stderr,
88                 "usage: %s "
89                 "-H <uri> | ([-h <host>] -p <port>) "
90                 "-D <manager> "
91                 "-w <passwd> "
92                 "-d <datadir> "
93                 "[-i <ignore>] "
94                 "[-j <maxchild>] "
95                 "[-l {<loops>|<type>=<loops>[,...]}] "
96                 "[-L <outerloops>] "
97                 "-P <progdir> "
98                 "[-r <maxretries>] "
99                 "[-t <delay>] "
100                 "[-C] "
101                 "[-F] "
102                 "[-I] "
103                 "[-N]\n",
104                 name );
105         exit( EXIT_FAILURE );
106 }
107
108 int
109 main( int argc, char **argv )
110 {
111         int             i, j;
112         char            *uri = NULL;
113         char            *host = "localhost";
114         char            *port = NULL;
115         char            *manager = NULL;
116         char            *passwd = NULL;
117         char            *dirname = NULL;
118         char            *progdir = NULL;
119         int             loops = LOOPS;
120         char            *outerloops = OUTERLOOPS;
121         char            *retries = RETRIES;
122         char            *delay = "0";
123         DIR             *datadir;
124         struct dirent   *file;
125         int             friendly = 0;
126         int             chaserefs = 0;
127         int             noattrs = 0;
128         int             nobind = 0;
129         int             noinit = 1;
130         char            *ignore = NULL;
131         /* search */
132         char            *sfile = NULL;
133         char            *sreqs[MAXREQS];
134         char            *sattrs[MAXREQS];
135         char            *sbase[MAXREQS];
136         LDAPURLDesc     *slud[MAXREQS];
137         int             snum = 0;
138         char            *sargs[MAXARGS];
139         int             sanum;
140         int             sextra_args = 0;
141         char            scmd[MAXPATHLEN];
142         /* static so that its address can be used in initializer below. */
143         static char     sloops[LDAP_PVT_INTTYPE_CHARS(unsigned long)];
144         /* read */
145         char            *rfile = NULL;
146         char            *rreqs[MAXREQS];
147         int             rnum = 0;
148         char            *rargs[MAXARGS];
149         char            *rflts[MAXREQS];
150         int             ranum;
151         int             rextra_args = 0;
152         char            rcmd[MAXPATHLEN];
153         static char     rloops[LDAP_PVT_INTTYPE_CHARS(unsigned long)];
154         /* addel */
155         char            *afiles[MAXREQS];
156         int             anum = 0;
157         char            *aargs[MAXARGS];
158         int             aanum;
159         char            acmd[MAXPATHLEN];
160         static char     aloops[LDAP_PVT_INTTYPE_CHARS(unsigned long)];
161         /* modrdn */
162         char            *nfile = NULL;
163         char            *nreqs[MAXREQS];
164         int             nnum = 0;
165         char            *nargs[MAXARGS];
166         int             nanum;
167         char            ncmd[MAXPATHLEN];
168         static char     nloops[LDAP_PVT_INTTYPE_CHARS(unsigned long)];
169         /* modify */
170         char            *mfile = NULL;
171         char            *mreqs[MAXREQS];
172         char            *mdn[MAXREQS];
173         int             mnum = 0;
174         char            *margs[MAXARGS];
175         int             manum;
176         char            mcmd[MAXPATHLEN];
177         static char     mloops[LDAP_PVT_INTTYPE_CHARS(unsigned long)];
178         /* bind */
179         char            *bfile = NULL;
180         char            *breqs[MAXREQS];
181         char            *bcreds[MAXREQS];
182         char            *battrs[MAXREQS];
183         int             bnum = 0;
184         char            *bargs[MAXARGS];
185         int             banum;
186         char            bcmd[MAXPATHLEN];
187         static char     bloops[LDAP_PVT_INTTYPE_CHARS(unsigned long)];
188         char            **bargs_extra = NULL;
189
190         char            *friendlyOpt = NULL;
191         int             pw_ask = 0;
192         char            *pw_file = NULL;
193
194         /* extra action to do after bind... */
195         typedef struct extra_t {
196                 char            *action;
197                 struct extra_t  *next;
198         }               extra_t;
199
200         extra_t         *extra = NULL;
201         int             nextra = 0;
202
203         tester_init( "slapd-tester", TESTER_TESTER );
204
205         sloops[0] = '\0';
206         rloops[0] = '\0';
207         aloops[0] = '\0';
208         nloops[0] = '\0';
209         mloops[0] = '\0';
210         bloops[0] = '\0';
211
212         while ( ( i = getopt( argc, argv, "AB:CD:d:FH:h:Ii:j:L:l:NP:p:r:t:Ww:y:" ) ) != EOF )
213         {
214                 switch ( i ) {
215                 case 'A':
216                         noattrs++;
217                         break;
218
219                 case 'B': {
220                         char    **p,
221                                 **b = ldap_str2charray( optarg, "," );
222                         extra_t **epp;
223
224                         for ( epp = &extra; *epp; epp = &(*epp)->next )
225                                 ;
226
227                         for ( p = b; p[0]; p++ ) {
228                                 *epp = calloc( 1, sizeof( extra_t ) );
229                                 (*epp)->action = p[0];
230                                 epp = &(*epp)->next;
231                                 nextra++;
232                         }
233
234                         ldap_memfree( b );
235                         } break;
236
237                 case 'C':
238                         chaserefs++;
239                         break;
240
241                 case 'D':               /* slapd manager */
242                         manager = ArgDup( optarg );
243                         break;
244
245                 case 'd':               /* data directory */
246                         dirname = strdup( optarg );
247                         break;
248
249                 case 'F':
250                         friendly++;
251                         break;
252
253                 case 'H':               /* slapd uri */
254                         uri = strdup( optarg );
255                         break;
256
257                 case 'h':               /* slapd host */
258                         host = strdup( optarg );
259                         break;
260
261                 case 'I':
262                         noinit = 0;
263                         break;
264
265                 case 'i':
266                         ignore = optarg;
267                         break;
268
269                 case 'j':               /* the number of parallel clients */
270                         if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
271                                 usage( argv[0], 'j' );
272                         }
273                         break;
274
275                 case 'l':               /* the number of loops per client */
276                         if ( !isdigit( (unsigned char) optarg[0] ) ) {
277                                 char    **p,
278                                         **l = ldap_str2charray( optarg, "," );
279
280                                 for ( p = l; p[0]; p++) {
281                                         struct {
282                                                 struct berval   type;
283                                                 char            *buf;
284                                         } types[] = {
285                                                 { BER_BVC( "add=" ),    aloops },
286                                                 { BER_BVC( "bind=" ),   bloops },
287                                                 { BER_BVC( "modify=" ), mloops },
288                                                 { BER_BVC( "modrdn=" ), nloops },
289                                                 { BER_BVC( "read=" ),   rloops },
290                                                 { BER_BVC( "search=" ), sloops },
291                                                 { BER_BVNULL,           NULL }
292                                         };
293                                         int     c, n;
294
295                                         for ( c = 0; types[c].type.bv_val; c++ ) {
296                                                 if ( strncasecmp( p[0], types[c].type.bv_val, types[c].type.bv_len ) == 0 ) {
297                                                         break;
298                                                 }
299                                         }
300
301                                         if ( types[c].type.bv_val == NULL ) {
302                                                 usage( argv[0], 'l' );
303                                         }
304
305                                         if ( lutil_atoi( &n, &p[0][types[c].type.bv_len] ) != 0 ) {
306                                                 usage( argv[0], 'l' );
307                                         }
308
309                                         snprintf( types[c].buf, sizeof( aloops ), "%d", n );
310                                 }
311
312                                 ldap_charray_free( l );
313
314                         } else if ( lutil_atoi( &loops, optarg ) != 0 ) {
315                                 usage( argv[0], 'l' );
316                         }
317                         break;
318
319                 case 'L':               /* the number of outerloops per client */
320                         outerloops = strdup( optarg );
321                         break;
322
323                 case 'N':
324                         nobind++;
325                         break;
326
327                 case 'P':               /* prog directory */
328                         progdir = strdup( optarg );
329                         break;
330
331                 case 'p':               /* the servers port number */
332                         port = strdup( optarg );
333                         break;
334
335                 case 'r':               /* the number of retries in case of error */
336                         retries = strdup( optarg );
337                         break;
338
339                 case 't':               /* the delay in seconds between each retry */
340                         delay = strdup( optarg );
341                         break;
342
343                 case 'w':               /* the managers passwd */
344                         passwd = ArgDup( optarg );
345                         memset( optarg, '*', strlen( optarg ) );
346                         break;
347
348                 case 'W':
349                         pw_ask++;
350                         break;
351
352                 case 'y':
353                         pw_file = optarg;
354                         break;
355
356                 default:
357                         usage( argv[0], '\0' );
358                         break;
359                 }
360         }
361
362         if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
363                         ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
364         {
365                 usage( argv[0], '\0' );
366         }
367
368 #ifdef HAVE_WINSOCK
369         children = malloc( maxkids * sizeof(HANDLE) );
370 #endif
371         /* get the file list */
372         if ( ( datadir = opendir( dirname )) == NULL ) {
373                 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
374                                         argv[0], dirname );
375                 exit( EXIT_FAILURE );
376         }
377
378         /*  look for search, read, modrdn, and add/delete files */
379         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
380
381                 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
382                         sfile = get_file_name( dirname, file->d_name );
383                         continue;
384                 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
385                         rfile = get_file_name( dirname, file->d_name );
386                         continue;
387                 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
388                         nfile = get_file_name( dirname, file->d_name );
389                         continue;
390                 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
391                         mfile = get_file_name( dirname, file->d_name );
392                         continue;
393                 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
394                         && ( anum < MAXREQS )) {
395                         afiles[anum++] = get_file_name( dirname, file->d_name );
396                         continue;
397                 } else if ( !strcasecmp( file->d_name, TBINDFILE )) {
398                         bfile = get_file_name( dirname, file->d_name );
399                         continue;
400                 }
401         }
402
403         closedir( datadir );
404
405         if ( pw_ask ) {
406                 passwd = getpassphrase( _("Enter LDAP Password: ") );
407
408         } else if ( pw_file ) {
409                 struct berval   pw;
410
411                 if ( lutil_get_filed_password( pw_file, &pw ) ) {
412                         exit( EXIT_FAILURE );
413                 }
414
415                 passwd = pw.bv_val;
416         }
417
418         if ( !sfile && !rfile && !nfile && !mfile && !bfile && !anum ) {
419                 fprintf( stderr, "no data files found.\n" );
420                 exit( EXIT_FAILURE );
421         }
422
423         /* look for search requests */
424         if ( sfile ) {
425                 snum = get_search_filters( sfile, sreqs, sattrs, sbase, slud );
426                 if ( snum < 0 ) {
427                         fprintf( stderr,
428                                 "unable to parse file \"%s\" line %d\n",
429                                 sfile, -2*(snum + 1));
430                         exit( EXIT_FAILURE );
431                 }
432         }
433
434         /* look for read requests */
435         if ( rfile ) {
436                 rnum = get_read_entries( rfile, rreqs, rflts );
437                 if ( rnum < 0 ) {
438                         fprintf( stderr,
439                                 "unable to parse file \"%s\" line %d\n",
440                                 rfile, -2*(rnum + 1) );
441                         exit( EXIT_FAILURE );
442                 }
443         }
444
445         /* look for modrdn requests */
446         if ( nfile ) {
447                 nnum = get_read_entries( nfile, nreqs, NULL );
448                 if ( nnum < 0 ) {
449                         fprintf( stderr,
450                                 "unable to parse file \"%s\" line %d\n",
451                                 nfile, -2*(nnum + 1) );
452                         exit( EXIT_FAILURE );
453                 }
454         }
455
456         /* look for modify requests */
457         if ( mfile ) {
458                 mnum = get_search_filters( mfile, mreqs, NULL, mdn, NULL );
459                 if ( mnum < 0 ) {
460                         fprintf( stderr,
461                                 "unable to parse file \"%s\" line %d\n",
462                                 mfile, -2*(mnum + 1) );
463                         exit( EXIT_FAILURE );
464                 }
465         }
466
467         /* look for bind requests */
468         if ( bfile ) {
469                 bnum = get_search_filters( bfile, bcreds, battrs, breqs, NULL );
470                 if ( bnum < 0 ) {
471                         fprintf( stderr,
472                                 "unable to parse file \"%s\" line %d\n",
473                                 bfile, -2*(bnum + 1) );
474                         exit( EXIT_FAILURE );
475                 }
476         }
477
478         /* setup friendly option */
479
480         switch ( friendly ) {
481         case 0:
482                 break;
483
484         case 1:
485                 friendlyOpt = "-F";
486                 break;
487
488         default:
489                 /* NOTE: right now we don't need it more than twice */
490         case 2:
491                 friendlyOpt = "-FF";
492                 break;
493         }
494
495         if ( sloops[0] == '\0' ) snprintf( sloops, sizeof( sloops ), "%d", 10 * loops );
496         if ( rloops[0] == '\0' ) snprintf( rloops, sizeof( rloops ), "%d", 20 * loops );
497         if ( aloops[0] == '\0' ) snprintf( aloops, sizeof( aloops ), "%d", loops );
498         if ( nloops[0] == '\0' ) snprintf( nloops, sizeof( nloops ), "%d", loops );
499         if ( mloops[0] == '\0' ) snprintf( mloops, sizeof( mloops ), "%d", loops );
500         if ( bloops[0] == '\0' ) snprintf( bloops, sizeof( bloops ), "%d", 20 * loops );
501
502         /*
503          * generate the search clients
504          */
505
506         sanum = 0;
507         snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
508                 progdir );
509         sargs[sanum++] = scmd;
510         if ( uri ) {
511                 sargs[sanum++] = "-H";
512                 sargs[sanum++] = uri;
513         } else {
514                 sargs[sanum++] = "-h";
515                 sargs[sanum++] = host;
516                 sargs[sanum++] = "-p";
517                 sargs[sanum++] = port;
518         }
519         sargs[sanum++] = "-D";
520         sargs[sanum++] = manager;
521         sargs[sanum++] = "-w";
522         sargs[sanum++] = passwd;
523         sargs[sanum++] = "-l";
524         sargs[sanum++] = sloops;
525         sargs[sanum++] = "-L";
526         sargs[sanum++] = outerloops;
527         sargs[sanum++] = "-r";
528         sargs[sanum++] = retries;
529         sargs[sanum++] = "-t";
530         sargs[sanum++] = delay;
531         if ( friendly ) {
532                 sargs[sanum++] = friendlyOpt;
533         }
534         if ( chaserefs ) {
535                 sargs[sanum++] = "-C";
536         }
537         if ( noattrs ) {
538                 sargs[sanum++] = "-A";
539         }
540         if ( nobind ) {
541                 sargs[sanum++] = "-N";
542         }
543         if ( ignore ) {
544                 sargs[sanum++] = "-i";
545                 sargs[sanum++] = ignore;
546         }
547         sargs[sanum++] = "-b";
548         sargs[sanum++] = NULL;          /* will hold the search base */
549         sargs[sanum++] = "-s";
550         sargs[sanum++] = NULL;          /* will hold the search scope */
551         sargs[sanum++] = "-f";
552         sargs[sanum++] = NULL;          /* will hold the search request */
553
554         sargs[sanum++] = NULL;
555         sargs[sanum++] = NULL;          /* might hold the "attr" request */
556         sextra_args += 2;
557
558         sargs[sanum] = NULL;
559
560         /*
561          * generate the read clients
562          */
563
564         ranum = 0;
565         snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
566                 progdir );
567         rargs[ranum++] = rcmd;
568         if ( uri ) {
569                 rargs[ranum++] = "-H";
570                 rargs[ranum++] = uri;
571         } else {
572                 rargs[ranum++] = "-h";
573                 rargs[ranum++] = host;
574                 rargs[ranum++] = "-p";
575                 rargs[ranum++] = port;
576         }
577         rargs[ranum++] = "-D";
578         rargs[ranum++] = manager;
579         rargs[ranum++] = "-w";
580         rargs[ranum++] = passwd;
581         rargs[ranum++] = "-l";
582         rargs[ranum++] = rloops;
583         rargs[ranum++] = "-L";
584         rargs[ranum++] = outerloops;
585         rargs[ranum++] = "-r";
586         rargs[ranum++] = retries;
587         rargs[ranum++] = "-t";
588         rargs[ranum++] = delay;
589         if ( friendly ) {
590                 rargs[ranum++] = friendlyOpt;
591         }
592         if ( chaserefs ) {
593                 rargs[ranum++] = "-C";
594         }
595         if ( noattrs ) {
596                 rargs[ranum++] = "-A";
597         }
598         if ( ignore ) {
599                 rargs[ranum++] = "-i";
600                 rargs[ranum++] = ignore;
601         }
602         rargs[ranum++] = "-e";
603         rargs[ranum++] = NULL;          /* will hold the read entry */
604
605         rargs[ranum++] = NULL;
606         rargs[ranum++] = NULL;          /* might hold the filter arg */
607         rextra_args += 2;
608
609         rargs[ranum] = NULL;
610
611         /*
612          * generate the modrdn clients
613          */
614
615         nanum = 0;
616         snprintf( ncmd, sizeof ncmd, "%s" LDAP_DIRSEP MODRDNCMD,
617                 progdir );
618         nargs[nanum++] = ncmd;
619         if ( uri ) {
620                 nargs[nanum++] = "-H";
621                 nargs[nanum++] = uri;
622         } else {
623                 nargs[nanum++] = "-h";
624                 nargs[nanum++] = host;
625                 nargs[nanum++] = "-p";
626                 nargs[nanum++] = port;
627         }
628         nargs[nanum++] = "-D";
629         nargs[nanum++] = manager;
630         nargs[nanum++] = "-w";
631         nargs[nanum++] = passwd;
632         nargs[nanum++] = "-l";
633         nargs[nanum++] = nloops;
634         nargs[nanum++] = "-L";
635         nargs[nanum++] = outerloops;
636         nargs[nanum++] = "-r";
637         nargs[nanum++] = retries;
638         nargs[nanum++] = "-t";
639         nargs[nanum++] = delay;
640         if ( friendly ) {
641                 nargs[nanum++] = friendlyOpt;
642         }
643         if ( chaserefs ) {
644                 nargs[nanum++] = "-C";
645         }
646         if ( ignore ) {
647                 nargs[nanum++] = "-i";
648                 nargs[nanum++] = ignore;
649         }
650         nargs[nanum++] = "-e";
651         nargs[nanum++] = NULL;          /* will hold the modrdn entry */
652         nargs[nanum] = NULL;
653         
654         /*
655          * generate the modify clients
656          */
657
658         manum = 0;
659         snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODIFYCMD,
660                 progdir );
661         margs[manum++] = mcmd;
662         if ( uri ) {
663                 margs[manum++] = "-H";
664                 margs[manum++] = uri;
665         } else {
666                 margs[manum++] = "-h";
667                 margs[manum++] = host;
668                 margs[manum++] = "-p";
669                 margs[manum++] = port;
670         }
671         margs[manum++] = "-D";
672         margs[manum++] = manager;
673         margs[manum++] = "-w";
674         margs[manum++] = passwd;
675         margs[manum++] = "-l";
676         margs[manum++] = mloops;
677         margs[manum++] = "-L";
678         margs[manum++] = outerloops;
679         margs[manum++] = "-r";
680         margs[manum++] = retries;
681         margs[manum++] = "-t";
682         margs[manum++] = delay;
683         if ( friendly ) {
684                 margs[manum++] = friendlyOpt;
685         }
686         if ( chaserefs ) {
687                 margs[manum++] = "-C";
688         }
689         if ( ignore ) {
690                 margs[manum++] = "-i";
691                 margs[manum++] = ignore;
692         }
693         margs[manum++] = "-e";
694         margs[manum++] = NULL;          /* will hold the modify entry */
695         margs[manum++] = "-a";;
696         margs[manum++] = NULL;          /* will hold the ava */
697         margs[manum] = NULL;
698
699         /*
700          * generate the add/delete clients
701          */
702
703         aanum = 0;
704         snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
705                 progdir );
706         aargs[aanum++] = acmd;
707         if ( uri ) {
708                 aargs[aanum++] = "-H";
709                 aargs[aanum++] = uri;
710         } else {
711                 aargs[aanum++] = "-h";
712                 aargs[aanum++] = host;
713                 aargs[aanum++] = "-p";
714                 aargs[aanum++] = port;
715         }
716         aargs[aanum++] = "-D";
717         aargs[aanum++] = manager;
718         aargs[aanum++] = "-w";
719         aargs[aanum++] = passwd;
720         aargs[aanum++] = "-l";
721         aargs[aanum++] = aloops;
722         aargs[aanum++] = "-L";
723         aargs[aanum++] = outerloops;
724         aargs[aanum++] = "-r";
725         aargs[aanum++] = retries;
726         aargs[aanum++] = "-t";
727         aargs[aanum++] = delay;
728         if ( friendly ) {
729                 aargs[aanum++] = friendlyOpt;
730         }
731         if ( chaserefs ) {
732                 aargs[aanum++] = "-C";
733         }
734         if ( ignore ) {
735                 aargs[aanum++] = "-i";
736                 aargs[aanum++] = ignore;
737         }
738         aargs[aanum++] = "-f";
739         aargs[aanum++] = NULL;          /* will hold the add data file */
740         aargs[aanum] = NULL;
741
742         /*
743          * generate the bind clients
744          */
745
746         banum = 0;
747         snprintf( bcmd, sizeof bcmd, "%s" LDAP_DIRSEP BINDCMD,
748                 progdir );
749         bargs[banum++] = bcmd;
750         if ( !noinit ) {
751                 bargs[banum++] = "-I";  /* init on each bind */
752         }
753         if ( uri ) {
754                 bargs[banum++] = "-H";
755                 bargs[banum++] = uri;
756         } else {
757                 bargs[banum++] = "-h";
758                 bargs[banum++] = host;
759                 bargs[banum++] = "-p";
760                 bargs[banum++] = port;
761         }
762         bargs[banum++] = "-l";
763         bargs[banum++] = bloops;
764         bargs[banum++] = "-L";
765         bargs[banum++] = outerloops;
766 #if 0
767         bargs[banum++] = "-r";
768         bargs[banum++] = retries;
769         bargs[banum++] = "-t";
770         bargs[banum++] = delay;
771 #endif
772         if ( friendly ) {
773                 bargs[banum++] = friendlyOpt;
774         }
775         if ( chaserefs ) {
776                 bargs[banum++] = "-C";
777         }
778         if ( ignore ) {
779                 bargs[banum++] = "-i";
780                 bargs[banum++] = ignore;
781         }
782         if ( nextra ) {
783                 bargs[banum++] = "-B";
784                 bargs_extra = &bargs[banum++];
785         }
786         bargs[banum++] = "-D";
787         bargs[banum++] = NULL;
788         bargs[banum++] = "-w";
789         bargs[banum++] = NULL;
790         bargs[banum] = NULL;
791
792 #define DOREQ(n,j) ((n) && ((maxkids > (n)) ? ((j) < maxkids ) : ((j) < (n))))
793
794         for ( j = 0; j < MAXREQS; j++ ) {
795                 /* search */
796                 if ( DOREQ( snum, j ) ) {
797                         int     jj = j % snum;
798                         int     x = sanum - sextra_args;
799
800                         /* base */
801                         if ( sbase[jj] != NULL ) {
802                                 sargs[sanum - 7] = sbase[jj];
803
804                         } else {
805                                 sargs[sanum - 7] = slud[jj]->lud_dn;
806                         }
807
808                         /* scope */
809                         if ( slud[jj] != NULL ) {
810                                 sargs[sanum - 5] = (char *)ldap_pvt_scope2str( slud[jj]->lud_scope );
811
812                         } else {
813                                 sargs[sanum - 5] = "sub";
814                         }
815
816                         /* filter */
817                         if ( sreqs[jj] != NULL ) {
818                                 sargs[sanum - 3] = sreqs[jj];
819
820                         } else if ( slud[jj]->lud_filter != NULL ) {
821                                 sargs[sanum - 3] = slud[jj]->lud_filter;
822
823                         } else {
824                                 sargs[sanum - 3] = "(objectClass=*)";
825                         }
826
827                         /* extras */
828                         sargs[x] = NULL;
829
830                         /* attr */
831                         if ( sattrs[jj] != NULL ) {
832                                 sargs[x++] = "-a";
833                                 sargs[x++] = sattrs[jj];
834                         }
835
836                         /* attrs */
837                         if ( slud[jj] != NULL && slud[jj]->lud_attrs != NULL ) {
838                                 int     i;
839
840                                 for ( i = 0; slud[jj]->lud_attrs[ i ] != NULL && x + i < MAXARGS - 1; i++ ) {
841                                         sargs[x + i] = slud[jj]->lud_attrs[ i ];
842                                 }
843                                 sargs[x + i] = NULL;
844                         }
845
846                         fork_child( scmd, sargs );
847                 }
848
849                 /* read */
850                 if ( DOREQ( rnum, j ) ) {
851                         int     jj = j % rnum;
852                         int     x = ranum - rextra_args;
853
854                         rargs[ranum - 3] = rreqs[jj];
855                         if ( rflts[jj] != NULL ) {
856                                 rargs[x++] = "-f";
857                                 rargs[x++] = rflts[jj];
858                         }
859                         rargs[x] = NULL;
860                         fork_child( rcmd, rargs );
861                 }
862
863                 /* rename */
864                 if ( j < nnum ) {
865                         nargs[nanum - 1] = nreqs[j];
866                         fork_child( ncmd, nargs );
867                 }
868
869                 /* modify */
870                 if ( j < mnum ) {
871                         margs[manum - 3] = mdn[j];
872                         margs[manum - 1] = mreqs[j];
873                         fork_child( mcmd, margs );
874                 }
875
876                 /* add/delete */
877                 if ( j < anum ) {
878                         aargs[aanum - 1] = afiles[j];
879                         fork_child( acmd, aargs );
880                 }
881
882                 /* bind */
883                 if ( DOREQ( bnum, j ) ) {
884                         int     jj = j % bnum;
885
886                         if ( nextra ) {
887                                 int     n = ((double)nextra)*rand()/(RAND_MAX + 1.0);
888                                 extra_t *e;
889
890                                 for ( e = extra; n-- > 0; e = e->next )
891                                         ;
892                                 *bargs_extra = e->action;
893                         }
894
895                         if ( battrs[jj] != NULL ) {
896                                 bargs[banum - 3] = manager ? manager : "";
897                                 bargs[banum - 1] = passwd ? passwd : "";
898
899                                 bargs[banum + 0] = "-b";
900                                 bargs[banum + 1] = breqs[jj];
901                                 bargs[banum + 2] = "-f";
902                                 bargs[banum + 3] = bcreds[jj];
903                                 bargs[banum + 4] = "-a";
904                                 bargs[banum + 5] = battrs[jj];
905                                 bargs[banum + 6] = NULL;
906
907                         } else {
908                                 bargs[banum - 3] = breqs[jj];
909                                 bargs[banum - 1] = bcreds[jj];
910                                 bargs[banum] = NULL;
911                         }
912
913                         fork_child( bcmd, bargs );
914                         bargs[banum] = NULL;
915                 }
916         }
917
918         wait4kids( -1 );
919
920         exit( EXIT_SUCCESS );
921 }
922
923 static char *
924 get_file_name( char *dirname, char *filename )
925 {
926         char buf[MAXPATHLEN];
927
928         snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
929                 dirname, filename );
930         return( strdup( buf ));
931 }
932
933
934 static int
935 get_search_filters( char *filename, char *filters[], char *attrs[], char *bases[], LDAPURLDesc *luds[] )
936 {
937         FILE    *fp;
938         int     filter = 0;
939
940         if ( (fp = fopen( filename, "r" )) != NULL ) {
941                 char  line[BUFSIZ];
942
943                 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
944                         char    *nl;
945                         int     got_URL = 0;
946
947                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
948                                 *nl = '\0';
949
950                         if ( luds ) luds[filter] = NULL;
951
952                         if ( luds && strncmp( line, "ldap:///", STRLENOF( "ldap:///" ) ) == 0 ) {
953                                 LDAPURLDesc     *lud;
954
955                                 got_URL = 1;
956                                 bases[filter] = NULL;
957                                 if ( ldap_url_parse( line, &lud ) != LDAP_URL_SUCCESS ) {
958                                         filter = -filter - 1;
959                                         break;
960                                 }
961
962                                 if ( lud->lud_dn == NULL || lud->lud_exts != NULL ) {
963                                         filter = -filter - 1;
964                                         ldap_free_urldesc( lud );
965                                         break;
966                                 }
967
968                                 luds[filter] = lud;
969
970                         } else {
971                                 bases[filter] = ArgDup( line );
972                         }
973                         fgets( line, BUFSIZ, fp );
974                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
975                                 *nl = '\0';
976
977                         filters[filter] = ArgDup( line );
978                         if ( attrs ) {
979                                 if ( filters[filter][0] == '+') {
980                                         char    *sep = strchr( filters[filter], ':' );
981
982                                         attrs[ filter ] = &filters[ filter ][ 1 ];
983                                         if ( sep != NULL ) {
984                                                 sep[ 0 ] = '\0';
985                                                 /* NOTE: don't free this! */
986                                                 filters[ filter ] = &sep[ 1 ];
987                                         }
988
989                                 } else {
990                                         attrs[ filter ] = NULL;
991                                 }
992                         }
993                         filter++;
994
995                 }
996                 fclose( fp );
997         }
998
999         return filter;
1000 }
1001
1002
1003 static int
1004 get_read_entries( char *filename, char *entries[], char *filters[] )
1005 {
1006         FILE    *fp;
1007         int     entry = 0;
1008
1009         if ( (fp = fopen( filename, "r" )) != NULL ) {
1010                 char  line[BUFSIZ];
1011
1012                 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
1013                         char *nl;
1014
1015                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
1016                                 *nl = '\0';
1017                         if ( filters != NULL && line[0] == '+' ) {
1018                                 LDAPURLDesc     *lud;
1019
1020                                 if ( ldap_url_parse( &line[1], &lud ) != LDAP_URL_SUCCESS ) {
1021                                         entry = -entry - 1;
1022                                         break;
1023                                 }
1024
1025                                 if ( lud->lud_dn == NULL || lud->lud_dn[ 0 ] == '\0' ) {
1026                                         ldap_free_urldesc( lud );
1027                                         entry = -entry - 1;
1028                                         break;
1029                                 }
1030
1031                                 entries[entry] = ArgDup( lud->lud_dn );
1032
1033                                 if ( lud->lud_filter ) {
1034                                         filters[entry] = ArgDup( lud->lud_filter );
1035
1036                                 } else {
1037                                         filters[entry] = ArgDup( "(objectClass=*)" );
1038                                 }
1039                                 ldap_free_urldesc( lud );
1040
1041                         } else {
1042                                 entries[entry] = ArgDup( line );
1043                         }
1044
1045                         entry++;
1046
1047                 }
1048                 fclose( fp );
1049         }
1050
1051         return( entry );
1052 }
1053
1054 #ifndef HAVE_WINSOCK
1055 static void
1056 fork_child( char *prog, char **args )
1057 {
1058         /* note: obscures global pid var; intended */
1059         pid_t   pid;
1060
1061         wait4kids( maxkids );
1062
1063         switch ( pid = fork() ) {
1064         case 0:         /* child */
1065 #ifdef HAVE_EBCDIC
1066                 /* The __LIBASCII execvp only handles ASCII "prog",
1067                  * we still need to translate the arg vec ourselves.
1068                  */
1069                 { char *arg2[MAXREQS];
1070                 int i;
1071
1072                 for (i=0; args[i]; i++) {
1073                         arg2[i] = ArgDup(args[i]);
1074                         __atoe(arg2[i]);
1075                 }
1076                 arg2[i] = NULL;
1077                 args = arg2; }
1078 #endif
1079                 execvp( prog, args );
1080                 tester_perror( "execvp", NULL );
1081                 { int i;
1082                         for (i=0; args[i]; i++);
1083                         fprintf(stderr,"%d args\n", i);
1084                         for (i=0; args[i]; i++)
1085                                 fprintf(stderr,"%d %s\n", i, args[i]);
1086                 }
1087
1088                 exit( EXIT_FAILURE );
1089                 break;
1090
1091         case -1:        /* trouble */
1092                 tester_perror( "fork", NULL );
1093                 break;
1094
1095         default:        /* parent */
1096                 nkids++;
1097                 break;
1098         }
1099 }
1100
1101 static void
1102 wait4kids( int nkidval )
1103 {
1104         int             status;
1105
1106         while ( nkids >= nkidval ) {
1107                 wait( &status );
1108
1109                 if ( WIFSTOPPED(status) ) {
1110                         fprintf( stderr,
1111                             "stopping: child stopped with signal %d\n",
1112                             (int) WSTOPSIG(status) );
1113
1114                 } else if ( WIFSIGNALED(status) ) {
1115                         fprintf( stderr, 
1116                             "stopping: child terminated with signal %d%s\n",
1117                             (int) WTERMSIG(status),
1118 #ifdef WCOREDUMP
1119                                 WCOREDUMP(status) ? ", core dumped" : ""
1120 #else
1121                                 ""
1122 #endif
1123                                 );
1124                         exit( WEXITSTATUS(status)  );
1125
1126                 } else if ( WEXITSTATUS(status) != 0 ) {
1127                         fprintf( stderr, 
1128                             "stopping: child exited with status %d\n",
1129                             (int) WEXITSTATUS(status) );
1130                         exit( WEXITSTATUS(status) );
1131
1132                 } else {
1133                         nkids--;
1134                 }
1135         }
1136 }
1137 #else
1138
1139 static void
1140 wait4kids( int nkidval )
1141 {
1142         int rc, i;
1143
1144         while ( nkids >= nkidval ) {
1145                 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
1146                 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
1147                         children[i] = children[i+1];
1148                 nkids--;
1149         }
1150 }
1151
1152 static void
1153 fork_child( char *prog, char **args )
1154 {
1155         int rc;
1156
1157         wait4kids( maxkids );
1158
1159         rc = _spawnvp( _P_NOWAIT, prog, args );
1160
1161         if ( rc == -1 ) {
1162                 tester_perror( "_spawnvp", NULL );
1163         } else {
1164                 children[nkids++] = (HANDLE)rc;
1165         }
1166 }
1167 #endif