~james-page/ubuntu/raring/dovecot/autopkgtest

« back to all changes in this revision

Viewing changes to src/pop3/pop3-client.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2012-06-11 11:11:54 UTC
  • mfrom: (1.15.2) (4.1.27 sid)
  • Revision ID: package-import@ubuntu.com-20120611111154-678cwbdj6ktgsv1h
Tags: 1:2.1.7-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/{control,rules}: enable PIE hardening.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + d/control: Added Pre-Depends: dpkg (>= 1.15.6) to dovecot-dbg to support
    xz compression in Ubuntu.
  + d/control: Demote dovecot-common Recommends: to Suggests: to prevent
    install of extra packages on upgrade.
  + d/patches/dovecot-drac.patch: Updated with version for dovecot >= 2.0.0.
  + d/control: Drop B-D on systemd.
* Dropped changes:
  + d/patches/fix-racey-restart.patch: part of 2.1.x, no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "pop3-common.h"
4
4
#include "array.h"
6
6
#include "network.h"
7
7
#include "istream.h"
8
8
#include "ostream.h"
 
9
#include "crc32.h"
9
10
#include "str.h"
10
11
#include "llist.h"
11
12
#include "hostpid.h"
72
73
static int
73
74
pop3_mail_get_size(struct client *client, struct mail *mail, uoff_t *size_r)
74
75
{
75
 
        struct mail_storage *storage;
76
76
        enum mail_error error;
77
77
        int ret;
78
78
 
86
86
        if (ret == 0)
87
87
                return 0;
88
88
 
89
 
        storage = mailbox_get_storage(mail->box);
90
 
        (void)mail_storage_get_last_error(storage, &error);
 
89
        (void)mailbox_get_last_error(mail->box, &error);
91
90
        if (error != MAIL_ERROR_NOTPOSSIBLE)
92
91
                return -1;
93
92
 
99
98
        if (ret == 0)
100
99
                return 0;
101
100
 
102
 
        (void)mail_storage_get_last_error(storage, &error);
 
101
        (void)mailbox_get_last_error(mail->box, &error);
103
102
        if (error != MAIL_ERROR_NOTPOSSIBLE)
104
103
                return -1;
105
104
 
120
119
 
121
120
        if (!array_is_created(msgnum_to_seq_map))
122
121
                i_array_init(msgnum_to_seq_map, client->messages_count);
123
 
        else {
124
 
                /* add any messages between this and the previous one that had
125
 
                   a POP3 order defined */
126
 
                seq = array_count(msgnum_to_seq_map) + 1;
127
 
                for (; seq <= msgnum; seq++)
128
 
                        array_append(msgnum_to_seq_map, &seq, 1);
129
 
        }
 
122
 
 
123
        /* add any messages between this and the previous one that had
 
124
           a POP3 order defined */
 
125
        seq = array_count(msgnum_to_seq_map) + 1;
 
126
        for (; seq <= msgnum; seq++)
 
127
                array_append(msgnum_to_seq_map, &seq, 1);
130
128
        array_append(msgnum_to_seq_map, &mail->seq, 1);
131
129
}
132
130
 
145
143
 
146
144
        *failed_uid_r = 0;
147
145
 
148
 
        mailbox_get_status(client->mailbox, STATUS_UIDVALIDITY, &status);
 
146
        mailbox_get_open_status(client->mailbox, STATUS_UIDVALIDITY, &status);
149
147
        client->uid_validity = status.uidvalidity;
150
148
        client->messages_count = status.messages;
151
149
 
153
151
 
154
152
        search_args = mail_search_build_init();
155
153
        mail_search_build_add_all(search_args);
156
 
        ctx = mailbox_search_init(t, search_args, pop3_sort_program);
 
154
        ctx = mailbox_search_init(t, search_args, pop3_sort_program,
 
155
                                  client->set->pop3_fast_size_lookups ? 0 :
 
156
                                  MAIL_FETCH_VIRTUAL_SIZE, NULL);
157
157
        mail_search_args_unref(&search_args);
158
158
 
159
159
        client->last_seen_pop3_msn = 0;
161
161
        i_array_init(&message_sizes, client->messages_count);
162
162
 
163
163
        msgnum = 0;
164
 
        mail = mail_alloc(t, MAIL_FETCH_VIRTUAL_SIZE, NULL);
165
 
        while (mailbox_search_next(ctx, mail)) {
 
164
        while (mailbox_search_next(ctx, &mail)) {
166
165
                if (pop3_mail_get_size(client, mail, &size) < 0) {
167
166
                        ret = mail->expunged ? 0 : -1;
168
167
                        *failed_uid_r = mail->uid;
177
176
                array_append(&message_sizes, &size, 1);
178
177
                msgnum++;
179
178
        }
180
 
        mail_free(&mail);
181
179
 
182
180
        if (mailbox_search_deinit(&ctx) < 0)
183
181
                ret = -1;
191
189
                        array_free(&msgnum_to_seq_map);
192
190
                return ret;
193
191
        }
 
192
        i_assert(msgnum == client->messages_count);
194
193
 
195
194
        client->trans = t;
196
195
        client->message_sizes =
228
227
        }
229
228
 
230
229
        if (ret < 0) {
231
 
                struct mail_storage *storage;
232
 
                enum mail_error error;
233
 
 
234
 
                storage = mailbox_get_storage(client->mailbox);
235
 
                *error_r = mail_storage_get_last_error(storage, &error);
 
230
                *error_r = mailbox_get_last_error(client->mailbox, NULL);
236
231
                client_send_storage_error(client);
237
232
        } else {
238
233
                if (failed_uid == last_failed_uid && failed_uid != 0) {
277
272
        return mask;
278
273
}
279
274
 
280
 
struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
 
275
struct client *client_create(int fd_in, int fd_out, const char *session_id,
 
276
                             struct mail_user *user,
281
277
                             struct mail_storage_service_user *service_user,
282
278
                             const struct pop3_settings *set)
283
279
{
284
280
        struct mail_namespace *ns;
285
281
        struct mail_storage *storage;
286
 
        const char *inbox, *ident;
 
282
        const char *ident;
287
283
        struct client *client;
288
284
        enum mailbox_flags flags;
289
285
        const char *errmsg;
296
292
        client = i_new(struct client, 1);
297
293
        client->service_user = service_user;
298
294
        client->set = set;
 
295
        client->session_id = i_strdup(session_id);
299
296
        client->fd_in = fd_in;
300
297
        client->fd_out = fd_out;
301
298
        client->input = i_stream_create_fd(fd_in, MAX_INBUF_SIZE, FALSE);
316
313
        pop3_client_count++;
317
314
        DLLIST_PREPEND(&pop3_clients, client);
318
315
 
319
 
        inbox = "INBOX";
320
 
        ns = mail_namespace_find(user->namespaces, &inbox);
 
316
        ns = mail_namespace_find(user->namespaces, "INBOX");
321
317
        if (ns == NULL) {
322
318
                client_send_line(client, "-ERR [IN-USE] No INBOX namespace for user.");
323
319
                client_destroy(client, "No INBOX namespace for user.");
326
322
        client->inbox_ns = ns;
327
323
 
328
324
        flags = MAILBOX_FLAG_POP3_SESSION;
329
 
        if (set->pop3_no_flag_updates)
330
 
                flags |= MAILBOX_FLAG_KEEP_RECENT;
 
325
        if (!set->pop3_no_flag_updates)
 
326
                flags |= MAILBOX_FLAG_DROP_RECENT;
331
327
        if (set->pop3_lock_session)
332
328
                flags |= MAILBOX_FLAG_KEEP_LOCKED;
333
329
        client->mailbox = mailbox_alloc(ns->list, "INBOX", flags);
334
330
        storage = mailbox_get_storage(client->mailbox);
335
331
        if (mailbox_open(client->mailbox) < 0) {
336
332
                errmsg = t_strdup_printf("Couldn't open INBOX: %s",
337
 
                                         mail_storage_get_last_error(storage,
338
 
                                                                     &error));
 
333
                                         mailbox_get_last_error(client->mailbox,
 
334
                                                                &error));
339
335
                i_error("%s", errmsg);
340
336
                client_send_line(client, "-ERR [IN-USE] %s", errmsg);
341
337
                client_destroy(client, "Couldn't open INBOX");
349
345
                return NULL;
350
346
        }
351
347
 
352
 
        if (var_has_key(set->pop3_logout_format, 'u', "uidl_change") &&
353
 
            client->messages_count > 0)
354
 
                client->message_uidl_hashes_save = TRUE;
355
 
 
356
348
        client->uidl_keymask =
357
349
                parse_uidl_keymask(client->mail_set->pop3_uidl_format);
358
350
        if (client->uidl_keymask == 0)
359
351
                i_fatal("Invalid pop3_uidl_format");
360
352
 
 
353
        if (var_has_key(set->pop3_logout_format, 'u', "uidl_change")) {
 
354
                /* logging uidl_change. we need hashes of the UIDLs */
 
355
                client->message_uidls_save = TRUE;
 
356
        } else if (strcmp(set->pop3_uidl_duplicates, "allow") != 0) {
 
357
                /* UIDL duplicates aren't allowed, so we'll need to
 
358
                   keep track of them */
 
359
                client->message_uidls_save = TRUE;
 
360
        }
 
361
 
361
362
        if (!set->pop3_no_flag_updates && client->messages_count > 0)
362
363
                client->seen_bitmask = i_malloc(MSGS_BITMASK_SIZE(client));
363
364
 
380
381
        uint32_t i, old_hash, new_hash;
381
382
        unsigned int old_msg_count, new_msg_count;
382
383
 
383
 
        if (client->message_uidl_hashes == NULL) {
384
 
                /* UIDL command not given or %u not actually used in format */
385
 
                return "";
386
 
        }
387
 
        if (client->message_uidl_hashes_save) {
388
 
                /* UIDL command not finished */
 
384
        if (client->message_uidls == NULL) {
 
385
                /* UIDL command not given */
389
386
                return "";
390
387
        }
391
388
 
393
390
        old_msg_count = client->lowest_retr_pop3_msn > 0 ?
394
391
                client->lowest_retr_pop3_msn - 1 : client->messages_count;
395
392
        for (i = 0, old_hash = 0; i < old_msg_count; i++)
396
 
                old_hash ^= client->message_uidl_hashes[i];
 
393
                old_hash ^= crc32_str(client->message_uidls[i]);
397
394
 
398
395
        /* assume all except deleted messages were sent to POP3 client */
399
396
        if (!client->deleted) {
400
397
                for (i = 0, new_hash = 0; i < client->messages_count; i++)
401
 
                        new_hash ^= client->message_uidl_hashes[i];
 
398
                        new_hash ^= crc32_str(client->message_uidls[i]);
402
399
        } else {
403
400
                for (i = 0, new_hash = 0; i < client->messages_count; i++) {
404
401
                        if (client->deleted_bitmask[i / CHAR_BIT] &
405
402
                            (1 << (i % CHAR_BIT)))
406
403
                                continue;
407
 
                        new_hash ^= client->message_uidl_hashes[i];
 
404
                        new_hash ^= crc32_str(client->message_uidls[i]);
408
405
                }
409
406
        }
410
407
 
431
428
                { 'i', NULL, "input" },
432
429
                { 'o', NULL, "output" },
433
430
                { 'u', NULL, "uidl_change" },
 
431
                { '\0', NULL, "session" },
434
432
                { '\0', NULL, NULL }
435
433
        };
436
434
        struct var_expand_table *tab;
448
446
        tab[6].value = dec2str(client->total_size);
449
447
        tab[7].value = dec2str(client->input->v_offset);
450
448
        tab[8].value = dec2str(client->output->offset);
451
 
        tab[9].value = client_build_uidl_change_string(client);
 
449
        if (var_has_key(client->set->pop3_logout_format,
 
450
                        tab[9].key, tab[9].long_key))
 
451
                tab[9].value = client_build_uidl_change_string(client);
 
452
        else
 
453
                tab[9].value = "";
 
454
        tab[10].value = client->session_id;
452
455
 
453
456
        str = t_str_new(128);
454
457
        var_expand(str, client->set->pop3_logout_format, tab);
501
504
        }
502
505
        mail_user_unref(&client->user);
503
506
 
 
507
        if (client->uidl_pool != NULL)
 
508
                pool_unref(&client->uidl_pool);
504
509
        i_free(client->message_sizes);
505
 
        i_free(client->message_uidl_hashes);
506
510
        i_free(client->deleted_bitmask);
507
511
        i_free(client->seen_bitmask);
508
512
        i_free(client->msgnum_to_seq_map);
520
524
        if (client->fd_in != client->fd_out)
521
525
                net_disconnect(client->fd_out);
522
526
        mail_storage_service_user_free(&client->service_user);
 
527
        i_free(client->session_id);
523
528
        i_free(client);
524
529
 
525
530
        master_service_client_connection_destroyed(master_service);
597
602
 
598
603
void client_send_storage_error(struct client *client)
599
604
{
600
 
        struct mail_storage *storage;
601
 
        enum mail_error error;
602
 
 
603
605
        if (mailbox_is_inconsistent(client->mailbox)) {
604
606
                client_send_line(client, "-ERR Mailbox is in inconsistent "
605
607
                                 "state, please relogin.");
607
609
                return;
608
610
        }
609
611
 
610
 
        storage = mailbox_get_storage(client->mailbox);
611
612
        client_send_line(client, "-ERR %s",
612
 
                         mail_storage_get_last_error(storage, &error));
 
613
                         mailbox_get_last_error(client->mailbox, NULL));
613
614
}
614
615
 
615
616
bool client_handle_input(struct client *client)