~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to src/plugins/virtual/virtual-config.c

  • Committer: Bazaar Package Importer
  • Author(s): CHuck Short, Chuck Short
  • Date: 2009-11-06 00:47:29 UTC
  • mfrom: (4.1.9 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091106004729-i39n7v9e7d4h51f6
Tags: 1:1.2.6-1ubuntu1
* Merge from debian testing, remaining changes:
  Add new binary pkg dovecot-postfix that integrates postfix and dovecot
  automatically: (LP: #164837)
  + debian/control:
    - add new binary with short description
    - set Architecture all for dovecot-postfix (LP: #329878)
  + debian/dovecot-postfix.postinst:
    - create initial certificate symlinks to snakeoil.
    - set up postfix with postconf to:
      - use Maildir/ as the default mailbox.
      - use dovecot as the sasl authentication server.
      - use dovecot LDA (deliver).
      - use tls for smtp{d} services.
    - fix certificates paths in postfix' main.cf
    - add reject_unauth_destination to postfix' recipient restrictions
    - add reject_unknown_sender_domain to postfix' sender restrictions
    - rename configuration name on remove, delete on purge
    - restart dovecot after linking certificates
    - handle use case when postfix is unconfigurated
   + debian/dovecot-postfix.dirs: create backup directory for postfix's configuration
   + restart postfix and dovecot.
   + debian/dovecot-postfix.postrm:
     - remove all dovecot related configuration from postfix.
     - restart postfix and dovecot.
   + debian/dovecot-common.init:
     - check if /etc/dovecot/dovecot-postfix.conf exists and use it
       as the configuration file if so.
   + debian/patches/warning-ubuntu-postfix.dpatch
     - add warning about dovecot-postfix.conf in dovecot default 
       configuration file
   + debian/patches/dovecot-postfix.conf.diff:
     - Ubuntu server custom changes to the default dovecot configuration for
       better interfation with postfix
     - enable sieve plugin
   + debian/patches/dovecot-postfix.conf.diff:
     + Ubuntu server custom changes to the default dovecot configuration for
       better integration with postfix:
       - enable imap, pop3, imaps, pop3s and managesieve by default.
       - enable dovecot LDA (deliver).
       - enable SASL auth socket in postfix private directory.
   + debian/rules:
     - copy, patch and install dovecot-postfix.conf in /etc/dovecot/.
     - build architecure independent packages too
   + Use Snakeoil SSL certificates by default.
     - debian/control: Depend on ssl-cert.
     - debian/patches/ssl-cert-snakeoil.dpatch: Change default SSL cert
       paths to snakeoil.
     - debian/dovecot-common.postinst: Relax grep for SSL_* a bit.
   + Add autopkgtest to debian/tests/*.
   + Fast TearDown: Update the lsb init header to not stop in level 6.
   + Add ufw integration:
     - Created debian/dovecot-common.ufw.profile.
     - debian/rules:
       + install profile
     - debian/control:
       + Suggest ufw
   + debian/{control,rules}: enable PIE hardening.
   + dovecot-imapd, dovecot-pop3: Replaces dovecot-common (<< 1:1.1). LP: #254721
   + debian/control:
     - Update Vcs-* headers.
   + debian/rules:
     - Create emtpy stamp.h.in files in dovecot-sieve/ and dovecot-managesieve/
       if they're not there since empty files are not included in the diff.gz 
       file.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
   + Dropped:
     - debian/patches/security-CVE-2009-3235: Applied upstream.
     - debian/patches/fix-pop3-assertion.dpatch: Applied upstream.
     - dovecot-sieve and dovecot-managesieve: Use the debian patches instead.

  [Chuck Short]
  - Updated dovecot-sieve to 0.1.13.
  - Updated dovecot-managesieve to 0.11.9.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2008-2009 Dovecot authors, see the included COPYING file */
 
2
 
 
3
#include "lib.h"
 
4
#include "array.h"
 
5
#include "crc32.h"
 
6
#include "istream.h"
 
7
#include "str.h"
 
8
#include "imap-parser.h"
 
9
#include "imap-match.h"
 
10
#include "mail-search-build.h"
 
11
#include "virtual-storage.h"
 
12
#include "virtual-plugin.h"
 
13
 
 
14
#include <unistd.h>
 
15
#include <fcntl.h>
 
16
 
 
17
struct virtual_parse_context {
 
18
        struct virtual_mailbox *mbox;
 
19
        struct istream *input;
 
20
 
 
21
        pool_t pool;
 
22
        string_t *rule;
 
23
        unsigned int rule_idx;
 
24
 
 
25
        char sep;
 
26
        bool have_wildcards;
 
27
};
 
28
 
 
29
static struct mail_search_args *
 
30
virtual_search_args_parse(const string_t *rule, const char **error_r)
 
31
{
 
32
        struct istream *input;
 
33
        struct imap_parser *parser;
 
34
        const struct imap_arg *args;
 
35
        struct mail_search_args *sargs;
 
36
        bool fatal;
 
37
        int ret;
 
38
 
 
39
        if (str_len(rule) == 0) {
 
40
                sargs = mail_search_build_init();
 
41
                mail_search_build_add_all(sargs);
 
42
                return sargs;
 
43
        }
 
44
 
 
45
        input = i_stream_create_from_data(str_data(rule), str_len(rule));
 
46
        (void)i_stream_read(input);
 
47
 
 
48
        parser = imap_parser_create(input, NULL, (size_t)-1);
 
49
        ret = imap_parser_finish_line(parser, 0,  0, &args);
 
50
        if (ret < 0) {
 
51
                sargs = NULL;
 
52
                *error_r = t_strdup(imap_parser_get_error(parser, &fatal));
 
53
        } else if (mail_search_build_from_imap_args(args, "UTF-8", &sargs,
 
54
                                                    error_r) < 0)
 
55
                sargs = NULL;
 
56
 
 
57
        imap_parser_destroy(&parser);
 
58
        i_stream_destroy(&input);
 
59
        return sargs;
 
60
}
 
61
 
 
62
static int
 
63
virtual_config_add_rule(struct virtual_parse_context *ctx, const char **error_r)
 
64
{
 
65
        struct virtual_backend_box *const *bboxes;
 
66
        struct mail_search_args *search_args;
 
67
        unsigned int i, count;
 
68
 
 
69
        if (ctx->rule_idx == array_count(&ctx->mbox->backend_boxes)) {
 
70
                i_assert(str_len(ctx->rule) == 0);
 
71
                return 0;
 
72
        }
 
73
 
 
74
        ctx->mbox->search_args_crc32 =
 
75
                crc32_str_more(ctx->mbox->search_args_crc32, str_c(ctx->rule));
 
76
        search_args = virtual_search_args_parse(ctx->rule, error_r);
 
77
        str_truncate(ctx->rule, 0);
 
78
        if (search_args == NULL) {
 
79
                *error_r = t_strconcat("Previous search rule is invalid: ",
 
80
                                       *error_r, NULL);
 
81
                return -1;
 
82
        }
 
83
 
 
84
        /* update at all the mailboxes that were introduced since the previous
 
85
           rule. */
 
86
        bboxes = array_get(&ctx->mbox->backend_boxes, &count);
 
87
        i_assert(ctx->rule_idx < count);
 
88
        for (i = ctx->rule_idx; i < count; i++) {
 
89
                i_assert(bboxes[i]->search_args == NULL);
 
90
                mail_search_args_ref(search_args);
 
91
                bboxes[i]->search_args = search_args;
 
92
        }
 
93
        mail_search_args_unref(&search_args);
 
94
 
 
95
        ctx->rule_idx = array_count(&ctx->mbox->backend_boxes);
 
96
        return 0;
 
97
}
 
98
 
 
99
static int
 
100
virtual_config_parse_line(struct virtual_parse_context *ctx, const char *line,
 
101
                          const char **error_r)
 
102
{
 
103
        struct mail_user *user = ctx->mbox->storage->storage.ns->user;
 
104
        struct virtual_backend_box *bbox;
 
105
        const char *name;
 
106
 
 
107
        if (*line == ' ' || *line == '\t') {
 
108
                /* continues the previous search rule */
 
109
                if (ctx->rule_idx == array_count(&ctx->mbox->backend_boxes)) {
 
110
                        *error_r = "Search rule without a mailbox";
 
111
                        return -1;
 
112
                }
 
113
                str_append(ctx->rule, line);
 
114
                return 0;
 
115
        }
 
116
        /* if there is no rule yet, it means we want the previous mailboxes
 
117
           to use the rule that comes later */
 
118
        if (str_len(ctx->rule) > 0) {
 
119
                if (virtual_config_add_rule(ctx, error_r) < 0)
 
120
                        return -1;
 
121
        }
 
122
 
 
123
        /* new mailbox. the search args are added to it later. */
 
124
        bbox = p_new(ctx->pool, struct virtual_backend_box, 1);
 
125
        if (strcasecmp(line, "INBOX") == 0)
 
126
                line = "INBOX";
 
127
        bbox->name = p_strdup(ctx->pool, line);
 
128
        if (*line == '-') line++;
 
129
        bbox->ns = strcasecmp(line, "!INBOX") != 0 ?
 
130
                mail_namespace_find(user->namespaces, &line) :
 
131
                mail_namespace_find_inbox(user->namespaces);
 
132
        if (bbox->ns == NULL) {
 
133
                *error_r = t_strdup_printf("Namespace not found for %s",
 
134
                                           bbox->name);
 
135
                return -1;
 
136
        }
 
137
        if (strchr(bbox->name, '*') != NULL ||
 
138
            strchr(bbox->name, '%') != NULL) {
 
139
                name = bbox->name[0] == '-' ? bbox->name + 1 : bbox->name;
 
140
                bbox->glob = imap_match_init(ctx->pool, name, TRUE, ctx->sep);
 
141
                ctx->have_wildcards = TRUE;
 
142
        } else if (bbox->name[0] == '!') {
 
143
                /* save messages here */
 
144
                if (ctx->mbox->save_bbox != NULL) {
 
145
                        *error_r = "Multiple save mailboxes defined";
 
146
                        return -1;
 
147
                }
 
148
                bbox->name++;
 
149
                ctx->mbox->save_bbox = bbox;
 
150
        }
 
151
        array_append(&ctx->mbox->backend_boxes, &bbox, 1);
 
152
        return 0;
 
153
}
 
154
 
 
155
static void
 
156
virtual_mailbox_get_list_patterns(struct virtual_parse_context *ctx)
 
157
{
 
158
        struct virtual_mailbox *mbox = ctx->mbox;
 
159
        ARRAY_TYPE(mailbox_virtual_patterns) *dest;
 
160
        struct mailbox_virtual_pattern pattern;
 
161
        struct virtual_backend_box *const *bboxes;
 
162
        unsigned int i, count;
 
163
 
 
164
        memset(&pattern, 0, sizeof(pattern));
 
165
        bboxes = array_get_modifiable(&mbox->backend_boxes, &count);
 
166
        p_array_init(&mbox->list_include_patterns, ctx->pool, count);
 
167
        p_array_init(&mbox->list_exclude_patterns, ctx->pool, count);
 
168
        for (i = 0; i < count; i++) {
 
169
                pattern.ns = bboxes[i]->ns;
 
170
                pattern.pattern = bboxes[i]->name;
 
171
                if (*pattern.pattern != '-')
 
172
                        dest = &mbox->list_include_patterns;
 
173
                else {
 
174
                        dest = &mbox->list_exclude_patterns;
 
175
                        pattern.pattern++;
 
176
                }
 
177
                array_append(dest, &pattern, 1);
 
178
        }
 
179
}
 
180
 
 
181
static void
 
182
separate_wildcard_mailboxes(struct virtual_mailbox *mbox,
 
183
                            ARRAY_TYPE(virtual_backend_box) *wildcard_boxes,
 
184
                            ARRAY_TYPE(virtual_backend_box) *neg_boxes)
 
185
{
 
186
        struct virtual_backend_box *const *bboxes;
 
187
        ARRAY_TYPE(virtual_backend_box) *dest;
 
188
        unsigned int i, count;
 
189
 
 
190
        bboxes = array_get_modifiable(&mbox->backend_boxes, &count);
 
191
        t_array_init(wildcard_boxes, I_MIN(16, count));
 
192
        t_array_init(neg_boxes, 4);
 
193
        for (i = 0; i < count;) {
 
194
                if (*bboxes[i]->name == '-')
 
195
                        dest = neg_boxes;
 
196
                else if (bboxes[i]->glob != NULL)
 
197
                        dest = wildcard_boxes;
 
198
                else {
 
199
                        dest = NULL;
 
200
                        i++;
 
201
                }
 
202
 
 
203
                if (dest != NULL) {
 
204
                        array_append(dest, &bboxes[i], 1);
 
205
                        array_delete(&mbox->backend_boxes, i, 1);
 
206
                        bboxes = array_get_modifiable(&mbox->backend_boxes,
 
207
                                                      &count);
 
208
                }
 
209
        }
 
210
}
 
211
 
 
212
static void virtual_config_copy_expanded(struct virtual_parse_context *ctx,
 
213
                                         struct virtual_backend_box *wbox,
 
214
                                         const char *name)
 
215
{
 
216
        struct virtual_backend_box *bbox;
 
217
 
 
218
        bbox = p_new(ctx->pool, struct virtual_backend_box, 1);
 
219
        *bbox = *wbox;
 
220
        bbox->name = p_strdup(ctx->pool, name);
 
221
        bbox->glob = NULL;
 
222
        bbox->wildcard = TRUE;
 
223
        mail_search_args_ref(bbox->search_args);
 
224
        array_append(&ctx->mbox->backend_boxes, &bbox, 1);
 
225
}
 
226
 
 
227
static bool virtual_config_match(const struct mailbox_info *info,
 
228
                                 ARRAY_TYPE(virtual_backend_box) *boxes_arr,
 
229
                                 unsigned int *idx_r)
 
230
{
 
231
        struct virtual_backend_box *const *boxes;
 
232
        unsigned int i, count;
 
233
 
 
234
        boxes = array_get_modifiable(boxes_arr, &count);
 
235
        for (i = 0; i < count; i++) {
 
236
                if (boxes[i]->glob != NULL) {
 
237
                        /* we match only one namespace for each pattern. */
 
238
                        if (boxes[i]->ns == info->ns &&
 
239
                            imap_match(boxes[i]->glob,
 
240
                                       info->name) == IMAP_MATCH_YES) {
 
241
                                *idx_r = i;
 
242
                                return TRUE;
 
243
                        }
 
244
                } else {
 
245
                        i_assert(boxes[i]->name[0] == '-');
 
246
                        if (strcmp(boxes[i]->name + 1, info->name) == 0) {
 
247
                                *idx_r = i;
 
248
                                return TRUE;
 
249
                        }
 
250
                }
 
251
        }
 
252
        return FALSE;
 
253
}
 
254
 
 
255
static int virtual_config_expand_wildcards(struct virtual_parse_context *ctx)
 
256
{
 
257
        struct mail_user *user = ctx->mbox->storage->storage.ns->user;
 
258
        ARRAY_TYPE(virtual_backend_box) wildcard_boxes, neg_boxes;
 
259
        struct mailbox_list_iterate_context *iter;
 
260
        struct virtual_backend_box *const *wboxes;
 
261
        const char **patterns;
 
262
        const struct mailbox_info *info;
 
263
        unsigned int i, j, count;
 
264
 
 
265
        separate_wildcard_mailboxes(ctx->mbox, &wildcard_boxes, &neg_boxes);
 
266
 
 
267
        /* get patterns we want to list */
 
268
        wboxes = array_get_modifiable(&wildcard_boxes, &count);
 
269
        if (count == 0) {
 
270
                /* only negative wildcards - doesn't really make sense.
 
271
                   just ignore. */
 
272
                return 0;
 
273
        }
 
274
        patterns = t_new(const char *, count + 1);
 
275
        for (i = 0; i < count; i++)
 
276
                patterns[i] = wboxes[i]->name;
 
277
 
 
278
        /* match listed mailboxes to wildcards */
 
279
        iter = mailbox_list_iter_init_namespaces(user->namespaces, patterns,
 
280
                                        MAILBOX_LIST_ITER_VIRTUAL_NAMES |
 
281
                                        MAILBOX_LIST_ITER_RETURN_NO_FLAGS);
 
282
        while ((info = mailbox_list_iter_next(iter)) != NULL) {
 
283
                /* skip non-selectable mailboxes (especially mbox
 
284
                   directories) */
 
285
                if ((info->flags & MAILBOX_NOSELECT) != 0)
 
286
                        continue;
 
287
 
 
288
                if (virtual_config_match(info, &wildcard_boxes, &i) &&
 
289
                    !virtual_config_match(info, &neg_boxes, &j) &&
 
290
                    virtual_backend_box_lookup_name(ctx->mbox,
 
291
                                                    info->name) == NULL) {
 
292
                        virtual_config_copy_expanded(ctx, wboxes[i],
 
293
                                                     info->name);
 
294
                }
 
295
        }
 
296
        for (i = 0; i < count; i++)
 
297
                mail_search_args_unref(&wboxes[i]->search_args);
 
298
        return mailbox_list_iter_deinit(&iter);
 
299
}
 
300
 
 
301
static void virtual_config_search_args_dup(struct virtual_mailbox *mbox)
 
302
{
 
303
        struct virtual_backend_box *const *bboxes;
 
304
        struct mail_search_args *old_args;
 
305
        unsigned int i, count;
 
306
 
 
307
        bboxes = array_get_modifiable(&mbox->backend_boxes, &count);
 
308
        for (i = 0; i < count; i++) {
 
309
                old_args = bboxes[i]->search_args;
 
310
                bboxes[i]->search_args = mail_search_args_dup(old_args);
 
311
                mail_search_args_unref(&old_args);
 
312
        }
 
313
}
 
314
 
 
315
int virtual_config_read(struct virtual_mailbox *mbox)
 
316
{
 
317
        struct mail_user *user = mbox->storage->storage.ns->user;
 
318
        struct virtual_parse_context ctx;
 
319
        const char *path, *line, *error;
 
320
        unsigned int linenum = 0;
 
321
        int fd, ret = 0;
 
322
 
 
323
        i_array_init(&mbox->backend_boxes, 8);
 
324
        mbox->search_args_crc32 = (uint32_t)-1;
 
325
 
 
326
        path = t_strconcat(mbox->path, "/"VIRTUAL_CONFIG_FNAME, NULL);
 
327
        fd = open(path, O_RDONLY);
 
328
        if (fd == -1) {
 
329
                if (errno == ENOENT) {
 
330
                        mail_storage_set_error(mbox->ibox.storage,
 
331
                                MAIL_ERROR_NOTPOSSIBLE,
 
332
                                "Virtual mailbox missing configuration file");
 
333
                        return -1;
 
334
                }
 
335
                mail_storage_set_critical(mbox->ibox.storage,
 
336
                                          "open(%s) failed: %m", path);
 
337
                return -1;
 
338
        }
 
339
 
 
340
        memset(&ctx, 0, sizeof(ctx));
 
341
        ctx.sep = mail_namespace_get_root_sep(user->namespaces);
 
342
        ctx.mbox = mbox;
 
343
        ctx.pool = mbox->ibox.box.pool;
 
344
        ctx.rule = t_str_new(256);
 
345
        ctx.input = i_stream_create_fd(fd, (size_t)-1, FALSE);
 
346
        i_stream_set_return_partial_line(ctx.input, TRUE);
 
347
        while ((line = i_stream_read_next_line(ctx.input)) != NULL) {
 
348
                linenum++;
 
349
                if (*line == '#')
 
350
                        continue;
 
351
                if (*line == '\0')
 
352
                        ret = virtual_config_add_rule(&ctx, &error);
 
353
                else
 
354
                        ret = virtual_config_parse_line(&ctx, line, &error);
 
355
                if (ret < 0) {
 
356
                        mail_storage_set_critical(mbox->ibox.storage,
 
357
                                                  "%s: Error at line %u: %s",
 
358
                                                  path, linenum, error);
 
359
                        break;
 
360
                }
 
361
        }
 
362
        if (ret == 0) {
 
363
                ret = virtual_config_add_rule(&ctx, &error);
 
364
                if (ret < 0) {
 
365
                        mail_storage_set_critical(mbox->ibox.storage,
 
366
                                                  "%s: Error at line %u: %s",
 
367
                                                  path, linenum, error);
 
368
                }
 
369
        }
 
370
 
 
371
        virtual_mailbox_get_list_patterns(&ctx);
 
372
        if (ret == 0 && ctx.have_wildcards)
 
373
                ret = virtual_config_expand_wildcards(&ctx);
 
374
 
 
375
        if (ret == 0 && array_count(&mbox->backend_boxes) == 0) {
 
376
                mail_storage_set_critical(mbox->ibox.storage,
 
377
                                          "%s: No mailboxes defined", path);
 
378
                ret = -1;
 
379
        }
 
380
        if (ret == 0)
 
381
                virtual_config_search_args_dup(mbox);
 
382
        i_stream_unref(&ctx.input);
 
383
        (void)close(fd);
 
384
        return ret;
 
385
}
 
386
 
 
387
void virtual_config_free(struct virtual_mailbox *mbox)
 
388
{
 
389
        struct virtual_backend_box *const *bboxes;
 
390
        unsigned int i, count;
 
391
 
 
392
        bboxes = array_get_modifiable(&mbox->backend_boxes, &count);
 
393
        for (i = 0; i < count; i++) {
 
394
                if (bboxes[i]->search_args != NULL)
 
395
                        mail_search_args_unref(&bboxes[i]->search_args);
 
396
        }
 
397
}