[Dovecot] [PATCH, RFC] add APOP authentication mechanism

Andrey Panin pazke at donpac.ru
Thu Jul 1 13:30:44 EEST 2004


Hello all,

this patch add APOP authentication mechanism to dovecot 1.0-test23.
Please take a look.

Best regards.

-- 
Andrey Panin		| Linux and UNIX system administrator
pazke at donpac.ru		| PGP key: wwwkeys.pgp.net
-------------- next part --------------
diff -udrpN -X /usr/share/dontdiff -x Makefile dovecot-1.0-test23.vanilla/src/auth/Makefile.am dovecot-1.0-test23/src/auth/Makefile.am
--- dovecot-1.0-test23.vanilla/src/auth/Makefile.am	2004-06-24 12:14:13.000000000 +0400
+++ dovecot-1.0-test23/src/auth/Makefile.am	2004-07-01 11:38:32.000000000 +0400
@@ -31,6 +31,7 @@ dovecot_auth_SOURCES = \
 	mech-plain.c \
 	mech-cram-md5.c \
 	mech-digest-md5.c \
+	mech-apop.c \
 	mycrypt.c \
 	passdb.c \
 	passdb-bsdauth.c \
diff -udrpN -X /usr/share/dontdiff -x Makefile dovecot-1.0-test23.vanilla/src/auth/mech-apop.c dovecot-1.0-test23/src/auth/mech-apop.c
--- dovecot-1.0-test23.vanilla/src/auth/mech-apop.c	1970-01-01 03:00:00.000000000 +0300
+++ dovecot-1.0-test23/src/auth/mech-apop.c	2004-07-01 11:38:32.000000000 +0400
@@ -0,0 +1,183 @@
+/*
+ * APOP (RFC-1460) authentication mechanism.
+ *
+ * Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published 
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "common.h"
+#include "safe-memset.h"
+#include "mech.h"
+#include "passdb.h"
+#include "md5.h"
+#include "buffer.h"
+#include "hex-binary.h"
+
+#include <ctype.h>
+
+struct apop_auth_request {
+	struct auth_request auth_request;
+
+	pool_t pool;
+
+	/* requested: */
+	char *challenge;
+
+	/* received: */
+	char *username;
+	char *digest;
+	unsigned long maxbuf;
+};
+
+static void
+apop_credentials_callback(const char *credentials,
+			  struct auth_request *auth_request)
+{
+	struct apop_auth_request *auth =
+		(struct apop_auth_request *)auth_request;
+	buffer_t *digest_buf;
+	unsigned char remote_digest[16];
+	unsigned char digest[16];
+	struct md5_context ctx;
+
+	digest_buf = buffer_create_data(pool_datastack_create(),
+					remote_digest, sizeof(remote_digest));
+	if (hex_to_binary(auth->digest, digest_buf) <= 0) {
+		if (verbose)
+			i_info("apop(%s): invalid characters in APOP digest", get_log_prefix(auth_request));
+		mech_auth_finish(auth_request, NULL, 0, FALSE);
+		return;
+	}
+
+	md5_init(&ctx);
+	md5_update(&ctx, auth->challenge, strlen(auth->challenge));
+	md5_update(&ctx, credentials, strlen(credentials));
+	md5_final(&ctx, digest);
+
+	safe_memset((void *) credentials, 0, strlen(credentials));
+
+	mech_auth_finish(auth_request, NULL, 0,
+			 memcmp(digest, remote_digest, 16) ? FALSE : TRUE);
+}
+
+static int
+mech_apop_auth_initial(struct auth_request *auth_request,
+			struct auth_client_request_new *request,
+			const unsigned char *data,
+			mech_callback_t *callback)
+{
+	struct apop_auth_request *auth =
+		(struct apop_auth_request *)auth_request;
+	const unsigned char *tmp, *end, *username;
+
+	auth_request->callback = callback;
+
+	if (strcmp(auth_request->protocol, "POP3")) {
+		if (verbose)
+			i_info("apop(%s): wrong protocol %s", get_log_prefix(auth_request),
+				auth_request->protocol);
+		mech_auth_finish(auth_request, NULL, 0, FALSE);
+		return TRUE;
+	}
+
+	if (!AUTH_CLIENT_REQUEST_HAVE_INITIAL_RESPONSE(request)) {
+		/* Should never happen */
+		if (verbose)
+			i_info("apop(%s): no initial respone", get_log_prefix(auth_request));
+		mech_auth_finish(auth_request, NULL, 0, FALSE);
+		return TRUE;
+	}
+
+	tmp = data = data + request->initial_resp_idx;
+	end = data + request->data_size - request->initial_resp_idx;
+
+	while (*tmp && (tmp < end))
+		tmp++;
+
+	if (tmp == end) {
+		/* Should never happen */
+		if (verbose)
+			i_info("apop(%s): mailformed data", get_log_prefix(auth_request));
+		mech_auth_finish(auth_request, NULL, 0, FALSE);
+		return TRUE;
+	}
+	tmp++;
+
+	auth->challenge = p_strdup(auth->pool, data);
+
+	username = tmp;
+	while (*tmp && !isspace(*tmp) && (tmp < end))
+		tmp++;
+
+	if (tmp == end) {
+		if (verbose)
+			i_info("apop(%s): mailformed response", get_log_prefix(auth_request));
+		mech_auth_finish(auth_request, NULL, 0, FALSE);
+		return TRUE;
+	}
+	tmp++;
+
+	auth->username = p_strndup(auth->pool, username, tmp - username - 1);
+	if (!mech_is_valid_username(auth->username)) {
+		if (verbose)
+			i_info("apop(%s): invalid username", get_log_prefix(auth_request));
+		mech_auth_finish(auth_request, NULL, 0, FALSE);
+		return TRUE;
+	}
+
+	auth_request->user = p_strdup(auth->pool, auth->username);
+
+	if ((end - tmp) != 32) {
+		if (verbose)
+			i_info("apop(%s): wrong APOP digest length", get_log_prefix(auth_request));
+		mech_auth_finish(auth_request, NULL, 0, FALSE);
+		return TRUE;
+	}
+
+	auth->digest = p_strndup(auth->pool, tmp, 32);
+
+	passdb->lookup_credentials(auth_request, PASSDB_CREDENTIALS_PLAINTEXT,
+				   apop_credentials_callback);
+
+	return TRUE;
+}
+
+static void
+mech_apop_auth_free(struct auth_request *auth_request)
+{
+	pool_unref(auth_request->pool);
+}
+
+static struct auth_request *mech_apop_auth_new(void)
+{
+	struct apop_auth_request *auth;
+	pool_t pool;
+
+	pool = pool_alloconly_create("apop_auth_request", 256);
+	auth = p_new(pool, struct apop_auth_request, 1);
+	auth->pool = pool;
+
+	auth->auth_request.refcount = 1;
+	auth->auth_request.pool = pool;
+	auth->auth_request.auth_initial = mech_apop_auth_initial;
+	auth->auth_request.auth_continue = NULL;
+	auth->auth_request.auth_free = mech_apop_auth_free;
+
+	return &auth->auth_request;
+}
+
+const struct mech_module mech_apop = {
+	"APOP",
+
+	MEMBER(plaintext) FALSE,
+	MEMBER(advertise) FALSE,
+
+	MEMBER(passdb_need_plain) FALSE,
+	MEMBER(passdb_need_credentials) TRUE,
+
+	mech_apop_auth_new,
+};
diff -udrpN -X /usr/share/dontdiff -x Makefile dovecot-1.0-test23.vanilla/src/auth/mech.c dovecot-1.0-test23/src/auth/mech.c
--- dovecot-1.0-test23.vanilla/src/auth/mech.c	2004-06-01 00:10:02.000000000 +0400
+++ dovecot-1.0-test23/src/auth/mech.c	2004-07-01 11:38:33.000000000 +0400
@@ -384,6 +384,7 @@ static void auth_failure_timeout(void *c
 }
 
 extern struct mech_module mech_plain;
+extern struct mech_module mech_apop;
 extern struct mech_module mech_cram_md5;
 extern struct mech_module mech_digest_md5;
 extern struct mech_module mech_anonymous;
@@ -411,6 +412,8 @@ void mech_init(void)
 	while (*mechanisms != NULL) {
 		if (strcasecmp(*mechanisms, "PLAIN") == 0)
 			mech_register_module(&mech_plain);
+		else if (strcasecmp(*mechanisms, "APOP") == 0)
+			mech_register_module(&mech_apop);
 		else if (strcasecmp(*mechanisms, "CRAM-MD5") == 0)
 			mech_register_module(&mech_cram_md5);
 		else if (strcasecmp(*mechanisms, "DIGEST-MD5") == 0)
@@ -471,6 +474,7 @@ void mech_deinit(void)
 	timeout_remove(to_auth_failures);
 
 	mech_unregister_module(&mech_plain);
+	mech_unregister_module(&mech_apop);
 	mech_unregister_module(&mech_cram_md5);
 	mech_unregister_module(&mech_digest_md5);
 	mech_unregister_module(&mech_anonymous);
diff -udrpN -X /usr/share/dontdiff -x Makefile dovecot-1.0-test23.vanilla/src/pop3-login/client-authenticate.c dovecot-1.0-test23/src/pop3-login/client-authenticate.c
--- dovecot-1.0-test23.vanilla/src/pop3-login/client-authenticate.c	2004-06-24 12:14:14.000000000 +0400
+++ dovecot-1.0-test23/src/pop3-login/client-authenticate.c	2004-07-01 11:38:33.000000000 +0400
@@ -338,3 +338,49 @@ int cmd_auth(struct pop3_client *client,
 
 	return TRUE;
 }
+
+int cmd_apop(struct pop3_client *client, const char *args)
+{
+	const char *error;
+	struct auth_request_info info;
+	string_t *apop_data;
+
+	if (!client->apop_challenge) {
+	        client_send_line(client, "-ERR Unknown command.");
+		return TRUE;
+	}
+
+	/* APOP challenge \0 APOP responce */
+	apop_data = t_str_new(128);
+	str_append(apop_data, client->apop_challenge);
+	str_append_c(apop_data, '\0');
+	str_append(apop_data, args);
+
+	memset(&info, 0, sizeof(info));
+	info.mech = "APOP";
+	info.protocol = "POP3";
+	info.flags = client_get_auth_flags(client);
+	info.local_ip = client->common.local_ip;
+	info.remote_ip = client->common.ip;
+	info.initial_resp_data = str_data(apop_data);
+	info.initial_resp_size = str_len(apop_data);
+
+	client_ref(client);
+	client->common.auth_request =
+		auth_client_request_new(auth_client, &info,
+					login_callback, client, &error);
+
+	if (client->common.auth_request != NULL) {
+		/* don't read any input from client until login is finished */
+		if (client->common.io != NULL) {
+			io_remove(client->common.io);
+			client->common.io = NULL;
+		}
+		return TRUE;
+	} else {
+		client_send_line(client,
+			t_strconcat("-ERR Login failed: ", error, NULL));
+		client_unref(client);
+		return TRUE;
+	}
+}
diff -udrpN -X /usr/share/dontdiff -x Makefile dovecot-1.0-test23.vanilla/src/pop3-login/client-authenticate.h dovecot-1.0-test23/src/pop3-login/client-authenticate.h
--- dovecot-1.0-test23.vanilla/src/pop3-login/client-authenticate.h	2003-01-30 22:52:39.000000000 +0300
+++ dovecot-1.0-test23/src/pop3-login/client-authenticate.h	2004-07-01 11:38:33.000000000 +0400
@@ -5,5 +5,6 @@ int cmd_capa(struct pop3_client *client,
 int cmd_user(struct pop3_client *client, const char *args);
 int cmd_pass(struct pop3_client *client, const char *args);
 int cmd_auth(struct pop3_client *client, const char *args);
+int cmd_apop(struct pop3_client *client, const char *args);
 
 #endif
diff -udrpN -X /usr/share/dontdiff -x Makefile dovecot-1.0-test23.vanilla/src/pop3-login/client.c dovecot-1.0-test23/src/pop3-login/client.c
--- dovecot-1.0-test23.vanilla/src/pop3-login/client.c	2004-05-31 22:04:47.000000000 +0400
+++ dovecot-1.0-test23/src/pop3-login/client.c	2004-07-01 13:57:40.000000000 +0400
@@ -13,6 +13,8 @@
 #include "client-authenticate.h"
 #include "auth-client.h"
 #include "ssl-proxy.h"
+#include "hostpid.h"
+#include "imem.h"
 
 /* max. length of input command line (spec says 512) */
 #define MAX_INBUF_SIZE 2048
@@ -122,6 +124,8 @@ static int client_command_execute(struct
 		return cmd_pass(client, args);
 	if (strcmp(cmd, "AUTH") == 0)
 		return cmd_auth(client, args);
+	if (strcmp(cmd, "APOP") == 0)
+		return cmd_apop(client, args);
 	if (strcmp(cmd, "STLS") == 0)
 		return cmd_stls(client);
 	if (strcmp(cmd, "QUIT") == 0)
@@ -228,6 +232,15 @@ static void client_destroy_oldest(void)
 	}
 }
 
+static char *get_apop_challenge(void)
+{
+	if (auth_client_find_mech(auth_client, "APOP")) {
+		hostpid_init();
+		return i_strdup_printf("<%s.%s@%s>", my_pid, dec2str(ioloop_time), my_hostname);
+	} else
+		return NULL;
+}
+
 struct client *client_create(int fd, int ssl, const struct ip_addr *local_ip,
 			     const struct ip_addr *ip)
 {
@@ -265,7 +278,8 @@ struct client *client_create(int fd, int
 
 	main_ref();
 
-	client_send_line(client, "+OK " PACKAGE " ready.");
+	client->apop_challenge = get_apop_challenge();
+	client_send_line(client, t_strconcat("+OK " PACKAGE " ready.", client->apop_challenge, NULL));
 	client_set_title(client);
 	return &client->common;
 }
@@ -318,6 +332,7 @@ int client_unref(struct pop3_client *cli
 	i_stream_unref(client->input);
 	o_stream_unref(client->output);
 
+	i_free(client->apop_challenge);
 	i_free(client->common.virtual_user);
 	i_free(client);
 
diff -udrpN -X /usr/share/dontdiff -x Makefile dovecot-1.0-test23.vanilla/src/pop3-login/client.h dovecot-1.0-test23/src/pop3-login/client.h
--- dovecot-1.0-test23.vanilla/src/pop3-login/client.h	2004-05-31 22:04:47.000000000 +0400
+++ dovecot-1.0-test23/src/pop3-login/client.h	2004-07-01 11:38:33.000000000 +0400
@@ -19,6 +19,8 @@ struct pop3_client {
 
 	char *last_user;
 
+	char *apop_challenge;
+
 	unsigned int tls:1;
 	unsigned int secured:1;
 	unsigned int input_blocked:1;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://dovecot.org/pipermail/dovecot/attachments/20040701/fa9927fc/attachment-0001.bin>


More information about the dovecot mailing list