]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Add the ability to lock down principal keys
authorSimo Sorce <simo@redhat.com>
Fri, 18 Dec 2015 23:13:29 +0000 (18:13 -0500)
committerGreg Hudson <ghudson@mit.edu>
Fri, 19 Feb 2016 20:45:32 +0000 (15:45 -0500)
A new attribute named KRB5_KDC_LOCKDOWN_KEYS can be set on principals.
This flag prevents keys for the principal from being extracted or set
to a known value by the kadmin protocol.  Principals with this flag
cannot be deleted or renamed, and cannot have keys set by setkey or
chpass.  chrand operations are allowed, but keys are not returned.
This attribute can be set via the modify operation but cannot be
reset; an authorization error is resturned if an attempt to reset it
is performed.

When creating a KDB, set the lockdown flag on the krbtgt and kadmin
principals.

[ghudson@mit.edu: squash with t_kadmin_acl.py commit; condense commit
message]

ticket: 8365 (new)

src/include/kdb.h
src/kadmin/cli/kadmin.c
src/kadmin/dbutil/kadm5_create.c
src/kadmin/dbutil/kdb5_create.c
src/kadmin/server/server_stubs.c
src/lib/kadm5/kadm_err.et
src/lib/kadm5/str_conv.c
src/tests/dejagnu/krb-standalone/kadmin.exp
src/tests/t_kadmin_acl.py
src/util/princflags.py

index 71546afec46665cd334a51d55b8efa13dd74c342..0a9ddbdb9339209bf004d8cc13a9363ff3a9c7b8 100644 (file)
@@ -98,6 +98,7 @@
 #define KRB5_KDB_OK_AS_DELEGATE         0x00100000
 #define KRB5_KDB_OK_TO_AUTH_AS_DELEGATE 0x00200000 /* S4U2Self OK */
 #define KRB5_KDB_NO_AUTH_DATA_REQUIRED  0x00400000
+#define KRB5_KDB_LOCKDOWN_KEYS          0x00800000
 
 /* Creation flags */
 #define KRB5_KDB_CREATE_BTREE           0x00000001
index c9cc0b050380fb4299a066ae56fecaea644196b0..41f172eb4bc836ca949dbd9ec686189feeb1914f 100644 (file)
@@ -1105,6 +1105,7 @@ kadmin_addprinc_usage()
             "\t\trequires_hwauth needchange allow_svr "
             "password_changing_service\n"
             "\t\tok_as_delegate ok_to_auth_as_delegate no_auth_data_required\n"
+            "\t\tlockdown_keys\n"
             "\nwhere,\n\t[-x db_princ_args]* - any number of database "
             "specific arguments.\n"
             "\t\t\tLook at each database documentation for supported "
@@ -1127,6 +1128,7 @@ kadmin_modprinc_usage()
             "\t\trequires_hwauth needchange allow_svr "
             "password_changing_service\n"
             "\t\tok_as_delegate ok_to_auth_as_delegate no_auth_data_required\n"
+            "\t\tlockdown_keys\n"
             "\nwhere,\n\t[-x db_princ_args]* - any number of database "
             "specific arguments.\n"
             "\t\t\tLook at each database documentation for supported "
index 159a419263a20084eb2444c5297d2d17e77a35ed..121305006359984c04926b052b105aad0ef6a179 100644 (file)
@@ -201,20 +201,23 @@ static int add_admin_princs(void *handle, krb5_context context, char *realm)
 
     if ((ret = add_admin_princ(handle, context,
                                service_name, realm,
-                               KRB5_KDB_DISALLOW_TGT_BASED,
+                               KRB5_KDB_DISALLOW_TGT_BASED |
+                               KRB5_KDB_LOCKDOWN_KEYS,
                                ADMIN_LIFETIME)))
         goto clean_and_exit;
 
     if ((ret = add_admin_princ(handle, context,
                                KADM5_ADMIN_SERVICE, realm,
-                               KRB5_KDB_DISALLOW_TGT_BASED,
+                               KRB5_KDB_DISALLOW_TGT_BASED |
+                               KRB5_KDB_LOCKDOWN_KEYS,
                                ADMIN_LIFETIME)))
         goto clean_and_exit;
 
     if ((ret = add_admin_princ(handle, context,
                                KADM5_CHANGEPW_SERVICE, realm,
                                KRB5_KDB_DISALLOW_TGT_BASED |
-                               KRB5_KDB_PWCHANGE_SERVICE,
+                               KRB5_KDB_PWCHANGE_SERVICE |
+                               KRB5_KDB_LOCKDOWN_KEYS,
                                CHANGEPW_LIFETIME)))
         goto clean_and_exit;
 
index 3698d57193c5f974266095793917e8dccd606c2f..74e506a56d412ddd3cb461dc0e0473953e5a8a76 100644 (file)
@@ -500,6 +500,7 @@ add_principal(context, princ, op, pblock)
     entry->mask = (KADM5_KEY_DATA | KADM5_PRINCIPAL | KADM5_ATTRIBUTES |
                    KADM5_MAX_LIFE | KADM5_MAX_RLIFE | KADM5_TL_DATA |
                    KADM5_PRINC_EXPIRE_TIME);
+    entry->attributes |= KRB5_KDB_LOCKDOWN_KEYS;
 
     retval = krb5_db_put_principal(context, entry);
 
index 1126b7b41defe9563f46c46265e1afb000611842..8d44fff8eced5b39f31e7233bfadc67efdb6678d 100644 (file)
@@ -454,6 +454,21 @@ exit_func:
     return &ret;
 }
 
+/* Return KADM5_PROTECT_KEYS if KRB5_KDB_LOCKDOWN_KEYS is set for princ. */
+static kadm5_ret_t
+check_lockdown_keys(kadm5_server_handle_t handle, krb5_principal princ)
+{
+    kadm5_principal_ent_rec rec;
+    kadm5_ret_t ret;
+
+    ret = kadm5_get_principal(handle, princ, &rec, KADM5_ATTRIBUTES);
+    if (ret)
+        return ret;
+    ret = (rec.attributes & KRB5_KDB_LOCKDOWN_KEYS) ? KADM5_PROTECT_KEYS : 0;
+    kadm5_free_principal_ent(handle, &rec);
+    return ret;
+}
+
 generic_ret *
 delete_principal_2_svc(dprinc_arg *arg, struct svc_req *rqstp)
 {
@@ -491,7 +506,17 @@ delete_principal_2_svc(dprinc_arg *arg, struct svc_req *rqstp)
         log_unauth("kadm5_delete_principal", prime_arg,
                    &client_name, &service_name, rqstp);
     } else {
+        ret.code = check_lockdown_keys(handle, arg->princ);
+        if (ret.code == KADM5_PROTECT_KEYS) {
+            log_unauth("kadm5_delete_principal", prime_arg, &client_name,
+                       &service_name, rqstp);
+            ret.code = KADM5_AUTH_DELETE;
+        }
+    }
+
+    if (ret.code == KADM5_OK)
         ret.code = kadm5_delete_principal((void *)handle, arg->princ);
+    if (ret.code != KADM5_AUTH_DELETE) {
         if( ret.code != 0 )
             errmsg = krb5_get_error_message(handle->context, ret.code);
 
@@ -548,7 +573,17 @@ modify_principal_2_svc(mprinc_arg *arg, struct svc_req *rqstp)
         ret.code = KADM5_AUTH_MODIFY;
         log_unauth("kadm5_modify_principal", prime_arg,
                    &client_name, &service_name, rqstp);
-    } else {
+    } else if ((arg->mask & KADM5_ATTRIBUTES) &&
+               (!(arg->rec.attributes & KRB5_KDB_LOCKDOWN_KEYS))) {
+        ret.code = check_lockdown_keys(handle, arg->rec.principal);
+        if (ret.code == KADM5_PROTECT_KEYS) {
+            log_unauth("kadm5_modify_principal", prime_arg, &client_name,
+                       &service_name, rqstp);
+            ret.code = KADM5_AUTH_MODIFY;
+        }
+    }
+
+    if (ret.code == KADM5_OK) {
         ret.code = kadm5_modify_principal((void *)handle, &arg->rec,
                                           arg->mask);
         if( ret.code != 0 )
@@ -621,6 +656,14 @@ rename_principal_2_svc(rprinc_arg *arg, struct svc_req *rqstp)
             else
                 ret.code = KADM5_AUTH_ADD;
         }
+        if (ret.code == KADM5_OK) {
+            ret.code = check_lockdown_keys(handle, arg->src);
+            if (ret.code == KADM5_PROTECT_KEYS) {
+                log_unauth("kadm5_rename_principal", prime_arg1, &client_name,
+                           &service_name, rqstp);
+                ret.code = KADM5_AUTH_DELETE;
+            }
+        }
     } else
         ret.code = KADM5_AUTH_INSUFFICIENT;
     if (ret.code != KADM5_OK) {
@@ -815,7 +858,14 @@ chpass_principal_2_svc(chpass_arg *arg, struct svc_req *rqstp)
         goto exit_func;
     }
 
-    if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
+    ret.code = check_lockdown_keys(handle, arg->princ);
+    if (ret.code != KADM5_OK) {
+        if (ret.code == KADM5_PROTECT_KEYS) {
+            log_unauth("kadm5_chpass_principal", prime_arg, &client_name,
+                       &service_name, rqstp);
+            ret.code = KADM5_AUTH_CHANGEPW;
+        }
+    } else if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
         ret.code = chpass_principal_wrapper_3((void *)handle, arg->princ,
                                               FALSE, 0, NULL, arg->pass);
     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
@@ -878,7 +928,14 @@ chpass_principal3_2_svc(chpass3_arg *arg, struct svc_req *rqstp)
         goto exit_func;
     }
 
-    if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
+    ret.code = check_lockdown_keys(handle, arg->princ);
+    if (ret.code != KADM5_OK) {
+        if (ret.code == KADM5_PROTECT_KEYS) {
+            log_unauth("kadm5_chpass_principal", prime_arg, &client_name,
+                       &service_name, rqstp);
+            ret.code = KADM5_AUTH_CHANGEPW;
+        }
+    } else if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
         ret.code = chpass_principal_wrapper_3((void *)handle, arg->princ,
                                               arg->keepold,
                                               arg->n_ks_tuple,
@@ -947,7 +1004,14 @@ setv4key_principal_2_svc(setv4key_arg *arg, struct svc_req *rqstp)
         goto exit_func;
     }
 
-    if (!(CHANGEPW_SERVICE(rqstp)) &&
+    ret.code = check_lockdown_keys(handle, arg->princ);
+    if (ret.code != KADM5_OK) {
+        if (ret.code == KADM5_PROTECT_KEYS) {
+            log_unauth("kadm5_setv4key_principal", prime_arg, &client_name,
+                       &service_name, rqstp);
+            ret.code = KADM5_AUTH_SETKEY;
+        }
+    } else if (!(CHANGEPW_SERVICE(rqstp)) &&
         kadm5int_acl_check(handle->context, rqst2name(rqstp),
                            ACL_SETKEY, arg->princ, NULL)) {
         ret.code = kadm5_setv4key_principal((void *)handle, arg->princ,
@@ -1007,7 +1071,14 @@ setkey_principal_2_svc(setkey_arg *arg, struct svc_req *rqstp)
         goto exit_func;
     }
 
-    if (!(CHANGEPW_SERVICE(rqstp)) &&
+    ret.code = check_lockdown_keys(handle, arg->princ);
+    if (ret.code != KADM5_OK) {
+        if (ret.code == KADM5_PROTECT_KEYS) {
+            log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
+                       &service_name, rqstp);
+            ret.code = KADM5_AUTH_SETKEY;
+        }
+    } else if (!(CHANGEPW_SERVICE(rqstp)) &&
         kadm5int_acl_check(handle->context, rqst2name(rqstp),
                            ACL_SETKEY, arg->princ, NULL)) {
         ret.code = kadm5_setkey_principal((void *)handle, arg->princ,
@@ -1067,7 +1138,14 @@ setkey_principal3_2_svc(setkey3_arg *arg, struct svc_req *rqstp)
         goto exit_func;
     }
 
-    if (!(CHANGEPW_SERVICE(rqstp)) &&
+    ret.code = check_lockdown_keys(handle, arg->princ);
+    if (ret.code != KADM5_OK) {
+        if (ret.code == KADM5_PROTECT_KEYS) {
+            log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
+                       &service_name, rqstp);
+            ret.code = KADM5_AUTH_SETKEY;
+        }
+    } else if (!(CHANGEPW_SERVICE(rqstp)) &&
         kadm5int_acl_check(handle->context, rqst2name(rqstp),
                            ACL_SETKEY, arg->princ, NULL)) {
         ret.code = kadm5_setkey_principal_3((void *)handle, arg->princ,
@@ -1130,7 +1208,14 @@ setkey_principal4_2_svc(setkey4_arg *arg, struct svc_req *rqstp)
         goto exit_func;
     }
 
-    if (!(CHANGEPW_SERVICE(rqstp)) &&
+    ret.code = check_lockdown_keys(handle, arg->princ);
+    if (ret.code != KADM5_OK) {
+        if (ret.code == KADM5_PROTECT_KEYS) {
+            log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
+                       &service_name, rqstp);
+            ret.code = KADM5_AUTH_SETKEY;
+        }
+    } else if (!(CHANGEPW_SERVICE(rqstp)) &&
         kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_SETKEY,
                            arg->princ, NULL)) {
         ret.code = kadm5_setkey_principal_4((void *)handle, arg->princ,
@@ -1161,6 +1246,27 @@ exit_func:
     return &ret;
 }
 
+/* Empty out *keys/*nkeys if princ is protected with the lockdown attribute, or
+ * if we fail to check. */
+static kadm5_ret_t
+chrand_check_lockdown(kadm5_server_handle_t handle, krb5_principal princ,
+                      krb5_keyblock **keys, int *nkeys)
+{
+    kadm5_ret_t ret;
+    int i;
+
+    ret = check_lockdown_keys(handle, princ);
+    if (!ret)
+        return 0;
+
+    for (i = 0; i < *nkeys; i++)
+        krb5_free_keyblock_contents(handle->context, &((*keys)[i]));
+    free(*keys);
+    *keys = NULL;
+    *nkeys = 0;
+    return (ret == KADM5_PROTECT_KEYS) ? KADM5_OK : ret;
+}
+
 chrand_ret *
 chrand_principal_2_svc(chrand_arg *arg, struct svc_req *rqstp)
 {
@@ -1211,6 +1317,7 @@ chrand_principal_2_svc(chrand_arg *arg, struct svc_req *rqstp)
     }
 
     if(ret.code == KADM5_OK) {
+        ret.code = chrand_check_lockdown(handle, arg->princ, &k, &nkeys);
         ret.keys = k;
         ret.n_keys = nkeys;
     }
@@ -1288,6 +1395,7 @@ chrand_principal3_2_svc(chrand3_arg *arg, struct svc_req *rqstp)
     }
 
     if(ret.code == KADM5_OK) {
+        ret.code = chrand_check_lockdown(handle, arg->princ, &k, &nkeys);
         ret.keys = k;
         ret.n_keys = nkeys;
     }
@@ -1920,6 +2028,21 @@ get_principal_keys_2_svc(getpkeys_arg *arg, struct svc_req *rqstp)
         ret.code = KADM5_AUTH_EXTRACT;
     }
 
+    if (ret.code == KADM5_OK) {
+        ret.code = check_lockdown_keys(handle, arg->princ);
+        if (ret.code != KADM5_OK) {
+            kadm5_free_kadm5_key_data(handle->context, ret.n_key_data,
+                                      ret.key_data);
+            ret.key_data = NULL;
+            ret.n_key_data = 0;
+        }
+        if (ret.code == KADM5_PROTECT_KEYS) {
+            log_unauth("kadm5_get_principal_keys", prime_arg,
+                       &client_name, &service_name, rqstp);
+            ret.code = KADM5_AUTH_EXTRACT;
+        }
+    }
+
     if (ret.code != KADM5_AUTH_EXTRACT) {
         if (ret.code != 0)
             errmsg = krb5_get_error_message(handle->context, ret.code);
index 56a4e27e6e3b8e7d1a1edf298ac29fb53685e787..71b053460117beda88c5c54d5a367b9637d25ef6 100644 (file)
@@ -65,4 +65,5 @@ error_code KADM5_PASS_Q_GENERIC, "Unspecified password quality failure"
 error_code KADM5_BAD_KEYSALTS, "Invalid key/salt tuples"
 error_code KADM5_SETKEY_BAD_KVNO, "Invalid multiple or duplicate kvnos in setkey operation"
 error_code KADM5_AUTH_EXTRACT, "Operation requires ``extract-keys'' privilege"
+error_code KADM5_PROTECT_KEYS, "Principal keys are locked down"
 end
index 0441a17682aff6f55c4a24b40ffe6688e30c4b0e..7cf51d3168e10a2a81c135df8deac5411b95f6d7 100644 (file)
@@ -90,6 +90,7 @@ static const struct flag_table_row ftbl[] = {
     {"ok_as_delegate",          KRB5_KDB_OK_AS_DELEGATE,        0},
     {"ok_to_auth_as_delegate",  KRB5_KDB_OK_TO_AUTH_AS_DELEGATE, 0},
     {"no_auth_data_required",   KRB5_KDB_NO_AUTH_DATA_REQUIRED, 0},
+    {"lockdown_keys",           KRB5_KDB_LOCKDOWN_KEYS,         0},
 };
 #define NFTBL (sizeof(ftbl) / sizeof(ftbl[0]))
 
@@ -117,6 +118,7 @@ static const char *outflags[] = {
     "OK_AS_DELEGATE",           /* 0x00100000 */
     "OK_TO_AUTH_AS_DELEGATE",   /* 0x00200000 */
     "NO_AUTH_DATA_REQUIRED",    /* 0x00400000 */
+    "LOCKDOWN_KEYS",            /* 0x00800000 */
 };
 #define NOUTFLAGS (sizeof(outflags) / sizeof(outflags[0]))
 
index c62e183e75a408baf1d00b51c2e93960912fcb33..33fc34a7bb08929975399d1fc42f769aa9c98fd9 100644 (file)
@@ -599,6 +599,100 @@ proc kadmin_delete { pname } {
     }
 }
 
+#++
+# kadmin_delete        - Test delete principal function of kadmin.
+#
+# Deletes principal $pname.  Returns 1 on success.
+#--
+proc kadmin_delete_locked_down { pname } {
+    global REALMNAME
+    global KADMIN
+    global KADMIN_LOCAL
+    global KEY
+    global spawn_id
+    global tmppwd
+
+    #
+    # First test that we fail, then unlock and retry
+    #
+
+    set good 0
+    spawn $KADMIN -p krbtest/admin@$REALMNAME -q "delprinc -force $pname"
+    expect_after {
+       "Cannot contact any KDC" {
+           fail "kadmin_delete $pname lost KDC"
+           catch "expect_after"
+           return 0
+       }
+       timeout {
+           fail "kadmin delprinc $pname"
+           catch "expect_after"
+           return 0
+       }
+       eof {
+           fail "kadmin delprinc $pname"
+           catch "expect_after"
+           return 0
+       }
+    }
+    expect -re "assword\[^\r\n\]*: *" {
+       send "adminpass$KEY\r"
+    }
+    expect "delete_principal: Operation requires ``delete'' privilege while deleting principal \"$pname@$REALMNAME\"" { set good 1 }
+    expect_after
+    expect eof
+    set k_stat [wait -i $spawn_id]
+    verbose "wait -i $spawn_id returned $k_stat (kadmin delprinc)"
+    catch "close -i $spawn_id"
+    if { $good == 1 } {
+       #
+       # use kadmin.local to remove lockdown.
+       #
+       envstack_push
+       setup_kerberos_env kdc
+       spawn $KADMIN_LOCAL -r $REALMNAME
+       envstack_pop
+       expect_after {
+           -i $spawn_id
+           timeout {
+               fail "kadmin delprinc $pname"
+               catch "expect_after"
+               return 0
+           }
+           eof {
+               fail "kadmin delprinc $pname"
+               catch "expect_after"
+               return 0
+           }
+       }
+       set good 0
+       expect "kadmin.local: " { send "modprinc -lockdown_keys $pname\r" }
+       expect "Principal \"$pname@$REALMNAME\" modified." { set good 1 }
+       expect "kadmin.local: " { send "quit\r" }
+       expect_after
+       expect eof
+       set k_stat [wait -i $spawn_id]
+       verbose "wait -i $spawn_id returned $k_stat (kadmin.local show)"
+       catch "close -i $spawn_id"
+       if { $good == 1 } {
+            set good 0
+            if {[kadmin_delete $pname]} { set good 1 }
+        }
+       if { $good == 1 } {
+           pass "kadmin delprinc $pname"
+           return 1
+       }
+       else {
+           fail "kadmin delprinc $pname"
+           return 0
+       }
+    }
+    else {
+       fail "kadmin delprinc $pname"
+       return 0
+    }
+}
+
 #++
 # kpasswd_cpw  - Test password changing using kpasswd.
 #
@@ -1051,7 +1145,7 @@ proc kadmin_test { } {
     }
 
     # test fallback to kadmin/admin
-    if {![kadmin_delete kadmin/$hostname] \
+    if {![kadmin_delete_locked_down kadmin/$hostname] \
            || ![kadmin_list] \
            || ![kadmin_add_rnd kadmin/$hostname -allow_tgs_req] \
            || ![kadmin_list]} {
index 6f5c58981357e142a00aa765697a418a47731051..188929a76c91147fb96131516f96482f538bed54 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/python
 from k5test import *
+import os
 
 realm = K5Realm(create_host=False, create_user=False)
 
@@ -23,6 +24,8 @@ all_inquire = make_client('all_inquire')
 all_list = make_client('all_list')
 all_modify = make_client('all_modify')
 all_rename = make_client('all_rename')
+all_wildcard = make_client('all_wildcard')
+all_extract = make_client('all_extract')
 some_add = make_client('some_add')
 some_changepw = make_client('some_changepw')
 some_delete = make_client('some_delete')
@@ -49,6 +52,8 @@ all_inquire        i
 all_list           l
 all_modify         im
 all_rename         ad
+all_wildcard       x
+all_extract        ie
 some_add           a   selected
 some_changepw      c   selected
 some_delete        d   selected
@@ -318,4 +323,39 @@ out = realm.run([kadminl, 'getprinc', 'type3'])
 if 'Maximum renewable life: 0 days 02:00:00' not in out:
     fail('restriction (maxrenewlife high)')
 
+realm.run([kadminl, 'addprinc', '-pw', 'pw', 'extractkeys'])
+out = kadmin_as(all_wildcard, ['ktadd', '-norandkey', 'extractkeys'],
+                expected_code=1)
+if 'Operation requires ``extract-keys\'\' privilege' not in out:
+    fail('extractkeys failure (all_wildcard)')
+kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys'])
+realm.kinit('extractkeys', flags=['-k'])
+os.remove(realm.keytab)
+
+kadmin_as(all_modify, ['modprinc', '+lockdown_keys', 'extractkeys'])
+out = kadmin_as(all_changepw, ['cpw', '-pw', 'newpw', 'extractkeys'],
+                expected_code=1)
+if 'Operation requires ``change-password\'\' privilege' not in out:
+    fail('extractkeys failure (all_changepw)')
+kadmin_as(all_changepw, ['cpw', '-randkey', 'extractkeys'])
+out = kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys'],
+                expected_code=1)
+if 'Operation requires ``extract-keys\'\' privilege' not in out:
+    fail('extractkeys failure (all_extract)')
+out = kadmin_as(all_delete, ['delprinc', 'extractkeys'], expected_code=1)
+if 'Operation requires ``delete\'\' privilege' not in out:
+    fail('extractkeys failure (all_delete)')
+out = kadmin_as(all_rename, ['renprinc', 'extractkeys', 'renamedprinc'],
+                expected_code=1)
+if 'Operation requires ``delete\'\' privilege' not in out:
+    fail('extractkeys failure (all_rename)')
+out = kadmin_as(all_modify, ['modprinc', '-lockdown_keys', 'extractkeys'],
+                expected_code=1)
+if 'Operation requires ``modify\'\' privilege' not in out:
+    fail('extractkeys failure (all_modify)')
+realm.run([kadminl, 'modprinc', '-lockdown_keys', 'extractkeys'])
+kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys'])
+realm.kinit('extractkeys', flags=['-k'])
+os.remove(realm.keytab)
+
 success('kadmin ACL enforcement')
index 16485c5e3b850d16b9d0b90c98d8d1be876fdc00..f568dd2f1dd1f23ef29787faea1ab6d38db0f454 100644 (file)
@@ -26,6 +26,7 @@ KRB5_KDB_NEW_PRINC              = 0x00008000
 KRB5_KDB_OK_AS_DELEGATE         = 0x00100000
 KRB5_KDB_OK_TO_AUTH_AS_DELEGATE = 0x00200000
 KRB5_KDB_NO_AUTH_DATA_REQUIRED  = 0x00400000
+KRB5_KDB_LOCKDOWN_KEYS          = 0x00800000
 
 # Input tables -- list of tuples of the form (name, flag, invert)
 
@@ -47,6 +48,7 @@ _kadmin_pflags = [
     ("ok_as_delegate",          KRB5_KDB_OK_AS_DELEGATE,        False),
     ("ok_to_auth_as_delegate",  KRB5_KDB_OK_TO_AUTH_AS_DELEGATE, False),
     ("no_auth_data_required",   KRB5_KDB_NO_AUTH_DATA_REQUIRED, False),
+    ("lockdown_keys",           KRB5_KDB_LOCKDOWN_KEYS,         False),
 ]
 
 # Input forms from lib/kadm5/str_conv.c
@@ -67,6 +69,7 @@ _strconv_pflags = [
     ("md5",                     KRB5_KDB_SUPPORT_DESMD5,        False),
     ("ok-to-auth-as-delegate",  KRB5_KDB_OK_TO_AUTH_AS_DELEGATE, False),
     ("no-auth-data-required",   KRB5_KDB_NO_AUTH_DATA_REQUIRED, False),
+    ("lockdown-keys",           KRB5_KDB_LOCKDOWN_KEYS,         False),
 ]
 
 # kdb.h symbol prefix