Beispiel #1
0
/* 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;
}
Beispiel #2
0
static void
finish_realm(kdc_realm_t *rdp)
{
    if (rdp->realm_name)
        free(rdp->realm_name);
    if (rdp->realm_mpname)
        free(rdp->realm_mpname);
    if (rdp->realm_stash)
        free(rdp->realm_stash);
    if (rdp->realm_listen)
        free(rdp->realm_listen);
    if (rdp->realm_tcp_listen)
        free(rdp->realm_tcp_listen);
    if (rdp->realm_keytab)
        krb5_kt_close(rdp->realm_context, rdp->realm_keytab);
    if (rdp->realm_hostbased)
        free(rdp->realm_hostbased);
    if (rdp->realm_no_referral)
        free(rdp->realm_no_referral);
    if (rdp->realm_context) {
        if (rdp->realm_mprinc)
            krb5_free_principal(rdp->realm_context, rdp->realm_mprinc);
        if (rdp->realm_mkey.length && rdp->realm_mkey.contents) {
            /* XXX shouldn't memset be zap for safety? */
            memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length);
            free(rdp->realm_mkey.contents);
        }
        krb5_db_fini(rdp->realm_context);
        if (rdp->realm_tgsprinc)
            krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc);
        krb5_free_context(rdp->realm_context);
    }
    memset(rdp, 0, sizeof(*rdp));
    free(rdp);
}
Beispiel #3
0
static void
finish_realm(kdc_realm_t *rdp)
{
    if (rdp->realm_dbname)
	free(rdp->realm_dbname);
    if (rdp->realm_mpname)
	free(rdp->realm_mpname);
    if (rdp->realm_stash)
	free(rdp->realm_stash);
    if (rdp->realm_ports)
	free(rdp->realm_ports);
    if (rdp->realm_tcp_ports)
	free(rdp->realm_tcp_ports);
    if (rdp->realm_keytab)
	krb5_kt_close(rdp->realm_context, rdp->realm_keytab);
    if (rdp->realm_context) {
	if (rdp->realm_mprinc)
	    krb5_free_principal(rdp->realm_context, rdp->realm_mprinc);
	if (rdp->realm_mkey.length && rdp->realm_mkey.contents) {
	    memset(rdp->realm_mkey.contents, 0, rdp->realm_mkey.length);
	    free(rdp->realm_mkey.contents);
	}
	krb5_db_fini(rdp->realm_context);
	if (rdp->realm_tgsprinc)
	    krb5_free_principal(rdp->realm_context, rdp->realm_tgsprinc);
	krb5_free_context(rdp->realm_context);
    }
    memset((char *) rdp, 0, sizeof(*rdp));
    free(rdp);
}
Beispiel #4
0
krb5_error_code kdb_init_master(kadm5_server_handle_t handle,
                                char *r, int from_keyboard)
{
    int            ret = 0;
    char           *realm;
    krb5_boolean   from_kbd = FALSE;
    krb5_kvno       mkvno = IGNORE_VNO;

    if (from_keyboard)
        from_kbd = TRUE;

    if (r == NULL)  {
        if ((ret = krb5_get_default_realm(handle->context, &realm)))
            return ret;
    } else {
        realm = r;
    }

    if ((ret = krb5_db_setup_mkey_name(handle->context,
                                       handle->params.mkey_name,
                                       realm, NULL, &master_princ)))
        goto done;

    master_keyblock.enctype = handle->params.enctype;

    /*
     * Fetch the local mkey, may not be the latest but that's okay because we
     * really want the list of all mkeys and those can be retrieved with any
     * valid mkey.
     */
    ret = krb5_db_fetch_mkey(handle->context, master_princ,
                             master_keyblock.enctype, from_kbd,
                             FALSE /* only prompt once */,
                             handle->params.stash_file,
                             &mkvno  /* get the kvno of the returned mkey */,
                             NULL /* I'm not sure about this,
                                     but it's what the kdc does --marc */,
                             &master_keyblock);
    if (ret)
        goto done;

    if ((ret = krb5_db_fetch_mkey_list(handle->context, master_princ,
                                       &master_keyblock))) {
        krb5_db_fini(handle->context);
        return (ret);
    }

done:
    if (r == NULL)
        free(realm);

    return(ret);
}
Beispiel #5
0
krb5_error_code kdb_init_master(kadm5_server_handle_t handle,
				char *r, int from_keyboard)
{
    int		   ret = 0;
    char	   *realm;
    krb5_boolean   from_kbd = FALSE;

    if (from_keyboard)
      from_kbd = TRUE;

    if (r == NULL)  {
	if ((ret = krb5_get_default_realm(handle->context, &realm)))
	    return ret;
    } else {
	realm = r;
    }

    if ((ret = krb5_db_setup_mkey_name(handle->context,
				       handle->params.mkey_name,
				       realm, NULL, &master_princ)))
	goto done;
/* Solaris Kerberos */
#if 0
    master_keyblock.enctype = handle->params.enctype;
#endif

    /* Solaris Kerberos */
    ret = krb5_db_fetch_mkey(handle->context, master_princ,
			     handle->params.enctype, from_kbd,
			     FALSE /* only prompt once */,
			     handle->params.stash_file,
			     NULL /* I'm not sure about this,
				     but it's what the kdc does --marc */,
			     &handle->master_keyblock);
    if (ret)
	goto done;
				 
    /* Solaris Kerberos */
    if ((ret = krb5_db_verify_master_key(handle->context, master_princ,
					 &handle->master_keyblock))) {
	  krb5_db_fini(handle->context);
	  return ret;
    }

done:
    if (r == NULL)
	free(realm);

    return(ret);
}
Beispiel #6
0
krb5_error_code kdb_init_master(kadm5_server_handle_t handle,
				char *r, int from_keyboard)
{
    int		   ret = 0;
    char	   *realm;
    krb5_keyblock  tmk;

    if (r == NULL)  {
	if ((ret = krb5_get_default_realm(handle->context, &realm)))
	    return ret;
    } else {
	realm = r;
    }
	    
    if ((ret = krb5_db_setup_mkey_name(handle->context,
				       handle->params.mkey_name,
				       realm, NULL, &master_princ)))
	goto done;

    if (ret = krb5_db_fetch_mkey(handle->context, master_princ,
				 handle->params.enctype,
				from_keyboard,
				 FALSE /* only prompt once */,
				 handle->params.stash_file,
				 NULL /* I'm not sure about this,
					 but it's what the kdc does --marc */,
				 &handle->master_keyblock))
	goto done;
				 
    if ((ret = krb5_db_init(handle->context)) != KSUCCESS)
	goto done;

    if ((ret = krb5_db_verify_master_key(handle->context, master_princ,
					 &handle->master_keyblock))) {
	  krb5_db_fini(handle->context);
	  return ret;
    }

done:
    if (r == NULL)
	free(realm);

    return(ret);
}
Beispiel #7
0
/* Child process: acquire and release a write lock on the KDB, synchronized
 * with parent. */
static int
locker(int inpipe, int outpipe, char **db_args)
{
    krb5_error_code retval;
    unsigned char c = '\0';
    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;

    if (syncpair_wr("first", inpipe, outpipe, &c) < 0) {
        retval = errno;
        goto cleanup;
    }
    printf("locker: acquiring lock...\n");
    retval = krb5_db_lock(ctx, KRB5_DB_LOCKMODE_EXCLUSIVE);
    if (retval)
        goto cleanup;
    printf("locker: acquired lock\n");
    if (syncpair_wr("second", inpipe, outpipe, &c) < 0) {
        retval = errno;
        goto cleanup;
    }
    krb5_db_unlock(ctx);
    printf("locker: released lock\n");
    printf("locker: writing final sync byte\n");
    if (write(outpipe, &c, 1) < 0) {
        retval = errno;
        goto cleanup;
    }
    retval = krb5_db_fini(ctx);
cleanup:
    if (retval)
        com_err("locker", retval, "");

    krb5_free_context(ctx);
    exit(retval != 0);
}
Beispiel #8
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;
}
Beispiel #9
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", &regexp) != 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);
}
Beispiel #10
0
void
kdb5_list_mkeys(int argc, char *argv[])
{
    krb5_error_code retval;
    char  *mkey_fullname = NULL, *output_str = NULL, enctype[BUFSIZ];
    krb5_kvno  act_kvno;
    krb5_timestamp act_time;
    krb5_actkvno_node *actkvno_list = NULL, *cur_actkvno;
    krb5_db_entry *master_entry;
    krb5_keylist_node  *cur_kb_node;
    krb5_keyblock *act_mkey;
    krb5_keylist_node *master_keylist = krb5_db_mkey_list_alias(util_context);

    if (master_keylist == NULL) {
        com_err(progname, 0, _("master keylist not initialized"));
        exit_status++;
        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;
    }

    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;
    }

    if (actkvno_list == NULL) {
        act_kvno = master_entry->key_data[0].key_data_kvno;
    } else {
        retval = krb5_dbe_find_act_mkey(util_context, actkvno_list, &act_kvno,
                                        &act_mkey);
        if (retval == KRB5_KDB_NOACTMASTERKEY) {
            /* Maybe we went through a time warp, and the only keys
               with activation dates have them set in the future?  */
            com_err(progname, retval, "");
            /* Keep going.  */
            act_kvno = -1;
        } else if (retval != 0) {
            com_err(progname, retval, _("while looking up active master key"));
            exit_status++;
            goto cleanup_return;
        }
    }

    printf("Master keys for Principal: %s\n", mkey_fullname);

    for (cur_kb_node = master_keylist; cur_kb_node != NULL;
         cur_kb_node = cur_kb_node->next) {

        if ((retval = krb5_enctype_to_name(cur_kb_node->keyblock.enctype,
                                           FALSE, enctype, sizeof(enctype)))) {
            com_err(progname, retval, _("while getting enctype description"));
            exit_status++;
            goto cleanup_return;
        }

        if (actkvno_list != NULL) {
            act_time = -1; /* assume actkvno entry not found */
            for (cur_actkvno = actkvno_list; cur_actkvno != NULL;
                 cur_actkvno = cur_actkvno->next) {
                if (cur_actkvno->act_kvno == cur_kb_node->kvno) {
                    act_time = cur_actkvno->act_time;
                    break;
                }
            }
        } else {
            /*
             * mkey princ doesn't have an active knvo list so assume the current
             * key is active now
             */
            if ((retval = krb5_timeofday(util_context, &act_time))) {
                com_err(progname, retval, _("while getting current time"));
                exit_status++;
                goto cleanup_return;
            }
        }

        if (cur_kb_node->kvno == act_kvno) {
            /* * indicates kvno is currently active */
            retval = asprintf(&output_str,
                              _("KVNO: %d, Enctype: %s, Active on: %s *\n"),
                              cur_kb_node->kvno, enctype, strdate(act_time));
        } else {
            if (act_time != -1) {
                retval = asprintf(&output_str,
                                  _("KVNO: %d, Enctype: %s, Active on: %s\n"),
                                  cur_kb_node->kvno, enctype, strdate(act_time));
            } else {
                retval = asprintf(&output_str,
                                  _("KVNO: %d, Enctype: %s, No activate time "
                                    "set\n"), cur_kb_node->kvno, enctype);
            }
        }
        if (retval == -1) {
            com_err(progname, ENOMEM, _("asprintf could not allocate enough "
                                        "memory to hold output"));
            exit_status++;
            goto cleanup_return;
        }
        printf("%s", output_str);
        free(output_str);
        output_str = NULL;
    }

cleanup_return:
    /* clean up */
    (void) krb5_db_fini(util_context);
    krb5_free_unparsed_name(util_context, mkey_fullname);
    free(output_str);
    krb5_free_principal(util_context, master_princ);
    krb5_dbe_free_actkvno_list(util_context, actkvno_list);
    return;
}
Beispiel #11
0
void
kdb5_use_mkey(int argc, char *argv[])
{
    krb5_error_code retval;
    char  *mkey_fullname = NULL;
    krb5_kvno  use_kvno;
    krb5_timestamp now, start_time;
    krb5_actkvno_node *actkvno_list = NULL, *new_actkvno = NULL,
        *prev_actkvno, *cur_actkvno;
    krb5_db_entry *master_entry;
    krb5_keylist_node *keylist_node;
    krb5_boolean inserted = FALSE;
    krb5_keylist_node *master_keylist = krb5_db_mkey_list_alias(util_context);

    memset(&master_princ, 0, sizeof(master_princ));

    if (argc < 2 || argc > 3) {
        /* usage calls exit */
        usage();
    }

    use_kvno = atoi(argv[1]);
    if (use_kvno == 0) {
        com_err(progname, EINVAL, _("0 is an invalid KVNO value"));
        exit_status++;
        return;
    } else {
        /* verify use_kvno is valid */
        for (keylist_node = master_keylist; keylist_node != NULL;
             keylist_node = keylist_node->next) {
            if (use_kvno == keylist_node->kvno)
                break;
        }
        if (!keylist_node) {
            com_err(progname, EINVAL, _("%d is an invalid KVNO value"),
                    use_kvno);
            exit_status++;
            return;
        }
    }

    if ((retval = krb5_timeofday(util_context, &now))) {
        com_err(progname, retval, _("while getting current time"));
        exit_status++;
        return;
    }

    if (argc == 3) {
        time_t t = get_date(argv[2]);
        if (t == -1) {
            com_err(progname, 0, _("could not parse date-time string '%s'"),
                    argv[2]);
            exit_status++;
            return;
        } else
            start_time = (krb5_timestamp) t;
    } else {
        start_time = now;
    }

    /*
     * Need to:
     *
     * 1. get mkey princ
     * 2. get krb5_actkvno_node list
     * 3. add use_kvno to actkvno list (sorted in right spot)
     * 4. update mkey princ's tl data
     * 5. put mkey princ.
     */

    /* 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++;
        goto cleanup_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;
    }

    retval = krb5_dbe_lookup_actkvno(util_context, master_entry, &actkvno_list);
    if (retval != 0) {
        com_err(progname, retval,
                _("while looking up active version of master key"));
        exit_status++;
        goto cleanup_return;
    }

    /*
     * If an entry already exists with the same kvno either delete it or if it's
     * the only entry, just set its active time.
     */
    for (prev_actkvno = NULL, cur_actkvno = actkvno_list;
         cur_actkvno != NULL;
         prev_actkvno = cur_actkvno, cur_actkvno = cur_actkvno->next) {

        if (cur_actkvno->act_kvno == use_kvno) {
            /* delete it */
            if (prev_actkvno) {
                prev_actkvno->next = cur_actkvno->next;
                cur_actkvno->next = NULL;
                krb5_dbe_free_actkvno_list(util_context, cur_actkvno);
            } else {
                if (cur_actkvno->next) {
                    /* delete it from front of list */
                    actkvno_list = cur_actkvno->next;
                    cur_actkvno->next = NULL;
                    krb5_dbe_free_actkvno_list(util_context, cur_actkvno);
                } else {
                    /* There's only one entry, go ahead and change the time */
                    cur_actkvno->act_time = start_time;
                    inserted = TRUE;
                }
            }
            break;
        }
    }

    if (!inserted) {
        /* alloc enough space to hold new and existing key_data */
        new_actkvno = (krb5_actkvno_node *) malloc(sizeof(krb5_actkvno_node));
        if (new_actkvno == NULL) {
            com_err(progname, ENOMEM, _("while adding new master key"));
            exit_status++;
            goto cleanup_return;
        }
        memset(new_actkvno, 0, sizeof(krb5_actkvno_node));
        new_actkvno->act_kvno = use_kvno;
        new_actkvno->act_time = start_time;

        /* insert new act kvno node */

        if (actkvno_list == NULL) {
            /* new actkvno is the list */
            actkvno_list = new_actkvno;
        } else {
            for (prev_actkvno = NULL, cur_actkvno = actkvno_list;
                 cur_actkvno != NULL;
                 prev_actkvno = cur_actkvno, cur_actkvno = cur_actkvno->next) {

                if (new_actkvno->act_time < cur_actkvno->act_time) {
                    if (prev_actkvno) {
                        prev_actkvno->next = new_actkvno;
                        new_actkvno->next = cur_actkvno;
                    } else {
                        new_actkvno->next = actkvno_list;
                        actkvno_list = new_actkvno;
                    }
                    break;
                } else if (cur_actkvno->next == NULL) {
                    /* end of line, just add new node to end of list */
                    cur_actkvno->next = new_actkvno;
                    break;
                }
            }
        }
    }

    if (actkvno_list->act_time > now) {
        com_err(progname, EINVAL,
                _("there must be one master key currently active"));
        exit_status++;
        goto cleanup_return;
    }

    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_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;
    }

    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;
    }

cleanup_return:
    /* clean up */
    (void) krb5_db_fini(util_context);
    krb5_free_unparsed_name(util_context, mkey_fullname);
    krb5_free_principal(util_context, master_princ);
    krb5_dbe_free_actkvno_list(util_context, actkvno_list);
    return;
}
Beispiel #12
0
void
kdb5_add_mkey(int argc, char *argv[])
{
    int optchar;
    krb5_error_code retval;
    char *mkey_fullname;
    char *pw_str = 0;
    unsigned int pw_size = 0;
    int do_stash = 0;
    krb5_data pwd;
    krb5_kvno new_mkey_kvno;
    krb5_keyblock new_mkeyblock;
    krb5_enctype new_master_enctype = ENCTYPE_UNKNOWN;
    char *new_mkey_password;
    krb5_db_entry *master_entry;
    krb5_timestamp now;

    /*
     * The command table entry for this command causes open_db_and_mkey() to be
     * called first to open the KDB and get the current mkey.
     */

    memset(&new_mkeyblock, 0, sizeof(new_mkeyblock));
    memset(&master_princ, 0, sizeof(master_princ));
    master_salt.data = NULL;

    while ((optchar = getopt(argc, argv, "e:s")) != -1) {
        switch(optchar) {
        case 'e':
            if (krb5_string_to_enctype(optarg, &new_master_enctype)) {
                com_err(progname, EINVAL, _("%s is an invalid enctype"),
                        optarg);
                exit_status++;
                return;
            }
            break;
        case 's':
            do_stash++;
            break;
        case '?':
        default:
            usage();
            return;
        }
    }

    if (new_master_enctype == ENCTYPE_UNKNOWN)
        new_master_enctype = global_params.enctype;

    /* 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;
    }

    printf(_("Creating new master key for master key principal '%s'\n"),
           mkey_fullname);

    printf(_("You will be prompted for a new database Master Password.\n"));
    printf(_("It is important that you NOT FORGET this password.\n"));
    fflush(stdout);

    pw_size = 1024;
    pw_str = malloc(pw_size);
    if (pw_str == NULL) {
        com_err(progname, ENOMEM, _("while creating new master key"));
        exit_status++;
        goto cleanup_return;
    }

    retval = krb5_read_password(util_context, KRB5_KDC_MKEY_1, KRB5_KDC_MKEY_2,
                                pw_str, &pw_size);
    if (retval) {
        com_err(progname, retval,
                _("while reading new master key from keyboard"));
        exit_status++;
        goto cleanup_return;
    }
    new_mkey_password = pw_str;

    pwd.data = new_mkey_password;
    pwd.length = strlen(new_mkey_password);
    retval = krb5_principal2salt(util_context, master_princ, &master_salt);
    if (retval) {
        com_err(progname, retval, _("while calculating master key salt"));
        exit_status++;
        goto cleanup_return;
    }

    retval = krb5_c_string_to_key(util_context, new_master_enctype,
                                  &pwd, &master_salt, &new_mkeyblock);
    if (retval) {
        com_err(progname, retval,
                _("while transforming master key from password"));
        exit_status++;
        goto cleanup_return;
    }

    new_mkey_kvno = get_next_kvno(util_context, master_entry);
    retval = add_new_mkey(util_context, master_entry, &new_mkeyblock,
                          new_mkey_kvno);
    if (retval) {
        com_err(progname, retval,
                _("adding new master key to master principal"));
        exit_status++;
        goto cleanup_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;
    }

    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;
    }

    if (do_stash) {
        retval = krb5_db_store_master_key(util_context,
                                          global_params.stash_file,
                                          master_princ,
                                          new_mkey_kvno,
                                          &new_mkeyblock,
                                          mkey_password);
        if (retval) {
            com_err(progname, errno, _("while storing key"));
            printf(_("Warning: couldn't stash master key.\n"));
        }
    }

cleanup_return:
    /* clean up */
    (void) krb5_db_fini(util_context);
    zap((char *)master_keyblock.contents, master_keyblock.length);
    free(master_keyblock.contents);
    zap((char *)new_mkeyblock.contents, new_mkeyblock.length);
    free(new_mkeyblock.contents);
    if (pw_str) {
        zap(pw_str, pw_size);
        free(pw_str);
    }
    free(master_salt.data);
    krb5_free_unparsed_name(util_context, mkey_fullname);
    return;
}
Beispiel #13
0
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;
}