Line 0
Link Here
|
|
|
1 |
diff -ruN ../dovecot-2.3.13.orig/configure.ac ./configure.ac |
2 |
--- ../dovecot-2.3.13.orig/configure.ac 2020-12-22 14:26:52.000000000 +0100 |
3 |
+++ ./configure.ac 2021-01-29 14:26:35.068783000 +0100 |
4 |
@@ -91,6 +91,22 @@ |
5 |
TEST_WITH(libunwind, $withval), |
6 |
want_libunwind=auto) |
7 |
|
8 |
+AC_ARG_WITH(vpopmail, |
9 |
+AS_HELP_STRING([--with-vpopmail], [Build with vpopmail support (auto)]), |
10 |
+ if test x$withval = xno; then |
11 |
+ want_vpopmail=no |
12 |
+ else |
13 |
+ if test x$withval = xyes || test x$withval = xauto; then |
14 |
+ vpopmail_home="`echo ~vpopmail`" |
15 |
+ want_vpopmail=$withval |
16 |
+ else |
17 |
+ vpopmail_home="$withval" |
18 |
+ want_vpopmail=yes |
19 |
+ fi |
20 |
+ fi, [ |
21 |
+ want_vpopmail=no |
22 |
+ ]) |
23 |
+ |
24 |
# Berkeley DB support is more or less broken. Disabled for now. |
25 |
#AC_ARG_WITH(db, |
26 |
#AS_HELP_STRING([--with-db], [Build with Berkeley DB support]), |
27 |
@@ -548,6 +564,7 @@ |
28 |
DOVECOT_WANT_SODIUM |
29 |
DOVECOT_WANT_SQLITE |
30 |
DOVECOT_WANT_CASSANDRA |
31 |
+DOVECOT_WANT_VPOPMAIL |
32 |
|
33 |
DOVECOT_SQL |
34 |
|
35 |
diff -ruN ../dovecot-2.3.13.orig/doc/example-config/conf.d/10-auth.conf ./doc/example-config/conf.d/10-auth.conf |
36 |
--- ../dovecot-2.3.13.orig/doc/example-config/conf.d/10-auth.conf 2020-12-22 14:26:52.000000000 +0100 |
37 |
+++ ./doc/example-config/conf.d/10-auth.conf 2021-01-29 13:21:19.267469000 +0100 |
38 |
@@ -10,7 +10,7 @@ |
39 |
#disable_plaintext_auth = yes |
40 |
|
41 |
# Authentication cache size (e.g. 10M). 0 means it's disabled. Note that |
42 |
-# bsdauth and PAM require cache_key to be set for caching to be used. |
43 |
+# bsdauth, PAM and vpopmail require cache_key to be set for caching to be used. |
44 |
#auth_cache_size = 0 |
45 |
# Time to live for cached data. After TTL expires the cached record is no |
46 |
# longer used, *except* if the main database lookup returns internal failure. |
47 |
@@ -124,4 +124,5 @@ |
48 |
#!include auth-ldap.conf.ext |
49 |
#!include auth-passwdfile.conf.ext |
50 |
#!include auth-checkpassword.conf.ext |
51 |
+#!include auth-vpopmail.conf.ext |
52 |
#!include auth-static.conf.ext |
53 |
diff -ruN ../dovecot-2.3.13.orig/doc/example-config/conf.d/Makefile.am ./doc/example-config/conf.d/Makefile.am |
54 |
--- ../dovecot-2.3.13.orig/doc/example-config/conf.d/Makefile.am 2020-12-22 14:26:52.000000000 +0100 |
55 |
+++ ./doc/example-config/conf.d/Makefile.am 2021-01-29 13:21:19.268070000 +0100 |
56 |
@@ -11,6 +11,7 @@ |
57 |
auth-sql.conf.ext \ |
58 |
auth-static.conf.ext \ |
59 |
auth-system.conf.ext \ |
60 |
+ auth-vpopmail.conf.ext \ |
61 |
10-auth.conf \ |
62 |
10-director.conf \ |
63 |
10-logging.conf \ |
64 |
diff -ruN ../dovecot-2.3.13.orig/doc/example-config/conf.d/auth-vpopmail.conf.ext ./doc/example-config/conf.d/auth-vpopmail.conf.ext |
65 |
--- ../dovecot-2.3.13.orig/doc/example-config/conf.d/auth-vpopmail.conf.ext 1970-01-01 01:00:00.000000000 +0100 |
66 |
+++ ./doc/example-config/conf.d/auth-vpopmail.conf.ext 2021-01-29 13:24:12.341999000 +0100 |
67 |
@@ -0,0 +1,17 @@ |
68 |
+# Authentication for vpopmail users. Included from 10-auth.conf. |
69 |
+# |
70 |
+# <doc/wiki/AuthDatabase.VPopMail.txt> |
71 |
+ |
72 |
+passdb { |
73 |
+ driver = vpopmail |
74 |
+ |
75 |
+ # [cache_key=<key>] [webmail=<ip>] |
76 |
+ args = |
77 |
+} |
78 |
+ |
79 |
+userdb { |
80 |
+ driver = vpopmail |
81 |
+ |
82 |
+ # [quota_template=<template>] - %q expands to Maildir++ quota |
83 |
+ args = quota_template=quota_rule=*:backend=%q |
84 |
+} |
85 |
diff -ruN ../dovecot-2.3.13.orig/m4/want_vpopmail.m4 ./m4/want_vpopmail.m4 |
86 |
--- ../dovecot-2.3.13.orig/m4/want_vpopmail.m4 1970-01-01 01:00:00.000000000 +0100 |
87 |
+++ ./m4/want_vpopmail.m4 2021-01-29 13:24:40.287852000 +0100 |
88 |
@@ -0,0 +1,33 @@ |
89 |
+AC_DEFUN([DOVECOT_WANT_VPOPMAIL], [ |
90 |
+ have_vpopmail=no |
91 |
+ if test $want_vpopmail != no; then |
92 |
+ vpop_etc="$vpopmail_home/etc" |
93 |
+ AC_MSG_CHECKING([for vpopmail configuration at $vpop_etc/lib_deps]) |
94 |
+ if ! test -f $vpop_etc/lib_deps; then |
95 |
+ AC_MSG_RESULT(not found) |
96 |
+ vpop_etc="$vpopmail_home" |
97 |
+ AC_MSG_CHECKING([for vpopmail configuration at $vpop_etc/lib_deps]) |
98 |
+ fi |
99 |
+ if test -f $vpop_etc/lib_deps; then |
100 |
+ AUTH_CFLAGS="$AUTH_CFLAGS `cat $vpop_etc/inc_deps` $CFLAGS" |
101 |
+ AUTH_LIBS="$AUTH_LIBS `cat $vpop_etc/lib_deps`" |
102 |
+ AC_DEFINE(USERDB_VPOPMAIL,, [Build with vpopmail support]) |
103 |
+ AC_DEFINE(PASSDB_VPOPMAIL,, [Build with vpopmail support]) |
104 |
+ AC_MSG_RESULT(found) |
105 |
+ have_vpopmail=yes |
106 |
+ else |
107 |
+ AC_MSG_RESULT(not found) |
108 |
+ if test $want_vpopmail = yes; then |
109 |
+ AC_ERROR([Can't build with vpopmail support: $vpop_etc/lib_deps not found]) |
110 |
+ fi |
111 |
+ fi |
112 |
+ fi |
113 |
+ |
114 |
+ if test $have_vpopmail = no; then |
115 |
+ not_passdb="$not_passdb vpopmail" |
116 |
+ not_userdb="$not_userdb vpopmail" |
117 |
+ else |
118 |
+ userdb="$userdb vpopmail" |
119 |
+ passdb="$passdb vpopmail" |
120 |
+ fi |
121 |
+]) |
122 |
diff -ruN ../dovecot-2.3.13.orig/src/auth/Makefile.am ./src/auth/Makefile.am |
123 |
--- ../dovecot-2.3.13.orig/src/auth/Makefile.am 2020-12-22 14:26:52.000000000 +0100 |
124 |
+++ ./src/auth/Makefile.am 2021-01-29 13:21:19.270313000 +0100 |
125 |
@@ -134,6 +134,7 @@ |
126 |
passdb-passwd-file.c \ |
127 |
passdb-pam.c \ |
128 |
passdb-shadow.c \ |
129 |
+ passdb-vpopmail.c \ |
130 |
passdb-sql.c \ |
131 |
passdb-static.c \ |
132 |
passdb-template.c \ |
133 |
@@ -145,6 +146,7 @@ |
134 |
userdb-passwd-file.c \ |
135 |
userdb-prefetch.c \ |
136 |
userdb-static.c \ |
137 |
+ userdb-vpopmail.c \ |
138 |
userdb-sql.c \ |
139 |
userdb-template.c \ |
140 |
$(ldap_sources) \ |
141 |
@@ -188,7 +190,8 @@ |
142 |
password-scheme.h \ |
143 |
userdb.h \ |
144 |
userdb-blocking.h \ |
145 |
- userdb-template.h |
146 |
+ userdb-template.h \ |
147 |
+ userdb-vpopmail.h |
148 |
|
149 |
if GSSAPI_PLUGIN |
150 |
libmech_gssapi_la_LDFLAGS = -module -avoid-version |
151 |
diff -ruN ../dovecot-2.3.13.orig/src/auth/db-checkpassword.c ./src/auth/db-checkpassword.c |
152 |
--- ../dovecot-2.3.13.orig/src/auth/db-checkpassword.c 2020-12-22 14:26:52.000000000 +0100 |
153 |
+++ ./src/auth/db-checkpassword.c 2021-01-29 13:21:19.271324000 +0100 |
154 |
@@ -116,8 +116,20 @@ |
155 |
checkpassword_request_finish_auth(struct chkpw_auth_request *request) |
156 |
{ |
157 |
switch (request->exit_status) { |
158 |
+ /* vpopmail exit codes: */ |
159 |
+ case 3: /* password fail / vpopmail user not found */ |
160 |
+ case 12: /* null user name given */ |
161 |
+ case 13: /* null password given */ |
162 |
+ case 15: /* user has no password */ |
163 |
+ case 20: /* invalid user/domain characters */ |
164 |
+ case 21: /* system user not found */ |
165 |
+ case 22: /* system user shadow entry not found */ |
166 |
+ case 23: /* system password fail */ |
167 |
+ |
168 |
/* standard checkpassword exit codes: */ |
169 |
case 1: |
170 |
+ /* (1 is additionally defined in vpopmail for |
171 |
+ "pop/smtp/webmail/ imap/access denied") */ |
172 |
e_info(authdb_event(request->request), |
173 |
"Login failed (status=%d)", |
174 |
request->exit_status); |
175 |
diff -ruN ../dovecot-2.3.13.orig/src/auth/passdb-vpopmail.c ./src/auth/passdb-vpopmail.c |
176 |
--- ../dovecot-2.3.13.orig/src/auth/passdb-vpopmail.c 1970-01-01 01:00:00.000000000 +0100 |
177 |
+++ ./src/auth/passdb-vpopmail.c 2021-01-29 13:23:23.979572000 +0100 |
178 |
@@ -0,0 +1,229 @@ |
179 |
+/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ |
180 |
+ |
181 |
+/* Thanks to Courier-IMAP for showing how the vpopmail API should be used */ |
182 |
+ |
183 |
+#include "auth-common.h" |
184 |
+#include "passdb.h" |
185 |
+ |
186 |
+#ifdef PASSDB_VPOPMAIL |
187 |
+ |
188 |
+#include "safe-memset.h" |
189 |
+#include "password-scheme.h" |
190 |
+#include "auth-cache.h" |
191 |
+ |
192 |
+#include "userdb-vpopmail.h" |
193 |
+ |
194 |
+ |
195 |
+#define VPOPMAIL_DEFAULT_PASS_SCHEME "CRYPT" |
196 |
+ |
197 |
+/* pw_flags was added in vpopmail 5.4, olders use pw_gid field */ |
198 |
+#ifndef VQPASSWD_HAS_PW_FLAGS |
199 |
+# define pw_flags pw_gid |
200 |
+#endif |
201 |
+ |
202 |
+struct vpopmail_passdb_module { |
203 |
+ struct passdb_module module; |
204 |
+ |
205 |
+ struct ip_addr webmail_ip; |
206 |
+}; |
207 |
+ |
208 |
+static bool vpopmail_is_disabled(struct auth_request *request, |
209 |
+ const struct vqpasswd *vpw) |
210 |
+{ |
211 |
+ struct passdb_module *_module = request->passdb->passdb; |
212 |
+ struct vpopmail_passdb_module *module = |
213 |
+ (struct vpopmail_passdb_module *)_module; |
214 |
+ |
215 |
+ if (strcasecmp(request->fields.service, "IMAP") == 0) { |
216 |
+ if ((vpw->pw_flags & NO_IMAP) != 0) { |
217 |
+ /* IMAP from webmail IP may still be allowed */ |
218 |
+ if (!net_ip_compare(&module->webmail_ip, |
219 |
+ &request->fields.remote_ip)) |
220 |
+ return TRUE; |
221 |
+ } |
222 |
+ if ((vpw->pw_flags & NO_WEBMAIL) != 0) { |
223 |
+ if (net_ip_compare(&module->webmail_ip, |
224 |
+ &request->fields.remote_ip)) |
225 |
+ return TRUE; |
226 |
+ } |
227 |
+ } |
228 |
+ if ((vpw->pw_flags & NO_POP) != 0 && |
229 |
+ strcasecmp(request->fields.service, "POP3") == 0) |
230 |
+ return TRUE; |
231 |
+ if ((vpw->pw_flags & NO_SMTP) != 0 && |
232 |
+ strcasecmp(request->fields.service, "SMTP") == 0) |
233 |
+ return TRUE; |
234 |
+ return FALSE; |
235 |
+} |
236 |
+ |
237 |
+static char * |
238 |
+vpopmail_password_lookup(struct auth_request *auth_request, bool *cleartext, |
239 |
+ enum passdb_result *result_r) |
240 |
+{ |
241 |
+ char vpop_user[VPOPMAIL_LIMIT], vpop_domain[VPOPMAIL_LIMIT]; |
242 |
+ struct vqpasswd *vpw; |
243 |
+ char *password; |
244 |
+ |
245 |
+ vpw = vpopmail_lookup_vqp(auth_request, vpop_user, vpop_domain); |
246 |
+ if (vpw == NULL) { |
247 |
+ *result_r = PASSDB_RESULT_USER_UNKNOWN; |
248 |
+ return NULL; |
249 |
+ } |
250 |
+ |
251 |
+ if (vpopmail_is_disabled(auth_request, vpw)) { |
252 |
+ e_info(authdb_event(auth_request), |
253 |
+ "%s disabled in vpopmail for this user", |
254 |
+ auth_request->fields.service); |
255 |
+ password = NULL; |
256 |
+ *result_r = PASSDB_RESULT_USER_DISABLED; |
257 |
+ } else { |
258 |
+ if (vpw->pw_clear_passwd != NULL && |
259 |
+ *vpw->pw_clear_passwd != '\0') { |
260 |
+ password = t_strdup_noconst(vpw->pw_clear_passwd); |
261 |
+ *cleartext = TRUE; |
262 |
+ } else if (!*cleartext) |
263 |
+ password = t_strdup_noconst(vpw->pw_passwd); |
264 |
+ else |
265 |
+ password = NULL; |
266 |
+ *result_r = password != NULL ? PASSDB_RESULT_OK : |
267 |
+ PASSDB_RESULT_SCHEME_NOT_AVAILABLE; |
268 |
+ } |
269 |
+ |
270 |
+ safe_memset(vpw->pw_passwd, 0, strlen(vpw->pw_passwd)); |
271 |
+ if (vpw->pw_clear_passwd != NULL) { |
272 |
+ safe_memset(vpw->pw_clear_passwd, 0, |
273 |
+ strlen(vpw->pw_clear_passwd)); |
274 |
+ } |
275 |
+ |
276 |
+ return password; |
277 |
+} |
278 |
+ |
279 |
+static void vpopmail_lookup_credentials(struct auth_request *request, |
280 |
+ lookup_credentials_callback_t *callback) |
281 |
+{ |
282 |
+ enum passdb_result result; |
283 |
+ char *password; |
284 |
+ bool cleartext = TRUE; |
285 |
+ |
286 |
+ password = vpopmail_password_lookup(request, &cleartext, &result); |
287 |
+ if (password == NULL) { |
288 |
+ callback(result, NULL, 0, request); |
289 |
+ return; |
290 |
+ } |
291 |
+ |
292 |
+ passdb_handle_credentials(PASSDB_RESULT_OK, password, "CLEARTEXT", |
293 |
+ callback, request); |
294 |
+ safe_memset(password, 0, strlen(password)); |
295 |
+} |
296 |
+ |
297 |
+static void |
298 |
+vpopmail_verify_plain(struct auth_request *request, const char *password, |
299 |
+ verify_plain_callback_t *callback) |
300 |
+{ |
301 |
+ enum passdb_result result; |
302 |
+ const char *scheme, *tmp_pass; |
303 |
+ char *crypted_pass; |
304 |
+ bool cleartext = FALSE; |
305 |
+ int ret; |
306 |
+ |
307 |
+ crypted_pass = vpopmail_password_lookup(request, &cleartext, &result); |
308 |
+ if (crypted_pass == NULL) { |
309 |
+ callback(result, request); |
310 |
+ return; |
311 |
+ } |
312 |
+ tmp_pass = crypted_pass; |
313 |
+ |
314 |
+ if (cleartext) |
315 |
+ scheme = "CLEARTEXT"; |
316 |
+ else { |
317 |
+ scheme = password_get_scheme(&tmp_pass); |
318 |
+ if (scheme == NULL) |
319 |
+ scheme = request->passdb->passdb->default_pass_scheme; |
320 |
+ } |
321 |
+ |
322 |
+ ret = auth_request_password_verify(request, password, tmp_pass, |
323 |
+ scheme, AUTH_SUBSYS_DB); |
324 |
+ safe_memset(crypted_pass, 0, strlen(crypted_pass)); |
325 |
+ |
326 |
+ if (ret <= 0) { |
327 |
+ callback(PASSDB_RESULT_PASSWORD_MISMATCH, request); |
328 |
+ return; |
329 |
+ } |
330 |
+ |
331 |
+#ifdef POP_AUTH_OPEN_RELAY |
332 |
+ if (strcasecmp(request->fields.service, "POP3") == 0 || |
333 |
+ strcasecmp(request->fields.service, "IMAP") == 0) { |
334 |
+ const char *host = net_ip2addr(&request->fields.remote_ip); |
335 |
+ /* vpopmail 5.4 does not understand IPv6 */ |
336 |
+ if (host[0] != '\0' && IPADDR_IS_V4(&request->fields.remote_ip)) { |
337 |
+ /* use putenv() directly rather than env_put() which |
338 |
+ would leak memory every time we got here. use a |
339 |
+ static buffer for putenv() as SUSv2 requirements |
340 |
+ would otherwise corrupt our environment later. */ |
341 |
+ static char ip_env[256]; |
342 |
+ |
343 |
+ i_snprintf(ip_env, sizeof(ip_env), |
344 |
+ "TCPREMOTEIP=%s", host); |
345 |
+ putenv(ip_env); |
346 |
+ open_smtp_relay(); |
347 |
+ } |
348 |
+ } |
349 |
+#endif |
350 |
+ |
351 |
+ callback(PASSDB_RESULT_OK, request); |
352 |
+} |
353 |
+ |
354 |
+static struct passdb_module * |
355 |
+vpopmail_preinit(pool_t pool, const char *args) |
356 |
+{ |
357 |
+ static bool vauth_load_initialized = FALSE; |
358 |
+ struct vpopmail_passdb_module *module; |
359 |
+ const char *const *tmp; |
360 |
+ |
361 |
+ module = p_new(pool, struct vpopmail_passdb_module, 1); |
362 |
+ module->module.default_pass_scheme = VPOPMAIL_DEFAULT_PASS_SCHEME; |
363 |
+ module->module.blocking = TRUE; |
364 |
+ |
365 |
+ tmp = t_strsplit_spaces(args, " "); |
366 |
+ for (; *tmp != NULL; tmp++) { |
367 |
+ if (str_begins(*tmp, "cache_key=")) { |
368 |
+ module->module.default_cache_key = |
369 |
+ auth_cache_parse_key(pool, *tmp + 10); |
370 |
+ } else if (str_begins(*tmp, "webmail=")) { |
371 |
+ if (net_addr2ip(*tmp + 8, &module->webmail_ip) < 0) |
372 |
+ i_fatal("vpopmail: Invalid webmail IP address"); |
373 |
+ } else if (strcmp(*tmp, "blocking=no") == 0) { |
374 |
+ module->module.blocking = FALSE; |
375 |
+ } else { |
376 |
+ i_fatal("passdb vpopmail: Unknown setting: %s", *tmp); |
377 |
+ } |
378 |
+ } |
379 |
+ if (!vauth_load_initialized) { |
380 |
+ vauth_load_initialized = TRUE; |
381 |
+ if (vauth_open(0) != 0) |
382 |
+ i_fatal("vpopmail: vauth_open() failed"); |
383 |
+ } |
384 |
+ return &module->module; |
385 |
+} |
386 |
+ |
387 |
+static void vpopmail_deinit(struct passdb_module *module ATTR_UNUSED) |
388 |
+{ |
389 |
+ vclose(); |
390 |
+} |
391 |
+ |
392 |
+struct passdb_module_interface passdb_vpopmail = { |
393 |
+ "vpopmail", |
394 |
+ |
395 |
+ vpopmail_preinit, |
396 |
+ NULL, |
397 |
+ vpopmail_deinit, |
398 |
+ |
399 |
+ vpopmail_verify_plain, |
400 |
+ vpopmail_lookup_credentials, |
401 |
+ NULL |
402 |
+}; |
403 |
+#else |
404 |
+struct passdb_module_interface passdb_vpopmail = { |
405 |
+ .name = "vpopmail" |
406 |
+}; |
407 |
+#endif |
408 |
diff -ruN ../dovecot-2.3.13.orig/src/auth/passdb.c ./src/auth/passdb.c |
409 |
--- ../dovecot-2.3.13.orig/src/auth/passdb.c 2020-12-22 14:26:52.000000000 +0100 |
410 |
+++ ./src/auth/passdb.c 2021-01-29 13:21:19.273185000 +0100 |
411 |
@@ -321,6 +321,7 @@ |
412 |
extern struct passdb_module_interface passdb_passwd_file; |
413 |
extern struct passdb_module_interface passdb_pam; |
414 |
extern struct passdb_module_interface passdb_checkpassword; |
415 |
+extern struct passdb_module_interface passdb_vpopmail; |
416 |
extern struct passdb_module_interface passdb_ldap; |
417 |
extern struct passdb_module_interface passdb_sql; |
418 |
extern struct passdb_module_interface passdb_static; |
419 |
@@ -340,6 +341,7 @@ |
420 |
passdb_register_module(&passdb_pam); |
421 |
passdb_register_module(&passdb_checkpassword); |
422 |
passdb_register_module(&passdb_shadow); |
423 |
+ passdb_register_module(&passdb_vpopmail); |
424 |
passdb_register_module(&passdb_ldap); |
425 |
passdb_register_module(&passdb_sql); |
426 |
passdb_register_module(&passdb_static); |
427 |
diff -ruN ../dovecot-2.3.13.orig/src/auth/userdb-vpopmail.c ./src/auth/userdb-vpopmail.c |
428 |
--- ../dovecot-2.3.13.orig/src/auth/userdb-vpopmail.c 1970-01-01 01:00:00.000000000 +0100 |
429 |
+++ ./src/auth/userdb-vpopmail.c 2021-01-29 13:22:54.910947000 +0100 |
430 |
@@ -0,0 +1,202 @@ |
431 |
+/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ |
432 |
+ |
433 |
+/* Thanks to Courier-IMAP for showing how the vpopmail API should be used */ |
434 |
+ |
435 |
+#include "auth-common.h" |
436 |
+#include "userdb.h" |
437 |
+ |
438 |
+#if defined(PASSDB_VPOPMAIL) || defined(USERDB_VPOPMAIL) |
439 |
+#include "str.h" |
440 |
+#include "var-expand.h" |
441 |
+#include "userdb-vpopmail.h" |
442 |
+ |
443 |
+struct vpopmail_userdb_module { |
444 |
+ struct userdb_module module; |
445 |
+ |
446 |
+ const char *quota_template_key; |
447 |
+ const char *quota_template_value; |
448 |
+}; |
449 |
+ |
450 |
+struct vqpasswd *vpopmail_lookup_vqp(struct auth_request *request, |
451 |
+ char vpop_user[VPOPMAIL_LIMIT], |
452 |
+ char vpop_domain[VPOPMAIL_LIMIT]) |
453 |
+{ |
454 |
+ struct vqpasswd *vpw; |
455 |
+ |
456 |
+ /* vpop_user must be zero-filled or parse_email() leaves an |
457 |
+ extra character after the user name. we'll fill vpop_domain |
458 |
+ as well just to be sure... */ |
459 |
+ memset(vpop_user, '\0', VPOPMAIL_LIMIT); |
460 |
+ memset(vpop_domain, '\0', VPOPMAIL_LIMIT); |
461 |
+ |
462 |
+ if (parse_email(request->fields.user, vpop_user, vpop_domain, |
463 |
+ VPOPMAIL_LIMIT-1) < 0) { |
464 |
+ e_info(authdb_event(request), |
465 |
+ "parse_email() failed"); |
466 |
+ return NULL; |
467 |
+ } |
468 |
+ |
469 |
+ e_debug(authdb_event(request), |
470 |
+ "lookup user=%s domain=%s", |
471 |
+ vpop_user, vpop_domain); |
472 |
+ |
473 |
+ vpw = vauth_getpw(vpop_user, vpop_domain); |
474 |
+ if (vpw == NULL) { |
475 |
+ auth_request_log_unknown_user(request, AUTH_SUBSYS_DB); |
476 |
+ return NULL; |
477 |
+ } |
478 |
+ |
479 |
+ return vpw; |
480 |
+} |
481 |
+#endif |
482 |
+ |
483 |
+#ifdef USERDB_VPOPMAIL |
484 |
+static int |
485 |
+userdb_vpopmail_get_quota(const char *template, const char *vpop_str, |
486 |
+ const char **quota_r, const char **error_r) |
487 |
+{ |
488 |
+ struct var_expand_table *tab; |
489 |
+ string_t *quota; |
490 |
+ |
491 |
+ if (template == NULL || *vpop_str == '\0' || |
492 |
+ strcmp(vpop_str, "NOQUOTA") == 0) { |
493 |
+ *quota_r = ""; |
494 |
+ return 0; |
495 |
+ } |
496 |
+ |
497 |
+ tab = t_new(struct var_expand_table, 2); |
498 |
+ tab[0].key = 'q'; |
499 |
+ tab[0].value = format_maildirquota(vpop_str); |
500 |
+ |
501 |
+ quota = t_str_new(128); |
502 |
+ if (var_expand(quota, template, tab, error_r) < 0) |
503 |
+ return -1; |
504 |
+ |
505 |
+ *quota_r = str_c(quota); |
506 |
+ return 0; |
507 |
+} |
508 |
+ |
509 |
+static void vpopmail_lookup(struct auth_request *auth_request, |
510 |
+ userdb_callback_t *callback) |
511 |
+{ |
512 |
+ struct userdb_module *_module = auth_request->userdb->userdb; |
513 |
+ struct vpopmail_userdb_module *module = |
514 |
+ (struct vpopmail_userdb_module *)_module; |
515 |
+ char vpop_user[VPOPMAIL_LIMIT], vpop_domain[VPOPMAIL_LIMIT]; |
516 |
+ struct vqpasswd *vpw; |
517 |
+ const char *quota, *error; |
518 |
+ uid_t uid; |
519 |
+ gid_t gid; |
520 |
+ |
521 |
+ vpw = vpopmail_lookup_vqp(auth_request, vpop_user, vpop_domain); |
522 |
+ if (vpw == NULL) { |
523 |
+ callback(USERDB_RESULT_USER_UNKNOWN, auth_request); |
524 |
+ return; |
525 |
+ } |
526 |
+ |
527 |
+ /* we have to get uid/gid separately, because the gid field in |
528 |
+ struct vqpasswd isn't really gid at all but just some flags... */ |
529 |
+ if (vget_assign(vpop_domain, NULL, 0, &uid, &gid) == NULL) { |
530 |
+ e_info(authdb_event(auth_request), |
531 |
+ "vget_assign(%s) failed", vpop_domain); |
532 |
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request); |
533 |
+ return; |
534 |
+ } |
535 |
+ |
536 |
+ if (auth_request->fields.successful) { |
537 |
+ /* update the last login only when we're really */ |
538 |
+ vset_lastauth(vpop_user, vpop_domain, |
539 |
+ t_strdup_noconst(auth_request->fields.service)); |
540 |
+ } |
541 |
+ |
542 |
+ if (vpw->pw_dir == NULL || vpw->pw_dir[0] == '\0') { |
543 |
+ /* user's homedir doesn't exist yet, create it */ |
544 |
+ e_info(authdb_event(auth_request), |
545 |
+ "pw_dir isn't set, creating"); |
546 |
+ |
547 |
+ if (make_user_dir(vpop_user, vpop_domain, uid, gid) == NULL) { |
548 |
+ e_error(authdb_event(auth_request), |
549 |
+ "make_user_dir(%s, %s) failed", |
550 |
+ vpop_user, vpop_domain); |
551 |
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request); |
552 |
+ return; |
553 |
+ } |
554 |
+ |
555 |
+ /* get the user again so pw_dir is visible */ |
556 |
+ vpw = vauth_getpw(vpop_user, vpop_domain); |
557 |
+ if (vpw == NULL) { |
558 |
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request); |
559 |
+ return; |
560 |
+ } |
561 |
+ } |
562 |
+ |
563 |
+ if (userdb_vpopmail_get_quota(module->quota_template_value, |
564 |
+ vpw->pw_shell, "a, &error) < 0) { |
565 |
+ e_error(authdb_event(auth_request), |
566 |
+ "userdb_vpopmail_get_quota(%s, %s) failed: %s", |
567 |
+ module->quota_template_value, |
568 |
+ vpw->pw_shell, error); |
569 |
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request); |
570 |
+ return; |
571 |
+ } |
572 |
+ |
573 |
+ auth_request_set_userdb_field(auth_request, "uid", dec2str(uid)); |
574 |
+ auth_request_set_userdb_field(auth_request, "gid", dec2str(gid)); |
575 |
+ auth_request_set_userdb_field(auth_request, "home", vpw->pw_dir); |
576 |
+ |
577 |
+ if (*quota != '\0') { |
578 |
+ auth_request_set_userdb_field(auth_request, |
579 |
+ module->quota_template_key, |
580 |
+ quota); |
581 |
+ } |
582 |
+ callback(USERDB_RESULT_OK, auth_request); |
583 |
+} |
584 |
+ |
585 |
+static struct userdb_module * |
586 |
+vpopmail_preinit(pool_t pool, const char *args) |
587 |
+{ |
588 |
+ struct vpopmail_userdb_module *module; |
589 |
+ const char *const *tmp, *p; |
590 |
+ |
591 |
+ module = p_new(pool, struct vpopmail_userdb_module, 1); |
592 |
+ module->module.blocking = TRUE; |
593 |
+ |
594 |
+ for (tmp = t_strsplit(args, " "); *tmp != NULL; tmp++) { |
595 |
+ if (str_begins(*tmp, "cache_key=")) |
596 |
+ module->module.default_cache_key = |
597 |
+ p_strdup(pool, *tmp + 10); |
598 |
+ else if (str_begins(*tmp, "quota_template=")) { |
599 |
+ p = strchr(*tmp + 15, '='); |
600 |
+ if (p == NULL) { |
601 |
+ i_fatal("vpopmail userdb: " |
602 |
+ "quota_template missing '='"); |
603 |
+ } |
604 |
+ module->quota_template_key = |
605 |
+ p_strdup_until(pool, *tmp + 15, p); |
606 |
+ module->quota_template_value = p_strdup(pool, p + 1); |
607 |
+ } else if (strcmp(*tmp, "blocking=no") == 0) { |
608 |
+ module->module.blocking = FALSE; |
609 |
+ } else |
610 |
+ i_fatal("userdb vpopmail: Unknown setting: %s", *tmp); |
611 |
+ } |
612 |
+ return &module->module; |
613 |
+} |
614 |
+ |
615 |
+struct userdb_module_interface userdb_vpopmail = { |
616 |
+ "vpopmail", |
617 |
+ |
618 |
+ vpopmail_preinit, |
619 |
+ NULL, |
620 |
+ NULL, |
621 |
+ |
622 |
+ vpopmail_lookup, |
623 |
+ |
624 |
+ NULL, |
625 |
+ NULL, |
626 |
+ NULL |
627 |
+}; |
628 |
+#else |
629 |
+struct userdb_module_interface userdb_vpopmail = { |
630 |
+ .name = "vpopmail" |
631 |
+}; |
632 |
+#endif |
633 |
diff -ruN ../dovecot-2.3.13.orig/src/auth/userdb-vpopmail.h ./src/auth/userdb-vpopmail.h |
634 |
--- ../dovecot-2.3.13.orig/src/auth/userdb-vpopmail.h 1970-01-01 01:00:00.000000000 +0100 |
635 |
+++ ./src/auth/userdb-vpopmail.h 2021-01-29 13:23:51.526326000 +0100 |
636 |
@@ -0,0 +1,17 @@ |
637 |
+#ifndef USERDB_VPOPMAIL_H |
638 |
+#define USERDB_VPOPMAIL_H |
639 |
+ |
640 |
+#include <stdio.h> |
641 |
+#include <vpopmail.h> |
642 |
+#include <vauth.h> |
643 |
+ |
644 |
+/* Limit user and domain to 80 chars each (+1 for \0). I wouldn't recommend |
645 |
+ raising this limit at least much, vpopmail is full of potential buffer |
646 |
+ overflows. */ |
647 |
+#define VPOPMAIL_LIMIT 81 |
648 |
+ |
649 |
+struct vqpasswd *vpopmail_lookup_vqp(struct auth_request *request, |
650 |
+ char vpop_user[VPOPMAIL_LIMIT], |
651 |
+ char vpop_domain[VPOPMAIL_LIMIT]); |
652 |
+ |
653 |
+#endif |
654 |
diff -ruN ../dovecot-2.3.13.orig/src/auth/userdb.c ./src/auth/userdb.c |
655 |
--- ../dovecot-2.3.13.orig/src/auth/userdb.c 2020-12-22 14:26:52.000000000 +0100 |
656 |
+++ ./src/auth/userdb.c 2021-01-29 13:21:19.275688000 +0100 |
657 |
@@ -228,6 +228,7 @@ |
658 |
extern struct userdb_module_interface userdb_static; |
659 |
extern struct userdb_module_interface userdb_passwd; |
660 |
extern struct userdb_module_interface userdb_passwd_file; |
661 |
+extern struct userdb_module_interface userdb_vpopmail; |
662 |
extern struct userdb_module_interface userdb_ldap; |
663 |
extern struct userdb_module_interface userdb_sql; |
664 |
extern struct userdb_module_interface userdb_checkpassword; |
665 |
@@ -244,6 +245,7 @@ |
666 |
userdb_register_module(&userdb_passwd_file); |
667 |
userdb_register_module(&userdb_prefetch); |
668 |
userdb_register_module(&userdb_static); |
669 |
+ userdb_register_module(&userdb_vpopmail); |
670 |
userdb_register_module(&userdb_ldap); |
671 |
userdb_register_module(&userdb_sql); |
672 |
userdb_register_module(&userdb_checkpassword); |
673 |
diff -ruN ../dovecot-2.3.13.orig/src/master/main.c ./src/master/main.c |
674 |
--- ../dovecot-2.3.13.orig/src/master/main.c 2020-12-22 14:26:52.000000000 +0100 |
675 |
+++ ./src/master/main.c 2021-01-29 13:21:19.276733000 +0100 |
676 |
@@ -706,6 +706,9 @@ |
677 |
#ifdef PASSDB_SQL |
678 |
" sql" |
679 |
#endif |
680 |
+#ifdef PASSDB_VPOPMAIL |
681 |
+ " vpopmail" |
682 |
+#endif |
683 |
"\nUserdb:" |
684 |
#ifdef USERDB_CHECKPASSWORD |
685 |
" checkpassword" |
686 |
@@ -733,6 +736,9 @@ |
687 |
#endif |
688 |
#ifdef USERDB_STATIC |
689 |
" static" |
690 |
+#endif |
691 |
+#ifdef USERDB_VPOPMAIL |
692 |
+ " vpopmail" |
693 |
#endif |
694 |
"\n", IO_BLOCK_SIZE); |
695 |
} |