[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