1 diff -ruNp postfix-2.11.10.orig/README_FILES/VDA_README postfix-2.11.10/README_FILES/VDA_README
2 --- postfix-2.11.10.orig/README_FILES/VDA_README 1970-01-01 01:00:00.000000000 +0100
3 +++ postfix-2.11.10/README_FILES/VDA_README 2017-07-02 00:13:25.773285426 +0200
5 +Postfix VDA patch for maildir++ quota support by
6 + Anderson Nadal <andernadal@gmail.com>
7 + Tomas Macek <maca02@atlas.cz>
10 +See VDA patch official website http://vda.sf.net for instructions
11 +howto patch the Postfix's sourcetree and configure the options
12 +provided by this patch.
15 diff -ruNp postfix-2.11.10.orig/src/global/mail_params.h postfix-2.11.10/src/global/mail_params.h
16 --- postfix-2.11.10.orig/src/global/mail_params.h 2015-07-20 00:39:31.000000000 +0200
17 +++ postfix-2.11.10/src/global/mail_params.h 2017-07-02 00:13:25.775285421 +0200
18 @@ -2413,6 +2413,54 @@ extern char *var_virt_uid_maps;
19 #define DEF_VIRT_GID_MAPS ""
20 extern char *var_virt_gid_maps;
22 +#define VAR_VIRT_MAILBOX_LIMIT_MAPS "virtual_mailbox_limit_maps"
23 +#define DEF_VIRT_MAILBOX_LIMIT_MAPS ""
24 +extern char *var_virt_mailbox_limit_maps;
26 +#define VAR_VIRT_MAILBOX_LIMIT_INBOX "virtual_mailbox_limit_inbox"
27 +#define DEF_VIRT_MAILBOX_LIMIT_INBOX 0
28 +extern bool var_virt_mailbox_limit_inbox;
30 +#define VAR_VIRT_MAILBOX_LIMIT_OVERRIDE "virtual_mailbox_limit_override"
31 +#define DEF_VIRT_MAILBOX_LIMIT_OVERRIDE 0
32 +extern bool var_virt_mailbox_limit_override;
34 +#define VAR_VIRT_MAILDIR_EXTENDED "virtual_maildir_extended"
35 +#define DEF_VIRT_MAILDIR_EXTENDED 0
36 +extern bool var_virt_maildir_extended;
38 +#define VAR_VIRT_OVERQUOTA_BOUNCE "virtual_overquota_bounce"
39 +#define DEF_VIRT_OVERQUOTA_BOUNCE 0
40 +extern bool var_virt_overquota_bounce;
42 +#define VAR_VIRT_MAILDIR_LIMIT_MESSAGE "virtual_maildir_limit_message"
43 +#define DEF_VIRT_MAILDIR_LIMIT_MESSAGE "Sorry, the user's maildir has overdrawn his diskspace quota, please try again later."
44 +extern char *var_virt_maildir_limit_message;
46 +#define VAR_VIRT_MAILDIR_LIMIT_MESSAGE_MAPS "virtual_maildir_limit_message_maps"
47 +#define DEF_VIRT_MAILDIR_LIMIT_MESSAGE_MAPS ""
48 +extern char *var_virt_maildir_limit_message_maps;
50 +#define VAR_VIRT_MAILDIR_SUFFIX "virtual_maildir_suffix"
51 +#define DEF_VIRT_MAILDIR_SUFFIX ""
52 +extern char *var_virt_maildir_suffix;
54 +#define VAR_VIRT_TRASH_COUNT "virtual_trash_count"
55 +#define DEF_VIRT_TRASH_COUNT 0
56 +extern bool var_virt_trash_count;
58 +#define VAR_VIRT_TRASH_NAME "virtual_trash_name"
59 +#define DEF_VIRT_TRASH_NAME ".Trash"
60 +extern char *var_virt_trash_name;
62 +#define VAR_VIRT_MAILDIR_FILTER "virtual_maildir_filter"
63 +#define DEF_VIRT_MAILDIR_FILTER 0
64 +extern bool var_virt_maildir_filter;
66 +#define VAR_VIRT_MAILDIR_FILTER_MAPS "virtual_maildir_filter_maps"
67 +#define DEF_VIRT_MAILDIR_FILTER_MAPS ""
68 +extern char *var_virt_maildir_filter_maps;
70 #define VAR_VIRT_MINUID "virtual_minimum_uid"
71 #define DEF_VIRT_MINUID 100
72 extern int var_virt_minimum_uid;
73 diff -ruNp postfix-2.11.10.orig/src/util/file_limit.c postfix-2.11.10/src/util/file_limit.c
74 --- postfix-2.11.10.orig/src/util/file_limit.c 2003-10-22 20:48:36.000000000 +0200
75 +++ postfix-2.11.10/src/util/file_limit.c 2017-07-02 00:13:25.775285421 +0200
76 @@ -85,7 +85,11 @@ void set_file_limit(off_t limit)
80 - rlim.rlim_cur = rlim.rlim_max = limit;
81 + /* rlim_max can only be changed by root. */
82 + if (getrlimit(RLIMIT_FSIZE, &rlim) < 0)
83 + msg_fatal("getrlimit: %m");
84 + rlim.rlim_cur = limit;
86 if (setrlimit(RLIMIT_FSIZE, &rlim) < 0)
87 msg_fatal("setrlimit: %m");
89 diff -ruNp postfix-2.11.10.orig/src/virtual/mailbox.c postfix-2.11.10/src/virtual/mailbox.c
90 --- postfix-2.11.10.orig/src/virtual/mailbox.c 2016-08-22 23:24:31.000000000 +0200
91 +++ postfix-2.11.10/src/virtual/mailbox.c 2017-07-02 00:13:25.776285418 +0200
94 #include <stringops.h>
95 #include <set_eugid.h>
104 +/* change_mailbox_limit - change limit for mailbox file */
105 +static int change_mailbox_limit(LOCAL_STATE state, USER_ATTR usr_attr)
107 + char *myname = "change_mailbox_limit";
108 + const char *limit_res;
113 + * Look up the virtual mailbox limit size for this user.
114 + * Fall back to virtual_mailbox_limit in case lookup failed.
115 + * If virtual mailbox limit size is negative, fall back to virtual_mailbox_limit.
116 + * If it's 0, set the mailbox limit to 0, which means unlimited.
117 + * If it's more than 0 (positive int), check if the value is smaller than the maximum message size,
118 + * if it is and the virtual mailbox limit can't be overridden, fall back to virtual_mailbox_limit and
119 + * warn the user, else use the value directly as the mailbox limit.
121 + if (*var_virt_mailbox_limit_maps != 0 && (limit_res = mail_addr_find(virtual_mailbox_limit_maps, state.msg_attr.user, (char **) NULL)) != 0) {
122 + n = atol(limit_res);
124 + if ((n < var_message_limit) && (!var_virt_mailbox_limit_override)) {
125 + set_file_limit(var_virt_mailbox_limit);
128 + msg_warn("%s: recipient %s - virtual mailbox limit is "
129 + "smaller than %s in %s - falling back to %s",
131 + state.msg_attr.user,
133 + virtual_mailbox_limit_maps->title,
134 + VAR_VIRT_MAILBOX_LIMIT);
137 + set_file_limit((off_t) n);
141 + msg_info("%s: set virtual mailbox limit size for %s to %ld",
142 + myname, usr_attr.mailbox, n);
146 + set_file_limit(OFF_T_MAX);
150 + msg_info("%s: set virtual mailbox limit size for %s to %ld",
151 + myname, usr_attr.mailbox, OFF_T_MAX);
154 + /* Invalid limit size (negative). Use default virtual_mailbox_limit. */
155 + set_file_limit(var_virt_mailbox_limit);
160 + /* There is no limit in the maps. Use default virtual_mailbox_limit. */
161 + set_file_limit(var_virt_mailbox_limit);
168 /* deliver_mailbox_file - deliver to recipient mailbox */
170 static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
171 @@ -214,62 +279,72 @@ int deliver_mailbox(LOCAL_STATE stat
172 * Look up the mailbox owner rights. Defer in case of trouble.
174 uid_res = mail_addr_find(virtual_uid_maps, state.msg_attr.user,
176 - if (uid_res == 0) {
177 - msg_warn("recipient %s: not found in %s",
178 - state.msg_attr.user, virtual_uid_maps->title);
179 - dsb_simple(why, "4.3.5", "mail system configuration error");
180 - *statusp = defer_append(BOUNCE_FLAGS(state.request),
181 - BOUNCE_ATTR(state.msg_attr));
185 + if ((uid_res = mail_addr_find(virtual_uid_maps, state.msg_attr.user, (char **) 0)) == 0) {
186 + if ((uid_res = maps_find(virtual_uid_maps, strchr(state.msg_attr.user, '@'), DICT_FLAG_FIXED)) == 0) {
187 + msg_warn("recipient %s: not found in %s", state.msg_attr.user, virtual_uid_maps->title);
188 + dsb_simple(why, "4.3.5", "mail system configuration error");
189 + *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
194 if ((n = atol(uid_res)) < var_virt_minimum_uid) {
195 - msg_warn("recipient %s: bad uid %s in %s",
196 - state.msg_attr.user, uid_res, virtual_uid_maps->title);
197 - dsb_simple(why, "4.3.5", "mail system configuration error");
198 - *statusp = defer_append(BOUNCE_FLAGS(state.request),
199 - BOUNCE_ATTR(state.msg_attr));
201 + msg_warn("recipient %s: bad uid %s in %s", state.msg_attr.user, uid_res, virtual_uid_maps->title);
202 + dsb_simple(why, "4.3.5", "mail system configuration error");
203 + *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
207 usr_attr.uid = (uid_t) n;
210 * Look up the mailbox group rights. Defer in case of trouble.
212 gid_res = mail_addr_find(virtual_gid_maps, state.msg_attr.user,
214 - if (gid_res == 0) {
215 - msg_warn("recipient %s: not found in %s",
216 - state.msg_attr.user, virtual_gid_maps->title);
217 - dsb_simple(why, "4.3.5", "mail system configuration error");
218 - *statusp = defer_append(BOUNCE_FLAGS(state.request),
219 - BOUNCE_ATTR(state.msg_attr));
223 + if ((gid_res = mail_addr_find(virtual_gid_maps, state.msg_attr.user, (char **) 0)) == 0) {
224 + if ((gid_res = maps_find(virtual_gid_maps, strchr(state.msg_attr.user, '@'), DICT_FLAG_FIXED)) == 0) {
225 + msg_warn("recipient %s: not found in %s", state.msg_attr.user, virtual_gid_maps->title);
226 + dsb_simple(why, "4.3.5", "mail system configuration error");
227 + *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
232 if ((n = atol(gid_res)) <= 0) {
233 - msg_warn("recipient %s: bad gid %s in %s",
234 - state.msg_attr.user, gid_res, virtual_gid_maps->title);
235 - dsb_simple(why, "4.3.5", "mail system configuration error");
236 - *statusp = defer_append(BOUNCE_FLAGS(state.request),
237 - BOUNCE_ATTR(state.msg_attr));
239 + msg_warn("recipient %s: bad gid %s in %s", state.msg_attr.user, gid_res, virtual_gid_maps->title);
240 + dsb_simple(why, "4.3.5", "mail system configuration error");
241 + *statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
245 usr_attr.gid = (gid_t) n;
248 - msg_info("%s[%d]: set user_attr: %s, uid = %u, gid = %u",
249 - myname, state.level, usr_attr.mailbox,
250 - (unsigned) usr_attr.uid, (unsigned) usr_attr.gid);
251 + msg_info("%s[%d]: set user_attr: %s, uid = %u, gid = %u",
252 + myname, state.level, usr_attr.mailbox,
253 + (unsigned) usr_attr.uid, (unsigned) usr_attr.gid);
256 * Deliver to mailbox or to maildir.
258 #define LAST_CHAR(s) (s[strlen(s) - 1])
260 - if (LAST_CHAR(usr_attr.mailbox) == '/')
261 - *statusp = deliver_maildir(state, usr_attr);
263 - *statusp = deliver_mailbox_file(state, usr_attr);
264 + if (LAST_CHAR(usr_attr.mailbox) == '/') {
265 + *statusp = deliver_maildir(state, usr_attr);
270 + changed_limit = change_mailbox_limit(state, usr_attr);
271 + *statusp = deliver_mailbox_file(state, usr_attr);
274 + set_file_limit(var_virt_mailbox_limit);
279 diff -ruNp postfix-2.11.10.orig/src/virtual/maildir.c postfix-2.11.10/src/virtual/maildir.c
280 --- postfix-2.11.10.orig/src/virtual/maildir.c 2012-01-25 01:41:08.000000000 +0100
281 +++ postfix-2.11.10/src/virtual/maildir.c 2017-07-02 00:13:25.779285410 +0200
283 #include <mbox_open.h>
284 #include <dsn_util.h>
286 +/* Patch library. */
288 +#include <sys/types.h> /* opendir(3), stat(2) */
289 +#include <sys/stat.h> /* stat(2) */
290 +#include <dirent.h> /* opendir(3) */
291 +#include <unistd.h> /* stat(2) */
292 +#include <stdlib.h> /* atol(3) */
293 +#include <string.h> /* strrchr(3) */
294 +#include <vstring_vstream.h>
296 +#include <dict_regexp.h>
299 +#include <sys_defs.h>
300 +#include <mail_addr_find.h>
302 /* Application-specific. */
306 -/* deliver_maildir - delivery to maildir-style mailbox */
307 +/* Maildirsize maximal size. */
309 +#define SIZEFILE_MAX 5120
312 + * Chris Stratford <chriss@pipex.net>
313 + * Read the maildirsize file to get quota info.
316 + * dirname: the maildir
317 + * countptr: number of messages
319 + * Returns the size of all mails as read from maildirsize,
320 + * zero if it couldn't read the file.
322 +static long read_maildirsize(char *filename, long *sumptr, long *countptr)
324 + char *myname = "read_maildirsize";
325 + struct stat statbuf;
329 + long sum = 0, count = 0, ret_value = -1;
332 + msg_info("%s: we will use sizefile = '%s'", myname, filename);
334 + sizefile = vstream_fopen(filename, O_RDONLY, 0);
337 + msg_info("%s: cannot open %s: %m (maybe file does not exist)", myname, filename);
340 + } else if (stat(filename, &statbuf) < 0 || statbuf.st_size > SIZEFILE_MAX) {
342 + vstream_fclose(sizefile);
347 + msg_info("%s: stat() returned < 0 or filesize > SIZEFILE_MAX (filename = %s, filesize = %ld)", myname, filename, statbuf.st_size);
352 + VSTRING *sizebuf = vstring_alloc(SIZEFILE_MAX);
353 + len = vstream_fread(sizefile, STR(sizebuf), SIZEFILE_MAX);
364 + if (*p++ == '\n') {
375 + if (sscanf(q, "%ld %ld", &n, &c) == 2) {
378 + /* if (msg_verbose)
379 + msg_info("%s: we read line '%s', totals: sum = %ld, count = %ld", myname, q, sum, count); */
382 + vstream_fclose(sizefile);
384 + msg_warn("%s: invalid line '%s' found in %s, removing maildirsize file", myname, q, filename);
385 + vstring_free(sizebuf);
394 + if (sum < 0 || count < 0 || (sum == 0 && count != 0) || (sum != 0 && count == 0)) {
396 + msg_info("%s: we will return -1 and unlink %s, because file count or sum is <= 0 (sum = %ld, count = %ld)", myname, filename, sum, count);
403 + msg_info("%s: we will return Maildir size = %ld, count = %ld", myname, *sumptr, *countptr);
408 + vstream_fclose(sizefile);
409 + vstring_free(sizebuf);
415 + * Gives the size of the file according to the Maildir++ extension
416 + * present in the filename (code taken from courier-imap).
421 + * Returns the size given in ",S=<size>" in the filename,
422 + * zero if it cannot find ",S=<size>" in the filename.
424 +static long maildir_parsequota(const char *n)
429 + if ((o = strrchr(n, '/')) == 0)
437 + for (; o >= n; --o) {
441 + if (*o == ',' && o[1] == 'S' && o[2] == '=') {
451 + while (*o >= '0' && *o <= '9')
452 + s = s*10 + (*o++ - '0');
461 + * Computes quota usage for a directory (taken from exim).
463 + * This function is called to determine the exact quota usage of a virtual
464 + * maildir box. To achieve maximum possible speed while doing this, it takes
465 + * advantage of the maildirsize file and the Maildir++ extensions to filenames,
466 + * when applicable and configured to be used. In all other cases it simply
467 + * stats all the files as needed to get the size information.
470 + * dirname: the name of the directory
471 + * countptr: where to add the file count (because this function recurses)
473 + * Returns the sum of the sizes of all measurable files,
474 + * zero if the directory could not be opened.
476 +static long check_dir_size(char *dirname, long *countptr)
478 + char *myname = "check_dir_size";
481 + struct dirent *ent;
482 + struct stat statbuf;
484 + dir = opendir(dirname);
486 + if (make_dirs(dirname, 0700) == 0) { /* Try to create the dirs. */
487 + dir = opendir(dirname); /* Reopen the dir. */
489 + msg_warn("%s: cannot reopen directory: %s", myname, dirname);
494 + msg_warn("%s: cannot open directory: %s", myname, dirname);
499 + while ((ent = readdir(dir)) != NULL) {
500 + char *name = ent->d_name;
504 + /* do not count dot a double-dot dirs */
505 + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
507 + /* do not count if this is the trash subdir and if we should NOT count it */
508 + else if (var_virt_trash_count == 0 && strcmp(name, var_virt_trash_name) == 0)
512 + * Here comes the real logic behind this function.
513 + * Optimized to be the most efficient possible,
514 + * depending on the settings given.
515 + * See above for a more detailed description.
517 + if (var_virt_mailbox_limit_inbox) {
518 + if (var_virt_maildir_extended && (tmpsum = maildir_parsequota(name))) {
523 + buffer = vstring_alloc(1024);
524 + vstring_sprintf(buffer, "%s/%s", dirname, name);
526 + if (stat(STR(buffer), &statbuf) < 0) {
527 + vstring_free(buffer);
530 + if ((statbuf.st_mode & S_IFREG) != 0) {
531 + sum += (long) statbuf.st_size;
535 + vstring_free(buffer);
539 + buffer = vstring_alloc(1024);
540 + vstring_sprintf(buffer, "%s/%s", dirname, name);
542 + if (stat(STR(buffer), &statbuf) < 0) {
543 + vstring_free(buffer);
546 + if ((statbuf.st_mode & S_IFREG) != 0) {
547 + if (strcmp(dirname + strlen(dirname) - 3, "new") == 0 || strcmp(dirname + strlen(dirname) - 3, "cur") == 0 || strcmp(dirname + strlen(dirname) - 3, "tmp") == 0) {
548 + sum += (long) statbuf.st_size;
552 + else if ((statbuf.st_mode & S_IFDIR) != 0) {
553 + sum += check_dir_size(STR(buffer), countptr);
556 + vstring_free(buffer);
561 -int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
563 + msg_info("%s: full scan done: dir=%s sum=%ld count=%ld", myname, dirname, sum, *countptr);
568 +/* Cut all occurrences of pattern from string. */
569 +static char *strcut(char *str, const char *pat)
571 + char *ptr, *loc, *ret;
575 + /* No match, return original string. */
576 + if (!strstr(loc, pat))
579 + while (*loc && (ptr = strstr(loc, pat))) {
582 + loc += strlen(pat);
593 +/* Check if maildirfilter file is up-to-date compared to SQL, (re)write it if not. */
594 +static long sql2file(char *filename, char *user)
596 + char *myname = "sql2file";
597 + char *filter_sqlres;
598 + char filter_fileres[128];
599 + long sqlmtime = 0, filemtime = 0, retval = 0;
600 + int filterfile, size_sqlres, i;
601 + struct stat statbuf;
603 + if (*var_virt_maildir_filter_maps != 0) {
604 + filter_sqlres = (char *) mymalloc(16000);
605 + filter_sqlres = (char *) mail_addr_find(virtual_maildir_filter_maps, user, (char **) 0);
607 + if (filter_sqlres) {
608 + strcut(filter_sqlres, "\r");
609 + if (filter_sqlres[0] == '#' && filter_sqlres[1] == ' ' && filter_sqlres[2] == 'M') {
610 + size_sqlres = strlen(filter_sqlres);
612 + for (i = 4; i <= size_sqlres; i++) {
613 + if(filter_sqlres[i] == '/' && filter_sqlres[i+1] == '^') {
614 + filter_sqlres[i-1] = '\n';
618 + filter_sqlres[(size_sqlres+1)] = '\0';
620 + sqlmtime = atol(filter_sqlres+3);
623 + filterfile = open(filename, O_RDONLY, 0);
625 + read(filterfile, (void *) filter_fileres, 127);
628 + filemtime = atol(filter_fileres+3);
632 + msg_info("%s: filter data: sql_size=%li sql_mtime=%ld file_mtime=%ld", myname, strlen(filter_sqlres), sqlmtime, filemtime);
634 + if (sqlmtime != filemtime && sqlmtime != 0) {
635 + if ((filterfile = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0640))) {
637 + msg_info("%s: updating filter file: %s", myname, filename);
638 + write(filterfile, filter_sqlres, strlen(filter_sqlres));
642 + msg_warn("%s: can't create filter file: %s", myname, filename);
649 + if (stat(filename, &statbuf) == 0)
650 + retval = (long) statbuf.st_mtime;
652 + msg_info("%s: processing filter file: file_mtime=%ld", myname, retval);
658 +/* deliver_maildir - delivery to maildir-style mailbox */
659 +int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
661 const char *myname = "deliver_maildir";
672 DSN_BUF *why = state.msg_attr.why;
675 - int mail_copy_status;
676 - int deliver_status;
679 - struct timeval starttime;
680 + int mail_copy_status;
681 + int deliver_status;
684 + struct timeval starttime;
686 + /* Maildir Quota. */
687 + const char *limit_res; /* Limit from map. */
688 + char *sizefilename = (char *) 0; /* Maildirsize file name. */
689 + VSTRING *filequota; /* Quota setting from the maildirsize file. */
690 + VSTREAM *sizefile; /* Maildirsize file handle. */
691 + long n = 0; /* Limit in long integer format. */
692 + long saved_count = 0; /* The total number of files. */
693 + long saved_size = 0; /* The total quota of all files. */
694 + struct stat mail_stat; /* To check the size of the mail to be written. */
695 + struct stat sizefile_stat; /* To check the size of the maildirsize file. */
696 + time_t tm; /* To check the age of the maildirsize file. */
698 + /* Maildir Filters. */
699 + const char *value, *cmd_text; /* Filter values. */
703 + char *mdffilename = (char *) 0; /* Maildirfolder file name. */
705 + VSTREAM *tmpfilter;
706 + VSTREAM *mdffile; /* Maildirfolder file handle. */
708 + long sqlmtime; /* Latest modification time from sql2file(). */
710 + int read_mds = -1; /* read_maildirsize() returned value */
711 + struct stat mdffile_stat; /* To check if the maildirfolder file exists. */
713 GETTIMEOFDAY(&starttime);
715 @@ -94,15 +486,14 @@ int deliver_maildir(LOCAL_STATE stat
719 - MSG_LOG_STATE(myname, state);
720 + MSG_LOG_STATE(myname, state);
723 * Don't deliver trace-only requests.
725 if (DEL_REQ_TRACE_ONLY(state.request->flags)) {
726 - dsb_simple(why, "2.0.0", "delivers to maildir");
727 - return (sent(BOUNCE_FLAGS(state.request),
728 - SENT_ATTR(state.msg_attr)));
729 + dsb_simple(why, "2.0.0", "delivers to maildir");
730 + return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr)));
734 @@ -110,18 +501,116 @@ int deliver_maildir(LOCAL_STATE stat
735 * attribute to reflect the final recipient.
737 if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
738 - msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
739 + msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
740 state.msg_attr.delivered = state.msg_attr.rcpt.address;
741 mail_copy_status = MAIL_COPY_STAT_WRITE;
742 buf = vstring_alloc(100);
744 - copy_flags = MAIL_COPY_TOFILE | MAIL_COPY_RETURN_PATH
745 - | MAIL_COPY_DELIVERED | MAIL_COPY_ORIG_RCPT;
746 + copy_flags = MAIL_COPY_TOFILE | MAIL_COPY_RETURN_PATH | MAIL_COPY_DELIVERED | MAIL_COPY_ORIG_RCPT;
748 - newdir = concatenate(usr_attr.mailbox, "new/", (char *) 0);
749 - tmpdir = concatenate(usr_attr.mailbox, "tmp/", (char *) 0);
750 - curdir = concatenate(usr_attr.mailbox, "cur/", (char *) 0);
752 + * Concatenate the maildir suffix (if set).
754 + if (*var_virt_maildir_suffix == 0) {
755 + newdir = concatenate(usr_attr.mailbox, "new/", (char *) 0);
756 + tmpdir = concatenate(usr_attr.mailbox, "tmp/", (char *) 0);
757 + curdir = concatenate(usr_attr.mailbox, "cur/", (char *) 0);
760 + newdir = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
761 + tmpdir = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
762 + curdir = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
763 + newdir = concatenate(newdir, "new/", (char *) 0);
764 + tmpdir = concatenate(tmpdir, "tmp/", (char *) 0);
765 + curdir = concatenate(curdir, "cur/", (char *) 0);
768 + /* get the sizefilename, no matter if we use var_virt_maildir_extended */
769 + if (*var_virt_maildir_suffix == 0) {
770 + sizefilename = concatenate(usr_attr.mailbox, "maildirsize", (char *) 0);
772 + sizefilename = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
773 + sizefilename = concatenate(sizefilename, "maildirsize", (char *) 0);
777 + * Look up the virtual maildir limit size for this user.
778 + * Fall back to virtual_mailbox_limit in case lookup failed.
779 + * If virtual maildir limit size is negative, fall back to virtual_mailbox_limit.
780 + * If it's 0, set the mailbox limit to 0, which means unlimited.
781 + * If it's more than 0 (positive int), check if the value is smaller than the maximum message size,
782 + * if it is and the virtual maildir limit can't be overridden, fall back to virtual_mailbox_limit and
783 + * warn the user, else use the value directly as the maildir limit.
785 + if (*var_virt_mailbox_limit_maps != 0 && (limit_res = mail_addr_find(virtual_mailbox_limit_maps, state.msg_attr.user, (char **) NULL)) != 0) {
786 + n = atol(limit_res);
788 + if ((n < var_message_limit) && (!var_virt_mailbox_limit_override)) {
789 + n = var_virt_mailbox_limit;
791 + msg_warn("%s: recipient %s - virtual maildir limit is smaller than %s in %s - falling back to %s",
792 + myname, state.msg_attr.user, VAR_MESSAGE_LIMIT, virtual_mailbox_limit_maps->title,
793 + VAR_VIRT_MAILBOX_LIMIT);
797 + msg_info("%s: set virtual maildir limit size for %s to %ld",
798 + myname, usr_attr.mailbox, n);
803 + msg_info("%s: set virtual maildir limit size for %s to %ld",
804 + myname, usr_attr.mailbox, n);
808 + msg_info("%s: quota is negative (%ld), using default virtual_mailbox_limit (%ld)",
809 + myname, n, var_virt_mailbox_limit);
810 + /* Invalid limit size (negative). Use default virtual_mailbox_limit. */
811 + n = var_virt_mailbox_limit;
816 + msg_info("%s: no limit found in the maps, using default virtual_mailbox_limit (%ld)",
817 + myname, var_virt_mailbox_limit);
818 + /* There is no limit in the maps. Use default virtual_mailbox_limit. */
819 + n = var_virt_mailbox_limit;
822 + /* If there should is a quota on maildir generaly, check it before delivering the mail */
824 + set_eugid(usr_attr.uid, usr_attr.gid);
825 + /* try to read the quota from maildirsize file. Returned values by read_maildirsize:
826 + x < 0 = something failed
827 + x >= 0 = reading successfully finished - sum si returned, so sum size of Maildir was 0 or more */
828 + if (!var_virt_mailbox_limit_inbox && var_virt_maildir_extended && (read_mds = read_maildirsize(sizefilename, &saved_size, &saved_count)) >= 0) {
830 + msg_info("%s: maildirsize used=%s sum=%ld count=%ld", myname, sizefilename, saved_size, saved_count);
833 + msg_info("%s: We will recount the quota (var_virt_mailbox_limit = %ld, var_virt_maildir_extended = %d, read_maildirsize = %d)",
834 + myname, var_virt_mailbox_limit, var_virt_maildir_extended, read_mds);
840 + if (var_virt_mailbox_limit_inbox) {
841 + /* Check Inbox only (new, cur and tmp dirs). */
842 + saved_size = check_dir_size(newdir, &saved_count);
843 + saved_size += check_dir_size(curdir, &saved_count);
844 + saved_size += check_dir_size(tmpdir, &saved_count);
846 + /* Check all boxes. */
847 + saved_size = check_dir_size(usr_attr.mailbox, &saved_count);
850 + set_eugid(var_owner_uid, var_owner_gid);
855 * Create and write the file as the recipient, so that file quota work.
856 * Create any missing directories on the fly. The file name is chosen
857 @@ -175,46 +664,288 @@ int deliver_maildir(LOCAL_STATE stat
860 set_eugid(usr_attr.uid, usr_attr.gid);
861 - vstring_sprintf(buf, "%lu.P%d.%s",
862 - (unsigned long) starttime.tv_sec, var_pid, get_hostname());
863 + vstring_sprintf(buf, "%lu.P%d.%s", (unsigned long) starttime.tv_sec, var_pid, get_hostname());
864 tmpfile = concatenate(tmpdir, STR(buf), (char *) 0);
867 if ((dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0
868 - && (errno != ENOENT
869 - || make_dirs(tmpdir, 0700) < 0
870 - || (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
871 - dsb_simple(why, mbox_dsn(errno, "4.2.0"),
872 - "create maildir file %s: %m", tmpfile);
873 - } else if (fstat(vstream_fileno(dst), &st) < 0) {
876 - * Coverity 200604: file descriptor leak in code that never executes.
877 - * Code replaced by msg_fatal(), as it is not worthwhile to continue
878 - * after an impossible error condition.
880 - msg_fatal("fstat %s: %m", tmpfile);
882 - vstring_sprintf(buf, "%lu.V%lxI%lxM%lu.%s",
883 - (unsigned long) starttime.tv_sec,
884 - (unsigned long) st.st_dev,
885 - (unsigned long) st.st_ino,
886 - (unsigned long) starttime.tv_usec,
888 - newfile = concatenate(newdir, STR(buf), (char *) 0);
889 - if ((mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr),
890 - dst, copy_flags, "\n",
892 - if (sane_link(tmpfile, newfile) < 0
893 - && (errno != ENOENT
894 - || (make_dirs(curdir, 0700), make_dirs(newdir, 0700)) < 0
895 - || sane_link(tmpfile, newfile) < 0)) {
896 - dsb_simple(why, mbox_dsn(errno, "4.2.0"),
897 - "create maildir file %s: %m", newfile);
898 - mail_copy_status = MAIL_COPY_STAT_WRITE;
901 - if (unlink(tmpfile) < 0)
902 - msg_warn("remove %s: %m", tmpfile);
903 + && (errno != ENOENT
904 + || make_dirs(tmpdir, 0700) < 0
905 + || (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
906 + dsb_simple(why, mbox_dsn(errno, "4.2.0"), "create maildir file %s: %m", tmpfile);
908 + else if (fstat(vstream_fileno(dst), &st) < 0) {
910 + * Coverity 200604: file descriptor leak in code that never executes.
911 + * Code replaced by msg_fatal(), as it is not worthwhile to continue
912 + * after an impossible error condition.
914 + msg_fatal("fstat %s: %m", tmpfile);
917 + vstring_sprintf(buf, "%lu.V%lxI%lxM%lu.%s",
918 + (unsigned long) starttime.tv_sec,
919 + (unsigned long) st.st_dev,
920 + (unsigned long) st.st_ino,
921 + (unsigned long) starttime.tv_usec,
923 + newfile = concatenate(newdir, STR(buf), (char *) 0);
924 + bkpnewfile = concatenate(STR(buf), (char *) 0); /* Will need it later, if we MOVE to other folders. */
926 + if ((mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), dst, copy_flags, "\n", why)) == 0) {
928 + * Add a ",S=<sizeoffile>" to the newly written file according to the
929 + * Maildir++ specifications: http://www.inter7.com/courierimap/README.maildirquota.html
930 + * This needs a stat(2) of the tempfile and modification of the
931 + * name of the file.
933 + if (stat(tmpfile, &mail_stat) == 0) {
935 + saved_size += (long) mail_stat.st_size;
938 + if (var_virt_maildir_extended) {
939 + /* Append the size of the file to newfile. */
940 + vstring_sprintf(buf, ",S=%ld", (long) mail_stat.st_size);
941 + newfile = concatenate(newfile, STR(buf), (char *) 0);
942 + bkpnewfile = concatenate(bkpnewfile, STR(buf), (char *) 0);
947 + * Now we have the maildir size in saved_size, compare it to the max
948 + * quota value and eventually issue a message that we've overdrawn it.
950 + if (saved_size > n) {
951 + mail_copy_status = MAIL_COPY_STAT_WRITE;
952 + if (((long) mail_stat.st_size > n) || (var_virt_overquota_bounce))
958 + /* Maildirfilter code by rk@demiurg.net. */
959 + if (var_virt_maildir_filter) {
961 + msg_info("%s: loading DICT filters", myname);
963 +#define STREQUAL(x,y,l) (strncasecmp((x), (y), (l)) == 0 && (y)[l] == 0)
964 +#define MAIL_COPY_STAT_REJECT (1<<3)
965 +#define MAIL_COPY_STAT_DISCARD (1<<4)
967 + /* Read filters. */
968 + filtername = concatenate("regexp:", usr_attr.mailbox, "maildirfilter", (char *) 0);
969 + sqlmtime = sql2file(strchr(filtername, '/'), state.msg_attr.user);
971 + /* Check if this filter is already registered as dictionary. */
973 + msg_info("%s: checking DICT filters for %s", myname, filtername);
975 + if ((FILTERS = dict_handle(filtername))) {
977 + msg_info("%s: DICT filter found", myname);
980 + * If we have mtime in our DICT structure, check it against sqlmtime
981 + * and reload the filters if they differ.
983 + if (FILTERS->mtime > 0 && sqlmtime > 0 && FILTERS->mtime != sqlmtime) {
985 + msg_info("%s: reloading DICT filters (dict_mtime=%ld != sql_mtime=%ld)",
986 + myname, FILTERS->mtime, sqlmtime);
988 + dict_unregister(filtername);
989 + FILTERS = dict_open(filtername, O_RDONLY, DICT_FLAG_LOCK);
990 + dict_register(filtername, FILTERS);
991 + FILTERS->mtime = sqlmtime;
995 + if (sqlmtime > 0) {
996 + /* Registering filter as new dictionary. */
998 + msg_info("%s: loading DICT filters from %s (mtime=%ld)",
999 + myname, filtername, sqlmtime);
1001 + FILTERS = dict_open(filtername, O_RDONLY, DICT_FLAG_LOCK);
1002 + dict_register(filtername, FILTERS);
1003 + FILTERS->mtime = sqlmtime;
1007 + if (FILTERS && (tmpfilter = vstream_fopen(tmpfile, O_RDONLY, 0))) {
1008 + fltstr = vstring_alloc(1024);
1009 + header = (char *) malloc(8192); /* !!!INSECURE!!! See 7168-hack below. */
1011 + vstring_get_nonl_bound(fltstr, tmpfilter, 1023);
1012 + header = concatenate(header, STR(fltstr), (char *) 0);
1014 + while(!vstream_feof(tmpfilter) && fltstr->vbuf.data[0] && strlen(header) < 7168 ) {
1015 + vstring_get_nonl_bound(fltstr, tmpfilter, 1023);
1016 + /* Glue multiline headers, replacing leading TAB with space. */
1018 + msg_info("%s: fltstr value: %s", myname, STR(fltstr));
1020 + if (fltstr->vbuf.data[0] == ' ' || fltstr->vbuf.data[0] == '\t' ) {
1021 + if (fltstr->vbuf.data[0] == '\t')
1022 + fltstr->vbuf.data[0] = ' ';
1023 + header = concatenate(header, STR(fltstr), (char *) 0);
1026 + header = concatenate(header, "\n", STR(fltstr), (char *) 0);
1031 + msg_info("%s: checking filter CMD for %s", myname, filtername);
1033 + /* Check whole header part with regexp maps. */
1034 + if ((value = dict_get(FILTERS, lowercase(header))) != 0) {
1036 + msg_info("%s: preparing filter CMD", myname);
1038 + cmd_text = value + strcspn(value, " \t");
1039 + cmd_len = cmd_text - value;
1040 + while (*cmd_text && ISSPACE(*cmd_text))
1044 + msg_info("%s: executing filter CMD", myname);
1046 + if (STREQUAL(value, "REJECT", cmd_len)) {
1048 + msg_info("%s: executing filter CMD REJECT", myname);
1050 + mail_copy_status = MAIL_COPY_STAT_REJECT;
1051 + vstring_sprintf(why->reason, "%s", cmd_text);
1052 + dsb_simple(why, "5.0.0", "User filter - REJECT");
1055 + if (STREQUAL(value, "DISCARD", cmd_len)) {
1057 + msg_info("%s: executing filter CMD DISCARD", myname);
1059 + mail_copy_status = MAIL_COPY_STAT_DISCARD;
1060 + vstring_sprintf(why->reason, "%s", cmd_text);
1061 + dsb_simple(why, "5.0.0", "User filter - DISCARD");
1064 + if (var_virt_maildir_extended) {
1065 + if (STREQUAL(value, "MOVE", cmd_len)) {
1067 + msg_info("%s: executing filter CMD MOVE", myname);
1069 + strcut((char *) cmd_text, " ");
1070 + strcut((char *) cmd_text, "\t");
1071 + strcut((char *) cmd_text, "/");
1072 + strcut((char *) cmd_text, "..");
1074 + if (*var_virt_maildir_suffix == 0) {
1075 + newfile = concatenate(usr_attr.mailbox, (char *) 0);
1078 + newfile = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
1081 + if (cmd_text[0] != '.') {
1082 + newfile = concatenate(newfile, ".", (char *) 0);
1084 + newdir = concatenate(newfile, cmd_text, "/", "new/", (char *) 0);
1085 + tmpdir = concatenate(newfile, cmd_text, "/", "tmp/", (char *) 0);
1086 + curdir = concatenate(newfile, cmd_text, "/", "cur/", (char *) 0);
1087 + mdffilename = concatenate(newfile, cmd_text, "/", "maildirfolder", (char *) 0);
1088 + newfile = concatenate(newfile, cmd_text, "/", "new/", bkpnewfile, (char *) 0);
1092 + if (STREQUAL(value, "LOG", cmd_len) || STREQUAL(value, "WARN", cmd_len)) {
1093 + msg_warn("%s: header check warning: %s", myname, cmd_text);
1096 + if (STREQUAL(value, "INFO", cmd_len)) {
1097 + msg_info("%s: header check info: %s", myname, cmd_text);
1101 + msg_info("%s: exiting filter CMD", myname);
1102 + } /* End-Of-Check */
1105 + vstring_free(fltstr);
1106 + vstream_fclose(tmpfilter);
1109 + myfree(filtername);
1110 + } /* End-Of-Maildirfilter */
1112 + /* Deliver to curdir. */
1113 + if (mail_copy_status == 0) {
1114 + if (sane_link(tmpfile, newfile) < 0
1115 + && (errno != ENOENT
1116 + || (make_dirs(curdir, 0700), make_dirs(newdir, 0700), make_dirs(tmpdir, 0700)) < 0
1117 + || sane_link(tmpfile, newfile) < 0)) {
1118 + dsb_simple(why, mbox_dsn(errno, "4.2.0"), "create maildir file %s: %m", newfile);
1119 + mail_copy_status = MAIL_COPY_STAT_WRITE;
1122 + if (var_virt_maildir_extended) {
1125 + /* Check if the quota in the file is the same as the current one, if not, delete the file. */
1126 + sizefile = vstream_fopen(sizefilename, O_RDONLY, 0);
1128 + filequota = vstring_alloc(128);
1129 + vstring_get_null_bound(filequota, sizefile, 127);
1130 + vstream_fclose(sizefile);
1131 + if (atol(vstring_export(filequota)) != n)
1132 + unlink(sizefilename);
1135 + /* Open maildirsize file to append this transaction. */
1136 + sizefile = vstream_fopen(sizefilename, O_WRONLY | O_APPEND, 0640);
1138 + /* If the open fails (maildirsize doesn't exist), or it's too large, or too old, overwrite it. */
1139 + if(!sizefile || (stat(sizefilename, &sizefile_stat) < 0) || (sizefile_stat.st_size > SIZEFILE_MAX) || (sizefile_stat.st_mtime + 15*60 < tm)) {
1140 + /* If the file exists, sizefile has been opened above, so close it first. */
1142 + vstream_fclose(sizefile);
1143 + sizefile = vstream_fopen(sizefilename, O_WRONLY | O_TRUNC, 0640);
1146 + sizefile = vstream_fopen(sizefilename, O_WRONLY | O_CREAT, 0640);
1149 + /* If the creation worked, write to the file, otherwise just give up. */
1151 + vstream_fprintf(sizefile, "%ldS\n%ld %ld\n", n, saved_size, saved_count);
1152 + vstream_fclose(sizefile);
1156 + /* We opened maildirsize, so let's just append this transaction and close it. */
1157 + vstream_fprintf(sizefile, "%ld 1\n", (long) mail_stat.st_size);
1158 + vstream_fclose(sizefile);
1162 + * 1) mdffilename != 0, so the maildirfilter code went through the MOVE to subfolder rule.
1163 + * 2) stat() failed, maybe the file does not exist? Try to create it.
1165 + if (mdffilename && (stat(mdffilename, &mdffile_stat) < 0)) {
1166 + mdffile = vstream_fopen(mdffilename, O_WRONLY | O_CREAT, 0600);
1168 + vstream_fclose(mdffile);
1171 + msg_warn("Cannot create maildirfolder file '%s': %s", mdffilename, strerror(errno));
1178 + if (unlink(tmpfile) < 0)
1179 + msg_warn("remove %s: %m", tmpfile);
1181 set_eugid(var_owner_uid, var_owner_gid);
1183 @@ -224,31 +955,64 @@ int deliver_maildir(LOCAL_STATE stat
1184 * location possibly under user control.
1186 if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
1187 - deliver_status = DEL_STAT_DEFER;
1188 - } else if (mail_copy_status != 0) {
1189 - if (errno == EACCES) {
1190 - msg_warn("maildir access problem for UID/GID=%lu/%lu: %s",
1191 - (long) usr_attr.uid, (long) usr_attr.gid,
1192 - STR(why->reason));
1193 - msg_warn("perhaps you need to create the maildirs in advance");
1195 - vstring_sprintf_prepend(why->reason, "maildir delivery failed: ");
1197 - (STR(why->status)[0] == '4' ?
1198 - defer_append : bounce_append)
1199 - (BOUNCE_FLAGS(state.request),
1200 - BOUNCE_ATTR(state.msg_attr));
1202 - dsb_simple(why, "2.0.0", "delivered to maildir");
1203 - deliver_status = sent(BOUNCE_FLAGS(state.request),
1204 - SENT_ATTR(state.msg_attr));
1205 + deliver_status = DEL_STAT_DEFER;
1207 + else if (mail_copy_status != 0) {
1208 + if (errno == EACCES) {
1209 + msg_warn("maildir access problem for UID/GID=%lu/%lu: %s",
1210 + (long) usr_attr.uid, (long) usr_attr.gid, STR(why->reason));
1211 + msg_warn("perhaps you need to create the maildirs in advance");
1214 + /* Support per-recipient bounce messages. */
1215 + const char *limit_message;
1216 + int errnored = errno; /* Seems like mail_addr_find resets errno ... */
1218 + if (*var_virt_maildir_limit_message_maps != 0 && (limit_message = mail_addr_find(virtual_maildir_limit_message_maps, state.msg_attr.user, (char **) NULL)) != 0) {
1220 + if (errno == EFBIG) {
1221 + dsb_simple(why, "5.2.2", limit_message, NULL);
1223 + if (errno == EDQUOT) {
1224 + dsb_simple(why, "4.2.2", limit_message, NULL);
1229 + if (errno == EFBIG) {
1230 + dsb_simple(why, "5.2.2", var_virt_maildir_limit_message, NULL);
1232 + if (errno == EDQUOT) {
1233 + dsb_simple(why, "4.2.2", var_virt_maildir_limit_message, NULL);
1237 + vstring_sprintf_prepend(why->reason, "maildir delivery failed: ");
1239 + (STR(why->status)[0] == '4' ? defer_append : bounce_append)
1240 + (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
1243 + dsb_simple(why, "2.0.0", "delivered to maildir");
1244 + deliver_status = sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr));
1254 + myfree(sizefilename);
1256 + myfree(mdffilename);
1263 + myfree(bkpnewfile);
1265 return (deliver_status);
1267 diff -ruNp postfix-2.11.10.orig/src/virtual/virtual.c postfix-2.11.10/src/virtual/virtual.c
1268 --- postfix-2.11.10.orig/src/virtual/virtual.c 2011-02-19 01:46:06.000000000 +0100
1269 +++ postfix-2.11.10/src/virtual/virtual.c 2017-07-02 00:13:25.779285410 +0200
1270 @@ -335,12 +335,30 @@ long var_virt_mailbox_limit;
1271 char *var_mail_spool_dir; /* XXX dependency fix */
1272 bool var_strict_mbox_owner;
1274 +char *var_virt_mailbox_limit_maps;
1275 +bool var_virt_mailbox_limit_inbox;
1276 +bool var_virt_mailbox_limit_override;
1277 +bool var_virt_maildir_extended;
1278 +bool var_virt_overquota_bounce;
1279 +char *var_virt_maildir_limit_message;
1280 +char *var_virt_maildir_limit_message_maps;
1281 +char *var_virt_maildir_suffix;
1282 +bool var_virt_trash_count;
1283 +char *var_virt_trash_name;
1284 +bool var_virt_maildir_filter;
1285 +char *var_virt_maildir_filter_maps;
1291 MAPS *virtual_mailbox_maps;
1292 MAPS *virtual_uid_maps;
1293 MAPS *virtual_gid_maps;
1294 +MAPS *virtual_mailbox_limit_maps;
1295 +MAPS *virtual_maildir_limit_message_maps;
1296 +MAPS *virtual_maildir_filter_maps;
1301 @@ -450,15 +468,28 @@ static void post_init(char *unused_name,
1303 virtual_mailbox_maps =
1304 maps_create(VAR_VIRT_MAILBOX_MAPS, var_virt_mailbox_maps,
1305 - DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
1309 maps_create(VAR_VIRT_UID_MAPS, var_virt_uid_maps,
1310 - DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
1314 maps_create(VAR_VIRT_GID_MAPS, var_virt_gid_maps,
1315 - DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
1318 + virtual_mailbox_limit_maps =
1319 + maps_create(VAR_VIRT_MAILBOX_LIMIT_MAPS, var_virt_mailbox_limit_maps,
1322 + virtual_maildir_limit_message_maps =
1323 + maps_create(VAR_VIRT_MAILDIR_LIMIT_MESSAGE_MAPS, var_virt_maildir_limit_message_maps,
1326 + virtual_maildir_filter_maps =
1327 + maps_create(VAR_VIRT_MAILDIR_FILTER_MAPS, var_virt_maildir_filter_maps,
1331 virtual_mbox_lock_mask = mbox_lock_mask(var_virt_mailbox_lock);
1333 @@ -510,10 +541,22 @@ int main(int argc, char **argv)
1334 VAR_VIRT_GID_MAPS, DEF_VIRT_GID_MAPS, &var_virt_gid_maps, 0, 0,
1335 VAR_VIRT_MAILBOX_BASE, DEF_VIRT_MAILBOX_BASE, &var_virt_mailbox_base, 1, 0,
1336 VAR_VIRT_MAILBOX_LOCK, DEF_VIRT_MAILBOX_LOCK, &var_virt_mailbox_lock, 1, 0,
1337 + VAR_VIRT_MAILBOX_LIMIT_MAPS, DEF_VIRT_MAILBOX_LIMIT_MAPS, &var_virt_mailbox_limit_maps, 0, 0,
1338 + VAR_VIRT_MAILDIR_LIMIT_MESSAGE, DEF_VIRT_MAILDIR_LIMIT_MESSAGE, &var_virt_maildir_limit_message, 1, 0,
1339 + VAR_VIRT_MAILDIR_LIMIT_MESSAGE_MAPS, DEF_VIRT_MAILDIR_LIMIT_MESSAGE_MAPS, &var_virt_maildir_limit_message_maps, 0, 0,
1340 + VAR_VIRT_MAILDIR_SUFFIX, DEF_VIRT_MAILDIR_SUFFIX, &var_virt_maildir_suffix, 0, 0,
1341 + VAR_VIRT_TRASH_NAME, DEF_VIRT_TRASH_NAME, &var_virt_trash_name, 0, 0,
1342 + VAR_VIRT_MAILDIR_FILTER_MAPS, DEF_VIRT_MAILDIR_FILTER_MAPS, &var_virt_maildir_filter_maps, 0, 0,
1345 static const CONFIG_BOOL_TABLE bool_table[] = {
1346 VAR_STRICT_MBOX_OWNER, DEF_STRICT_MBOX_OWNER, &var_strict_mbox_owner,
1347 + VAR_VIRT_MAILBOX_LIMIT_INBOX, DEF_VIRT_MAILBOX_LIMIT_INBOX, &var_virt_mailbox_limit_inbox,
1348 + VAR_VIRT_MAILBOX_LIMIT_OVERRIDE, DEF_VIRT_MAILBOX_LIMIT_OVERRIDE, &var_virt_mailbox_limit_override,
1349 + VAR_VIRT_MAILDIR_EXTENDED, DEF_VIRT_MAILDIR_EXTENDED, &var_virt_maildir_extended,
1350 + VAR_VIRT_OVERQUOTA_BOUNCE, DEF_VIRT_OVERQUOTA_BOUNCE, &var_virt_overquota_bounce,
1351 + VAR_VIRT_TRASH_COUNT, DEF_VIRT_TRASH_COUNT, &var_virt_trash_count,
1352 + VAR_VIRT_MAILDIR_FILTER, DEF_VIRT_MAILDIR_FILTER, &var_virt_maildir_filter,
1356 @@ -530,6 +573,7 @@ int main(int argc, char **argv)
1357 MAIL_SERVER_PRE_INIT, pre_init,
1358 MAIL_SERVER_POST_INIT, post_init,
1359 MAIL_SERVER_PRE_ACCEPT, pre_accept,
1360 + MAIL_SERVER_BOOL_TABLE, bool_table,
1361 MAIL_SERVER_PRIVILEGED,
1364 diff -ruNp postfix-2.11.10.orig/src/virtual/virtual.h postfix-2.11.10/src/virtual/virtual.h
1365 --- postfix-2.11.10.orig/src/virtual/virtual.h 2006-01-08 00:59:47.000000000 +0100
1366 +++ postfix-2.11.10/src/virtual/virtual.h 2017-07-02 00:13:25.780285407 +0200
1368 extern MAPS *virtual_mailbox_maps;
1369 extern MAPS *virtual_uid_maps;
1370 extern MAPS *virtual_gid_maps;
1371 +extern MAPS *virtual_mailbox_limit_maps;
1372 +extern MAPS *virtual_maildir_limit_message_maps;
1373 +extern MAPS *virtual_maildir_filter_maps;
1376 * User attributes: these control the privileges for delivery to external