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

« back to all changes in this revision

Viewing changes to src/imap/client.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:
8
8
#include "istream.h"
9
9
#include "ostream.h"
10
10
#include "var-expand.h"
 
11
#include "imap-resp-code.h"
 
12
#include "imap-util.h"
 
13
#include "mail-namespace.h"
11
14
#include "commands.h"
12
 
#include "mail-namespace.h"
13
15
 
14
16
#include <stdlib.h>
15
17
#include <unistd.h>
16
18
 
17
19
extern struct mail_storage_callbacks mail_storage_callbacks;
 
20
struct imap_module_register imap_module_register = { 0 };
18
21
 
19
22
static struct client *my_client; /* we don't need more than one currently */
20
23
 
21
 
static bool client_handle_input(struct client *client);
22
 
 
23
24
static void client_idle_timeout(struct client *client)
24
25
{
25
26
        if (client->output_lock == NULL)
27
28
        client_destroy(client, "Disconnected for inactivity");
28
29
}
29
30
 
30
 
struct client *client_create(int fd_in, int fd_out,
31
 
                             struct mail_namespace *namespaces)
 
31
struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
32
32
{
33
33
        struct client *client;
 
34
        struct mail_namespace *ns;
34
35
 
35
36
        /* always use nonblocking I/O */
36
37
        net_set_nonblock(fd_in, TRUE);
49
50
        client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
50
51
                                      client_idle_timeout, client);
51
52
 
52
 
        client->command_pool = pool_alloconly_create("client command", 1024*12);
53
 
        client->namespaces = namespaces;
 
53
        client->command_pool =
 
54
                pool_alloconly_create(MEMPOOL_GROWING"client command", 2048);
 
55
        client->user = user;
54
56
 
55
 
        while (namespaces != NULL) {
56
 
                mail_storage_set_callbacks(namespaces->storage,
 
57
        for (ns = user->namespaces; ns != NULL; ns = ns->next) {
 
58
                mail_storage_set_callbacks(ns->storage,
57
59
                                           &mail_storage_callbacks, client);
58
 
                namespaces = namespaces->next;
59
60
        }
60
61
 
61
62
        i_assert(my_client == NULL);
102
103
static const char *client_stats(struct client *client)
103
104
{
104
105
        static struct var_expand_table static_tab[] = {
105
 
                { 'i', NULL },
106
 
                { 'o', NULL },
107
 
                { '\0', NULL }
 
106
                { 'i', NULL, "input" },
 
107
                { 'o', NULL, "output" },
 
108
                { '\0', NULL, NULL }
108
109
        };
109
110
        struct var_expand_table *tab;
110
111
        string_t *str;
132
133
void client_destroy(struct client *client, const char *reason)
133
134
{
134
135
        struct client_command_context *cmd;
 
136
 
135
137
        i_assert(!client->destroyed);
136
138
        client->destroyed = TRUE;
137
139
 
159
161
        if (client->input_lock != NULL)
160
162
                client_command_cancel(&client->input_lock);
161
163
 
162
 
        if (client->mailbox != NULL)
 
164
        if (client->mailbox != NULL) {
 
165
                client_search_updates_free(client);
163
166
                mailbox_close(&client->mailbox);
164
 
        mail_namespaces_deinit(&client->namespaces);
 
167
        }
 
168
        mail_user_unref(&client->user);
165
169
 
166
170
        if (client->free_parser != NULL)
167
171
                imap_parser_destroy(&client->free_parser);
181
185
                        i_error("close(client out) failed: %m");
182
186
        }
183
187
 
 
188
        if (array_is_created(&client->search_saved_uidset))
 
189
                array_free(&client->search_saved_uidset);
 
190
        if (array_is_created(&client->search_updates))
 
191
                array_free(&client->search_updates);
184
192
        pool_unref(&client->command_pool);
185
193
        i_free(client);
186
194
 
295
303
bool client_read_args(struct client_command_context *cmd, unsigned int count,
296
304
                      unsigned int flags, const struct imap_arg **args_r)
297
305
{
 
306
        string_t *str;
298
307
        int ret;
299
308
 
300
309
        i_assert(count <= INT_MAX);
304
313
                /* all parameters read successfully */
305
314
                i_assert(cmd->client->input_lock == NULL ||
306
315
                         cmd->client->input_lock == cmd);
 
316
 
 
317
                str = t_str_new(256);
 
318
                imap_write_args(str, *args_r);
 
319
                cmd->args = p_strdup(cmd->pool, str_c(str));
 
320
 
307
321
                cmd->client->input_lock = NULL;
308
322
                return TRUE;
309
323
        } else if (ret == -2) {
357
371
 
358
372
static struct client_command_context *
359
373
client_command_find_with_flags(struct client_command_context *new_cmd,
360
 
                               enum command_flags flags)
 
374
                               enum command_flags flags,
 
375
                               enum client_command_state max_state)
361
376
{
362
377
        struct client_command_context *cmd;
363
378
 
364
379
        cmd = new_cmd->client->command_queue;
365
380
        for (; cmd != NULL; cmd = cmd->next) {
366
 
                if (cmd != new_cmd && (cmd->cmd_flags & flags) != 0)
 
381
                if (cmd->state <= max_state &&
 
382
                    cmd != new_cmd && (cmd->cmd_flags & flags) != 0)
367
383
                        return cmd;
368
384
        }
369
385
        return NULL;
372
388
static bool client_command_check_ambiguity(struct client_command_context *cmd)
373
389
{
374
390
        enum command_flags flags;
 
391
        enum client_command_state max_state =
 
392
                CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY;
375
393
        bool broken_client = FALSE;
376
394
 
 
395
        if ((cmd->cmd_flags & COMMAND_FLAG_REQUIRES_SYNC) != 0 &&
 
396
            !imap_sync_is_allowed(cmd->client))
 
397
                return TRUE;
 
398
 
377
399
        if ((cmd->cmd_flags & COMMAND_FLAG_BREAKS_MAILBOX) ==
378
400
            COMMAND_FLAG_BREAKS_MAILBOX) {
379
401
                /* there must be no other command running that uses the
380
402
                   selected mailbox */
381
403
                flags = COMMAND_FLAG_USES_MAILBOX;
 
404
                max_state = CLIENT_COMMAND_STATE_DONE;
382
405
        } else if ((cmd->cmd_flags & COMMAND_FLAG_USES_SEQS) != 0) {
383
406
                /* no existing command must be breaking sequences */
384
407
                flags = COMMAND_FLAG_BREAKS_SEQS;
390
413
                return FALSE;
391
414
        }
392
415
 
393
 
        if (client_command_find_with_flags(cmd, flags) == NULL) {
 
416
        if (client_command_find_with_flags(cmd, flags, max_state) == NULL) {
394
417
                if (cmd->client->syncing) {
395
418
                        /* don't do anything until syncing is finished */
396
419
                        return TRUE;
397
420
                }
 
421
                if (cmd->client->mailbox_change_lock != NULL &&
 
422
                    cmd->client->mailbox_change_lock != cmd) {
 
423
                        /* don't do anything until mailbox is fully
 
424
                           opened/closed */
 
425
                        return TRUE;
 
426
                }
398
427
                return FALSE;
399
428
        }
400
429
 
401
430
        if (broken_client) {
402
431
                client_send_line(cmd->client,
403
 
                        "* BAD Command pipelining results in ambiguity.");
 
432
                                 "* BAD ["IMAP_RESP_CODE_CLIENTBUG"] "
 
433
                                 "Command pipelining results in ambiguity.");
404
434
        }
405
435
 
406
436
        return TRUE;
414
444
        cmd = p_new(client->command_pool, struct client_command_context, 1);
415
445
        cmd->client = client;
416
446
        cmd->pool = client->command_pool;
 
447
        p_array_init(&cmd->module_contexts, cmd->pool, 5);
417
448
 
418
449
        if (client->free_parser != NULL) {
419
450
                cmd->parser = client->free_parser;
453
484
                client->input_lock = NULL;
454
485
        if (client->output_lock == cmd)
455
486
                client->output_lock = NULL;
 
487
        if (client->mailbox_change_lock == cmd)
 
488
                client->mailbox_change_lock = NULL;
456
489
 
457
490
        if (client->free_parser != NULL)
458
491
                imap_parser_destroy(&cmd->parser);
481
514
        }
482
515
}
483
516
 
484
 
void client_continue_pending_input(struct client **_client)
 
517
void client_continue_pending_input(struct client *client)
485
518
{
486
 
        struct client *client = *_client;
487
519
        size_t size;
488
520
 
489
521
        i_assert(!client->handling_input);
490
522
 
491
 
        if (client->disconnected) {
492
 
                if (!client->destroyed)
493
 
                        client_destroy(client, NULL);
494
 
                *_client = NULL;
495
 
                return;
496
 
        }
497
 
 
498
523
        if (client->input_lock != NULL) {
499
524
                /* there's a command that has locked the input */
500
525
                struct client_command_context *cmd = client->input_lock;
504
529
 
505
530
                /* the command is waiting for existing ambiguity causing
506
531
                   commands to finish. */
507
 
                if (client_command_check_ambiguity(cmd))
508
 
                        return;
 
532
                if (client_command_check_ambiguity(cmd)) {
 
533
                        /* we could be waiting for existing sync to finish */
 
534
                        if (!cmd_sync_delayed(client))
 
535
                                return;
 
536
                        if (client_command_check_ambiguity(cmd))
 
537
                                return;
 
538
                }
509
539
                cmd->state = CLIENT_COMMAND_STATE_WAIT_INPUT;
510
540
        }
511
541
 
513
543
 
514
544
        /* if there's unread data in buffer, handle it. */
515
545
        (void)i_stream_get_data(client->input, &size);
516
 
        if (size > 0)
517
 
                (void)client_handle_input(client);
 
546
        if (size > 0 && !client->disconnected) {
 
547
                if (client_handle_input(client))
 
548
                        client_continue_pending_input(client);
 
549
        }
518
550
}
519
551
 
520
552
/* Skip incoming data until newline is found,
670
702
        return client_command_input(client->input_lock);
671
703
}
672
704
 
673
 
static bool client_handle_input(struct client *client)
 
705
bool client_handle_input(struct client *client)
674
706
{
675
707
        bool ret, remove_io, handled_commands = FALSE;
676
708
 
 
709
        i_assert(!client->disconnected);
 
710
 
677
711
        client->handling_input = TRUE;
678
712
        do {
679
713
                T_BEGIN {
684
718
        } while (ret && !client->disconnected && client->io != NULL);
685
719
        client->handling_input = FALSE;
686
720
 
687
 
        if (client->output->closed) {
688
 
                client_destroy(client, NULL);
689
 
                return TRUE;
690
 
        } else {
691
 
                if (remove_io)
692
 
                        io_remove(&client->io);
693
 
                else
694
 
                        client_add_missing_io(client);
695
 
                if (!handled_commands)
696
 
                        return FALSE;
 
721
        if (remove_io)
 
722
                io_remove(&client->io);
 
723
        else
 
724
                client_add_missing_io(client);
 
725
        if (!handled_commands)
 
726
                return FALSE;
697
727
 
698
 
                ret = cmd_sync_delayed(client);
699
 
                if (ret)
700
 
                        client_continue_pending_input(&client);
701
 
                return TRUE;
702
 
        }
 
728
        if (client->input_lock == NULL)
 
729
                cmd_sync_delayed(client);
 
730
        return TRUE;
703
731
}
704
732
 
705
733
void client_input(struct client *client)
736
764
        }
737
765
        o_stream_uncork(output);
738
766
        o_stream_unref(&output);
 
767
 
 
768
        if (client->disconnected)
 
769
                client_destroy(client, NULL);
 
770
        else
 
771
                client_continue_pending_input(client);
739
772
}
740
773
 
741
774
static void client_output_cmd(struct client_command_context *cmd)
798
831
                }
799
832
        }
800
833
 
801
 
        if (client->output->closed) {
 
834
        (void)cmd_sync_delayed(client);
 
835
        o_stream_uncork(client->output);
 
836
        if (client->disconnected)
802
837
                client_destroy(client, NULL);
803
 
                return 1;
804
 
        } else {
805
 
                (void)cmd_sync_delayed(client);
806
 
                o_stream_uncork(client->output);
807
 
                client_continue_pending_input(&client);
808
 
                return ret;
809
 
        }
 
838
        else
 
839
                client_continue_pending_input(client);
 
840
        return ret;
 
841
}
 
842
 
 
843
bool client_handle_search_save_ambiguity(struct client_command_context *cmd)
 
844
{
 
845
        struct client_command_context *old_cmd = cmd->next;
 
846
 
 
847
        /* search only commands that were added before this command
 
848
           (commands are prepended to the queue, so they're after ourself) */
 
849
        for (; old_cmd != NULL; old_cmd = old_cmd->next) {
 
850
                if (old_cmd->search_save_result)
 
851
                        break;
 
852
        }
 
853
        if (old_cmd == NULL)
 
854
                return FALSE;
 
855
 
 
856
        /* ambiguity, wait until it's over */
 
857
        i_assert(cmd->state == CLIENT_COMMAND_STATE_WAIT_INPUT);
 
858
        cmd->client->input_lock = cmd;
 
859
        cmd->state = CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY;
 
860
        io_remove(&cmd->client->io);
 
861
        return TRUE;
 
862
}
 
863
 
 
864
void client_enable(struct client *client, enum mailbox_feature features)
 
865
{
 
866
        struct mailbox_status status;
 
867
 
 
868
        if ((client->enabled_features & features) == features)
 
869
                return;
 
870
 
 
871
        client->enabled_features |= features;
 
872
        if (client->mailbox == NULL)
 
873
                return;
 
874
 
 
875
        mailbox_enable(client->mailbox, features);
 
876
        if ((features & MAILBOX_FEATURE_CONDSTORE) != 0) {
 
877
                /* CONDSTORE being enabled while mailbox is selected.
 
878
                   Notify client of the latest HIGHESTMODSEQ. */
 
879
                mailbox_get_status(client->mailbox,
 
880
                                   STATUS_HIGHESTMODSEQ, &status);
 
881
                client_send_line(client, t_strdup_printf(
 
882
                        "* OK [HIGHESTMODSEQ %llu] Highest",
 
883
                        (unsigned long long)status.highest_modseq));
 
884
        }
 
885
}
 
886
 
 
887
struct imap_search_update *
 
888
client_search_update_lookup(struct client *client, const char *tag,
 
889
                            unsigned int *idx_r)
 
890
{
 
891
        struct imap_search_update *updates;
 
892
        unsigned int i, count;
 
893
 
 
894
        if (!array_is_created(&client->search_updates))
 
895
                return NULL;
 
896
 
 
897
        updates = array_get_modifiable(&client->search_updates, &count);
 
898
        for (i = 0; i < count; i++) {
 
899
                if (strcmp(updates[i].tag, tag) == 0) {
 
900
                        *idx_r = i;
 
901
                        return &updates[i];
 
902
                }
 
903
        }
 
904
        return NULL;
 
905
}
 
906
 
 
907
void client_search_updates_free(struct client *client)
 
908
{
 
909
        struct imap_search_update *updates;
 
910
        unsigned int i, count;
 
911
 
 
912
        if (!array_is_created(&client->search_updates))
 
913
                return;
 
914
 
 
915
        updates = array_get_modifiable(&client->search_updates, &count);
 
916
        for (i = 0; i < count; i++) {
 
917
                i_free(updates[i].tag);
 
918
                mailbox_search_result_free(&updates[i].result);
 
919
        }
 
920
        array_clear(&client->search_updates);
810
921
}
811
922
 
812
923
void clients_init(void)