Make principal renaming work in libkadm5srv by converting to explicit
authorGreg Hudson <ghudson@mit.edu>
Tue, 25 Jan 2011 05:20:07 +0000 (05:20 +0000)
committerGreg Hudson <ghudson@mit.edu>
Tue, 25 Jan 2011 05:20:07 +0000 (05:20 +0000)
salts as necessary.  Add a principal rename command to the client.
(The RPC infrastructure was already present.)

Adapted from patches submitted by mdw@umich.edu and lha@apple.com.

ticket: 6323

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

src/kadmin/cli/kadmin.c
src/kadmin/cli/kadmin.h
src/kadmin/cli/kadmin_ct.ct
src/lib/kadm5/srv/svr_principal.c
src/tests/Makefile.in
src/tests/t_renprinc.py [new file with mode: 0644]

index ecac1af4c6e2748b5bc815f666cc0260285cb8e3..38244bed93439014a25b344f68c9ac1fc2616e5d 100644 (file)
@@ -645,6 +645,69 @@ cleanup:
     free(canon);
 }
 
+void
+kadmin_renameprinc(int argc, char *argv[])
+{
+    kadm5_ret_t retval;
+    krb5_principal oprinc = NULL, nprinc = NULL;
+    char *ocanon = NULL, *ncanon = NULL;
+    char reply[5];
+
+    if (!(argc == 3 || (argc == 4 && !strcmp("-force", argv[1])))) {
+        fprintf(stderr, "usage: rename_principal [-force] old_principal "
+                "new_principal\n");
+        return;
+    }
+    retval = kadmin_parse_name(argv[argc - 2], &oprinc);
+    if (retval) {
+        com_err("rename_principal", retval,
+                "while parsing old principal name");
+        goto cleanup;
+    }
+    retval = kadmin_parse_name(argv[argc - 1], &nprinc);
+    if (retval) {
+        com_err("rename_principal", retval,
+                "while parsing new principal name");
+        goto cleanup;
+    }
+    retval = krb5_unparse_name(context, oprinc, &ocanon);
+    if (retval) {
+        com_err("rename_principal", retval,
+                "while canonicalizing old principal");
+        goto cleanup;
+    }
+    retval = krb5_unparse_name(context, nprinc, &ncanon);
+    if (retval) {
+        com_err("rename_principal", retval,
+                "while canonicalizing new principal");
+        goto cleanup;
+    }
+    if (argc == 3) {
+        printf("Are you sure you want to rename the principal \"%s\" "
+               "to \"%s\"? (yes/no): ", ocanon, ncanon);
+        fgets(reply, sizeof(reply), stdin);
+        if (strcmp("yes\n", reply)) {
+            fprintf(stderr, "Principal \"%s\" not renamed\n", ocanon);
+            goto cleanup;
+        }
+    }
+    retval = kadm5_rename_principal(handle, oprinc, nprinc);
+    if (retval) {
+        com_err("rename_principal", retval,
+                "while renaming principal \"%s\" to \"%s\"", ocanon, ncanon);
+        goto cleanup;
+    }
+    printf("Principal \"%s\" renamed to \"%s\".\n"
+           "Make sure that you have removed the old principal from all ACLs "
+           "before reusing.\n", ocanon, ncanon);
+
+cleanup:
+    krb5_free_principal(context, nprinc);
+    krb5_free_principal(context, oprinc);
+    free(ncanon);
+    free(ocanon);
+}
+
 static void
 cpw_usage(const char *str)
 {
index 66496687d778d04b4cae449a3a1f315c5a377254..92e5faa7b645772fc2196272af64e251fd3bf534 100644 (file)
@@ -37,6 +37,7 @@ extern int quit (void);
 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_renameprinc(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[]);
index 6228f95ad91dd00864848d2218214d24c038e831..86ac96e7083db1617740b5a21be862791c9dc305 100644 (file)
@@ -35,6 +35,9 @@ request kadmin_delprinc, "Delete principal",
 request kadmin_modprinc, "Modify principal",
        modify_principal, modprinc;
 
+request kadmin_renameprinc, "Rename principal",
+       rename_principal, renprinc;
+
 request kadmin_cpw, "Change password",
        change_password, cpw;
 
index 696362ac60ed42be499611e30320b511960c3a59..9abb4e6d6e2ae69845f5d22ebf041d849bdfe2c1 100644 (file)
@@ -4,21 +4,14 @@
  *
  * $Header$
  */
-#include <assert.h>
-#include        <sys/types.h>
+#include "k5-int.h"
 #include        <sys/time.h>
-#include        <errno.h>
 #include        <kadm5/admin.h>
 #include        <kdb.h>
-#include        <stdio.h>
-#include        <string.h>
 #include        "server_internal.h"
-#include        <stdarg.h>
-#include        <stdlib.h>
 #ifdef USE_PASSWORD_SERVER
 #include        <sys/wait.h>
 #include        <signal.h>
-
 #endif
 
 #include <krb5/kadm5_hook_plugin.h>
@@ -730,10 +723,12 @@ kadm5_ret_t
 kadm5_rename_principal(void *server_handle,
                        krb5_principal source, krb5_principal target)
 {
-    krb5_db_entry       *kdb;
-    osa_princ_ent_rec   adb;
-    int                 ret, i;
+    krb5_db_entry *kdb;
+    osa_princ_ent_rec adb;
+    int ret, i;
     kadm5_server_handle_t handle = server_handle;
+    krb5_int32 stype;
+    krb5_data sdata;
 
     CHECK_HANDLE(server_handle);
 
@@ -750,14 +745,53 @@ kadm5_rename_principal(void *server_handle,
     if ((ret = kdb_get_entry(handle, source, &kdb, &adb)))
         return ret;
 
-    /* this is kinda gross, but unavoidable */
+    /* Transform salts as necessary. */
+    for (i = 0; i < kdb->n_key_data; i++) {
+        sdata = empty_data();
+        if (kdb->key_data[i].key_data_ver > 1)
+            stype = kdb->key_data[i].key_data_type[1];
+        else
+            stype = KRB5_KDB_SALTTYPE_NORMAL;
 
-    for (i=0; i<kdb->n_key_data; i++) {
-        if ((kdb->key_data[i].key_data_ver == 1) ||
-            (kdb->key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) {
+        /* For salt types which compute a salt from the principal name, compute
+         * the salt based on the old principal name into sdata. */
+        switch (stype) {
+        case KRB5_KDB_SALTTYPE_NORMAL:
+            ret = krb5_principal2salt(handle->context, kdb->princ, &sdata);
+            if (ret)
+                goto done;
+            break;
+        case KRB5_KDB_SALTTYPE_NOREALM:
+            krb5_principal2salt_norealm(handle->context, kdb->princ, &sdata);
+            if (ret)
+                goto done;
+            break;
+        case KRB5_KDB_SALTTYPE_ONLYREALM:
+            ret = alloc_data(&sdata, kdb->princ->realm.length);
+            if (ret)
+                goto done;
+            memcpy(sdata.data, kdb->princ->realm.data,
+                   kdb->princ->realm.length);
+            break;
+        case KRB5_KDB_SALTTYPE_SPECIAL:
+        case KRB5_KDB_SALTTYPE_V4:
+        case KRB5_KDB_SALTTYPE_AFS3:
+            /* Don't compute a new salt.  Assume the realm doesn't change for
+             * V4 and AFS3. */
+            break;
+        default:
+            /* We don't recognize this salt type.  Be conservative. */
             ret = KADM5_NO_RENAME_SALT;
             goto done;
         }
+        /* If we computed a salt, store it as an explicit salt. */
+        if (sdata.data != NULL) {
+            kdb->key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL;
+            free(kdb->key_data[i].key_data_contents[1]);
+            kdb->key_data[i].key_data_contents[1] = (krb5_octet *)sdata.data;
+            kdb->key_data[i].key_data_length[1] = sdata.length;
+            kdb->key_data[i].key_data_ver = 2;
+        }
     }
 
     kadm5_free_principal(handle->context, kdb->princ);
index 964da6ee19021b68f192ccd5735b6a297ee0acae..987238cfbcf139961d8426eacb68489adba58f65 100644 (file)
@@ -67,6 +67,7 @@ check-pytests::
        $(RUNPYTEST) $(srcdir)/t_kadm5_hook.py $(PYTESTFLAGS)
        $(RUNPYTEST) $(srcdir)/t_keyrollover.py $(PYTESTFLAGS)
        $(RUNPYTEST) $(srcdir)/t_renew.py $(PYTESTFLAGS)
+       $(RUNPYTEST) $(srcdir)/t_renprinc.py $(PYTESTFLAGS)
 
 clean::
        $(RM) kdc.conf
diff --git a/src/tests/t_renprinc.py b/src/tests/t_renprinc.py
new file mode 100644 (file)
index 0000000..d4ad902
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright (C) 2011 by the Massachusetts Institute of Technology.
+# All rights reserved.
+
+# Export of this software from the United States of America may
+#   require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+#
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  Furthermore if you modify this software you must label
+# your software as modified software and not distribute it in such a
+# fashion that it might be confused with the original M.I.T. software.
+# M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+
+#!/usr/bin/python
+from k5test import *
+
+enctype = "aes128-cts"
+
+realm = K5Realm(create_host=False, create_user=False, start_kadmind=False)
+salttypes = ('normal', 'v4', 'norealm', 'onlyrealm')
+
+# For a variety of salt types, test that we can rename a principal and
+# still get tickets with the same password.
+for st in salttypes:
+    realm.run_kadminl('addprinc -e %s:%s -pw %s %s' %
+                      (enctype, st, password(st), st))
+    realm.kinit(st, password(st))
+    newprinc = 'new' + st
+    realm.run_kadminl('renprinc -force %s %s' % (st, newprinc))
+    realm.kinit(newprinc, password(st))
+
+# Rename the normal salt again to test renaming a principal with
+# special salt type (which it will have after the first rename).
+realm.run_kadminl('renprinc -force newnormal newnormal2')
+realm.kinit('newnormal2', password('normal'))
+
+success('Principal renaming tests.')