Created
February 9, 2023 08:27
-
-
Save turkerali/b66081ce80b0340c4a677ecaca1835fb to your computer and use it in GitHub Desktop.
Dovecot 2.3.20 with vpopmail authentication.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -ruN core-2.3.20-original/configure.ac core-2.3.20/configure.ac | |
--- core-2.3.20-original/configure.ac 2022-12-19 12:38:16.000000000 +0300 | |
+++ core-2.3.20/configure.ac 2023-02-09 11:22:36.282856675 +0300 | |
@@ -92,6 +92,22 @@ | |
TEST_WITH(libunwind, $withval), | |
want_libunwind=auto) | |
+AC_ARG_WITH(vpopmail, | |
+AS_HELP_STRING([--with-vpopmail], [Build with vpopmail support (auto)]), | |
+ if test x$withval = xno; then | |
+ want_vpopmail=no | |
+ else | |
+ if test x$withval = xyes || test x$withval = xauto; then | |
+ vpopmail_home="`echo ~vpopmail`" | |
+ want_vpopmail=$withval | |
+ else | |
+ vpopmail_home="$withval" | |
+ want_vpopmail=yes | |
+ fi | |
+ fi, [ | |
+ want_vpopmail=no | |
+ ]) | |
+ | |
# Berkeley DB support is more or less broken. Disabled for now. | |
#AC_ARG_WITH(db, | |
#AS_HELP_STRING([--with-db], [Build with Berkeley DB support]), | |
@@ -556,6 +572,7 @@ | |
DOVECOT_WANT_SODIUM | |
DOVECOT_WANT_SQLITE | |
DOVECOT_WANT_CASSANDRA | |
+DOVECOT_WANT_VPOPMAIL | |
DOVECOT_SQL | |
diff -ruN core-2.3.20-original/doc/example-config/conf.d/10-auth.conf core-2.3.20/doc/example-config/conf.d/10-auth.conf | |
--- core-2.3.20-original/doc/example-config/conf.d/10-auth.conf 2022-12-19 12:38:16.000000000 +0300 | |
+++ core-2.3.20/doc/example-config/conf.d/10-auth.conf 2023-02-09 11:22:36.282856675 +0300 | |
@@ -10,7 +10,7 @@ | |
#disable_plaintext_auth = yes | |
# Authentication cache size (e.g. 10M). 0 means it's disabled. Note that | |
-# bsdauth and PAM require cache_key to be set for caching to be used. | |
+# bsdauth, PAM and vpopmail require cache_key to be set for caching to be used. | |
#auth_cache_size = 0 | |
# Time to live for cached data. After TTL expires the cached record is no | |
# longer used, *except* if the main database lookup returns internal failure. | |
@@ -124,4 +124,5 @@ | |
#!include auth-ldap.conf.ext | |
#!include auth-passwdfile.conf.ext | |
#!include auth-checkpassword.conf.ext | |
+#!include auth-vpopmail.conf.ext | |
#!include auth-static.conf.ext | |
diff -ruN core-2.3.20-original/doc/example-config/conf.d/auth-vpopmail.conf.ext core-2.3.20/doc/example-config/conf.d/auth-vpopmail.conf.ext | |
--- core-2.3.20-original/doc/example-config/conf.d/auth-vpopmail.conf.ext 1970-01-01 02:00:00.000000000 +0200 | |
+++ core-2.3.20/doc/example-config/conf.d/auth-vpopmail.conf.ext 2023-02-09 11:22:36.282856675 +0300 | |
@@ -0,0 +1,17 @@ | |
+# Authentication for vpopmail users. Included from 10-auth.conf. | |
+# | |
+# <doc/wiki/AuthDatabase.VPopMail.txt> | |
+ | |
+passdb { | |
+ driver = vpopmail | |
+ | |
+ # [cache_key=<key>] [webmail=<ip>] | |
+ args = | |
+} | |
+ | |
+userdb { | |
+ driver = vpopmail | |
+ | |
+ # [quota_template=<template>] - %q expands to Maildir++ quota | |
+ args = quota_template=quota_rule=*:backend=%q | |
+} | |
diff -ruN core-2.3.20-original/doc/example-config/conf.d/Makefile.am core-2.3.20/doc/example-config/conf.d/Makefile.am | |
--- core-2.3.20-original/doc/example-config/conf.d/Makefile.am 2022-12-19 12:38:16.000000000 +0300 | |
+++ core-2.3.20/doc/example-config/conf.d/Makefile.am 2023-02-09 11:22:36.282856675 +0300 | |
@@ -11,6 +11,7 @@ | |
auth-sql.conf.ext \ | |
auth-static.conf.ext \ | |
auth-system.conf.ext \ | |
+ auth-vpopmail.conf.ext \ | |
10-auth.conf \ | |
10-director.conf \ | |
10-logging.conf \ | |
diff -ruN core-2.3.20-original/m4/want_vpopmail.m4 core-2.3.20/m4/want_vpopmail.m4 | |
--- core-2.3.20-original/m4/want_vpopmail.m4 1970-01-01 02:00:00.000000000 +0200 | |
+++ core-2.3.20/m4/want_vpopmail.m4 2023-02-09 11:22:36.282856675 +0300 | |
@@ -0,0 +1,33 @@ | |
+AC_DEFUN([DOVECOT_WANT_VPOPMAIL], [ | |
+ have_vpopmail=no | |
+ if test $want_vpopmail != no; then | |
+ vpop_etc="$vpopmail_home/etc" | |
+ AC_MSG_CHECKING([for vpopmail configuration at $vpop_etc/lib_deps]) | |
+ if ! test -f $vpop_etc/lib_deps; then | |
+ AC_MSG_RESULT(not found) | |
+ vpop_etc="$vpopmail_home" | |
+ AC_MSG_CHECKING([for vpopmail configuration at $vpop_etc/lib_deps]) | |
+ fi | |
+ if test -f $vpop_etc/lib_deps; then | |
+ AUTH_CFLAGS="$AUTH_CFLAGS `cat $vpop_etc/inc_deps` $CFLAGS" | |
+ AUTH_LIBS="$AUTH_LIBS `cat $vpop_etc/lib_deps`" | |
+ AC_DEFINE(USERDB_VPOPMAIL,, [Build with vpopmail support]) | |
+ AC_DEFINE(PASSDB_VPOPMAIL,, [Build with vpopmail support]) | |
+ AC_MSG_RESULT(found) | |
+ have_vpopmail=yes | |
+ else | |
+ AC_MSG_RESULT(not found) | |
+ if test $want_vpopmail = yes; then | |
+ AC_ERROR([Can't build with vpopmail support: $vpop_etc/lib_deps not found]) | |
+ fi | |
+ fi | |
+ fi | |
+ | |
+ if test $have_vpopmail = no; then | |
+ not_passdb="$not_passdb vpopmail" | |
+ not_userdb="$not_userdb vpopmail" | |
+ else | |
+ userdb="$userdb vpopmail" | |
+ passdb="$passdb vpopmail" | |
+ fi | |
+]) | |
diff -ruN core-2.3.20-original/src/auth/db-checkpassword.c core-2.3.20/src/auth/db-checkpassword.c | |
--- core-2.3.20-original/src/auth/db-checkpassword.c 2022-12-19 12:38:16.000000000 +0300 | |
+++ core-2.3.20/src/auth/db-checkpassword.c 2023-02-09 11:22:36.282856675 +0300 | |
@@ -116,8 +116,20 @@ | |
checkpassword_request_finish_auth(struct chkpw_auth_request *request) | |
{ | |
switch (request->exit_status) { | |
+ /* vpopmail exit codes: */ | |
+ case 3: /* password fail / vpopmail user not found */ | |
+ case 12: /* null user name given */ | |
+ case 13: /* null password given */ | |
+ case 15: /* user has no password */ | |
+ case 20: /* invalid user/domain characters */ | |
+ case 21: /* system user not found */ | |
+ case 22: /* system user shadow entry not found */ | |
+ case 23: /* system password fail */ | |
+ | |
/* standard checkpassword exit codes: */ | |
case 1: | |
+ /* (1 is additionally defined in vpopmail for | |
+ "pop/smtp/webmail/ imap/access denied") */ | |
e_info(authdb_event(request->request), | |
"Login failed (status=%d)", | |
request->exit_status); | |
diff -ruN core-2.3.20-original/src/auth/Makefile.am core-2.3.20/src/auth/Makefile.am | |
--- core-2.3.20-original/src/auth/Makefile.am 2022-12-19 12:38:16.000000000 +0300 | |
+++ core-2.3.20/src/auth/Makefile.am 2023-02-09 11:22:36.282856675 +0300 | |
@@ -139,6 +139,7 @@ | |
passdb-passwd-file.c \ | |
passdb-pam.c \ | |
passdb-shadow.c \ | |
+ passdb-vpopmail.c \ | |
passdb-sql.c \ | |
passdb-static.c \ | |
passdb-template.c \ | |
@@ -150,6 +151,7 @@ | |
userdb-passwd-file.c \ | |
userdb-prefetch.c \ | |
userdb-static.c \ | |
+ userdb-vpopmail.c \ | |
userdb-sql.c \ | |
userdb-template.c \ | |
$(ldap_sources) \ | |
@@ -193,7 +195,8 @@ | |
password-scheme.h \ | |
userdb.h \ | |
userdb-blocking.h \ | |
- userdb-template.h | |
+ userdb-template.h \ | |
+ userdb-vpopmail.h | |
if GSSAPI_PLUGIN | |
libmech_gssapi_la_LDFLAGS = -module -avoid-version | |
diff -ruN core-2.3.20-original/src/auth/passdb.c core-2.3.20/src/auth/passdb.c | |
--- core-2.3.20-original/src/auth/passdb.c 2022-12-19 12:38:16.000000000 +0300 | |
+++ core-2.3.20/src/auth/passdb.c 2023-02-09 11:22:36.282856675 +0300 | |
@@ -319,6 +319,7 @@ | |
extern struct passdb_module_interface passdb_passwd_file; | |
extern struct passdb_module_interface passdb_pam; | |
extern struct passdb_module_interface passdb_checkpassword; | |
+extern struct passdb_module_interface passdb_vpopmail; | |
extern struct passdb_module_interface passdb_ldap; | |
extern struct passdb_module_interface passdb_sql; | |
extern struct passdb_module_interface passdb_static; | |
@@ -338,6 +339,7 @@ | |
passdb_register_module(&passdb_pam); | |
passdb_register_module(&passdb_checkpassword); | |
passdb_register_module(&passdb_shadow); | |
+ passdb_register_module(&passdb_vpopmail); | |
passdb_register_module(&passdb_ldap); | |
passdb_register_module(&passdb_sql); | |
passdb_register_module(&passdb_static); | |
diff -ruN core-2.3.20-original/src/auth/passdb-vpopmail.c core-2.3.20/src/auth/passdb-vpopmail.c | |
--- core-2.3.20-original/src/auth/passdb-vpopmail.c 1970-01-01 02:00:00.000000000 +0200 | |
+++ core-2.3.20/src/auth/passdb-vpopmail.c 2023-02-09 11:22:36.282856675 +0300 | |
@@ -0,0 +1,229 @@ | |
+/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ | |
+ | |
+/* Thanks to Courier-IMAP for showing how the vpopmail API should be used */ | |
+ | |
+#include "auth-common.h" | |
+#include "passdb.h" | |
+ | |
+#ifdef PASSDB_VPOPMAIL | |
+ | |
+#include "safe-memset.h" | |
+#include "password-scheme.h" | |
+#include "auth-cache.h" | |
+ | |
+#include "userdb-vpopmail.h" | |
+ | |
+ | |
+#define VPOPMAIL_DEFAULT_PASS_SCHEME "CRYPT" | |
+ | |
+/* pw_flags was added in vpopmail 5.4, olders use pw_gid field */ | |
+#ifndef VQPASSWD_HAS_PW_FLAGS | |
+# define pw_flags pw_gid | |
+#endif | |
+ | |
+struct vpopmail_passdb_module { | |
+ struct passdb_module module; | |
+ | |
+ struct ip_addr webmail_ip; | |
+}; | |
+ | |
+static bool vpopmail_is_disabled(struct auth_request *request, | |
+ const struct vqpasswd *vpw) | |
+{ | |
+ struct passdb_module *_module = request->passdb->passdb; | |
+ struct vpopmail_passdb_module *module = | |
+ (struct vpopmail_passdb_module *)_module; | |
+ | |
+ if (strcasecmp(request->fields.service, "IMAP") == 0) { | |
+ if ((vpw->pw_flags & NO_IMAP) != 0) { | |
+ /* IMAP from webmail IP may still be allowed */ | |
+ if (!net_ip_compare(&module->webmail_ip, | |
+ &request->fields.remote_ip)) | |
+ return TRUE; | |
+ } | |
+ if ((vpw->pw_flags & NO_WEBMAIL) != 0) { | |
+ if (net_ip_compare(&module->webmail_ip, | |
+ &request->fields.remote_ip)) | |
+ return TRUE; | |
+ } | |
+ } | |
+ if ((vpw->pw_flags & NO_POP) != 0 && | |
+ strcasecmp(request->fields.service, "POP3") == 0) | |
+ return TRUE; | |
+ if ((vpw->pw_flags & NO_SMTP) != 0 && | |
+ strcasecmp(request->fields.service, "SMTP") == 0) | |
+ return TRUE; | |
+ return FALSE; | |
+} | |
+ | |
+static char * | |
+vpopmail_password_lookup(struct auth_request *auth_request, bool *cleartext, | |
+ enum passdb_result *result_r) | |
+{ | |
+ char vpop_user[VPOPMAIL_LIMIT], vpop_domain[VPOPMAIL_LIMIT]; | |
+ struct vqpasswd *vpw; | |
+ char *password; | |
+ | |
+ vpw = vpopmail_lookup_vqp(auth_request, vpop_user, vpop_domain); | |
+ if (vpw == NULL) { | |
+ *result_r = PASSDB_RESULT_USER_UNKNOWN; | |
+ return NULL; | |
+ } | |
+ | |
+ if (vpopmail_is_disabled(auth_request, vpw)) { | |
+ e_info(authdb_event(auth_request), | |
+ "%s disabled in vpopmail for this user", | |
+ auth_request->fields.service); | |
+ password = NULL; | |
+ *result_r = PASSDB_RESULT_USER_DISABLED; | |
+ } else { | |
+ if (vpw->pw_clear_passwd != NULL && | |
+ *vpw->pw_clear_passwd != '\0') { | |
+ password = t_strdup_noconst(vpw->pw_clear_passwd); | |
+ *cleartext = TRUE; | |
+ } else if (!*cleartext) | |
+ password = t_strdup_noconst(vpw->pw_passwd); | |
+ else | |
+ password = NULL; | |
+ *result_r = password != NULL ? PASSDB_RESULT_OK : | |
+ PASSDB_RESULT_SCHEME_NOT_AVAILABLE; | |
+ } | |
+ | |
+ safe_memset(vpw->pw_passwd, 0, strlen(vpw->pw_passwd)); | |
+ if (vpw->pw_clear_passwd != NULL) { | |
+ safe_memset(vpw->pw_clear_passwd, 0, | |
+ strlen(vpw->pw_clear_passwd)); | |
+ } | |
+ | |
+ return password; | |
+} | |
+ | |
+static void vpopmail_lookup_credentials(struct auth_request *request, | |
+ lookup_credentials_callback_t *callback) | |
+{ | |
+ enum passdb_result result; | |
+ char *password; | |
+ bool cleartext = TRUE; | |
+ | |
+ password = vpopmail_password_lookup(request, &cleartext, &result); | |
+ if (password == NULL) { | |
+ callback(result, NULL, 0, request); | |
+ return; | |
+ } | |
+ | |
+ passdb_handle_credentials(PASSDB_RESULT_OK, password, "CLEARTEXT", | |
+ callback, request); | |
+ safe_memset(password, 0, strlen(password)); | |
+} | |
+ | |
+static void | |
+vpopmail_verify_plain(struct auth_request *request, const char *password, | |
+ verify_plain_callback_t *callback) | |
+{ | |
+ enum passdb_result result; | |
+ const char *scheme, *tmp_pass; | |
+ char *crypted_pass; | |
+ bool cleartext = FALSE; | |
+ int ret; | |
+ | |
+ crypted_pass = vpopmail_password_lookup(request, &cleartext, &result); | |
+ if (crypted_pass == NULL) { | |
+ callback(result, request); | |
+ return; | |
+ } | |
+ tmp_pass = crypted_pass; | |
+ | |
+ if (cleartext) | |
+ scheme = "CLEARTEXT"; | |
+ else { | |
+ scheme = password_get_scheme(&tmp_pass); | |
+ if (scheme == NULL) | |
+ scheme = request->passdb->passdb->default_pass_scheme; | |
+ } | |
+ | |
+ ret = auth_request_password_verify(request, password, tmp_pass, | |
+ scheme, AUTH_SUBSYS_DB); | |
+ safe_memset(crypted_pass, 0, strlen(crypted_pass)); | |
+ | |
+ if (ret <= 0) { | |
+ callback(PASSDB_RESULT_PASSWORD_MISMATCH, request); | |
+ return; | |
+ } | |
+ | |
+#ifdef POP_AUTH_OPEN_RELAY | |
+ if (strcasecmp(request->fields.service, "POP3") == 0 || | |
+ strcasecmp(request->fields.service, "IMAP") == 0) { | |
+ const char *host = net_ip2addr(&request->fields.remote_ip); | |
+ /* vpopmail 5.4 does not understand IPv6 */ | |
+ if (host[0] != '\0' && IPADDR_IS_V4(&request->fields.remote_ip)) { | |
+ /* use putenv() directly rather than env_put() which | |
+ would leak memory every time we got here. use a | |
+ static buffer for putenv() as SUSv2 requirements | |
+ would otherwise corrupt our environment later. */ | |
+ static char ip_env[256]; | |
+ | |
+ i_snprintf(ip_env, sizeof(ip_env), | |
+ "TCPREMOTEIP=%s", host); | |
+ putenv(ip_env); | |
+ open_smtp_relay(); | |
+ } | |
+ } | |
+#endif | |
+ | |
+ callback(PASSDB_RESULT_OK, request); | |
+} | |
+ | |
+static struct passdb_module * | |
+vpopmail_preinit(pool_t pool, const char *args) | |
+{ | |
+ static bool vauth_load_initialized = FALSE; | |
+ struct vpopmail_passdb_module *module; | |
+ const char *const *tmp; | |
+ | |
+ module = p_new(pool, struct vpopmail_passdb_module, 1); | |
+ module->module.default_pass_scheme = VPOPMAIL_DEFAULT_PASS_SCHEME; | |
+ module->module.blocking = TRUE; | |
+ | |
+ tmp = t_strsplit_spaces(args, " "); | |
+ for (; *tmp != NULL; tmp++) { | |
+ if (str_begins(*tmp, "cache_key=")) { | |
+ module->module.default_cache_key = | |
+ auth_cache_parse_key(pool, *tmp + 10); | |
+ } else if (str_begins(*tmp, "webmail=")) { | |
+ if (net_addr2ip(*tmp + 8, &module->webmail_ip) < 0) | |
+ i_fatal("vpopmail: Invalid webmail IP address"); | |
+ } else if (strcmp(*tmp, "blocking=no") == 0) { | |
+ module->module.blocking = FALSE; | |
+ } else { | |
+ i_fatal("passdb vpopmail: Unknown setting: %s", *tmp); | |
+ } | |
+ } | |
+ if (!vauth_load_initialized) { | |
+ vauth_load_initialized = TRUE; | |
+ if (vauth_open(0) != 0) | |
+ i_fatal("vpopmail: vauth_open() failed"); | |
+ } | |
+ return &module->module; | |
+} | |
+ | |
+static void vpopmail_deinit(struct passdb_module *module ATTR_UNUSED) | |
+{ | |
+ vclose(); | |
+} | |
+ | |
+struct passdb_module_interface passdb_vpopmail = { | |
+ "vpopmail", | |
+ | |
+ vpopmail_preinit, | |
+ NULL, | |
+ vpopmail_deinit, | |
+ | |
+ vpopmail_verify_plain, | |
+ vpopmail_lookup_credentials, | |
+ NULL | |
+}; | |
+#else | |
+struct passdb_module_interface passdb_vpopmail = { | |
+ .name = "vpopmail" | |
+}; | |
+#endif | |
diff -ruN core-2.3.20-original/src/auth/userdb.c core-2.3.20/src/auth/userdb.c | |
--- core-2.3.20-original/src/auth/userdb.c 2022-12-19 12:38:16.000000000 +0300 | |
+++ core-2.3.20/src/auth/userdb.c 2023-02-09 11:22:36.286856471 +0300 | |
@@ -224,6 +224,7 @@ | |
extern struct userdb_module_interface userdb_static; | |
extern struct userdb_module_interface userdb_passwd; | |
extern struct userdb_module_interface userdb_passwd_file; | |
+extern struct userdb_module_interface userdb_vpopmail; | |
extern struct userdb_module_interface userdb_ldap; | |
extern struct userdb_module_interface userdb_sql; | |
extern struct userdb_module_interface userdb_checkpassword; | |
@@ -240,6 +241,7 @@ | |
userdb_register_module(&userdb_passwd_file); | |
userdb_register_module(&userdb_prefetch); | |
userdb_register_module(&userdb_static); | |
+ userdb_register_module(&userdb_vpopmail); | |
userdb_register_module(&userdb_ldap); | |
userdb_register_module(&userdb_sql); | |
userdb_register_module(&userdb_checkpassword); | |
diff -ruN core-2.3.20-original/src/auth/userdb-vpopmail.c core-2.3.20/src/auth/userdb-vpopmail.c | |
--- core-2.3.20-original/src/auth/userdb-vpopmail.c 1970-01-01 02:00:00.000000000 +0200 | |
+++ core-2.3.20/src/auth/userdb-vpopmail.c 2023-02-09 11:22:36.286856471 +0300 | |
@@ -0,0 +1,202 @@ | |
+/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ | |
+ | |
+/* Thanks to Courier-IMAP for showing how the vpopmail API should be used */ | |
+ | |
+#include "auth-common.h" | |
+#include "userdb.h" | |
+ | |
+#if defined(PASSDB_VPOPMAIL) || defined(USERDB_VPOPMAIL) | |
+#include "str.h" | |
+#include "var-expand.h" | |
+#include "userdb-vpopmail.h" | |
+ | |
+struct vpopmail_userdb_module { | |
+ struct userdb_module module; | |
+ | |
+ const char *quota_template_key; | |
+ const char *quota_template_value; | |
+}; | |
+ | |
+struct vqpasswd *vpopmail_lookup_vqp(struct auth_request *request, | |
+ char vpop_user[VPOPMAIL_LIMIT], | |
+ char vpop_domain[VPOPMAIL_LIMIT]) | |
+{ | |
+ struct vqpasswd *vpw; | |
+ | |
+ /* vpop_user must be zero-filled or parse_email() leaves an | |
+ extra character after the user name. we'll fill vpop_domain | |
+ as well just to be sure... */ | |
+ memset(vpop_user, '\0', VPOPMAIL_LIMIT); | |
+ memset(vpop_domain, '\0', VPOPMAIL_LIMIT); | |
+ | |
+ if (parse_email(request->fields.user, vpop_user, vpop_domain, | |
+ VPOPMAIL_LIMIT-1) < 0) { | |
+ e_info(authdb_event(request), | |
+ "parse_email() failed"); | |
+ return NULL; | |
+ } | |
+ | |
+ e_debug(authdb_event(request), | |
+ "lookup user=%s domain=%s", | |
+ vpop_user, vpop_domain); | |
+ | |
+ vpw = vauth_getpw(vpop_user, vpop_domain); | |
+ if (vpw == NULL) { | |
+ auth_request_log_unknown_user(request, AUTH_SUBSYS_DB); | |
+ return NULL; | |
+ } | |
+ | |
+ return vpw; | |
+} | |
+#endif | |
+ | |
+#ifdef USERDB_VPOPMAIL | |
+static int | |
+userdb_vpopmail_get_quota(const char *template, const char *vpop_str, | |
+ const char **quota_r, const char **error_r) | |
+{ | |
+ struct var_expand_table *tab; | |
+ string_t *quota; | |
+ | |
+ if (template == NULL || *vpop_str == '\0' || | |
+ strcmp(vpop_str, "NOQUOTA") == 0) { | |
+ *quota_r = ""; | |
+ return 0; | |
+ } | |
+ | |
+ tab = t_new(struct var_expand_table, 2); | |
+ tab[0].key = 'q'; | |
+ tab[0].value = format_maildirquota(vpop_str); | |
+ | |
+ quota = t_str_new(128); | |
+ if (var_expand(quota, template, tab, error_r) < 0) | |
+ return -1; | |
+ | |
+ *quota_r = str_c(quota); | |
+ return 0; | |
+} | |
+ | |
+static void vpopmail_lookup(struct auth_request *auth_request, | |
+ userdb_callback_t *callback) | |
+{ | |
+ struct userdb_module *_module = auth_request->userdb->userdb; | |
+ struct vpopmail_userdb_module *module = | |
+ (struct vpopmail_userdb_module *)_module; | |
+ char vpop_user[VPOPMAIL_LIMIT], vpop_domain[VPOPMAIL_LIMIT]; | |
+ struct vqpasswd *vpw; | |
+ const char *quota, *error; | |
+ uid_t uid; | |
+ gid_t gid; | |
+ | |
+ vpw = vpopmail_lookup_vqp(auth_request, vpop_user, vpop_domain); | |
+ if (vpw == NULL) { | |
+ callback(USERDB_RESULT_USER_UNKNOWN, auth_request); | |
+ return; | |
+ } | |
+ | |
+ /* we have to get uid/gid separately, because the gid field in | |
+ struct vqpasswd isn't really gid at all but just some flags... */ | |
+ if (vget_assign(vpop_domain, NULL, 0, &uid, &gid) == NULL) { | |
+ e_info(authdb_event(auth_request), | |
+ "vget_assign(%s) failed", vpop_domain); | |
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request); | |
+ return; | |
+ } | |
+ | |
+ if (auth_request->fields.successful) { | |
+ /* update the last login only when we're really */ | |
+ vset_lastauth(vpop_user, vpop_domain, | |
+ t_strdup_noconst(auth_request->fields.service)); | |
+ } | |
+ | |
+ if (vpw->pw_dir == NULL || vpw->pw_dir[0] == '\0') { | |
+ /* user's homedir doesn't exist yet, create it */ | |
+ e_info(authdb_event(auth_request), | |
+ "pw_dir isn't set, creating"); | |
+ | |
+ if (make_user_dir(vpop_user, vpop_domain, uid, gid) == NULL) { | |
+ e_error(authdb_event(auth_request), | |
+ "make_user_dir(%s, %s) failed", | |
+ vpop_user, vpop_domain); | |
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request); | |
+ return; | |
+ } | |
+ | |
+ /* get the user again so pw_dir is visible */ | |
+ vpw = vauth_getpw(vpop_user, vpop_domain); | |
+ if (vpw == NULL) { | |
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request); | |
+ return; | |
+ } | |
+ } | |
+ | |
+ if (userdb_vpopmail_get_quota(module->quota_template_value, | |
+ vpw->pw_shell, "a, &error) < 0) { | |
+ e_error(authdb_event(auth_request), | |
+ "userdb_vpopmail_get_quota(%s, %s) failed: %s", | |
+ module->quota_template_value, | |
+ vpw->pw_shell, error); | |
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request); | |
+ return; | |
+ } | |
+ | |
+ auth_request_set_userdb_field(auth_request, "uid", dec2str(uid)); | |
+ auth_request_set_userdb_field(auth_request, "gid", dec2str(gid)); | |
+ auth_request_set_userdb_field(auth_request, "home", vpw->pw_dir); | |
+ | |
+ if (*quota != '\0') { | |
+ auth_request_set_userdb_field(auth_request, | |
+ module->quota_template_key, | |
+ quota); | |
+ } | |
+ callback(USERDB_RESULT_OK, auth_request); | |
+} | |
+ | |
+static struct userdb_module * | |
+vpopmail_preinit(pool_t pool, const char *args) | |
+{ | |
+ struct vpopmail_userdb_module *module; | |
+ const char *const *tmp, *p; | |
+ | |
+ module = p_new(pool, struct vpopmail_userdb_module, 1); | |
+ module->module.blocking = TRUE; | |
+ | |
+ for (tmp = t_strsplit(args, " "); *tmp != NULL; tmp++) { | |
+ if (str_begins(*tmp, "cache_key=")) | |
+ module->module.default_cache_key = | |
+ p_strdup(pool, *tmp + 10); | |
+ else if (str_begins(*tmp, "quota_template=")) { | |
+ p = strchr(*tmp + 15, '='); | |
+ if (p == NULL) { | |
+ i_fatal("vpopmail userdb: " | |
+ "quota_template missing '='"); | |
+ } | |
+ module->quota_template_key = | |
+ p_strdup_until(pool, *tmp + 15, p); | |
+ module->quota_template_value = p_strdup(pool, p + 1); | |
+ } else if (strcmp(*tmp, "blocking=no") == 0) { | |
+ module->module.blocking = FALSE; | |
+ } else | |
+ i_fatal("userdb vpopmail: Unknown setting: %s", *tmp); | |
+ } | |
+ return &module->module; | |
+} | |
+ | |
+struct userdb_module_interface userdb_vpopmail = { | |
+ "vpopmail", | |
+ | |
+ vpopmail_preinit, | |
+ NULL, | |
+ NULL, | |
+ | |
+ vpopmail_lookup, | |
+ | |
+ NULL, | |
+ NULL, | |
+ NULL | |
+}; | |
+#else | |
+struct userdb_module_interface userdb_vpopmail = { | |
+ .name = "vpopmail" | |
+}; | |
+#endif | |
diff -ruN core-2.3.20-original/src/auth/userdb-vpopmail.h core-2.3.20/src/auth/userdb-vpopmail.h | |
--- core-2.3.20-original/src/auth/userdb-vpopmail.h 1970-01-01 02:00:00.000000000 +0200 | |
+++ core-2.3.20/src/auth/userdb-vpopmail.h 2023-02-09 11:22:36.286856471 +0300 | |
@@ -0,0 +1,17 @@ | |
+#ifndef USERDB_VPOPMAIL_H | |
+#define USERDB_VPOPMAIL_H | |
+ | |
+#include <stdio.h> | |
+#include <vpopmail.h> | |
+#include <vauth.h> | |
+ | |
+/* Limit user and domain to 80 chars each (+1 for \0). I wouldn't recommend | |
+ raising this limit at least much, vpopmail is full of potential buffer | |
+ overflows. */ | |
+#define VPOPMAIL_LIMIT 81 | |
+ | |
+struct vqpasswd *vpopmail_lookup_vqp(struct auth_request *request, | |
+ char vpop_user[VPOPMAIL_LIMIT], | |
+ char vpop_domain[VPOPMAIL_LIMIT]); | |
+ | |
+#endif | |
diff -ruN core-2.3.20-original/src/master/main.c core-2.3.20/src/master/main.c | |
--- core-2.3.20-original/src/master/main.c 2022-12-19 12:38:16.000000000 +0300 | |
+++ core-2.3.20/src/master/main.c 2023-02-09 11:22:36.286856471 +0300 | |
@@ -731,6 +731,9 @@ | |
#ifdef PASSDB_SQL | |
" sql" | |
#endif | |
+#ifdef PASSDB_VPOPMAIL | |
+ " vpopmail" | |
+#endif | |
"\nUserdb:" | |
#ifdef USERDB_CHECKPASSWORD | |
" checkpassword" | |
@@ -759,6 +762,9 @@ | |
#ifdef USERDB_STATIC | |
" static" | |
#endif | |
+#ifdef USERDB_VPOPMAIL | |
+ " vpopmail" | |
+#endif | |
"\n", IO_BLOCK_SIZE); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment