~ubuntu-dev/ubuntu/lucid/dovecot/lucid-201002110912

« back to all changes in this revision

Viewing changes to src/lib-storage/index/shared/shared-storage.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 "str.h"
 
6
#include "ioloop.h"
 
7
#include "var-expand.h"
 
8
#include "index-storage.h"
 
9
#include "shared-storage.h"
 
10
 
 
11
#include <stdlib.h>
 
12
#include <ctype.h>
 
13
 
 
14
#define SHARED_LIST_CONTEXT(obj) \
 
15
        MODULE_CONTEXT(obj, shared_mailbox_list_module)
 
16
 
 
17
extern struct mail_storage shared_storage;
 
18
extern struct mailbox shared_mailbox;
 
19
 
 
20
static MODULE_CONTEXT_DEFINE_INIT(shared_mailbox_list_module,
 
21
                                  &mailbox_list_module_register);
 
22
 
 
23
static struct mail_storage *shared_alloc(void)
 
24
{
 
25
        struct shared_storage *storage;
 
26
        pool_t pool;
 
27
 
 
28
        pool = pool_alloconly_create("shared storage", 1024);
 
29
        storage = p_new(pool, struct shared_storage, 1);
 
30
        storage->storage = shared_storage;
 
31
        storage->storage.pool = pool;
 
32
        storage->storage.storage_class = &shared_storage;
 
33
 
 
34
        storage->base_dir = p_strdup(pool, getenv("BASE_DIR"));
 
35
        if (storage->base_dir == NULL)
 
36
                storage->base_dir = PKG_RUNDIR;
 
37
 
 
38
        return &storage->storage;
 
39
}
 
40
 
 
41
static int shared_create(struct mail_storage *_storage, const char *data,
 
42
                         const char **error_r)
 
43
{
 
44
        struct shared_storage *storage = (struct shared_storage *)_storage;
 
45
        struct mailbox_list_settings list_set;
 
46
        const char *driver, *p;
 
47
        char *wildcardp;
 
48
        bool have_username;
 
49
 
 
50
        /* data must begin with the actual mailbox driver */
 
51
        p = strchr(data, ':');
 
52
        if (p == NULL) {
 
53
                *error_r = "Shared mailbox location not prefixed with driver";
 
54
                return -1;
 
55
        }
 
56
        driver = t_strdup_until(data, p);
 
57
        storage->location = p_strdup(_storage->pool, data);
 
58
        storage->storage_class = mail_storage_find_class(driver);
 
59
        if (storage->storage_class == NULL) {
 
60
                *error_r = t_strconcat("Unknown shared storage driver: ",
 
61
                                       driver, NULL);
 
62
                return -1;
 
63
        }
 
64
        _storage->mailbox_is_file = storage->storage_class->mailbox_is_file;
 
65
 
 
66
        wildcardp = strchr(_storage->ns->prefix, '%');
 
67
        if (wildcardp == NULL) {
 
68
                *error_r = "Shared namespace prefix doesn't contain %";
 
69
                return -1;
 
70
        }
 
71
        storage->ns_prefix_pattern = p_strdup(_storage->pool, wildcardp);
 
72
 
 
73
        have_username = FALSE;
 
74
        for (p = storage->ns_prefix_pattern; *p != '\0'; p++) {
 
75
                if (*p != '%')
 
76
                        continue;
 
77
                if (*++p == '\0')
 
78
                        break;
 
79
                if (*p == 'u' || *p == 'n')
 
80
                        have_username = TRUE;
 
81
                else if (*p != '%' && *p != 'd')
 
82
                        break;
 
83
        }
 
84
        if (*p != '\0') {
 
85
                *error_r = "Shared namespace prefix contains unknown variables";
 
86
                return -1;
 
87
        }
 
88
        if (!have_username) {
 
89
                *error_r = "Shared namespace prefix doesn't contain %u or %n";
 
90
                return -1;
 
91
        }
 
92
 
 
93
        /* truncate prefix after the above checks are done, so they can log
 
94
           the full prefix in error conditions */
 
95
        *wildcardp = '\0';
 
96
 
 
97
        if (mailbox_list_alloc("shared", &_storage->list, error_r) < 0)
 
98
                return -1;
 
99
        MODULE_CONTEXT_SET_FULL(_storage->list, shared_mailbox_list_module,
 
100
                                storage, &storage->list_module_ctx);
 
101
 
 
102
        memset(&list_set, 0, sizeof(list_set));
 
103
        list_set.mail_storage_flags = &_storage->flags;
 
104
        list_set.lock_method = &_storage->lock_method;
 
105
        mailbox_list_init(_storage->list, _storage->ns, &list_set,
 
106
                          mail_storage_get_list_flags(_storage->flags));
 
107
        return 0;
 
108
}
 
109
 
 
110
static void
 
111
get_nonexisting_user_location(struct shared_storage *storage,
 
112
                              const char *username, string_t *location)
 
113
{
 
114
        /* user wasn't found. we'll still need to create the storage
 
115
           to avoid exposing which users exist and which don't. */
 
116
        str_append(location, storage->storage_class->name);
 
117
        str_append_c(location, ':');
 
118
 
 
119
        /* use a reachable but non-existing path as the mail root directory */
 
120
        str_append(location, storage->base_dir);
 
121
        str_append(location, "/user-not-found/");
 
122
        str_append(location, username);
 
123
}
 
124
 
 
125
int shared_storage_get_namespace(struct mail_storage *_storage,
 
126
                                 const char **_name,
 
127
                                 struct mail_namespace **ns_r)
 
128
{
 
129
        struct shared_storage *storage = (struct shared_storage *)_storage;
 
130
        struct mail_user *user = _storage->ns->user;
 
131
        static struct var_expand_table static_tab[] = {
 
132
                { 'u', NULL, "user" },
 
133
                { 'n', NULL, "username" },
 
134
                { 'd', NULL, "domain" },
 
135
                { 'h', NULL, "home" },
 
136
                { '\0', NULL, NULL }
 
137
        };
 
138
        struct var_expand_table *tab;
 
139
        struct mail_namespace *ns;
 
140
        struct mail_user *owner;
 
141
        const char *domain = NULL, *username = NULL, *userdomain = NULL;
 
142
        const char *name, *p, *next, **dest, *error;
 
143
        string_t *prefix, *location;
 
144
        int ret;
 
145
 
 
146
        *ns_r = NULL;
 
147
 
 
148
        p = storage->ns_prefix_pattern;
 
149
        for (name = *_name; *p != '\0';) {
 
150
                if (*p != '%') {
 
151
                        if (*p != *name)
 
152
                                break;
 
153
                        p++; name++;
 
154
                        continue;
 
155
                }
 
156
                switch (*++p) {
 
157
                case 'd':
 
158
                        dest = &domain;
 
159
                        break;
 
160
                case 'n':
 
161
                        dest = &username;
 
162
                        break;
 
163
                case 'u':
 
164
                        dest = &userdomain;
 
165
                        break;
 
166
                default:
 
167
                        /* we checked this already above */
 
168
                        i_unreached();
 
169
                }
 
170
                p++;
 
171
 
 
172
                next = strchr(name, *p != '\0' ? *p : _storage->ns->sep);
 
173
                if (next == NULL) {
 
174
                        *dest = name;
 
175
                        name = "";
 
176
                        break;
 
177
                }
 
178
                *dest = t_strdup_until(name, next);
 
179
                name = next;
 
180
        }
 
181
        if (*p != '\0') {
 
182
                if (*name == '\0' ||
 
183
                    (name[1] == '\0' && *name == _storage->ns->sep)) {
 
184
                        /* trying to open <prefix>/<user> mailbox */
 
185
                        name = "INBOX";
 
186
                } else {
 
187
                        mail_storage_set_critical(_storage,
 
188
                                        "Invalid namespace prefix %s vs %s",
 
189
                                        storage->ns_prefix_pattern, *_name);
 
190
                        return -1;
 
191
                }
 
192
        }
 
193
 
 
194
        /* successfully matched the name. */
 
195
        if (userdomain != NULL) {
 
196
                /* user@domain given */
 
197
                domain = strchr(userdomain, '@');
 
198
                if (domain == NULL)
 
199
                        username = userdomain;
 
200
                else {
 
201
                        username = t_strdup_until(userdomain, domain);
 
202
                        domain++;
 
203
                }
 
204
        } else if (username == NULL) {
 
205
                /* trying to open namespace "shared/domain"
 
206
                   namespace prefix. */
 
207
                mail_storage_set_error(_storage, MAIL_ERROR_NOTFOUND,
 
208
                                       T_MAIL_ERR_MAILBOX_NOT_FOUND(*_name));
 
209
                return -1;
 
210
        } else {
 
211
                if (domain == NULL) {
 
212
                        /* no domain given, use ours (if we have one) */
 
213
                        domain = strchr(user->username, '@');
 
214
                        if (domain != NULL) domain++;
 
215
                }
 
216
                userdomain = domain == NULL ? username :
 
217
                        t_strconcat(username, "@", domain, NULL);
 
218
        }
 
219
        if (*userdomain == '\0') {
 
220
                mail_storage_set_error(_storage, MAIL_ERROR_PARAMS,
 
221
                                       "Empty username doesn't exist");
 
222
                return -1;
 
223
        }
 
224
 
 
225
        /* expand the namespace prefix and see if it already exists.
 
226
           this should normally happen only when the mailbox is being opened */
 
227
        tab = t_malloc(sizeof(static_tab));
 
228
        memcpy(tab, static_tab, sizeof(static_tab));
 
229
        tab[0].value = userdomain;
 
230
        tab[1].value = username;
 
231
        tab[2].value = domain;
 
232
 
 
233
        prefix = t_str_new(128);
 
234
        str_append(prefix, _storage->ns->prefix);
 
235
        var_expand(prefix, storage->ns_prefix_pattern, tab);
 
236
 
 
237
        ns = mail_namespace_find_prefix(user->namespaces, str_c(prefix));
 
238
        if (ns != NULL) {
 
239
                *_name = mail_namespace_fix_sep(ns, name);
 
240
                *ns_r = ns;
 
241
                return 0;
 
242
        }
 
243
 
 
244
        owner = mail_user_init(userdomain);
 
245
        if (!var_has_key(storage->location, 'h', "home"))
 
246
                ret = 1;
 
247
        else {
 
248
                /* we'll need to look up the user's home directory */
 
249
                if ((ret = mail_user_get_home(owner, &tab[3].value)) < 0) {
 
250
                        mail_storage_set_critical(_storage, "Namespace '%s': "
 
251
                                "Could not lookup home for user %s",
 
252
                                _storage->ns->prefix, userdomain);
 
253
                        mail_user_unref(&owner);
 
254
                        return -1;
 
255
                }
 
256
        }
 
257
 
 
258
        /* create the new namespace */
 
259
        ns = i_new(struct mail_namespace, 1);
 
260
        ns->type = NAMESPACE_SHARED;
 
261
        ns->user = user;
 
262
        ns->prefix = i_strdup(str_c(prefix));
 
263
        ns->owner = owner;
 
264
        ns->flags = (NAMESPACE_FLAG_SUBSCRIPTIONS & _storage->ns->flags) |
 
265
                NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_HIDDEN |
 
266
                NAMESPACE_FLAG_AUTOCREATED | NAMESPACE_FLAG_INBOX;
 
267
        ns->sep = _storage->ns->sep;
 
268
 
 
269
        location = t_str_new(256);
 
270
        if (ret > 0)
 
271
                var_expand(location, storage->location, tab);
 
272
        else {
 
273
                get_nonexisting_user_location(storage, userdomain, location);
 
274
                ns->flags |= NAMESPACE_FLAG_UNUSABLE;
 
275
        }
 
276
        if (mail_storage_create(ns, NULL, str_c(location), _storage->flags,
 
277
                                _storage->lock_method, &error) < 0) {
 
278
                mail_storage_set_critical(_storage, "Namespace '%s': %s",
 
279
                                          ns->prefix, error);
 
280
                mail_namespace_destroy(ns);
 
281
                return -1;
 
282
        }
 
283
        _storage->ns->flags |= NAMESPACE_FLAG_USABLE;
 
284
        *_name = mail_namespace_fix_sep(ns, name);
 
285
        *ns_r = ns;
 
286
 
 
287
        mail_user_add_namespace(user, &ns);
 
288
        return 0;
 
289
}
 
290
 
 
291
static void shared_mailbox_copy_error(struct mail_storage *shared_storage,
 
292
                                      struct mail_namespace *backend_ns)
 
293
{
 
294
        const char *str;
 
295
        enum mail_error error;
 
296
 
 
297
        str = mail_storage_get_last_error(backend_ns->storage, &error);
 
298
        mail_storage_set_error(shared_storage, error, str);
 
299
}
 
300
 
 
301
static int shared_mailbox_create(struct mail_storage *storage,
 
302
                                 const char *name, bool directory)
 
303
{
 
304
        struct mail_namespace *ns;
 
305
        int ret;
 
306
 
 
307
        if (shared_storage_get_namespace(storage, &name, &ns) < 0)
 
308
                return -1;
 
309
 
 
310
        ret = mail_storage_mailbox_create(ns->storage, name, directory);
 
311
        if (ret < 0)
 
312
                shared_mailbox_copy_error(storage, ns);
 
313
        return ret;
 
314
}
 
315
 
 
316
struct mail_storage shared_storage = {
 
317
        MEMBER(name) SHARED_STORAGE_NAME,
 
318
        MEMBER(mailbox_is_file) FALSE, /* unknown at this point */
 
319
 
 
320
        {
 
321
                NULL,
 
322
                NULL,
 
323
                shared_alloc,
 
324
                shared_create,
 
325
                index_storage_destroy,
 
326
                NULL,
 
327
                NULL,
 
328
                shared_mailbox_create
 
329
        }
 
330
};