aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Yu <tlyu@mit.edu>2010-10-08 03:57:28 +0000
committerTom Yu <tlyu@mit.edu>2010-10-08 03:57:28 +0000
commit1cc59c12550c828d487c622990d83481e8bbb6c5 (patch)
treea22d50f4041bfa23ad1001bfa6164626602885ac
parentbd7b3a76ef6ca5485ec8a8b2de4a2a5170356f84 (diff)
downloadkrb5-1cc59c12550c828d487c622990d83481e8bbb6c5.zip
krb5-1cc59c12550c828d487c622990d83481e8bbb6c5.tar.gz
krb5-1cc59c12550c828d487c622990d83481e8bbb6c5.tar.bz2
Add a kadm5 RPC for purging old keys from the KDB (e.g., from
change_password -keepold), and add a kadmin CLI command for it. Keeping ticket open because an automated test needs to be added. Long-term future work includes start/expire dates on keys, or not-yet-valid flags. ticket: 1219 status: open target_version: 1.9 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24442 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--doc/admin.texinfo21
-rw-r--r--src/kadmin/cli/kadmin.M21
-rw-r--r--src/kadmin/cli/kadmin.c47
-rw-r--r--src/kadmin/cli/kadmin_ct.ct3
-rw-r--r--src/kadmin/server/kadm_rpc_svc.c6
-rw-r--r--src/kadmin/server/ovsec_kadmd.c3
-rw-r--r--src/kadmin/server/server_stubs.c57
-rw-r--r--src/lib/kadm5/admin.h5
-rw-r--r--src/lib/kadm5/clnt/client_principal.c23
-rw-r--r--src/lib/kadm5/clnt/client_rpc.c15
-rw-r--r--src/lib/kadm5/clnt/libkadm5clnt_mit.exports1
-rw-r--r--src/lib/kadm5/kadm_rpc.h11
-rw-r--r--src/lib/kadm5/kadm_rpc_xdr.c16
-rw-r--r--src/lib/kadm5/srv/libkadm5srv_mit.exports2
-rw-r--r--src/lib/kadm5/srv/svr_principal.c62
15 files changed, 272 insertions, 21 deletions
diff --git a/doc/admin.texinfo b/doc/admin.texinfo
index 9c0d290..bcabb62 100644
--- a/doc/admin.texinfo
+++ b/doc/admin.texinfo
@@ -2586,10 +2586,10 @@ earlier than krb5-1.2. See @ref{Supported Encryption Types} and
@ref{Salts} for possible values.
@item @b{-keepold}
-Keeps the previous kvno's keys around. There is no easy way to delete
-the old keys, and this flag is usually not necessary except perhaps for
-TGS keys. Don't use this flag unless you know what you're doing. This
-option is not supported for the LDAP database
+Keeps the previous kvno's keys around. This flag is usually not
+necessary except perhaps for TGS keys. Don't use this flag unless you
+know what you're doing. This option is not supported for the LDAP
+database
@@ -4015,14 +4015,11 @@ well as the new key. For example:
@end group
@end smallexample
-There is currently no way to remove the old key without running
-@code{change_password} without the @b{-keepold} flag (and thereby
-invalidating all existing TGTs). After issuing this command, the old
-key is still valid and is still vulnerable to (for instance) brute force
-attacks. To completely retire an old key or encryption type, it's
-therefore currently necessary to declare a flag day, run
-@code{change_password} without the @b{-keepold} flag, and force all
-users to acquire new tickets.
+After issuing this command, the old key is still valid and is still
+vulnerable to (for instance) brute force attacks. To completely
+retire an old key or encryption type, run the @code{purgekeys} command
+to delete keys with older kvnos, ideally first making sure that all
+tickets issued with the old keys have expired.
@node Configuring Kerberos with OpenLDAP back-end, Application Servers, Administrating the Kerberos Database, Top
@chapter Configuring Kerberos with OpenLDAP back-end
diff --git a/src/kadmin/cli/kadmin.M b/src/kadmin/cli/kadmin.M
index d6f2df5..7e6db2c 100644
--- a/src/kadmin/cli/kadmin.M
+++ b/src/kadmin/cli/kadmin.M
@@ -562,8 +562,7 @@ enctype\-salttype pairs. This will not function against kadmin
daemons earlier than krb5\-1.2.
.TP
\fB\-keepold \fP
-Keeps the previous kvno's keys around. There is no
-easy way to delete the old keys, and this flag is usually not
+Keeps the previous kvno's keys around. This flag is usually not
necessary except perhaps for TGS keys. Don't use this flag unless you
know what you're doing. This option is not supported for the LDAP database.
.nf
@@ -586,6 +585,18 @@ expired)
.RE
.fi
.TP
+\fBpurgekeys\fP [\fB-keepkvno\fP \fIoldest_kvno_to_keep\fP] \fIprincipal\fP
+purges previously retained old keys (e.g., from
+.B change_password
+.BR -keepold )
+from
+.IR principal .
+If
+.B -keepkvno
+is specified, then only purges keys with kvnos lower than
+.IR oldest_kvno_to_keep .
+.fi
+.TP
\fBget_principal\fP [\fB-terse\fP] \fIprincipal\fP
gets the attributes of
.IR principal .
@@ -922,9 +933,3 @@ OpenVision Kerberos administration program.
.SH BUGS
.PP
Command output needs to be cleaned up.
-
-There is no way to delete a key kept around from a "\-keepold" option
-to a password-changing command, other than to do a password change
-without the "\-keepold" option, which will of course cause problems if
-the key is a TGS key. There will be more powerful key-manipulation
-commands in the future.
diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c
index ff6eeca..bf37bbe 100644
--- a/src/kadmin/cli/kadmin.c
+++ b/src/kadmin/cli/kadmin.c
@@ -1742,3 +1742,50 @@ kadmin_getprivs(int argc, char *argv[])
}
printf("\n");
}
+
+void
+kadmin_purgekeys(int argc, char *argv[])
+{
+ kadm5_ret_t retval;
+ int keepkvno = -1;
+ char *pname = NULL, *canon = NULL;
+ krb5_principal princ;
+
+ if (argc == 4 && strcmp(argv[1], "-keepkvno") == 0) {
+ keepkvno = atoi(argv[2]);
+ pname = argv[3];
+ }
+ if (argc == 2) {
+ pname = argv[1];
+ }
+ if (pname == NULL) {
+ fprintf(stderr, "usage: purgekeys [-keepkvno oldest_kvno_to_keep] "
+ "principal\n");
+ return;
+ }
+
+ retval = kadmin_parse_name(pname, &princ);
+ if (retval) {
+ com_err("purgekeys", retval, "while parsing principal");
+ return;
+ }
+
+ retval = krb5_unparse_name(context, princ, &canon);
+ if (retval) {
+ com_err("purgekeys", retval, "while canonicalizing principal");
+ goto cleanup;
+ }
+
+ retval = kadm5_purgekeys(handle, princ, keepkvno);
+ if (retval) {
+ com_err("purgekeys", retval,
+ "while purging keys for principal \"%s\"", canon);
+ goto cleanup;
+ }
+
+ printf("Old keys for principal \"%s\" purged.\n", canon);
+cleanup:
+ krb5_free_principal(context, princ);
+ free(canon);
+ return;
+}
diff --git a/src/kadmin/cli/kadmin_ct.ct b/src/kadmin/cli/kadmin_ct.ct
index 05a4efb..6228f95 100644
--- a/src/kadmin/cli/kadmin_ct.ct
+++ b/src/kadmin/cli/kadmin_ct.ct
@@ -74,6 +74,9 @@ request kadmin_lock, "Lock database exclusively (use with extreme caution!)",
request kadmin_unlock, "Release exclusive database lock",
unlock;
+request kadmin_purgekeys, "Purge previously retained old keys from a principal",
+ purgekeys;
+
# list_requests is generic -- unrelated to Kerberos
request ss_list_requests, "List available requests.",
list_requests, lr, "?";
diff --git a/src/kadmin/server/kadm_rpc_svc.c b/src/kadmin/server/kadm_rpc_svc.c
index 76df26e..a231d0b 100644
--- a/src/kadmin/server/kadm_rpc_svc.c
+++ b/src/kadmin/server/kadm_rpc_svc.c
@@ -212,6 +212,12 @@ void kadm_1(rqstp, transp)
local = (char *(*)()) setkey_principal3_2_svc;
break;
+ case PURGEKEYS:
+ xdr_argument = xdr_purgekeys_arg;
+ xdr_result = xdr_generic_ret;
+ local = (char *(*)()) purgekeys_2_svc;
+ break;
+
default:
krb5_klog_syslog(LOG_ERR, "Invalid KADM5 procedure number: %s, %d",
inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr),
diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c
index 8e87616..4d7a261 100644
--- a/src/kadmin/server/ovsec_kadmd.c
+++ b/src/kadmin/server/ovsec_kadmd.c
@@ -922,7 +922,8 @@ void log_badverf(gss_name_t client_name, gss_name_t server_name,
{18, "CREATE_PRINCIPAL3"},
{19, "CHPASS_PRINCIPAL3"},
{20, "CHRAND_PRINCIPAL3"},
- {21, "SETKEY_PRINCIPAL3"}
+ {21, "SETKEY_PRINCIPAL3"},
+ {22, "PURGEKEYS"}
};
#define NPROCNAMES (sizeof (proc_names) / sizeof (struct procnames))
OM_uint32 minor;
diff --git a/src/kadmin/server/server_stubs.c b/src/kadmin/server/server_stubs.c
index 29a8805..79bd283 100644
--- a/src/kadmin/server/server_stubs.c
+++ b/src/kadmin/server/server_stubs.c
@@ -1564,6 +1564,63 @@ exit_func:
return &ret;
}
+generic_ret *
+purgekeys_2_svc(purgekeys_arg *arg, struct svc_req *rqstp)
+{
+ static generic_ret ret;
+ char *prime_arg, *funcname;
+ gss_buffer_desc client_name, service_name;
+ OM_uint32 minor_stat;
+ kadm5_server_handle_t handle;
+
+ const char *errmsg = NULL;
+
+ xdr_free(xdr_generic_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;
+
+ funcname = "kadm5_purgekeys";
+
+ 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_MODIFY,
+ arg->princ, NULL)) {
+ ret.code = KADM5_AUTH_MODIFY;
+ log_unauth(funcname, prime_arg, &client_name, &service_name, rqstp);
+ } else {
+ ret.code = kadm5_purgekeys((void *)handle, arg->princ,
+ arg->keepkvno);
+ if (ret.code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret.code);
+
+ log_done(funcname, prime_arg, errmsg ? errmsg : "success",
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+ free(prime_arg);
+ gss_release_buffer(&minor_stat, &client_name);
+ gss_release_buffer(&minor_stat, &service_name);
+exit_func:
+ free_server_handle(handle);
+ return &ret;
+}
+
generic_ret *init_2_svc(krb5_ui_4 *arg, struct svc_req *rqstp)
{
static generic_ret ret;
diff --git a/src/lib/kadm5/admin.h b/src/lib/kadm5/admin.h
index 647226c..9983703 100644
--- a/src/lib/kadm5/admin.h
+++ b/src/lib/kadm5/admin.h
@@ -508,6 +508,11 @@ kadm5_ret_t kadm5_get_principal_keys(void *server_handle,
krb5_keyblock **keyblocks,
int *n_keys);
+
+kadm5_ret_t kadm5_purgekeys(void *server_handle,
+ krb5_principal principal,
+ int keepkvno);
+
KADM5INT_END_DECLS
#endif /* __KADM5_ADMIN_H__ */
diff --git a/src/lib/kadm5/clnt/client_principal.c b/src/lib/kadm5/clnt/client_principal.c
index 95d5c2d..019c50a 100644
--- a/src/lib/kadm5/clnt/client_principal.c
+++ b/src/lib/kadm5/clnt/client_principal.c
@@ -463,3 +463,26 @@ kadm5_ret_t kadm5_decrypt_key(void *server_handle,
{
return EINVAL;
}
+
+kadm5_ret_t
+kadm5_purgekeys(void *server_handle,
+ krb5_principal princ,
+ int keepkvno)
+{
+ purgekeys_arg arg;
+ generic_ret *r;
+ kadm5_server_handle_t handle = server_handle;
+
+ CHECK_HANDLE(server_handle);
+
+ arg.princ = princ;
+ arg.keepkvno = keepkvno;
+ arg.api_version = handle->api_version;
+
+ if (princ == NULL)
+ return EINVAL;
+ r = purgekeys_2(&arg, handle->clnt);
+ if(r == NULL)
+ eret();
+ return r->code;
+}
diff --git a/src/lib/kadm5/clnt/client_rpc.c b/src/lib/kadm5/clnt/client_rpc.c
index 184f154..95417a6 100644
--- a/src/lib/kadm5/clnt/client_rpc.c
+++ b/src/lib/kadm5/clnt/client_rpc.c
@@ -326,3 +326,18 @@ init_2(void *argp, CLIENT *clnt)
}
return (&clnt_res);
}
+
+generic_ret *
+purgekeys_2(purgekeys_arg *argp, CLIENT *clnt)
+{
+ static generic_ret clnt_res;
+
+ memset(&clnt_res, 0, sizeof(clnt_res));
+ if (clnt_call(clnt, PURGEKEYS,
+ (xdrproc_t) xdr_purgekeys_arg, (caddr_t) argp,
+ (xdrproc_t) xdr_generic_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 5e81580..249a3c7 100644
--- a/src/lib/kadm5/clnt/libkadm5clnt_mit.exports
+++ b/src/lib/kadm5/clnt/libkadm5clnt_mit.exports
@@ -32,6 +32,7 @@ kadm5_init_with_skey
kadm5_lock
kadm5_modify_policy
kadm5_modify_principal
+kadm5_purgekeys
kadm5_randkey_principal
kadm5_randkey_principal_3
kadm5_rename_principal
diff --git a/src/lib/kadm5/kadm_rpc.h b/src/lib/kadm5/kadm_rpc.h
index fb86605..1aa98d0 100644
--- a/src/lib/kadm5/kadm_rpc.h
+++ b/src/lib/kadm5/kadm_rpc.h
@@ -200,6 +200,13 @@ struct getprivs_ret {
};
typedef struct getprivs_ret getprivs_ret;
+struct purgekeys_arg {
+ krb5_ui_4 api_version;
+ krb5_principal princ;
+ int keepkvno;
+};
+typedef struct purgekeys_arg purgekeys_arg;
+
#define KADM 2112
#define KADMVERS 2
#define CREATE_PRINCIPAL 1
@@ -265,6 +272,9 @@ extern chrand_ret * chrand_principal3_2_svc(chrand3_arg *, struct svc_req *);
#define SETKEY_PRINCIPAL3 21
extern generic_ret * setkey_principal3_2(setkey3_arg *, CLIENT *);
extern generic_ret * setkey_principal3_2_svc(setkey3_arg *, struct svc_req *);
+#define PURGEKEYS 22
+extern generic_ret * purgekeys_2(purgekeys_arg *, CLIENT *);
+extern generic_ret * purgekeys_2_svc(purgekeys_arg *, struct svc_req *);
extern bool_t xdr_cprinc_arg ();
extern bool_t xdr_cprinc3_arg ();
@@ -301,6 +311,7 @@ extern bool_t xdr_gpol_ret ();
extern bool_t xdr_gpols_arg ();
extern bool_t xdr_gpols_ret ();
extern bool_t xdr_getprivs_ret ();
+extern bool_t xdr_purgekeys_arg ();
#endif /* __KADM_RPC_H__ */
diff --git a/src/lib/kadm5/kadm_rpc_xdr.c b/src/lib/kadm5/kadm_rpc_xdr.c
index 5fb67eb..0b14ff8 100644
--- a/src/lib/kadm5/kadm_rpc_xdr.c
+++ b/src/lib/kadm5/kadm_rpc_xdr.c
@@ -956,6 +956,22 @@ bool_t xdr_getprivs_ret(XDR *xdrs, getprivs_ret *objp)
}
bool_t
+xdr_purgekeys_arg(XDR *xdrs, purgekeys_arg *objp)
+{
+ if (!xdr_ui_4(xdrs, &objp->api_version)) {
+ return (FALSE);
+ }
+ if (!xdr_krb5_principal(xdrs, &objp->princ)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->keepkvno)) {
+ return FALSE;
+ }
+
+ return (TRUE);
+}
+
+bool_t
xdr_krb5_principal(XDR *xdrs, krb5_principal *objp)
{
int ret;
diff --git a/src/lib/kadm5/srv/libkadm5srv_mit.exports b/src/lib/kadm5/srv/libkadm5srv_mit.exports
index 345957a..49a1b88 100644
--- a/src/lib/kadm5/srv/libkadm5srv_mit.exports
+++ b/src/lib/kadm5/srv/libkadm5srv_mit.exports
@@ -43,6 +43,7 @@ kadm5_lock
kadm5_modify_policy
kadm5_modify_policy_internal
kadm5_modify_principal
+kadm5_purgekeys
kadm5_randkey_principal
kadm5_randkey_principal_3
kadm5_rename_principal
@@ -129,6 +130,7 @@ xdr_nullstring
xdr_nulltype
xdr_osa_princ_ent_rec
xdr_osa_pw_hist_ent
+xdr_purgekeys_arg
xdr_rprinc_arg
xdr_setkey3_arg
xdr_setkey_arg
diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c
index e50c922..696362a 100644
--- a/src/lib/kadm5/srv/svr_principal.c
+++ b/src/lib/kadm5/srv/svr_principal.c
@@ -2219,3 +2219,65 @@ kadm5_ret_t kadm5_decrypt_key(void *server_handle,
return KADM5_OK;
}
+
+kadm5_ret_t
+kadm5_purgekeys(void *server_handle,
+ krb5_principal principal,
+ int keepkvno)
+{
+ kadm5_server_handle_t handle = server_handle;
+ kadm5_ret_t ret;
+ krb5_db_entry *kdb;
+ osa_princ_ent_rec adb;
+ krb5_key_data *old_keydata;
+ int n_old_keydata;
+ int i, j, k;
+
+ CHECK_HANDLE(server_handle);
+
+ if (principal == NULL)
+ return EINVAL;
+
+ ret = kdb_get_entry(handle, principal, &kdb, &adb);
+ if (ret)
+ return(ret);
+
+ if (keepkvno <= 0) {
+ keepkvno = krb5_db_get_key_data_kvno(handle->context, kdb->n_key_data,
+ kdb->key_data);
+ }
+
+ old_keydata = kdb->key_data;
+ n_old_keydata = kdb->n_key_data;
+ kdb->n_key_data = 0;
+ kdb->key_data = krb5_db_alloc(handle->context, NULL,
+ n_old_keydata * sizeof(krb5_key_data));
+ if (kdb->key_data == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ memset(kdb->key_data, 0, n_old_keydata * sizeof(krb5_key_data));
+ for (i = 0, j = 0; i < n_old_keydata; i++) {
+ if (old_keydata[i].key_data_kvno < keepkvno)
+ continue;
+
+ /* Alias the key_data_contents pointers; we null them out in the
+ * source array immediately after. */
+ kdb->key_data[j] = old_keydata[i];
+ for (k = 0; k < old_keydata[i].key_data_ver; k++) {
+ old_keydata[i].key_data_contents[k] = NULL;
+ }
+ j++;
+ }
+ kdb->n_key_data = j;
+ cleanup_key_data(handle->context, n_old_keydata, old_keydata);
+
+ kdb->mask = KADM5_KEY_DATA;
+ ret = kdb_put_entry(handle, kdb, &adb);
+ if (ret)
+ goto done;
+
+done:
+ kdb_free_entry(handle, kdb, &adb);
+ return ret;
+}