/* * lib/kdb/t_kdb.c * * Copyright 1995 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ /* * t_kdb.c - Test [and optionally obtain timing information about] the * Kerberos database functions. */ #define KDB5_DISPATCH #include "k5-int.h" #include #if HAVE_SRAND48 #define RAND() lrand48() #define SRAND(a) srand48(a) #define RAND_TYPE long #elif HAVE_SRAND #define RAND() rand() #define SRAND(a) srand(a) #define RAND_TYPE int #elif HAVE_SRANDOM #define RAND() random() #define SRAND(a) srandom(a) #define RAND_TYPE long #else /* no random */ need a random number generator #endif /* no random */ #define T_KDB_N_PASSES 100 #define T_KDB_DEF_DB "test_db" #define MAX_PNAME_LEN 1024 #define MAX_PRINC_COMPS 8 #define MAX_COMP_SIZE 32 #define RANDOM(a,b) (a + (RAND() % (b-a))) enum dbtype { DB_UFO, DB_DEFAULT, DB_BERKELEY, DB_DBM }; char *programname = (char *) NULL; krb5_data mprinc_data_entries[] = { { 0, sizeof("master")-1, "master"}, { 0, sizeof("key")-1, "key"} }; krb5_principal_data master_princ_data = { 0, /* Magic number */ { 0, sizeof("test.realm")-1, "test.realm"}, /* Realm */ mprinc_data_entries, /* Name/instance */ sizeof(mprinc_data_entries)/ sizeof(mprinc_data_entries[0]), /* Number */ KRB5_NT_SRV_INST /* Type */ }; struct timeval tstart_time, tend_time; struct timezone dontcare; krb5_principal *recorded_principals = (krb5_principal *) NULL; char **recorded_names = (char **) NULL; extern DBM *db_dbm_open PROTOTYPE((char *, int, int)); extern void db_dbm_close PROTOTYPE((DBM *)); extern datum db_dbm_fetch PROTOTYPE((DBM *, datum)); extern datum db_dbm_firstkey PROTOTYPE((DBM *)); extern datum db_dbm_nextkey PROTOTYPE((DBM *)); extern int db_dbm_delete PROTOTYPE((DBM *, datum)); extern int db_dbm_store PROTOTYPE((DBM *, datum, datum, int)); extern int db_dbm_error PROTOTYPE((DBM *)); extern int db_dbm_clearerr PROTOTYPE((DBM *)); extern int db_dbm_dirfno PROTOTYPE((DBM *)); static kdb5_dispatch_table berkeley_dispatch = { "Berkeley Hashed Database", ".db", /* Index file name ext */ (char *) NULL, /* Data file name ext */ ".ok", /* Lock file name ext */ db_dbm_open, /* Open Database */ db_dbm_close, /* Close Database */ db_dbm_fetch, /* Fetch Key */ db_dbm_firstkey, /* Fetch First Key */ db_dbm_nextkey, /* Fetch Next Key */ db_dbm_delete, /* Delete Key */ db_dbm_store, /* Store Key */ db_dbm_error, /* Get Database Error */ db_dbm_clearerr, /* Clear Database Error */ db_dbm_dirfno, /* Get Database FD num */ (int (*)()) NULL /* Get Database FD num */ }; static kdb5_dispatch_table dbm_dispatch = { "Stock [N]DBM Database", ".dir", /* Index file name ext */ ".pag", /* Data file name ext */ ".ok", /* Lock file name ext */ dbm_open, /* Open Database */ dbm_close, /* Close Database */ dbm_fetch, /* Fetch Key */ dbm_firstkey, /* Fetch First Key */ dbm_nextkey, /* Fetch Next Key */ dbm_delete, /* Delete Key */ dbm_store, /* Store Key */ /* * The following are #ifdef'd because they have the potential to be * macros rather than functions. */ #ifdef dbm_error (int (*)()) NULL, /* Get Database Error */ #else /* dbm_error */ dbm_error, /* Get Database Error */ #endif /* dbm_error */ #ifdef dbm_clearerr (int (*)()) NULL, /* Clear Database Error */ #else /* dbm_clearerr */ dbm_clearerr, /* Clear Database Error */ #endif /* dbm_clearerr */ #ifdef dbm_dirfno (int (*)()) NULL, /* Get Database FD num */ #else /* dbm_dirfno */ dbm_dirfno, /* Get Database FD num */ #endif /* dbm_dirfno */ #ifdef dbm_pagfno (int (*)()) NULL, /* Get Database FD num */ #else /* dbm_pagfno */ dbm_pagfno, /* Get Database FD num */ #endif /* dbm_pagfno */ }; /* * Timer macros. */ #define swatch_on() ((void) gettimeofday(&tstart_time, &dontcare)) #define swatch_eltime() ((gettimeofday(&tend_time, &dontcare)) ? -1.0 : \ (((float) (tend_time.tv_sec - \ tstart_time.tv_sec)) + \ (((float) (tend_time.tv_usec - \ tstart_time.tv_usec))/1000000.0))) /* * Free all principals and names in the recorded names list. */ void free_principals(kcontext, nentries) krb5_context kcontext; int nentries; { int i; if (recorded_principals) { for (i=0; i 1) fprintf(stdout, "%s: generating %d names\n", programname, passes); for (passno=0; passno passes) nvalid = passes; if (verbose > 1) fprintf(stdout, "%s: priming database with %d principals\n", programname, nvalid); highwater = 0; for (passno=0; passno 4) fprintf(stderr, "*A(%s)\n", playback_name(passno)); highwater++; } if (verbose > 1) fprintf(stderr, "%s: beginning random loop\n", programname); /* Loop through some number of times and pick random operations */ for (i=0; i<3*passes; i++) { discrim = RANDOM(0,100); /* Add a principal 25% of the time, if possible */ if ((discrim < 25) && (nvalid < passes)) { op = "adding principal"; coinflip = RANDOM(0,2); kbp = (coinflip) ? &stat_kb : (krb5_keyblock *) NULL; if (timing) { swatch_on(); } if (kret = add_principal(kcontext, playback_principal(nvalid), &master_encblock, kbp, rseed)) { oparg = playback_name(nvalid); goto cya; } if (timing) { elapsed = swatch_eltime(); accumulated[0].t_time += elapsed; accumulated[0].t_number++; } if (verbose > 4) fprintf(stderr, "*A(%s)\n", playback_name(nvalid)); nvalid++; if (nvalid > highwater) highwater = nvalid; } /* Delete a principal 15% of the time, if possible */ else if ((discrim > 85) && (nvalid > 10)) { op = "deleting principal"; if (timing) { swatch_on(); } if (kret = delete_principal(kcontext, playback_principal(nvalid-1))) { oparg = playback_name(nvalid-1); goto cya; } if (timing) { elapsed = swatch_eltime(); accumulated[2].t_time += elapsed; accumulated[2].t_number++; } if (verbose > 4) fprintf(stderr, "XD(%s)\n", playback_name(nvalid-1)); nvalid--; } /* Otherwise, find a principal */ else { op = "looking up principal"; passno = RANDOM(0, nvalid); if (timing) { swatch_on(); } if (kret = find_principal(kcontext, playback_principal(passno), check)) { oparg = playback_name(passno); goto cya; } if (timing) { elapsed = swatch_eltime(); accumulated[1].t_time += elapsed; accumulated[1].t_number++; } if (verbose > 4) fprintf(stderr, "-S(%s)\n", playback_name(passno)); } } if (!dontclean) { /* Clean up the remaining principals */ if (verbose > 1) fprintf(stdout, "%s: deleting remaining %d principals\n", programname, nvalid); for (passno=0; passno 4) fprintf(stderr, "XD(%s)\n", playback_name(passno)); } } cya: if (verbose) fprintf(stdout, "%s: highwater mark was %d principals\n", programname, highwater); if (accumulated[0].t_number && timing) fprintf(stdout, "%s: performed %8d additions in %9.4f seconds (%9.4f/add)\n", programname, accumulated[0].t_number, accumulated[0].t_time, accumulated[0].t_time / (float) accumulated[0].t_number); if (accumulated[1].t_number && timing) fprintf(stdout, "%s: performed %8d lookups in %9.4f seconds (%9.4f/search)\n", programname, accumulated[1].t_number, accumulated[1].t_time, accumulated[1].t_time / (float) accumulated[1].t_number); if (accumulated[2].t_number && timing) fprintf(stdout, "%s: performed %8d deletions in %9.4f seconds (%9.4f/delete)\n", programname, accumulated[2].t_number, accumulated[2].t_time, accumulated[2].t_time / (float) accumulated[2].t_number); if (kret) goto goodbye; } else { /* * Generate principal names. */ for (passno=0; passno 4) fprintf(stderr, "*A(%s)\n", playback_name(passno)); } if (timing) { elapsed = swatch_eltime(); fprintf(stdout, "%s: added %d principals in %9.4f seconds (%9.4f/add)\n", programname, passes, elapsed, elapsed/((float) passes)); } /* * Lookup principals. */ if (timing) { swatch_on(); } for (passno=0; passno 4) fprintf(stderr, "-S(%s)\n", playback_name(passno)); } if (timing) { elapsed = swatch_eltime(); fprintf(stdout, "%s: found %d principals in %9.4f seconds (%9.4f/search)\n", programname, passes, elapsed, elapsed/((float) passes)); } /* * Delete principals. */ if (!dontclean) { if (timing) { swatch_on(); } for (passno=passes-1; passno>=0; passno--) { op = "deleting principal"; if (kret = delete_principal(kcontext, playback_principal(passno))) goto goodbye; if (verbose > 4) fprintf(stderr, "XD(%s)\n", playback_name(passno)); } if (timing) { elapsed = swatch_eltime(); fprintf(stdout, "%s: deleted %d principals in %9.4f seconds (%9.4f/delete)\n", programname, passes, elapsed, elapsed/((float) passes)); } } } goodbye: if (kret) fprintf(stderr, "%s: error while %s %s%s(%s)\n", programname, op, linkage, oparg, error_message(kret)); free_principals(kcontext, passes); if (db_open) (void) krb5_db_fini(kcontext); if (db_created) { if (!kret && !save_db) { switch (db_type) { case DB_BERKELEY: op = "setting up Berkeley database operations"; if (kret = kdb5_db_set_dbops(kcontext, &berkeley_dispatch)) goto goodbye1; break; case DB_DBM: op = "setting up DBM database operations"; if (kret = kdb5_db_set_dbops(kcontext, &dbm_dispatch)) goto goodbye1; break; case DB_DEFAULT: break; default: op = "checking database type"; kret = EINVAL; goto goodbye1; break; } kdb5_db_destroy(kcontext, db); krb5_db_fini(kcontext); } else { if (kret && verbose) fprintf(stderr, "%s: database not deleted because of error\n", programname); } } goodbye1: return((kret) ? 1 : 0); } /* * usage: * t_kdb [-t] - Get timing information. * [-r] - Generate random cases. * [-n ] - Use as the number of passes. * [-c] - Check contents. * [-v] - Verbose output. * [-d ] - Database name. * [-s] - Save database even on successful completion. * [-D] - Leave database dirty. * [-o] - Use dbm instead of default. * [-O] - Use Berkeley db instead of default. */ int main(argc, argv) int argc; char *argv[]; { int option; extern char *optarg; int do_time, do_random, num_passes, check_cont, verbose, error; int save_db, dont_clean; enum dbtype db_type; char *db_name; programname = argv[0]; if (strrchr(programname, (int) '/')) programname = strrchr(programname, (int) '/') + 1; SRAND((RAND_TYPE)time((void *) NULL)); /* Default values. */ do_time = 0; do_random = 0; num_passes = T_KDB_N_PASSES; check_cont = 0; verbose = 0; db_name = T_KDB_DEF_DB; save_db = 0; dont_clean = 0; db_type = DB_DEFAULT; error = 0; /* Parse argument list */ while ((option = getopt(argc, argv, "cd:n:orstvDO")) != EOF) { switch (option) { case 'c': check_cont = 1; break; case 'd': db_name = optarg; break; case 'n': if (sscanf(optarg, "%d", &num_passes) != 1) { fprintf(stderr, "%s: %s is not a valid number for %c option\n", programname, optarg, option); error++; } break; case 'r': do_random = 1; break; case 's': save_db = 1; break; case 't': do_time = 1; break; case 'v': verbose++; break; case 'D': dont_clean = 1; break; case 'o': db_type = DB_DBM; break; case 'O': db_type = DB_BERKELEY; break; default: error++; break; } } if (error) fprintf(stderr, "%s: usage is %s [-crstv] [-d ] [-n ]\n", programname, programname); else error = do_testing(db_name, num_passes, verbose, do_time, do_random, check_cont, save_db, dont_clean, db_type); return(error); }