Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/plugins/kdb/ldap/libkdb_ldap/lockout.c
39642 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* plugins/kdb/ldap/libkdb_ldap/lockout.c */
3
/*
4
* Copyright (C) 2009 by the Massachusetts Institute of Technology.
5
* All rights reserved.
6
*
7
* Export of this software from the United States of America may
8
* require a specific license from the United States Government.
9
* It is the responsibility of any person or organization contemplating
10
* export to obtain such a license before exporting.
11
*
12
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13
* distribute this software and its documentation for any purpose and
14
* without fee is hereby granted, provided that the above copyright
15
* notice appear in all copies and that both that copyright notice and
16
* this permission notice appear in supporting documentation, and that
17
* the name of M.I.T. not be used in advertising or publicity pertaining
18
* to distribution of the software without specific, written prior
19
* permission. Furthermore if you modify this software you must label
20
* your software as modified software and not distribute it in such a
21
* fashion that it might be confused with the original M.I.T. software.
22
* M.I.T. makes no representations about the suitability of
23
* this software for any purpose. It is provided "as is" without express
24
* or implied warranty.
25
*/
26
27
#include <k5-int.h>
28
#include <kadm5/admin.h>
29
#include <kdb.h>
30
31
#include "kdb_ldap.h"
32
#include "princ_xdr.h"
33
#include "ldap_principal.h"
34
#include "ldap_pwd_policy.h"
35
#include "ldap_tkt_policy.h"
36
37
static krb5_error_code
38
lookup_lockout_policy(krb5_context context,
39
krb5_db_entry *entry,
40
krb5_kvno *pw_max_fail,
41
krb5_deltat *pw_failcnt_interval,
42
krb5_deltat *pw_lockout_duration)
43
{
44
krb5_tl_data tl_data;
45
krb5_error_code code;
46
osa_princ_ent_rec adb;
47
48
*pw_max_fail = 0;
49
*pw_failcnt_interval = 0;
50
*pw_lockout_duration = 0;
51
52
tl_data.tl_data_type = KRB5_TL_KADM_DATA;
53
54
code = krb5_dbe_lookup_tl_data(context, entry, &tl_data);
55
if (code != 0 || tl_data.tl_data_length == 0)
56
return code;
57
58
memset(&adb, 0, sizeof(adb));
59
60
code = krb5_lookup_tl_kadm_data(&tl_data, &adb);
61
if (code != 0)
62
return code;
63
64
if (adb.policy != NULL) {
65
osa_policy_ent_t policy = NULL;
66
67
code = krb5_ldap_get_password_policy(context, adb.policy, &policy);
68
if (code == 0) {
69
*pw_max_fail = policy->pw_max_fail;
70
*pw_failcnt_interval = policy->pw_failcnt_interval;
71
*pw_lockout_duration = policy->pw_lockout_duration;
72
}
73
krb5_db_free_policy(context, policy);
74
}
75
76
ldap_osa_free_princ_ent(&adb);
77
78
return 0;
79
}
80
81
/* draft-behera-ldap-password-policy-10.txt 7.1 */
82
static krb5_boolean
83
locked_check_p(krb5_context context,
84
krb5_timestamp stamp,
85
krb5_kvno max_fail,
86
krb5_timestamp lockout_duration,
87
krb5_db_entry *entry)
88
{
89
krb5_timestamp unlock_time;
90
91
/* If the entry was unlocked since the last failure, it's not locked. */
92
if (krb5_dbe_lookup_last_admin_unlock(context, entry, &unlock_time) == 0 &&
93
!ts_after(entry->last_failed, unlock_time))
94
return FALSE;
95
96
if (max_fail == 0 || entry->fail_auth_count < max_fail)
97
return FALSE;
98
99
if (lockout_duration == 0)
100
return TRUE; /* principal permanently locked */
101
102
return ts_after(ts_incr(entry->last_failed, lockout_duration), stamp);
103
}
104
105
krb5_error_code
106
krb5_ldap_lockout_check_policy(krb5_context context,
107
krb5_db_entry *entry,
108
krb5_timestamp stamp)
109
{
110
krb5_error_code code;
111
kdb5_dal_handle *dal_handle;
112
krb5_ldap_context *ldap_context;
113
krb5_kvno max_fail = 0;
114
krb5_deltat failcnt_interval = 0;
115
krb5_deltat lockout_duration = 0;
116
117
SETUP_CONTEXT();
118
if (ldap_context->disable_lockout)
119
return 0;
120
121
code = lookup_lockout_policy(context, entry, &max_fail,
122
&failcnt_interval,
123
&lockout_duration);
124
if (code != 0)
125
return code;
126
127
if (locked_check_p(context, stamp, max_fail, lockout_duration, entry))
128
return KRB5KDC_ERR_CLIENT_REVOKED;
129
130
return 0;
131
}
132
133
krb5_error_code
134
krb5_ldap_lockout_audit(krb5_context context,
135
krb5_db_entry *entry,
136
krb5_timestamp stamp,
137
krb5_error_code status)
138
{
139
krb5_error_code code;
140
kdb5_dal_handle *dal_handle;
141
krb5_ldap_context *ldap_context;
142
krb5_kvno max_fail = 0;
143
krb5_deltat failcnt_interval = 0;
144
krb5_deltat lockout_duration = 0;
145
krb5_timestamp unlock_time;
146
147
SETUP_CONTEXT();
148
149
switch (status) {
150
case 0:
151
case KRB5KDC_ERR_PREAUTH_FAILED:
152
case KRB5KRB_AP_ERR_BAD_INTEGRITY:
153
break;
154
default:
155
return 0;
156
}
157
158
if (entry == NULL)
159
return 0;
160
161
if (!ldap_context->disable_lockout) {
162
code = lookup_lockout_policy(context, entry, &max_fail,
163
&failcnt_interval,
164
&lockout_duration);
165
if (code != 0)
166
return code;
167
}
168
169
/*
170
* Don't continue to modify the DB for an already locked account.
171
* (In most cases, status will be KRB5KDC_ERR_CLIENT_REVOKED, and
172
* this check is unneeded, but in rare cases, we can fail with an
173
* integrity error or preauth failure before a policy check.)
174
*/
175
if (locked_check_p(context, stamp, max_fail, lockout_duration, entry))
176
return 0;
177
178
entry->mask = 0;
179
180
/* Only mark the authentication as successful if the entry
181
* required preauthentication, otherwise we have no idea. */
182
if (status == 0 && (entry->attributes & KRB5_KDB_REQUIRES_PRE_AUTH)) {
183
if (!ldap_context->disable_lockout && entry->fail_auth_count != 0) {
184
entry->fail_auth_count = 0;
185
entry->mask |= KADM5_FAIL_AUTH_COUNT;
186
}
187
if (!ldap_context->disable_last_success) {
188
entry->last_success = stamp;
189
entry->mask |= KADM5_LAST_SUCCESS;
190
}
191
} else if (!ldap_context->disable_lockout &&
192
(status == KRB5KDC_ERR_PREAUTH_FAILED ||
193
status == KRB5KRB_AP_ERR_BAD_INTEGRITY)) {
194
if (krb5_dbe_lookup_last_admin_unlock(context, entry,
195
&unlock_time) == 0 &&
196
!ts_after(entry->last_failed, unlock_time)) {
197
/* Reset fail_auth_count after administrative unlock. */
198
entry->fail_auth_count = 0;
199
entry->mask |= KADM5_FAIL_AUTH_COUNT;
200
}
201
202
if (failcnt_interval != 0 &&
203
ts_after(stamp, ts_incr(entry->last_failed, failcnt_interval))) {
204
/* Reset fail_auth_count after failcnt_interval */
205
entry->fail_auth_count = 0;
206
entry->mask |= KADM5_FAIL_AUTH_COUNT;
207
}
208
209
entry->last_failed = stamp;
210
entry->mask |= KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT_INCREMENT;
211
}
212
213
if (entry->mask) {
214
code = krb5_ldap_put_principal(context, entry, NULL);
215
if (code != 0)
216
return code;
217
}
218
219
return 0;
220
}
221
222