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