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

« back to all changes in this revision

Viewing changes to src/plugins/acl/acl-backend-vfile-acllist.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:
10
10
#include "mail-storage.h"
11
11
#include "acl-plugin.h"
12
12
#include "acl-cache.h"
 
13
#include "acl-lookup-dict.h"
13
14
#include "acl-backend-vfile.h"
14
15
 
15
16
#include <stdio.h>
20
21
struct acl_mailbox_list_context_vfile {
21
22
        struct acl_mailbox_list_context ctx;
22
23
 
23
 
        unsigned int acllist_change_counter;
24
24
        unsigned int idx;
25
25
};
26
26
 
27
27
static void
28
28
acllist_clear(struct acl_backend_vfile *backend, uoff_t file_size)
29
29
{
30
 
        backend->acllist_change_counter++;
31
30
        if (backend->acllist_pool == NULL) {
32
31
                backend->acllist_pool =
33
32
                        pool_alloconly_create("vfile acllist",
39
38
        }
40
39
}
41
40
 
 
41
static const char *acl_list_get_root_dir(struct acl_backend_vfile *backend)
 
42
{
 
43
        struct mail_storage *storage;
 
44
        const char *rootdir, *maildir;
 
45
        bool is_file;
 
46
 
 
47
        rootdir = mailbox_list_get_path(backend->backend.list, NULL,
 
48
                                        MAILBOX_LIST_PATH_TYPE_DIR);
 
49
 
 
50
        storage = mailbox_list_get_namespace(backend->backend.list)->storage;
 
51
        (void)mail_storage_get_mailbox_path(storage, "", &is_file);
 
52
        if (is_file) {
 
53
                maildir = mailbox_list_get_path(backend->backend.list, NULL,
 
54
                                                MAILBOX_LIST_PATH_TYPE_MAILBOX);
 
55
                if (strcmp(maildir, rootdir) == 0) {
 
56
                        /* dovecot-acl-list would show up as a mailbox if we
 
57
                           created it to root dir. since we don't really have
 
58
                           any other good alternatives, place it to control
 
59
                           dir */
 
60
                        rootdir = mailbox_list_get_path(backend->backend.list,
 
61
                                        NULL, MAILBOX_LIST_PATH_TYPE_CONTROL);
 
62
                }
 
63
        }
 
64
        return rootdir;
 
65
}
 
66
 
 
67
static const char *acl_list_get_path(struct acl_backend_vfile *backend)
 
68
{
 
69
        return t_strconcat(acl_list_get_root_dir(backend),
 
70
                           "/"ACLLIST_FILENAME, NULL);
 
71
}
 
72
 
42
73
static int acl_backend_vfile_acllist_read(struct acl_backend_vfile *backend)
43
74
{
44
75
        struct acl_backend_vfile_acllist acllist;
45
76
        struct istream *input;
46
77
        struct stat st;
47
 
        const char *rootdir, *path, *line, *p;
 
78
        const char *path, *line, *p;
48
79
        int fd, ret = 0;
49
80
 
50
81
        backend->acllist_last_check = ioloop_time;
51
82
 
52
 
        rootdir = mailbox_list_get_path(backend->backend.list, NULL,
53
 
                                        MAILBOX_LIST_PATH_TYPE_DIR);
54
 
        path = t_strdup_printf("%s/"ACLLIST_FILENAME, rootdir);
 
83
        path = acl_list_get_path(backend);
 
84
        if (path == NULL) {
 
85
                /* we're never going to build acllist for this namespace. */
 
86
                i_array_init(&backend->acllist, 1);
 
87
                return 0;
 
88
        }
55
89
 
56
90
        if (backend->acllist_mtime != 0) {
57
91
                /* see if the file's mtime has changed */
109
143
 
110
144
void acl_backend_vfile_acllist_refresh(struct acl_backend_vfile *backend)
111
145
{
 
146
        i_assert(!backend->iterating_acllist);
 
147
 
112
148
        if (backend->acllist_last_check +
113
149
            (time_t)backend->cache_secs > ioloop_time)
114
150
                return;
120
156
        }
121
157
}
122
158
 
123
 
static bool rights_has_lookup_changes(const struct acl_rights *rights)
124
 
{
125
 
        const char *const *p;
126
 
 
127
 
        if (rights->id_type == ACL_ID_OWNER) {
128
 
                /* ignore owner rights */
129
 
                return FALSE;
130
 
        }
131
 
 
132
 
        if (rights->rights == NULL)
133
 
                return FALSE;
134
 
 
135
 
        for (p = rights->rights; *p != NULL; p++) {
136
 
                if (strcmp(*p, MAIL_ACL_LOOKUP) == 0)
137
 
                        return TRUE;
138
 
        }
139
 
        return FALSE;
140
 
}
141
 
 
142
159
static int
143
160
acllist_append(struct acl_backend_vfile *backend, struct ostream *output,
144
161
               struct mail_storage *storage, const char *name)
154
171
 
155
172
        iter = acl_object_list_init(aclobj);
156
173
        while ((ret = acl_object_list_next(iter, &rights)) > 0) {
157
 
                if (rights_has_lookup_changes(&rights))
 
174
                if (acl_rights_has_nonowner_lookup_changes(&rights))
158
175
                        break;
159
176
        }
160
177
        acl_object_list_deinit(&iter);
177
194
        return ret < 0 ? -1 : 0;
178
195
}
179
196
 
180
 
int acl_backend_vfile_acllist_rebuild(struct acl_backend_vfile *backend)
 
197
static int
 
198
acl_backend_vfile_acllist_try_rebuild(struct acl_backend_vfile *backend)
181
199
{
182
200
        struct mailbox_list *list = backend->backend.list;
183
201
        struct mail_namespace *ns;
184
202
        struct mailbox_list_iterate_context *iter;
185
203
        const struct mailbox_info *info;
186
 
        const char *rootdir, *acllist_path;
 
204
        const char *rootdir, *origin, *acllist_path;
187
205
        struct ostream *output;
188
206
        struct stat st;
189
207
        string_t *path;
191
209
        gid_t gid;
192
210
        int fd, ret;
193
211
 
194
 
        mailbox_list_get_permissions(list, &mode, &gid);
 
212
        i_assert(!backend->rebuilding_acllist);
 
213
 
 
214
        rootdir = acl_list_get_root_dir(backend);
 
215
        if (rootdir == NULL)
 
216
                return 0;
 
217
 
 
218
        ns = mailbox_list_get_namespace(list);
 
219
        if ((ns->flags & NAMESPACE_FLAG_UNUSABLE) != 0) {
 
220
                /* we can't write anything here */
 
221
                return 0;
 
222
        }
195
223
 
196
224
        path = t_str_new(256);
197
 
        rootdir = mailbox_list_get_path(list, NULL,
198
 
                                        MAILBOX_LIST_PATH_TYPE_DIR);
199
225
        str_printfa(path, "%s/%s", rootdir, mailbox_list_get_temp_prefix(list));
200
226
 
201
227
        /* Build it into a temporary file and rename() over. There's no need
202
228
           to use locking, because even if multiple processes are rebuilding
203
229
           the file at the same time the result should be the same. */
204
 
        fd = safe_mkstemp(path, mode, (uid_t)-1, gid);
 
230
        mailbox_list_get_permissions(list, NULL, &mode, &gid, &origin);
 
231
        fd = safe_mkstemp_group(path, mode, gid, origin);
 
232
        if (fd == -1 && errno == ENOENT) {
 
233
                if (mailbox_list_create_parent_dir(backend->backend.list, NULL,
 
234
                                                   str_c(path)) < 0)
 
235
                        return -1;
 
236
                fd = safe_mkstemp_group(path, mode, gid, origin);
 
237
        }
205
238
        if (fd == -1) {
206
239
                if (errno == EACCES) {
207
240
                        /* Ignore silently if we can't create it */
215
248
 
216
249
        ret = 0;
217
250
        acllist_clear(backend, 0);
218
 
        ns = mailbox_list_get_namespace(list);
219
251
 
220
252
        backend->rebuilding_acllist = TRUE;
221
253
        iter = mailbox_list_iter_init(list, "*", MAILBOX_LIST_ITER_RAW_LIST |
228
260
                }
229
261
        }
230
262
 
 
263
        if (output->stream_errno != 0) {
 
264
                i_error("write(%s) failed: %m", str_c(path));
 
265
                ret = -1;
 
266
        }
231
267
        if (mailbox_list_iter_deinit(&iter) < 0)
232
268
                ret = -1;
233
269
        o_stream_destroy(&output);
234
 
        backend->rebuilding_acllist = FALSE;
235
270
 
236
271
        if (ret == 0) {
237
272
                if (fstat(fd, &st) < 0) {
245
280
        }
246
281
 
247
282
        if (ret == 0) {
248
 
                acllist_path = t_strdup_printf("%s/"ACLLIST_FILENAME, rootdir);
 
283
                acllist_path = acl_list_get_path(backend);
249
284
                if (rename(str_c(path), acllist_path) < 0) {
250
285
                        i_error("rename(%s, %s) failed: %m",
251
286
                                str_c(path), acllist_path);
253
288
                }
254
289
        }
255
290
        if (ret == 0) {
 
291
                struct acl_user *auser = ACL_USER_CONTEXT(ns->user);
 
292
 
256
293
                backend->acllist_mtime = st.st_mtime;
257
294
                backend->acllist_last_check = ioloop_time;
 
295
                /* FIXME: dict reubild is expensive, try to avoid it */
 
296
                (void)acl_lookup_dict_rebuild(auser->acl_lookup_dict);
258
297
        } else {
259
298
                acllist_clear(backend, 0);
260
299
                if (unlink(str_c(path)) < 0 && errno != ENOENT)
261
300
                        i_error("unlink(%s) failed: %m", str_c(path));
262
301
        }
 
302
        backend->rebuilding_acllist = FALSE;
263
303
        return ret;
264
304
}
265
305
 
 
306
int acl_backend_vfile_acllist_rebuild(struct acl_backend_vfile *backend)
 
307
{
 
308
        const char *acllist_path;
 
309
 
 
310
        if (acl_backend_vfile_acllist_try_rebuild(backend) == 0)
 
311
                return 0;
 
312
        else {
 
313
                /* delete it to make sure it gets rebuilt later */
 
314
                acllist_path = acl_list_get_path(backend);
 
315
                if (unlink(acllist_path) < 0 && errno != ENOENT)
 
316
                        i_error("unlink(%s) failed: %m", acllist_path);
 
317
                return -1;
 
318
        }
 
319
}
 
320
 
266
321
static const struct acl_backend_vfile_acllist *
267
322
acl_backend_vfile_acllist_find(struct acl_backend_vfile *backend,
268
323
                               const char *name)
283
338
{
284
339
        const struct acl_backend_vfile_acllist *acllist;
285
340
 
 
341
        if (backend->rebuilding_acllist || backend->iterating_acllist)
 
342
                return;
 
343
 
286
344
        acl_backend_vfile_acllist_refresh(backend);
287
345
        acllist = acl_backend_vfile_acllist_find(backend, name);
288
 
        if (acllist != NULL && acllist->mtime != mtime &&
289
 
            !backend->rebuilding_acllist)
 
346
        if (acllist != NULL && acllist->mtime != mtime)
290
347
                (void)acl_backend_vfile_acllist_rebuild(backend);
291
348
}
292
349
 
301
358
 
302
359
        ctx = i_new(struct acl_mailbox_list_context_vfile, 1);
303
360
        ctx->ctx.backend = _backend;
304
 
        ctx->acllist_change_counter = backend->acllist_change_counter;
 
361
        backend->iterating_acllist = TRUE;
305
362
        return &ctx->ctx;
306
363
}
307
364
 
315
372
        const struct acl_backend_vfile_acllist *acllist;
316
373
        unsigned int count;
317
374
 
318
 
        if (ctx->acllist_change_counter != backend->acllist_change_counter)
319
 
                return -1;
320
 
 
321
375
        acllist = array_get(&backend->acllist, &count);
322
376
        if (ctx->idx == count)
323
377
                return 0;
329
383
void
330
384
acl_backend_vfile_nonowner_iter_deinit(struct acl_mailbox_list_context *ctx)
331
385
{
 
386
        struct acl_backend_vfile *backend =
 
387
                (struct acl_backend_vfile *)ctx->backend;
 
388
 
 
389
        backend->iterating_acllist = FALSE;
332
390
        i_free(ctx);
333
391
}