@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
@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
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
.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 .
.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.
}
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;
+}
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, "?";
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),
{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;
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;
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__ */
{
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;
+}
}
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);
+}
kadm5_lock
kadm5_modify_policy
kadm5_modify_principal
+kadm5_purgekeys
kadm5_randkey_principal
kadm5_randkey_principal_3
kadm5_rename_principal
};
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
#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 ();
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__ */
return TRUE;
}
+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)
{
kadm5_modify_policy
kadm5_modify_policy_internal
kadm5_modify_principal
+kadm5_purgekeys
kadm5_randkey_principal
kadm5_randkey_principal_3
kadm5_rename_principal
xdr_nulltype
xdr_osa_princ_ent_rec
xdr_osa_pw_hist_ent
+xdr_purgekeys_arg
xdr_rprinc_arg
xdr_setkey3_arg
xdr_setkey_arg
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;
+}