]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
was missing from last commit
authorTimo Sirainen <tss@iki.fi>
Sat, 3 Jul 2004 10:43:12 +0000 (13:43 +0300)
committerTimo Sirainen <tss@iki.fi>
Sat, 3 Jul 2004 10:43:12 +0000 (13:43 +0300)
--HG--
branch : HEAD

src/auth/mech-apop.c [new file with mode: 0644]

diff --git a/src/auth/mech-apop.c b/src/auth/mech-apop.c
new file mode 100644 (file)
index 0000000..49305c9
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * APOP (RFC-1460) authentication mechanism.
+ *
+ * Copyright (c) 2004 Andrey Panin <pazke@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 "auth-client-connection.h"
+#include "auth-master-connection.h"
+
+#include <ctype.h>
+
+struct apop_auth_request {
+       struct auth_request auth_request;
+
+       pool_t pool;
+
+       /* requested: */
+       char *challenge;
+
+       /* received: */
+       unsigned char digest[16];
+};
+
+static void
+apop_credentials_callback(const char *credentials,
+                         struct auth_request *auth_request)
+{
+       struct apop_auth_request *auth =
+               (struct apop_auth_request *)auth_request;
+       unsigned char digest[16];
+       struct md5_context ctx;
+
+       md5_init(&ctx);
+       md5_update(&ctx, auth->challenge, strlen(auth->challenge));
+       md5_update(&ctx, credentials, strlen(credentials));
+       md5_final(&ctx, digest);
+
+       mech_auth_finish(auth_request, NULL, 0,
+                        memcmp(digest, auth->digest, 16) == 0);
+}
+
+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 = NULL;
+       const char *str;
+
+       auth_request->callback = callback;
+
+       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 != end && *tmp != '\0')
+               tmp++;
+
+       /* the challenge must begin with trusted unique ID. we trust only
+          ourself, so make sure it matches our connection specific UID
+          which we told to client in handshake. */
+        str = t_strdup_printf("<%x.%x.", auth_request->conn->master->pid,
+                             auth_request->conn->connect_uid);
+       if (memcmp(data, str, strlen(str)) != 0) {
+               if (verbose) {
+                       i_info("apop(%s): invalid challenge",
+                              get_log_prefix(auth_request));
+               }
+               mech_auth_finish(auth_request, NULL, 0, FALSE);
+               return TRUE;
+       }
+       auth->challenge = p_strdup(auth->pool, data);
+
+       if (tmp != end) {
+               username = ++tmp;
+               while (tmp != end && *tmp != '\0')
+                       tmp++;
+       }
+
+       if (tmp + 1 + 16 != end) {
+               /* Should never happen */
+               if (verbose) {
+                       i_info("apop(%s): malformed data",
+                              get_log_prefix(auth_request));
+               }
+               mech_auth_finish(auth_request, NULL, 0, FALSE);
+               return TRUE;
+       }
+       tmp++;
+
+       auth_request->user = p_strdup(auth->pool, username);
+       if (!mech_is_valid_username(auth_request->user)) {
+               if (verbose) {
+                       i_info("apop(%s): invalid username",
+                              get_log_prefix(auth_request));
+               }
+               mech_auth_finish(auth_request, NULL, 0, FALSE);
+               return TRUE;
+       }
+
+       memcpy(auth->digest, tmp, sizeof(auth->digest));
+
+       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,
+};