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