svn rev #24424: trunk/src/ include/ kadmin/cli/ lib/kdb/ plugins/kdb/db2/ plugins/kdb/ldap/libkdb_ldap/ ...
ghudson@MIT.EDU
ghudson at MIT.EDU
Tue Oct 5 10:53:09 EDT 2010
http://src.mit.edu/fisheye/changelog/krb5/?cs=24424
Commit By: ghudson
Log Message:
ticket: 6795
subject: Propagate modprinc -unlock from master to slave KDCs
Create a new tl-data type to hold the time of the last administrative
unlock, and factor it into decisions about account lockout. Since
tl-data values are propagated from master to slave, this will cause
modprinc -unlock operations to reach slave KDCs on the next
propagation.
Changed Files:
U trunk/src/include/kdb.h
U trunk/src/kadmin/cli/kadmin.c
U trunk/src/lib/kdb/kdb5.c
U trunk/src/lib/kdb/libkdb5.exports
U trunk/src/plugins/kdb/db2/lockout.c
U trunk/src/plugins/kdb/ldap/libkdb_ldap/kerberos.ldif
U trunk/src/plugins/kdb/ldap/libkdb_ldap/kerberos.schema
U trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
U trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
U trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h
U trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
U trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_rights.c
U trunk/src/plugins/kdb/ldap/libkdb_ldap/lockout.c
U trunk/src/tests/t_lockout.py
Modified: trunk/src/include/kdb.h
===================================================================
--- trunk/src/include/kdb.h 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/include/kdb.h 2010-10-05 14:53:09 UTC (rev 24424)
@@ -238,6 +238,7 @@
#define KRB5_TL_CONSTRAINED_DELEGATION_ACL 0x0400 /* Each entry is a permitted SPN */
#define KRB5_TL_LM_KEY 0x0500 /* LM OWF */
#define KRB5_TL_X509_SUBJECT_ISSUER_NAME 0x0600 /* <I>IssuerDN<S>SubjectDN */
+#define KRB5_TL_LAST_ADMIN_UNLOCK 0x0700 /* Timestamp of admin unlock */
/* version number for KRB5_TL_ACTKVNO data */
#define KRB5_TL_ACTKVNO_VER 1
@@ -494,6 +495,11 @@
krb5_timestamp stamp);
krb5_error_code
+krb5_dbe_update_last_admin_unlock( krb5_context context,
+ krb5_db_entry * entry,
+ krb5_timestamp stamp);
+
+krb5_error_code
krb5_dbe_lookup_tl_data( krb5_context context,
krb5_db_entry * entry,
krb5_tl_data * ret_tl_data);
@@ -523,6 +529,11 @@
krb5_timestamp * stamp);
krb5_error_code
+krb5_dbe_lookup_last_admin_unlock( krb5_context context,
+ krb5_db_entry * entry,
+ krb5_timestamp * stamp);
+
+krb5_error_code
krb5_dbe_delete_tl_data( krb5_context context,
krb5_db_entry * entry,
krb5_int16 tl_data_type);
Modified: trunk/src/kadmin/cli/kadmin.c
===================================================================
--- trunk/src/kadmin/cli/kadmin.c 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/kadmin/cli/kadmin.c 2010-10-05 14:53:09 UTC (rev 24424)
@@ -815,6 +815,55 @@
}
}
+/* Construct a tl_data element and add it to the tail of princ->tl_data. */
+static void
+add_tl_data(kadm5_principal_ent_t princ, krb5_int16 tl_type, krb5_ui_2 len,
+ krb5_octet *contents)
+{
+ krb5_tl_data *tl_data, **tlp;
+ krb5_octet *copy;
+
+ copy = malloc(len);
+ tl_data = calloc(1, sizeof(*tl_data));
+ if (copy == NULL || tl_data == NULL) {
+ fprintf(stderr, "Not enough memory\n");
+ exit(1);
+ }
+ memcpy(copy, contents, len);
+
+ tl_data->tl_data_type = tl_type;
+ tl_data->tl_data_length = len;
+ tl_data->tl_data_contents = copy;
+ tl_data->tl_data_next = NULL;
+
+ for (tlp = &princ->tl_data; *tlp != NULL; tlp = &(*tlp)->tl_data_next);
+ *tlp = tl_data;
+ princ->n_tl_data++;
+}
+
+static void
+unlock_princ(kadm5_principal_ent_t princ, long *mask, const char *caller)
+{
+ krb5_error_code retval;
+ krb5_timestamp now;
+ krb5_octet timebuf[4];
+
+ /* Zero out the failed auth count. */
+ princ->fail_auth_count = 0;
+ *mask |= KADM5_FAIL_AUTH_COUNT;
+
+ /* Record the timestamp of this unlock operation so that slave KDCs will
+ * see it, since fail_auth_count is unreplicated. */
+ retval = krb5_timeofday(context, &now);
+ if (retval) {
+ com_err(caller, retval, "while getting time");
+ exit(1);
+ }
+ store_32_le((krb5_int32)now, timebuf);
+ add_tl_data(princ, KRB5_TL_LAST_ADMIN_UNLOCK, 4, timebuf);
+ *mask |= KADM5_TL_DATA;
+}
+
/*
* Parse addprinc or modprinc arguments. Some output fields may be
* filled in on error.
@@ -834,7 +883,6 @@
time_t date;
time_t now;
krb5_error_code retval;
- krb5_tl_data *tl_data, *tail = NULL;
*mask = 0;
*pass = NULL;
@@ -851,29 +899,8 @@
if (++i > argc - 2)
return -1;
- tl_data = malloc(sizeof(krb5_tl_data));
- if (tl_data == NULL) {
- fprintf(stderr, "Not enough memory\n");
- exit(1);
- }
-
- memset(tl_data, 0, sizeof(krb5_tl_data));
- tl_data->tl_data_type = KRB5_TL_DB_ARGS;
- tl_data->tl_data_length = strlen(argv[i])+1;
- tl_data->tl_data_contents = (krb5_octet *) strdup(argv[i]);
-
- if (tail) {
- tail->tl_data_next = tl_data;
- } else {
- oprinc->tl_data = tl_data;
- }
- tail = tl_data;
- oprinc->n_tl_data++;
-
- if (tl_data->tl_data_contents == NULL) {
- fprintf(stderr, "Not enough memory\n");
- exit(1);
- }
+ add_tl_data(oprinc, KRB5_TL_DB_ARGS, strlen(argv[i]) + 1,
+ (krb5_octet *)argv[i]);
*mask |= KADM5_TL_DATA;
continue;
}
@@ -983,8 +1010,7 @@
}
#endif /* APPLE_PKINIT */
if (strlen(argv[i]) == 7 && !strcmp("-unlock", argv[i])) {
- oprinc->fail_auth_count = 0;
- *mask |= KADM5_FAIL_AUTH_COUNT;
+ unlock_princ(oprinc, mask, caller);
continue;
}
if (!strcmp("-e", argv[i])) {
Modified: trunk/src/lib/kdb/kdb5.c
===================================================================
--- trunk/src/lib/kdb/kdb5.c 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/lib/kdb/kdb5.c 2010-10-05 14:53:09 UTC (rev 24424)
@@ -1431,6 +1431,31 @@
}
krb5_error_code
+krb5_dbe_lookup_last_admin_unlock(krb5_context context, krb5_db_entry *entry,
+ krb5_timestamp *stamp)
+{
+ krb5_tl_data tl_data;
+ krb5_error_code code;
+ krb5_int32 tmp;
+
+ tl_data.tl_data_type = KRB5_TL_LAST_ADMIN_UNLOCK;
+
+ if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
+ return (code);
+
+ if (tl_data.tl_data_length != 4) {
+ *stamp = 0;
+ return (0);
+ }
+
+ krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp);
+
+ *stamp = (krb5_timestamp) tmp;
+
+ return (0);
+}
+
+krb5_error_code
krb5_dbe_lookup_tl_data(krb5_context context, krb5_db_entry *entry,
krb5_tl_data *ret_tl_data)
{
@@ -1922,6 +1947,21 @@
}
krb5_error_code
+krb5_dbe_update_last_admin_unlock(krb5_context context, krb5_db_entry *entry,
+ krb5_timestamp stamp)
+{
+ krb5_tl_data tl_data;
+ krb5_octet buf[4]; /* this is the encoded size of an int32 */
+
+ tl_data.tl_data_type = KRB5_TL_LAST_ADMIN_UNLOCK;
+ tl_data.tl_data_length = sizeof(buf);
+ krb5_kdb_encode_int32((krb5_int32) stamp, buf);
+ tl_data.tl_data_contents = buf;
+
+ return (krb5_dbe_update_tl_data(context, entry, &tl_data));
+}
+
+krb5_error_code
krb5_dbe_delete_tl_data(krb5_context context, krb5_db_entry *entry,
krb5_int16 tl_data_type)
{
Modified: trunk/src/lib/kdb/libkdb5.exports
===================================================================
--- trunk/src/lib/kdb/libkdb5.exports 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/lib/kdb/libkdb5.exports 2010-10-05 14:53:09 UTC (rev 24424)
@@ -44,6 +44,7 @@
krb5_dbe_free_mkey_aux_list
krb5_dbe_free_key_list
krb5_dbe_get_mkvno
+krb5_dbe_lookup_last_admin_unlock
krb5_dbe_lookup_last_pwd_change
krb5_dbe_lookup_actkvno
krb5_dbe_lookup_mkey_aux
@@ -52,6 +53,7 @@
krb5_dbe_lookup_tl_data
krb5_dbe_search_enctype
krb5_dbe_update_actkvno
+krb5_dbe_update_last_admin_unlock
krb5_dbe_update_last_pwd_change
krb5_dbe_update_mkey_aux
krb5_dbe_update_mkvno
Modified: trunk/src/plugins/kdb/db2/lockout.c
===================================================================
--- trunk/src/plugins/kdb/db2/lockout.c 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/plugins/kdb/db2/lockout.c 2010-10-05 14:53:09 UTC (rev 24424)
@@ -100,6 +100,13 @@
krb5_timestamp lockout_duration,
krb5_db_entry *entry)
{
+ krb5_timestamp unlock_time;
+
+ /* If the entry was unlocked since the last failure, it's not locked. */
+ if (krb5_dbe_lookup_last_admin_unlock(context, entry, &unlock_time) == 0 &&
+ entry->last_failed <= unlock_time)
+ return FALSE;
+
if (max_fail == 0 || entry->fail_auth_count < max_fail)
return FALSE;
@@ -147,6 +154,7 @@
krb5_deltat lockout_duration = 0;
krb5_db2_context *db_ctx = context->dal_handle->db_context;
krb5_boolean need_update = FALSE;
+ krb5_timestamp unlock_time;
switch (status) {
case 0:
@@ -182,6 +190,13 @@
} else if (!db_ctx->disable_lockout &&
(status == KRB5KDC_ERR_PREAUTH_FAILED ||
status == KRB5KRB_AP_ERR_BAD_INTEGRITY)) {
+ if (krb5_dbe_lookup_last_admin_unlock(context, entry,
+ &unlock_time) == 0 &&
+ entry->last_failed <= unlock_time) {
+ /* Reset fail_auth_count after administrative unlock. */
+ entry->fail_auth_count = 0;
+ }
+
if (failcnt_interval != 0 &&
stamp > entry->last_failed + failcnt_interval) {
/* Reset fail_auth_count after failcnt_interval. */
Modified: trunk/src/plugins/kdb/ldap/libkdb_ldap/kerberos.ldif
===================================================================
--- trunk/src/plugins/kdb/ldap/libkdb_ldap/kerberos.ldif 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/plugins/kdb/ldap/libkdb_ldap/kerberos.ldif 2010-10-05 14:53:09 UTC (rev 24424)
@@ -550,7 +550,17 @@
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE)
+##### The time at which the principal was last administratively unlocked.
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributetypes: ( 1.3.6.1.4.1.5322.21.2.5
+ NAME 'krbLastAdminUnlock'
+ EQUALITY generalizedTimeMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
+ SINGLE-VALUE)
+
##### This attribute holds the kerberos master key.
##### This can be used to encrypt principal keys.
##### This attribute has to be secured in directory.
@@ -754,7 +764,7 @@
objectClasses: ( 2.16.840.1.113719.1.301.6.8.1
NAME 'krbPrincipalAux'
AUXILIARY
- MAY ( krbPrincipalName $ krbCanonicalName $ krbUPEnabled $ krbPrincipalKey $ krbTicketPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration $ krbPwdPolicyReference $ krbPrincipalType $ krbPwdHistory $ krbLastPwdChange $ krbPrincipalAliases $ krbLastSuccessfulAuth $ krbLastFailedAuth $ krbLoginFailedCount $ krbExtraData $ krbAllowedToDelegateTo ) )
+ MAY ( krbPrincipalName $ krbCanonicalName $ krbUPEnabled $ krbPrincipalKey $ krbTicketPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration $ krbPwdPolicyReference $ krbPrincipalType $ krbPwdHistory $ krbLastPwdChange $ krbLastAdminUnlock $ krbPrincipalAliases $ krbLastSuccessfulAuth $ krbLastFailedAuth $ krbLoginFailedCount $ krbExtraData $ krbAllowedToDelegateTo ) )
###### This class is used to create additional principals and stand alone principals.
Modified: trunk/src/plugins/kdb/ldap/libkdb_ldap/kerberos.schema
===================================================================
--- trunk/src/plugins/kdb/ldap/libkdb_ldap/kerberos.schema 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/plugins/kdb/ldap/libkdb_ldap/kerberos.schema 2010-10-05 14:53:09 UTC (rev 24424)
@@ -445,7 +445,14 @@
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE)
+##### The time at which the principal was last administratively unlocked.
+attributetype ( 1.3.6.1.4.1.5322.21.2.5
+ NAME 'krbLastAdminUnlock'
+ EQUALITY generalizedTimeMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
+ SINGLE-VALUE)
+
##### This attribute holds the kerberos master key.
##### This can be used to encrypt principal keys.
##### This attribute has to be secured in directory.
@@ -609,7 +616,7 @@
NAME 'krbPrincipalAux'
SUP top
AUXILIARY
- MAY ( krbPrincipalName $ krbCanonicalName $ krbUPEnabled $ krbPrincipalKey $ krbTicketPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration $ krbPwdPolicyReference $ krbPrincipalType $ krbPwdHistory $ krbLastPwdChange $ krbPrincipalAliases $ krbLastSuccessfulAuth $ krbLastFailedAuth $ krbLoginFailedCount $ krbExtraData $ krbAllowedToDelegateTo ) )
+ MAY ( krbPrincipalName $ krbCanonicalName $ krbUPEnabled $ krbPrincipalKey $ krbTicketPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration $ krbPwdPolicyReference $ krbPrincipalType $ krbPwdHistory $ krbLastPwdChange $ krbLastAdminUnlock $ krbPrincipalAliases $ krbLastSuccessfulAuth $ krbLastFailedAuth $ krbLoginFailedCount $ krbExtraData $ krbAllowedToDelegateTo ) )
###### This class is used to create additional principals and stand alone principals.
Modified: trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
===================================================================
--- trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c 2010-10-05 14:53:09 UTC (rev 24424)
@@ -1997,6 +1997,20 @@
}
}
+ /* LAST ADMIN UNLOCK */
+ {
+ krb5_timestamp unlock_time=0;
+ if ((st=krb5_ldap_get_time(ld, ent, "krbLastAdminUnlock",
+ &unlock_time, &attr_present)) != 0)
+ goto cleanup;
+ if (attr_present == TRUE) {
+ if ((st=krb5_dbe_update_last_admin_unlock(context, entry,
+ unlock_time)))
+ goto cleanup;
+ mask |= KDB_LAST_ADMIN_UNLOCK_ATTR;
+ }
+ }
+
/* ALLOWED TO DELEGATE TO */
{
char **a2d2 = NULL;
Modified: trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
===================================================================
--- trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c 2010-10-05 14:53:09 UTC (rev 24424)
@@ -60,6 +60,7 @@
"logindisabled",
#endif
"krbLastPwdChange",
+ "krbLastAdminUnlock",
"krbExtraData",
"krbObjectReferences",
"krbAllowedToDelegateTo",
@@ -80,6 +81,7 @@
"krbLastSuccessfulAuth",
"krbLastFailedAuth",
"krbLoginFailedCount",
+ "krbLastAdminUnlock",
NULL };
void
Modified: trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h
===================================================================
--- trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.h 2010-10-05 14:53:09 UTC (rev 24424)
@@ -82,7 +82,7 @@
#define KDB_LAST_SUCCESS_ATTR 0x000800
#define KDB_LAST_FAILED_ATTR 0x001000
#define KDB_FAIL_AUTH_COUNT_ATTR 0x002000
-#define KDB_LOCKED_TIME_ATTR 0x004000
+#define KDB_LAST_ADMIN_UNLOCK_ATTR 0x004000
/*
* This is a private contract between krb5_ldap_lockout_audit()
Modified: trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
===================================================================
--- trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c 2010-10-05 14:53:09 UTC (rev 24424)
@@ -1051,6 +1051,7 @@
int count = 0;
struct berval **ber_tl_data = NULL;
krb5_tl_data *ptr;
+ krb5_timestamp unlock_time;
for (ptr = entry->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
#ifdef SECURID
@@ -1058,7 +1059,8 @@
#endif
|| ptr->tl_data_type == KRB5_TL_KADM_DATA
|| ptr->tl_data_type == KDB_TL_USER_INFO
- || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL)
+ || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL
+ || ptr->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK)
continue;
count++;
}
@@ -1079,7 +1081,8 @@
#endif
|| ptr->tl_data_type == KRB5_TL_KADM_DATA
|| ptr->tl_data_type == KDB_TL_USER_INFO
- || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL)
+ || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL
+ || ptr->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK)
continue;
if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0)
break;
@@ -1099,6 +1102,22 @@
ber_tl_data)) != 0)
goto cleanup;
}
+ if ((st=krb5_dbe_lookup_last_admin_unlock(context, entry,
+ &unlock_time)) != 0)
+ goto cleanup;
+ if (unlock_time != 0) {
+ /* Update last admin unlock */
+ memset(strval, 0, sizeof(strval));
+ if ((strval[0] = getstringtime(unlock_time)) == NULL)
+ goto cleanup;
+
+ if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastAdminUnlock",
+ LDAP_MOD_REPLACE, strval)) != 0) {
+ free (strval[0]);
+ goto cleanup;
+ }
+ free (strval[0]);
+ }
}
/* Directory specific attribute */
Modified: trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_rights.c
===================================================================
--- trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_rights.c 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_rights.c 2010-10-05 14:53:09 UTC (rev 24424)
@@ -54,6 +54,7 @@
{"2#subtree#","#krbMaxPwdLife"},
{"2#subtree#","#krbObjectReferences"},
{"2#subtree#","#krbLastPwdChange"},
+ {"2#subtree#","#krbLastAdminUnlock"},
{"6#subtree#","#krbExtraData"},
{"2#subtree#","#krbPasswordExpiration"},
{"6#subtree#","#krbLastFailedAuth"},
@@ -82,6 +83,7 @@
{"6#subtree#","#krbPwdMinLength"},
{"6#subtree#","#krbPwdPolicyReference"},
{"6#subtree#","#krbLastPwdChange"},
+ {"6#subtree#","#krbLastAdminUnlock"},
{"6#subtree#","#krbObjectReferences"},
{"6#subtree#","#krbExtraData"},
{"6#subtree#","#krbPasswordExpiration"},
@@ -114,6 +116,7 @@
{"2#subtree#","#krbPwdMinLength"},
{"2#subtree#","#krbPwdPolicyReference"},
{"6#subtree#","#krbLastPwdChange"},
+ {"6#subtree#","#krbLastAdminUnlock"},
{"2#subtree#","#krbObjectReferences"},
{"6#subtree#","#krbExtraData"},
{"6#subtree#","#krbPasswordExpiration"},
@@ -150,6 +153,7 @@
{"2#subtree#","#krbMaxPwdLife"},
{"2#subtree#","#krbObjectReferences"},
{"2#subtree#","#krbLastPwdChange"},
+ {"2#subtree#","#krbLastAdminUnlock"},
{"6#subtree#","#krbExtraData"},
{"2#subtree#","#krbPasswordExpiration"},
{"2#subtree#","#krbDefaultEncSaltTypes"},
@@ -187,6 +191,7 @@
{"6#subtree#","#krbPwdMinLength"},
{"6#subtree#","#krbPwdPolicyReference"},
{"6#subtree#","#krbLastPwdChange"},
+ {"6#subtree#","#krbLastAdminUnlock"},
{"6#subtree#","#krbObjectReferences"},
{"6#subtree#","#krbExtraData"},
{"6#subtree#","#krbPasswordExpiration"},
@@ -228,6 +233,7 @@
{"2#subtree#","#krbPwdMinLength"},
{"2#subtree#","#krbPwdPolicyReference"},
{"2#subtree#","#krbLastPwdChange"},
+ {"2#subtree#","#krbLastAdminUnlock"},
{"2#subtree#","#krbObjectReferences"},
{"6#subtree#","#krbExtraData"},
{"6#subtree#","#krbPasswordExpiration"},
Modified: trunk/src/plugins/kdb/ldap/libkdb_ldap/lockout.c
===================================================================
--- trunk/src/plugins/kdb/ldap/libkdb_ldap/lockout.c 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/plugins/kdb/ldap/libkdb_ldap/lockout.c 2010-10-05 14:53:09 UTC (rev 24424)
@@ -96,6 +96,13 @@
krb5_timestamp lockout_duration,
krb5_db_entry *entry)
{
+ krb5_timestamp unlock_time;
+
+ /* If the entry was unlocked since the last failure, it's not locked. */
+ if (krb5_dbe_lookup_last_admin_unlock(context, entry, &unlock_time) == 0 &&
+ entry->last_failed <= unlock_time)
+ return FALSE;
+
if (max_fail == 0 || entry->fail_auth_count < max_fail)
return FALSE;
@@ -145,6 +152,7 @@
krb5_kvno max_fail = 0;
krb5_deltat failcnt_interval = 0;
krb5_deltat lockout_duration = 0;
+ krb5_timestamp unlock_time;
SETUP_CONTEXT();
@@ -183,6 +191,13 @@
} else if (!ldap_context->disable_lockout &&
(status == KRB5KDC_ERR_PREAUTH_FAILED ||
status == KRB5KRB_AP_ERR_BAD_INTEGRITY)) {
+ if (krb5_dbe_lookup_last_admin_unlock(context, entry,
+ &unlock_time) == 0 &&
+ entry->last_failed <= unlock_time) {
+ /* Reset fail_auth_count after administrative unlock. */
+ entry->fail_auth_count = 0;
+ }
+
if (failcnt_interval != 0 &&
stamp > entry->last_failed + failcnt_interval) {
/* Reset fail_auth_count after failcnt_interval */
Modified: trunk/src/tests/t_lockout.py
===================================================================
--- trunk/src/tests/t_lockout.py 2010-10-05 13:57:27 UTC (rev 24423)
+++ trunk/src/tests/t_lockout.py 2010-10-05 14:53:09 UTC (rev 24424)
@@ -23,7 +23,7 @@
#!/usr/bin/python
from k5test import *
-realm = K5Realm(create_host=False)
+realm = K5Realm(create_host=False, start_kadmind=False)
realm.run_kadminl('addpol -maxfailure 2 -failurecountinterval 5m lockout')
realm.run_kadminl('modprinc +requires_preauth -policy lockout user')
@@ -44,5 +44,9 @@
not in output:
fail('Expected lockout error message not seen in kinit output')
+# Check that modprinc -unlock allows a further attempt.
+output = realm.run_kadminl('modprinc -unlock user')
+realm.kinit(realm.user_princ, password('user'))
+
success('Account lockout.')
More information about the cvs-krb5
mailing list