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