mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-01-06 10:46:21 +08:00
Add TOTP pw mechanism
This commit is contained in:
parent
a23fc2fd94
commit
e069a79239
46
contrib/slapd-modules/passwd/totp/Makefile
Normal file
46
contrib/slapd-modules/passwd/totp/Makefile
Normal file
@ -0,0 +1,46 @@
|
||||
# $OpenLDAP$
|
||||
|
||||
LDAP_SRC = ../../../..
|
||||
LDAP_BUILD = $(LDAP_SRC)
|
||||
LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd
|
||||
LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \
|
||||
$(LDAP_BUILD)/libraries/liblber/liblber.la
|
||||
|
||||
LIBTOOL = $(LDAP_BUILD)/libtool
|
||||
CC = gcc
|
||||
OPT = -g -O2 -Wall
|
||||
DEFS =
|
||||
INCS = $(LDAP_INC)
|
||||
LIBS = $(LDAP_LIB)
|
||||
|
||||
PROGRAMS = pw-totp.la
|
||||
LTVER = 0:0:0
|
||||
|
||||
prefix=/usr/local
|
||||
exec_prefix=$(prefix)
|
||||
ldap_subdir=/openldap
|
||||
|
||||
libdir=$(exec_prefix)/lib
|
||||
libexecdir=$(exec_prefix)/libexec
|
||||
moduledir = $(libexecdir)$(ldap_subdir)
|
||||
|
||||
.SUFFIXES: .c .o .lo
|
||||
|
||||
.c.lo:
|
||||
$(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $<
|
||||
|
||||
all: $(PROGRAMS)
|
||||
|
||||
pw-totp.la: slapd-totp.lo
|
||||
$(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \
|
||||
-rpath $(moduledir) -module -o $@ $? $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.lo *.la .libs
|
||||
|
||||
install: $(PROGRAMS)
|
||||
mkdir -p $(DESTDIR)$(moduledir)
|
||||
for p in $(PROGRAMS) ; do \
|
||||
$(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \
|
||||
done
|
||||
|
75
contrib/slapd-modules/passwd/totp/README
Normal file
75
contrib/slapd-modules/passwd/totp/README
Normal file
@ -0,0 +1,75 @@
|
||||
TOTP OpenLDAP support
|
||||
----------------------
|
||||
|
||||
slapd-totp.c provides support for RFC 6238 TOTP Time-based One
|
||||
Time Passwords in OpenLDAP using SHA-1, SHA-256, and SHA-512.
|
||||
For instance, one could have the LDAP attribute:
|
||||
|
||||
userPassword: {TOTP1}GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ
|
||||
|
||||
which encodes the key '12345678901234567890'.
|
||||
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
1) Customize the LDAP_SRC variable in Makefile to point to the OpenLDAP
|
||||
source root.
|
||||
|
||||
2) Run 'make' to produce slapd-totp.so
|
||||
|
||||
3) Copy slapd-totp.so somewhere permanent.
|
||||
|
||||
4) Edit your slapd.conf (eg. /etc/ldap/slapd.conf), and add:
|
||||
|
||||
moduleload ...path/to/slapd-sha2.so
|
||||
|
||||
5) This module also requires the use of the slapo-lastbind overlay. You
|
||||
should build that module and also add it to your slapd configuration.
|
||||
|
||||
6) Restart slapd.
|
||||
|
||||
|
||||
Configuring
|
||||
-----------
|
||||
|
||||
The {TOTP1}, {TOTP256}, and {TOTP512} password schemes should now be recognised.
|
||||
|
||||
You can also tell OpenLDAP to use one of these new schemes when processing LDAP
|
||||
Password Modify Extended Operations, thanks to the password-hash option in
|
||||
slapd.conf. For example:
|
||||
|
||||
password-hash {TOTP1}
|
||||
|
||||
On the databases where your users reside you must configure both the
|
||||
lastbind overlay and the totp overlay:
|
||||
|
||||
database mdb
|
||||
...
|
||||
|
||||
overlay lastbind
|
||||
overlay totp
|
||||
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
The TOTP1 algorithm is compatible with Google Authenticator.
|
||||
|
||||
---
|
||||
|
||||
This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
|
||||
Copyright 2015 The OpenLDAP Foundation.
|
||||
Portions Copyright 2015 by Howard Chu, Symas Corp.
|
||||
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>.
|
||||
|
580
contrib/slapd-modules/passwd/totp/slapd-totp.c
Normal file
580
contrib/slapd-modules/passwd/totp/slapd-totp.c
Normal file
@ -0,0 +1,580 @@
|
||||
/* slapd-totp.c - Password module and overlay for TOTP */
|
||||
/* $OpenLDAP$ */
|
||||
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
||||
*
|
||||
* Copyright 2015 The OpenLDAP Foundation.
|
||||
* Portions Copyright 2015 by Howard Chu, Symas Corp.
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
#include <portable.h>
|
||||
|
||||
#include <lber.h>
|
||||
#include <lber_pvt.h>
|
||||
#include "lutil.h"
|
||||
#include <ac/stdlib.h>
|
||||
#include <ac/ctype.h>
|
||||
#include <ac/string.h>
|
||||
/* include socket.h to get sys/types.h and/or winsock2.h */
|
||||
#include <ac/socket.h>
|
||||
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#include "slap.h"
|
||||
#include "config.h"
|
||||
|
||||
static LUTIL_PASSWD_CHK_FUNC chk_totp1, chk_totp256, chk_totp512;
|
||||
static LUTIL_PASSWD_HASH_FUNC hash_totp1, hash_totp256, hash_totp512;
|
||||
static const struct berval scheme_totp1 = BER_BVC("{TOTP1}");
|
||||
static const struct berval scheme_totp256 = BER_BVC("{TOTP256}");
|
||||
static const struct berval scheme_totp512 = BER_BVC("{TOTP512}");
|
||||
|
||||
static AttributeDescription *ad_authTimestamp;
|
||||
|
||||
/* RFC3548 base32 encoding/decoding */
|
||||
|
||||
static const char Base32[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
static const char Pad32 = '=';
|
||||
|
||||
static int
|
||||
totp_b32_ntop(
|
||||
u_char const *src,
|
||||
size_t srclength,
|
||||
char *target,
|
||||
size_t targsize)
|
||||
{
|
||||
size_t datalength = 0;
|
||||
u_char input0;
|
||||
u_int input1; /* assumed to be at least 32 bits */
|
||||
u_char output[8];
|
||||
int i;
|
||||
|
||||
while (4 < srclength) {
|
||||
if (datalength + 8 > targsize)
|
||||
return (-1);
|
||||
input0 = *src++;
|
||||
input1 = *src++;
|
||||
input1 <<= 8;
|
||||
input1 |= *src++;
|
||||
input1 <<= 8;
|
||||
input1 |= *src++;
|
||||
input1 <<= 8;
|
||||
input1 |= *src++;
|
||||
srclength -= 5;
|
||||
|
||||
for (i=7; i>1; i--) {
|
||||
output[i] = input1 & 0x1f;
|
||||
input1 >>= 5;
|
||||
}
|
||||
output[0] = input0 >> 3;
|
||||
output[1] = (input0 & 0x07) << 2 | input1;
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
target[datalength++] = Base32[output[i]];
|
||||
}
|
||||
|
||||
/* Now we worry about padding. */
|
||||
if (0 != srclength) {
|
||||
static const int outlen[] = { 2,4,5,7 };
|
||||
int n;
|
||||
if (datalength + 8 > targsize)
|
||||
return (-1);
|
||||
|
||||
/* Get what's left. */
|
||||
input1 = *src++;
|
||||
for (i = 1; i < srclength; i++) {
|
||||
input1 <<= 8;
|
||||
input1 |= *src++;
|
||||
}
|
||||
input1 <<= 8 * (4-srclength);
|
||||
n = outlen[srclength-1];
|
||||
for (i=0; i<n; i++) {
|
||||
target[datalength++] = Base32[(input1 & 0xf8000000) >> 27];
|
||||
input1 <<= 5;
|
||||
}
|
||||
for (; i<8; i++)
|
||||
target[datalength++] = Pad32;
|
||||
}
|
||||
if (datalength >= targsize)
|
||||
return (-1);
|
||||
target[datalength] = '\0'; /* Returned value doesn't count \0. */
|
||||
return (datalength);
|
||||
}
|
||||
|
||||
/* converts characters, eight at a time, starting at src
|
||||
from base - 32 numbers into five 8 bit bytes in the target area.
|
||||
it returns the number of data bytes stored at the target, or -1 on error.
|
||||
*/
|
||||
|
||||
static int
|
||||
totp_b32_pton(
|
||||
char const *src,
|
||||
u_char *target,
|
||||
size_t targsize)
|
||||
{
|
||||
int tarindex, state, ch;
|
||||
char *pos;
|
||||
|
||||
state = 0;
|
||||
tarindex = 0;
|
||||
|
||||
while ((ch = *src++) != '\0') {
|
||||
if (ch == Pad32)
|
||||
break;
|
||||
|
||||
pos = strchr(Base32, ch);
|
||||
if (pos == 0) /* A non-base32 character. */
|
||||
return (-1);
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
if (target) {
|
||||
if ((size_t)tarindex >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] = (pos - Base32) << 3;
|
||||
}
|
||||
state = 1;
|
||||
break;
|
||||
case 1:
|
||||
if (target) {
|
||||
if ((size_t)tarindex + 1 >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= (pos - Base32) >> 2;
|
||||
target[tarindex+1] = ((pos - Base32) & 0x3)
|
||||
<< 6 ;
|
||||
}
|
||||
tarindex++;
|
||||
state = 2;
|
||||
break;
|
||||
case 2:
|
||||
if (target) {
|
||||
target[tarindex] |= (pos - Base32) << 1;
|
||||
}
|
||||
state = 3;
|
||||
break;
|
||||
case 3:
|
||||
if (target) {
|
||||
if ((size_t)tarindex + 1 >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= (pos - Base32) >> 4;
|
||||
target[tarindex+1] = ((pos - Base32) & 0xf)
|
||||
<< 4 ;
|
||||
}
|
||||
tarindex++;
|
||||
state = 4;
|
||||
break;
|
||||
case 4:
|
||||
if (target) {
|
||||
if ((size_t)tarindex + 1 >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= (pos - Base32) >> 1;
|
||||
target[tarindex+1] = ((pos - Base32) & 0x1)
|
||||
<< 7 ;
|
||||
}
|
||||
tarindex++;
|
||||
state = 5;
|
||||
break;
|
||||
case 5:
|
||||
if (target) {
|
||||
target[tarindex] |= (pos - Base32) << 2;
|
||||
}
|
||||
state = 6;
|
||||
break;
|
||||
case 6:
|
||||
if (target) {
|
||||
if ((size_t)tarindex + 1 >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= (pos - Base32) >> 3;
|
||||
target[tarindex+1] = ((pos - Base32) & 0x7)
|
||||
<< 5 ;
|
||||
}
|
||||
tarindex++;
|
||||
state = 7;
|
||||
break;
|
||||
case 7:
|
||||
if (target) {
|
||||
target[tarindex] |= (pos - Base32);
|
||||
}
|
||||
state = 0;
|
||||
tarindex++;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We are done decoding Base-32 chars. Let's see if we ended
|
||||
* on a byte boundary, and/or with erroneous trailing characters.
|
||||
*/
|
||||
|
||||
if (ch == Pad32) { /* We got a pad char. */
|
||||
int i = 1;
|
||||
|
||||
/* count pad chars */
|
||||
for (; ch; ch = *src++) {
|
||||
if (ch != Pad32)
|
||||
return (-1);
|
||||
i++;
|
||||
}
|
||||
/* there are only 4 valid ending states with a
|
||||
* pad character, make sure the number of pads is valid.
|
||||
*/
|
||||
switch(state) {
|
||||
case 2: if (i != 6) return -1;
|
||||
break;
|
||||
case 4: if (i != 4) return -1;
|
||||
break;
|
||||
case 5: if (i != 3) return -1;
|
||||
break;
|
||||
case 7: if (i != 1) return -1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Now make sure that the "extra" bits that slopped past
|
||||
* the last full byte were zeros. If we don't check them,
|
||||
* they become a subliminal channel.
|
||||
*/
|
||||
if (target && target[tarindex] != 0)
|
||||
return (-1);
|
||||
} else {
|
||||
/*
|
||||
* We ended by seeing the end of the string. Make sure we
|
||||
* have no partial bytes lying around.
|
||||
*/
|
||||
if (state != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (tarindex);
|
||||
}
|
||||
|
||||
/* RFC6238 TOTP */
|
||||
|
||||
#define HMAC_setup(ctx, key, len, hash) HMAC_CTX_init(&ctx); HMAC_Init_ex(&ctx, key, len, hash, 0)
|
||||
#define HMAC_crunch(ctx, buf, len) HMAC_Update(&ctx, buf, len)
|
||||
#define HMAC_finish(ctx, dig, dlen) HMAC_Final(&ctx, dig, &dlen); HMAC_CTX_cleanup(&ctx)
|
||||
|
||||
typedef struct myval {
|
||||
ber_len_t mv_len;
|
||||
void *mv_val;
|
||||
} myval;
|
||||
|
||||
static void do_hmac(
|
||||
const void *hash,
|
||||
myval *key,
|
||||
myval *data,
|
||||
myval *out)
|
||||
{
|
||||
HMAC_CTX ctx;
|
||||
unsigned int digestLen;
|
||||
|
||||
HMAC_setup(ctx, key->mv_val, key->mv_len, hash);
|
||||
HMAC_crunch(ctx, data->mv_val, data->mv_len);
|
||||
HMAC_finish(ctx, out->mv_val, digestLen);
|
||||
out->mv_len = digestLen;
|
||||
}
|
||||
|
||||
static const int DIGITS_POWER[] = {
|
||||
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
|
||||
|
||||
static void generate(
|
||||
myval *key,
|
||||
unsigned long tval,
|
||||
int digits,
|
||||
myval *out,
|
||||
const void *mech)
|
||||
{
|
||||
unsigned char digest[SHA512_DIGEST_LENGTH];
|
||||
myval digval;
|
||||
myval data;
|
||||
unsigned char msg[8];
|
||||
int i, offset, res, otp;
|
||||
|
||||
#if !WORDS_BIGENDIAN
|
||||
/* only needed on little-endian, can just use tval directly on big-endian */
|
||||
for (i=7; i>=0; i--) {
|
||||
msg[i] = tval & 0xff;
|
||||
tval >>= 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
data.mv_val = msg;
|
||||
data.mv_len = sizeof(msg);
|
||||
|
||||
digval.mv_val = digest;
|
||||
digval.mv_len = sizeof(digest);
|
||||
do_hmac(mech, key, &data, &digval);
|
||||
|
||||
offset = digest[digval.mv_len-1] & 0xf;
|
||||
res = ((digest[offset] & 0x7f) << 24) |
|
||||
((digest[offset+1] & 0xff) << 16) |
|
||||
((digest[offset+2] & 0xff) << 8) |
|
||||
(digest[offset+3] & 0xff);
|
||||
|
||||
otp = res % DIGITS_POWER[digits];
|
||||
out->mv_len = snprintf(out->mv_val, out->mv_len, "%0*d", digits, otp);
|
||||
}
|
||||
|
||||
static int totp_op_cleanup( Operation *op, SlapReply *rs );
|
||||
|
||||
#define TIME_STEP 30
|
||||
#define DIGITS 6
|
||||
|
||||
static int chk_totp(
|
||||
const struct berval *passwd,
|
||||
const struct berval *cred,
|
||||
const void *mech,
|
||||
const char **text)
|
||||
{
|
||||
void *ctx, *op_tmp;
|
||||
Operation *op;
|
||||
Entry *e;
|
||||
Attribute *a;
|
||||
long t = time(0L) / TIME_STEP;
|
||||
int rc;
|
||||
myval out, key;
|
||||
char outbuf[32];
|
||||
|
||||
/* Find our thread context, find our Operation */
|
||||
ctx = ldap_pvt_thread_pool_context();
|
||||
if (ldap_pvt_thread_pool_getkey(ctx, totp_op_cleanup, &op_tmp, NULL) ||
|
||||
!op_tmp)
|
||||
return LUTIL_PASSWD_ERR;
|
||||
op = op_tmp;
|
||||
|
||||
rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &e);
|
||||
if (rc != LDAP_SUCCESS) return LUTIL_PASSWD_ERR;
|
||||
|
||||
/* Make sure previous login is older than current time */
|
||||
a = attr_find(e->e_attrs, ad_authTimestamp);
|
||||
if (a) {
|
||||
struct lutil_tm tm;
|
||||
struct lutil_timet tt;
|
||||
if (lutil_parsetime(a->a_vals[0].bv_val, &tm) == 0 &&
|
||||
lutil_tm2time(&tm, &tt) == 0) {
|
||||
long told = tt.tt_sec / TIME_STEP;
|
||||
if (told >= t)
|
||||
rc = LUTIL_PASSWD_ERR;
|
||||
}
|
||||
} /* else no previous login, 1st use is OK */
|
||||
|
||||
be_entry_release_r(op, e);
|
||||
if (rc) return rc;
|
||||
|
||||
/* Key is stored in base32 */
|
||||
key.mv_len = passwd->bv_len * 5 / 8;
|
||||
key.mv_val = ber_memalloc(key.mv_len+1);
|
||||
|
||||
if (!key.mv_val)
|
||||
return LUTIL_PASSWD_ERR;
|
||||
|
||||
rc = totp_b32_pton(passwd->bv_val, key.mv_val, key.mv_len);
|
||||
if (rc < 1) {
|
||||
rc = LUTIL_PASSWD_ERR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out.mv_val = outbuf;
|
||||
out.mv_len = sizeof(outbuf);
|
||||
generate(&key, t, DIGITS, &out, mech);
|
||||
memset(key.mv_val, 0, key.mv_len);
|
||||
|
||||
/* compare */
|
||||
if (out.mv_len != cred->bv_len)
|
||||
return LUTIL_PASSWD_ERR;
|
||||
|
||||
rc = memcmp(out.mv_val, cred->bv_val, out.mv_len) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
|
||||
|
||||
out:
|
||||
ber_memfree(key.mv_val);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int chk_totp1(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
const struct berval *cred,
|
||||
const char **text)
|
||||
{
|
||||
return chk_totp(passwd, cred, EVP_sha1(), text);
|
||||
}
|
||||
|
||||
static int chk_totp256(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
const struct berval *cred,
|
||||
const char **text)
|
||||
{
|
||||
return chk_totp(passwd, cred, EVP_sha256(), text);
|
||||
}
|
||||
|
||||
static int chk_totp512(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
const struct berval *cred,
|
||||
const char **text)
|
||||
{
|
||||
return chk_totp(passwd, cred, EVP_sha512(), text);
|
||||
}
|
||||
|
||||
static int passwd_string32(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
struct berval *hash)
|
||||
{
|
||||
int b32len = (passwd->bv_len + 4)/5 * 8;
|
||||
int rc;
|
||||
hash->bv_len = scheme->bv_len + b32len;
|
||||
hash->bv_val = ber_memalloc(hash->bv_len + 1);
|
||||
AC_MEMCPY(hash->bv_val, scheme->bv_val, scheme->bv_len);
|
||||
rc = totp_b32_ntop((unsigned char *)passwd->bv_val, passwd->bv_len,
|
||||
hash->bv_val + scheme->bv_len, b32len+1);
|
||||
if (rc < 0) {
|
||||
ber_memfree(hash->bv_val);
|
||||
hash->bv_val = NULL;
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
return LUTIL_PASSWD_OK;
|
||||
}
|
||||
|
||||
static int hash_totp1(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
struct berval *hash,
|
||||
const char **text)
|
||||
{
|
||||
#if 0
|
||||
if (passwd->bv_len != SHA_DIGEST_LENGTH) {
|
||||
*text = "invalid key length";
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
#endif
|
||||
return passwd_string32(scheme, passwd, hash);
|
||||
}
|
||||
|
||||
static int hash_totp256(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
struct berval *hash,
|
||||
const char **text)
|
||||
{
|
||||
#if 0
|
||||
if (passwd->bv_len != SHA256_DIGEST_LENGTH) {
|
||||
*text = "invalid key length";
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
#endif
|
||||
return passwd_string32(scheme, passwd, hash);
|
||||
}
|
||||
|
||||
static int hash_totp512(
|
||||
const struct berval *scheme,
|
||||
const struct berval *passwd,
|
||||
struct berval *hash,
|
||||
const char **text)
|
||||
{
|
||||
#if 0
|
||||
if (passwd->bv_len != SHA512_DIGEST_LENGTH) {
|
||||
*text = "invalid key length";
|
||||
return LUTIL_PASSWD_ERR;
|
||||
}
|
||||
#endif
|
||||
return passwd_string32(scheme, passwd, hash);
|
||||
}
|
||||
|
||||
static int totp_op_cleanup(
|
||||
Operation *op,
|
||||
SlapReply *rs )
|
||||
{
|
||||
slap_callback *cb;
|
||||
|
||||
/* clear out the current key */
|
||||
ldap_pvt_thread_pool_setkey( op->o_threadctx, totp_op_cleanup,
|
||||
NULL, 0, NULL, NULL );
|
||||
|
||||
/* free the callback */
|
||||
cb = op->o_callback;
|
||||
op->o_callback = cb->sc_next;
|
||||
op->o_tmpfree( cb, op->o_tmpmemctx );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int totp_op_bind(
|
||||
Operation *op,
|
||||
SlapReply *rs )
|
||||
{
|
||||
/* If this is a simple Bind, stash the Op pointer so our chk
|
||||
* function can find it. Set a cleanup callback to clear it
|
||||
* out when the Bind completes.
|
||||
*/
|
||||
if ( op->oq_bind.rb_method == LDAP_AUTH_SIMPLE ) {
|
||||
slap_callback *cb;
|
||||
ldap_pvt_thread_pool_setkey( op->o_threadctx,
|
||||
totp_op_cleanup, op, 0, NULL, NULL );
|
||||
cb = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
|
||||
cb->sc_cleanup = totp_op_cleanup;
|
||||
cb->sc_next = op->o_callback;
|
||||
op->o_callback = cb;
|
||||
}
|
||||
return SLAP_CB_CONTINUE;
|
||||
}
|
||||
|
||||
static int totp_db_open(
|
||||
BackendDB *be,
|
||||
ConfigReply *cr
|
||||
)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!ad_authTimestamp) {
|
||||
const char *text = NULL;
|
||||
rc = slap_str2ad("authTimestamp", &ad_authTimestamp, &text);
|
||||
if (rc) {
|
||||
snprintf(cr->msg, sizeof(cr->msg), "unable to find authTimestamp attribute: %s (%d)",
|
||||
text, rc);
|
||||
Debug(LDAP_DEBUG_ANY, "totp: %s.\n", cr->msg, 0, 0);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static slap_overinst totp;
|
||||
|
||||
int
|
||||
totp_initialize(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
totp.on_bi.bi_type = "totp";
|
||||
|
||||
totp.on_bi.bi_db_open = totp_db_open;
|
||||
totp.on_bi.bi_op_bind = totp_op_bind;
|
||||
|
||||
rc = lutil_passwd_add((struct berval *) &scheme_totp1, chk_totp1, hash_totp1);
|
||||
if (!rc)
|
||||
rc = lutil_passwd_add((struct berval *) &scheme_totp256, chk_totp256, hash_totp256);
|
||||
if (!rc)
|
||||
rc = lutil_passwd_add((struct berval *) &scheme_totp512, chk_totp512, hash_totp512);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return overlay_register(&totp);
|
||||
}
|
||||
|
||||
int init_module(int argc, char *argv[]) {
|
||||
return totp_initialize();
|
||||
}
|
Loading…
Reference in New Issue
Block a user