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>