Add support for extracting existing keys from the KDC with kadmin.local.
authorRuss Allbery <rra@stanford.edu>
Mon, 16 Apr 2007 21:35:01 +0000 (21:35 +0000)
committerRuss Allbery <rra@stanford.edu>
Mon, 16 Apr 2007 21:35:01 +0000 (21:35 +0000)
Adds a -norandkey option to the ktadd command only in kadmin.local, and
adds a new function to the libkadm5srv library that kadmin.local can
call.  There is no protocol or network access to this function.

Ticket: 914

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@19474 dc483132-0cff-0310-8789-dd5450dbe970

src/kadmin/cli/kadmin.M
src/kadmin/cli/keytab.c
src/lib/kadm5/admin.h
src/lib/kadm5/srv/svr_principal.c

index 20958e88e6b73608bd669e36b816fa5b11d291f5..7739bbbbe35e3c8f534e1ebe03cf6dd1008bc3c8 100644 (file)
@@ -749,11 +749,29 @@ kadmin:
 .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
index d0fca77d5a46bf6d01f47174de27d712a5a923ce..297b7994ea8b9494d1610c1909cf3f025b310217 100644 (file)
@@ -55,9 +55,17 @@ static char *etype_string(krb5_enctype enctype);
 
 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()
@@ -126,6 +134,9 @@ void kadmin_keytab_add(int argc, char **argv)
 
      argc--; argv++;
      quiet = 0;
+#ifdef KADMIN_LOCAL
+     norandkey = 0;
+#endif
      while (argc) {
          if (strncmp(*argv, "-k", 2) == 0) {
               argc--; argv++;
@@ -136,6 +147,10 @@ void kadmin_keytab_add(int argc, char **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) {
@@ -160,6 +175,13 @@ void kadmin_keytab_add(int argc, char **argv)
          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;
      
@@ -261,6 +283,11 @@ int add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab,
          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,
index 99d18d4e295d1c9bcc49a59ca68196b127652090..adbd6c8cd02e445b5dedb704c149f9cd8faad0ca 100644 (file)
@@ -494,6 +494,16 @@ kadm5_ret_t    kadm5_free_name_list(void *server_handle, char **names,
 
 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
index 0a66a063151263272629433f3a314a823130d052..a7636e770b4271b8882b71d516578b82fdd62170 100644 (file)
@@ -1995,6 +1995,61 @@ done:
     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