changeset 2270:52a52b3a0357 HEAD

was missing from last commit
author Timo Sirainen <tss@iki.fi>
date Sat, 03 Jul 2004 13:43:12 +0300
parents 945403a685f9
children 15d959d262a4
files src/auth/mech-apop.c
diffstat 1 files changed, 164 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/auth/mech-apop.c	Sat Jul 03 13:43:12 2004 +0300
@@ -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,
+};