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 + * + * 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 + +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;