1 /* $NetBSD: slapd-totp.c,v 1.2 2021/08/14 16:14:53 christos Exp $ */
2
3 /* slapd-totp.c - Password module and overlay for TOTP */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2015-2021 The OpenLDAP Foundation.
8 * Portions Copyright 2015 by Howard Chu, Symas Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted only as authorized by the OpenLDAP
13 * Public License.
14 *
15 * A copy of this license is available in the file LICENSE in the
16 * top-level directory of the distribution or, alternatively, at
17 * <http://www.OpenLDAP.org/license.html>.
18 */
19 /* ACKNOWLEDGEMENTS:
20 * This work includes code from the lastbind overlay.
21 */
22
23 #include <portable.h>
24
25 #if HAVE_STDINT_H
26 #include <stdint.h>
27 #endif
28
29 #include <lber.h>
30 #include <lber_pvt.h>
31 #include "lutil.h"
32 #include <ac/stdlib.h>
33 #include <ac/ctype.h>
34 #include <ac/string.h>
35 /* include socket.h to get sys/types.h and/or winsock2.h */
36 #include <ac/socket.h>
37
38 #if HAVE_OPENSSL
39 #include <openssl/sha.h>
40 #include <openssl/hmac.h>
41
42 #define TOTP_SHA512_DIGEST_LENGTH SHA512_DIGEST_LENGTH
43 #define TOTP_SHA1 EVP_sha1()
44 #define TOTP_SHA256 EVP_sha256()
45 #define TOTP_SHA512 EVP_sha512()
46 #define TOTP_HMAC_CTX HMAC_CTX *
47
48 #if OPENSSL_VERSION_NUMBER < 0x10100000L
HMAC_CTX_new(void)49 static HMAC_CTX *HMAC_CTX_new(void)
50 {
51 HMAC_CTX *ctx = OPENSSL_malloc(sizeof(*ctx));
52 if (ctx != NULL) {
53 HMAC_CTX_init(ctx);
54 }
55 return ctx;
56 }
57
HMAC_CTX_free(HMAC_CTX * ctx)58 static void HMAC_CTX_free(HMAC_CTX *ctx)
59 {
60 if (ctx != NULL) {
61 HMAC_CTX_cleanup(ctx);
62 OPENSSL_free(ctx);
63 }
64 }
65 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
66
67 #define HMAC_setup(ctx, key, len, hash) \
68 ctx = HMAC_CTX_new(); \
69 HMAC_Init_ex(ctx, key, len, hash, 0)
70 #define HMAC_crunch(ctx, buf, len) HMAC_Update(ctx, buf, len)
71 #define HMAC_finish(ctx, dig, dlen) \
72 HMAC_Final(ctx, dig, &dlen); \
73 HMAC_CTX_free(ctx)
74
75 #elif HAVE_GNUTLS
76 #include <nettle/hmac.h>
77
78 #define TOTP_SHA512_DIGEST_LENGTH SHA512_DIGEST_SIZE
79 #define TOTP_SHA1 &nettle_sha1
80 #define TOTP_SHA256 &nettle_sha256
81 #define TOTP_SHA512 &nettle_sha512
82 #define TOTP_HMAC_CTX struct hmac_sha512_ctx
83
84 #define HMAC_setup(ctx, key, len, hash) \
85 const struct nettle_hash *h=hash;\
86 hmac_set_key(&ctx.outer, &ctx.inner, &ctx.state, h, len, key)
87 #define HMAC_crunch(ctx, buf, len) hmac_update(&ctx.state, h, len, buf)
88 #define HMAC_finish(ctx, dig, dlen) \
89 hmac_digest(&ctx.outer, &ctx.inner, &ctx.state, h, h->digest_size, dig);\
90 dlen = h->digest_size
91
92 #else
93 # error Unsupported crypto backend.
94 #endif
95
96 #include "slap.h"
97 #include "slap-config.h"
98
99 static LUTIL_PASSWD_CHK_FUNC chk_totp1, chk_totp256, chk_totp512,
100 chk_totp1andpw, chk_totp256andpw, chk_totp512andpw;
101 static LUTIL_PASSWD_HASH_FUNC hash_totp1, hash_totp256, hash_totp512,
102 hash_totp1andpw, hash_totp256andpw, hash_totp512andpw;
103 static const struct berval scheme_totp1 = BER_BVC("{TOTP1}");
104 static const struct berval scheme_totp256 = BER_BVC("{TOTP256}");
105 static const struct berval scheme_totp512 = BER_BVC("{TOTP512}");
106 static const struct berval scheme_totp1andpw = BER_BVC("{TOTP1ANDPW}");
107 static const struct berval scheme_totp256andpw = BER_BVC("{TOTP256ANDPW}");
108 static const struct berval scheme_totp512andpw = BER_BVC("{TOTP512ANDPW}");
109
110 static AttributeDescription *ad_authTimestamp;
111
112 /* This is the definition used by ISODE, as supplied to us in
113 * ITS#6238 Followup #9
114 */
115 static struct schema_info {
116 char *def;
117 AttributeDescription **ad;
118 } totp_OpSchema[] = {
119 { "( 1.3.6.1.4.1.453.16.2.188 "
120 "NAME 'authTimestamp' "
121 "DESC 'last successful authentication using any method/mech' "
122 "EQUALITY generalizedTimeMatch "
123 "ORDERING generalizedTimeOrderingMatch "
124 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
125 "SINGLE-VALUE NO-USER-MODIFICATION USAGE dsaOperation )",
126 &ad_authTimestamp},
127 { NULL, NULL }
128 };
129
130 /* RFC3548 base32 encoding/decoding */
131
132 static const char Base32[] =
133 "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
134 static const char Pad32 = '=';
135
136 static int
totp_b32_ntop(u_char const * src,size_t srclength,char * target,size_t targsize)137 totp_b32_ntop(
138 u_char const *src,
139 size_t srclength,
140 char *target,
141 size_t targsize)
142 {
143 size_t datalength = 0;
144 u_char input0;
145 u_int input1; /* assumed to be at least 32 bits */
146 u_char output[8];
147 int i;
148
149 while (4 < srclength) {
150 if (datalength + 8 > targsize)
151 return (-1);
152 input0 = *src++;
153 input1 = *src++;
154 input1 <<= 8;
155 input1 |= *src++;
156 input1 <<= 8;
157 input1 |= *src++;
158 input1 <<= 8;
159 input1 |= *src++;
160 srclength -= 5;
161
162 for (i=7; i>1; i--) {
163 output[i] = input1 & 0x1f;
164 input1 >>= 5;
165 }
166 output[0] = input0 >> 3;
167 output[1] = (input0 & 0x07) << 2 | input1;
168
169 for (i=0; i<8; i++)
170 target[datalength++] = Base32[output[i]];
171 }
172
173 /* Now we worry about padding. */
174 if (0 != srclength) {
175 static const int outlen[] = { 2,4,5,7 };
176 int n;
177 if (datalength + 8 > targsize)
178 return (-1);
179
180 /* Get what's left. */
181 input1 = *src++;
182 for (i = 1; i < srclength; i++) {
183 input1 <<= 8;
184 input1 |= *src++;
185 }
186 input1 <<= 8 * (4-srclength);
187 n = outlen[srclength-1];
188 for (i=0; i<n; i++) {
189 target[datalength++] = Base32[(input1 & 0xf8000000) >> 27];
190 input1 <<= 5;
191 }
192 for (; i<8; i++)
193 target[datalength++] = Pad32;
194 }
195 if (datalength >= targsize)
196 return (-1);
197 target[datalength] = '\0'; /* Returned value doesn't count \0. */
198 return (datalength);
199 }
200
201 /* converts characters, eight at a time, starting at src
202 from base - 32 numbers into five 8 bit bytes in the target area.
203 it returns the number of data bytes stored at the target, or -1 on error.
204 */
205
206 static int
totp_b32_pton(char const * src,u_char * target,size_t targsize)207 totp_b32_pton(
208 char const *src,
209 u_char *target,
210 size_t targsize)
211 {
212 int tarindex, state, ch;
213 char *pos;
214
215 state = 0;
216 tarindex = 0;
217
218 while ((ch = *src++) != '\0') {
219 if (ch == Pad32)
220 break;
221
222 pos = strchr(Base32, ch);
223 if (pos == 0) /* A non-base32 character. */
224 return (-1);
225
226 switch (state) {
227 case 0:
228 if (target) {
229 if ((size_t)tarindex >= targsize)
230 return (-1);
231 target[tarindex] = (pos - Base32) << 3;
232 }
233 state = 1;
234 break;
235 case 1:
236 if (target) {
237 if ((size_t)tarindex + 1 >= targsize)
238 return (-1);
239 target[tarindex] |= (pos - Base32) >> 2;
240 target[tarindex+1] = ((pos - Base32) & 0x3)
241 << 6 ;
242 }
243 tarindex++;
244 state = 2;
245 break;
246 case 2:
247 if (target) {
248 target[tarindex] |= (pos - Base32) << 1;
249 }
250 state = 3;
251 break;
252 case 3:
253 if (target) {
254 if ((size_t)tarindex + 1 >= targsize)
255 return (-1);
256 target[tarindex] |= (pos - Base32) >> 4;
257 target[tarindex+1] = ((pos - Base32) & 0xf)
258 << 4 ;
259 }
260 tarindex++;
261 state = 4;
262 break;
263 case 4:
264 if (target) {
265 if ((size_t)tarindex + 1 >= targsize)
266 return (-1);
267 target[tarindex] |= (pos - Base32) >> 1;
268 target[tarindex+1] = ((pos - Base32) & 0x1)
269 << 7 ;
270 }
271 tarindex++;
272 state = 5;
273 break;
274 case 5:
275 if (target) {
276 target[tarindex] |= (pos - Base32) << 2;
277 }
278 state = 6;
279 break;
280 case 6:
281 if (target) {
282 if ((size_t)tarindex + 1 >= targsize)
283 return (-1);
284 target[tarindex] |= (pos - Base32) >> 3;
285 target[tarindex+1] = ((pos - Base32) & 0x7)
286 << 5 ;
287 }
288 tarindex++;
289 state = 7;
290 break;
291 case 7:
292 if (target) {
293 target[tarindex] |= (pos - Base32);
294 }
295 state = 0;
296 tarindex++;
297 break;
298
299 default:
300 abort();
301 }
302 }
303
304 /*
305 * We are done decoding Base-32 chars. Let's see if we ended
306 * on a byte boundary, and/or with erroneous trailing characters.
307 */
308
309 if (ch == Pad32) { /* We got a pad char. */
310 int i = 0;
311
312 /* count pad chars */
313 for (; ch; ch = *src++) {
314 if (ch != Pad32)
315 return (-1);
316 i++;
317 }
318 /* there are only 4 valid ending states with a
319 * pad character, make sure the number of pads is valid.
320 */
321 switch(state) {
322 case 2: if (i != 6) return -1;
323 break;
324 case 4: if (i != 4) return -1;
325 break;
326 case 5: if (i != 3) return -1;
327 break;
328 case 7: if (i != 1) return -1;
329 break;
330 default:
331 return -1;
332 }
333 /*
334 * Now make sure that the "extra" bits that slopped past
335 * the last full byte were zeros. If we don't check them,
336 * they become a subliminal channel.
337 */
338 if (target && target[tarindex] != 0)
339 return (-1);
340 } else {
341 /*
342 * We ended by seeing the end of the string. Make sure we
343 * have no partial bytes lying around.
344 */
345 if (state != 0)
346 return (-1);
347 }
348
349 return (tarindex);
350 }
351
352 /* RFC6238 TOTP */
353
354
355 typedef struct myval {
356 ber_len_t mv_len;
357 void *mv_val;
358 } myval;
359
do_hmac(const void * hash,myval * key,myval * data,myval * out)360 static void do_hmac(
361 const void *hash,
362 myval *key,
363 myval *data,
364 myval *out)
365 {
366 TOTP_HMAC_CTX ctx;
367 unsigned int digestLen;
368
369 HMAC_setup(ctx, key->mv_val, key->mv_len, hash);
370 HMAC_crunch(ctx, data->mv_val, data->mv_len);
371 HMAC_finish(ctx, out->mv_val, digestLen);
372 out->mv_len = digestLen;
373 }
374
375 static const int DIGITS_POWER[] = {
376 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
377
generate(myval * key,uint64_t tval,int digits,myval * out,const void * mech)378 static void generate(
379 myval *key,
380 uint64_t tval,
381 int digits,
382 myval *out,
383 const void *mech)
384 {
385 unsigned char digest[TOTP_SHA512_DIGEST_LENGTH];
386 myval digval;
387 myval data;
388 unsigned char msg[8];
389 int i, offset, res, otp;
390
391 #if WORDS_BIGENDIAN
392 *(uint64_t *)msg = tval;
393 #else
394 for (i=7; i>=0; i--) {
395 msg[i] = tval & 0xff;
396 tval >>= 8;
397 }
398 #endif
399
400 data.mv_val = msg;
401 data.mv_len = sizeof(msg);
402
403 digval.mv_val = digest;
404 digval.mv_len = sizeof(digest);
405 do_hmac(mech, key, &data, &digval);
406
407 offset = digest[digval.mv_len-1] & 0xf;
408 res = ((digest[offset] & 0x7f) << 24) |
409 ((digest[offset+1] & 0xff) << 16) |
410 ((digest[offset+2] & 0xff) << 8) |
411 (digest[offset+3] & 0xff);
412
413 otp = res % DIGITS_POWER[digits];
414 out->mv_len = snprintf(out->mv_val, out->mv_len, "%0*d", digits, otp);
415 }
416
417 static int totp_op_cleanup( Operation *op, SlapReply *rs );
418 static int totp_bind_response( Operation *op, SlapReply *rs );
419
420 #define TIME_STEP 30
421 #define DIGITS 6
422 #define DELIM '|' /* a single character */
423 #define TOTP_AND_PW_HASH_SCHEME "{SSHA}"
424
chk_totp(const struct berval * passwd,const struct berval * cred,const void * mech,const char ** text)425 static int chk_totp(
426 const struct berval *passwd,
427 const struct berval *cred,
428 const void *mech,
429 const char **text)
430 {
431 void *ctx, *op_tmp;
432 Operation *op;
433 Entry *e;
434 Attribute *a;
435 long t, told = 0;
436 int rc;
437 myval out, key;
438 char outbuf[32];
439
440 /* Find our thread context, find our Operation */
441 ctx = ldap_pvt_thread_pool_context();
442 if (ldap_pvt_thread_pool_getkey(ctx, totp_op_cleanup, &op_tmp, NULL) ||
443 !op_tmp)
444 return LUTIL_PASSWD_ERR;
445 op = op_tmp;
446
447 rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &e);
448 if (rc != LDAP_SUCCESS) return LUTIL_PASSWD_ERR;
449
450 /* Make sure previous login is older than current time */
451 t = op->o_time / TIME_STEP;
452 a = attr_find(e->e_attrs, ad_authTimestamp);
453 if (a) {
454 struct lutil_tm tm;
455 struct lutil_timet tt;
456 if (lutil_parsetime(a->a_vals[0].bv_val, &tm) == 0 &&
457 lutil_tm2time(&tm, &tt) == 0) {
458 told = tt.tt_sec / TIME_STEP;
459 if (told >= t)
460 rc = LUTIL_PASSWD_ERR;
461 }
462 if (!rc) { /* seems OK, remember old stamp */
463 slap_callback *sc;
464 for (sc = op->o_callback; sc; sc = sc->sc_next) {
465 if (sc->sc_response == totp_bind_response) {
466 sc->sc_private = ber_dupbv_x(NULL, &a->a_vals[0], op->o_tmpmemctx);
467 break;
468 }
469 }
470 }
471 } /* else no previous login, 1st use is OK */
472
473 be_entry_release_r(op, e);
474 if (rc) return rc;
475
476 /* Key is stored in base32 */
477 key.mv_len = passwd->bv_len * 5 / 8;
478 key.mv_val = ber_memalloc(key.mv_len+1);
479
480 if (!key.mv_val)
481 return LUTIL_PASSWD_ERR;
482
483 rc = totp_b32_pton(passwd->bv_val, key.mv_val, key.mv_len);
484 if (rc < 1) {
485 rc = LUTIL_PASSWD_ERR;
486 goto out;
487 }
488
489 out.mv_val = outbuf;
490 out.mv_len = sizeof(outbuf);
491 generate(&key, t, DIGITS, &out, mech);
492
493 /* compare */
494 if (out.mv_len != cred->bv_len) {
495 rc = LUTIL_PASSWD_ERR;
496 goto out;
497 }
498
499 rc = memcmp(out.mv_val, cred->bv_val, out.mv_len) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
500
501 /* If current value doesn't match, try again with previous value
502 * but only if the most recent login is older than the previous
503 * time step but still set */
504 if (rc == LUTIL_PASSWD_ERR && told < t - 1 && told > 0) {
505 out.mv_val = outbuf;
506 out.mv_len = sizeof(outbuf);
507 generate(&key, t - 1, DIGITS, &out, mech);
508 /* compare */
509 if (out.mv_len != cred->bv_len)
510 goto out;
511 rc = memcmp(out.mv_val, cred->bv_val, out.mv_len) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
512 }
513
514 out:
515 memset(key.mv_val, 0, key.mv_len);
516 ber_memfree(key.mv_val);
517 return rc;
518 }
519
chk_totp_and_pw(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text,const void * mech)520 static int chk_totp_and_pw(
521 const struct berval *scheme,
522 const struct berval *passwd,
523 const struct berval *cred,
524 const char **text,
525 const void *mech)
526 {
527 char *s;
528 int rc = LUTIL_PASSWD_ERR, rc_pass, rc_otp;
529 ber_len_t len;
530 struct berval cred_pass, cred_otp, passwd_pass, passwd_otp;
531
532 /* Check credential length, no point to continue if too short */
533 if (cred->bv_len <= DIGITS)
534 return rc;
535
536 /* The OTP seed of the stored password */
537 s = strchr(passwd->bv_val, DELIM);
538 if (s) {
539 len = s - passwd->bv_val;
540 } else {
541 return rc;
542 }
543 if (!ber_str2bv(passwd->bv_val, len, 1, &passwd_otp))
544 return rc;
545
546 /* The password part of the stored password */
547 s++;
548 ber_str2bv(s, 0, 0, &passwd_pass);
549
550 /* The OTP part of the entered credential */
551 ber_str2bv(&cred->bv_val[cred->bv_len - DIGITS], DIGITS, 0, &cred_otp);
552
553 /* The password part of the entered credential */
554 if (!ber_str2bv(cred->bv_val, cred->bv_len - DIGITS, 0, &cred_pass)) {
555 /* Cleanup */
556 memset(passwd_otp.bv_val, 0, passwd_otp.bv_len);
557 ber_memfree(passwd_otp.bv_val);
558 return rc;
559 }
560
561 rc_otp = chk_totp(&passwd_otp, &cred_otp, mech, text);
562 rc_pass = lutil_passwd(&passwd_pass, &cred_pass, NULL, text);
563 if (rc_otp == LUTIL_PASSWD_OK && rc_pass == LUTIL_PASSWD_OK)
564 rc = LUTIL_PASSWD_OK;
565
566 /* Cleanup and return */
567 memset(passwd_otp.bv_val, 0, passwd_otp.bv_len);
568 ber_memfree(passwd_otp.bv_val);
569
570 return rc;
571 }
572
chk_totp1(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)573 static int chk_totp1(
574 const struct berval *scheme,
575 const struct berval *passwd,
576 const struct berval *cred,
577 const char **text)
578 {
579 return chk_totp(passwd, cred, TOTP_SHA1, text);
580 }
581
chk_totp256(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)582 static int chk_totp256(
583 const struct berval *scheme,
584 const struct berval *passwd,
585 const struct berval *cred,
586 const char **text)
587 {
588 return chk_totp(passwd, cred, TOTP_SHA256, text);
589 }
590
chk_totp512(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)591 static int chk_totp512(
592 const struct berval *scheme,
593 const struct berval *passwd,
594 const struct berval *cred,
595 const char **text)
596 {
597 return chk_totp(passwd, cred, TOTP_SHA512, text);
598 }
599
chk_totp1andpw(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)600 static int chk_totp1andpw(
601 const struct berval *scheme,
602 const struct berval *passwd,
603 const struct berval *cred,
604 const char **text)
605 {
606 return chk_totp_and_pw(scheme, passwd, cred, text, TOTP_SHA1);
607 }
608
chk_totp256andpw(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)609 static int chk_totp256andpw(
610 const struct berval *scheme,
611 const struct berval *passwd,
612 const struct berval *cred,
613 const char **text)
614 {
615 return chk_totp_and_pw(scheme, passwd, cred, text, TOTP_SHA256);
616 }
617
chk_totp512andpw(const struct berval * scheme,const struct berval * passwd,const struct berval * cred,const char ** text)618 static int chk_totp512andpw(
619 const struct berval *scheme,
620 const struct berval *passwd,
621 const struct berval *cred,
622 const char **text)
623 {
624 return chk_totp_and_pw(scheme, passwd, cred, text, TOTP_SHA512);
625 }
626
passwd_string32(const struct berval * scheme,const struct berval * passwd,struct berval * hash)627 static int passwd_string32(
628 const struct berval *scheme,
629 const struct berval *passwd,
630 struct berval *hash)
631 {
632 int b32len = (passwd->bv_len + 4)/5 * 8;
633 int rc;
634 hash->bv_len = scheme->bv_len + b32len;
635 hash->bv_val = ber_memalloc(hash->bv_len + 1);
636 AC_MEMCPY(hash->bv_val, scheme->bv_val, scheme->bv_len);
637 rc = totp_b32_ntop((unsigned char *)passwd->bv_val, passwd->bv_len,
638 hash->bv_val + scheme->bv_len, b32len+1);
639 if (rc < 0) {
640 ber_memfree(hash->bv_val);
641 hash->bv_val = NULL;
642 return LUTIL_PASSWD_ERR;
643 }
644 return LUTIL_PASSWD_OK;
645 }
646
hash_totp_and_pw(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)647 static int hash_totp_and_pw(
648 const struct berval *scheme,
649 const struct berval *passwd,
650 struct berval *hash,
651 const char **text)
652 {
653 struct berval otp, pass, hash_otp, hash_pass;
654 ber_len_t len;
655 char *s;
656 int rc = LUTIL_PASSWD_ERR;
657
658 /* The OTP seed part */
659 s = strchr(passwd->bv_val, DELIM);
660 if (s) {
661 len = s - passwd->bv_val;
662 } else {
663 return rc;
664 }
665 if (!ber_str2bv(passwd->bv_val, len, 0, &otp))
666 return rc;
667
668 /* The static password part */
669 s++;
670 ber_str2bv(s, 0, 0, &pass);
671
672 /* Hash the OTP seed */
673 rc = passwd_string32(scheme, &otp, &hash_otp);
674
675 /* If successful, hash the static password, else cleanup and return */
676 if (rc == LUTIL_PASSWD_OK) {
677 rc = lutil_passwd_hash(&pass, TOTP_AND_PW_HASH_SCHEME,
678 &hash_pass, text);
679 } else {
680 return LUTIL_PASSWD_ERR;
681 }
682
683 /* If successful, allocate memory to combine them, else cleanup
684 * and return */
685 if (rc == LUTIL_PASSWD_OK) {
686 /* Add 1 character to bv_len to hold DELIM */
687 hash->bv_len = hash_pass.bv_len + hash_otp.bv_len + 1;
688 hash->bv_val = ber_memalloc(hash->bv_len + 1);
689 if (!hash->bv_val)
690 rc = LUTIL_PASSWD_ERR;
691 } else {
692 memset(hash_otp.bv_val, 0, hash_otp.bv_len);
693 ber_memfree(hash_otp.bv_val);
694 return LUTIL_PASSWD_ERR;
695 }
696
697 /* If successful, combine the two hashes with the delimiter */
698 if (rc == LUTIL_PASSWD_OK) {
699 AC_MEMCPY(hash->bv_val, hash_otp.bv_val, hash_otp.bv_len);
700 hash->bv_val[hash_otp.bv_len] = DELIM;
701 AC_MEMCPY(hash->bv_val + hash_otp.bv_len + 1,
702 hash_pass.bv_val, hash_pass.bv_len);
703 hash->bv_val[hash->bv_len] = '\0';
704 }
705
706 /* Cleanup and return */
707 memset(hash_otp.bv_val, 0, hash_otp.bv_len);
708 memset(hash_pass.bv_val, 0, hash_pass.bv_len);
709 ber_memfree(hash_otp.bv_val);
710 ber_memfree(hash_pass.bv_val);
711
712 return rc;
713 }
714
hash_totp1(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)715 static int hash_totp1(
716 const struct berval *scheme,
717 const struct berval *passwd,
718 struct berval *hash,
719 const char **text)
720 {
721 #if 0
722 if (passwd->bv_len != SHA_DIGEST_LENGTH) {
723 *text = "invalid key length";
724 return LUTIL_PASSWD_ERR;
725 }
726 #endif
727 return passwd_string32(scheme, passwd, hash);
728 }
729
hash_totp256(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)730 static int hash_totp256(
731 const struct berval *scheme,
732 const struct berval *passwd,
733 struct berval *hash,
734 const char **text)
735 {
736 #if 0
737 if (passwd->bv_len != SHA256_DIGEST_LENGTH) {
738 *text = "invalid key length";
739 return LUTIL_PASSWD_ERR;
740 }
741 #endif
742 return passwd_string32(scheme, passwd, hash);
743 }
744
hash_totp512(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)745 static int hash_totp512(
746 const struct berval *scheme,
747 const struct berval *passwd,
748 struct berval *hash,
749 const char **text)
750 {
751 #if 0
752 if (passwd->bv_len != SHA512_DIGEST_LENGTH) {
753 *text = "invalid key length";
754 return LUTIL_PASSWD_ERR;
755 }
756 #endif
757 return passwd_string32(scheme, passwd, hash);
758 }
759
hash_totp1andpw(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)760 static int hash_totp1andpw(
761 const struct berval *scheme,
762 const struct berval *passwd,
763 struct berval *hash,
764 const char **text)
765 {
766 #if 0
767 if (passwd->bv_len != SHA_DIGEST_LENGTH) {
768 *text = "invalid key length";
769 return LUTIL_PASSWD_ERR;
770 }
771 #endif
772 return hash_totp_and_pw(scheme, passwd, hash, text);
773 }
774
hash_totp256andpw(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)775 static int hash_totp256andpw(
776 const struct berval *scheme,
777 const struct berval *passwd,
778 struct berval *hash,
779 const char **text)
780 {
781 #if 0
782 if (passwd->bv_len != SHA256_DIGEST_LENGTH) {
783 *text = "invalid key length";
784 return LUTIL_PASSWD_ERR;
785 }
786 #endif
787 return hash_totp_and_pw(scheme, passwd, hash, text);
788 }
789
hash_totp512andpw(const struct berval * scheme,const struct berval * passwd,struct berval * hash,const char ** text)790 static int hash_totp512andpw(
791 const struct berval *scheme,
792 const struct berval *passwd,
793 struct berval *hash,
794 const char **text)
795 {
796 #if 0
797 if (passwd->bv_len != SHA512_DIGEST_LENGTH) {
798 *text = "invalid key length";
799 return LUTIL_PASSWD_ERR;
800 }
801 #endif
802 return hash_totp_and_pw(scheme, passwd, hash, text);
803 }
804
totp_op_cleanup(Operation * op,SlapReply * rs)805 static int totp_op_cleanup(
806 Operation *op,
807 SlapReply *rs )
808 {
809 slap_callback *cb;
810
811 /* clear out the current key */
812 ldap_pvt_thread_pool_setkey( op->o_threadctx, totp_op_cleanup,
813 NULL, 0, NULL, NULL );
814
815 /* free the callback */
816 cb = op->o_callback;
817 op->o_callback = cb->sc_next;
818 if (cb->sc_private)
819 ber_bvfree_x(cb->sc_private, op->o_tmpmemctx);
820 op->o_tmpfree( cb, op->o_tmpmemctx );
821 return 0;
822 }
823
824 static int
totp_bind_response(Operation * op,SlapReply * rs)825 totp_bind_response( Operation *op, SlapReply *rs )
826 {
827 Modifications *mod = NULL;
828 BackendInfo *bi = op->o_bd->bd_info;
829 Entry *e;
830 int rc;
831
832 /* we're only interested if the bind was successful */
833 if ( rs->sr_err != LDAP_SUCCESS )
834 return SLAP_CB_CONTINUE;
835
836 rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &e );
837 op->o_bd->bd_info = bi;
838
839 if ( rc != LDAP_SUCCESS ) {
840 return SLAP_CB_CONTINUE;
841 }
842
843 {
844 time_t now;
845 Attribute *a;
846 Modifications *m;
847 char nowstr[ LDAP_LUTIL_GENTIME_BUFSIZE ];
848 struct berval timestamp;
849
850 /* get the current time */
851 now = op->o_time;
852
853 /* update the authTimestamp in the user's entry with the current time */
854 timestamp.bv_val = nowstr;
855 timestamp.bv_len = sizeof(nowstr);
856 slap_timestamp( &now, ×tamp );
857
858 m = ch_calloc( sizeof(Modifications), 1 );
859 m->sml_op = LDAP_MOD_REPLACE;
860 m->sml_flags = 0;
861 m->sml_type = ad_authTimestamp->ad_cname;
862 m->sml_desc = ad_authTimestamp;
863 m->sml_numvals = 1;
864 m->sml_values = ch_calloc( sizeof(struct berval), 2 );
865 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
866
867 ber_dupbv( &m->sml_values[0], ×tamp );
868 ber_dupbv( &m->sml_nvalues[0], ×tamp );
869 m->sml_next = mod;
870 mod = m;
871
872 /* get authTimestamp attribute, if it exists */
873 if ((a = attr_find( e->e_attrs, ad_authTimestamp)) != NULL && op->o_callback->sc_private) {
874 struct berval *bv = op->o_callback->sc_private;
875 m = ch_calloc( sizeof(Modifications), 1 );
876 m->sml_op = LDAP_MOD_DELETE;
877 m->sml_flags = 0;
878 m->sml_type = ad_authTimestamp->ad_cname;
879 m->sml_desc = ad_authTimestamp;
880 m->sml_numvals = 1;
881 m->sml_values = ch_calloc( sizeof(struct berval), 2 );
882 m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
883
884 ber_dupbv( &m->sml_values[0], bv );
885 ber_dupbv( &m->sml_nvalues[0], bv );
886 m->sml_next = mod;
887 mod = m;
888 }
889 }
890
891 be_entry_release_r( op, e );
892
893 /* perform the update */
894 if ( mod ) {
895 Operation op2 = *op;
896 SlapReply r2 = { REP_RESULT };
897 slap_callback cb = { NULL, slap_null_cb, NULL, NULL };
898
899 /* This is a DSA-specific opattr, it never gets replicated. */
900 op2.o_tag = LDAP_REQ_MODIFY;
901 op2.o_callback = &cb;
902 op2.orm_modlist = mod;
903 op2.o_dn = op->o_bd->be_rootdn;
904 op2.o_ndn = op->o_bd->be_rootndn;
905 op2.o_dont_replicate = 1;
906 rc = op->o_bd->be_modify( &op2, &r2 );
907 slap_mods_free( mod, 1 );
908 if (rc != LDAP_SUCCESS) {
909 /* slapd has logged this as a success already, but we
910 * need to fail it because the authTimestamp changed
911 * out from under us.
912 */
913 rs->sr_err = LDAP_INVALID_CREDENTIALS;
914 connection2anonymous(op->o_conn);
915 op2 = *op;
916 op2.o_callback = NULL;
917 send_ldap_result(&op2, rs);
918 op->o_bd->bd_info = bi;
919 return rs->sr_err;
920 }
921 }
922
923 op->o_bd->bd_info = bi;
924 return SLAP_CB_CONTINUE;
925 }
926
totp_op_bind(Operation * op,SlapReply * rs)927 static int totp_op_bind(
928 Operation *op,
929 SlapReply *rs )
930 {
931 /* If this is a simple Bind, stash the Op pointer so our chk
932 * function can find it. Set a cleanup callback to clear it
933 * out when the Bind completes.
934 */
935 if ( op->oq_bind.rb_method == LDAP_AUTH_SIMPLE ) {
936 slap_callback *cb;
937 ldap_pvt_thread_pool_setkey( op->o_threadctx,
938 totp_op_cleanup, op, 0, NULL, NULL );
939 cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
940 cb->sc_response = totp_bind_response;
941 cb->sc_cleanup = totp_op_cleanup;
942 cb->sc_next = op->o_callback;
943 op->o_callback = cb;
944 }
945 return SLAP_CB_CONTINUE;
946 }
947
totp_db_open(BackendDB * be,ConfigReply * cr)948 static int totp_db_open(
949 BackendDB *be,
950 ConfigReply *cr
951 )
952 {
953 int rc = 0;
954
955 if (!ad_authTimestamp) {
956 const char *text = NULL;
957 rc = slap_str2ad("authTimestamp", &ad_authTimestamp, &text);
958 if (rc) {
959 rc = register_at(totp_OpSchema[0].def, totp_OpSchema[0].ad, 0 );
960 if (rc) {
961 snprintf(cr->msg, sizeof(cr->msg), "unable to find or register authTimestamp attribute: %s (%d)",
962 text, rc);
963 Debug(LDAP_DEBUG_ANY, "totp: %s.\n", cr->msg );
964 }
965 ad_authTimestamp->ad_type->sat_flags |= SLAP_AT_MANAGEABLE;
966 }
967 }
968 return rc;
969 }
970
971 static slap_overinst totp;
972
973 int
totp_initialize(void)974 totp_initialize(void)
975 {
976 int rc;
977
978 totp.on_bi.bi_type = "totp";
979
980 totp.on_bi.bi_db_open = totp_db_open;
981 totp.on_bi.bi_op_bind = totp_op_bind;
982
983 rc = lutil_passwd_add((struct berval *) &scheme_totp1, chk_totp1, hash_totp1);
984 if (!rc)
985 rc = lutil_passwd_add((struct berval *) &scheme_totp256, chk_totp256, hash_totp256);
986 if (!rc)
987 rc = lutil_passwd_add((struct berval *) &scheme_totp512, chk_totp512, hash_totp512);
988 if (!rc)
989 rc = lutil_passwd_add((struct berval *) &scheme_totp1andpw, chk_totp1andpw, hash_totp1andpw);
990 if (!rc)
991 rc = lutil_passwd_add((struct berval *) &scheme_totp256andpw, chk_totp256andpw, hash_totp256andpw);
992 if (!rc)
993 rc = lutil_passwd_add((struct berval *) &scheme_totp512andpw, chk_totp512andpw, hash_totp512andpw);
994 if (rc)
995 return rc;
996
997 return overlay_register(&totp);
998 }
999
init_module(int argc,char * argv[])1000 int init_module(int argc, char *argv[]) {
1001 return totp_initialize();
1002 }
1003