svn rev #24442: trunk/ doc/ src/kadmin/cli/ src/kadmin/server/ src/lib/kadm5/ ...

tlyu@MIT.EDU tlyu at MIT.EDU
Thu Oct 7 23:57:28 EDT 2010


http://src.mit.edu/fisheye/changelog/krb5/?cs=24442
Commit By: tlyu
Log Message:
ticket: 1219
status: open
target_version: 1.9

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.


Changed Files:
U   trunk/doc/admin.texinfo
U   trunk/src/kadmin/cli/kadmin.M
U   trunk/src/kadmin/cli/kadmin.c
U   trunk/src/kadmin/cli/kadmin_ct.ct
U   trunk/src/kadmin/server/kadm_rpc_svc.c
U   trunk/src/kadmin/server/ovsec_kadmd.c
U   trunk/src/kadmin/server/server_stubs.c
U   trunk/src/lib/kadm5/admin.h
U   trunk/src/lib/kadm5/clnt/client_principal.c
U   trunk/src/lib/kadm5/clnt/client_rpc.c
U   trunk/src/lib/kadm5/clnt/libkadm5clnt_mit.exports
U   trunk/src/lib/kadm5/kadm_rpc.h
U   trunk/src/lib/kadm5/kadm_rpc_xdr.c
U   trunk/src/lib/kadm5/srv/libkadm5srv_mit.exports
U   trunk/src/lib/kadm5/srv/svr_principal.c
Modified: trunk/doc/admin.texinfo
===================================================================
--- trunk/doc/admin.texinfo	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/doc/admin.texinfo	2010-10-08 03:57:28 UTC (rev 24442)
@@ -2586,10 +2586,10 @@
 @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 @@
 @end group
 @end smallexample
 
-There is currently no way to remove the old key without running
- at 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
- at 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

Modified: trunk/src/kadmin/cli/kadmin.M
===================================================================
--- trunk/src/kadmin/cli/kadmin.M	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/kadmin/cli/kadmin.M	2010-10-08 03:57:28 UTC (rev 24442)
@@ -562,8 +562,7 @@
 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 @@
 .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 @@
 .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.

Modified: trunk/src/kadmin/cli/kadmin.c
===================================================================
--- trunk/src/kadmin/cli/kadmin.c	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/kadmin/cli/kadmin.c	2010-10-08 03:57:28 UTC (rev 24442)
@@ -1742,3 +1742,50 @@
     }
     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;
+}

Modified: trunk/src/kadmin/cli/kadmin_ct.ct
===================================================================
--- trunk/src/kadmin/cli/kadmin_ct.ct	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/kadmin/cli/kadmin_ct.ct	2010-10-08 03:57:28 UTC (rev 24442)
@@ -74,6 +74,9 @@
 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, "?";

Modified: trunk/src/kadmin/server/kadm_rpc_svc.c
===================================================================
--- trunk/src/kadmin/server/kadm_rpc_svc.c	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/kadmin/server/kadm_rpc_svc.c	2010-10-08 03:57:28 UTC (rev 24442)
@@ -212,6 +212,12 @@
 	  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),

Modified: trunk/src/kadmin/server/ovsec_kadmd.c
===================================================================
--- trunk/src/kadmin/server/ovsec_kadmd.c	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/kadmin/server/ovsec_kadmd.c	2010-10-08 03:57:28 UTC (rev 24442)
@@ -922,7 +922,8 @@
         {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;

Modified: trunk/src/kadmin/server/server_stubs.c
===================================================================
--- trunk/src/kadmin/server/server_stubs.c	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/kadmin/server/server_stubs.c	2010-10-08 03:57:28 UTC (rev 24442)
@@ -1564,6 +1564,63 @@
     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;

Modified: trunk/src/lib/kadm5/admin.h
===================================================================
--- trunk/src/lib/kadm5/admin.h	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/lib/kadm5/admin.h	2010-10-08 03:57:28 UTC (rev 24442)
@@ -508,6 +508,11 @@
                                         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__ */

Modified: trunk/src/lib/kadm5/clnt/client_principal.c
===================================================================
--- trunk/src/lib/kadm5/clnt/client_principal.c	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/lib/kadm5/clnt/client_principal.c	2010-10-08 03:57:28 UTC (rev 24442)
@@ -463,3 +463,26 @@
 {
     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;
+}

Modified: trunk/src/lib/kadm5/clnt/client_rpc.c
===================================================================
--- trunk/src/lib/kadm5/clnt/client_rpc.c	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/lib/kadm5/clnt/client_rpc.c	2010-10-08 03:57:28 UTC (rev 24442)
@@ -326,3 +326,18 @@
      }
      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);
+}

Modified: trunk/src/lib/kadm5/clnt/libkadm5clnt_mit.exports
===================================================================
--- trunk/src/lib/kadm5/clnt/libkadm5clnt_mit.exports	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/lib/kadm5/clnt/libkadm5clnt_mit.exports	2010-10-08 03:57:28 UTC (rev 24442)
@@ -32,6 +32,7 @@
 kadm5_lock
 kadm5_modify_policy
 kadm5_modify_principal
+kadm5_purgekeys
 kadm5_randkey_principal
 kadm5_randkey_principal_3
 kadm5_rename_principal

Modified: trunk/src/lib/kadm5/kadm_rpc.h
===================================================================
--- trunk/src/lib/kadm5/kadm_rpc.h	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/lib/kadm5/kadm_rpc.h	2010-10-08 03:57:28 UTC (rev 24442)
@@ -200,6 +200,13 @@
 };
 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 @@
 #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_gpols_arg ();
 extern bool_t xdr_gpols_ret ();
 extern bool_t xdr_getprivs_ret ();
+extern bool_t xdr_purgekeys_arg ();
 
 
 #endif /* __KADM_RPC_H__ */

Modified: trunk/src/lib/kadm5/kadm_rpc_xdr.c
===================================================================
--- trunk/src/lib/kadm5/kadm_rpc_xdr.c	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/lib/kadm5/kadm_rpc_xdr.c	2010-10-08 03:57:28 UTC (rev 24442)
@@ -956,6 +956,22 @@
 }
 
 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;

Modified: trunk/src/lib/kadm5/srv/libkadm5srv_mit.exports
===================================================================
--- trunk/src/lib/kadm5/srv/libkadm5srv_mit.exports	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/lib/kadm5/srv/libkadm5srv_mit.exports	2010-10-08 03:57:28 UTC (rev 24442)
@@ -43,6 +43,7 @@
 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_nulltype
 xdr_osa_princ_ent_rec
 xdr_osa_pw_hist_ent
+xdr_purgekeys_arg
 xdr_rprinc_arg
 xdr_setkey3_arg
 xdr_setkey_arg

Modified: trunk/src/lib/kadm5/srv/svr_principal.c
===================================================================
--- trunk/src/lib/kadm5/srv/svr_principal.c	2010-10-07 17:50:06 UTC (rev 24441)
+++ trunk/src/lib/kadm5/srv/svr_principal.c	2010-10-08 03:57:28 UTC (rev 24442)
@@ -2219,3 +2219,65 @@
 
     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;
+}




More information about the cvs-krb5 mailing list