From: Simo Sorce Date: Fri, 18 Dec 2015 23:13:29 +0000 (-0500) Subject: Add the ability to lock down principal keys X-Git-Tag: krb5-1.15-beta1~260 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=534db9834d6a77dc5e948e12844e72ba4e971e8c;p=thirdparty%2Fkrb5.git Add the ability to lock down principal keys 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) --- diff --git a/src/include/kdb.h b/src/include/kdb.h index 71546afec4..0a9ddbdb93 100644 --- a/src/include/kdb.h +++ b/src/include/kdb.h @@ -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 diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c index c9cc0b0503..41f172eb4b 100644 --- a/src/kadmin/cli/kadmin.c +++ b/src/kadmin/cli/kadmin.c @@ -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 " diff --git a/src/kadmin/dbutil/kadm5_create.c b/src/kadmin/dbutil/kadm5_create.c index 159a419263..1213050063 100644 --- a/src/kadmin/dbutil/kadm5_create.c +++ b/src/kadmin/dbutil/kadm5_create.c @@ -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; diff --git a/src/kadmin/dbutil/kdb5_create.c b/src/kadmin/dbutil/kdb5_create.c index 3698d57193..74e506a56d 100644 --- a/src/kadmin/dbutil/kdb5_create.c +++ b/src/kadmin/dbutil/kdb5_create.c @@ -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); diff --git a/src/kadmin/server/server_stubs.c b/src/kadmin/server/server_stubs.c index 1126b7b41d..8d44fff8ec 100644 --- a/src/kadmin/server/server_stubs.c +++ b/src/kadmin/server/server_stubs.c @@ -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); diff --git a/src/lib/kadm5/kadm_err.et b/src/lib/kadm5/kadm_err.et index 56a4e27e6e..71b0534601 100644 --- a/src/lib/kadm5/kadm_err.et +++ b/src/lib/kadm5/kadm_err.et @@ -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 diff --git a/src/lib/kadm5/str_conv.c b/src/lib/kadm5/str_conv.c index 0441a17682..7cf51d3168 100644 --- a/src/lib/kadm5/str_conv.c +++ b/src/lib/kadm5/str_conv.c @@ -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])) diff --git a/src/tests/dejagnu/krb-standalone/kadmin.exp b/src/tests/dejagnu/krb-standalone/kadmin.exp index c62e183e75..33fc34a7bb 100644 --- a/src/tests/dejagnu/krb-standalone/kadmin.exp +++ b/src/tests/dejagnu/krb-standalone/kadmin.exp @@ -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]} { diff --git a/src/tests/t_kadmin_acl.py b/src/tests/t_kadmin_acl.py index 6f5c589813..188929a76c 100755 --- a/src/tests/t_kadmin_acl.py +++ b/src/tests/t_kadmin_acl.py @@ -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') diff --git a/src/util/princflags.py b/src/util/princflags.py index 16485c5e3b..f568dd2f1d 100644 --- a/src/util/princflags.py +++ b/src/util/princflags.py @@ -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