~ubuntu-dev/ubuntu/lucid/dovecot/lucid-201002101901

« back to all changes in this revision

Viewing changes to src/deliver/duplicate.c

  • Committer: Chuck Short
  • Date: 2010-01-21 20:21:25 UTC
  • mfrom: (4.1.11 squeeze)
  • Revision ID: zulcss@ubuntu.com-20100121202125-pme73o491kfwj5nc
* 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 restriction
    - 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 config
    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.
    - 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.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
* New upstream release.
* debian/patches/gold-fix.patch: Removed. Fixed upstream.
* Moved libexec to lib corrections in dovecot-managesieve.patch and
  dovecot-managesieve-dist.patch to dovecot-example.patch
* debian/patches/dovecot-mboxlocking.patch: Regenerated to avoid FTBFS
  when quilt isn't installed.
* debian/patches/quota-mountpoint.patch: Removed. Not needed anymore.
* debian/patches/dovecot-quota.patch: Removed. Quotas aren't properly
  enabled unless mail_plugins = quota imap_quota.
* debian/patches/gold-fix.patch: Fixed configure script to build even
  with binutils-gold or --no-add-needed linker flag (Closes: #554306)
* debian/dovecot-common.init: fixed LSB headers. Thanks to Pascal Volk.
  (Closes: #558040)
* debian/changelog: added CVE references to previous changelog entry.
* debian/rules: checked up the build system. It's not fragile anymore.
  (Closes: 493803)
* debian/dovecot-common.postinst: Now invoking dpkg-reconfigure
  on dovecot-common is enough to generate new certificates
  if the previous ones were removed. (Closes: #545582)
* debian/rules: No longer install convert-tool in /usr/bin.
  It isn't an user utility and it should stay in /usr/lib/dovecot
  like all other similar tool.
* New upstream release. (Closes: #557601)
* [SECURITY] Fixes local information disclosure and denial of service.
  (see: http://www.dovecot.org/list/dovecot-news/2009-November/000143.html
  and CVE-2009-3897)
* Added myself to uploaders.
* Switched to the new source format "3.0 (quilt)":
  - removed dpatch from build-depends
  - removed debian/README.source because now we use only standard
    dpkg features
  - regenerated all patches
* Prepared to switch to multi-origin source:
  - recreated dovecot-libsieve.patch and dovecot-managesieve-dist.patch
    starting from the upstream tarball
  - removed all autotools related build-depends and build-conflict
  - renamed dovecot-libsieve and dovecot-managesieve directories
    to libsieve and managesieve.
* debian/rules: Moved the configuration of libsieve and managesieve from
  the build phase to the configuration phase
* Added dovecot-dbg package  with debugging symbols.  Thanks Stephan Bosch.
  (Closes: #554710)
* Fixed some stray libexec'isms in the default configuration.
* New upstream release.
* debian/dovecot-common.init:
  - use $CONF when starting the daemon. (Closes: #549944)
  - always output start/stop messages. (Closes: #523810)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
2
 
 
3
 
#include "lib.h"
4
 
#include "ioloop.h"
5
 
#include "istream.h"
6
 
#include "ostream.h"
7
 
#include "home-expand.h"
8
 
#include "file-dotlock.h"
9
 
#include "hash.h"
10
 
#include "duplicate.h"
11
 
 
12
 
#include <stdlib.h>
13
 
#include <fcntl.h>
14
 
#include <unistd.h>
15
 
 
16
 
#define DUPLICATE_PATH "~/.dovecot.lda-dupes"
17
 
#define COMPRESS_PERCENTAGE 10
18
 
#define DUPLICATE_BUFSIZE 4096
19
 
#define DUPLICATE_VERSION 2
20
 
 
21
 
struct duplicate {
22
 
        const void *id;
23
 
        unsigned int id_size;
24
 
 
25
 
        const char *user;
26
 
        time_t time;
27
 
};
28
 
 
29
 
struct duplicate_file_header {
30
 
        uint32_t version;
31
 
};
32
 
 
33
 
struct duplicate_record_header {
34
 
        uint32_t stamp;
35
 
        uint32_t id_size;
36
 
        uint32_t user_size;
37
 
};
38
 
 
39
 
struct duplicate_file {
40
 
        pool_t pool;
41
 
        struct hash_table *hash;
42
 
        const char *path;
43
 
 
44
 
        int new_fd;
45
 
        struct dotlock *dotlock;
46
 
        unsigned int changed:1;
47
 
};
48
 
 
49
 
static struct dotlock_settings duplicate_dotlock_set = {
50
 
        MEMBER(temp_prefix) NULL,
51
 
        MEMBER(lock_suffix) NULL,
52
 
 
53
 
        MEMBER(timeout) 20,
54
 
        MEMBER(stale_timeout) 10,
55
 
 
56
 
        MEMBER(callback) NULL,
57
 
        MEMBER(context) NULL,
58
 
 
59
 
        MEMBER(use_excl_lock) FALSE
60
 
};
61
 
static struct duplicate_file *duplicate_file = NULL;
62
 
 
63
 
static int duplicate_cmp(const void *p1, const void *p2)
64
 
{
65
 
        const struct duplicate *d1 = p1, *d2 = p2;
66
 
 
67
 
        return (d1->id_size == d2->id_size &&
68
 
                memcmp(d1->id, d2->id, d1->id_size) == 0 &&
69
 
                strcasecmp(d1->user, d2->user) == 0) ? 0 : 1;
70
 
}
71
 
 
72
 
static unsigned int duplicate_hash(const void *p)
73
 
{
74
 
        /* a char* hash function from ASU -- from glib */
75
 
        const struct duplicate *d = p;
76
 
        const unsigned char *s = d->id, *end = s + d->id_size;
77
 
        unsigned int g, h = 0;
78
 
 
79
 
        while (s != end) {
80
 
                h = (h << 4) + *s;
81
 
                if ((g = h & 0xf0000000UL)) {
82
 
                        h = h ^ (g >> 24);
83
 
                        h = h ^ g;
84
 
                }
85
 
                s++;
86
 
        }
87
 
 
88
 
        return h ^ strcase_hash(d->user);
89
 
}
90
 
 
91
 
static int
92
 
duplicate_read_records(struct duplicate_file *file, struct istream *input,
93
 
                       unsigned int record_size)
94
 
{
95
 
        const unsigned char *data;
96
 
        struct duplicate_record_header hdr;
97
 
        size_t size;
98
 
        unsigned int change_count;
99
 
 
100
 
        change_count = 0;
101
 
        while (i_stream_read_data(input, &data, &size, record_size) > 0) {
102
 
                if (record_size == sizeof(hdr))
103
 
                        memcpy(&hdr, data, sizeof(hdr));
104
 
                else {
105
 
                        /* FIXME: backwards compatibility with v1.0 */
106
 
                        time_t stamp;
107
 
 
108
 
                        i_assert(record_size ==
109
 
                                 sizeof(time_t) + sizeof(uint32_t)*2);
110
 
                        memcpy(&stamp, data, sizeof(stamp));
111
 
                        hdr.stamp = stamp;
112
 
                        memcpy(&hdr.id_size, data + sizeof(time_t),
113
 
                               sizeof(hdr.id_size));
114
 
                        memcpy(&hdr.user_size,
115
 
                               data + sizeof(time_t) + sizeof(uint32_t),
116
 
                               sizeof(hdr.user_size));
117
 
                }
118
 
                i_stream_skip(input, record_size);
119
 
 
120
 
                if (hdr.id_size == 0 || hdr.user_size == 0 ||
121
 
                    hdr.id_size > DUPLICATE_BUFSIZE ||
122
 
                    hdr.user_size > DUPLICATE_BUFSIZE) {
123
 
                        i_error("broken duplicate file %s", file->path);
124
 
                        return -1;
125
 
                }
126
 
 
127
 
                if (i_stream_read_data(input, &data, &size,
128
 
                                       hdr.id_size + hdr.user_size - 1) <= 0) {
129
 
                        i_error("unexpected end of file in %s", file->path);
130
 
                        return -1;
131
 
                }
132
 
 
133
 
                if ((time_t)hdr.stamp >= ioloop_time) {
134
 
                        /* still valid, save it */
135
 
                        struct duplicate *d;
136
 
                        void *new_id;
137
 
 
138
 
                        new_id = p_malloc(file->pool, hdr.id_size);
139
 
                        memcpy(new_id, data, hdr.id_size);
140
 
 
141
 
                        d = p_new(file->pool, struct duplicate, 1);
142
 
                        d->id = new_id;
143
 
                        d->id_size = hdr.id_size;
144
 
                        d->user = p_strndup(file->pool,
145
 
                                            data + hdr.id_size, hdr.user_size);
146
 
                        d->time = hdr.stamp;
147
 
                        hash_table_insert(file->hash, d, d);
148
 
                } else {
149
 
                        change_count++;
150
 
                }
151
 
                i_stream_skip(input, hdr.id_size + hdr.user_size);
152
 
        }
153
 
 
154
 
        if (hash_table_count(file->hash) *
155
 
            COMPRESS_PERCENTAGE / 100 > change_count)
156
 
                file->changed = TRUE;
157
 
        return 0;
158
 
}
159
 
 
160
 
static int duplicate_read(struct duplicate_file *file)
161
 
{
162
 
        struct istream *input;
163
 
        struct duplicate_file_header hdr;
164
 
        const unsigned char *data;
165
 
        size_t size;
166
 
        int fd;
167
 
        unsigned int record_size = 0;
168
 
 
169
 
        fd = open(file->path, O_RDONLY);
170
 
        if (fd == -1) {
171
 
                if (errno == ENOENT)
172
 
                        return 0;
173
 
                i_error("open(%s) failed: %m", file->path);
174
 
                return -1;
175
 
        }
176
 
 
177
 
        /* <timestamp> <id_size> <user_size> <id> <user> */
178
 
        input = i_stream_create_fd(fd, DUPLICATE_BUFSIZE, FALSE);
179
 
        if (i_stream_read_data(input, &data, &size, sizeof(hdr)) > 0) {
180
 
                memcpy(&hdr, data, sizeof(hdr));
181
 
                if (hdr.version == 0 || hdr.version > DUPLICATE_VERSION + 10) {
182
 
                        /* FIXME: backwards compatibility with v1.0 */
183
 
                        record_size = sizeof(time_t) + sizeof(uint32_t)*2;
184
 
                } else if (hdr.version == DUPLICATE_VERSION) {
185
 
                        record_size = sizeof(struct duplicate_record_header);
186
 
                        i_stream_skip(input, sizeof(hdr));
187
 
                }
188
 
        }
189
 
 
190
 
        if (record_size == 0 ||
191
 
            duplicate_read_records(file, input, record_size) < 0) {
192
 
                if (unlink(file->path) < 0 && errno != ENOENT)
193
 
                        i_error("unlink(%s) failed: %m", file->path);
194
 
        }
195
 
 
196
 
        i_stream_unref(&input);
197
 
        if (close(fd) < 0)
198
 
                i_error("close(%s) failed: %m", file->path);
199
 
        return 0;
200
 
}
201
 
 
202
 
static struct duplicate_file *duplicate_new(const char *path)
203
 
{
204
 
        struct duplicate_file *file;
205
 
        pool_t pool;
206
 
 
207
 
        pool = pool_alloconly_create("duplicates", 10240);
208
 
 
209
 
        file = p_new(pool, struct duplicate_file, 1);
210
 
        file->pool = pool;
211
 
        file->path = p_strdup(pool, path);
212
 
        file->new_fd = file_dotlock_open(&duplicate_dotlock_set, path, 0,
213
 
                                         &file->dotlock);
214
 
        if (file->new_fd == -1)
215
 
                i_error("file_dotlock_create(%s) failed: %m", path);
216
 
        file->hash = hash_table_create(default_pool, pool, 0,
217
 
                                       duplicate_hash, duplicate_cmp);
218
 
        (void)duplicate_read(file);
219
 
        return file;
220
 
}
221
 
 
222
 
static void duplicate_free(struct duplicate_file **_file)
223
 
{
224
 
        struct duplicate_file *file = *_file;
225
 
 
226
 
        *_file = NULL;
227
 
        if (file->dotlock != NULL)
228
 
                file_dotlock_delete(&file->dotlock);
229
 
 
230
 
        hash_table_destroy(&file->hash);
231
 
        pool_unref(&file->pool);
232
 
}
233
 
 
234
 
int duplicate_check(const void *id, size_t id_size, const char *user)
235
 
{
236
 
        struct duplicate d;
237
 
 
238
 
        if (duplicate_file == NULL)
239
 
                duplicate_file = duplicate_new(home_expand(DUPLICATE_PATH));
240
 
 
241
 
        d.id = id;
242
 
        d.id_size = id_size;
243
 
        d.user = user;
244
 
 
245
 
        return hash_table_lookup(duplicate_file->hash, &d) != NULL;
246
 
}
247
 
 
248
 
void duplicate_mark(const void *id, size_t id_size,
249
 
                    const char *user, time_t timestamp)
250
 
{
251
 
        struct duplicate *d;
252
 
        void *new_id;
253
 
 
254
 
        if (duplicate_file == NULL)
255
 
                duplicate_file = duplicate_new(home_expand(DUPLICATE_PATH));
256
 
 
257
 
        new_id = p_malloc(duplicate_file->pool, id_size);
258
 
        memcpy(new_id, id, id_size);
259
 
 
260
 
        d = p_new(duplicate_file->pool, struct duplicate, 1);
261
 
        d->id = new_id;
262
 
        d->id_size = id_size;
263
 
        d->user = p_strdup(duplicate_file->pool, user);
264
 
        d->time = timestamp;
265
 
 
266
 
        duplicate_file->changed = TRUE;
267
 
        hash_table_insert(duplicate_file->hash, d, d);
268
 
}
269
 
 
270
 
void duplicate_flush(void)
271
 
{
272
 
        struct duplicate_file *file = duplicate_file;
273
 
        struct duplicate_file_header hdr;
274
 
        struct duplicate_record_header rec;
275
 
        struct ostream *output;
276
 
        struct hash_iterate_context *iter;
277
 
        void *key, *value;
278
 
 
279
 
        if (duplicate_file == NULL || !file->changed || file->new_fd == -1)
280
 
                return;
281
 
 
282
 
        memset(&hdr, 0, sizeof(hdr));
283
 
        hdr.version = DUPLICATE_VERSION;
284
 
 
285
 
        output = o_stream_create_fd_file(file->new_fd, 0, FALSE);
286
 
        o_stream_send(output, &hdr, sizeof(hdr));
287
 
 
288
 
        memset(&rec, 0, sizeof(rec));
289
 
        iter = hash_table_iterate_init(file->hash);
290
 
        while (hash_table_iterate(iter, &key, &value)) {
291
 
                struct duplicate *d = value;
292
 
 
293
 
                rec.stamp = d->time;
294
 
                rec.id_size = d->id_size;
295
 
                rec.user_size = strlen(d->user);
296
 
 
297
 
                o_stream_send(output, &rec, sizeof(rec));
298
 
                o_stream_send(output, d->id, rec.id_size);
299
 
                o_stream_send(output, d->user, rec.user_size);
300
 
        }
301
 
        hash_table_iterate_deinit(&iter);
302
 
        o_stream_unref(&output);
303
 
 
304
 
        file->changed = FALSE;
305
 
        if (file_dotlock_replace(&file->dotlock, 0) < 0)
306
 
                i_error("file_dotlock_replace(%s) failed: %m", file->path);
307
 
        file->new_fd = -1;
308
 
}
309
 
 
310
 
void duplicate_init(void)
311
 
{
312
 
        duplicate_dotlock_set.use_excl_lock =
313
 
                getenv("DOTLOCK_USE_EXCL") != NULL;
314
 
        duplicate_dotlock_set.nfs_flush =
315
 
                getenv("MAIL_NFS_STORAGE") != NULL;
316
 
}
317
 
 
318
 
void duplicate_deinit(void)
319
 
{
320
 
        if (duplicate_file != NULL) {
321
 
                duplicate_flush();
322
 
                duplicate_free(&duplicate_file);
323
 
        }
324
 
}