/* Parent process: iterate over the KDB, using a callback that synchronizes * with the locking child. */ static int iterator(struct cb_arg *cb_arg, char **db_args, pid_t child) { krb5_error_code retval; krb5_context ctx; retval = krb5_init_context_profile(NULL, KRB5_INIT_CONTEXT_KDC, &ctx); if (retval) goto cleanup; retval = krb5_db_open(ctx, db_args, KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN); if (retval) goto cleanup; retval = krb5_db_iterate(ctx, NULL, cb, cb_arg, 0); if (retval) goto cleanup; retval = krb5_db_fini(ctx); cleanup: krb5_free_context(ctx); if (retval) { com_err("iterator", retval, ""); kill(child, SIGTERM); exit(1); } return retval; }
/* * Usaage is: * tabdump [-H] [-c] [-e] [-n] [-o outfile] dumptype */ void tabdump(int argc, char **argv) { int ch; size_t i; const char *rectype; struct rec_args args; struct tdopts opts; krb5_error_code ret; memset(&opts, 0, sizeof(opts)); memset(&args, 0, sizeof(args)); optind = 1; while ((ch = getopt(argc, argv, "Hceno:")) != -1) { switch (ch) { case 'H': opts.omitheader = 1; break; case 'c': opts.csv = 1; break; case 'e': opts.emptyhex_empty = 1; break; case 'n': opts.numeric = 1; break; case 'o': opts.fname = optarg; break; case '?': default: usage(); break; } } if (argc - optind < 1) usage(); rectype = argv[optind]; for (i = 0; i < NTDTYPES; i++) { if (strcmp(rectype, tdtypes[i].rectype) == 0) { setup_args(&args, &tdtypes[i], &opts); break; } } if (i >= NTDTYPES) usage(); ret = krb5_db_iterate(util_context, NULL, tditer, &args, 0); cleanup_args(&args); if (ret) { com_err(progname, ret, _("performing tabular dump")); exit_status++; } }
krb5_error_code kdb_iter_entry(kadm5_server_handle_t handle, void (*iter_fct)(void *, krb5_principal), void *data) { iter_data id; krb5_error_code ret; id.func = iter_fct; id.data = data; if (ret = krb5_db_iterate(handle->context, kdb_iter_func, &id)) return(ret); return(0); }
krb5_error_code kdb_iter_entry(kadm5_server_handle_t handle, char *match_entry, void (*iter_fct)(void *, krb5_principal), void *data) { iter_data id; krb5_error_code ret; id.func = iter_fct; id.data = data; /* Solaris Kerberos: added support for db_args */ ret = krb5_db_iterate(handle->context, match_entry, kdb_iter_func, &id, NULL); if (ret) return(ret); return(0); }
int main() { krb5_db_entry *ent; osa_policy_ent_t pol; krb5_pa_data **e_data; const char *status; char *defrealm; int count; CHECK(krb5_init_context_profile(NULL, KRB5_INIT_CONTEXT_KDC, &ctx)); /* Currently necessary for krb5_db_open to work. */ CHECK(krb5_get_default_realm(ctx, &defrealm)); /* If we can, revert to requiring all entries match sample_princ in * iter_princ_handler */ CHECK_COND(krb5_db_inited(ctx) != 0); CHECK(krb5_db_create(ctx, NULL)); CHECK(krb5_db_inited(ctx)); CHECK(krb5_db_fini(ctx)); CHECK_COND(krb5_db_inited(ctx) != 0); CHECK_COND(krb5_db_inited(ctx) != 0); CHECK(krb5_db_open(ctx, NULL, KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN)); CHECK(krb5_db_inited(ctx)); /* Manipulate a policy, leaving it in place at the end. */ CHECK_COND(krb5_db_put_policy(ctx, &sample_policy) != 0); CHECK_COND(krb5_db_delete_policy(ctx, polname) != 0); CHECK_COND(krb5_db_get_policy(ctx, polname, &pol) == KRB5_KDB_NOENTRY); CHECK(krb5_db_create_policy(ctx, &sample_policy)); CHECK_COND(krb5_db_create_policy(ctx, &sample_policy) != 0); CHECK(krb5_db_get_policy(ctx, polname, &pol)); check_policy(pol); pol->pw_min_length--; CHECK(krb5_db_put_policy(ctx, pol)); krb5_db_free_policy(ctx, pol); CHECK(krb5_db_get_policy(ctx, polname, &pol)); CHECK_COND(pol->pw_min_length == sample_policy.pw_min_length - 1); krb5_db_free_policy(ctx, pol); CHECK(krb5_db_delete_policy(ctx, polname)); CHECK_COND(krb5_db_put_policy(ctx, &sample_policy) != 0); CHECK_COND(krb5_db_delete_policy(ctx, polname) != 0); CHECK_COND(krb5_db_get_policy(ctx, polname, &pol) == KRB5_KDB_NOENTRY); CHECK(krb5_db_create_policy(ctx, &sample_policy)); count = 0; CHECK(krb5_db_iter_policy(ctx, NULL, iter_pol_handler, &count)); CHECK_COND(count == 1); /* Create a principal. */ CHECK_COND(krb5_db_delete_principal(ctx, &sample_princ) == KRB5_KDB_NOENTRY); CHECK_COND(krb5_db_get_principal(ctx, &xrealm_princ, 0, &ent) == KRB5_KDB_NOENTRY); CHECK(krb5_db_put_principal(ctx, &sample_entry)); /* Putting again will fail with LDAP (due to KADM5_PRINCIPAL in mask) * but succeed with DB2, so don't check the result. */ (void)krb5_db_put_principal(ctx, &sample_entry); /* But it should succeed in both back ends with KADM5_LOAD in mask. */ sample_entry.mask |= KADM5_LOAD; CHECK(krb5_db_put_principal(ctx, &sample_entry)); sample_entry.mask &= ~KADM5_LOAD; /* Fetch and compare the added principal. */ CHECK(krb5_db_get_principal(ctx, &sample_princ, 0, &ent)); check_entry(ent); /* We can't set up a successful allowed-to-delegate check through existing * APIs yet, but we can make a failed check. */ CHECK_COND(krb5_db_check_allowed_to_delegate(ctx, &sample_princ, ent, &sample_princ) != 0); /* Exercise lockout code. */ /* Policy params: max_fail 2, failcnt_interval 60, lockout_duration 120 */ /* Initial state: last_success 1, last_failed 5, fail_auth_count 2, * last admin unlock 6 */ /* Check succeeds due to last admin unlock. */ CHECK(krb5_db_check_policy_as(ctx, NULL, ent, ent, 7, &status, &e_data)); /* Failure count resets to 1 due to last admin unlock. */ sim_preauth(8, FALSE, &ent); CHECK_COND(ent->fail_auth_count == 1 && ent->last_failed == 8); /* Failure count resets to 1 due to failcnt_interval */ sim_preauth(70, FALSE, &ent); CHECK_COND(ent->fail_auth_count == 1 && ent->last_failed == 70); /* Failure count resets to 0 due to successful preauth. */ sim_preauth(75, TRUE, &ent); CHECK_COND(ent->fail_auth_count == 0 && ent->last_success == 75); /* Failure count increments to 2 and stops incrementing. */ sim_preauth(80, FALSE, &ent); CHECK_COND(ent->fail_auth_count == 1 && ent->last_failed == 80); sim_preauth(100, FALSE, &ent); CHECK_COND(ent->fail_auth_count == 2 && ent->last_failed == 100); sim_preauth(110, FALSE, &ent); CHECK_COND(ent->fail_auth_count == 2 && ent->last_failed == 100); /* Check fails due to reaching maximum failure count. */ CHECK_COND(krb5_db_check_policy_as(ctx, NULL, ent, ent, 170, &status, &e_data) == KRB5KDC_ERR_CLIENT_REVOKED); /* Check succeeds after lockout_duration has passed. */ CHECK(krb5_db_check_policy_as(ctx, NULL, ent, ent, 230, &status, &e_data)); /* Failure count resets to 1 on next failure. */ sim_preauth(240, FALSE, &ent); CHECK_COND(ent->fail_auth_count == 1 && ent->last_failed == 240); /* Exercise LDAP code to clear a policy reference and to set the key * data on an existing principal. */ CHECK(krb5_dbe_update_tl_data(ctx, ent, &tl_no_policy)); ent->mask = KADM5_POLICY_CLR | KADM5_KEY_DATA; CHECK(krb5_db_put_principal(ctx, ent)); CHECK(krb5_db_delete_policy(ctx, polname)); /* Put the modified entry again (with KDB_TL_USER_INFO tl-data for LDAP) as * from a load operation. */ ent->mask = (sample_entry.mask & ~KADM5_POLICY) | KADM5_LOAD; CHECK(krb5_db_put_principal(ctx, ent)); /* Exercise LDAP code to create a new principal at a DN from * KDB_TL_USER_INFO tl-data. */ CHECK(krb5_db_delete_principal(ctx, &sample_princ)); CHECK(krb5_db_put_principal(ctx, ent)); krb5_db_free_principal(ctx, ent); /* Exercise principal iteration code. */ count = 0; CHECK(krb5_db_iterate(ctx, "xy*", iter_princ_handler, &count)); CHECK_COND(count == 1); CHECK(krb5_db_fini(ctx)); CHECK_COND(krb5_db_inited(ctx) != 0); /* It might be nice to exercise krb5_db_destroy here, but the LDAP module * doesn't support it. */ krb5_free_default_realm(ctx, defrealm); krb5_free_context(ctx); return 0; }
void kdb5_update_princ_encryption(int argc, char *argv[]) { struct update_enc_mkvno data = { 0 }; char *name_pattern = NULL; int force = 0; int optchar; krb5_error_code retval; krb5_actkvno_node *actkvno_list = 0; krb5_db_entry *master_entry; char *mkey_fullname = 0; #ifdef BSD_REGEXPS char *msg; #endif char *regexp = NULL; krb5_keyblock *act_mkey; krb5_keylist_node *master_keylist = krb5_db_mkey_list_alias(util_context); while ((optchar = getopt(argc, argv, "fnv")) != -1) { switch (optchar) { case 'f': force = 1; break; case 'n': data.dry_run = 1; break; case 'v': data.verbose = 1; break; case '?': case ':': default: usage(); } } if (argv[optind] != NULL) { name_pattern = argv[optind]; if (argv[optind+1] != NULL) usage(); } retval = krb5_unparse_name(util_context, master_princ, &mkey_fullname); if (retval) { com_err(progname, retval, _("while formatting master principal name")); exit_status++; goto cleanup; } if (master_keylist == NULL) { com_err(progname, retval, _("master keylist not initialized")); exit_status++; goto cleanup; } /* The glob_to_regexp code only cares if the "realm" parameter is NULL or not; the string data is irrelevant. */ if (name_pattern == NULL) name_pattern = "*"; if (glob_to_regexp(name_pattern, "hi", ®exp) != 0) { com_err(progname, ENOMEM, _("converting glob pattern '%s' to regular expression"), name_pattern); exit_status++; goto cleanup; } if ( #ifdef SOLARIS_REGEXPS ((data.expbuf = compile(regexp, NULL, NULL)) == NULL) #endif #ifdef POSIX_REGEXPS ((regcomp(&data.preg, regexp, REG_NOSUB)) != 0) #endif #ifdef BSD_REGEXPS ((msg = (char *) re_comp(regexp)) != NULL) #endif ) { /* XXX syslog msg or regerr(regerrno) */ com_err(progname, 0, _("error compiling converted regexp '%s'"), regexp); exit_status++; goto cleanup; } retval = krb5_db_get_principal(util_context, master_princ, 0, &master_entry); if (retval != 0) { com_err(progname, retval, _("while getting master key principal %s"), mkey_fullname); exit_status++; goto cleanup; } retval = krb5_dbe_lookup_actkvno(util_context, master_entry, &actkvno_list); if (retval != 0) { com_err(progname, retval, _("while looking up active kvno list")); exit_status++; goto cleanup; } retval = krb5_dbe_find_act_mkey(util_context, actkvno_list, &new_mkvno, &act_mkey); if (retval) { com_err(progname, retval, _("while looking up active master key")); exit_status++; goto cleanup; } new_master_keyblock = *act_mkey; if (!force && !data.dry_run && !are_you_sure(_("Re-encrypt all keys not using master key vno %u?"), new_mkvno)) { printf(_("OK, doing nothing.\n")); exit_status++; goto cleanup; } if (data.verbose) { if (data.dry_run) { printf(_("Principals whose keys WOULD BE re-encrypted to master " "key vno %u:\n"), new_mkvno); } else { printf(_("Principals whose keys are being re-encrypted to master " "key vno %u if necessary:\n"), new_mkvno); } } if (!data.dry_run) { /* Grab a write lock so we don't have to upgrade to a write lock and * reopen the DB while iterating. */ retval = krb5_db_lock(util_context, KRB5_DB_LOCKMODE_EXCLUSIVE); if (retval != 0 && retval != KRB5_PLUGIN_OP_NOTSUPP) { com_err(progname, retval, _("trying to lock database")); exit_status++; } } retval = krb5_db_iterate(util_context, name_pattern, update_princ_encryption_1, &data); /* If exit_status is set, then update_princ_encryption_1 already printed a message. */ if (retval != 0 && exit_status == 0) { com_err(progname, retval, _("trying to process principal database")); exit_status++; } if (!data.dry_run) (void)krb5_db_unlock(util_context); (void) krb5_db_fini(util_context); if (data.dry_run) { printf(_("%u principals processed: %u would be updated, %u already " "current\n"), data.re_match_count, data.updated, data.already_current); } else { printf(_("%u principals processed: %u updated, %u already current\n"), data.re_match_count, data.updated, data.already_current); } cleanup: free(regexp); memset(&new_master_keyblock, 0, sizeof(new_master_keyblock)); krb5_free_unparsed_name(util_context, mkey_fullname); krb5_dbe_free_actkvno_list(util_context, actkvno_list); }
void kdb5_purge_mkeys(int argc, char *argv[]) { int optchar; krb5_error_code retval; char *mkey_fullname = NULL; krb5_timestamp now; krb5_db_entry *master_entry; krb5_boolean force = FALSE, dry_run = FALSE, verbose = FALSE; struct purge_args args; char buf[5]; unsigned int i, j, k, num_kvnos_inuse, num_kvnos_purged; unsigned int old_key_data_count; krb5_actkvno_node *actkvno_list = NULL, *actkvno_entry, *prev_actkvno_entry; krb5_mkey_aux_node *mkey_aux_list = NULL, *mkey_aux_entry, *prev_mkey_aux_entry; krb5_key_data *old_key_data; /* * Verify that the master key list has been initialized before doing * anything else. */ if (krb5_db_mkey_list_alias(util_context) == NULL) { com_err(progname, KRB5_KDB_DBNOTINITED, _("master keylist not initialized")); exit_status++; return; } memset(&master_princ, 0, sizeof(master_princ)); memset(&args, 0, sizeof(args)); optind = 1; while ((optchar = getopt(argc, argv, "fnv")) != -1) { switch(optchar) { case 'f': force = TRUE; break; case 'n': dry_run = TRUE; /* mkey princ will not be modified */ force = TRUE; /* implied */ break; case 'v': verbose = TRUE; break; case '?': default: usage(); return; } } /* assemble & parse the master key name */ if ((retval = krb5_db_setup_mkey_name(util_context, global_params.mkey_name, global_params.realm, &mkey_fullname, &master_princ))) { com_err(progname, retval, _("while setting up master key name")); exit_status++; return; } retval = krb5_db_get_principal(util_context, master_princ, 0, &master_entry); if (retval != 0) { com_err(progname, retval, _("while getting master key principal %s"), mkey_fullname); exit_status++; goto cleanup_return; } if (!force) { printf(_("Will purge all unused master keys stored in the '%s' " "principal, are you sure?\n"), mkey_fullname); printf(_("(type 'yes' to confirm)? ")); if (fgets(buf, sizeof(buf), stdin) == NULL) { exit_status++; goto cleanup_return; } if (strcmp(buf, "yes\n")) { exit_status++; goto cleanup_return; } printf(_("OK, purging unused master keys from '%s'...\n"), mkey_fullname); } /* save the old keydata */ old_key_data_count = master_entry->n_key_data; if (old_key_data_count == 1) { if (verbose) printf(_("There is only one master key which can not be " "purged.\n")); goto cleanup_return; } old_key_data = master_entry->key_data; args.kvnos = (struct kvnos_in_use *) malloc(sizeof(struct kvnos_in_use) * old_key_data_count); if (args.kvnos == NULL) { retval = ENOMEM; com_err(progname, ENOMEM, _("while allocating args.kvnos")); exit_status++; goto cleanup_return; } memset(args.kvnos, 0, sizeof(struct kvnos_in_use) * old_key_data_count); args.num_kvnos = old_key_data_count; args.kcontext = util_context; /* populate the kvnos array with all the current mkvnos */ for (i = 0; i < old_key_data_count; i++) args.kvnos[i].kvno = master_entry->key_data[i].key_data_kvno; if ((retval = krb5_db_iterate(util_context, NULL, find_mkvnos_in_use, (krb5_pointer) &args))) { com_err(progname, retval, _("while finding master keys in use")); exit_status++; goto cleanup_return; } /* * args.kvnos has been marked with the mkvno's that are currently protecting * princ entries */ if (dry_run) { printf(_("Would purge the following master key(s) from %s:\n"), mkey_fullname); } else { printf(_("Purging the following master key(s) from %s:\n"), mkey_fullname); } /* find # of keys still in use or print out verbose info */ for (i = num_kvnos_inuse = num_kvnos_purged = 0; i < args.num_kvnos; i++) { if (args.kvnos[i].use_count > 0) { num_kvnos_inuse++; } else { /* this key would be deleted */ if (args.kvnos[i].kvno == master_kvno) { com_err(progname, KRB5_KDB_STORED_MKEY_NOTCURRENT, _("master key stash file needs updating, command " "aborting")); exit_status++; goto cleanup_return; } num_kvnos_purged++; printf(_("KVNO: %d\n"), args.kvnos[i].kvno); } } /* didn't find any keys to purge */ if (num_kvnos_inuse == args.num_kvnos) { printf(_("All keys in use, nothing purged.\n")); goto cleanup_return; } if (dry_run) { /* bail before doing anything else */ printf(_("%d key(s) would be purged.\n"), num_kvnos_purged); goto cleanup_return; } retval = krb5_dbe_lookup_actkvno(util_context, master_entry, &actkvno_list); if (retval != 0) { com_err(progname, retval, _("while looking up active kvno list")); exit_status++; goto cleanup_return; } retval = krb5_dbe_lookup_mkey_aux(util_context, master_entry, &mkey_aux_list); if (retval != 0) { com_err(progname, retval, _("while looking up mkey aux data list")); exit_status++; goto cleanup_return; } master_entry->key_data = (krb5_key_data *) malloc(sizeof(krb5_key_data) * num_kvnos_inuse); if (master_entry->key_data == NULL) { retval = ENOMEM; com_err(progname, ENOMEM, _("while allocating key_data")); exit_status++; goto cleanup_return; } memset(master_entry->key_data, 0, sizeof(krb5_key_data) * num_kvnos_inuse); master_entry->n_key_data = num_kvnos_inuse; /* there's only 1 mkey per kvno */ /* * Assuming that the latest mkey will not be purged because it will always * be "in use" so this code will not bother with encrypting keys again. */ for (i = k = 0; i < old_key_data_count; i++) { for (j = 0; j < args.num_kvnos; j++) { if (args.kvnos[j].kvno == (krb5_kvno) old_key_data[i].key_data_kvno) { if (args.kvnos[j].use_count != 0) { master_entry->key_data[k++] = old_key_data[i]; break; } else { /* remove unused mkey */ /* adjust the actkno data */ for (prev_actkvno_entry = actkvno_entry = actkvno_list; actkvno_entry != NULL; actkvno_entry = actkvno_entry->next) { if (actkvno_entry->act_kvno == args.kvnos[j].kvno) { if (actkvno_entry == actkvno_list) { /* remove from head */ actkvno_list = actkvno_entry->next; prev_actkvno_entry = actkvno_list; } else if (actkvno_entry->next == NULL) { /* remove from tail */ prev_actkvno_entry->next = NULL; } else { /* remove in between */ prev_actkvno_entry->next = actkvno_entry->next; } actkvno_entry->next = NULL; krb5_dbe_free_actkvno_list(util_context, actkvno_entry); break; /* deleted entry, no need to loop further */ } else { prev_actkvno_entry = actkvno_entry; } } /* adjust the mkey aux data */ for (prev_mkey_aux_entry = mkey_aux_entry = mkey_aux_list; mkey_aux_entry != NULL; mkey_aux_entry = mkey_aux_entry->next) { if (mkey_aux_entry->mkey_kvno == args.kvnos[j].kvno) { if (mkey_aux_entry == mkey_aux_list) { mkey_aux_list = mkey_aux_entry->next; prev_mkey_aux_entry = mkey_aux_list; } else if (mkey_aux_entry->next == NULL) { prev_mkey_aux_entry->next = NULL; } else { prev_mkey_aux_entry->next = mkey_aux_entry->next; } mkey_aux_entry->next = NULL; krb5_dbe_free_mkey_aux_list(util_context, mkey_aux_entry); break; /* deleted entry, no need to loop further */ } else { prev_mkey_aux_entry = mkey_aux_entry; } } } } } } assert(k == num_kvnos_inuse); if ((retval = krb5_dbe_update_actkvno(util_context, master_entry, actkvno_list))) { com_err(progname, retval, _("while updating actkvno data for master principal entry")); exit_status++; goto cleanup_return; } if ((retval = krb5_dbe_update_mkey_aux(util_context, master_entry, mkey_aux_list))) { com_err(progname, retval, _("while updating mkey_aux data for master principal entry")); exit_status++; return; } if ((retval = krb5_timeofday(util_context, &now))) { com_err(progname, retval, _("while getting current time")); exit_status++; goto cleanup_return; } if ((retval = krb5_dbe_update_mod_princ_data(util_context, master_entry, now, master_princ))) { com_err(progname, retval, _("while updating the master key principal " "modification time")); exit_status++; goto cleanup_return; } master_entry->mask |= KADM5_KEY_DATA; if ((retval = krb5_db_put_principal(util_context, master_entry))) { (void) krb5_db_fini(util_context); com_err(progname, retval, _("while adding master key entry to the database")); exit_status++; goto cleanup_return; } printf(_("%d key(s) purged.\n"), num_kvnos_purged); cleanup_return: /* clean up */ (void) krb5_db_fini(util_context); krb5_free_principal(util_context, master_princ); free(args.kvnos); krb5_free_unparsed_name(util_context, mkey_fullname); krb5_dbe_free_actkvno_list(util_context, actkvno_list); krb5_dbe_free_mkey_aux_list(util_context, mkey_aux_list); return; }