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