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