[Dovecot] Exim4 authentication patch

Andrey Panin pazke at donpac.ru
Thu Dec 9 15:54:58 EET 2004


Hello all,

attached patch makes possible to use dovecot as an authentication
backend for Exim 4. Reasons beyond this patch are simple:
exim's authenticators require use of plaintext passwords and NTLM
code in exim is quite outdated and hairy.
Patch generated against Exim 4.43, but should apply to earlier
versions too.

Patch adds new 'dovecot' authenticator, which can be used as such:

ntlm:
	driver = dovecot
	public_name = NTLM
	server_socket = /var/authentication_socket_path
	server_set_id = $1

cram:
	driver = dovecot
	public_name = CRAM-MD5
	...

Authenticator has only one parameter 'server_socket', it's value
used as path for dovecot's authentication socket. Authenticator
can be used for server authentication only.

Hope it will be useful for someone.

Best regards.

-- 
Andrey Panin		| Linux and UNIX system administrator
pazke at donpac.ru		| PGP key: wwwkeys.pgp.net
-------------- next part --------------
diff -urdpNx build-Linux-i386 -x Local exim-4.43.vanilla/scripts/MakeLinks exim-4.43/scripts/MakeLinks
--- exim-4.43.vanilla/scripts/MakeLinks	2004-10-05 12:32:08.000000000 +0400
+++ exim-4.43/scripts/MakeLinks	2004-12-09 15:38:46.000000000 +0300
@@ -167,6 +167,8 @@ ln -s ../../src/auths/auth-spa.h        
 ln -s ../../src/auths/sha1.c             sha1.c
 ln -s ../../src/auths/spa.c              spa.c
 ln -s ../../src/auths/spa.h              spa.h
+ln -s ../../src/auths/dovecot.c          dovecot.c
+ln -s ../../src/auths/dovecot.h          dovecot.h
 cd ..
 
 # The basic source files for Exim and utilities. NB local_scan.h gets linked,
diff -urdpNx build-Linux-i386 -x Local exim-4.43.vanilla/src/auths/dovecot.c exim-4.43/src/auths/dovecot.c
--- exim-4.43.vanilla/src/auths/dovecot.c	1970-01-01 03:00:00.000000000 +0300
+++ exim-4.43/src/auths/dovecot.c	2004-12-09 15:38:46.000000000 +0300
@@ -0,0 +1,247 @@
+/*
+ * 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 General Public License as published 
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "../exim.h"
+#include "dovecot.h"
+
+#define VERSION_MAJOR	1
+#define	VERSION_MINOR	0
+
+/* Options specific to the authentication mechanism. */
+optionlist auth_dovecot_options[] = {
+	{
+		"server_socket",
+		opt_stringptr,
+		(void *)(offsetof(auth_dovecot_options_block, server_socket))
+	},
+};
+
+/* Size of the options list. An extern variable has to be used so that its
+address can appear in the tables drtables.c. */
+int auth_dovecot_options_count =
+	sizeof(auth_dovecot_options) / sizeof(optionlist);
+
+/* Default private options block for the authentication method. */
+auth_dovecot_options_block auth_dovecot_option_defaults = {
+	NULL,				/* server_socket */
+};
+
+/*************************************************
+ *          Initialization entry point           *
+ *************************************************/
+
+/* Called for each instance, after its options have been read, to
+enable consistency checks to be done, or anything else that needs
+to be set up. */
+void auth_dovecot_init(auth_instance *ablock)
+{
+	auth_dovecot_options_block *ob =
+		(auth_dovecot_options_block *)(ablock->options_block);
+
+	if (ablock->public_name == NULL)
+		ablock->public_name = ablock->name;
+	if (ob->server_socket != NULL)
+		ablock->server = TRUE;
+	ablock->client = FALSE;
+}
+
+static int strcut(char *str, char **ptrs, int nptrs)
+{
+	char *tmp = str;
+	int n;
+
+	for (n = 0; n < nptrs; n++)
+		ptrs[n] = NULL;
+	n = 1;
+
+	while (*str) {
+		if (*str == '\t') {
+			if (n <= nptrs) {
+				*ptrs++ = tmp;
+				tmp = str + 1;
+				*str = 0;
+			}
+			n++;
+		}
+		str++;
+	}
+
+	if (n < nptrs)
+		*ptrs = tmp;
+
+	return n;
+}
+
+#define CHECK_COMMAND(str, arg_min, arg_max) do { \
+	if (strcasecmp((str), args[0]) != 0) \
+		goto out; \
+	if (nargs - 1 < (arg_min)) \
+		goto out; \
+	if (nargs - 1 > (arg_max)) \
+		goto out; \
+} while (0)
+
+#define OUT(msg) do { \
+	auth_defer_msg = (msg); \
+	goto out; \
+} while(0)
+
+/*************************************************
+ *             Server entry point                *
+ *************************************************/
+
+int auth_dovecot_server(auth_instance *ablock, uschar *data)
+{
+	auth_dovecot_options_block *ob =
+		(auth_dovecot_options_block *)(ablock->options_block);
+	struct sockaddr_un sa;
+	char buffer[4096];
+	char *args[8];
+	int nargs, tmp;
+	int cuid = 0, cont = 1, found = 0, fd, ret = DEFER;
+	FILE *f;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sun_family = AF_UNIX;
+	if (strncpy(sa.sun_path, ob->server_socket, sizeof(sa.sun_path)) < 0) {
+		auth_defer_msg = "authentication socket path too long";
+		return DEFER;
+	}
+
+	auth_defer_msg = "authentication socket connection error";
+
+	fd = socket(PF_UNIX, SOCK_STREAM, 0);
+	if (fd < 0)
+		return DEFER;
+
+	if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
+		goto out;
+
+	f = fdopen(fd, "a+");
+	if (f == NULL)
+		goto out;
+
+	auth_defer_msg = "authentication socket protocol error";
+
+	while (cont) {
+		if (fgets(buffer, sizeof(buffer), f) == NULL)
+			OUT("authentication socket read error or premature eof");
+
+		buffer[strlen(buffer) - 1] = 0;
+		nargs = strcut(buffer, args, sizeof(args) / sizeof(args[0]));
+
+		switch (toupper(*args[0])) {
+		case 'C':
+			CHECK_COMMAND("CUID", 1, 1);
+			cuid = atoi(args[1]);
+			break;
+
+		case 'D':
+			CHECK_COMMAND("DONE", 0, 0);
+			cont = 0;
+			break;
+
+		case 'M':
+			CHECK_COMMAND("MECH", 1, INT_MAX);
+			if (!strcasecmp(args[1], ablock->public_name))
+				found = 1;
+			break;
+
+		case 'S':
+			CHECK_COMMAND("SPID", 1, 1);
+			break;
+
+		case 'V':
+			CHECK_COMMAND("VERSION", 2, 2);
+			if (atoi(args[1]) != VERSION_MAJOR)
+				OUT("authentication socket protocol version mismatch");
+			break;
+
+		default:
+			goto out;
+		}
+	}
+
+	if (!found)
+		goto out;
+
+	fprintf(f, "VERSION\t%d\t%d\r\nSERVICE\tSMTP\r\nCPID\t%d\r\n"
+		"AUTH\t%d\t%s\trip=%s\tlip=%s\tresp=%s\r\n",
+		VERSION_MAJOR, VERSION_MINOR, getpid(), cuid,
+		ablock->public_name, sender_host_address, interface_address,
+		data ? (char *) data : "");
+
+	while (1) {
+		if (fgets(buffer, sizeof(buffer), f) == NULL) {
+			auth_defer_msg = "authentication socket read error or premature eof";
+			goto out;
+		}
+
+		buffer[strlen(buffer) - 1] = 0;
+		nargs = strcut(buffer, args, sizeof(args) / sizeof(args[0]));
+
+		if (atoi(args[1]) != cuid)
+			OUT("authentication socket connection id mismatch");
+
+		switch (toupper(*args[0])) {
+		case 'C':
+			CHECK_COMMAND("CONT", 1, 2);
+
+			tmp = auth_get_no64_data(&data, args[2]);
+			if (tmp != OK) {
+				ret = tmp;
+				goto out;
+			}
+
+			if (fprintf(f, "CONT\t%d\t%s\r\n", cuid, data) < 0)
+				OUT("authentication socket write error");
+
+			break;
+
+		case 'F':
+			CHECK_COMMAND("FAIL", 1, 2);
+
+			/* FIXME: add proper response handling */
+			if (args[2]) {
+				char *p = strchr(args[2], '=');
+				if (p) {
+					++p;
+					expand_nstring[1] = p;
+					expand_nlength[1] = strlen(p);
+					expand_nmax = 1;
+				}
+			}
+
+			ret = FAIL;
+			goto out;
+
+		case 'O':
+			CHECK_COMMAND("OK", 2, 2);
+			{
+				/* FIXME: add proper response handling */
+				char *p = strchr(args[2], '=');
+				if (!p)
+					OUT("authentication socket protocol error, username missing");
+
+				p++;
+				expand_nstring[1] = p;
+				expand_nlength[1] = strlen(p);
+				expand_nmax = 1;
+			}
+			ret = OK;
+			/* fallthrough */
+
+		default:
+			goto out;
+		}
+	}
+
+out:	close(fd);
+	return ret;
+}
diff -urdpNx build-Linux-i386 -x Local exim-4.43.vanilla/src/auths/dovecot.h exim-4.43/src/auths/dovecot.h
--- exim-4.43.vanilla/src/auths/dovecot.h	1970-01-01 03:00:00.000000000 +0300
+++ exim-4.43/src/auths/dovecot.h	2004-12-09 15:47:43.000000000 +0300
@@ -0,0 +1,28 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 1995 - 2003 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Private structure for the private options. */
+
+typedef struct {
+  uschar *server_socket;
+} auth_dovecot_options_block;
+
+/* Data for reading the private options. */
+
+extern optionlist auth_dovecot_options[];
+extern int auth_dovecot_options_count;
+
+/* Block containing default values. */
+
+extern auth_dovecot_options_block auth_dovecot_option_defaults;
+
+/* The entry points for the mechanism */
+
+extern void auth_dovecot_init(auth_instance *);
+extern int auth_dovecot_server(auth_instance *, uschar *);
+
+/* End of dovecot.h */
diff -urdpNx build-Linux-i386 -x Local exim-4.43.vanilla/src/auths/Makefile exim-4.43/src/auths/Makefile
--- exim-4.43.vanilla/src/auths/Makefile	2004-10-05 12:32:08.000000000 +0400
+++ exim-4.43/src/auths/Makefile	2004-12-09 15:46:44.000000000 +0300
@@ -7,7 +7,7 @@
 
 OBJ = b64encode.o b64decode.o call_pam.o call_pwcheck.o call_radius.o \
       xtextencode.o xtextdecode.o get_data.o get_no64_data.o md5.o \
-      cram_md5.o cyrus_sasl.o plaintext.o pwcheck.o sha1.o auth-spa.o spa.o
+      cram_md5.o cyrus_sasl.o plaintext.o pwcheck.o sha1.o auth-spa.o spa.o dovecot.o
 
 auths.a:         $(OBJ)
 		 /bin/rm -f auths.a
@@ -37,4 +37,6 @@ cyrus_sasl.o:    $(HDRS) cyrus_sasl.c cy
 plaintext.o:     $(HDRS) plaintext.c plaintext.h
 spa.o:           $(HDRS) spa.c spa.h
 
+dovecot.o:       $(HDRS) dovecot.c dovecot.h
+
 # End
diff -urdpNx build-Linux-i386 -x Local exim-4.43.vanilla/src/config.h.defaults exim-4.43/src/config.h.defaults
--- exim-4.43.vanilla/src/config.h.defaults	2004-10-05 12:32:08.000000000 +0400
+++ exim-4.43/src/config.h.defaults	2004-12-09 15:38:46.000000000 +0300
@@ -20,6 +20,7 @@ in config.h unless some value is defined
 #define AUTH_CYRUS_SASL
 #define AUTH_PLAINTEXT
 #define AUTH_SPA
+#define AUTH_DOVECOT
 
 #define BIN_DIRECTORY
 
diff -urdpNx build-Linux-i386 -x Local exim-4.43.vanilla/src/drtables.c exim-4.43/src/drtables.c
--- exim-4.43.vanilla/src/drtables.c	2004-10-05 12:32:08.000000000 +0400
+++ exim-4.43/src/drtables.c	2004-12-09 15:47:14.000000000 +0300
@@ -515,6 +515,10 @@ set to NULL for those that are not compi
 #include "auths/spa.h"
 #endif
 
+#ifdef AUTH_DOVECOT
+#include "auths/dovecot.h"
+#endif
+
 auth_info auths_available[] = {
 
 /* Checking by an expansion condition on plain text */
@@ -571,6 +575,18 @@ auth_info auths_available[] = {
   },
 #endif
 
+#ifdef AUTH_DOVECOT
+  {
+  US"dovecot",                                /* lookup name */
+  auth_dovecot_options,
+  &auth_dovecot_options_count,
+  &auth_dovecot_option_defaults,
+  sizeof(auth_dovecot_options_block),
+  auth_dovecot_init,                          /* init function */
+  auth_dovecot_server,                        /* server function */
+  },
+#endif
+
 { US"", NULL, NULL, NULL, 0, NULL, NULL, NULL  }
 };
 
diff -urdpNx build-Linux-i386 -x Local exim-4.43.vanilla/src/EDITME exim-4.43/src/EDITME
--- exim-4.43.vanilla/src/EDITME	2004-10-05 12:32:08.000000000 +0400
+++ exim-4.43/src/EDITME	2004-12-09 16:00:00.000000000 +0300
@@ -410,6 +410,7 @@ FIXED_NEVER_USERS=root
 # AUTH_CYRUS_SASL=yes
 # AUTH_PLAINTEXT=yes
 # AUTH_SPA=yes
+# AUTH_DOVECOT=yes
 
 
 #------------------------------------------------------------------------------
diff -urdpNx build-Linux-i386 -x Local exim-4.43.vanilla/src/exim.c exim-4.43/src/exim.c
--- exim-4.43.vanilla/src/exim.c	2004-10-05 12:32:08.000000000 +0400
+++ exim-4.43/src/exim.c	2004-12-09 15:38:46.000000000 +0300
@@ -895,6 +895,10 @@ fprintf(f, "Authenticators:");
 #ifdef AUTH_SPA
   fprintf(f, " spa");
 #endif
+#ifdef AUTH_DOVECOT
+  fprintf(f, " dovecot");
+#endif
+
 fprintf(f, "\n");
 
 fprintf(f, "Routers:");
-------------- 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/20041209/a83d3485/attachment-0001.bin>


More information about the dovecot mailing list