/* tests/hammer/kdc5_hammer.c */ /* * Copyright 1990,1991 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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. */ #include #include #include "k5-int.h" #include "com_err.h" #define KRB5_DEFAULT_OPTIONS 0 #define KRB5_DEFAULT_LIFE 60*60*8 /* 8 hours */ #define KRB5_RENEWABLE_LIFE 60*60*2 /* 2 hours */ struct h_timer { float ht_cumulative; float ht_min; float ht_max; krb5_int32 ht_observations; }; extern int optind; extern char *optarg; char *prog; static int brief; static char *cur_realm = 0; static int do_timer = 0; krb5_data tgtname = { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME }; int verify_cs_pair (krb5_context, char *, krb5_principal, char *, char *, int, int, int, krb5_ccache); int get_tgt (krb5_context, char *, krb5_principal *, krb5_ccache); static void usage(who, status) char *who; int status; { fprintf(stderr, "usage: %s -p prefix -n num_to_check [-c cachename] [-r realmname]\n", who); fprintf(stderr, "\t [-D depth]\n"); fprintf(stderr, "\t [-P preauth type] [-R repeat_count] [-t] [-b] [-v] \n"); exit(status); } static krb5_preauthtype * patype = NULL, patypedata[2] = { 0, -1 }; static krb5_context test_context; struct timeval tstart_time, tend_time; struct timezone dontcare; struct h_timer in_tkt_times = { 0.0, 1000000.0, -1.0, 0 }; struct h_timer tgs_req_times = { 0.0, 1000000.0, -1.0, 0 }; /* * 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))) int main(argc, argv) int argc; char **argv; { krb5_ccache ccache = NULL; char *cache_name = NULL; /* -f option */ int option; int errflg = 0; krb5_error_code code; int num_to_check, n, i, j, repeat_count, counter; int n_tried, errors; char prefix[BUFSIZ], client[4096], server[4096]; int depth; char ctmp[4096], ctmp2[BUFSIZ], stmp[4096], stmp2[BUFSIZ]; krb5_principal client_princ; krb5_error_code retval; krb5_init_context(&test_context); if (strrchr(argv[0], '/')) prog = strrchr(argv[0], '/')+1; else prog = argv[0]; num_to_check = 0; depth = 1; repeat_count = 1; brief = 0; n_tried = 0; errors = 0; while ((option = getopt(argc, argv, "D:p:n:c:R:P:e:bvr:t")) != -1) { switch (option) { case 't': do_timer = 1; break; case 'b': brief = 1; break; case 'v': brief = 0; break; case 'R': repeat_count = atoi(optarg); /* how many times? */ break; case 'r': cur_realm = optarg; break; case 'D': depth = atoi(optarg); /* how deep to go */ break; case 'p': /* prefix name to check */ strncpy(prefix, optarg, sizeof(prefix) - 1); prefix[sizeof(prefix) - 1] = '\0'; break; case 'n': /* how many to check */ num_to_check = atoi(optarg); break; case 'P': patypedata[0] = atoi(optarg); patype = patypedata; break; case 'c': if (ccache == NULL) { cache_name = optarg; code = krb5_cc_resolve (test_context, cache_name, &ccache); if (code != 0) { com_err (prog, code, "resolving %s", cache_name); errflg++; } } else { fprintf(stderr, "Only one -c option allowed\n"); errflg++; } break; case '?': default: errflg++; break; } } if (!(num_to_check && prefix[0])) usage(prog, 1); if (!cur_realm) { if ((retval = krb5_get_default_realm(test_context, &cur_realm))) { com_err(prog, retval, "while retrieving default realm name"); exit(1); } } if (ccache == NULL) { if ((code = krb5_cc_default(test_context, &ccache))) { com_err(prog, code, "while getting default ccache"); exit(1); } } memset(ctmp, 0, sizeof(ctmp)); memset(stmp, 0, sizeof(stmp)); for (counter = 0; counter < repeat_count; counter++) { fprintf(stderr, "\nRound %d\n", counter); for (n = 1; n <= num_to_check; n++) { /* build the new principal name */ /* we can't pick random names because we need to generate all the names again given a prefix and count to test the db lib and kdb */ ctmp[0] = '\0'; for (i = 1; i <= depth; i++) { (void) snprintf(ctmp2, sizeof(ctmp2), "%s%s%d-DEPTH-%d", (i != 1) ? "/" : "", prefix, n, i); ctmp2[sizeof(ctmp2) - 1] = '\0'; strncat(ctmp, ctmp2, sizeof(ctmp) - 1 - strlen(ctmp)); ctmp[sizeof(ctmp) - 1] = '\0'; snprintf(client, sizeof(client), "%s@%s", ctmp, cur_realm); if (get_tgt (test_context, client, &client_princ, ccache)) { errors++; n_tried++; continue; } n_tried++; stmp[0] = '\0'; for (j = 1; j <= depth; j++) { (void) snprintf(stmp2, sizeof(stmp2), "%s%s%d-DEPTH-%d", (j != 1) ? "/" : "", prefix, n, j); stmp2[sizeof (stmp2) - 1] = '\0'; strncat(stmp, stmp2, sizeof(stmp) - 1 - strlen(stmp)); stmp[sizeof(stmp) - 1] = '\0'; snprintf(server, sizeof(server), "%s@%s", stmp, cur_realm); if (verify_cs_pair(test_context, client, client_princ, stmp, cur_realm, n, i, j, ccache)) errors++; n_tried++; } krb5_free_principal(test_context, client_princ); } } } fprintf (stderr, "\nTried %d. Got %d errors.\n", n_tried, errors); if (do_timer) { if (in_tkt_times.ht_observations) fprintf(stderr, "%8d AS_REQ requests: %9.6f average (min: %9.6f, max:%9.6f)\n", in_tkt_times.ht_observations, in_tkt_times.ht_cumulative / (float) in_tkt_times.ht_observations, in_tkt_times.ht_min, in_tkt_times.ht_max); if (tgs_req_times.ht_observations) fprintf(stderr, "%8d TGS_REQ requests: %9.6f average (min: %9.6f, max:%9.6f)\n", tgs_req_times.ht_observations, tgs_req_times.ht_cumulative / (float) tgs_req_times.ht_observations, tgs_req_times.ht_min, tgs_req_times.ht_max); } (void) krb5_cc_close(test_context, ccache); krb5_free_context(test_context); exit(errors); } static krb5_error_code get_server_key(context, server, enctype, key) krb5_context context; krb5_principal server; krb5_enctype enctype; krb5_keyblock ** key; { krb5_error_code retval; krb5_encrypt_block eblock; char * string; krb5_data salt; krb5_data pwd; if ((retval = krb5_principal2salt(context, server, &salt))) return retval; if ((retval = krb5_unparse_name(context, server, &string))) goto cleanup_salt; pwd.data = string; pwd.length = strlen(string); if ((*key = (krb5_keyblock *)malloc(sizeof(krb5_keyblock)))) { krb5_use_enctype(context, &eblock, enctype); if ((retval = krb5_string_to_key(context, &eblock, *key, &pwd, &salt))) free(*key); } else retval = ENOMEM; free(string); cleanup_salt: free(salt.data); return retval; } int verify_cs_pair(context, p_client_str, p_client, service, hostname, p_num, c_depth, s_depth, ccache) krb5_context context; char *p_client_str; krb5_principal p_client; char * service; char * hostname; int p_num, c_depth, s_depth; krb5_ccache ccache; { krb5_error_code retval; krb5_creds creds; krb5_creds * credsp = NULL; krb5_ticket * ticket = NULL; krb5_keyblock * keyblock = NULL; krb5_auth_context auth_context = NULL; krb5_data request_data = empty_data(); char * sname; float dt; if (brief) fprintf(stderr, "\tprinc (%d) client (%d) for server (%d)\n", p_num, c_depth, s_depth); else fprintf(stderr, "\tclient %s for server %s\n", p_client_str, service); /* Initialize variables */ memset(&creds, 0, sizeof(creds)); /* Do client side */ if (asprintf(&sname, "%s@%s", service, hostname) >= 0) { retval = krb5_parse_name(context, sname, &creds.server); free(sname); } else retval = ENOMEM; if (retval) return(retval); /* obtain ticket & session key */ if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) { com_err(prog, retval, "while getting client princ for %s", hostname); return retval; } if ((retval = krb5_get_credentials(context, 0, ccache, &creds, &credsp))) { com_err(prog, retval, "while getting creds for %s", hostname); return retval; } if (do_timer) swatch_on(); if ((retval = krb5_mk_req_extended(context, &auth_context, 0, NULL, credsp, &request_data))) { com_err(prog, retval, "while preparing AP_REQ for %s", hostname); goto cleanup; } krb5_auth_con_free(context, auth_context); auth_context = NULL; /* Do server side now */ if ((retval = get_server_key(context, credsp->server, credsp->keyblock.enctype, &keyblock))) { com_err(prog, retval, "while getting server key for %s", hostname); goto cleanup; } if (krb5_auth_con_init(context, &auth_context)) { com_err(prog, retval, "while creating auth_context for %s", hostname); goto cleanup; } if (krb5_auth_con_setuseruserkey(context, auth_context, keyblock)) { com_err(prog, retval, "while setting auth_context key %s", hostname); goto cleanup; } if ((retval = krb5_rd_req(context, &auth_context, &request_data, NULL /* server */, 0, NULL, &ticket))) { com_err(prog, retval, "while decoding AP_REQ for %s", hostname); goto cleanup; } if (do_timer) { dt = swatch_eltime(); tgs_req_times.ht_cumulative += dt; tgs_req_times.ht_observations++; if (dt > tgs_req_times.ht_max) tgs_req_times.ht_max = dt; if (dt < tgs_req_times.ht_min) tgs_req_times.ht_min = dt; } if (!(krb5_principal_compare(context,ticket->enc_part2->client,p_client))){ char *returned_client; if ((retval = krb5_unparse_name(context, ticket->enc_part2->client, &returned_client))) com_err (prog, retval, "Client not as expected, but cannot unparse client name"); else com_err (prog, 0, "Client not as expected (%s).", returned_client); retval = KRB5_PRINC_NOMATCH; free(returned_client); } else { retval = 0; } cleanup: krb5_free_cred_contents(context, &creds); krb5_free_ticket(context, ticket); krb5_auth_con_free(context, auth_context); krb5_free_keyblock(context, keyblock); krb5_free_data_contents(context, &request_data); krb5_free_creds(context, credsp); return retval; } int get_tgt (context, p_client_str, p_client, ccache) krb5_context context; char *p_client_str; krb5_principal *p_client; krb5_ccache ccache; { char *cache_name = NULL; /* -f option */ long lifetime = KRB5_DEFAULT_LIFE; /* -l option */ int options = KRB5_DEFAULT_OPTIONS; krb5_error_code code; krb5_creds my_creds; krb5_timestamp start; krb5_principal tgt_server; float dt; if (!brief) fprintf(stderr, "\tgetting TGT for %s\n", p_client_str); if ((code = krb5_timeofday(context, &start))) { com_err(prog, code, "while getting time of day"); return(-1); } memset(&my_creds, 0, sizeof(my_creds)); if ((code = krb5_parse_name (context, p_client_str, p_client))) { com_err (prog, code, "when parsing name %s", p_client_str); return(-1); } if ((code = krb5_build_principal_ext(context, &tgt_server, krb5_princ_realm(context, *p_client)->length, krb5_princ_realm(context, *p_client)->data, tgtname.length, tgtname.data, krb5_princ_realm(context, *p_client)->length, krb5_princ_realm(context, *p_client)->data, 0))) { com_err(prog, code, "when setting up tgt principal"); return(-1); } my_creds.client = *p_client; my_creds.server = tgt_server; code = krb5_cc_initialize (context, ccache, *p_client); if (code != 0) { com_err (prog, code, "when initializing cache %s", cache_name?cache_name:""); return(-1); } my_creds.times.starttime = 0; /* start timer when request gets to KDC */ my_creds.times.endtime = start + lifetime; my_creds.times.renew_till = 0; if (do_timer) swatch_on(); code = krb5_get_in_tkt_with_password(context, options, 0, NULL, patype, p_client_str, ccache, &my_creds, 0); if (do_timer) { dt = swatch_eltime(); in_tkt_times.ht_cumulative += dt; in_tkt_times.ht_observations++; if (dt > in_tkt_times.ht_max) in_tkt_times.ht_max = dt; if (dt < in_tkt_times.ht_min) in_tkt_times.ht_min = dt; } my_creds.server = my_creds.client = 0; krb5_free_principal(context, tgt_server); krb5_free_cred_contents(context, &my_creds); if (code != 0) { com_err (prog, code, "while getting initial credentials"); return(-1); } return(0); }