[dovecot-cvs] dovecot/src/auth Makefile.am, 1.51, 1.52 mech-otp.c, NONE, 1.1 mech-skey.c, NONE, 1.1 mech.c, 1.56, 1.57 otp-skey-common.c, NONE, 1.1 otp-skey-common.h, NONE, 1.1 passdb.c, 1.43, 1.44 passdb.h, 1.35, 1.36 password-scheme-otp.c, NONE, 1.1 password-scheme.c, 1.24, 1.25 password-scheme.h, 1.8, 1.9

tss at dovecot.org tss at dovecot.org
Sun Nov 12 19:36:46 UTC 2006


Update of /var/lib/cvs/dovecot/src/auth
In directory talvi:/tmp/cvs-serv24954/src/auth

Modified Files:
	Makefile.am mech.c passdb.c passdb.h password-scheme.c 
	password-scheme.h 
Added Files:
	mech-otp.c mech-skey.c otp-skey-common.c otp-skey-common.h 
	password-scheme-otp.c 
Log Message:
Added OTP and S/KEY authentication mechanisms. Patch by Andrey Panin.



Index: Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/Makefile.am,v
retrieving revision 1.51
retrieving revision 1.52
diff -u -d -r1.51 -r1.52
--- Makefile.am	8 Oct 2006 21:25:17 -0000	1.51
+++ Makefile.am	12 Nov 2006 19:36:41 -0000	1.52
@@ -9,6 +9,7 @@
 	-I$(top_srcdir)/src/lib-sql \
 	-I$(top_srcdir)/src/lib-settings \
 	-I$(top_srcdir)/src/lib-ntlm \
+	-I$(top_srcdir)/src/lib-otp \
 	-DAUTH_MODULE_DIR=\""$(moduledir)/auth"\" \
 	-DPKG_LIBEXECDIR=\""$(pkglibexecdir)"\" \
 	$(AUTH_CFLAGS)
@@ -21,12 +22,14 @@
 	password-scheme-md5crypt.c \
 	password-scheme-cram-md5.c \
 	password-scheme-ntlm.c \
+	password-scheme-otp.c \
 	password-scheme-rpa.c
 
 dovecot_auth_LDADD = \
 	libpassword.a \
 	../lib-settings/libsettings.a \
 	../lib-ntlm/libntlm.a \
+	../lib-otp/libotp.a \
 	../lib-sql/libsql.a \
 	../lib/liblib.a \
 	$(AUTH_LIBS) \
@@ -56,9 +59,12 @@
 	mech-cram-md5.c \
 	mech-digest-md5.c \
 	mech-ntlm.c \
+	mech-otp.c \
+	mech-skey.c \
 	mech-gssapi.c \
 	mech-rpa.c \
 	mech-apop.c \
+	otp-skey-common.c \
 	passdb.c \
 	passdb-blocking.c \
 	passdb-bsdauth.c \
@@ -102,6 +108,7 @@
 	common.h \
 	mech.h \
 	mycrypt.h \
+	otp-skey-common.h \
 	passdb.h \
 	passdb-blocking.h \
 	passdb-cache.h \

--- NEW FILE: mech-otp.c ---
/*
 * One-Time-Password (RFC 2444) authentication mechanism.
 *
 * Copyright (c) 2006 Andrey Panin <pazke at donpac.ru>
 *
 * This software is released under the MIT license.
 */

#include "common.h"
#include "safe-memset.h"
#include "hash.h"
#include "mech.h"
#include "passdb.h"
#include "hex-binary.h"
#include "otp.h"
#include "otp-skey-common.h"

static void 
otp_send_challenge(struct auth_request *auth_request,
		   const char *credentials)
{
	struct otp_auth_request *request =
		(struct otp_auth_request *)auth_request;
	const char *answer;

	if (otp_parse_dbentry(credentials, &request->state) != 0) {
		auth_request_log_error(&request->auth_request, "otp",
				       "invalid OTP data in passdb");
		auth_request_fail(auth_request);
		return;
	}

	if (--request->state.seq < 1) {
		auth_request_log_error(&request->auth_request, "otp",
				       "sequence number < 1");
		auth_request_fail(auth_request);
		return;
	}

	request->lock = otp_try_lock(auth_request);
	if (!request->lock) {
		auth_request_log_error(&request->auth_request, "otp",
				       "user is locked, race attack?");
		auth_request_fail(auth_request);
		return;
	}

	answer = p_strdup_printf(request->pool, "otp-%s %u %s ext",
				 digest_name(request->state.algo),
				 request->state.seq, request->state.seed);

	auth_request->callback(auth_request,
			       AUTH_CLIENT_RESULT_CONTINUE,
			       answer, strlen(answer));
}

static void
skey_credentials_callback(enum passdb_result result,
			  const char *credentials,
			  struct auth_request *auth_request)
{
	switch (result) {
	case PASSDB_RESULT_OK:
		otp_send_challenge(auth_request, credentials);
		break;
	case PASSDB_RESULT_INTERNAL_FAILURE:
		auth_request_internal_failure(auth_request);
		break;
	default:
		auth_request_fail(auth_request);
		break;
	}
}

static void
otp_credentials_callback(enum passdb_result result,
			 const char *credentials,
			 struct auth_request *auth_request)
{
	switch (result) {
	case PASSDB_RESULT_OK:
		otp_send_challenge(auth_request, credentials);
		break;
	case PASSDB_RESULT_INTERNAL_FAILURE:
		auth_request_internal_failure(auth_request);
		break;
	default:
		/* OTP credentials not found, try S/KEY */
		auth_request_lookup_credentials(auth_request,
						PASSDB_CREDENTIALS_OTP,
						skey_credentials_callback);
		break;
	}
}

static void
mech_otp_auth_phase1(struct auth_request *auth_request,
		     const unsigned char *data, size_t data_size)
{
	struct otp_auth_request *request =
		(struct otp_auth_request *)auth_request;
	const char *authzid, *authenid, *error;
	size_t i, count;

	/* authorization ID \0 authentication ID
	   FIXME: we'll ignore authorization ID for now. */
	authzid = (const char *) data;
	authenid = NULL;

	count = 0;
	for (i = 0; i < data_size; i++) {
		if (data[i] == '\0') {
			if (++count == 1)
				authenid = (const char *) data + i + 1;
		}
	}

	if ((count < 1) || (count > 2)) {
		auth_request_log_error(&request->auth_request, "otp",
                                       "invalid input");
		auth_request_fail(auth_request);
		return;
	}

	if (!auth_request_set_username(auth_request, authenid, &error)) {
		auth_request_log_info(auth_request, "otp", "%s", error);
		auth_request_fail(auth_request);
		return;
	}

	auth_request_lookup_credentials(auth_request, PASSDB_CREDENTIALS_OTP,
					otp_credentials_callback);
}

static void mech_otp_verify(struct auth_request *auth_request,
			    const char *data, bool hex)
{
	struct otp_auth_request *request =
		(struct otp_auth_request *)auth_request;
	struct otp_state *state = &request->state;
	unsigned char hash[OTP_HASH_SIZE], cur_hash[OTP_HASH_SIZE];
	int ret;

	ret = otp_parse_response(data, hash, hex);
	if (ret < 0) {
		auth_request_log_error(&request->auth_request, "otp",
				       "invalid response");
		auth_request_fail(auth_request);
		otp_unlock(auth_request);
		return;
	}

	otp_next_hash(state->algo, hash, cur_hash);

	ret = memcmp(cur_hash, state->hash, OTP_HASH_SIZE);
	if (ret != 0) {
		auth_request_fail(auth_request);
		otp_unlock(auth_request);
		return;
	}

	memcpy(state->hash, hash, sizeof(state->hash));

	auth_request_set_credentials(auth_request,
				     PASSDB_CREDENTIALS_OTP,
				     otp_print_dbentry(state),
				     otp_set_credentials_callback);
}

static void mech_otp_verify_init(struct auth_request *auth_request,
				 const char *data, bool hex)
{
	struct otp_auth_request *request =
		(struct otp_auth_request *)auth_request;
	struct otp_state new_state;
	unsigned char hash[OTP_HASH_SIZE], cur_hash[OTP_HASH_SIZE];
	const char *error;
	int ret;

	ret = otp_parse_init_response(data, &new_state, cur_hash, hex, &error);
	if (ret < 0) {
		auth_request_log_error(&request->auth_request, "otp",
                                       "invalid init response, %s", error);
		auth_request_fail(auth_request);
		otp_unlock(auth_request);
		return;
	}

	otp_next_hash(request->state.algo, cur_hash, hash);

	ret = memcmp(hash, request->state.hash, OTP_HASH_SIZE);
	if (ret != 0) {
		auth_request_fail(auth_request);
		otp_unlock(auth_request);
		return;
	}

	auth_request_set_credentials(auth_request,
				     PASSDB_CREDENTIALS_OTP,
				     otp_print_dbentry(&new_state),
				     otp_set_credentials_callback);
}

static void
mech_otp_auth_phase2(struct auth_request *auth_request,
		     const unsigned char *data, size_t data_size)
{
	const char *str = t_strndup(data, data_size);

	if (strncmp(str, "hex:", 4) == 0) {
		mech_otp_verify(auth_request, str + 4, TRUE);
	} else if (strncmp(str, "word:", 5) == 0) {
		mech_otp_verify(auth_request, str + 5, FALSE);
	} else if (strncmp(str, "init-hex:", 9) == 0) {
		mech_otp_verify_init(auth_request, str + 9, TRUE);
	} else if (strncmp(str, "init-word:", 10) == 0) {
		mech_otp_verify_init(auth_request, str + 10, FALSE);
	} else {
		auth_request_log_error(auth_request, "otp",
				       "unsupported response type");
		auth_request_fail(auth_request);
		otp_unlock(auth_request);
	}
}

static void
mech_otp_auth_continue(struct auth_request *auth_request,
		       const unsigned char *data, size_t data_size)
{
	if (auth_request->user == NULL) {
		mech_otp_auth_phase1(auth_request, data, data_size);
	} else {
		mech_otp_auth_phase2(auth_request, data, data_size);
	}
}

static struct auth_request *mech_otp_auth_new(void)
{
	struct otp_auth_request *request;
	pool_t pool;

	otp_lock_init();

	pool = pool_alloconly_create("otp_auth_request", 256);
	request = p_new(pool, struct otp_auth_request, 1);
	request->pool = pool;
	request->lock = FALSE;

	request->auth_request.refcount = 1;
	request->auth_request.pool = pool;
	return &request->auth_request;
}

const struct mech_module mech_otp = {
	"OTP",

	MEMBER(flags) MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE,

	MEMBER(passdb_need_plain) FALSE,
	MEMBER(passdb_need_credentials) TRUE,
	MEMBER(passdb_need_set_credentials) TRUE,

	mech_otp_auth_new,
	mech_generic_auth_initial,
	mech_otp_auth_continue,
	mech_otp_skey_auth_free
};

--- NEW FILE: mech-skey.c ---
/*
 * S/Key (RFC 1731) authentication mechanism.
 *
 * Copyright (c) 2006 Andrey Panin <pazke at donpac.ru>
 *
 * This software is released under the MIT license.
 */

#include "common.h"
#include "safe-memset.h"
#include "hash.h"
#include "mech.h"
#include "passdb.h"
#include "hex-binary.h"
#include "otp.h"
#include "otp-skey-common.h"

static void 
skey_send_challenge(struct auth_request *auth_request,
		    const char *credentials)
{
	struct otp_auth_request *request =
		(struct otp_auth_request *)auth_request;
	const char *answer;

	if (otp_parse_dbentry(credentials, &request->state) != 0) {
		auth_request_log_error(&request->auth_request, "skey",
				       "invalid OTP data in passdb");
		auth_request_fail(auth_request);
		return;
	}

	if (request->state.algo != OTP_HASH_MD4) {
		auth_request_log_error(&request->auth_request, "skey",
				       "md4 hash is needed");
		auth_request_fail(auth_request);
		return;
	}

	if (--request->state.seq < 1) {
		auth_request_log_error(&request->auth_request, "skey",
				       "sequence number < 1");
		auth_request_fail(auth_request);
		return;
	}

	request->lock = otp_try_lock(auth_request);
	if (!request->lock) {
		auth_request_log_error(&request->auth_request, "skey",
				       "user is locked, race attack?");
		auth_request_fail(auth_request);
		return;
	}

	answer = p_strdup_printf(request->pool, "%u %s",
				 request->state.seq, request->state.seed);

	auth_request->callback(auth_request,
			       AUTH_CLIENT_RESULT_CONTINUE,
			       answer, strlen(answer));
}

static void
otp_credentials_callback(enum passdb_result result,
			 const char *credentials,
			 struct auth_request *auth_request)
{
	switch (result) {
	case PASSDB_RESULT_OK:
		skey_send_challenge(auth_request, credentials);
		break;
	case PASSDB_RESULT_INTERNAL_FAILURE:
		auth_request_internal_failure(auth_request);
		break;
	default:
		auth_request_fail(auth_request);
		break;
	}
}

static void
skey_credentials_callback(enum passdb_result result,
			  const char *credentials,
			  struct auth_request *auth_request)
{
	switch (result) {
	case PASSDB_RESULT_OK:
		skey_send_challenge(auth_request, credentials);
		break;
	case PASSDB_RESULT_INTERNAL_FAILURE:
		auth_request_internal_failure(auth_request);
		break;
	default:
		/* S/KEY credentials not found, try OTP */
		auth_request_lookup_credentials(auth_request,
						PASSDB_CREDENTIALS_OTP,
						otp_credentials_callback);
		break;
	}
}

static void
mech_skey_auth_phase1(struct auth_request *auth_request,
		      const unsigned char *data, size_t data_size)
{
	const char *username, *error;

	username = t_strndup(data, data_size);

	if (!auth_request_set_username(auth_request, username, &error)) {
		auth_request_log_info(auth_request, "skey", "%s", error);
		auth_request_fail(auth_request);
		return;
	}

	auth_request_lookup_credentials(auth_request, PASSDB_CREDENTIALS_SKEY,
					skey_credentials_callback);
}

static void
mech_skey_auth_phase2(struct auth_request *auth_request,
		      const unsigned char *data, size_t data_size)
{
	struct otp_auth_request *request =
		(struct otp_auth_request *)auth_request;
	struct otp_state *state = &request->state;
	unsigned char hash[OTP_HASH_SIZE], cur_hash[OTP_HASH_SIZE];
	int ret;

	if (data_size == 8) {
		memcpy(hash, data, 8);
	} else {
		const char *words = t_strndup(data, data_size);

		ret = otp_parse_response(words, hash, 0);
		if (ret < 0) {
			auth_request_log_error(&request->auth_request, "skey",
					       "invalid response");
			auth_request_fail(auth_request);
			otp_unlock(auth_request);
			return;
		}
	}

	otp_next_hash(state->algo, hash, cur_hash);

	ret = memcmp(cur_hash, state->hash, OTP_HASH_SIZE);
	if (ret != 0) {
		auth_request_fail(auth_request);
		otp_unlock(auth_request);
		return;
	}

	memcpy(state->hash, hash, sizeof(state->hash));

	auth_request_set_credentials(auth_request,
				     PASSDB_CREDENTIALS_OTP,
				     otp_print_dbentry(state),
				     otp_set_credentials_callback);
}

static void
mech_skey_auth_continue(struct auth_request *auth_request,
		       const unsigned char *data, size_t data_size)
{
	if (auth_request->user == NULL) {
		mech_skey_auth_phase1(auth_request, data, data_size);
	} else {
		mech_skey_auth_phase2(auth_request, data, data_size);
	}
}

static struct auth_request *mech_skey_auth_new(void)
{
	struct otp_auth_request *request;
	pool_t pool;

	otp_lock_init();

	pool = pool_alloconly_create("skey_auth_request", 256);
	request = p_new(pool, struct otp_auth_request, 1);
	request->pool = pool;
	request->lock = FALSE;

	request->auth_request.refcount = 1;
	request->auth_request.pool = pool;
	return &request->auth_request;
}

const struct mech_module mech_skey = {
	"SKEY",

	MEMBER(flags) MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE,

	MEMBER(passdb_need_plain) FALSE,
	MEMBER(passdb_need_credentials) TRUE,
	MEMBER(passdb_need_set_credentials) TRUE,

	mech_skey_auth_new,
	mech_generic_auth_initial,
	mech_skey_auth_continue,
	mech_otp_skey_auth_free
};

Index: mech.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/mech.c,v
retrieving revision 1.56
retrieving revision 1.57
diff -u -d -r1.56 -r1.57
--- mech.c	17 Jun 2006 19:15:20 -0000	1.56
+++ mech.c	12 Nov 2006 19:36:41 -0000	1.57
@@ -68,6 +68,8 @@
 extern struct mech_module mech_cram_md5;
 extern struct mech_module mech_digest_md5;
 extern struct mech_module mech_ntlm;
+extern struct mech_module mech_otp;
+extern struct mech_module mech_skey;
 extern struct mech_module mech_rpa;
 extern struct mech_module mech_anonymous;
 #ifdef HAVE_GSSAPI
@@ -82,6 +84,8 @@
 	mech_register_module(&mech_cram_md5);
 	mech_register_module(&mech_digest_md5);
 	mech_register_module(&mech_ntlm);
+	mech_register_module(&mech_otp);
+	mech_register_module(&mech_skey);
 	mech_register_module(&mech_rpa);
 	mech_register_module(&mech_anonymous);
 #ifdef HAVE_GSSAPI
@@ -97,6 +101,8 @@
 	mech_unregister_module(&mech_cram_md5);
 	mech_unregister_module(&mech_digest_md5);
 	mech_unregister_module(&mech_ntlm);
+	mech_unregister_module(&mech_otp);
+	mech_unregister_module(&mech_skey);
 	mech_unregister_module(&mech_rpa);
 	mech_unregister_module(&mech_anonymous);
 #ifdef HAVE_GSSAPI

--- NEW FILE: otp-skey-common.c ---
/*
 * Common code for OTP and SKEY authentication mechanisms.
 *
 * Copyright (c) 2006 Andrey Panin <pazke at donpac.ru>
 *
 * This software is released under the MIT license.
 */

#include "common.h"
#include "hash.h"
#include "mech.h"

#include "otp.h"
#include "otp-skey-common.h"

static struct hash_table *otp_lock_table;

void otp_lock_init(void)
{
	if (otp_lock_table != NULL)
		return;

	otp_lock_table = hash_create(system_pool, system_pool,
				     128, strcase_hash,
				     (hash_cmp_callback_t *)strcasecmp);
}

int otp_try_lock(struct auth_request *auth_request)
{
	if (hash_lookup(otp_lock_table, auth_request->user))
		return FALSE;

	hash_insert(otp_lock_table, auth_request->user, auth_request);

	return TRUE;
}

void otp_unlock(struct auth_request *auth_request)
{
	struct otp_auth_request *request =
		(struct otp_auth_request *)auth_request;

	if (!request->lock)
		return;

	hash_remove(otp_lock_table, auth_request->user);
	request->lock = FALSE;
}

void otp_set_credentials_callback(enum passdb_result result,
				  struct auth_request *auth_request)
{
	switch (result) {
	case PASSDB_RESULT_OK:
		auth_request_success(auth_request, NULL, 0);
		break;
	default:
		auth_request_internal_failure(auth_request);
		otp_unlock(auth_request);
		break;
	}

	otp_unlock(auth_request);
}

void mech_otp_skey_auth_free(struct auth_request *auth_request)
{
	otp_unlock(auth_request);

	pool_unref(auth_request->pool);
}

--- NEW FILE: otp-skey-common.h ---
#ifndef __OTP_SKEY_COMMON_H__
#define __OTP_SKEY_COMMON_H__

struct otp_auth_request {
	struct auth_request auth_request;

	pool_t pool;

	int lock;

	struct otp_state state;
};

void otp_lock_init(void);
int otp_try_lock(struct auth_request *auth_request);
void otp_unlock(struct auth_request *auth_request);

void otp_set_credentials_callback(enum passdb_result result,
				  struct auth_request *auth_request);
void mech_otp_skey_auth_free(struct auth_request *auth_request);

#endif	/* __OTP_SKEY_COMMON_H__ */

Index: passdb.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -d -r1.43 -r1.44
--- passdb.c	8 Oct 2006 21:25:17 -0000	1.43
+++ passdb.c	12 Nov 2006 19:36:41 -0000	1.44
@@ -71,6 +71,10 @@
 		return "LANMAN";
 	case PASSDB_CREDENTIALS_NTLM:
 		return "NTLM";
+	case PASSDB_CREDENTIALS_OTP:
+		return "OTP";
+	case PASSDB_CREDENTIALS_SKEY:
+		return "SKEY";
 	case PASSDB_CREDENTIALS_RPA:
 		return "RPA";
 	}

Index: passdb.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb.h,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -d -r1.35 -r1.36
--- passdb.h	8 Nov 2006 20:22:08 -0000	1.35
+++ passdb.h	12 Nov 2006 19:36:41 -0000	1.36
@@ -15,6 +15,8 @@
 	PASSDB_CREDENTIALS_DIGEST_MD5,
 	PASSDB_CREDENTIALS_LANMAN,
 	PASSDB_CREDENTIALS_NTLM,
+	PASSDB_CREDENTIALS_OTP,
+	PASSDB_CREDENTIALS_SKEY,
 	PASSDB_CREDENTIALS_RPA
 };
 

--- NEW FILE: password-scheme-otp.c ---
/*
 * OTP password scheme.
 *
 * Copyright (c) 2006 Andrey Panin <pazke at donpac.ru>
 *
 * This software is released under the MIT license.
 */

#include "lib.h"
#include "hex-binary.h"
#include "password-scheme.h"
#include "randgen.h"
#include "otp.h"

const char *password_generate_otp(const char *pw, const char *data,
				  unsigned int algo)
{
	struct otp_state state;

	if (data != NULL) {
		if (otp_parse_dbentry(data, &state) != 0) {
			i_warning("Invalid OTP data in passdb");
			return "";
		}
	} else {
		/* Generate new OTP credentials from plaintext */
		unsigned char random_data[OTP_MAX_SEED_LEN / 2];

		random_fill(random_data, sizeof(random_data));
		strocpy(state.seed, binary_to_hex(random_data,
			OTP_MAX_SEED_LEN / 2), sizeof(state.seed));

		state.seq = 1024;
		state.algo = algo;
	}

	otp_hash(state.algo, state.seed, pw, state.seq, state.hash);

	return otp_print_dbentry(&state);
}

Index: password-scheme.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/password-scheme.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- password-scheme.c	8 Oct 2006 23:18:18 -0000	1.24
+++ password-scheme.c	12 Nov 2006 19:36:41 -0000	1.25
@@ -10,6 +10,7 @@
 #include "mycrypt.h"
 #include "randgen.h"
 #include "sha1.h"
+#include "otp.h"
 #include "str.h"
 #include "password-scheme.h"
 
@@ -448,6 +449,25 @@
 	return password_generate_ntlm(plaintext);
 }
 
+static bool otp_verify(const char *plaintext, const char *password,
+		       const char *user __attr_unused__)
+{
+	return strcasecmp(password,
+		password_generate_otp(plaintext, password, -1)) == 0;
+}
+
+static const char *otp_generate(const char *plaintext,
+				const char *user __attr_unused__)
+{
+	return password_generate_otp(plaintext, NULL, OTP_HASH_SHA1);
+}
+
+static const char *skey_generate(const char *plaintext,
+				 const char *user __attr_unused__)
+{
+	return password_generate_otp(plaintext, NULL, OTP_HASH_MD4);
+}
+
 static bool rpa_verify(const char *plaintext, const char *password,
 		       const char *user __attr_unused__)
 {
@@ -476,6 +496,8 @@
 	{ "LDAP-MD5", plain_md5_verify, ldap_md5_generate },
 	{ "LANMAN", lm_verify, lm_generate },
 	{ "NTLM", ntlm_verify, ntlm_generate },
+	{ "OTP", otp_verify, otp_generate },
+	{ "SKEY", otp_verify, skey_generate },
 	{ "RPA", rpa_verify, rpa_generate },
 	{ NULL, NULL, NULL }
 };

Index: password-scheme.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/password-scheme.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- password-scheme.h	13 Jan 2006 20:25:57 -0000	1.8
+++ password-scheme.h	12 Nov 2006 19:36:41 -0000	1.9
@@ -32,6 +32,8 @@
 const char *password_generate_cram_md5(const char *pw);
 const char *password_generate_lm(const char *pw);
 const char *password_generate_ntlm(const char *pw);
+const char *password_generate_otp(const char *pw, const char *state,
+				  unsigned int algo);
 const char *password_generate_rpa(const char *pw);
 
 #endif



More information about the dovecot-cvs mailing list