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