-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathexplockout.c
259 lines (208 loc) · 7.04 KB
/
explockout.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/* explockout.c - Lock user account until he has waited */
/* an exponential time after failed authentication attempts */
/* $OpenLDAP$ */
/*
* Copyright 2018 David Coutadeur <[email protected]>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
* This work is loosely derived from the explockout overlay.
*/
#include "portable.h"
/*
* This file implements an overlay that denies authentication to
* users who have previously failed to authenticate, requiring them
* to wait for an exponential time.
*
*/
#ifdef SLAPD_OVER_EXPLOCKOUT
#include <ldap.h>
#include "lutil.h"
#include "slap.h"
#include <ac/errno.h>
#include <ac/time.h>
#include <ac/string.h>
#include <ac/ctype.h>
#include "slap-config.h"
#define ATTR_PWDFAILURETIME "pwdFailureTime"
#define ATTR_NAME_MAX_LEN 150
/* Per-instance configuration information */
/*
* if (base time) ^ ( number of pwdFailureTime ) < max time
* waiting time = (base time) ^ ( number of pwdFailureTime )
* if (base time) ^ ( number of pwdFailureTime ) >= max time
* waiting time = max time
*/
typedef struct explockout_info {
/* basetime to compute waiting time */
int basetime;
/* maximum waiting time at any time */
int maxtime;
} explockout_info;
/* Attribute Description pwdFailureTime */
static AttributeDescription *ad_pwdFailureTime;
/* configuration attribute and objectclass */
static ConfigTable explockoutcfg[] = {
{ "explockout-basetime", "seconds", 2, 2, 0,
ARG_INT|ARG_OFFSET,
(void *)offsetof(explockout_info, basetime),
"( OLcfgCtAt:190.1 "
"NAME 'olcExpLockoutBaseTime' "
"DESC 'base time used for computing exponential lockout waiting time'"
"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
{ "explockout-maxtime", "seconds", 2, 2, 0,
ARG_INT|ARG_OFFSET,
(void *)offsetof(explockout_info, maxtime),
"( OLcfgCtAt:190.2 "
"NAME 'olcExpLockoutMaxTime' "
"DESC 'maximum time used for computing exponential lockout waiting time'"
"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
};
static ConfigOCs explockoutocs[] = {
{ "( OLcfgCtOc:190.1 "
"NAME 'olcExpLockoutConfig' "
"DESC 'Exponential lockout configuration' "
"SUP olcOverlayConfig "
"MAY ( olcExpLockoutBaseTime $ olcExpLockoutMaxTime ) )",
Cft_Overlay, explockoutcfg, NULL, NULL },
{ NULL, 0, NULL }
};
static time_t
parse_time( char *atm )
{
struct lutil_tm tm;
struct lutil_timet tt;
time_t ret = (time_t)-1;
if ( lutil_parsetime( atm, &tm ) == 0) {
lutil_tm2time( &tm, &tt );
ret = tt.tt_sec;
}
return ret;
}
int power(int base, unsigned int exp) {
int i, result = 1;
for (i = 0; i < exp; i++)
result *= base;
return result;
}
static int
explockout_bind( Operation *op, SlapReply *rs )
{
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
Entry *e;
int rc;
int nb_pwdFailureTime = 0;
time_t now, pwdftime = (time_t)-1;
Attribute *a;
int i;
int delay = 0;
int future_delay = 0;
char result[1024];
rc = overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on );
if ( rc != LDAP_SUCCESS ) {
overlay_entry_release_ov( op, e, 0, on );
return SLAP_CB_CONTINUE;
}
// get configuration parameters
explockout_info *lbi = (explockout_info *) on->on_bi.bi_private;
/* get the current time */
now = slap_get_time();
Debug( LDAP_DEBUG_ANY, "explockout: basetime: %d\n", lbi->basetime );
Debug( LDAP_DEBUG_ANY, "explockout: maxtime: %d\n", lbi->maxtime );
/* get pwdFailureTime attribute, if it exists */
if ((a = attr_find( e->e_attrs, ad_pwdFailureTime)) != NULL) {
nb_pwdFailureTime = a->a_numvals;
Debug( LDAP_DEBUG_ANY, "explockout: nb of pwdFailureTime: %d\n", nb_pwdFailureTime );
// Compute exponential time
delay = power(lbi->basetime, nb_pwdFailureTime);
if( delay > lbi->maxtime )
{
delay = lbi->maxtime;
}
Debug( LDAP_DEBUG_ANY, "explockout: computed waiting time (determine if password is still locked): %d\n", delay );
// Compute future_delay = base ^ (nb of pwdFailureTime + 1)
// if password is locked by explockout, then explockout will make this authentication as failed
// thus, as ppolicy overlay will consider this authentication as failed, one more pwdFailureTime will be recorded
future_delay = power(lbi->basetime, (nb_pwdFailureTime+1));
if( future_delay > lbi->maxtime )
{
future_delay = lbi->maxtime;
}
Debug( LDAP_DEBUG_ANY, "explockout: computed future waiting time (if current authentication is locked or failed): %d\n", future_delay );
// For each pwdFailureTime, verify that
// exponential time + pwdFailureTime < now
for(i=0 ; i < nb_pwdFailureTime ; i++)
{
Debug( LDAP_DEBUG_ANY, "explockout: verifying pwdFailureTime: %s\n", a->a_nvals[i].bv_val );
pwdftime = parse_time( a->a_nvals[i].bv_val );
if( now < (pwdftime + delay) )
{
Debug( LDAP_DEBUG_ANY, "explockout: error, you should wait for %d seconds before you can authenticate again\n", (int)(pwdftime + future_delay - now) );
// send deny
overlay_entry_release_ov( op, e, 0, on );
sprintf(result, "password locked! You should wait %d seconds", (int)(pwdftime + future_delay - now));
send_ldap_error( op, rs, LDAP_INVALID_CREDENTIALS, result );
return LDAP_INVALID_CREDENTIALS;
}
}
}
overlay_entry_release_ov( op, e, 0, on );
return SLAP_CB_CONTINUE;
}
static int
explockout_db_init(BackendDB *be, ConfigReply *cr)
{
const char *err_msg;
// register pwdFailureTime description
if ( slap_str2ad( ATTR_PWDFAILURETIME, &ad_pwdFailureTime, &err_msg )
!= LDAP_SUCCESS )
{
Log( LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, "explockout: attribute '%s': %s.\n", ATTR_PWDFAILURETIME, err_msg );
return -1;
}
slap_overinst *on = (slap_overinst *) be->bd_info;
/* initialize private structure to store configuration */
on->on_bi.bi_private = ch_calloc( 1, sizeof(explockout_info) );
return 0;
}
static int
explockout_db_close(
BackendDB *be,
ConfigReply *cr
)
{
slap_overinst *on = (slap_overinst *) be->bd_info;
explockout_info *lbi = (explockout_info *) on->on_bi.bi_private;
/* free private structure to store configuration */
free( lbi );
return 0;
}
static slap_overinst explockout;
int explockout_initialize()
{
int code;
explockout.on_bi.bi_type = "explockout";
explockout.on_bi.bi_db_init = explockout_db_init;
explockout.on_bi.bi_db_close = explockout_db_close;
explockout.on_bi.bi_op_bind = explockout_bind;
// register configuration directives
explockout.on_bi.bi_cf_ocs = explockoutocs;
code = config_register_schema( explockoutcfg, explockoutocs );
if ( code ) return code;
return overlay_register( &explockout );
}
#if SLAPD_OVER_EXPLOCKOUT == SLAPD_MOD_DYNAMIC
int init_module(int argc, char *argv[]) {
return explockout_initialize();
}
#endif
#endif /* defined(SLAPD_OVER_EXPLOCKOUT) */