Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 606494 | Differences between
and this patch

Collapse All | Expand All

(-)postfix-3.0.3.orig/README_FILES/VDA_README (+12 lines)
Line 0 Link Here
1
Postfix VDA patch for maildir++ quota support by 
2
    Anderson Nadal <andernadal@gmail.com>
3
    Tomas Macek <maca02@atlas.cz>
4
    Lucca Longinotti
5
6
See VDA patch official website http://vda.sf.net for instructions
7
howto patch the Postfix's sourcetree and configure the options 
8
provided by this patch.
9
10
    Cristian Sava <csava@central.ucv.ro> *** port to postfix-3.0.3
11
12
(-)postfix-3.0.3.orig/src/global/mail_params.h (+48 lines)
Lines 2468-2473 Link Here
2468
#define DEF_VIRT_GID_MAPS		""
2468
#define DEF_VIRT_GID_MAPS		""
2469
extern char *var_virt_gid_maps;
2469
extern char *var_virt_gid_maps;
2470
2470
2471
#define VAR_VIRT_MAILBOX_LIMIT_MAPS     "virtual_mailbox_limit_maps"
2472
#define DEF_VIRT_MAILBOX_LIMIT_MAPS     ""
2473
extern char *var_virt_mailbox_limit_maps;
2474
2475
#define VAR_VIRT_MAILBOX_LIMIT_INBOX    "virtual_mailbox_limit_inbox"
2476
#define DEF_VIRT_MAILBOX_LIMIT_INBOX    0
2477
extern bool var_virt_mailbox_limit_inbox;
2478
2479
#define VAR_VIRT_MAILBOX_LIMIT_OVERRIDE "virtual_mailbox_limit_override"
2480
#define DEF_VIRT_MAILBOX_LIMIT_OVERRIDE 0
2481
extern bool var_virt_mailbox_limit_override;
2482
2483
#define VAR_VIRT_MAILDIR_EXTENDED       "virtual_maildir_extended"
2484
#define DEF_VIRT_MAILDIR_EXTENDED       0
2485
extern bool var_virt_maildir_extended;
2486
2487
#define VAR_VIRT_OVERQUOTA_BOUNCE       "virtual_overquota_bounce"
2488
#define DEF_VIRT_OVERQUOTA_BOUNCE       0
2489
extern bool var_virt_overquota_bounce;
2490
2491
#define VAR_VIRT_MAILDIR_LIMIT_MESSAGE  "virtual_maildir_limit_message"
2492
#define DEF_VIRT_MAILDIR_LIMIT_MESSAGE  "Sorry, the user's maildir has overdrawn his diskspace quota, please try again later."
2493
extern char *var_virt_maildir_limit_message;
2494
2495
#define VAR_VIRT_MAILDIR_LIMIT_MESSAGE_MAPS "virtual_maildir_limit_message_maps"
2496
#define DEF_VIRT_MAILDIR_LIMIT_MESSAGE_MAPS ""
2497
extern char *var_virt_maildir_limit_message_maps;
2498
2499
#define VAR_VIRT_MAILDIR_SUFFIX         "virtual_maildir_suffix"
2500
#define DEF_VIRT_MAILDIR_SUFFIX         ""
2501
extern char *var_virt_maildir_suffix;
2502
2503
#define VAR_VIRT_TRASH_COUNT            "virtual_trash_count"
2504
#define DEF_VIRT_TRASH_COUNT            0
2505
extern bool var_virt_trash_count;
2506
2507
#define VAR_VIRT_TRASH_NAME             "virtual_trash_name"
2508
#define DEF_VIRT_TRASH_NAME             ".Trash"
2509
extern char *var_virt_trash_name;
2510
2511
#define VAR_VIRT_MAILDIR_FILTER         "virtual_maildir_filter"
2512
#define DEF_VIRT_MAILDIR_FILTER         0
2513
extern bool var_virt_maildir_filter;
2514
2515
#define VAR_VIRT_MAILDIR_FILTER_MAPS    "virtual_maildir_filter_maps"
2516
#define DEF_VIRT_MAILDIR_FILTER_MAPS    ""
2517
extern char *var_virt_maildir_filter_maps;
2518
2471
#define VAR_VIRT_MINUID			"virtual_minimum_uid"
2519
#define VAR_VIRT_MINUID			"virtual_minimum_uid"
2472
#define DEF_VIRT_MINUID			100
2520
#define DEF_VIRT_MINUID			100
2473
extern int var_virt_minimum_uid;
2521
extern int var_virt_minimum_uid;
(-)postfix-3.0.3.orig/src/util/file_limit.c (-1 / +5 lines)
Lines 85-91 Link Here
85
#else
85
#else
86
    struct rlimit rlim;
86
    struct rlimit rlim;
87
87
88
    rlim.rlim_cur = rlim.rlim_max = limit;
88
    /* rlim_max can only be changed by root. */
89
    if (getrlimit(RLIMIT_FSIZE, &rlim) < 0)
90
        msg_fatal("getrlimit: %m");
91
    rlim.rlim_cur = limit;
92
89
    if (setrlimit(RLIMIT_FSIZE, &rlim) < 0)
93
    if (setrlimit(RLIMIT_FSIZE, &rlim) < 0)
90
	msg_fatal("setrlimit: %m");
94
	msg_fatal("setrlimit: %m");
91
#ifdef SIGXFSZ
95
#ifdef SIGXFSZ
(-)postfix-3.0.3.orig/src/virtual/mailbox.c (-37 / +111 lines)
Lines 52-57 Link Here
52
#include <mymalloc.h>
52
#include <mymalloc.h>
53
#include <stringops.h>
53
#include <stringops.h>
54
#include <set_eugid.h>
54
#include <set_eugid.h>
55
#include <iostuff.h>
55
56
56
/* Global library. */
57
/* Global library. */
57
58
Lines 70-75 Link Here
70
#define YES	1
71
#define YES	1
71
#define NO	0
72
#define NO	0
72
73
74
/* change_mailbox_limit - change limit for mailbox file */
75
static int change_mailbox_limit(LOCAL_STATE state, USER_ATTR usr_attr)
76
{
77
    char *myname = "change_mailbox_limit";
78
    const char *limit_res;
79
    long n = 0;
80
    int status = NO;
81
82
    /*
83
     * Look up the virtual mailbox limit size for this user.
84
     * Fall back to virtual_mailbox_limit in case lookup failed.
85
     * If virtual mailbox limit size is negative, fall back to virtual_mailbox_limit.
86
     * If it's 0, set the mailbox limit to 0, which means unlimited.
87
     * If it's more than 0 (positive int), check if the value is smaller than the maximum message size,
88
     * if it is and the virtual mailbox limit can't be overridden, fall back to virtual_mailbox_limit and
89
     * warn the user, else use the value directly as the mailbox limit.
90
     */
91
    if (*var_virt_mailbox_limit_maps != 0 && (limit_res = mail_addr_find(virtual_mailbox_limit_maps, state.msg_attr.user, (char **) NULL)) != 0) {
92
        n = atol(limit_res);
93
        if (n > 0) {
94
            if ((n < var_message_limit) && (!var_virt_mailbox_limit_override)) {
95
                set_file_limit(var_virt_mailbox_limit);
96
                status = NO;
97
98
                msg_warn("%s: recipient %s - virtual mailbox limit is "
99
                        "smaller than %s in %s - falling back to %s",
100
                        myname,
101
                        state.msg_attr.user,
102
                        VAR_MESSAGE_LIMIT,
103
                        virtual_mailbox_limit_maps->title,
104
                        VAR_VIRT_MAILBOX_LIMIT);
105
            }
106
            else {
107
                set_file_limit((off_t) n);
108
                status = YES;
109
110
                if (msg_verbose)
111
                    msg_info("%s: set virtual mailbox limit size for %s to %ld",
112
                            myname, usr_attr.mailbox, n);
113
            }
114
        }
115
        else if (n == 0) {
116
                set_file_limit(OFF_T_MAX);
117
                status = YES;
118
119
                if (msg_verbose)
120
                    msg_info("%s: set virtual mailbox limit size for %s to %ld",
121
                            myname, usr_attr.mailbox, OFF_T_MAX);
122
        }
123
        else {
124
            /* Invalid limit size (negative). Use default virtual_mailbox_limit. */
125
            set_file_limit(var_virt_mailbox_limit);
126
            status = NO;
127
        }
128
    }
129
    else {
130
        /* There is no limit in the maps. Use default virtual_mailbox_limit. */
131
        set_file_limit(var_virt_mailbox_limit);
132
        status = NO;
133
    }
134
135
    return(status);
136
}
137
73
/* deliver_mailbox_file - deliver to recipient mailbox */
138
/* deliver_mailbox_file - deliver to recipient mailbox */
74
139
75
static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
140
static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
Lines 80-86 Link Here
80
    int     mail_copy_status;
145
    int     mail_copy_status;
81
    int     deliver_status;
146
    int     deliver_status;
82
    int     copy_flags;
147
    int     copy_flags;
83
    long    end;
84
    struct stat st;
148
    struct stat st;
85
149
86
    /*
150
    /*
Lines 132-138 Link Here
132
	    msg_warn("specify \"%s = no\" to ignore mailbox ownership mismatch",
196
	    msg_warn("specify \"%s = no\" to ignore mailbox ownership mismatch",
133
		     VAR_STRICT_MBOX_OWNER);
197
		     VAR_STRICT_MBOX_OWNER);
134
	} else {
198
	} else {
135
	    end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END);
199
	    vstream_fseek(mp->fp, (off_t) 0, SEEK_END);
136
	    mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
200
	    mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
137
					 copy_flags, "\n", why);
201
					 copy_flags, "\n", why);
138
	}
202
	}
Lines 213-274 Link Here
213
     * Look up the mailbox owner rights. Defer in case of trouble.
277
     * Look up the mailbox owner rights. Defer in case of trouble.
214
     */
278
     */
215
    uid_res = mail_addr_find(virtual_uid_maps, state.msg_attr.user,
279
    uid_res = mail_addr_find(virtual_uid_maps, state.msg_attr.user,
216
			     IGNORE_EXTENSION);
280
                            IGNORE_EXTENSION);
217
    if (uid_res == 0) {
281
218
	msg_warn("recipient %s: not found in %s",
282
    if ((uid_res = mail_addr_find(virtual_uid_maps, state.msg_attr.user, (char **) 0)) == 0) {
219
		 state.msg_attr.user, virtual_uid_maps->title);
283
        if ((uid_res = maps_find(virtual_uid_maps, strchr(state.msg_attr.user, '@'), DICT_FLAG_FIXED)) == 0) {
220
	dsb_simple(why, "4.3.5", "mail system configuration error");
284
			msg_warn("recipient %s: not found in %s", state.msg_attr.user, virtual_uid_maps->title);
221
	*statusp = defer_append(BOUNCE_FLAGS(state.request),
285
			dsb_simple(why, "4.3.5", "mail system configuration error");
222
				BOUNCE_ATTR(state.msg_attr));
286
			*statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
223
	RETURN(YES);
287
			RETURN(YES);
288
        }
224
    }
289
    }
290
225
    if ((n = atol(uid_res)) < var_virt_minimum_uid) {
291
    if ((n = atol(uid_res)) < var_virt_minimum_uid) {
226
	msg_warn("recipient %s: bad uid %s in %s",
292
		msg_warn("recipient %s: bad uid %s in %s", state.msg_attr.user, uid_res, virtual_uid_maps->title);
227
		 state.msg_attr.user, uid_res, virtual_uid_maps->title);
293
		dsb_simple(why, "4.3.5", "mail system configuration error");
228
	dsb_simple(why, "4.3.5", "mail system configuration error");
294
		*statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
229
	*statusp = defer_append(BOUNCE_FLAGS(state.request),
295
		RETURN(YES);
230
				BOUNCE_ATTR(state.msg_attr));
231
	RETURN(YES);
232
    }
296
    }
297
233
    usr_attr.uid = (uid_t) n;
298
    usr_attr.uid = (uid_t) n;
234
299
235
    /*
300
    /*
236
     * Look up the mailbox group rights. Defer in case of trouble.
301
     * Look up the mailbox group rights. Defer in case of trouble.
237
     */
302
     */
238
    gid_res = mail_addr_find(virtual_gid_maps, state.msg_attr.user,
303
    gid_res = mail_addr_find(virtual_gid_maps, state.msg_attr.user,
239
			     IGNORE_EXTENSION);
304
                            IGNORE_EXTENSION);
240
    if (gid_res == 0) {
305
241
	msg_warn("recipient %s: not found in %s",
306
    if ((gid_res = mail_addr_find(virtual_gid_maps, state.msg_attr.user, (char **) 0)) == 0) {
242
		 state.msg_attr.user, virtual_gid_maps->title);
307
        if ((gid_res = maps_find(virtual_gid_maps, strchr(state.msg_attr.user, '@'), DICT_FLAG_FIXED)) == 0) {
243
	dsb_simple(why, "4.3.5", "mail system configuration error");
308
			msg_warn("recipient %s: not found in %s", state.msg_attr.user, virtual_gid_maps->title);
244
	*statusp = defer_append(BOUNCE_FLAGS(state.request),
309
			dsb_simple(why, "4.3.5", "mail system configuration error");
245
				BOUNCE_ATTR(state.msg_attr));
310
			*statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
246
	RETURN(YES);
311
			RETURN(YES);
312
        }
247
    }
313
    }
314
248
    if ((n = atol(gid_res)) <= 0) {
315
    if ((n = atol(gid_res)) <= 0) {
249
	msg_warn("recipient %s: bad gid %s in %s",
316
		msg_warn("recipient %s: bad gid %s in %s", state.msg_attr.user, gid_res, virtual_gid_maps->title);
250
		 state.msg_attr.user, gid_res, virtual_gid_maps->title);
317
		dsb_simple(why, "4.3.5", "mail system configuration error");
251
	dsb_simple(why, "4.3.5", "mail system configuration error");
318
		*statusp = defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
252
	*statusp = defer_append(BOUNCE_FLAGS(state.request),
319
		RETURN(YES);
253
				BOUNCE_ATTR(state.msg_attr));
254
	RETURN(YES);
255
    }
320
    }
321
256
    usr_attr.gid = (gid_t) n;
322
    usr_attr.gid = (gid_t) n;
257
323
258
    if (msg_verbose)
324
    if (msg_verbose)
259
	msg_info("%s[%d]: set user_attr: %s, uid = %u, gid = %u",
325
        msg_info("%s[%d]: set user_attr: %s, uid = %u, gid = %u",
260
		 myname, state.level, usr_attr.mailbox,
326
                myname, state.level, usr_attr.mailbox,
261
		 (unsigned) usr_attr.uid, (unsigned) usr_attr.gid);
327
                (unsigned) usr_attr.uid, (unsigned) usr_attr.gid);
262
328
263
    /*
329
    /*
264
     * Deliver to mailbox or to maildir.
330
     * Deliver to mailbox or to maildir.
265
     */
331
     */
266
#define LAST_CHAR(s) (s[strlen(s) - 1])
332
#define LAST_CHAR(s) (s[strlen(s) - 1])
267
333
268
    if (LAST_CHAR(usr_attr.mailbox) == '/')
334
    if (LAST_CHAR(usr_attr.mailbox) == '/') {
269
	*statusp = deliver_maildir(state, usr_attr);
335
        *statusp = deliver_maildir(state, usr_attr);
270
    else
336
    }
271
	*statusp = deliver_mailbox_file(state, usr_attr);
337
    else {
338
        int changed_limit;
339
340
        changed_limit = change_mailbox_limit(state, usr_attr);
341
        *statusp = deliver_mailbox_file(state, usr_attr);
342
343
        if (changed_limit)
344
            set_file_limit(var_virt_mailbox_limit);
345
    }
272
346
273
    /*
347
    /*
274
     * Cleanup.
348
     * Cleanup.
(-)postfix-3.0.3.orig/src/virtual/maildir.c (-78 / +842 lines)
Lines 64-91 Link Here
64
#include <mbox_open.h>
64
#include <mbox_open.h>
65
#include <dsn_util.h>
65
#include <dsn_util.h>
66
66
67
/* Patch library. */
68
69
#include <sys/types.h> /* opendir(3), stat(2) */
70
#include <sys/stat.h>  /* stat(2) */
71
#include <dirent.h>    /* opendir(3) */
72
#include <unistd.h>    /* stat(2) */
73
#include <stdlib.h>    /* atol(3) */
74
#include <string.h>    /* strrchr(3) */
75
#include <vstring_vstream.h>
76
#include <dict.h>
77
#include <dict_regexp.h>
78
#include <ctype.h>
79
#include <stdio.h>
80
#include <sys_defs.h>
81
#include <mail_addr_find.h>
82
67
/* Application-specific. */
83
/* Application-specific. */
68
84
69
#include "virtual.h"
85
#include "virtual.h"
70
86
71
/* deliver_maildir - delivery to maildir-style mailbox */
87
/* Maildirsize maximal size. */
88
89
#define SIZEFILE_MAX 5120
90
91
/*
92
 * Chris Stratford <chriss@pipex.net>
93
 * Read the maildirsize file to get quota info.
94
 *
95
 * Arguments:
96
 *  dirname: the maildir
97
 *  countptr: number of messages
98
 *
99
 * Returns the size of all mails as read from maildirsize,
100
 * zero if it couldn't read the file.
101
 */
102
static long read_maildirsize(char *filename, long *sumptr, long *countptr)
103
{
104
    char *myname = "read_maildirsize";
105
    struct stat statbuf;
106
    VSTREAM *sizefile;
107
    char *p;
108
    int len, first;
109
    long sum = 0, count = 0, ret_value = -1;
110
111
    if (msg_verbose) 
112
	msg_info("%s: we will use sizefile = '%s'", myname, filename);
113
	
114
    sizefile = vstream_fopen(filename, O_RDONLY, 0);
115
    if (!sizefile) {
116
	if (msg_verbose)
117
	    msg_info("%s: cannot open %s: %m (maybe file does not exist)", myname, filename);
118
	    
119
	return -1;
120
    } else if (stat(filename, &statbuf) < 0 || statbuf.st_size > SIZEFILE_MAX) {
121
        if (sizefile) {
122
            vstream_fclose(sizefile);
123
            unlink(filename);
124
        }
125
        
126
        if (msg_verbose) 
127
	    msg_info("%s: stat() returned < 0 or filesize > SIZEFILE_MAX (filename = %s, filesize = %ld)", myname, filename, statbuf.st_size);
128
        
129
        return -1;
130
    }
131
    
132
    VSTRING *sizebuf = vstring_alloc(SIZEFILE_MAX);
133
    len = vstream_fread(sizefile, STR(sizebuf), SIZEFILE_MAX);
134
135
    p = STR(sizebuf);
136
    *(p + len) = '\0';
137
    first = 1;
138
139
    while (*p) {
140
        long n = 0, c = 0;
141
        char *q = p;
142
143
        while (*p) {
144
            if (*p++ == '\n') {
145
                p[-1] = 0;
146
                break;
147
            }
148
        }
149
150
        if (first) {
151
            first = 0;
152
            continue;
153
        }
154
155
        if (sscanf(q, "%ld %ld", &n, &c) == 2) {
156
            sum += n;
157
            count += c;
158
            /* if (msg_verbose)
159
    		msg_info("%s: we read line '%s', totals: sum = %ld, count = %ld", myname, q, sum, count); */
160
        }
161
        else {
162
            vstream_fclose(sizefile);
163
            unlink(filename);
164
            msg_warn("%s: invalid line '%s' found in %s, removing maildirsize file", myname, q, filename);
165
            vstring_free(sizebuf);
166
167
            return -1;
168
        }
169
    }
170
171
    *countptr = count;
172
    *sumptr = sum;
173
        
174
    if (sum < 0 || count < 0 || (sum == 0 && count != 0) || (sum != 0 && count == 0)) {
175
	if (msg_verbose) {
176
	    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);
177
	}
178
	
179
	unlink(filename);
180
	ret_value = -1;
181
    } else {
182
	if (msg_verbose) 
183
	    msg_info("%s: we will return Maildir size = %ld, count = %ld", myname, *sumptr, *countptr);
184
185
	ret_value = sum;	
186
    }
187
188
    vstream_fclose(sizefile);
189
    vstring_free(sizebuf);
190
    
191
    return ret_value;
192
}
193
194
/*
195
 * Gives the size of the file according to the Maildir++ extension
196
 * present in the filename (code taken from courier-imap).
197
 *
198
 * Arguments:
199
 *  n: filename
200
 *
201
 * Returns the size given in ",S=<size>" in the filename,
202
 * zero if it cannot find ",S=<size>" in the filename.
203
 */
204
static long maildir_parsequota(const char *n)
205
{
206
    const char *o;
207
    int yes = 0;
208
209
    if ((o = strrchr(n, '/')) == 0)
210
        o = n;
211
212
    for (; *o; o++) {
213
        if (*o == ':')
214
            break;
215
    }
216
217
    for (; o >= n; --o) {
218
        if (*o == '/')
219
            break;
220
221
        if (*o == ',' && o[1] == 'S' && o[2] == '=') {
222
            yes = 1;
223
            o += 3;
224
            break;
225
        }
226
    }
227
228
    if (yes) {
229
        long s = 0;
230
231
        while (*o >= '0' && *o <= '9')
232
            s = s*10 + (*o++ - '0');
233
234
        return s;
235
    }
236
237
    return 0;
238
}
239
240
/*
241
 * Computes quota usage for a directory (taken from exim).
242
 *
243
 * This function is called to determine the exact quota usage of a virtual
244
 * maildir box. To achieve maximum possible speed while doing this, it takes
245
 * advantage of the maildirsize file and the Maildir++ extensions to filenames,
246
 * when applicable and configured to be used. In all other cases it simply
247
 * stats all the files as needed to get the size information.
248
 *
249
 * Arguments:
250
 *  dirname: the name of the directory
251
 *  countptr: where to add the file count (because this function recurses)
252
 *
253
 * Returns the sum of the sizes of all measurable files,
254
 * zero if the directory could not be opened.
255
 */
256
static long check_dir_size(char *dirname, long *countptr)
257
{
258
    char *myname = "check_dir_size";
259
    DIR *dir;
260
    long sum = 0;
261
    struct dirent *ent;
262
    struct stat statbuf;
263
264
    dir = opendir(dirname);
265
    if (dir == NULL) {
266
        if (make_dirs(dirname, 0700) == 0) {    /* Try to create the dirs. */
267
            dir = opendir(dirname);             /* Reopen the dir. */
268
            if (dir == NULL) {
269
                msg_warn("%s: cannot reopen directory: %s", myname, dirname);
270
                return 0;
271
            }
272
        }
273
        else {
274
            msg_warn("%s: cannot open directory: %s", myname, dirname);
275
            return 0;
276
        }
277
    }
278
279
    while ((ent = readdir(dir)) != NULL) {
280
        char *name = ent->d_name;
281
        long tmpsum = 0;
282
        VSTRING *buffer;
283
284
	/* do not count dot a double-dot dirs */
285
        if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
286
            continue;
287
        /* do not count if this is the trash subdir and if we should NOT count it */
288
	else if (var_virt_trash_count == 0 && strcmp(name, var_virt_trash_name) == 0)
289
    	    continue;
290
291
        /*
292
         * Here comes the real logic behind this function.
293
         * Optimized to be the most efficient possible,
294
         * depending on the settings given.
295
         * See above for a more detailed description.
296
         */
297
        if (var_virt_mailbox_limit_inbox) {
298
            if (var_virt_maildir_extended && (tmpsum = maildir_parsequota(name))) {
299
                sum += tmpsum;
300
                (*countptr)++;
301
            }
302
            else {
303
                buffer = vstring_alloc(1024);
304
                vstring_sprintf(buffer, "%s/%s", dirname, name);
305
306
                if (stat(STR(buffer), &statbuf) < 0) {
307
                    vstring_free(buffer);
308
                    continue;
309
                }
310
                if ((statbuf.st_mode & S_IFREG) != 0) {
311
                    sum += (long) statbuf.st_size;
312
                    (*countptr)++;
313
                }
314
315
                vstring_free(buffer);
316
            }
317
        }
318
        else {
319
            buffer = vstring_alloc(1024);
320
            vstring_sprintf(buffer, "%s/%s", dirname, name);
321
322
            if (stat(STR(buffer), &statbuf) < 0) {
323
                vstring_free(buffer);
324
                continue;
325
            }
326
            if ((statbuf.st_mode & S_IFREG) != 0) {
327
                if (strcmp(dirname + strlen(dirname) - 3, "new") == 0 || strcmp(dirname + strlen(dirname) - 3, "cur") == 0 || strcmp(dirname + strlen(dirname) - 3, "tmp") == 0) {
328
                    sum += (long) statbuf.st_size;
329
                    (*countptr)++;
330
                }
331
            }
332
            else if ((statbuf.st_mode & S_IFDIR) != 0) {
333
                sum += check_dir_size(STR(buffer), countptr);
334
            }
335
336
            vstring_free(buffer);
337
        }
338
    }
339
    closedir(dir);
72
340
73
int     deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
341
    if (msg_verbose)
342
        msg_info("%s: full scan done: dir=%s sum=%ld count=%ld", myname, dirname, sum, *countptr);
343
344
    return sum;
345
}
346
347
/* Cut all occurrences of pattern from string. */
348
static char *strcut(char *str, const char *pat)
349
{
350
    char *ptr, *loc, *ret;
351
    ret = str;
352
    loc = str;
353
354
    /* No match, return original string. */
355
    if (!strstr(loc, pat))
356
        return(str);
357
358
    while (*loc && (ptr = strstr(loc, pat))) {
359
        while (loc < ptr)
360
            *str++ = *loc++;
361
        loc += strlen(pat);
362
    }
363
364
    while (*loc)
365
        *str++ = *loc++;
366
367
    *str = 0;
368
369
    return(ret);
370
}
371
372
/* Check if maildirfilter file is up-to-date compared to SQL, (re)write it if not. */
373
static long sql2file(char *filename, char *user)
374
{
375
    char *myname = "sql2file";
376
    char *filter_sqlres;
377
    char filter_fileres[128];
378
    long sqlmtime = 0, filemtime = 0, retval = 0;
379
    int filterfile, size_sqlres, i;
380
    struct stat statbuf;
381
382
    if (*var_virt_maildir_filter_maps != 0) {
383
        filter_sqlres = (char *) mymalloc(16000);
384
        filter_sqlres = (char *) mail_addr_find(virtual_maildir_filter_maps, user, (char **) 0);
385
386
        if (filter_sqlres) {
387
            strcut(filter_sqlres, "\r");
388
            if (filter_sqlres[0] == '#' && filter_sqlres[1] == ' ' && filter_sqlres[2] == 'M') {
389
                size_sqlres = strlen(filter_sqlres);
390
391
                for (i = 4; i <= size_sqlres; i++) {
392
                    if(filter_sqlres[i] == '/' && filter_sqlres[i+1] == '^') {
393
                        filter_sqlres[i-1] = '\n';
394
                    }
395
                }
396
397
                filter_sqlres[(size_sqlres+1)] = '\0';
398
399
                sqlmtime = atol(filter_sqlres+3);
400
                retval = sqlmtime;
401
402
                filterfile = open(filename, O_RDONLY, 0);
403
                if (filterfile) {
404
                    read(filterfile, (void *) filter_fileres, 127);
405
                    close(filterfile);
406
407
                    filemtime = atol(filter_fileres+3);
408
                }
409
410
                if (msg_verbose)
411
                    msg_info("%s: filter data: sql_size=%li sql_mtime=%ld file_mtime=%ld", myname, strlen(filter_sqlres), sqlmtime, filemtime);
412
            }
413
            if (sqlmtime != filemtime && sqlmtime != 0) {
414
                if ((filterfile = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0640))) {
415
                    if (msg_verbose)
416
                        msg_info("%s: updating filter file: %s", myname, filename);
417
                    write(filterfile, filter_sqlres, strlen(filter_sqlres));
418
                    close(filterfile);
419
                }
420
                else {
421
                    msg_warn("%s: can't create filter file: %s", myname, filename);
422
                    retval = 0;
423
                }
424
            }
425
        }
426
    }
427
    else {
428
        if (stat(filename, &statbuf) == 0)
429
            retval = (long) statbuf.st_mtime;
430
        if (msg_verbose)
431
            msg_info("%s: processing filter file: file_mtime=%ld", myname, retval);
432
    }
433
434
    return retval;
435
}
436
437
/* deliver_maildir - delivery to maildir-style mailbox */
438
int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr)
74
{
439
{
75
    const char *myname = "deliver_maildir";
440
    const char *myname = "deliver_maildir";
76
    char   *newdir;
441
    char    *newdir;
77
    char   *tmpdir;
442
    char    *tmpdir;
78
    char   *curdir;
443
    char    *curdir;
79
    char   *tmpfile;
444
    char    *newfile;
80
    char   *newfile;
445
    char    *tmpfile;
81
    DSN_BUF *why = state.msg_attr.why;
446
    DSN_BUF *why = state.msg_attr.why;
82
    VSTRING *buf;
447
    VSTRING *buf;
83
    VSTREAM *dst;
448
    VSTREAM *dst;
84
    int     mail_copy_status;
449
    int      mail_copy_status;
85
    int     deliver_status;
450
    int      deliver_status;
86
    int     copy_flags;
451
    int      copy_flags;
87
    struct stat st;
452
    struct   stat st;
88
    struct timeval starttime;
453
    struct   timeval starttime;
454
455
    /* Maildir Quota. */
456
    const char *limit_res;              /* Limit from map. */
457
    char    *sizefilename = (char *) 0; /* Maildirsize file name. */
458
    VSTRING *filequota;                 /* Quota setting from the maildirsize file. */
459
    VSTREAM *sizefile;                  /* Maildirsize file handle. */
460
    long     n = 0;                     /* Limit in long integer format. */
461
    long     saved_count = 0;           /* The total number of files. */
462
    long     saved_size = 0;            /* The total quota of all files. */
463
    struct   stat mail_stat;            /* To check the size of the mail to be written. */
464
    struct   stat sizefile_stat;        /* To check the size of the maildirsize file. */
465
    time_t   tm;                        /* To check the age of the maildirsize file. */
466
467
    /* Maildir Filters. */
468
    const char *value, *cmd_text;       /* Filter values. */
469
    char    *filtername;
470
    char    *header;
471
    char    *bkpnewfile;
472
    char    *mdffilename = (char *) 0;  /* Maildirfolder file name. */
473
    VSTRING *fltstr;
474
    VSTREAM *tmpfilter;
475
    VSTREAM *mdffile;                   /* Maildirfolder file handle. */
476
    DICT    *FILTERS;
477
    long     sqlmtime;                  /* Latest modification time from sql2file(). */
478
    int      cmd_len;
479
    int	    read_mds = -1;		/* read_maildirsize() returned value */
480
    struct   stat mdffile_stat;         /* To check if the maildirfolder file exists. */
89
481
90
    GETTIMEOFDAY(&starttime);
482
    GETTIMEOFDAY(&starttime);
91
483
Lines 94-108 Link Here
94
     */
486
     */
95
    state.level++;
487
    state.level++;
96
    if (msg_verbose)
488
    if (msg_verbose)
97
	MSG_LOG_STATE(myname, state);
489
	    MSG_LOG_STATE(myname, state);
98
490
99
    /*
491
    /*
100
     * Don't deliver trace-only requests.
492
     * Don't deliver trace-only requests.
101
     */
493
     */
102
    if (DEL_REQ_TRACE_ONLY(state.request->flags)) {
494
    if (DEL_REQ_TRACE_ONLY(state.request->flags)) {
103
	dsb_simple(why, "2.0.0", "delivers to maildir");
495
        dsb_simple(why, "2.0.0", "delivers to maildir");
104
	return (sent(BOUNCE_FLAGS(state.request),
496
        return (sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr)));
105
		     SENT_ATTR(state.msg_attr)));
106
    }
497
    }
107
498
108
    /*
499
    /*
Lines 110-127 Link Here
110
     * attribute to reflect the final recipient.
501
     * attribute to reflect the final recipient.
111
     */
502
     */
112
    if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
503
    if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
113
	msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
504
        msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
114
    state.msg_attr.delivered = state.msg_attr.rcpt.address;
505
    state.msg_attr.delivered = state.msg_attr.rcpt.address;
115
    mail_copy_status = MAIL_COPY_STAT_WRITE;
506
    mail_copy_status = MAIL_COPY_STAT_WRITE;
116
    buf = vstring_alloc(100);
507
    buf = vstring_alloc(100);
117
508
118
    copy_flags = MAIL_COPY_TOFILE | MAIL_COPY_RETURN_PATH
509
    copy_flags = MAIL_COPY_TOFILE | MAIL_COPY_RETURN_PATH | MAIL_COPY_DELIVERED | MAIL_COPY_ORIG_RCPT;
119
	| MAIL_COPY_DELIVERED | MAIL_COPY_ORIG_RCPT;
120
510
121
    newdir = concatenate(usr_attr.mailbox, "new/", (char *) 0);
511
    /*
122
    tmpdir = concatenate(usr_attr.mailbox, "tmp/", (char *) 0);
512
     * Concatenate the maildir suffix (if set).
123
    curdir = concatenate(usr_attr.mailbox, "cur/", (char *) 0);
513
     */
514
    if (*var_virt_maildir_suffix == 0) {
515
        newdir = concatenate(usr_attr.mailbox, "new/", (char *) 0);
516
        tmpdir = concatenate(usr_attr.mailbox, "tmp/", (char *) 0);
517
        curdir = concatenate(usr_attr.mailbox, "cur/", (char *) 0);
518
    }
519
    else {
520
        newdir = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
521
        tmpdir = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
522
        curdir = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
523
        newdir = concatenate(newdir, "new/", (char *) 0);
524
        tmpdir = concatenate(tmpdir, "tmp/", (char *) 0);
525
        curdir = concatenate(curdir, "cur/", (char *) 0);
526
    }
124
527
528
    /* get the sizefilename, no matter if we use var_virt_maildir_extended */
529
    if (*var_virt_maildir_suffix == 0) {
530
        sizefilename = concatenate(usr_attr.mailbox, "maildirsize", (char *) 0);
531
    } else {
532
        sizefilename = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
533
        sizefilename = concatenate(sizefilename, "maildirsize", (char *) 0);
534
    }
535
    
536
    /*
537
     * Look up the virtual maildir limit size for this user.
538
     * Fall back to virtual_mailbox_limit in case lookup failed.
539
     * If virtual maildir limit size is negative, fall back to virtual_mailbox_limit.
540
     * If it's 0, set the mailbox limit to 0, which means unlimited.
541
     * If it's more than 0 (positive int), check if the value is smaller than the maximum message size,
542
     * if it is and the virtual maildir limit can't be overridden, fall back to virtual_mailbox_limit and
543
     * warn the user, else use the value directly as the maildir limit.
544
     */
545
    if (*var_virt_mailbox_limit_maps != 0 && (limit_res = mail_addr_find(virtual_mailbox_limit_maps, state.msg_attr.user, (char **) NULL)) != 0) {
546
        n = atol(limit_res);
547
        if (n > 0) {
548
            if ((n < var_message_limit) && (!var_virt_mailbox_limit_override)) {
549
                n = var_virt_mailbox_limit;
550
551
                msg_warn("%s: recipient %s - virtual maildir limit is smaller than %s in %s - falling back to %s",
552
                        myname, state.msg_attr.user, VAR_MESSAGE_LIMIT, virtual_mailbox_limit_maps->title,
553
                        VAR_VIRT_MAILBOX_LIMIT);
554
            }
555
            else {
556
                if (msg_verbose)
557
                    msg_info("%s: set virtual maildir limit size for %s to %ld",
558
                            myname, usr_attr.mailbox, n);
559
            }
560
        }
561
        else if (n == 0) {
562
                if (msg_verbose)
563
                    msg_info("%s: set virtual maildir limit size for %s to %ld",
564
                            myname, usr_attr.mailbox, n);
565
        }
566
        else {
567
	    if (msg_verbose)
568
		msg_info("%s: quota is negative (%ld), using default virtual_mailbox_limit (%ld)", 
569
			    myname, n, var_virt_mailbox_limit);
570
            /* Invalid limit size (negative). Use default virtual_mailbox_limit. */
571
            n = var_virt_mailbox_limit;
572
        }
573
    }
574
    else {
575
	if (msg_verbose)
576
	    msg_info("%s: no limit found in the maps, using default virtual_mailbox_limit (%ld)", 
577
			myname, var_virt_mailbox_limit);
578
        /* There is no limit in the maps. Use default virtual_mailbox_limit. */
579
        n = var_virt_mailbox_limit;
580
    }
581
582
    /* If there should is a quota on maildir generaly, check it before delivering the mail */
583
    if (n != 0) {
584
        set_eugid(usr_attr.uid, usr_attr.gid);
585
	/* try to read the quota from maildirsize file. Returned values by read_maildirsize:
586
	x < 0  = something failed
587
	x >= 0 = reading successfully finished - sum si returned, so sum size of Maildir was 0 or more */
588
        if (!var_virt_mailbox_limit_inbox && var_virt_maildir_extended && (read_mds = read_maildirsize(sizefilename, &saved_size, &saved_count)) >= 0) {
589
    	    if (msg_verbose)
590
        	msg_info("%s: maildirsize used=%s sum=%ld count=%ld", myname, sizefilename, saved_size, saved_count);
591
	} else {
592
	    if (msg_verbose) 
593
		msg_info("%s: We will recount the quota (var_virt_mailbox_limit = %ld, var_virt_maildir_extended = %d, read_maildirsize = %d)", 
594
			    myname, var_virt_mailbox_limit, var_virt_maildir_extended, read_mds);
595
596
	    /* sanity */
597
	    saved_size = 0; 
598
	    saved_count = 0;
599
	    
600
    	    if (var_virt_mailbox_limit_inbox) {
601
        	/* Check Inbox only (new, cur and tmp dirs). */
602
        	saved_size = check_dir_size(newdir, &saved_count);
603
        	saved_size += check_dir_size(curdir, &saved_count);
604
        	saved_size += check_dir_size(tmpdir, &saved_count);
605
    	    } else {
606
        	/* Check all boxes. */
607
        	saved_size = check_dir_size(usr_attr.mailbox, &saved_count);
608
    	    }
609
610
    	    set_eugid(var_owner_uid, var_owner_gid);
611
    	}    	
612
    }
613
    
125
    /*
614
    /*
126
     * Create and write the file as the recipient, so that file quota work.
615
     * Create and write the file as the recipient, so that file quota work.
127
     * Create any missing directories on the fly. The file name is chosen
616
     * Create any missing directories on the fly. The file name is chosen
Lines 175-220 Link Here
175
     * [...]
664
     * [...]
176
     */
665
     */
177
    set_eugid(usr_attr.uid, usr_attr.gid);
666
    set_eugid(usr_attr.uid, usr_attr.gid);
178
    vstring_sprintf(buf, "%lu.P%d.%s",
667
    vstring_sprintf(buf, "%lu.P%d.%s", (unsigned long) starttime.tv_sec, var_pid, get_hostname());
179
		 (unsigned long) starttime.tv_sec, var_pid, get_hostname());
180
    tmpfile = concatenate(tmpdir, STR(buf), (char *) 0);
668
    tmpfile = concatenate(tmpdir, STR(buf), (char *) 0);
181
    newfile = 0;
669
    newfile = 0;
670
    bkpnewfile = 0;
182
    if ((dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0
671
    if ((dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0
183
	&& (errno != ENOENT
672
        && (errno != ENOENT
184
	    || make_dirs(tmpdir, 0700) < 0
673
            || make_dirs(tmpdir, 0700) < 0
185
	    || (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
674
            || (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
186
	dsb_simple(why, mbox_dsn(errno, "4.2.0"),
675
        dsb_simple(why, mbox_dsn(errno, "4.2.0"), "create maildir file %s: %m", tmpfile);
187
		   "create maildir file %s: %m", tmpfile);
676
    }
188
    } else if (fstat(vstream_fileno(dst), &st) < 0) {
677
    else if (fstat(vstream_fileno(dst), &st) < 0) {
189
678
        /*
190
	/*
679
         * Coverity 200604: file descriptor leak in code that never executes.
191
	 * Coverity 200604: file descriptor leak in code that never executes.
680
         * Code replaced by msg_fatal(), as it is not worthwhile to continue
192
	 * Code replaced by msg_fatal(), as it is not worthwhile to continue
681
         * after an impossible error condition.
193
	 * after an impossible error condition.
682
         */
194
	 */
683
        msg_fatal("fstat %s: %m", tmpfile);
195
	msg_fatal("fstat %s: %m", tmpfile);
684
    }
196
    } else {
685
    else {
197
	vstring_sprintf(buf, "%lu.V%lxI%lxM%lu.%s",
686
        vstring_sprintf(buf, "%lu.V%lxI%lxM%lu.%s",
198
			(unsigned long) starttime.tv_sec,
687
                (unsigned long) starttime.tv_sec,
199
			(unsigned long) st.st_dev,
688
                (unsigned long) st.st_dev,
200
			(unsigned long) st.st_ino,
689
                (unsigned long) st.st_ino,
201
			(unsigned long) starttime.tv_usec,
690
                (unsigned long) starttime.tv_usec,
202
			get_hostname());
691
                get_hostname());
203
	newfile = concatenate(newdir, STR(buf), (char *) 0);
692
        newfile = concatenate(newdir, STR(buf), (char *) 0);
204
	if ((mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr),
693
        bkpnewfile = concatenate(STR(buf), (char *) 0); /* Will need it later, if we MOVE to other folders. */
205
					  dst, copy_flags, "\n",
694
206
					  why)) == 0) {
695
        if ((mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), dst, copy_flags, "\n", why)) == 0) {
207
	    if (sane_link(tmpfile, newfile) < 0
696
            /*
208
		&& (errno != ENOENT
697
             * Add a ",S=<sizeoffile>" to the newly written file according to the
209
		    || (make_dirs(curdir, 0700), make_dirs(newdir, 0700)) < 0
698
             * Maildir++ specifications: http://www.inter7.com/courierimap/README.maildirquota.html
210
		    || sane_link(tmpfile, newfile) < 0)) {
699
             * This needs a stat(2) of the tempfile and modification of the
211
		dsb_simple(why, mbox_dsn(errno, "4.2.0"),
700
             * name of the file.
212
			   "create maildir file %s: %m", newfile);
701
             */
213
		mail_copy_status = MAIL_COPY_STAT_WRITE;
702
            if (stat(tmpfile, &mail_stat) == 0) {
214
	    }
703
                if (n != 0) {
215
	}
704
                    saved_size += (long) mail_stat.st_size;
216
	if (unlink(tmpfile) < 0)
705
                    saved_count++;
217
	    msg_warn("remove %s: %m", tmpfile);
706
                }
707
                if (var_virt_maildir_extended) {
708
                    /* Append the size of the file to newfile. */
709
                    vstring_sprintf(buf, ",S=%ld", (long) mail_stat.st_size);
710
                    newfile = concatenate(newfile, STR(buf), (char *) 0);
711
                    bkpnewfile = concatenate(bkpnewfile, STR(buf), (char *) 0);
712
                }
713
            }
714
715
            /*
716
             * Now we have the maildir size in saved_size, compare it to the max
717
             * quota value and eventually issue a message that we've overdrawn it.
718
             */
719
            if (saved_size > n) {
720
                mail_copy_status = MAIL_COPY_STAT_WRITE;
721
                if (((long) mail_stat.st_size > n) || (var_virt_overquota_bounce))
722
                    errno = EFBIG;
723
                else
724
                    errno = EDQUOT;
725
            }
726
            else {
727
                /* Maildirfilter code by rk@demiurg.net. */
728
                if (var_virt_maildir_filter) {
729
                    if (msg_verbose)
730
                        msg_info("%s: loading DICT filters", myname);
731
732
#define STREQUAL(x,y,l) (strncasecmp((x), (y), (l)) == 0 && (y)[l] == 0)
733
#define MAIL_COPY_STAT_REJECT  (1<<3)
734
#define MAIL_COPY_STAT_DISCARD (1<<4)
735
736
                    /* Read filters. */
737
                    filtername = concatenate("regexp:", usr_attr.mailbox, "maildirfilter", (char *) 0);
738
                    sqlmtime = sql2file(strchr(filtername, '/'), state.msg_attr.user);
739
740
                    /* Check if this filter is already registered as dictionary. */
741
                    if (msg_verbose)
742
                        msg_info("%s: checking DICT filters for %s", myname, filtername);
743
744
                    if ((FILTERS = dict_handle(filtername))) {
745
                        if (msg_verbose)
746
                            msg_info("%s: DICT filter found", myname);
747
748
                        /*
749
                         * If we have mtime in our DICT structure, check it against sqlmtime
750
                         * and reload the filters if they differ.
751
                         */
752
                        if (FILTERS->mtime > 0 && sqlmtime > 0 && FILTERS->mtime != sqlmtime) {
753
                            if (msg_verbose)
754
                                msg_info("%s: reloading DICT filters (dict_mtime=%ld != sql_mtime=%ld)",
755
                                        myname, FILTERS->mtime, sqlmtime);
756
757
                            dict_unregister(filtername);
758
                            FILTERS = dict_open(filtername, O_RDONLY, DICT_FLAG_LOCK);
759
                            dict_register(filtername, FILTERS);
760
                            FILTERS->mtime = sqlmtime;
761
                        }
762
                    }
763
                    else {
764
                        if (sqlmtime > 0) {
765
                            /* Registering filter as new dictionary. */
766
                            if (msg_verbose)
767
                                msg_info("%s: loading DICT filters from %s (mtime=%ld)",
768
                                        myname, filtername, sqlmtime);
769
770
                            FILTERS = dict_open(filtername, O_RDONLY, DICT_FLAG_LOCK);
771
                            dict_register(filtername, FILTERS);
772
                            FILTERS->mtime = sqlmtime;
773
                        }
774
                    }
775
776
                    if (FILTERS && (tmpfilter = vstream_fopen(tmpfile, O_RDONLY, 0))) {
777
                        fltstr = vstring_alloc(1024);
778
                        header = (char *) malloc(8192); /* !!!INSECURE!!! See 7168-hack below. */
779
                        header[0] = 0;
780
                        vstring_get_nonl_bound(fltstr, tmpfilter, 1023);
781
                        header = concatenate(header, STR(fltstr), (char *) 0);
782
783
                        while(!vstream_feof(tmpfilter) && fltstr->vbuf.data[0] && strlen(header) < 7168 ) {
784
                            vstring_get_nonl_bound(fltstr, tmpfilter, 1023);
785
                            /* Glue multiline headers, replacing leading TAB with space. */
786
                            if (msg_verbose)
787
                                msg_info("%s: fltstr value: %s", myname, STR(fltstr));
788
789
                            if (fltstr->vbuf.data[0] == ' ' || fltstr->vbuf.data[0] == '\t' ) {
790
                                if (fltstr->vbuf.data[0] == '\t')
791
                                    fltstr->vbuf.data[0] = ' ';
792
                                header = concatenate(header, STR(fltstr), (char *) 0);
793
                            }
794
                            else {
795
                                header = concatenate(header, "\n", STR(fltstr), (char *) 0);
796
                            }
797
                        }
798
799
                        if (msg_verbose)
800
                            msg_info("%s: checking filter CMD for %s", myname, filtername);
801
802
                        /* Check whole header part with regexp maps. */
803
                        if ((value = dict_get(FILTERS, lowercase(header))) != 0) {
804
                            if (msg_verbose)
805
                                msg_info("%s: preparing filter CMD", myname);
806
807
                            cmd_text = value + strcspn(value, " \t");
808
                            cmd_len = cmd_text - value;
809
                            while (*cmd_text && ISSPACE(*cmd_text))
810
                                cmd_text++;
811
812
                            if (msg_verbose)
813
                                msg_info("%s: executing filter CMD", myname);
814
815
                            if (STREQUAL(value, "REJECT", cmd_len)) {
816
                                if (msg_verbose)
817
                                    msg_info("%s: executing filter CMD REJECT", myname);
818
819
                                mail_copy_status = MAIL_COPY_STAT_REJECT;
820
                                vstring_sprintf(why->reason, "%s", cmd_text);
821
                                dsb_simple(why, "5.0.0", "User filter - REJECT");
822
                            }
823
824
                            if (STREQUAL(value, "DISCARD", cmd_len)) {
825
                                if (msg_verbose)
826
                                    msg_info("%s: executing filter CMD DISCARD", myname);
827
828
                                mail_copy_status = MAIL_COPY_STAT_DISCARD;
829
                                vstring_sprintf(why->reason, "%s", cmd_text);
830
                                dsb_simple(why, "5.0.0", "User filter - DISCARD");
831
                            }
832
833
                            if (var_virt_maildir_extended) {
834
                                if (STREQUAL(value, "MOVE", cmd_len)) {
835
                                    if (msg_verbose)
836
                                        msg_info("%s: executing filter CMD MOVE", myname);
837
838
                                    strcut((char *) cmd_text, " ");
839
                                    strcut((char *) cmd_text, "\t");
840
                                    strcut((char *) cmd_text, "/");
841
                                    strcut((char *) cmd_text, "..");
842
843
                                    if (*var_virt_maildir_suffix == 0) {
844
                                        newfile = concatenate(usr_attr.mailbox, (char *) 0);
845
                                    }
846
                                    else {
847
                                        newfile = concatenate(usr_attr.mailbox, var_virt_maildir_suffix, (char *) 0);
848
                                    }
849
850
                                    if (cmd_text[0] != '.') {
851
                                        newfile = concatenate(newfile, ".", (char *) 0);
852
                                    }
853
                                    newdir  = concatenate(newfile, cmd_text, "/", "new/", (char *) 0);
854
                                    tmpdir  = concatenate(newfile, cmd_text, "/", "tmp/", (char *) 0);
855
                                    curdir  = concatenate(newfile, cmd_text, "/", "cur/", (char *) 0);
856
                                    mdffilename = concatenate(newfile, cmd_text, "/", "maildirfolder", (char *) 0);
857
                                    newfile = concatenate(newfile, cmd_text, "/", "new/", bkpnewfile, (char *) 0);
858
                                }
859
                            }
860
861
                            if (STREQUAL(value, "LOG", cmd_len) || STREQUAL(value, "WARN", cmd_len)) {
862
                                msg_warn("%s: header check warning: %s", myname, cmd_text);
863
                            }
864
865
                            if (STREQUAL(value, "INFO", cmd_len)) {
866
                                msg_info("%s: header check info: %s", myname, cmd_text);
867
                            }
868
869
                            if (msg_verbose)
870
                                msg_info("%s: exiting filter CMD", myname);
871
                        } /* End-Of-Check */
872
873
                        myfree(header);
874
                        vstring_free(fltstr);
875
                        vstream_fclose(tmpfilter);
876
                    }
877
878
                    myfree(filtername);
879
                } /* End-Of-Maildirfilter */
880
881
                /* Deliver to curdir. */
882
                if (mail_copy_status == 0) {
883
                    if (sane_link(tmpfile, newfile) < 0
884
                        && (errno != ENOENT
885
                            || (make_dirs(curdir, 0700), make_dirs(newdir, 0700), make_dirs(tmpdir, 0700)) < 0
886
                            || sane_link(tmpfile, newfile) < 0)) {
887
                        dsb_simple(why, mbox_dsn(errno, "4.2.0"), "create maildir file %s: %m", newfile);
888
                        mail_copy_status = MAIL_COPY_STAT_WRITE;
889
                    }
890
891
                    if (var_virt_maildir_extended) {
892
                        time(&tm);
893
894
                        /* Check if the quota in the file is the same as the current one, if not, delete the file. */
895
                        sizefile = vstream_fopen(sizefilename, O_RDONLY, 0);
896
                        if (sizefile) {
897
                            filequota = vstring_alloc(128);
898
                            vstring_get_null_bound(filequota, sizefile, 127);
899
                            vstream_fclose(sizefile);
900
                            if (atol(vstring_export(filequota)) != n)
901
                                unlink(sizefilename);
902
                        }
903
904
                        /* Open maildirsize file to append this transaction. */
905
                        sizefile = vstream_fopen(sizefilename, O_WRONLY | O_APPEND, 0640);
906
907
                        /* If the open fails (maildirsize doesn't exist), or it's too large, or too old, overwrite it. */
908
                        if(!sizefile || (stat(sizefilename, &sizefile_stat) < 0) || (sizefile_stat.st_size > SIZEFILE_MAX) || (sizefile_stat.st_mtime + 15*60 < tm)) {
909
                            /* If the file exists, sizefile has been opened above, so close it first. */
910
                            if (sizefile) {
911
                                vstream_fclose(sizefile);
912
                                sizefile = vstream_fopen(sizefilename, O_WRONLY | O_TRUNC, 0640);
913
                            }
914
                            else {
915
                                sizefile = vstream_fopen(sizefilename, O_WRONLY | O_CREAT, 0640);
916
                            }
917
918
                            /* If the creation worked, write to the file, otherwise just give up. */
919
                            if (sizefile) {
920
                                vstream_fprintf(sizefile, "%ldS\n%ld %ld\n", n, saved_size, saved_count);
921
                                vstream_fclose(sizefile);
922
                            }
923
                        }
924
                        else {
925
                            /* We opened maildirsize, so let's just append this transaction and close it. */
926
                            vstream_fprintf(sizefile, "%ld 1\n", (long) mail_stat.st_size);
927
                            vstream_fclose(sizefile);
928
                        }
929
930
                        /*
931
                         * 1) mdffilename != 0, so the maildirfilter code went through the MOVE to subfolder rule.
932
                         * 2) stat() failed, maybe the file does not exist? Try to create it.
933
                         */
934
                        if (mdffilename && (stat(mdffilename, &mdffile_stat) < 0)) {
935
                            mdffile = vstream_fopen(mdffilename, O_WRONLY | O_CREAT, 0600);
936
                            if (mdffile) {
937
                                vstream_fclose(mdffile);
938
                            }
939
                            else {
940
                                msg_warn("Cannot create maildirfolder file '%s': %s", mdffilename, strerror(errno));
941
                            }
942
                        }
943
                    }
944
                }
945
            }
946
        }
947
        if (unlink(tmpfile) < 0)
948
            msg_warn("remove %s: %m", tmpfile);
218
    }
949
    }
219
    set_eugid(var_owner_uid, var_owner_gid);
950
    set_eugid(var_owner_uid, var_owner_gid);
220
951
Lines 224-254 Link Here
224
     * location possibly under user control.
955
     * location possibly under user control.
225
     */
956
     */
226
    if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
957
    if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
227
	deliver_status = DEL_STAT_DEFER;
958
        deliver_status = DEL_STAT_DEFER;
228
    } else if (mail_copy_status != 0) {
959
    }
229
	if (errno == EACCES) {
960
    else if (mail_copy_status != 0) {
230
	    msg_warn("maildir access problem for UID/GID=%lu/%lu: %s",
961
        if (errno == EACCES) {
231
		     (long) usr_attr.uid, (long) usr_attr.gid,
962
            msg_warn("maildir access problem for UID/GID=%lu/%lu: %s",
232
		     STR(why->reason));
963
                    (long) usr_attr.uid, (long) usr_attr.gid, STR(why->reason));
233
	    msg_warn("perhaps you need to create the maildirs in advance");
964
            msg_warn("perhaps you need to create the maildirs in advance");
234
	}
965
        }
235
	vstring_sprintf_prepend(why->reason, "maildir delivery failed: ");
966
236
	deliver_status =
967
        /* Support per-recipient bounce messages. */
237
	    (STR(why->status)[0] == '4' ?
968
        const char *limit_message;
238
	     defer_append : bounce_append)
969
        int errnored = errno; /* Seems like mail_addr_find resets errno ... */
239
	    (BOUNCE_FLAGS(state.request),
970
240
	     BOUNCE_ATTR(state.msg_attr));
971
        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) {
241
    } else {
972
            errno = errnored;
242
	dsb_simple(why, "2.0.0", "delivered to maildir");
973
            if (errno == EFBIG) {
243
	deliver_status = sent(BOUNCE_FLAGS(state.request),
974
                dsb_simple(why, "5.2.2", limit_message, NULL);
244
			      SENT_ATTR(state.msg_attr));
975
            }
976
            if (errno == EDQUOT) {
977
                dsb_simple(why, "4.2.2", limit_message, NULL);
978
            }
979
        }
980
        else {
981
            errno = errnored;
982
            if (errno == EFBIG) {
983
                dsb_simple(why, "5.2.2", var_virt_maildir_limit_message, NULL);
984
            }
985
            if (errno == EDQUOT) {
986
                dsb_simple(why, "4.2.2", var_virt_maildir_limit_message, NULL);
987
            }
988
        }
989
990
        vstring_sprintf_prepend(why->reason, "maildir delivery failed: ");
991
        deliver_status =
992
                (STR(why->status)[0] == '4' ? defer_append : bounce_append)
993
                (BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr));
245
    }
994
    }
995
    else {
996
        dsb_simple(why, "2.0.0", "delivered to maildir");
997
        deliver_status = sent(BOUNCE_FLAGS(state.request), SENT_ATTR(state.msg_attr));
998
    }
999
246
    vstring_free(buf);
1000
    vstring_free(buf);
1001
247
    myfree(newdir);
1002
    myfree(newdir);
248
    myfree(tmpdir);
1003
    myfree(tmpdir);
249
    myfree(curdir);
1004
    myfree(curdir);
1005
1006
    if (sizefilename)
1007
        myfree(sizefilename);
1008
    if (mdffilename)
1009
        myfree(mdffilename);
1010
250
    myfree(tmpfile);
1011
    myfree(tmpfile);
251
    if (newfile)
1012
    if (newfile)
252
	myfree(newfile);
1013
        myfree(newfile);
1014
    if (bkpnewfile)
1015
        myfree(bkpnewfile);
1016
253
    return (deliver_status);
1017
    return (deliver_status);
254
}
1018
}
(-)postfix-3.0.3.orig/src/virtual/virtual.c (-6 / +44 lines)
Lines 341-346 Link Here
341
char   *var_mail_spool_dir;		/* XXX dependency fix */
341
char   *var_mail_spool_dir;		/* XXX dependency fix */
342
bool    var_strict_mbox_owner;
342
bool    var_strict_mbox_owner;
343
char   *var_virt_dsn_filter;
343
char   *var_virt_dsn_filter;
344
 
345
char   *var_virt_mailbox_limit_maps;
346
bool    var_virt_mailbox_limit_inbox;
347
bool    var_virt_mailbox_limit_override;
348
bool    var_virt_maildir_extended;
349
bool    var_virt_overquota_bounce;
350
char   *var_virt_maildir_limit_message;
351
char   *var_virt_maildir_limit_message_maps;
352
char   *var_virt_maildir_suffix;
353
bool    var_virt_trash_count;
354
char   *var_virt_trash_name;
355
bool    var_virt_maildir_filter;
356
char   *var_virt_maildir_filter_maps;
344
357
345
 /*
358
 /*
346
  * Mappings.
359
  * Mappings.
Lines 348-353 Link Here
348
MAPS   *virtual_mailbox_maps;
361
MAPS   *virtual_mailbox_maps;
349
MAPS   *virtual_uid_maps;
362
MAPS   *virtual_uid_maps;
350
MAPS   *virtual_gid_maps;
363
MAPS   *virtual_gid_maps;
364
MAPS   *virtual_mailbox_limit_maps;
365
MAPS   *virtual_maildir_limit_message_maps;
366
MAPS   *virtual_maildir_filter_maps;
351
367
352
 /*
368
 /*
353
  * Bit masks.
369
  * Bit masks.
Lines 457-474 Link Here
457
     */
473
     */
458
    virtual_mailbox_maps =
474
    virtual_mailbox_maps =
459
	maps_create(VAR_VIRT_MAILBOX_MAPS, var_virt_mailbox_maps,
475
	maps_create(VAR_VIRT_MAILBOX_MAPS, var_virt_mailbox_maps,
460
		    DICT_FLAG_LOCK | DICT_FLAG_PARANOID
476
		    DICT_FLAG_LOCK);
461
		    | DICT_FLAG_UTF8_REQUEST);
462
477
463
    virtual_uid_maps =
478
    virtual_uid_maps =
464
	maps_create(VAR_VIRT_UID_MAPS, var_virt_uid_maps,
479
	maps_create(VAR_VIRT_UID_MAPS, var_virt_uid_maps,
465
		    DICT_FLAG_LOCK | DICT_FLAG_PARANOID
480
		    DICT_FLAG_LOCK);
466
		    | DICT_FLAG_UTF8_REQUEST);
467
481
468
    virtual_gid_maps =
482
    virtual_gid_maps =
469
	maps_create(VAR_VIRT_GID_MAPS, var_virt_gid_maps,
483
	maps_create(VAR_VIRT_GID_MAPS, var_virt_gid_maps,
470
		    DICT_FLAG_LOCK | DICT_FLAG_PARANOID
484
		    DICT_FLAG_LOCK);
471
		    | DICT_FLAG_UTF8_REQUEST);
485
486
    virtual_mailbox_limit_maps =
487
        maps_create(VAR_VIRT_MAILBOX_LIMIT_MAPS, var_virt_mailbox_limit_maps,
488
                    DICT_FLAG_LOCK);
489
490
    virtual_maildir_limit_message_maps =
491
        maps_create(VAR_VIRT_MAILDIR_LIMIT_MESSAGE_MAPS, var_virt_maildir_limit_message_maps,
492
                    DICT_FLAG_LOCK);
493
494
    virtual_maildir_filter_maps =
495
        maps_create(VAR_VIRT_MAILDIR_FILTER_MAPS, var_virt_maildir_filter_maps,
496
                    DICT_FLAG_LOCK);
472
497
473
    virtual_mbox_lock_mask = mbox_lock_mask(var_virt_mailbox_lock);
498
    virtual_mbox_lock_mask = mbox_lock_mask(var_virt_mailbox_lock);
474
}
499
}
Lines 520-530 Link Here
520
	VAR_VIRT_GID_MAPS, DEF_VIRT_GID_MAPS, &var_virt_gid_maps, 0, 0,
545
	VAR_VIRT_GID_MAPS, DEF_VIRT_GID_MAPS, &var_virt_gid_maps, 0, 0,
521
	VAR_VIRT_MAILBOX_BASE, DEF_VIRT_MAILBOX_BASE, &var_virt_mailbox_base, 1, 0,
546
	VAR_VIRT_MAILBOX_BASE, DEF_VIRT_MAILBOX_BASE, &var_virt_mailbox_base, 1, 0,
522
	VAR_VIRT_MAILBOX_LOCK, DEF_VIRT_MAILBOX_LOCK, &var_virt_mailbox_lock, 1, 0,
547
	VAR_VIRT_MAILBOX_LOCK, DEF_VIRT_MAILBOX_LOCK, &var_virt_mailbox_lock, 1, 0,
548
	VAR_VIRT_MAILBOX_LIMIT_MAPS, DEF_VIRT_MAILBOX_LIMIT_MAPS, &var_virt_mailbox_limit_maps, 0, 0,
549
	VAR_VIRT_MAILDIR_LIMIT_MESSAGE, DEF_VIRT_MAILDIR_LIMIT_MESSAGE, &var_virt_maildir_limit_message, 1, 0,
550
	VAR_VIRT_MAILDIR_LIMIT_MESSAGE_MAPS, DEF_VIRT_MAILDIR_LIMIT_MESSAGE_MAPS, &var_virt_maildir_limit_message_maps, 0, 0,
551
	VAR_VIRT_MAILDIR_SUFFIX, DEF_VIRT_MAILDIR_SUFFIX, &var_virt_maildir_suffix, 0, 0,
552
	VAR_VIRT_TRASH_NAME, DEF_VIRT_TRASH_NAME, &var_virt_trash_name, 0, 0,
553
	VAR_VIRT_MAILDIR_FILTER_MAPS, DEF_VIRT_MAILDIR_FILTER_MAPS, &var_virt_maildir_filter_maps, 0, 0,
523
	VAR_VIRT_DSN_FILTER, DEF_VIRT_DSN_FILTER, &var_virt_dsn_filter, 0, 0,
554
	VAR_VIRT_DSN_FILTER, DEF_VIRT_DSN_FILTER, &var_virt_dsn_filter, 0, 0,
524
	0,
555
	0,
525
    };
556
    };
526
    static const CONFIG_BOOL_TABLE bool_table[] = {
557
    static const CONFIG_BOOL_TABLE bool_table[] = {
527
	VAR_STRICT_MBOX_OWNER, DEF_STRICT_MBOX_OWNER, &var_strict_mbox_owner,
558
	VAR_STRICT_MBOX_OWNER, DEF_STRICT_MBOX_OWNER, &var_strict_mbox_owner,
559
	VAR_VIRT_MAILBOX_LIMIT_INBOX, DEF_VIRT_MAILBOX_LIMIT_INBOX, &var_virt_mailbox_limit_inbox,
560
	VAR_VIRT_MAILBOX_LIMIT_OVERRIDE, DEF_VIRT_MAILBOX_LIMIT_OVERRIDE, &var_virt_mailbox_limit_override,
561
	VAR_VIRT_MAILDIR_EXTENDED, DEF_VIRT_MAILDIR_EXTENDED, &var_virt_maildir_extended,
562
	VAR_VIRT_OVERQUOTA_BOUNCE, DEF_VIRT_OVERQUOTA_BOUNCE, &var_virt_overquota_bounce,
563
	VAR_VIRT_TRASH_COUNT, DEF_VIRT_TRASH_COUNT, &var_virt_trash_count,
564
	VAR_VIRT_MAILDIR_FILTER, DEF_VIRT_MAILDIR_FILTER, &var_virt_maildir_filter,
528
	0,
565
	0,
529
    };
566
    };
530
567
Lines 541-546 Link Here
541
		       CA_MAIL_SERVER_PRE_INIT(pre_init),
578
		       CA_MAIL_SERVER_PRE_INIT(pre_init),
542
		       CA_MAIL_SERVER_POST_INIT(post_init),
579
		       CA_MAIL_SERVER_POST_INIT(post_init),
543
		       CA_MAIL_SERVER_PRE_ACCEPT(pre_accept),
580
		       CA_MAIL_SERVER_PRE_ACCEPT(pre_accept),
581
		       CA_MAIL_SERVER_BOOL_TABLE(bool_table),
544
		       CA_MAIL_SERVER_PRIVILEGED,
582
		       CA_MAIL_SERVER_PRIVILEGED,
545
		       CA_MAIL_SERVER_BOUNCE_INIT(VAR_VIRT_DSN_FILTER,
583
		       CA_MAIL_SERVER_BOUNCE_INIT(VAR_VIRT_DSN_FILTER,
546
						  &var_virt_dsn_filter),
584
						  &var_virt_dsn_filter),
(-)postfix-3.0.3.orig/src/virtual/virtual.h (+3 lines)
Lines 34-39 Link Here
34
extern MAPS *virtual_mailbox_maps;
34
extern MAPS *virtual_mailbox_maps;
35
extern MAPS *virtual_uid_maps;
35
extern MAPS *virtual_uid_maps;
36
extern MAPS *virtual_gid_maps;
36
extern MAPS *virtual_gid_maps;
37
extern MAPS *virtual_mailbox_limit_maps;
38
extern MAPS *virtual_maildir_limit_message_maps;
39
extern MAPS *virtual_maildir_filter_maps;
37
40
38
 /*
41
 /*
39
  * User attributes: these control the privileges for delivery to external
42
  * User attributes: these control the privileges for delivery to external

Return to bug 606494