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