[krbdev.mit.edu #3699] [PATCH] add support to kadm5 for removing old kvnos

The RT System itself via RT rt-comment at krbdev.mit.edu
Wed Apr 26 17:00:41 EDT 2006


>From krb5-bugs-incoming-bounces at PCH.mit.edu  Wed Apr 26 17:00:37 2006
Received: from pch.mit.edu (PCH.MIT.EDU [18.7.21.90]) by krbdev.mit.edu (8.9.3p2) with ESMTP
	id RAA28300; Wed, 26 Apr 2006 17:00:37 -0400 (EDT)
Received: from pch.mit.edu (pch.mit.edu [127.0.0.1])
	by pch.mit.edu (8.13.6/8.12.8) with ESMTP id k3QL06iv023228
	for <krb5-send-pr at krbdev.mit.edu>; Wed, 26 Apr 2006 17:00:06 -0400
Received: from pacific-carrier-annex.mit.edu (PACIFIC-CARRIER-ANNEX.MIT.EDU
	[18.7.21.83])
	by pch.mit.edu (8.13.6/8.12.8) with ESMTP id k3QGegFZ009513
	for <krb5-bugs-incoming at PCH.mit.edu>; Wed, 26 Apr 2006 12:40:42 -0400
Received: from srvr22.engin.umich.edu (srvr22.engin.umich.edu [141.213.75.21])
	by pacific-carrier-annex.mit.edu (8.13.6/8.9.2) with ESMTP id
	k3QGeZSh027805
	for <krb5-bugs at mit.edu>; Wed, 26 Apr 2006 12:40:35 -0400 (EDT)
Received: from gx620.engin.umich.edu
	(IDENT:U2FsdGVkX1+S5MucdlBM4ubgaa0dIv7ZYm7NgtjezZ4 at gx620.engin.umich.edu
	[141.213.40.58])
	by srvr22.engin.umich.edu (8.13.6/8.13.6) with ESMTP id k3QGeY1x000780
	for <krb5-bugs at mit.edu>; Wed, 26 Apr 2006 12:40:35 -0400 (EDT)
Received: (from wingc at localhost)
	by gx620.engin.umich.edu (8.13.6/8.13.6/Submit) id k3QGeX9g012128;
	Wed, 26 Apr 2006 12:40:33 -0400
Date: Wed, 26 Apr 2006 12:40:33 -0400
Message-Id: <200604261640.k3QGeX9g012128 at gx620.engin.umich.edu>
To: krb5-bugs at mit.edu
Subject: [PATCH] add support to kadm5 for removing old kvnos
From: wingc at engin.umich.edu
X-send-pr-version: 3.99
X-Spam-Score: -1.638
X-Spam-Flag: NO
X-Scanned-By: MIMEDefang 2.42
X-Mailman-Approved-At: Wed, 26 Apr 2006 16:55:53 -0400
X-BeenThere: krb5-bugs-incoming at mailman.mit.edu
X-Mailman-Version: 2.1.6
Precedence: list
Reply-To: wingc at engin.umich.edu
Sender: krb5-bugs-incoming-bounces at PCH.mit.edu
Errors-To: krb5-bugs-incoming-bounces at PCH.mit.edu


>Submitter-Id:	net
>Originator:	Christopher Allen Wing
>Organization:  University of Michigan - CAEN
>Confidential:	no
>Synopsis:	[PATCH] add support to kadm5 for removing old kvnos
>Severity:	non-critical
>Priority:	low
>Category:	krb5-admin
>Class:		change-request
>Release:	1.4.3
>Environment:
	
System: any
Architecture: any

>Description:
In krb5-1.4.3, there is no way to remove old kvnos for a principal whose
password was changed using the -keepold option in kadmin.  This is of
interest when rekeying the TGS key as per the kadmin man page:

	kadmin:  cpw -randkey -keepold krbtgt/REALM.NAME

Attached is a patch against 1.4.3 which adds a new kadm5 RPM called
'flushkeys' to remove old kvnos.  The patch does the following:

	1. define FLUSHKEYS_PRINCIPAL kadm5 RPC (#22)

	2. add kadm5_flushkeys_principal() API to libkadm5clnt and
	   libkadm5srv

	3. hook up support in kadmind, using the 'setkey' ACL permission
	   (seemed reasonable)

	4. add 'flushkeys' command to kadmin client

	5. update man pages and documentation


Does this seem reasonable?  The FLUSHKEYS_PRINCIPAL RPC just removes all
keys for a principal which are older than the current max kvno.  If all
keys have the same kvno then it does nothing.

As far as I can guess, this would only be needed for rekeying the TGS key,
which can be done (with the patch) as follows:

	kadmin:  cpw -randkey -keepold krbtgt/REALM

(now wait until all previously issued TGTs have expired)

	kadmin:  flushkeys krbtgt/REALM

(this removes the old kvnos for the TGS key)


All other service principals should be able to be rekeyed by doing a regular
'ktadd' and storing the new keys into the application server's keytab along
with the old kvnos.  The old kvnos shouldn't have to stay in the KDC
database for any reason, right?


TGS rekeying isn't too common, but it is necessary e.g. when upgrading
encryption types on an existing krb5 realm.  It would be nice to handle this
gracefully without hacks like manually editing the old kvnos out of the
database via a dump.

I can re-do the patch against the latest CVS code if the patch is
undesirable for 1.4 but would be considered for 1.5.

>How-To-Repeat:
	N/A
>Fix:

diff -uNr krb5-1.4.3.orig/doc/admin.texinfo krb5-1.4.3/doc/admin.texinfo
--- krb5-1.4.3.orig/doc/admin.texinfo	2004-06-10 17:46:01.000000000 -0400
+++ krb5-1.4.3/doc/admin.texinfo	2006-04-25 10:04:49.000000000 -0400
@@ -1861,6 +1861,32 @@
 explicitly setting the kvno with the @samp{-kvno} option.  See
 @ref{Cross-realm Authentication} for more details.
 
+ at node Removing a Principal's Old Keys
+ at node Removing a Principal's Old Keys
+
+After rekeying a TGS principal by using the @code{change_password}
+command with @b{-keepold} option, you should remove the old keys once
+all credentials issued with the old kvno have expired.  This is done 
+using the kadmin @code{flush_old_keys} command, which requires the 
+``setkey'' administrative privilege.  The syntax is:
+
+ at smallexample
+ at b{flush_old_keys} @i{principal}
+ at end smallexample
+
+ at noindent @code{flush_old_keys} has the alias @code{flushkeys}.  For
+example:
+
+ at smallexample
+ at group
+ at b{kadmin:} flushkeys krbtgt/@value{PRIMARYREALM}
+ at b{Are you sure you want to remove old keys for the principal
+"krbtgt/@value{PRIMARYREALM}@@@value{PRIMARYREALM}"? (yes/no):} yes
+ at b{Old keys for principal "krbtgt/@value{PRIMARYREALM}@@@value{PRIMARYREALM}" removed.
+kadmin:}
+ at end group
+ at end smallexample
+
 @node Deleting Principals, Changing Passwords, Adding or Modifying Principals, Principals
 @subsection Deleting Principals
 
@@ -1917,9 +1943,11 @@
 @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.
+Keeps the previous kvno's keys around.  This is useful when rekeying a
+TGS principal so that you do not cause problems for clients with
+existing credentials of the older kvno.  The @code{flush_old_keys}
+command can then be used to remove the old keys at a later time (e.g.,
+after all previously issued credentials have expired).
 
 @end table
 
diff -uNr krb5-1.4.3.orig/src/kadmin/cli/kadmin.c krb5-1.4.3/src/kadmin/cli/kadmin.c
--- krb5-1.4.3.orig/src/kadmin/cli/kadmin.c	2005-03-22 18:53:59.000000000 -0500
+++ krb5-1.4.3/src/kadmin/cli/kadmin.c	2006-04-25 09:43:57.000000000 -0400
@@ -575,6 +575,53 @@
     return;
 }
 
+void kadmin_flushkeys(argc, argv)
+    int argc;
+    char *argv[];
+{
+    kadm5_ret_t retval;
+    krb5_principal princ;
+    char *canon;
+    char reply[5];
+    
+    if (argc != 2) {
+	fprintf(stderr, "usage: flush_old_keys principal\n");
+	return;
+    }
+    retval = kadmin_parse_name(argv[1], &princ);
+    if (retval) {
+	com_err("flush_old_keys", retval, "while parsing principal name");
+	return;
+    }
+    retval = krb5_unparse_name(context, princ, &canon);
+    if (retval) {
+	com_err("flush_old_keys", retval,
+		"while canonicalizing principal");
+	krb5_free_principal(context, princ);
+	return;
+    }
+
+    printf("Are you sure you want to remove old keys for the principal \"%s\"? (yes/no): ", canon);
+    fgets(reply, sizeof (reply), stdin);
+    if (strcmp("yes\n", reply)) {
+	fprintf(stderr, "Principal \"%s\" unchanged\n", canon);
+	free(canon);
+	krb5_free_principal(context, princ);
+	return;
+    }
+    retval = kadm5_flushkeys_principal(handle, princ);
+    krb5_free_principal(context, princ);
+    if (retval) {
+	com_err("flush_old_keys", retval,
+		"while processing principal \"%s\"", canon);
+	free(canon);
+	return;
+    }
+    printf("Old keys for principal \"%s\" removed.\n", canon);
+    free(canon);
+    return;
+}
+
 void kadmin_cpw(argc, argv)
     int argc;
     char *argv[];
diff -uNr krb5-1.4.3.orig/src/kadmin/cli/kadmin_ct.ct krb5-1.4.3/src/kadmin/cli/kadmin_ct.ct
--- krb5-1.4.3.orig/src/kadmin/cli/kadmin_ct.ct	2002-10-08 16:20:29.000000000 -0400
+++ krb5-1.4.3/src/kadmin/cli/kadmin_ct.ct	2006-04-25 09:43:57.000000000 -0400
@@ -38,6 +38,9 @@
 request kadmin_cpw, "Change password",
 	change_password, cpw;
 
+request kadmin_flushkeys, "Flush old kvnos for a principal",
+	flush_old_keys, flushkeys;
+
 request kadmin_getprinc, "Get principal",
 	get_principal, getprinc;
 
diff -uNr krb5-1.4.3.orig/src/kadmin/cli/kadmin.h krb5-1.4.3/src/kadmin/cli/kadmin.h
--- krb5-1.4.3.orig/src/kadmin/cli/kadmin.h	2004-05-30 03:27:32.000000000 -0400
+++ krb5-1.4.3/src/kadmin/cli/kadmin.h	2006-04-25 09:43:57.000000000 -0400
@@ -36,6 +36,7 @@
 extern void kadmin_lock(int argc, char *argv[]);
 extern void kadmin_unlock(int argc, char *argv[]);
 extern void kadmin_delprinc(int argc, char *argv[]);
+extern void kadmin_flushkeys(int argc, char *argv[]);
 extern void kadmin_cpw(int argc, char *argv[]);
 extern void kadmin_addprinc(int argc, char *argv[]);
 extern void kadmin_modprinc(int argc, char *argv[]);
diff -uNr krb5-1.4.3.orig/src/kadmin/cli/kadmin.M krb5-1.4.3/src/kadmin/cli/kadmin.M
--- krb5-1.4.3.orig/src/kadmin/cli/kadmin.M	2005-03-22 18:53:59.000000000 -0500
+++ krb5-1.4.3/src/kadmin/cli/kadmin.M	2006-04-25 12:01:58.000000000 -0400
@@ -403,6 +403,32 @@
 .RE
 .fi
 .TP
+\fBflush_old_keys\fP \fIprincipal\fP
+removes keys with old kvnos for the specified principal.  This command 
+always prompts for confirmation before performing the operation.  This 
+command requires the
+.I setkey
+privilege.  If all keys have the same kvno, then this command has no 
+effect.  Aliased
+to
+.BR flushkeys .
+.sp
+.nf
+.RS
+.TP
+EXAMPLE:
+kadmin: flushkeys krbtgt/BLEEP.COM
+Are you sure you want to remove old keys for the principal
+"krbtgt/BLEEP.COM at BLEEP.COM"? (yes/no): yes
+Old keys for principal krbtgt/BLEEP.COM at BLEEP.COM removed.
+kadmin:
+.TP
+ERRORS:
+KADM5_AUTH_SETKEY (reequires "setkey" privilege)
+KADM5_UNK_PRINC (principal does not exist)
+.RE
+.fi
+.TP
 \fBmodify_principal\fP [\fIoptions\fP] \fIprincipal\fP
 modifies the specified principal, changing the fields as specified.  The
 options are as above for
@@ -454,10 +480,12 @@
 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
-necessary except perhaps for TGS keys.  Don't use this flag unless you
-know what you're doing.
+Keeps the previous kvno's keys around.  This is usually not necessary
+unless you are rekeying a TGS principal.  After rekeying a TGS 
+principal, wait for a sufficient length of time such that all previously 
+issued credentials have expired, and then use the 
+.BR flush_old_keys
+command to remove the old keys.
 .nf
 .TP
 EXAMPLE:
@@ -789,9 +817,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.
diff -uNr krb5-1.4.3.orig/src/kadmin/server/kadm_rpc_svc.c krb5-1.4.3/src/kadmin/server/kadm_rpc_svc.c
--- krb5-1.4.3.orig/src/kadmin/server/kadm_rpc_svc.c	2004-06-15 23:11:54.000000000 -0400
+++ krb5-1.4.3/src/kadmin/server/kadm_rpc_svc.c	2006-04-25 09:43:57.000000000 -0400
@@ -60,6 +60,7 @@
 	  dpol_arg delete_policy_1_arg;
 	  mpol_arg modify_policy_1_arg;
 	  gpol_arg get_policy_1_arg;
+	  flushkeys_arg flushkeys_principal_1_arg;
 	  setkey_arg setkey_principal_1_arg;
 	  setv4key_arg setv4key_principal_1_arg;
 	  cprinc3_arg create_principal3_1_arg;
@@ -212,6 +213,12 @@
 	  local = (char *(*)()) setkey_principal3_1_svc;
 	  break;
 
+     case FLUSHKEYS_PRINCIPAL:
+	  xdr_argument = xdr_flushkeys_arg;
+	  xdr_result = xdr_generic_ret;
+	  local = (char *(*)()) flushkeys_principal_1_svc;
+	  break;
+
      default:
 	  krb5_klog_syslog(LOG_ERR, "Invalid KADM5 procedure number: %s, %d",
 		 inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr),
diff -uNr krb5-1.4.3.orig/src/kadmin/server/server_stubs.c krb5-1.4.3/src/kadmin/server/server_stubs.c
--- krb5-1.4.3.orig/src/kadmin/server/server_stubs.c	2004-08-20 14:45:30.000000000 -0400
+++ krb5-1.4.3/src/kadmin/server/server_stubs.c	2006-04-25 09:43:57.000000000 -0400
@@ -786,6 +786,67 @@
 }
 
 generic_ret *
+flushkeys_principal_1_svc(flushkeys_arg *arg, struct svc_req *rqstp)
+{
+    static generic_ret		    ret;
+    char			    *prime_arg;
+    gss_buffer_desc		    client_name,
+				    service_name;
+    OM_uint32			    minor_stat;
+    kadm5_server_handle_t	    handle;
+
+    xdr_free(xdr_generic_ret, &ret);
+
+    if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle)))
+	 return &ret;
+
+    if ((ret.code = check_handle((void *)handle))) {
+	 free_server_handle(handle);
+	 return &ret;
+    }
+
+    ret.api_version = handle->api_version;
+
+    if (setup_gss_names(rqstp, &client_name, &service_name) < 0) {
+	 ret.code = KADM5_FAILURE;
+	 return &ret;
+    }
+    if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) {
+	 ret.code = KADM5_BAD_PRINCIPAL;
+	 return &ret;
+    }
+
+    /*
+     * For now, use the same ACL and error codes as setkey; this seems 
+     * reasonable.
+     */
+    if (!(CHANGEPW_SERVICE(rqstp)) &&
+	       kadm5int_acl_check(handle->context, rqst2name(rqstp),
+			 ACL_SETKEY, arg->princ, NULL)) {
+	 ret.code = kadm5_flushkeys_principal((void *)handle, arg->princ);
+    } else {
+	 krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_flushkeys_principal",
+		prime_arg, client_name.value, service_name.value,
+		inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+	 ret.code = KADM5_AUTH_SETKEY;
+    }
+
+    if(ret.code != KADM5_AUTH_SETKEY) {
+	krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_flushkeys_principal", 
+	       prime_arg, ((ret.code == 0) ? "success" :
+			   error_message(ret.code)), 
+	       client_name.value, service_name.value,
+	       inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
+    }
+
+    free_server_handle(handle);
+    free(prime_arg);
+    gss_release_buffer(&minor_stat, &client_name);
+    gss_release_buffer(&minor_stat, &service_name);
+    return &ret;
+}
+
+generic_ret *
 setv4key_principal_1_svc(setv4key_arg *arg, struct svc_req *rqstp)
 {
     static generic_ret		    ret;
diff -uNr krb5-1.4.3.orig/src/lib/kadm5/admin.h krb5-1.4.3/src/lib/kadm5/admin.h
--- krb5-1.4.3.orig/src/lib/kadm5/admin.h	2005-03-22 18:53:59.000000000 -0500
+++ krb5-1.4.3/src/lib/kadm5/admin.h	2006-04-25 09:43:57.000000000 -0400
@@ -392,6 +392,8 @@
 					 krb5_keyblock **keyblocks,
 					 int *n_keys);
 #endif
+kadm5_ret_t    kadm5_flushkeys_principal(void *server_handle,
+					 krb5_principal principal);
 kadm5_ret_t    kadm5_setv4key_principal(void *server_handle,
 					krb5_principal principal,
 					krb5_keyblock *keyblock);
diff -uNr krb5-1.4.3.orig/src/lib/kadm5/admin_xdr.h krb5-1.4.3/src/lib/kadm5/admin_xdr.h
--- krb5-1.4.3.orig/src/lib/kadm5/admin_xdr.h	2001-07-25 15:02:29.000000000 -0400
+++ krb5-1.4.3/src/lib/kadm5/admin_xdr.h	2006-04-25 09:43:57.000000000 -0400
@@ -35,6 +35,7 @@
 bool_t	    xdr_rprinc_arg(XDR *xdrs, rprinc_arg *objp);
 bool_t	    xdr_chpass_arg(XDR *xdrs, chpass_arg *objp);
 bool_t      xdr_chpass3_arg(XDR *xdrs, chpass3_arg *objp);
+bool_t      xdr_flushkeys_arg(XDR *xdrs, flushkeys_arg *objp);
 bool_t      xdr_setv4key_arg(XDR *xdrs, setv4key_arg *objp);
 bool_t      xdr_setkey_arg(XDR *xdrs, setkey_arg *objp);
 bool_t      xdr_setkey3_arg(XDR *xdrs, setkey3_arg *objp);
diff -uNr krb5-1.4.3.orig/src/lib/kadm5/clnt/client_principal.c krb5-1.4.3/src/lib/kadm5/clnt/client_principal.c
--- krb5-1.4.3.orig/src/lib/kadm5/clnt/client_principal.c	2004-06-15 23:11:54.000000000 -0400
+++ krb5-1.4.3/src/lib/kadm5/clnt/client_principal.c	2006-04-25 11:19:23.000000000 -0400
@@ -356,6 +356,25 @@
 }
 
 kadm5_ret_t
+kadm5_flushkeys_principal(void *server_handle, krb5_principal principal)
+{
+    flushkeys_arg	arg;
+    generic_ret		*r;
+    kadm5_server_handle_t handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    if(principal == NULL)
+	return EINVAL;
+    arg.princ = principal;
+    arg.api_version = handle->api_version;
+    r = flushkeys_principal_1(&arg, handle->clnt);
+    if(r == NULL)
+	eret();        
+    return r->code;
+}
+
+kadm5_ret_t
 kadm5_setv4key_principal(void *server_handle,
 			 krb5_principal princ,
 			 krb5_keyblock *keyblock)
diff -uNr krb5-1.4.3.orig/src/lib/kadm5/clnt/client_rpc.c krb5-1.4.3/src/lib/kadm5/clnt/client_rpc.c
--- krb5-1.4.3.orig/src/lib/kadm5/clnt/client_rpc.c	2001-02-18 17:58:36.000000000 -0500
+++ krb5-1.4.3/src/lib/kadm5/clnt/client_rpc.c	2006-04-25 09:43:57.000000000 -0400
@@ -137,6 +137,20 @@
 }
 
 generic_ret *
+flushkeys_principal_1(argp, clnt)
+	flushkeys_arg *argp;
+	CLIENT *clnt;
+{
+	static generic_ret res;
+
+	memset((char *)&res, 0, sizeof(res));
+	if (clnt_call(clnt, FLUSHKEYS_PRINCIPAL, xdr_flushkeys_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&res);
+}
+
+generic_ret *
 setv4key_principal_1(argp, clnt)
 	setv4key_arg *argp;
 	CLIENT *clnt;
diff -uNr krb5-1.4.3.orig/src/lib/kadm5/clnt/libkadm5clnt.exports krb5-1.4.3/src/lib/kadm5/clnt/libkadm5clnt.exports
--- krb5-1.4.3.orig/src/lib/kadm5/clnt/libkadm5clnt.exports	2004-06-30 16:30:54.000000000 -0400
+++ krb5-1.4.3/src/lib/kadm5/clnt/libkadm5clnt.exports	2006-04-25 09:43:57.000000000 -0400
@@ -32,6 +32,7 @@
 kadm5_delete_principal
 kadm5_destroy
 kadm5_flush
+kadm5_flushkeys_principal
 kadm5_free_config_params
 kadm5_free_key_data
 kadm5_free_name_list
diff -uNr krb5-1.4.3.orig/src/lib/kadm5/kadm_rpc.h krb5-1.4.3/src/lib/kadm5/kadm_rpc.h
--- krb5-1.4.3.orig/src/lib/kadm5/kadm_rpc.h	2001-02-18 18:00:08.000000000 -0500
+++ krb5-1.4.3/src/lib/kadm5/kadm_rpc.h	2006-04-25 09:43:57.000000000 -0400
@@ -91,6 +91,13 @@
 typedef struct chpass3_arg chpass3_arg;
 bool_t xdr_chpass3_arg();
 
+struct flushkeys_arg {
+	krb5_ui_4 api_version;
+	krb5_principal princ;
+};
+typedef struct flushkeys_arg flushkeys_arg;
+bool_t xdr_flushkeys_arg();
+
 struct setv4key_arg {
 	krb5_ui_4 api_version;
 	krb5_principal princ;
@@ -332,4 +339,9 @@
 					    struct svc_req *rqstp);
 extern generic_ret *setkey_principal3_1(setkey3_arg *argp, CLIENT *clnt);
 
+#define FLUSHKEYS_PRINCIPAL ((krb5_ui_4) 22)
+extern generic_ret *flushkeys_principal_1_svc(flushkeys_arg *arg, 
+					      struct svc_req *rqstp);
+extern generic_ret *flushkeys_principal_1(flushkeys_arg *argp, CLIENT *clnt);
+
 #endif /* __KADM_RPC_H__ */
diff -uNr krb5-1.4.3.orig/src/lib/kadm5/kadm_rpc_xdr.c krb5-1.4.3/src/lib/kadm5/kadm_rpc_xdr.c
--- krb5-1.4.3.orig/src/lib/kadm5/kadm_rpc_xdr.c	2004-06-25 19:23:36.000000000 -0400
+++ krb5-1.4.3/src/lib/kadm5/kadm_rpc_xdr.c	2006-04-25 09:43:57.000000000 -0400
@@ -669,6 +669,18 @@
 }
 
 bool_t
+xdr_flushkeys_arg(XDR *xdrs, flushkeys_arg *objp)
+{
+	if (!xdr_ui_4(xdrs, &objp->api_version)) {
+		return (FALSE);
+	}
+	if (!xdr_krb5_principal(xdrs, &objp->princ)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
 xdr_setv4key_arg(XDR *xdrs, setv4key_arg *objp)
 {
 	unsigned int n_keys = 1;
diff -uNr krb5-1.4.3.orig/src/lib/kadm5/srv/libkadm5srv.exports krb5-1.4.3/src/lib/kadm5/srv/libkadm5srv.exports
--- krb5-1.4.3.orig/src/lib/kadm5/srv/libkadm5srv.exports	2004-08-21 12:59:47.000000000 -0400
+++ krb5-1.4.3/src/lib/kadm5/srv/libkadm5srv.exports	2006-04-25 09:43:57.000000000 -0400
@@ -31,6 +31,7 @@
 kadm5_delete_principal
 kadm5_destroy
 kadm5_flush
+kadm5_flushkeys_principal
 kadm5_free_config_params
 kadm5_free_key_data
 kadm5_free_name_list
@@ -143,6 +144,7 @@
 xdr_cprinc_arg
 xdr_dpol_arg
 xdr_dprinc_arg
+xdr_flushkeys_arg
 xdr_generic_ret
 xdr_getprivs_ret
 xdr_gpol_arg
diff -uNr krb5-1.4.3.orig/src/lib/kadm5/srv/svr_principal.c krb5-1.4.3/src/lib/kadm5/srv/svr_principal.c
--- krb5-1.4.3.orig/src/lib/kadm5/srv/svr_principal.c	2004-12-20 16:16:20.000000000 -0500
+++ krb5-1.4.3/src/lib/kadm5/srv/svr_principal.c	2006-04-25 11:24:50.000000000 -0400
@@ -102,6 +102,22 @@
      free(data);
 }
 
+/* This is in lib/kdb/kdb_cpw.c, but is static */
+static int get_key_data_kvno(context, count, data)
+    krb5_context	  context;
+    int			  count;
+    krb5_key_data	* data;
+{
+    int i, kvno;
+    /* Find last key version number */
+    for (kvno = i = 0; i < count; i++) {
+	if (kvno < data[i].key_data_kvno) {
+	    kvno = data[i].key_data_kvno;
+	}
+    }
+    return(kvno);
+}
+
 kadm5_ret_t
 kadm5_create_principal(void *server_handle,
 			    kadm5_principal_ent_t entry, long mask,
@@ -1521,6 +1537,89 @@
     return ret;
 }
 
+kadm5_ret_t
+kadm5_flushkeys_principal(void *server_handle, krb5_principal principal)
+
+{
+    krb5_db_entry		kdb;
+    osa_princ_ent_rec		adb;
+    krb5_key_data		*key_data;
+    int				key_data_count;
+    int				kvno, oldkeys = 0;
+    int				i, ret;
+    kadm5_server_handle_t	handle = server_handle;
+
+    CHECK_HANDLE(server_handle);
+
+    if (principal == NULL)
+	return EINVAL;
+    if (hist_princ && /* this will be NULL when initializing the databse */
+	((krb5_principal_compare(handle->context,
+				 principal, hist_princ)) == TRUE))
+	return KADM5_PROTECT_PRINCIPAL;
+
+    if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
+       return(ret);
+
+    /* First save the old keydata */
+    kvno = get_key_data_kvno(handle->context, kdb.n_key_data, kdb.key_data);
+    key_data_count = kdb.n_key_data;
+    key_data = kdb.key_data;
+
+    /* See if there are any old keys */
+    for (i = 0; i < key_data_count; i++) {
+	if (key_data[i].key_data_kvno != kvno) {
+	    oldkeys = 1;
+	    break;
+	}
+    }
+
+    /* do nothing if all keys have the same kvno */
+    if (!oldkeys) {
+	ret = KADM5_OK;
+	goto done;
+    }
+
+    /* otherwise remove the old keys */
+    kdb.key_data = NULL;
+    kdb.n_key_data = 0;
+
+    for (i = 0; i < key_data_count; i++) {
+	if (key_data[i].key_data_kvno == kvno) {
+	    if ((ret = krb5_dbe_create_key_data(handle->context, &kdb))) {
+		cleanup_key_data(handle->context, kdb.n_key_data, kdb.key_data);
+		break;
+	    }
+	    /* We should decrypt/re-encrypt the data to use the same mkvno*/
+	    kdb.key_data[kdb.n_key_data - 1] = key_data[i];
+	    memset(&key_data[i], 0, sizeof(krb5_key_data));
+	}
+    }
+
+    if (ret) {
+	goto done;
+    }
+
+    /* free old keys */
+    cleanup_key_data(handle->context, key_data_count, key_data);
+
+    /*
+     * We don't update any admin data for the principal such as:
+     * kdb.attributes (KRB5_KDB_REQUIRES_PWCHANGE), kdb.pw_expiration, 
+     * or the time of last password change.  This is because we haven't 
+     * "changed" the default keys (those with max kvno).
+     */
+
+    if ((ret = kdb_put_entry(handle, &kdb, &adb)))
+	goto done;
+
+    ret = KADM5_OK;
+done:
+    kdb_free_entry(handle, &kdb, &adb);
+
+    return ret;
+}
+
 /*
  * kadm5_setv4key_principal:
  *




More information about the krb5-bugs mailing list