Mercurial > dovecot > core-2.2
changeset 2267:d2e186f716d8 HEAD
Added APOP authentication for POP3. Patch by Andrey Panin.
This required some changes in auth APIs.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 03 Jul 2004 01:03:36 +0300 |
parents | d6001ee7815d |
children | 5bd7fa814d7f |
files | AUTHORS dovecot-example.conf src/auth/Makefile.am src/auth/auth-client-connection.c src/auth/auth-client-connection.h src/auth/auth-client-interface.h src/auth/auth-master-connection.c src/auth/mech.c src/imap-login/client-authenticate.c src/lib-auth/auth-client.c src/lib-auth/auth-client.h src/lib-auth/auth-server-connection.c src/lib-auth/auth-server-connection.h src/lib-auth/auth-server-request.c src/pop3-login/client-authenticate.c src/pop3-login/client-authenticate.h src/pop3-login/client.c src/pop3-login/client.h |
diffstat | 18 files changed, 170 insertions(+), 20 deletions(-) [+] |
line wrap: on
line diff
--- a/AUTHORS Fri Jul 02 21:30:17 2004 +0300 +++ b/AUTHORS Sat Jul 03 01:03:36 2004 +0300 @@ -2,12 +2,12 @@ Solar Designer <solar@openwall.com> (src/auth/userinfo-passwd|shadow|pam.c) -Damian Ivereigh <damian@cisco.com> (src/lib-index/mail-tree-redblack.c) - Alex Howansky <alex@wankwood.com> (src/auth/*-pgsql.c) Matthew Reimer <mreimer@vpop.net> (src/auth/*-mysql.c) +Andrey Panin <pazke@donpac.ru> (src/auth/mech-apop.c) + This product includes software developed by Computing Services at Carnegie Mellon University (http://www.cmu.edu/computing/). (src/lib/base64.c, src/lib/mkgmtime.c)
--- a/dovecot-example.conf Fri Jul 02 21:30:17 2004 +0300 +++ b/dovecot-example.conf Sat Jul 03 01:03:36 2004 +0300 @@ -419,7 +419,7 @@ auth default { # Space separated list of wanted authentication mechanisms: - # plain digest-md5 cram-md5 anonymous + # plain digest-md5 cram-md5 apop anonymous mechanisms = plain # Where user database is kept:
--- a/src/auth/Makefile.am Fri Jul 02 21:30:17 2004 +0300 +++ b/src/auth/Makefile.am Sat Jul 03 01:03:36 2004 +0300 @@ -31,6 +31,7 @@ mech-plain.c \ mech-cram-md5.c \ mech-digest-md5.c \ + mech-apop.c \ mycrypt.c \ passdb.c \ passdb-bsdauth.c \
--- a/src/auth/auth-client-connection.c Fri Jul 02 21:30:17 2004 +0300 +++ b/src/auth/auth-client-connection.c Sat Jul 03 01:03:36 2004 +0300 @@ -185,7 +185,10 @@ struct auth_client_connection * auth_client_connection_create(struct auth_master_connection *master, int fd) { + static unsigned int connect_uid_counter = 0; struct auth_client_connection *conn; + struct auth_client_handshake_reply handshake_reply; + pool_t pool; pool = pool_alloconly_create("Auth client", 4096); @@ -193,6 +196,7 @@ conn->pool = pool; conn->master = master; conn->refcount = 1; + conn->connect_uid = ++connect_uid_counter; conn->fd = fd; conn->input = i_stream_create_file(fd, default_pool, MAX_INBUF_SIZE, @@ -207,9 +211,13 @@ conn->next = master->clients; master->clients = conn; - if (o_stream_send(conn->output, master->handshake_reply, - sizeof(*master->handshake_reply) + - master->handshake_reply->data_size) < 0) { + handshake_reply = *master->handshake_reply; + handshake_reply.connect_uid = conn->connect_uid; + + if (o_stream_send(conn->output, &handshake_reply, + sizeof(handshake_reply)) < 0 || + o_stream_send(conn->output, master->handshake_reply + 1, + handshake_reply.data_size) < 0) { auth_client_connection_destroy(conn); conn = NULL; }
--- a/src/auth/auth-client-connection.h Fri Jul 02 21:30:17 2004 +0300 +++ b/src/auth/auth-client-connection.h Sat Jul 03 01:03:36 2004 +0300 @@ -18,6 +18,7 @@ struct hash_table *auth_requests; unsigned int pid; + unsigned int connect_uid; }; struct auth_client_connection *
--- a/src/auth/auth-client-interface.h Fri Jul 02 21:30:17 2004 +0300 +++ b/src/auth/auth-client-interface.h Sat Jul 03 01:03:36 2004 +0300 @@ -37,6 +37,7 @@ /* Server -> Client */ struct auth_client_handshake_reply { unsigned int server_pid; /* unique auth process identifier */ + unsigned int connect_uid; /* unique connection identifier */ uint32_t mech_count; uint32_t data_size;
--- a/src/auth/auth-master-connection.c Fri Jul 02 21:30:17 2004 +0300 +++ b/src/auth/auth-master-connection.c Sat Jul 03 01:03:36 2004 +0300 @@ -226,7 +226,7 @@ mech_desc_offset += sizeof(mech_desc); } - reply.data_size = buffer_get_used_size(buf); + reply.data_size = buffer_get_used_size(buf) - sizeof(reply); memcpy(buffer_get_space_unsafe(buf, 0, sizeof(reply)), &reply, sizeof(reply));
--- a/src/auth/mech.c Fri Jul 02 21:30:17 2004 +0300 +++ b/src/auth/mech.c Sat Jul 03 01:03:36 2004 +0300 @@ -384,6 +384,7 @@ } 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 @@ 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 @@ 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);
--- a/src/imap-login/client-authenticate.c Fri Jul 02 21:30:17 2004 +0300 +++ b/src/imap-login/client-authenticate.c Sat Jul 03 01:03:36 2004 +0300 @@ -182,7 +182,7 @@ client_ref(client); client->common.auth_request = - auth_client_request_new(auth_client, &info, + auth_client_request_new(auth_client, NULL, &info, login_callback, client, &error); if (client->common.auth_request == NULL) { client_send_tagline(client, t_strconcat( @@ -315,7 +315,7 @@ client_ref(client); client->common.auth_request = - auth_client_request_new(auth_client, &info, + auth_client_request_new(auth_client, NULL, &info, authenticate_callback, client, &error); if (client->common.auth_request != NULL) { /* following input data will go to authentication */
--- a/src/lib-auth/auth-client.c Fri Jul 02 21:30:17 2004 +0300 +++ b/src/lib-auth/auth-client.c Sat Jul 03 01:03:36 2004 +0300 @@ -87,6 +87,22 @@ return NULL; } +int auth_client_reserve_connection(struct auth_client *client, const char *mech, + struct auth_connect_id *id_r) +{ + struct auth_server_connection *conn; + const char *error; + + conn = auth_server_connection_find_mech(client, mech, &error); + if (conn == NULL) + return FALSE; + + id_r->server_pid = conn->server_pid; + id_r->connect_uid = conn->connect_uid; + + return TRUE; +} + int auth_client_is_connected(struct auth_client *client) { return !client->reconnect &&
--- a/src/lib-auth/auth-client.h Fri Jul 02 21:30:17 2004 +0300 +++ b/src/lib-auth/auth-client.h Sat Jul 03 01:03:36 2004 +0300 @@ -13,6 +13,11 @@ unsigned int advertise:1; }; +struct auth_connect_id { + unsigned int server_pid; + unsigned int connect_uid; +}; + struct auth_request_info { const char *mech; const char *protocol; @@ -46,10 +51,17 @@ const struct auth_mech_desc * auth_client_find_mech(struct auth_client *client, const char *name); +/* Reserve connection for specific mechanism. The id can be given to + auth_client_request_new() to force it to use the same connection, or fail. + This is currently useful only for APOP authentication. Returns TRUE if + successfull. */ +int auth_client_reserve_connection(struct auth_client *client, const char *mech, + struct auth_connect_id *id_r); + /* Create a new authentication request. callback is called whenever something - happens for the request. */ + happens for the request. id can be NULL. */ struct auth_request * -auth_client_request_new(struct auth_client *client, +auth_client_request_new(struct auth_client *client, struct auth_connect_id *id, const struct auth_request_info *request_info, auth_request_callback_t *callback, void *context, const char **error_r);
--- a/src/lib-auth/auth-server-connection.c Fri Jul 02 21:30:17 2004 +0300 +++ b/src/lib-auth/auth-server-connection.c Sat Jul 03 01:03:36 2004 +0300 @@ -80,7 +80,8 @@ conn->has_plain_mech = TRUE; } - conn->pid = handshake->server_pid; + conn->server_pid = handshake->server_pid; + conn->connect_uid = handshake->connect_uid; conn->available_auth_mechs_count = buffer_get_used_size(buf) / sizeof(mech_desc); conn->available_auth_mechs = buffer_free_without_data(buf);
--- a/src/lib-auth/auth-server-connection.h Fri Jul 02 21:30:17 2004 +0300 +++ b/src/lib-auth/auth-server-connection.h Sat Jul 03 01:03:36 2004 +0300 @@ -37,7 +37,9 @@ struct istream *input; struct ostream *output; - unsigned int pid; + unsigned int server_pid; + unsigned int connect_uid; + const struct auth_mech_desc *available_auth_mechs; unsigned int available_auth_mechs_count; struct auth_client_request_reply reply;
--- a/src/lib-auth/auth-server-request.c Fri Jul 02 21:30:17 2004 +0300 +++ b/src/lib-auth/auth-server-request.c Sat Jul 03 01:03:36 2004 +0300 @@ -247,7 +247,7 @@ } struct auth_request * -auth_client_request_new(struct auth_client *client, +auth_client_request_new(struct auth_client *client, struct auth_connect_id *id, const struct auth_request_info *request_info, auth_request_callback_t *callback, void *context, const char **error_r) @@ -255,8 +255,20 @@ struct auth_server_connection *conn; struct auth_request *request; - conn = auth_server_connection_find_mech(client, request_info->mech, - error_r); + if (id == NULL) { + conn = auth_server_connection_find_mech(client, + request_info->mech, + error_r); + } else { + *error_r = NULL; + conn = client->connections; + for (; conn != NULL; conn = conn->next) { + if (conn->connect_uid == id->connect_uid && + conn->server_pid == id->server_pid) + break; + } + } + if (conn == NULL) return NULL; @@ -324,5 +336,5 @@ unsigned int auth_client_request_get_server_pid(struct auth_request *request) { - return request->conn->pid; + return request->conn->server_pid; }
--- a/src/pop3-login/client-authenticate.c Fri Jul 02 21:30:17 2004 +0300 +++ b/src/pop3-login/client-authenticate.c Sat Jul 03 01:03:36 2004 +0300 @@ -3,6 +3,7 @@ #include "common.h" #include "base64.h" #include "buffer.h" +#include "hex-binary.h" #include "ioloop.h" #include "istream.h" #include "ostream.h" @@ -184,7 +185,7 @@ client_ref(client); client->common.auth_request = - auth_client_request_new(auth_client, &info, + auth_client_request_new(auth_client, NULL, &info, login_callback, client, &error); if (client->common.auth_request != NULL) { @@ -322,7 +323,7 @@ client_ref(client); client->common.auth_request = - auth_client_request_new(auth_client, &info, + auth_client_request_new(auth_client, NULL, &info, authenticate_callback, client, &error); if (client->common.auth_request != NULL) { /* following input data will go to authentication */ @@ -338,3 +339,69 @@ return TRUE; } + +int cmd_apop(struct pop3_client *client, const char *args) +{ + struct auth_request_info info; + const char *error, *p; + buffer_t *apop_data; + + if (client->apop_challenge == NULL) { + client_send_line(client, "-ERR APOP not enabled."); + return TRUE; + } + + /* <username> <md5 sum in hex> */ + p = strchr(args, ' '); + if (p == NULL || strlen(p+1) != 32) { + client_send_line(client, "-ERR Invalid parameters."); + return TRUE; + } + + /* APOP challenge \0 username \0 APOP response */ + apop_data = buffer_create_dynamic(pool_datastack_create(), + 128, (size_t)-1); + buffer_append(apop_data, client->apop_challenge, + strlen(client->apop_challenge)+1); + buffer_append(apop_data, args, (size_t)(p-args)); + buffer_append_c(apop_data, '\0'); + + if (hex_to_binary(p+1, apop_data) <= 0) { + client_send_line(client, + "-ERR Invalid characters in MD5 response."); + return TRUE; + } + + 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 = + buffer_get_data(apop_data, &info.initial_resp_size); + + client_ref(client); + client->common.auth_request = + auth_client_request_new(auth_client, &client->auth_id, &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; + } + } else if (error == NULL) { + /* the auth connection was lost. we have no choice + but to fail the APOP logins completely since the + challenge is auth connection-specific. disconnect. */ + client_destroy(client, "APOP auth connection lost"); + client_unref(client); + } else { + client_send_line(client, + t_strconcat("-ERR Login failed: ", error, NULL)); + client_unref(client); + } + return TRUE; +}
--- a/src/pop3-login/client-authenticate.h Fri Jul 02 21:30:17 2004 +0300 +++ b/src/pop3-login/client-authenticate.h Sat Jul 03 01:03:36 2004 +0300 @@ -5,5 +5,6 @@ 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
--- a/src/pop3-login/client.c Fri Jul 02 21:30:17 2004 +0300 +++ b/src/pop3-login/client.c Sat Jul 03 01:03:36 2004 +0300 @@ -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 @@ 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,19 @@ } } +static char *get_apop_challenge(void) +{ + struct auth_connect_id id; + + /* FIXME: breaks if we're not connected! */ + + if (!auth_client_reserve_connection(auth_client, "APOP", &id)) + return NULL; + + return i_strdup_printf("<%x.%x.%s@%s>", id.server_pid, id.connect_uid, + dec2str(ioloop_time), my_hostname); +} + struct client *client_create(int fd, int ssl, const struct ip_addr *local_ip, const struct ip_addr *ip) { @@ -265,7 +282,9 @@ 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 +337,7 @@ i_stream_unref(client->input); o_stream_unref(client->output); + i_free(client->apop_challenge); i_free(client->common.virtual_user); i_free(client);
--- a/src/pop3-login/client.h Fri Jul 02 21:30:17 2004 +0300 +++ b/src/pop3-login/client.h Sat Jul 03 01:03:36 2004 +0300 @@ -4,6 +4,7 @@ #include "network.h" #include "master.h" #include "client-common.h" +#include "auth-client.h" struct pop3_client { struct client common; @@ -19,6 +20,9 @@ char *last_user; + char *apop_challenge; + struct auth_connect_id auth_id; + unsigned int tls:1; unsigned int secured:1; unsigned int input_blocked:1;