.TP
\fBktadd\fP [\fB\-k\fP \fIkeytab\fP] [\fB\-q\fP] [\fB\-e\fP \fIkeysaltlist\fP]
.br
-[\fIprincipal\fP | \fB\-glob\fP \fIprinc-exp\fP] [\fI...\fP]
+[\fB\-norandkey\fP] [[\fIprincipal\fP | \fB\-glob\fP \fIprinc-exp\fP] [\fI...\fP]
.br
Adds a principal or all principals matching
.I princ-exp
-to a keytab, randomizing each principal's key in the process. Requires the
+to a keytab.
+It randomizes each principal's key in the process, to prevent a
+compromised admin account from reading out all of the keys from the
+database. However,
+.B kadmin.local
+has the
+.B \-norandkey
+option, which leaves the keys and their version numbers unchanged,
+similar to the Kerberos V4
+.B ext_srvtab
+command.
+That allows users to continue to use the passwords they know
+to login normally, while simultaneously allowing scripts
+to login to the same account using a keytab.
+There is no significant security risk added since
+.B kadmin.local
+must be run by root on the KDC anyway.
+.sp
+Requires the
.I inquire
and
.I changepw
static int quiet;
+#ifdef KADMIN_LOCAL
+static int norandkey;
+#endif
+
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 rem_usage()
argc--; argv++;
quiet = 0;
+#ifdef KADMIN_LOCAL
+ norandkey = 0;
+#endif
while (argc) {
if (strncmp(*argv, "-k", 2) == 0) {
argc--; argv++;
keytab_str = *argv;
} else if (strcmp(*argv, "-q") == 0) {
quiet++;
+#ifdef KADMIN_LOCAL
+ } else if (strcmp(*argv, "-norandkey") == 0) {
+ norandkey++;
+#endif
} else if (strcmp(*argv, "-e") == 0) {
argc--;
if (argc < 1) {
return;
}
+#ifdef KADMIN_LOCAL
+ if (norandkey && ks_tuple) {
+ fprintf(stderr, "cannot specify keysaltlist when not changing key\n");
+ return;
+ }
+#endif
+
if (process_keytab(context, &keytab_str, &keytab))
return;
goto cleanup;
}
+#ifdef KADMIN_LOCAL
+ if (norandkey)
+ code = kadm5_get_principal_keys(handle, princ, &keys, &nkeys);
+ else
+#endif
if (keepold || ks_tuple != NULL) {
code = kadm5_randkey_principal_3(lhandle, princ,
keepold, n_ks_tuple, ks_tuple,
krb5_error_code kadm5_init_krb5_context (krb5_context *);
+/*
+ * kadm5_get_principal_keys is used only by kadmin.local to extract existing
+ * keys from the database without changing them. It should never be exposed
+ * to the network protocol.
+ */
+kadm5_ret_t kadm5_get_principal_keys(void *server_handle,
+ krb5_principal principal,
+ krb5_keyblock **keyblocks,
+ int *n_keys);
+
#if USE_KADM5_API_VERSION == 1
/*
* OVSEC_KADM_API_VERSION_1 should be, if possible, compile-time
return ret;
}
+/*
+ * Return the list of keys like kadm5_randkey_principal,
+ * but don't modify the principal.
+ */
+kadm5_ret_t
+kadm5_get_principal_keys(void *server_handle /* IN */,
+ krb5_principal principal /* IN */,
+ krb5_keyblock **keyblocks /* OUT */,
+ int *n_keys /* OUT */)
+{
+ krb5_db_entry kdb;
+ osa_princ_ent_rec adb;
+ krb5_key_data *key_data;
+ kadm5_ret_t ret;
+ kadm5_server_handle_t handle = server_handle;
+
+ if (keyblocks)
+ *keyblocks = NULL;
+
+ CHECK_HANDLE(server_handle);
+
+ if (principal == NULL)
+ return EINVAL;
+
+ if ((ret = kdb_get_entry(handle, principal, &kdb, &adb)))
+ return(ret);
+
+ if (keyblocks) {
+ if (handle->api_version == KADM5_API_VERSION_1) {
+ /* Version 1 clients will expect to see a DES_CRC enctype. */
+ if ((ret = krb5_dbe_find_enctype(handle->context, &kdb,
+ ENCTYPE_DES_CBC_CRC,
+ -1, -1, &key_data)))
+ goto done;
+
+ if ((ret = decrypt_key_data(handle->context, 1, key_data,
+ keyblocks, NULL)))
+ goto done;
+ } else {
+ ret = decrypt_key_data(handle->context,
+ kdb.n_key_data, kdb.key_data,
+ keyblocks, n_keys);
+ if (ret)
+ goto done;
+ }
+ }
+
+ ret = KADM5_OK;
+done:
+ kdb_free_entry(handle, &kdb, &adb);
+
+ return ret;
+}
+
+
/*
* Allocate an array of n_key_data krb5_keyblocks, fill in each
* element with the results of decrypting the nth key in key_data with