From: Simo Sorce Date: Thu, 17 Dec 2015 22:46:16 +0000 (-0500) Subject: Add get_principal_keys RPC to kadmin X-Git-Tag: krb5-1.15-beta1~261 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a64a49c3c836a2f4f03a0cbbdb89cfde9b29d1d;p=thirdparty%2Fkrb5.git Add get_principal_keys RPC to kadmin Change the prototype of kadm5_get_principal_keys() to report kvno and salt information along with each key. Add an RPC for extracting keys, requiring a new permission bit (which is not implied by 'x' or '*' in kadm5.acl). Add kadm5_free_kadm5_key_data(). In kadmin, deconditionalize "kadmin ktadd -norandkey". Use the new information from kadm5_get_principal_keys() to correctly set the kvno for each key when existing keys are extracted, fixing issue #7852. Add tests to t_keytab.py for the #7852 fix. Add tests to lib/kadm5/unit-test for the get_principal_keys RPC. [ghudson@mit.edu: factor out fetch_new_keys() from add_principal(); rewrite commit message to describe new RPC; add #7852 test cases; squash with lib/kadm5/unit-test commit] ticket: 8364 (new) --- diff --git a/doc/admin/conf_files/kadm5_acl.rst b/doc/admin/conf_files/kadm5_acl.rst index 2a6e634d68..f5cfd2f1e9 100644 --- a/doc/admin/conf_files/kadm5_acl.rst +++ b/doc/admin/conf_files/kadm5_acl.rst @@ -47,12 +47,13 @@ ignored. Lines containing ACL entries have the format:: a [Dis]allows the addition of principals or policies c [Dis]allows the changing of passwords for principals d [Dis]allows the deletion of principals or policies + e [Dis]allows the extraction of principal keys i [Dis]allows inquiries about principals or policies l [Dis]allows the listing of all principals or policies m [Dis]allows the modification of principals or policies p [Dis]allows the propagation of the principal database (used in :ref:`incr_db_prop`) s [Dis]allows the explicit setting of the key for a principal - x Short for admcilsp. All privileges + x Short for admcilsp. All privileges (except ``e``) \* Same as x. == ====================================================== diff --git a/src/kadmin/cli/keytab.c b/src/kadmin/cli/keytab.c index 96dc51be1f..b6edb7571c 100644 --- a/src/kadmin/cli/keytab.c +++ b/src/kadmin/cli/keytab.c @@ -52,13 +52,8 @@ static int norandkey; static void add_usage() { -#ifdef KADMIN_LOCAL fprintf(stderr, _("Usage: ktadd [-k[eytab] keytab] [-q] [-e keysaltlist] " "[-norandkey] [principal | -glob princ-exp] [...]\n")); -#else - fprintf(stderr, _("Usage: ktadd [-k[eytab] keytab] [-q] [-e keysaltlist] " - "[principal | -glob princ-exp] [...]\n")); -#endif } static void @@ -140,13 +135,7 @@ kadmin_keytab_add(int argc, char **argv) } else if (strcmp(*argv, "-q") == 0) { quiet++; } else if (strcmp(*argv, "-norandkey") == 0) { -#ifdef KADMIN_LOCAL norandkey++; -#else - fprintf(stderr, - _("-norandkey option only valid for kadmin.local\n")); - return; -#endif } else if (strcmp(*argv, "-e") == 0) { argc--; if (argc < 1) { @@ -253,21 +242,71 @@ kadmin_keytab_remove(int argc, char **argv) free(keytab_str); } +/* Generate new random keys for princ, and convert them into a kadm5_key_data + * array (with no salt information). */ +static krb5_error_code +fetch_new_keys(void *lhandle, krb5_principal princ, krb5_boolean keepold, + int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, + kadm5_key_data **key_data_out, int *nkeys_out) +{ + krb5_error_code code; + kadm5_key_data *key_data; + kadm5_principal_ent_rec princ_rec; + krb5_keyblock *keys = NULL; + int i, nkeys = 0; + + *key_data_out = NULL; + *nkeys_out = 0; + memset(&princ_rec, 0, sizeof(princ_rec)); + + /* Generate new random keys. */ + code = randkey_princ(lhandle, princ, keepold, n_ks_tuple, ks_tuple, + &keys, &nkeys); + if (code) + goto cleanup; + + /* Get the principal entry to find the kvno of the new keys. (This is not + * atomic, but randkey doesn't report the new kvno.) */ + code = kadm5_get_principal(lhandle, princ, &princ_rec, + KADM5_PRINCIPAL_NORMAL_MASK); + if (code) + goto cleanup; + + key_data = k5calloc(nkeys, sizeof(*key_data), &code); + if (key_data == NULL) + goto cleanup; + + /* Transfer the keyblocks and free the container array. */ + for (i = 0; i < nkeys; i++) { + key_data[i].key = keys[i]; + key_data[i].kvno = princ_rec.kvno; + } + *key_data_out = key_data; + *nkeys_out = nkeys; + free(keys); + keys = NULL; + nkeys = 0; + +cleanup: + for (i = 0; i < nkeys; i++) + krb5_free_keyblock_contents(context, &keys[i]); + free(keys); + kadm5_free_principal_ent(lhandle, &princ_rec); + return code; +} + static void add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char *princ_str) { - kadm5_principal_ent_rec princ_rec; krb5_principal princ = NULL; krb5_keytab_entry new_entry; - krb5_keyblock *keys; + kadm5_key_data *key_data; int code, nkeys, i; - memset(&princ_rec, 0, sizeof(princ_rec)); - princ = NULL; - keys = NULL; + key_data = NULL; nkeys = 0; code = krb5_parse_name(context, princ_str, &princ); @@ -277,13 +316,13 @@ add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab, goto cleanup; } -#ifdef KADMIN_LOCAL - if (norandkey) - code = kadm5_get_principal_keys(handle, princ, &keys, &nkeys); - else -#endif - code = randkey_princ(lhandle, princ, keepold, n_ks_tuple, ks_tuple, - &keys, &nkeys); + if (norandkey) { + code = kadm5_get_principal_keys(handle, princ, 0, &key_data, &nkeys); + } else { + code = fetch_new_keys(handle, princ, keepold, n_ks_tuple, ks_tuple, + &key_data, &nkeys); + } + if (code != 0) { if (code == KADM5_UNK_PRINC) { fprintf(stderr, _("%s: Principal %s does not exist.\n"), @@ -293,44 +332,28 @@ add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab, goto cleanup; } - code = kadm5_get_principal(lhandle, princ, &princ_rec, - KADM5_PRINCIPAL_NORMAL_MASK); - if (code != 0) { - com_err(whoami, code, _("while retrieving principal")); - goto cleanup; - } - for (i = 0; i < nkeys; i++) { memset(&new_entry, 0, sizeof(new_entry)); new_entry.principal = princ; - new_entry.key = keys[i]; - new_entry.vno = princ_rec.kvno; + new_entry.key = key_data[i].key; + new_entry.vno = key_data[i].kvno; code = krb5_kt_add_entry(context, keytab, &new_entry); if (code != 0) { com_err(whoami, code, _("while adding key to keytab")); - kadm5_free_principal_ent(lhandle, &princ_rec); goto cleanup; } if (!quiet) { printf(_("Entry for principal %s with kvno %d, " "encryption type %s added to keytab %s.\n"), - princ_str, princ_rec.kvno, - etype_string(keys[i].enctype), keytab_str); + princ_str, key_data[i].kvno, + etype_string(key_data[i].key.enctype), keytab_str); } } - code = kadm5_free_principal_ent(lhandle, &princ_rec); - if (code != 0) { - com_err(whoami, code, _("while freeing principal entry")); - goto cleanup; - } - cleanup: - for (i = 0; i < nkeys; i++) - krb5_free_keyblock_contents(context, &keys[i]); - free(keys); + kadm5_free_kadm5_key_data(context, nkeys, key_data); krb5_free_principal(context, princ); } diff --git a/src/kadmin/server/kadm_rpc_svc.c b/src/kadmin/server/kadm_rpc_svc.c index dee39384b7..e325164fe3 100644 --- a/src/kadmin/server/kadm_rpc_svc.c +++ b/src/kadmin/server/kadm_rpc_svc.c @@ -59,6 +59,7 @@ void kadm_1(rqstp, transp) chrand3_arg chrand_principal3_2_arg; setkey3_arg setkey_principal3_2_arg; setkey4_arg setkey_principal4_2_arg; + getpkeys_arg get_principal_keys_2_arg; } argument; char *result; bool_t (*xdr_argument)(), (*xdr_result)(); @@ -229,6 +230,12 @@ void kadm_1(rqstp, transp) local = (char *(*)()) setkey_principal4_2_svc; break; + case EXTRACT_KEYS: + xdr_argument = xdr_getpkeys_arg; + xdr_result = xdr_getpkeys_ret; + local = (char *(*)()) get_principal_keys_2_svc; + break; + default: krb5_klog_syslog(LOG_ERR, "Invalid KADM5 procedure number: %s, %d", client_addr(rqstp->rq_xprt), rqstp->rq_proc); diff --git a/src/kadmin/server/server_stubs.c b/src/kadmin/server/server_stubs.c index 673cc2e53f..1126b7b41d 100644 --- a/src/kadmin/server/server_stubs.c +++ b/src/kadmin/server/server_stubs.c @@ -1877,3 +1877,64 @@ rqst2name(struct svc_req *rqstp) else return rqstp->rq_clntcred; } + +getpkeys_ret * +get_principal_keys_2_svc(getpkeys_arg *arg, struct svc_req *rqstp) +{ + static getpkeys_ret ret; + char *prime_arg; + gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER; + gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; + + xdr_free(xdr_getpkeys_ret, &ret); + + if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) + goto exit_func; + + if ((ret.code = check_handle((void *)handle))) + goto exit_func; + + ret.api_version = handle->api_version; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + goto exit_func; + } + if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) { + ret.code = KADM5_BAD_PRINCIPAL; + goto exit_func; + } + + if (!(CHANGEPW_SERVICE(rqstp)) && + kadm5int_acl_check(handle->context, rqst2name(rqstp), + ACL_EXTRACT, arg->princ, NULL)) { + ret.code = kadm5_get_principal_keys((void *)handle, arg->princ, + arg->kvno, &ret.key_data, + &ret.n_key_data); + } else { + log_unauth("kadm5_get_principal_keys", prime_arg, + &client_name, &service_name, rqstp); + ret.code = KADM5_AUTH_EXTRACT; + } + + if (ret.code != KADM5_AUTH_EXTRACT) { + if (ret.code != 0) + errmsg = krb5_get_error_message(handle->context, ret.code); + + log_done("kadm5_get_principal_keys", prime_arg, errmsg, + &client_name, &service_name, rqstp); + + if (errmsg != NULL) + krb5_free_error_message(handle->context, errmsg); + } + + free(prime_arg); +exit_func: + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + free_server_handle(handle); + return &ret; +} diff --git a/src/kadmin/testing/scripts/init_db b/src/kadmin/testing/scripts/init_db index 06b33843ef..cd71656288 100755 --- a/src/kadmin/testing/scripts/init_db +++ b/src/kadmin/testing/scripts/init_db @@ -200,7 +200,7 @@ if [ $? -ne 0 ]; then fi cat > $K5ROOT/ovsec_adm.acl <code; } + +kadm5_ret_t +kadm5_get_principal_keys(void *server_handle, krb5_principal princ, + krb5_kvno kvno, kadm5_key_data **key_data, + int *n_key_data) +{ + getpkeys_arg arg; + getpkeys_ret *r; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + arg.api_version = handle->api_version; + arg.princ = princ; + arg.kvno = kvno; + + if (princ == NULL || key_data == NULL || n_key_data == 0) + return EINVAL; + r = get_principal_keys_2(&arg, handle->clnt); + if (r == NULL) + eret(); + if (r->code == 0) { + *key_data = r->key_data; + *n_key_data = r->n_key_data; + } + return r->code; +} diff --git a/src/lib/kadm5/clnt/client_rpc.c b/src/lib/kadm5/clnt/client_rpc.c index fa335a4b4b..a5f74e6b15 100644 --- a/src/lib/kadm5/clnt/client_rpc.c +++ b/src/lib/kadm5/clnt/client_rpc.c @@ -386,3 +386,18 @@ set_string_2(sstring_arg *argp, CLIENT *clnt) } return (&clnt_res); } + +getpkeys_ret * +get_principal_keys_2(getpkeys_arg *argp, CLIENT *clnt) +{ + static getpkeys_ret clnt_res; + + memset(&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, EXTRACT_KEYS, + (xdrproc_t)xdr_getpkeys_arg, (caddr_t)argp, + (xdrproc_t)xdr_getpkeys_ret, (caddr_t)&clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return NULL; + } + return &clnt_res; +} diff --git a/src/lib/kadm5/clnt/libkadm5clnt_mit.exports b/src/lib/kadm5/clnt/libkadm5clnt_mit.exports index d9e99ef621..9d1a573412 100644 --- a/src/lib/kadm5/clnt/libkadm5clnt_mit.exports +++ b/src/lib/kadm5/clnt/libkadm5clnt_mit.exports @@ -12,6 +12,7 @@ kadm5_delete_principal kadm5_destroy kadm5_flush kadm5_free_config_params +kadm5_free_kadm5_key_data kadm5_free_key_data kadm5_free_name_list kadm5_free_policy_ent @@ -22,6 +23,7 @@ kadm5_get_config_params kadm5_get_policies kadm5_get_policy kadm5_get_principal +kadm5_get_principal_keys kadm5_get_principals kadm5_get_privs kadm5_get_strings @@ -73,6 +75,8 @@ xdr_cprinc_arg xdr_dpol_arg xdr_dprinc_arg xdr_generic_ret +xdr_getpkeys_arg +xdr_getpkeys_ret xdr_getprivs_ret xdr_gpol_arg xdr_gpol_ret diff --git a/src/lib/kadm5/kadm_err.et b/src/lib/kadm5/kadm_err.et index bc10a5b07d..56a4e27e6e 100644 --- a/src/lib/kadm5/kadm_err.et +++ b/src/lib/kadm5/kadm_err.et @@ -64,4 +64,5 @@ error_code KADM5_CANT_RESOLVE, "Cannot resolve network address for admin server error_code KADM5_PASS_Q_GENERIC, "Unspecified password quality failure" error_code KADM5_BAD_KEYSALTS, "Invalid key/salt tuples" error_code KADM5_SETKEY_BAD_KVNO, "Invalid multiple or duplicate kvnos in setkey operation" +error_code KADM5_AUTH_EXTRACT, "Operation requires ``extract-keys'' privilege" end diff --git a/src/lib/kadm5/kadm_rpc.h b/src/lib/kadm5/kadm_rpc.h index 24565bd02d..a75df11f07 100644 --- a/src/lib/kadm5/kadm_rpc.h +++ b/src/lib/kadm5/kadm_rpc.h @@ -238,6 +238,21 @@ struct sstring_arg { }; typedef struct sstring_arg sstring_arg; +struct getpkeys_arg { + krb5_ui_4 api_version; + krb5_principal princ; + krb5_kvno kvno; +}; +typedef struct getpkeys_arg getpkeys_arg; + +struct getpkeys_ret { + krb5_ui_4 api_version; + kadm5_ret_t code; + kadm5_key_data *key_data; + int n_key_data; +}; +typedef struct getpkeys_ret getpkeys_ret; + #define KADM 2112 #define KADMVERS 2 #define CREATE_PRINCIPAL 1 @@ -315,6 +330,9 @@ extern generic_ret * set_string_2_svc(sstring_arg *, struct svc_req *); #define SETKEY_PRINCIPAL4 25 extern generic_ret * setkey_principal4_2(setkey4_arg *, CLIENT *); extern generic_ret * setkey_principal4_2_svc(setkey4_arg *, struct svc_req *); +#define EXTRACT_KEYS 26 +extern getpkeys_ret * get_principal_keys_2(getpkeys_arg *, CLIENT *); +extern getpkeys_ret * get_principal_keys_2_svc(getpkeys_arg *, struct svc_req *); extern bool_t xdr_cprinc_arg (); extern bool_t xdr_cprinc3_arg (); @@ -358,6 +376,7 @@ extern bool_t xdr_gstrings_ret (); extern bool_t xdr_sstring_arg (); extern bool_t xdr_krb5_string_attr (); extern bool_t xdr_kadm5_key_data (); - +extern bool_t xdr_getpkeys_arg (); +extern bool_t xdr_getpkeys_ret (); #endif /* __KADM_RPC_H__ */ diff --git a/src/lib/kadm5/kadm_rpc_xdr.c b/src/lib/kadm5/kadm_rpc_xdr.c index bfd0341815..2892d4147b 100644 --- a/src/lib/kadm5/kadm_rpc_xdr.c +++ b/src/lib/kadm5/kadm_rpc_xdr.c @@ -1192,3 +1192,37 @@ xdr_kadm5_key_data(XDR *xdrs, kadm5_key_data *objp) return FALSE; return TRUE; } + +bool_t +xdr_getpkeys_arg(XDR *xdrs, getpkeys_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return FALSE; + } + if (!xdr_krb5_principal(xdrs, &objp->princ)) { + return FALSE; + } + if (!xdr_krb5_kvno(xdrs, &objp->kvno)) { + return FALSE; + } + return TRUE; +} + +bool_t +xdr_getpkeys_ret(XDR *xdrs, getpkeys_ret *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return FALSE; + } + if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { + return FALSE; + } + if (objp->code == KADM5_OK) { + if (!xdr_array(xdrs, (caddr_t *) &objp->key_data, + (unsigned int *) &objp->n_key_data, ~0, + sizeof(kadm5_key_data), xdr_kadm5_key_data)) { + return FALSE; + } + } + return TRUE; +} diff --git a/src/lib/kadm5/misc_free.c b/src/lib/kadm5/misc_free.c index 497b8c2b69..74d23760fb 100644 --- a/src/lib/kadm5/misc_free.c +++ b/src/lib/kadm5/misc_free.c @@ -119,3 +119,21 @@ kadm5_free_strings(void *server_handle, krb5_string_attr *strings, free(strings); return KADM5_OK; } + +kadm5_ret_t +kadm5_free_kadm5_key_data(krb5_context context, int n_key_data, + kadm5_key_data *key_data) +{ + int i; + + if (key_data == NULL) + return KADM5_OK; + + for (i = 0; i < n_key_data; i++) { + krb5_free_keyblock_contents(context, &key_data[i].key); + krb5_free_data_contents(context, &key_data[i].salt.data); + } + free(key_data); + + return KADM5_OK; +} diff --git a/src/lib/kadm5/srv/Makefile.in b/src/lib/kadm5/srv/Makefile.in index 3fd4b9e522..6aa7d100f4 100644 --- a/src/lib/kadm5/srv/Makefile.in +++ b/src/lib/kadm5/srv/Makefile.in @@ -9,7 +9,7 @@ DEFINES = @HESIOD_DEFS@ ##DOSLIBNAME = libkadm5srv.lib LIBBASE=kadm5srv_mit -LIBMAJOR=10 +LIBMAJOR=11 LIBMINOR=0 STOBJLISTS=../OBJS.ST OBJS.ST diff --git a/src/lib/kadm5/srv/libkadm5srv_mit.exports b/src/lib/kadm5/srv/libkadm5srv_mit.exports index 2cdd5a0534..aedfdd7f58 100644 --- a/src/lib/kadm5/srv/libkadm5srv_mit.exports +++ b/src/lib/kadm5/srv/libkadm5srv_mit.exports @@ -19,6 +19,7 @@ kadm5_delete_principal kadm5_destroy kadm5_flush kadm5_free_config_params +kadm5_free_kadm5_key_data kadm5_free_key_data kadm5_free_name_list kadm5_free_policy_ent @@ -92,6 +93,8 @@ xdr_cprinc_arg xdr_dpol_arg xdr_dprinc_arg xdr_generic_ret +xdr_getpkeys_arg +xdr_getpkeys_ret xdr_getprivs_ret xdr_gpol_arg xdr_gpol_ret diff --git a/src/lib/kadm5/srv/server_acl.c b/src/lib/kadm5/srv/server_acl.c index 97b2f7e82d..59ed0b9754 100644 --- a/src/lib/kadm5/srv/server_acl.c +++ b/src/lib/kadm5/srv/server_acl.c @@ -65,6 +65,7 @@ static const aop_t acl_op_table[] = { { 's', ACL_SETKEY }, { 'x', ACL_ALL_MASK }, { '*', ACL_ALL_MASK }, + { 'e', ACL_EXTRACT }, { '\0', 0 } }; diff --git a/src/lib/kadm5/srv/server_acl.h b/src/lib/kadm5/srv/server_acl.h index d492ea9c88..d8db2f75b0 100644 --- a/src/lib/kadm5/srv/server_acl.h +++ b/src/lib/kadm5/srv/server_acl.h @@ -54,7 +54,7 @@ #define ACL_CHANGEPW 8 /* #define ACL_CHANGE_OWN_PW 16 */ #define ACL_INQUIRE 32 -/* #define ACL_EXTRACT 64 */ +#define ACL_EXTRACT 64 #define ACL_LIST 128 #define ACL_SETKEY 256 #define ACL_IPROP 512 diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c index cc1be5a51d..800e8dbc36 100644 --- a/src/lib/kadm5/srv/svr_principal.c +++ b/src/lib/kadm5/srv/svr_principal.c @@ -2203,36 +2203,54 @@ done: kadm5_ret_t kadm5_get_principal_keys(void *server_handle /* IN */, krb5_principal principal /* IN */, - krb5_keyblock **keyblocks /* OUT */, - int *n_keys /* OUT */) + krb5_kvno kvno /* IN */, + kadm5_key_data **key_data_out /* OUT */, + int *n_key_data_out /* OUT */) { krb5_db_entry *kdb; osa_princ_ent_rec adb; kadm5_ret_t ret; kadm5_server_handle_t handle = server_handle; + kadm5_key_data *key_data = NULL; + int i, nkeys = 0; - if (keyblocks) - *keyblocks = NULL; + if (principal == NULL || key_data_out == NULL || n_key_data_out == NULL) + return EINVAL; CHECK_HANDLE(server_handle); - if (principal == NULL) - return EINVAL; - if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) return(ret); - if (keyblocks) { - ret = decrypt_key_data(handle->context, - kdb->n_key_data, kdb->key_data, - keyblocks, n_keys); + key_data = calloc(kdb->n_key_data, sizeof(kadm5_key_data)); + if (key_data == NULL) { + ret = ENOMEM; + goto done; + } + + for (i = 0, nkeys = 0; i < kdb->n_key_data; i++) { + if (kvno != 0 && kvno != kdb->key_data[i].key_data_kvno) + continue; + key_data[nkeys].kvno = kdb->key_data[i].key_data_kvno; + + ret = krb5_dbe_decrypt_key_data(handle->context, NULL, + &kdb->key_data[i], + &key_data[nkeys].key, + &key_data[nkeys].salt); if (ret) goto done; + nkeys++; } + *n_key_data_out = nkeys; + *key_data_out = key_data; + key_data = NULL; + nkeys = 0; ret = KADM5_OK; + done: kdb_free_entry(handle, kdb, &adb); + kadm5_free_kadm5_key_data(handle->context, nkeys, key_data); return ret; } diff --git a/src/lib/kadm5/unit-test/setkey-test.c b/src/lib/kadm5/unit-test/setkey-test.c index 2ecb5eb94a..0729885d91 100644 --- a/src/lib/kadm5/unit-test/setkey-test.c +++ b/src/lib/kadm5/unit-test/setkey-test.c @@ -137,6 +137,8 @@ main(int argc, char **argv) */ for (test = 0; tests[test] != NULL; test++) { krb5_keyblock *testp = tests[test]; + kadm5_key_data *extracted; + int n_extracted, match; printf("+ Test %d:\n", test); for (encnum = 0; testp[encnum].magic != -1; encnum++) { @@ -165,9 +167,31 @@ main(int argc, char **argv) exit(1); } + ret = kadm5_get_principal_keys(handle, princ, 0, &extracted, + &n_extracted); + if (ret) { + com_err(whoami, ret, "while extracting keys"); + exit(1); + } + for (encnum = 0; testp[encnum].magic != -1; encnum++) { printf("+ enctype %d\n", testp[encnum].enctype); + for (match = 0; match < n_extracted; match++) { + if (extracted[match].key.enctype == testp[encnum].enctype) + break; + } + if (match >= n_extracted) { + com_err(whoami, KRB5_WRONG_ETYPE, "while matching enctypes"); + exit(1); + } + if (extracted[match].key.length != testp[encnum].length || + memcmp(extracted[match].key.contents, testp[encnum].contents, + testp[encnum].length) != 0) { + com_err(whoami, KRB5_KDB_NO_MATCHING_KEY, "verifying keys"); + exit(1); + } + memset(&ktent, 0, sizeof(ktent)); ktent.principal = princ; ktent.key = testp[encnum]; @@ -206,6 +230,8 @@ main(int argc, char **argv) exit(1); } } + + (void)kadm5_free_kadm5_key_data(context, n_extracted, extracted); } ret = krb5_kt_close(context, kt); diff --git a/src/tests/t_keytab.py b/src/tests/t_keytab.py index 6b7e9bcb2f..a06e6c2965 100755 --- a/src/tests/t_keytab.py +++ b/src/tests/t_keytab.py @@ -41,6 +41,26 @@ if 'keytab specified, forcing -k' not in output: fail('Expected output not seen from kinit -i') realm.klist(realm.user_princ) +# Test extracting keys with multiple key versions present. +os.remove(realm.keytab) +realm.run([kadminl, 'cpw', '-randkey', '-keepold', realm.host_princ]) +out = realm.run([kadminl, 'ktadd', '-norandkey', realm.host_princ]) +if 'with kvno 1,' not in out or 'with kvno 2,' not in out: + fail('Expected output not seen from kadmin.local ktadd -norandkey') +out = realm.run([klist, '-k', '-e']) +if ' 1 host/' not in out or ' 2 host/' not in out: + fail('Expected output not seen from klist -k -e') + +# Test again using kadmin over the network. +realm.prep_kadmin() +os.remove(realm.keytab) +out = realm.run_kadmin(['ktadd', '-norandkey', realm.host_princ]) +if 'with kvno 1,' not in out or 'with kvno 2,' not in out: + fail('Expected output not seen from kadmin.local ktadd -norandkey') +out = realm.run([klist, '-k', '-e']) +if ' 1 host/' not in out or ' 2 host/' not in out: + fail('Expected output not seen from klist -k -e') + # Test handling of kvno values beyond 255. Use kadmin over the # network since we used to have an 8-bit limit on kvno marshalling. @@ -57,7 +77,6 @@ def test_key_rotate(realm, princ, expected_kvno): if ('Key: vno %d,' % expected_kvno) not in out: fail('vno %d not seen in getprinc output' % expected_kvno) -realm.prep_kadmin() princ = 'foo/bar@%s' % realm.realm realm.addprinc(princ) os.remove(realm.keytab) diff --git a/src/util/k5test.py b/src/util/k5test.py index df6a68a74a..c1df32f05a 100644 --- a/src/util/k5test.py +++ b/src/util/k5test.py @@ -851,7 +851,7 @@ class K5Realm(object): global hostname filename = os.path.join(self.testdir, 'acl') file = open(filename, 'w') - file.write('%s *\n' % self.admin_princ) + file.write('%s *e\n' % self.admin_princ) file.write('kiprop/%s@%s p\n' % (hostname, self.realm)) file.close()