From 67deaac5656bca2731a27d25d53e6a67a0f4fdee Mon Sep 17 00:00:00 2001 From: Tomas Janousek Date: Mon, 5 Nov 2007 18:13:24 +0000 Subject: [PATCH] - update to latest upstream stable (1.0.7) - added the wibnind patch (#286351) --- dovecot-1.0.3-winbind.patch | 536 ++++++++++++++++++++++++++++++++++++ dovecot.spec | 4 + 2 files changed, 540 insertions(+) create mode 100644 dovecot-1.0.3-winbind.patch diff --git a/dovecot-1.0.3-winbind.patch b/dovecot-1.0.3-winbind.patch new file mode 100644 index 0000000..7e5efdf --- /dev/null +++ b/dovecot-1.0.3-winbind.patch @@ -0,0 +1,536 @@ +diff -Nrbu dovecot-1.0.3/dovecot-example.conf dovecot-1.0.3-OK/dovecot-example.conf +--- dovecot-1.0.3/dovecot-example.conf 2007-09-10 18:32:06.000000000 +0400 ++++ dovecot-1.0.3-OK/dovecot-example.conf 2007-09-10 17:52:37.000000000 +0400 +@@ -745,6 +745,13 @@ + # default (usually /etc/krb5.keytab) if not specified. + #auth_krb5_keytab = + ++# Do NTLM authentication using Samba's winbind daemon and ntlm_auth helper. ++# ++#auth_ntlm_use_winbind = no ++ ++# Path for Samba's ntlm_auth helper binary. ++#auth_winbind_helper_path = /usr/bin/ntlm_auth ++ + auth default { + # Space separated list of wanted authentication mechanisms: + # plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi +diff -Nrbu dovecot-1.0.3/src/auth/Makefile.am dovecot-1.0.3-OK/src/auth/Makefile.am +--- dovecot-1.0.3/src/auth/Makefile.am 2007-07-15 23:51:07.000000000 +0400 ++++ dovecot-1.0.3-OK/src/auth/Makefile.am 2007-09-10 17:53:42.000000000 +0400 +@@ -59,6 +59,7 @@ + mech-gssapi.c \ + mech-rpa.c \ + mech-apop.c \ ++ mech-winbind.c \ + passdb.c \ + passdb-blocking.c \ + passdb-bsdauth.c \ +diff -Nrbu dovecot-1.0.3/src/auth/Makefile.in dovecot-1.0.3-OK/src/auth/Makefile.in +--- dovecot-1.0.3/src/auth/Makefile.in 2007-07-23 09:24:08.000000000 +0400 ++++ dovecot-1.0.3-OK/src/auth/Makefile.in 2007-09-10 17:49:06.000000000 +0400 +@@ -78,6 +78,7 @@ + mech.$(OBJEXT) mech-anonymous.$(OBJEXT) mech-plain.$(OBJEXT) \ + mech-login.$(OBJEXT) mech-cram-md5.$(OBJEXT) \ + mech-digest-md5.$(OBJEXT) mech-ntlm.$(OBJEXT) \ ++ mech-winbind.$(OBJEXT) \ + mech-gssapi.$(OBJEXT) mech-rpa.$(OBJEXT) mech-apop.$(OBJEXT) \ + passdb.$(OBJEXT) passdb-blocking.$(OBJEXT) \ + passdb-bsdauth.$(OBJEXT) passdb-cache.$(OBJEXT) \ +@@ -326,6 +327,7 @@ + mech-cram-md5.c \ + mech-digest-md5.c \ + mech-ntlm.c \ ++ mech-winbind.c \ + mech-gssapi.c \ + mech-rpa.c \ + mech-apop.c \ +@@ -495,6 +497,7 @@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mech-ntlm.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mech-plain.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mech-rpa.Po@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mech-winbind.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mech.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mycrypt.Po@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/passdb-blocking.Po@am__quote@ +diff -Nrbu dovecot-1.0.3/src/auth/mech-winbind.c dovecot-1.0.3-OK/src/auth/mech-winbind.c +--- dovecot-1.0.3/src/auth/mech-winbind.c 1970-01-01 03:00:00.000000000 +0300 ++++ dovecot-1.0.3-OK/src/auth/mech-winbind.c 2007-09-10 18:31:35.000000000 +0400 +@@ -0,0 +1,363 @@ ++/* ++ * NTLM and Negotiate authentication mechanisms, ++ * using Samba winbind daemon ++ * ++ * Copyright (c) 2007 Dmitry Butskoy ++ * ++ * This software is released under the MIT license. ++ */ ++ ++#include "common.h" ++#include "lib-signals.h" ++#include "mech.h" ++#include "str.h" ++#include "buffer.h" ++#include "safe-memset.h" ++#include "base64.h" ++#include "istream.h" ++#include "ostream.h" ++ ++#include ++#include ++#include ++ ++#define DEFAULT_WINBIND_HELPER_PATH "/usr/bin/ntlm_auth" ++ ++enum helper_result { ++ HR_OK = 0, /* OK or continue */ ++ HR_FAIL = -1, /* authentication failed */ ++ HR_RESTART = -2 /* FAIL + try to restart helper */ ++}; ++ ++struct winbind_helper { ++ const char *param; ++ pid_t pid; ++ ++ struct istream *in_pipe; ++ struct ostream *out_pipe; ++}; ++ ++struct winbind_auth_request { ++ struct auth_request auth_request; ++ ++ struct winbind_helper *winbind; ++ bool continued; ++}; ++ ++static struct winbind_helper winbind_ntlm_context = { ++ "--helper-protocol=squid-2.5-ntlmssp", -1, NULL, NULL ++}; ++static struct winbind_helper winbind_spnego_context = { ++ "--helper-protocol=gss-spnego", -1, NULL, NULL ++}; ++ ++static bool sigchld_handler_set = FALSE; ++ ++static void winbind_helper_disconnect(struct winbind_helper *winbind) ++{ ++ if (winbind->in_pipe != NULL) ++ i_stream_destroy(&winbind->in_pipe); ++ if (winbind->out_pipe != NULL) ++ o_stream_destroy(&winbind->out_pipe); ++} ++ ++static void winbind_wait_pid(struct winbind_helper *winbind) ++{ ++ int status, ret; ++ ++ if (winbind->pid == -1) ++ return; ++ ++ if ((ret = waitpid(winbind->pid, &status, WNOHANG)) <= 0) { ++ if (ret < 0 && errno != ECHILD && errno != EINTR) ++ i_error("waitpid() failed: %m"); ++ return; ++ } ++ ++ if (WIFSIGNALED(status)) { ++ i_error("winbind: ntlm_auth died with signal %d", ++ WTERMSIG(status)); ++ } else if (WIFEXITED(status)) { ++ i_error("winbind: ntlm_auth exited with exit code %d", ++ WEXITSTATUS(status)); ++ } else { ++ /* shouldn't happen */ ++ i_error("winbind: ntlm_auth exited with status %d", ++ status); ++ } ++ winbind->pid = -1; ++} ++ ++static void sigchld_handler(int signo __attr_unused__, ++ void *context __attr_unused__) ++{ ++ winbind_wait_pid(&winbind_ntlm_context); ++ winbind_wait_pid(&winbind_spnego_context); ++} ++ ++static void winbind_helper_connect(struct winbind_helper *winbind) ++{ ++ int infd[2], outfd[2]; ++ pid_t pid; ++ ++ if (winbind->in_pipe != NULL || winbind->pid != -1) ++ return; ++ ++ if (pipe(infd) < 0) { ++ i_error("pipe() failed: %m"); ++ return; ++ } ++ if (pipe(outfd) < 0) { ++ (void)close(infd[0]); (void)close(infd[1]); ++ return; ++ } ++ ++ pid = fork (); ++ if (pid < 0) { ++ i_error("fork() failed: %m"); ++ (void)close(infd[0]); (void)close(infd[1]); ++ (void)close(outfd[0]); (void)close(outfd[1]); ++ return; ++ } ++ ++ if (pid == 0) { /* child */ ++ /* child */ ++ const char *helper_path, *args[3]; ++ ++ (void)close(infd[0]); ++ (void)close(outfd[1]); ++ ++ if (dup2(outfd[0], STDIN_FILENO) < 0 || ++ dup2(infd[1], STDOUT_FILENO) < 0) ++ i_fatal("dup2() failed: %m"); ++ ++ helper_path = getenv("WINBIND_HELPER_PATH"); ++ if (helper_path == NULL) ++ helper_path = DEFAULT_WINBIND_HELPER_PATH; ++ ++ args[0] = helper_path; ++ args[1] = winbind->param; ++ args[2] = NULL; ++ execv(args[0], (void *)args); ++ i_fatal("execv(%s) failed: %m", args[0]); ++ } ++ ++ /* parent */ ++ (void)close(infd[1]); ++ (void)close(outfd[0]); ++ ++ winbind->pid = pid; ++ winbind->in_pipe = ++ i_stream_create_file(infd[0], default_pool, ++ AUTH_CLIENT_MAX_LINE_LENGTH, FALSE); ++ winbind->out_pipe = ++ o_stream_create_file(outfd[1], default_pool, ++ (size_t)-1, FALSE); ++ ++ if (!sigchld_handler_set) { ++ sigchld_handler_set = TRUE; ++ lib_signals_set_handler(SIGCHLD, TRUE, sigchld_handler, NULL); ++ } ++} ++ ++static enum helper_result ++do_auth_continue(struct auth_request *auth_request, ++ const unsigned char *data, size_t data_size) ++ { ++ struct winbind_auth_request *request = ++ (struct winbind_auth_request *)auth_request; ++ struct istream *in_pipe = request->winbind->in_pipe; ++ string_t *str; ++ char *answer; ++ const char **token; ++ bool gss_spnego = request->winbind == &winbind_spnego_context; ++ ++ if (request->winbind->in_pipe == NULL) ++ return HR_RESTART; ++ ++ str = t_str_new(MAX_BASE64_ENCODED_SIZE(data_size + 1) + 4); ++ str_printfa(str, "%s ", request->continued ? "KK" : "YR"); ++ base64_encode(data, data_size, str); ++ str_append_c(str, '\n'); ++ ++ if (o_stream_send_str(request->winbind->out_pipe, str_c(str)) < 0 || ++ o_stream_flush(request->winbind->out_pipe) < 0) { ++ auth_request_log_error(auth_request, "winbind", ++ "write(out_pipe) failed: %m"); ++ return HR_RESTART; ++ } ++ request->continued = FALSE; ++ ++ while ((answer = i_stream_read_next_line(in_pipe)) == NULL) { ++ if (in_pipe->stream_errno != 0) ++ break; ++ } ++ if (answer == NULL) { ++ auth_request_log_error(auth_request, "winbind", ++ "read(in_pipe) failed: %m"); ++ return HR_RESTART; ++ } ++ ++ token = t_strsplit_spaces(answer, " "); ++ if (!token || token[0] == NULL || ++ (token[1] == NULL && strcmp(token[0], "BH") != 0) || ++ (gss_spnego && token[2] == NULL)) { ++ auth_request_log_error(auth_request, "winbind", ++ "Invalid input from helper: %s", answer); return HR_RESTART; ++ } ++ ++ /* ++ * NTLM: ++ * The child's reply contains 2 parts: ++ * - The code: TT, AF or NA ++ * - The argument: ++ * For TT it's the blob to send to the client, coded in base64 ++ * For AF it's user or DOMAIN\user ++ * For NA it's the NT error code ++ * ++ * GSS-SPNEGO: ++ * The child's reply contains 3 parts: ++ * - The code: TT, AF or NA ++ * - The blob to send to the client, coded in base64 ++ * - The argument: ++ * For TT it's a dummy '*' ++ * For AF it's DOMAIN\user ++ * For NA it's the NT error code ++ */ ++ ++ if (!strcmp (token[0], "TT")) { ++ buffer_t *buf; ++ size_t len = strlen (token[1]); ++ ++ buf = buffer_create_dynamic (pool_datastack_create(), ++ MAX_BASE64_DECODED_SIZE (len)); ++ base64_decode (token[1], len, NULL, buf); ++ ++ auth_request->callback (auth_request, ++ AUTH_CLIENT_RESULT_CONTINUE, ++ buf->data, buf->used); ++ request->continued = TRUE; ++ return HR_OK; ++ } ++ else if (!strcmp (token[0], "NA")) { ++ const char *error = gss_spnego ? token[2] : token[1]; ++ ++ auth_request_log_info (auth_request, "winbind", ++ "user not authenticated: %s", error); ++ ++ return HR_FAIL; ++ } ++ else if (!strcmp (token[0], "AF")) { ++ const char *user, *p, *error; ++ ++ user = gss_spnego ? token[2] : token[1]; ++ ++ p = strchr (user, '\\'); ++ if (p) { ++ /* change "DOMAIN\user" to uniform style "user@DOMAIN" */ ++ user = t_strconcat (p+1, "@", t_strdup_until (user, p), NULL); ++ } ++ ++ if (!auth_request_set_username (auth_request, user, &error)) { ++ auth_request_log_info (auth_request, "winbind", "%s", error); ++ ++ return HR_FAIL; ++ } ++ ++ if (gss_spnego && strcmp (token[1], "*") != 0) { ++ buffer_t *buf; ++ size_t len = strlen (token[1]); ++ ++ buf = buffer_create_dynamic (pool_datastack_create(), ++ MAX_BASE64_DECODED_SIZE (len)); ++ base64_decode (token[1], len, NULL, buf); ++ ++ auth_request_success (&request->auth_request, ++ buf->data, buf->used); ++ } else ++ auth_request_success (&request->auth_request, NULL, 0); ++ ++ return HR_OK; ++ } ++ else if (!strcmp (token[0], "BH")) { ++ auth_request_log_info (auth_request, "winbind", ++ "ntlm_auth reports broken helper: %s", ++ token[1] ? token[1] : ""); ++ return HR_RESTART; ++ } ++ else { ++ auth_request_log_info (auth_request, "winbind", ++ "Invalid input from helper: %s", answer); ++ return HR_RESTART; ++ } ++ ++} ++ ++static void ++mech_winbind_auth_continue(struct auth_request *auth_request, ++ const unsigned char *data, size_t data_size) ++ { ++ struct winbind_auth_request *request = ++ (struct winbind_auth_request *)auth_request; ++ enum helper_result res; ++ ++ res = do_auth_continue(auth_request, data, data_size); ++ if (res != HR_OK) { ++ if (res == HR_RESTART) ++ winbind_helper_disconnect(request->winbind); ++ auth_request_fail(auth_request); ++ } ++} ++ ++static struct auth_request *do_auth_new(struct winbind_helper *winbind) ++{ ++ struct winbind_auth_request *request; ++ pool_t pool; ++ ++ pool = pool_alloconly_create("winbind_auth_request", 1024); ++ request = p_new(pool, struct winbind_auth_request, 1); ++ request->auth_request.pool = pool; ++ ++ request->winbind = winbind; ++ winbind_helper_connect(request->winbind); ++ return &request->auth_request; ++} ++ ++static struct auth_request *mech_winbind_ntlm_auth_new(void) ++{ ++ return do_auth_new(&winbind_ntlm_context); ++} ++ ++static struct auth_request *mech_winbind_spnego_auth_new(void) ++{ ++ return do_auth_new(&winbind_spnego_context); ++} ++ ++const struct mech_module mech_winbind_ntlm = { ++ "NTLM", ++ ++ MEMBER(flags) MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE, ++ ++ MEMBER(passdb_need_plain) FALSE, ++ MEMBER(passdb_need_credentials) FALSE, ++ ++ mech_winbind_ntlm_auth_new, ++ mech_generic_auth_initial, ++ mech_winbind_auth_continue, ++ mech_generic_auth_free ++}; ++ ++const struct mech_module mech_winbind_spnego = { ++ "GSS-SPNEGO", ++ ++ MEMBER(flags) 0, ++ ++ MEMBER(passdb_need_plain) FALSE, ++ MEMBER(passdb_need_credentials) FALSE, ++ ++ mech_winbind_spnego_auth_new, ++ mech_generic_auth_initial, ++ mech_winbind_auth_continue, ++ mech_generic_auth_free ++}; ++ +diff -Nrbu dovecot-1.0.3/src/auth/mech.c dovecot-1.0.3-OK/src/auth/mech.c +--- dovecot-1.0.3/src/auth/mech.c 2007-05-19 15:14:04.000000000 +0400 ++++ dovecot-1.0.3-OK/src/auth/mech.c 2007-09-10 17:49:06.000000000 +0400 +@@ -73,6 +73,8 @@ + #ifdef HAVE_GSSAPI + extern struct mech_module mech_gssapi; + #endif ++extern struct mech_module mech_winbind_ntlm; ++extern struct mech_module mech_winbind_spnego; + + void mech_init(void) + { +@@ -81,12 +83,16 @@ + mech_register_module(&mech_apop); + mech_register_module(&mech_cram_md5); + mech_register_module(&mech_digest_md5); ++ if (getenv("NTLM_USE_WINBIND") != NULL) ++ mech_register_module(&mech_winbind_ntlm); ++ else + mech_register_module(&mech_ntlm); + mech_register_module(&mech_rpa); + mech_register_module(&mech_anonymous); + #ifdef HAVE_GSSAPI + mech_register_module(&mech_gssapi); + #endif ++ mech_register_module(&mech_winbind_spnego); + } + + void mech_deinit(void) +@@ -96,10 +102,14 @@ + mech_unregister_module(&mech_apop); + mech_unregister_module(&mech_cram_md5); + mech_unregister_module(&mech_digest_md5); ++ if (getenv("NTLM_USE_WINBIND") != NULL) ++ mech_unregister_module(&mech_winbind_ntlm); ++ else + mech_unregister_module(&mech_ntlm); + mech_unregister_module(&mech_rpa); + mech_unregister_module(&mech_anonymous); + #ifdef HAVE_GSSAPI + mech_unregister_module(&mech_gssapi); + #endif ++ mech_unregister_module(&mech_winbind_spnego); + } +diff -Nrbu dovecot-1.0.3/src/master/auth-process.c dovecot-1.0.3-OK/src/master/auth-process.c +--- dovecot-1.0.3/src/master/auth-process.c 2007-07-15 23:51:07.000000000 +0400 ++++ dovecot-1.0.3-OK/src/master/auth-process.c 2007-09-10 17:58:40.000000000 +0400 +@@ -474,6 +474,8 @@ + env_put("SSL_REQUIRE_CLIENT_CERT=1"); + if (set->ssl_username_from_cert) + env_put("SSL_USERNAME_FROM_CERT=1"); ++ if (set->ntlm_use_winbind) ++ env_put("NTLM_USE_WINBIND=1"); + if (*set->krb5_keytab != '\0') { + /* Environment used by Kerberos 5 library directly */ + env_put(t_strconcat("KRB5_KTNAME=", set->krb5_keytab, NULL)); +@@ -482,6 +484,8 @@ + env_put(t_strconcat("GSSAPI_HOSTNAME=", + set->gssapi_hostname, NULL)); + } ++ env_put(t_strconcat("WINBIND_HELPER_PATH=", ++ set->winbind_helper_path, NULL)); + + restrict_process_size(set->process_size, (unsigned int)-1); + } +diff -Nrbu dovecot-1.0.3/src/master/master-settings.c dovecot-1.0.3-OK/src/master/master-settings.c +--- dovecot-1.0.3/src/master/master-settings.c 2007-09-10 18:32:06.000000000 +0400 ++++ dovecot-1.0.3-OK/src/master/master-settings.c 2007-09-10 18:00:28.000000000 +0400 +@@ -72,12 +72,14 @@ + DEF(SET_STR, anonymous_username), + DEF(SET_STR, krb5_keytab), + DEF(SET_STR, gssapi_hostname), ++ DEF(SET_STR, winbind_helper_path), + + DEF(SET_BOOL, verbose), + DEF(SET_BOOL, debug), + DEF(SET_BOOL, debug_passwords), + DEF(SET_BOOL, ssl_require_client_cert), + DEF(SET_BOOL, ssl_username_from_cert), ++ DEF(SET_BOOL, ntlm_use_winbind), + + DEF(SET_INT, count), + DEF(SET_INT, worker_max_count), +@@ -291,12 +293,14 @@ + MEMBER(anonymous_username) "anonymous", + MEMBER(krb5_keytab) "", + MEMBER(gssapi_hostname) "", ++ MEMBER(winbind_helper_path) "/usr/bin/ntlm_auth", + + MEMBER(verbose) FALSE, + MEMBER(debug) FALSE, + MEMBER(debug_passwords) FALSE, + MEMBER(ssl_require_client_cert) FALSE, + MEMBER(ssl_username_from_cert) FALSE, ++ MEMBER(ntlm_use_winbind) FALSE, + + MEMBER(count) 1, + MEMBER(worker_max_count) 30, +diff -Nrbu dovecot-1.0.3/src/master/master-settings.h dovecot-1.0.3-OK/src/master/master-settings.h +--- dovecot-1.0.3/src/master/master-settings.h 2007-07-15 23:51:07.000000000 +0400 ++++ dovecot-1.0.3-OK/src/master/master-settings.h 2007-09-10 18:01:28.000000000 +0400 +@@ -191,10 +191,12 @@ + const char *anonymous_username; + const char *krb5_keytab; + const char *gssapi_hostname; ++ const char *winbind_helper_path; + + bool verbose, debug, debug_passwords; + bool ssl_require_client_cert; + bool ssl_username_from_cert; ++ bool ntlm_use_winbind; + + unsigned int count; + unsigned int worker_max_count; diff --git a/dovecot.spec b/dovecot.spec index d5b3c28..ea69f5d 100644 --- a/dovecot.spec +++ b/dovecot.spec @@ -47,6 +47,8 @@ Patch200: dovecot-1.0.rc32-split.patch #Patch105: dovecot-auth-log.patch # Patches 500+ from upstream fixes +Patch1000: http://www.dovecot.org/patches/1.0/dovecot-1.0.3-winbind.patch + URL: http://www.dovecot.org/ Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildRequires: openssl-devel @@ -177,6 +179,7 @@ This package provides the SQLite backend for dovecot-auth etc. %patch106 -p1 -b .quota-warning %patch200 -p1 -b .split #%patch200 -p1 -b .%{dovecot_hg} +%patch1000 -p1 -b .winbind %if %{build_sieve} %setup -q -n %{name}-%{upstream} -D -T -a 8 @@ -413,6 +416,7 @@ rm -rf $RPM_BUILD_ROOT %changelog * Mon Nov 05 2007 Tomas Janousek - 1:1.0.7-2 - update to latest upstream stable (1.0.7) +- added the wibnind patch (#286351) * Tue Sep 25 2007 Tomas Janousek - 1:1.0.5-1 - downgraded to lastest upstream stable (1.0.5)