From dovecot at dovecot.org Mon Dec 2 18:48:05 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Mon, 02 Dec 2013 18:48:05 +0200 Subject: dovecot-2.2: pop3: Handle UIDL failures by disconnecting the cli... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/0c9ab8cf9c1a changeset: 17035:0c9ab8cf9c1a user: Timo Sirainen date: Mon Dec 02 18:47:52 2013 +0200 description: pop3: Handle UIDL failures by disconnecting the client instead of killing the whole process. diffstat: src/pop3/pop3-commands.c | 80 ++++++++++++++++++++++++++++++++--------------- 1 files changed, 54 insertions(+), 26 deletions(-) diffs (183 lines): diff -r 5c170e0786f3 -r 0c9ab8cf9c1a src/pop3/pop3-commands.c --- a/src/pop3/pop3-commands.c Tue Nov 26 21:10:23 2013 +0100 +++ b/src/pop3/pop3-commands.c Mon Dec 02 18:47:52 2013 +0200 @@ -558,7 +558,7 @@ bool list_all; }; -static void +static int pop3_get_uid(struct client *client, struct mail *mail, string_t *str, bool *permanent_uidl_r) { @@ -579,7 +579,7 @@ str_append(str, uidl); /* UIDL is already permanent */ *permanent_uidl_r = TRUE; - return; + return 0; } *permanent_uidl_r = FALSE; @@ -587,7 +587,7 @@ if (client->set->pop3_reuse_xuidl && mail_get_first_header(mail, "X-UIDL", &uidl) > 0) { str_append(str, uidl); - return; + return 0; } tab = t_malloc(sizeof(static_tab)); @@ -595,39 +595,48 @@ tab[0].value = t_strdup_printf("%u", client->uid_validity); if ((client->uidl_keymask & UIDL_UID) != 0) { - if (i_snprintf(uid_str, sizeof(uid_str), "%u", - mail->uid) < 0) + if (i_snprintf(uid_str, sizeof(uid_str), "%u", mail->uid) < 0) i_unreached(); tab[1].value = uid_str; } if ((client->uidl_keymask & UIDL_MD5) != 0) { if (mail_get_special(mail, MAIL_FETCH_HEADER_MD5, - &tab[2].value) < 0 || - *tab[2].value == '\0') { - /* broken */ - i_fatal("UIDL: Header MD5 not found " + &tab[2].value) < 0) { + i_error("UIDL: Header MD5 lookup failed: %s", + mailbox_get_last_error(mail->box, NULL)); + return -1; + } else if (*tab[2].value == '\0') { + i_error("UIDL: Header MD5 not found " "(pop3_uidl_format=%%m not supported by storage?)"); + return -1; } } if ((client->uidl_keymask & UIDL_FILE_NAME) != 0) { if (mail_get_special(mail, MAIL_FETCH_UIDL_FILE_NAME, - &tab[3].value) < 0 || - *tab[3].value == '\0') { - /* broken */ - i_fatal("UIDL: File name not found " + &tab[3].value) < 0) { + i_error("UIDL: File name lookup failed: %s", + mailbox_get_last_error(mail->box, NULL)); + return -1; + } else if (*tab[3].value == '\0') { + i_error("UIDL: File name not found " "(pop3_uidl_format=%%f not supported by storage?)"); + return -1; } } if ((client->uidl_keymask & UIDL_GUID) != 0) { if (mail_get_special(mail, MAIL_FETCH_GUID, - &tab[4].value) < 0 || - *tab[4].value == '\0') { - /* broken */ - i_fatal("UIDL: Message GUID not found " + &tab[4].value) < 0) { + i_error("UIDL: Message GUID lookup failed: %s", + mailbox_get_last_error(mail->box, NULL)); + return -1; + } else if (*tab[4].value == '\0') { + i_error("UIDL: Message GUID not found " "(pop3_uidl_format=%%g not supported by storage?)"); + return -1; } } var_expand(str, client->mail_set->pop3_uidl_format, tab); + return 0; } static bool @@ -669,6 +678,7 @@ { string_t *str; bool permanent_uidl, found = FALSE; + bool failed = FALSE; if (client->message_uidls != NULL) return list_uidls_saved_iter(client, ctx); @@ -677,8 +687,10 @@ while (mailbox_search_next(ctx->search_ctx, &ctx->mail)) { uint32_t msgnum = ctx->msgnum++; - if (client_verify_ordering(client, ctx->mail, msgnum) < 0) - i_fatal("Can't finish POP3 UIDL command"); + if (client_verify_ordering(client, ctx->mail, msgnum) < 0) { + failed = TRUE; + break; + } if (client->deleted) { if (client->deleted_bitmask[msgnum / CHAR_BIT] & (1 << (msgnum % CHAR_BIT))) @@ -687,7 +699,10 @@ found = TRUE; str_truncate(str, 0); - pop3_get_uid(client, ctx->mail, str, &permanent_uidl); + if (pop3_get_uid(client, ctx->mail, str, &permanent_uidl) < 0) { + failed = TRUE; + break; + } if (client->set->pop3_save_uidl && !permanent_uidl) mail_update_pop3_uidl(ctx->mail, str_c(str)); @@ -707,10 +722,12 @@ client->cmd = NULL; - if (ctx->list_all) + if (ctx->list_all && !failed) client_send_line(client, "."); i_free(ctx); - return found; + if (failed) + client_disconnect(client, "POP3 UIDLs couldn't be listed"); + return found || failed; } static void cmd_uidl_callback(struct client *client) @@ -749,7 +766,7 @@ char *uidl; enum mail_fetch_field wanted_fields; uint32_t msgnum; - bool permanent_uidl, uidl_duplicates_rename; + bool permanent_uidl, uidl_duplicates_rename, failed = FALSE; i_assert(client->message_uidls == NULL); @@ -772,11 +789,17 @@ str = t_str_new(128); msgnum = 0; while (mailbox_search_next(search_ctx, &mail)) { - if (client_verify_ordering(client, mail, msgnum) < 0) - i_fatal("Can't finish POP3 UIDL command"); + if (client_verify_ordering(client, mail, msgnum) < 0) { + failed = TRUE; + break; + } str_truncate(str, 0); - pop3_get_uid(client, mail, str, &permanent_uidl); + if (pop3_get_uid(client, mail, str, &permanent_uidl) < 0) { + failed = TRUE; + break; + } + if (client->set->pop3_save_uidl && !permanent_uidl) mail_update_pop3_uidl(mail, str_c(str)); @@ -789,6 +812,11 @@ } (void)mailbox_search_deinit(&search_ctx); hash_table_destroy(&prev_uidls); + + if (failed) { + pool_unref(&client->uidl_pool); + client->message_uidls = NULL; + } } static struct cmd_uidl_context * From dovecot at dovecot.org Tue Dec 3 01:33:48 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Tue, 03 Dec 2013 01:33:48 +0200 Subject: dovecot-2.2: imap: Don't send [NOMODSEQ] on SELECT/EXAMINE reply... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/7171fd6732e1 changeset: 17036:7171fd6732e1 user: Timo Sirainen date: Tue Dec 03 01:33:18 2013 +0200 description: imap: Don't send [NOMODSEQ] on SELECT/EXAMINE reply when condstore hasn't been enabled yet. This is definitely the better behavior and was also clearly intended by the CONDSTORE RFC, although with some mixed language. diffstat: src/imap/cmd-select.c | 2 +- src/lib-storage/index/index-status.c | 3 ++- src/lib-storage/mail-storage.h | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diffs (38 lines): diff -r 0c9ab8cf9c1a -r 7171fd6732e1 src/imap/cmd-select.c --- a/src/imap/cmd-select.c Mon Dec 02 18:47:52 2013 +0200 +++ b/src/imap/cmd-select.c Tue Dec 03 01:33:18 2013 +0200 @@ -353,7 +353,7 @@ if (status.nonpermanent_modseqs) { client_send_line(client, "* OK [NOMODSEQ] No permanent modsequences"); - } else { + } else if (!status.no_modseq_tracking) { client_send_line(client, t_strdup_printf("* OK [HIGHESTMODSEQ %llu] Highest", (unsigned long long)status.highest_modseq)); diff -r 0c9ab8cf9c1a -r 7171fd6732e1 src/lib-storage/index/index-status.c --- a/src/lib-storage/index/index-status.c Mon Dec 02 18:47:52 2013 +0200 +++ b/src/lib-storage/index/index-status.c Tue Dec 03 01:33:18 2013 +0200 @@ -138,7 +138,8 @@ status_r->first_recent_uid = hdr->first_recent_uid; if ((items & STATUS_HIGHESTMODSEQ) != 0) { status_r->nonpermanent_modseqs = - mail_index_is_in_memory(box->index) || + mail_index_is_in_memory(box->index); + status_r->no_modseq_tracking = !mail_index_have_modseq_tracking(box->index); status_r->highest_modseq = mail_index_modseq_get_highest(box->view); diff -r 0c9ab8cf9c1a -r 7171fd6732e1 src/lib-storage/mail-storage.h --- a/src/lib-storage/mail-storage.h Mon Dec 02 18:47:52 2013 +0200 +++ b/src/lib-storage/mail-storage.h Tue Dec 03 01:33:18 2013 +0200 @@ -277,6 +277,9 @@ unsigned int allow_new_keywords:1; /* Modseqs aren't permanent (index is in memory) (STATUS_HIGHESTMODSEQ) */ unsigned int nonpermanent_modseqs:1; + /* Modseq tracking has never been enabled for this mailbox + yet. (STATUS_HIGHESTMODSEQ) */ + unsigned int no_modseq_tracking:1; /* Messages have GUIDs (always set) */ unsigned int have_guids:1; From dovecot at dovecot.org Tue Dec 3 17:17:16 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Tue, 03 Dec 2013 17:17:16 +0200 Subject: dovecot-2.2: lib-http: Removed assert Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/21d96c97f519 changeset: 17037:21d96c97f519 user: Timo Sirainen date: Tue Dec 03 17:17:03 2013 +0200 description: lib-http: Removed assert Time can't be relied on exactly. diffstat: src/lib-http/http-client-queue.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diffs (11 lines): diff -r 7171fd6732e1 -r 21d96c97f519 src/lib-http/http-client-queue.c --- a/src/lib-http/http-client-queue.c Tue Dec 03 01:33:18 2013 +0200 +++ b/src/lib-http/http-client-queue.c Tue Dec 03 17:17:03 2013 +0200 @@ -359,7 +359,6 @@ http_client_queue_submit_now(queue, reqs[i]); finished++; } - i_assert(finished > 0); if (i < count) { http_client_queue_set_delay_timer(queue, reqs[i]->release_time); } From dovecot at dovecot.org Tue Dec 3 17:29:52 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Tue, 03 Dec 2013 17:29:52 +0200 Subject: dovecot-2.2: imap: If SELECT fails with "mailbox is inconsistent... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/9946079253c4 changeset: 17038:9946079253c4 user: Timo Sirainen date: Tue Dec 03 17:29:38 2013 +0200 description: imap: If SELECT fails with "mailbox is inconsistent", disconnect client. (Plus related cleanups.) The inconsistency can also be used to indicate that something is badly wrong and nothing useful can be done before client reconnects. diffstat: src/imap/cmd-append.c | 23 ++++++++++------------- src/imap/cmd-create.c | 2 +- src/imap/cmd-delete.c | 2 +- src/imap/cmd-expunge.c | 3 +-- src/imap/cmd-getmetadata.c | 2 +- src/imap/cmd-rename.c | 2 +- src/imap/cmd-resetkey.c | 2 +- src/imap/cmd-select.c | 15 +++++---------- src/imap/cmd-setmetadata.c | 7 +++---- src/imap/cmd-store.c | 6 ++---- src/imap/cmd-subscribe.c | 4 ++-- src/imap/cmd-thread.c | 3 +-- src/imap/imap-commands-util.c | 16 ++++++++++++++-- src/imap/imap-commands-util.h | 3 +++ src/imap/imap-search.c | 3 +-- 15 files changed, 47 insertions(+), 46 deletions(-) diffs (truncated from 372 to 300 lines): diff -r 21d96c97f519 -r 9946079253c4 src/imap/cmd-append.c --- a/src/imap/cmd-append.c Tue Dec 03 17:17:03 2013 +0200 +++ b/src/imap/cmd-append.c Tue Dec 03 17:29:38 2013 +0200 @@ -26,7 +26,6 @@ struct cmd_append_context { struct client *client; struct client_command_context *cmd; - struct mail_storage *storage; struct mailbox *box; struct mailbox_transaction_context *t; time_t started; @@ -181,7 +180,7 @@ /* catenate URL */ ret = imap_msgpart_url_read_part(mpurl, &mpresult, &error); if (ret < 0) { - client_send_storage_error(cmd, ctx->storage); + client_send_box_error(cmd, ctx->box); return -1; } if (ret == 0) { @@ -219,11 +218,11 @@ "read(%s) failed: %s (for CATENATE URL %s)", i_stream_get_name(mpresult.input), i_stream_get_error(mpresult.input), caturl); - client_send_storage_error(cmd, ctx->storage); + client_send_box_error(cmd, ctx->box); ret = -1; } else if (!mpresult.input->eof) { /* save failed */ - client_send_storage_error(cmd, ctx->storage); + client_send_box_error(cmd, ctx->box); ret = -1; } else { /* all the input must be consumed, so istream-chain's read() @@ -248,7 +247,7 @@ ret = imap_msgpart_url_parse(cmd->client->user, cmd->client->mailbox, caturl, &mpurl, &error); if (ret < 0) { - client_send_storage_error(cmd, ctx->storage); + client_send_box_error(cmd, ctx->box); return -1; } if (ret == 0) { @@ -356,7 +355,7 @@ mailbox_save_cancel(&ctx->save_ctx); } else { if (mailbox_save_finish(&ctx->save_ctx) < 0) { - client_send_storage_error(cmd, ctx->storage); + client_send_box_error(cmd, ctx->box); ctx->failed = TRUE; } } @@ -532,7 +531,7 @@ else if (mailbox_keywords_create(ctx->box, keywords_list, &keywords) < 0) { /* invalid keywords - delay failure */ - client_send_storage_error(cmd, ctx->storage); + client_send_box_error(cmd, ctx->box); ctx->failed = TRUE; } } @@ -594,7 +593,7 @@ internal_date, timezone_offset); if (mailbox_save_begin(&ctx->save_ctx, ctx->input) < 0) { /* save initialization failed */ - client_send_storage_error(cmd, ctx->storage); + client_send_box_error(cmd, ctx->box); ctx->failed = TRUE; } } @@ -649,7 +648,7 @@ ret = mailbox_transaction_commit_get_changes(&ctx->t, &changes); if (ret < 0) { - client_send_storage_error(cmd, ctx->storage); + client_send_box_error(cmd, ctx->box); cmd_append_finish(ctx); return TRUE; } @@ -845,7 +844,7 @@ mailbox_save_cancel(&ctx->save_ctx); } else if (ctx->save_ctx == NULL) { /* failed above */ - client_send_storage_error(cmd, ctx->storage); + client_send_box_error(cmd, ctx->box); ctx->failed = TRUE; } else if (lit_offset != ctx->literal_size) { /* client disconnected before it finished sending the @@ -857,7 +856,7 @@ } else if (ctx->catenate) { /* CATENATE isn't finished yet */ } else if (mailbox_save_finish(&ctx->save_ctx) < 0) { - client_send_storage_error(cmd, ctx->storage); + client_send_box_error(cmd, ctx->box); ctx->failed = TRUE; } @@ -909,8 +908,6 @@ if (client_open_save_dest_box(cmd, mailbox, &ctx->box) < 0) ctx->failed = TRUE; else { - ctx->storage = mailbox_get_storage(ctx->box); - ctx->t = mailbox_transaction_begin(ctx->box, MAILBOX_TRANSACTION_FLAG_EXTERNAL | MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS); diff -r 21d96c97f519 -r 9946079253c4 src/imap/cmd-create.c --- a/src/imap/cmd-create.c Tue Dec 03 17:17:03 2013 +0200 +++ b/src/imap/cmd-create.c Tue Dec 03 17:29:38 2013 +0200 @@ -39,7 +39,7 @@ box = mailbox_alloc(ns->list, mailbox, 0); if (mailbox_create(box, NULL, directory) < 0) - client_send_storage_error(cmd, mailbox_get_storage(box)); + client_send_box_error(cmd, box); else client_send_tagline(cmd, "OK Create completed."); mailbox_free(&box); diff -r 21d96c97f519 -r 9946079253c4 src/imap/cmd-delete.c --- a/src/imap/cmd-delete.c Tue Dec 03 17:17:03 2013 +0200 +++ b/src/imap/cmd-delete.c Tue Dec 03 17:29:38 2013 +0200 @@ -41,7 +41,7 @@ else { errstr = mailbox_get_last_error(box, &error); if (error != MAIL_ERROR_EXISTS) - client_send_storage_error(cmd, mailbox_get_storage(box)); + client_send_box_error(cmd, box); else { /* mailbox has children */ client_send_tagline(cmd, t_strdup_printf("NO %s", errstr)); diff -r 21d96c97f519 -r 9946079253c4 src/imap/cmd-expunge.c --- a/src/imap/cmd-expunge.c Tue Dec 03 17:17:03 2013 +0200 +++ b/src/imap/cmd-expunge.c Tue Dec 03 17:29:38 2013 +0200 @@ -35,8 +35,7 @@ if (ret < 0) { errstr = mailbox_get_last_error(client->mailbox, &error); if (error != MAIL_ERROR_PERM) { - client_send_storage_error(cmd, - mailbox_get_storage(client->mailbox)); + client_send_box_error(cmd, client->mailbox); return TRUE; } else { return cmd_sync(cmd, 0, IMAP_SYNC_FLAG_SAFE, diff -r 21d96c97f519 -r 9946079253c4 src/imap/cmd-getmetadata.c --- a/src/imap/cmd-getmetadata.c Tue Dec 03 17:17:03 2013 +0200 +++ b/src/imap/cmd-getmetadata.c Tue Dec 03 17:29:38 2013 +0200 @@ -374,7 +374,7 @@ ctx->box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY); if (mailbox_open(ctx->box) < 0) { - client_send_storage_error(cmd, mailbox_get_storage(ctx->box)); + client_send_box_error(cmd, ctx->box); mailbox_free(&ctx->box); return TRUE; } diff -r 21d96c97f519 -r 9946079253c4 src/imap/cmd-rename.c --- a/src/imap/cmd-rename.c Tue Dec 03 17:17:03 2013 +0200 +++ b/src/imap/cmd-rename.c Tue Dec 03 17:29:38 2013 +0200 @@ -38,7 +38,7 @@ old_box = mailbox_alloc(old_ns->list, oldname, 0); new_box = mailbox_alloc(new_ns->list, newname, 0); if (mailbox_rename(old_box, new_box) < 0) - client_send_storage_error(cmd, mailbox_get_storage(old_box)); + client_send_box_error(cmd, old_box); else client_send_tagline(cmd, "OK Rename completed."); mailbox_free(&old_box); diff -r 21d96c97f519 -r 9946079253c4 src/imap/cmd-resetkey.c --- a/src/imap/cmd-resetkey.c Tue Dec 03 17:17:03 2013 +0200 +++ b/src/imap/cmd-resetkey.c Tue Dec 03 17:29:38 2013 +0200 @@ -50,7 +50,7 @@ /* open mailbox */ box = mailbox_alloc(ns->list, mailbox, flags); if (mailbox_open(box) < 0) { - client_send_storage_error(cmd, mailbox_get_storage(box)); + client_send_box_error(cmd, box); mailbox_free(&box); return TRUE; } diff -r 21d96c97f519 -r 9946079253c4 src/imap/cmd-select.c --- a/src/imap/cmd-select.c Tue Dec 03 17:17:03 2013 +0200 +++ b/src/imap/cmd-select.c Tue Dec 03 17:29:38 2013 +0200 @@ -233,10 +233,8 @@ } ret = imap_fetch_end(ctx->fetch_ctx); - if (ret < 0) { - client_send_storage_error(ctx->cmd, - mailbox_get_storage(ctx->box)); - } + if (ret < 0) + client_send_box_error(ctx->cmd, ctx->box); imap_fetch_free(&ctx->fetch_ctx); cmd_select_finish(ctx, ret); return TRUE; @@ -302,8 +300,7 @@ flags |= MAILBOX_FLAG_DROP_RECENT; ctx->box = mailbox_alloc(ctx->ns->list, mailbox, flags); if (mailbox_open(ctx->box) < 0) { - client_send_storage_error(ctx->cmd, - mailbox_get_storage(ctx->box)); + client_send_box_error(ctx->cmd, ctx->box); mailbox_free(&ctx->box); return -1; } @@ -312,8 +309,7 @@ ret = mailbox_enable(ctx->box, client->enabled_features); if (ret < 0 || mailbox_sync(ctx->box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) { - client_send_storage_error(ctx->cmd, - mailbox_get_storage(ctx->box)); + client_send_box_error(ctx->cmd, ctx->box); return -1; } mailbox_get_open_status(ctx->box, STATUS_MESSAGES | STATUS_RECENT | @@ -363,8 +359,7 @@ if (ctx->qresync_uid_validity == status.uidvalidity && status.uidvalidity != 0) { if ((ret = select_qresync(ctx)) < 0) { - client_send_storage_error(ctx->cmd, - mailbox_get_storage(ctx->box)); + client_send_box_error(ctx->cmd, ctx->box); return -1; } } else { diff -r 21d96c97f519 -r 9946079253c4 src/imap/cmd-setmetadata.c --- a/src/imap/cmd-setmetadata.c Tue Dec 03 17:17:03 2013 +0200 +++ b/src/imap/cmd-setmetadata.c Tue Dec 03 17:29:38 2013 +0200 @@ -244,9 +244,9 @@ if (ret < 0 || ctx->cmd_error_sent) /* already sent the error to client */ ; else if (ctx->storage_failure) - client_send_storage_error(cmd, mailbox_get_storage(ctx->box)); + client_send_box_error(cmd, ctx->box); else if (mailbox_transaction_commit(&ctx->trans) < 0) - client_send_storage_error(cmd, mailbox_get_storage(ctx->box)); + client_send_box_error(cmd, ctx->box); else client_send_tagline(cmd, "OK Setmetadata completed."); cmd_setmetadata_deinit(ctx); @@ -301,8 +301,7 @@ else { ctx->box = mailbox_alloc(ns->list, mailbox, 0); if (mailbox_open(ctx->box) < 0) { - client_send_storage_error(cmd, - mailbox_get_storage(ctx->box)); + client_send_box_error(cmd, ctx->box); mailbox_free(&ctx->box); return TRUE; } diff -r 21d96c97f519 -r 9946079253c4 src/imap/cmd-store.c --- a/src/imap/cmd-store.c Tue Dec 03 17:17:03 2013 +0200 +++ b/src/imap/cmd-store.c Tue Dec 03 17:29:38 2013 +0200 @@ -109,8 +109,7 @@ if (mailbox_keywords_create(cmd->client->mailbox, keywords_list, &ctx->keywords) < 0) { /* invalid keywords */ - client_send_storage_error(cmd, - mailbox_get_storage(cmd->client->mailbox)); + client_send_box_error(cmd, cmd->client->mailbox); return FALSE; } } @@ -211,8 +210,7 @@ ret = mailbox_transaction_commit(&t); if (ret < 0) { array_free(&modified_set); - client_send_storage_error(cmd, - mailbox_get_storage(client->mailbox)); + client_send_box_error(cmd, client->mailbox); return TRUE; } diff -r 21d96c97f519 -r 9946079253c4 src/imap/cmd-subscribe.c --- a/src/imap/cmd-subscribe.c Tue Dec 03 17:17:03 2013 +0200 +++ b/src/imap/cmd-subscribe.c Tue Dec 03 17:29:38 2013 +0200 @@ -12,7 +12,7 @@ int ret; if ((ret = mailbox_exists(box, TRUE, &existence)) < 0) { - client_send_storage_error(cmd, mailbox_get_storage(box)); + client_send_box_error(cmd, box); return FALSE; } if (existence == MAILBOX_EXISTENCE_NONE) { @@ -71,7 +71,7 @@ if (mailbox_set_subscribed(box, subscribe) < 0 && !unsubscribed_mailbox2) { - client_send_storage_error(cmd, mailbox_get_storage(box)); + client_send_box_error(cmd, box); } else { client_send_tagline(cmd, subscribe ? "OK Subscribe completed." : diff -r 21d96c97f519 -r 9946079253c4 src/imap/cmd-thread.c --- a/src/imap/cmd-thread.c Tue Dec 03 17:17:03 2013 +0200 +++ b/src/imap/cmd-thread.c Tue Dec 03 17:29:38 2013 +0200 @@ -283,8 +283,7 @@ ret = imap_thread_orderedsubject(cmd, sargs); mail_search_args_unref(&sargs); From dovecot at dovecot.org Tue Dec 3 21:32:42 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Tue, 03 Dec 2013 21:32:42 +0200 Subject: dovecot-2.2: lib-imap: imap_envelope_parse() added extra "," aft... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/342f6962390e changeset: 17039:342f6962390e user: Timo Sirainen date: Tue Dec 03 21:31:59 2013 +0200 description: lib-imap: imap_envelope_parse() added extra "," after address group. This function wasn't actually used by Dovecot anywhere anymore. Patch by Potapov Sergey. diffstat: src/lib-imap/imap-envelope.c | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diffs (55 lines): diff -r 9946079253c4 -r 342f6962390e src/lib-imap/imap-envelope.c --- a/src/lib-imap/imap-envelope.c Tue Dec 03 17:29:38 2013 +0200 +++ b/src/lib-imap/imap-envelope.c Tue Dec 03 21:31:59 2013 +0200 @@ -226,7 +226,7 @@ } static bool imap_address_arg_append(const struct imap_arg *arg, string_t *str, - bool *in_group) + bool *in_group, bool *begin_group) { const struct imap_arg *list_args; unsigned int list_count; @@ -250,10 +250,11 @@ /* end of group */ str_append_c(str, ';'); *in_group = FALSE; + *begin_group = FALSE; return TRUE; } - if (str_len(str) > 0) + if (str_len(str) > 0 && !*begin_group) str_append(str, ", "); if (!*in_group && args[0] == NULL && args[1] == NULL && @@ -262,8 +263,10 @@ str_append(str, args[2]); str_append(str, ": "); *in_group = TRUE; + *begin_group = TRUE; return TRUE; } + *begin_group = FALSE; /* a) mailbox at domain b) name <@route:mailbox at domain> */ @@ -302,15 +305,17 @@ const struct imap_arg *list_args; string_t *str; bool in_group; + bool begin_group; if (!imap_arg_get_list(arg, &list_args)) return NULL; in_group = FALSE; + begin_group = FALSE; str = t_str_new(128); for (; !IMAP_ARG_IS_EOL(list_args); list_args++) { - if (!imap_address_arg_append(list_args, str, &in_group)) + if (!imap_address_arg_append(list_args, str, &in_group, &begin_group)) return NULL; } From dovecot at dovecot.org Sun Dec 8 19:01:09 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sun, 08 Dec 2013 19:01:09 +0200 Subject: dovecot-2.2: auth: passdb/userdb dict rewrite to support more co... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/d2ad697ba810 changeset: 17040:d2ad697ba810 user: Timo Sirainen date: Sun Dec 08 19:00:31 2013 +0200 description: auth: passdb/userdb dict rewrite to support more complex configuration. See the new doc/example-config/dovecot-dict-auth.conf.ext for explanation how it works. The old configuration format will also stay functional. diffstat: doc/example-config/dovecot-dict-auth.conf.ext | 56 ++- src/auth/Makefile.am | 8 +- src/auth/db-dict-cache-key.c | 65 +++ src/auth/db-dict.c | 526 +++++++++++++++++++++++-- src/auth/db-dict.h | 57 ++- src/auth/passdb-dict.c | 49 +- src/auth/test-db-dict.c | 51 ++ src/auth/userdb-dict.c | 42 +- 8 files changed, 731 insertions(+), 123 deletions(-) diffs (truncated from 1134 to 300 lines): diff -r 342f6962390e -r d2ad697ba810 doc/example-config/dovecot-dict-auth.conf.ext --- a/doc/example-config/dovecot-dict-auth.conf.ext Tue Dec 03 21:31:59 2013 +0200 +++ b/doc/example-config/dovecot-dict-auth.conf.ext Sun Dec 08 19:00:31 2013 +0200 @@ -1,24 +1,54 @@ -# This file is commonly accessed via dict {} section in dovecot.conf +# This file is commonly accessed via passdb {} or userdb {} section in +# conf.d/auth-dict.conf.ext # Dictionary URI #uri = -# Key for passdb lookups -password_key = dovecot/passdb/%u - -# Key for userdb lookups -user_key = dovecot/userdb/%u - -# How to parse the value for key=value pairs. Currently we support only JSON -# format with { "key": "value", ... } object. -#value_format = json +# Default password scheme +default_pass_scheme = MD5 # Username iteration prefix. Keys under this are assumed to contain usernames. -iterate_prefix = dovecot/userdb/ +iterate_prefix = userdb/ # Should iteration be disabled for this userdb? If this userdb acts only as a # cache there's no reason to try to iterate the (partial & duplicate) users. #iterate_disable = no -# Default password scheme -default_pass_scheme = MD5 +# The example here shows how to do multiple dict lookups and merge the replies. +# The "passdb" and "userdb" keys are JSON objects containing key/value pairs, +# for example: { "uid": 1000, "gid": 1000, "home": "/home/user" } + +key passdb { + key = passdb/%u + format = json +} +key userdb { + key = userdb/%u + format = json +} +key quota { + key = userdb/%u/quota + #format = value + # The default_value is used if the key isn't found. If default_value setting + # isn't specified at all (even as empty), the passdb/userdb lookup fails with + # "user doesn't exist". + default_value = 100M +} + +# Space separated list of keys whose values contain key/value paired objects. +# All the key/value pairs inside the object are added as passdb fields. +passdb_objects = passdb + +#passdb_fields { +#} + +# Userdb key/value object list. +userdb_objects = userdb + +userdb_fields { + # dict: refers to key names + quota_rule = *:storage=%{dict:quota} + + # dict:. refers to the objkey inside (JSON) object + mail = maildir:%{dict:userdb.home}/Maildir +} diff -r 342f6962390e -r d2ad697ba810 src/auth/Makefile.am --- a/src/auth/Makefile.am Tue Dec 03 21:31:59 2013 +0200 +++ b/src/auth/Makefile.am Sun Dec 08 19:00:31 2013 +0200 @@ -77,6 +77,7 @@ auth-worker-server.c \ db-checkpassword.c \ db-dict.c \ + db-dict-cache-key.c \ db-sql.c \ db-passwd-file.c \ main.c \ @@ -193,7 +194,8 @@ checkpassword-reply.c test_programs = \ - test-auth-cache + test-auth-cache \ + test-db-dict noinst_PROGRAMS = $(test_programs) @@ -205,6 +207,10 @@ test_auth_cache_LDADD = auth-cache.o $(test_libs) test_auth_cache_DEPENDENCIES = $(pkglibexec_PROGRAMS) $(test_libs) +test_db_dict_SOURCES = test-db-dict.c +test_db_dict_LDADD = db-dict-cache-key.o $(test_libs) +test_db_dict_DEPENDENCIES = $(pkglibexec_PROGRAMS) $(test_libs) + check: check-am check-test check-test: all-am for bin in $(test_programs); do \ diff -r 342f6962390e -r d2ad697ba810 src/auth/db-dict-cache-key.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/db-dict-cache-key.c Sun Dec 08 19:00:31 2013 +0200 @@ -0,0 +1,65 @@ +/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */ + +#include "auth-common.h" +#include "array.h" +#include "str.h" +#include "var-expand.h" +#include "db-dict.h" + +const struct db_dict_key * +db_dict_set_key_find(const ARRAY_TYPE(db_dict_key) *keys, const char *name) +{ + const struct db_dict_key *key; + + array_foreach(keys, key) { + if (strcmp(key->name, name) == 0) + return key; + } + return NULL; +} + + +const char * +db_dict_parse_cache_key(const ARRAY_TYPE(db_dict_key) *keys, + const ARRAY_TYPE(db_dict_field) *fields, + const ARRAY_TYPE(db_dict_key_p) *objects) +{ + const struct db_dict_field *field; + const struct db_dict_key *key; + const struct db_dict_key *const *keyp; + const char *p, *name; + unsigned int idx, size; + string_t *str = t_str_new(128); + + array_foreach(fields, field) { + for (p = field->value; *p != '\0'; ) { + if (*p != '%') { + p++; + continue; + } + + var_get_key_range(++p, &idx, &size); + if (size == 0) { + /* broken %variable ending too early */ + break; + } + p += idx; + if (size > 5 && memcmp(p, "dict:", 5) == 0) { + name = t_strcut(t_strndup(p+5, size-5), ':'); + key = db_dict_set_key_find(keys, name); + if (key != NULL) + str_printfa(str, "\t%s", key->key); + } else if (size == 1) { + str_printfa(str, "\t%%%c", p[0]); + } else { + str_append(str, "\t%{"); + str_append_n(str, p, size); + str_append_c(str, '}'); + } + p += size; + } + } + array_foreach(objects, keyp) + str_printfa(str, "\t%s", (*keyp)->key); + return str_c(str); +} diff -r 342f6962390e -r d2ad697ba810 src/auth/db-dict.c --- a/src/auth/db-dict.c Tue Dec 03 21:31:59 2013 +0200 +++ b/src/auth/db-dict.c Sun Dec 08 19:00:31 2013 +0200 @@ -2,11 +2,12 @@ #include "auth-common.h" +#include "array.h" +#include "istream.h" +#include "str.h" +#include "json-parser.h" #include "settings.h" #include "dict.h" -#include "json-parser.h" -#include "istream.h" -#include "str.h" #include "auth-request.h" #include "auth-worker-client.h" #include "db-dict.h" @@ -14,29 +15,80 @@ #include #include +enum dict_settings_section { + DICT_SETTINGS_SECTION_ROOT = 0, + DICT_SETTINGS_SECTION_KEY, + DICT_SETTINGS_SECTION_PASSDB, + DICT_SETTINGS_SECTION_USERDB +}; + +struct dict_settings_parser_ctx { + struct dict_connection *conn; + enum dict_settings_section section; + struct db_dict_key *cur_key; +}; + +struct db_dict_iter_key { + const struct db_dict_key *key; + bool used; + const char *value; +}; + +struct db_dict_value_iter { + pool_t pool; + struct auth_request *auth_request; + struct dict_connection *conn; + const struct var_expand_table *var_expand_table; + ARRAY(struct db_dict_iter_key) keys; + + const ARRAY_TYPE(db_dict_field) *fields; + const ARRAY_TYPE(db_dict_key_p) *objects; + unsigned int field_idx; + unsigned int object_idx; + + struct json_parser *json_parser; + string_t *tmpstr; + const char *error; +}; + #define DEF_STR(name) DEF_STRUCT_STR(name, db_dict_settings) #define DEF_BOOL(name) DEF_STRUCT_BOOL(name, db_dict_settings) - static struct setting_def setting_defs[] = { DEF_STR(uri), - DEF_STR(password_key), - DEF_STR(user_key), + DEF_STR(default_pass_scheme), DEF_STR(iterate_prefix), - DEF_STR(value_format), DEF_BOOL(iterate_disable), - DEF_STR(default_pass_scheme), + DEF_STR(passdb_objects), + DEF_STR(userdb_objects), { 0, NULL, 0 } }; static struct db_dict_settings default_dict_settings = { .uri = NULL, - .password_key = "", - .user_key = "", + .default_pass_scheme = "MD5", .iterate_prefix = "", .iterate_disable = FALSE, - .value_format = "json", - .default_pass_scheme = "MD5" + .passdb_objects = "", + .userdb_objects = "" +}; + +#undef DEF_STR +#define DEF_STR(name) DEF_STRUCT_STR(name, db_dict_key) +static struct setting_def key_setting_defs[] = { + DEF_STR(name), + DEF_STR(key), + DEF_STR(format), + DEF_STR(default_value), + + { 0, NULL, 0 } +}; + +static struct db_dict_key default_key_settings = { + .name = NULL, + .key = "", + .format = "value", + .default_value = NULL }; static struct dict_connection *connections = NULL; @@ -53,15 +105,167 @@ return NULL; } +static bool +parse_obsolete_setting(const char *key, const char *value, + struct dict_settings_parser_ctx *ctx, + const char **error_r) +{ + const struct db_dict_key *dbkey; + + if (strcmp(key, "password_key") == 0) { + /* key passdb { key= format=json } + passdb_objects = passdb */ + ctx->cur_key = array_append_space(&ctx->conn->set.keys); + *ctx->cur_key = default_key_settings; + ctx->cur_key->name = "passdb"; + ctx->cur_key->format = "json"; + ctx->cur_key->parsed_format = DB_DICT_VALUE_FORMAT_JSON; From dovecot at dovecot.org Sun Dec 8 19:02:19 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sun, 08 Dec 2013 19:02:19 +0200 Subject: dovecot-2.2: lib-storage: Don't crash in mailbox_is_inconsistent... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/0595d54ab34a changeset: 17041:0595d54ab34a user: Timo Sirainen date: Sun Dec 08 19:02:12 2013 +0200 description: lib-storage: Don't crash in mailbox_is_inconsistent() if mailbox hasn't been opened. diffstat: src/lib-storage/index/index-storage.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diffs (13 lines): diff -r d2ad697ba810 -r 0595d54ab34a src/lib-storage/index/index-storage.c --- a/src/lib-storage/index/index-storage.c Sun Dec 08 19:00:31 2013 +0200 +++ b/src/lib-storage/index/index-storage.c Sun Dec 08 19:02:12 2013 +0200 @@ -760,7 +760,8 @@ bool index_storage_is_inconsistent(struct mailbox *box) { - return mail_index_view_is_inconsistent(box->view); + return box->view != NULL && + mail_index_view_is_inconsistent(box->view); } void index_save_context_free(struct mail_save_context *ctx) From dovecot at dovecot.org Sun Dec 8 20:48:15 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sun, 08 Dec 2013 20:48:15 +0200 Subject: dovecot-2.2: auth: Added userdb result_success/failure/tempfail ... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/eeadb7b5045b changeset: 17042:eeadb7b5045b user: Timo Sirainen date: Sun Dec 08 20:48:03 2013 +0200 description: auth: Added userdb result_success/failure/tempfail and skip settings, similar to passdb's. diffstat: src/auth/auth-master-connection.c | 4 +- src/auth/auth-postfix-connection.c | 4 +- src/auth/auth-request-handler.c | 4 +- src/auth/auth-request.c | 106 ++++++++++++++++++++++++++++++------ src/auth/auth-request.h | 4 +- src/auth/auth-settings.c | 16 +++++- src/auth/auth-settings.h | 8 ++- src/auth/auth-worker-client.c | 3 +- src/auth/auth.c | 40 ++++++++++--- src/auth/auth.h | 31 +++++++--- src/auth/userdb-blocking.c | 2 +- src/auth/userdb-dict.c | 2 - src/auth/userdb-ldap.c | 2 - src/auth/userdb-nss.c | 1 - src/auth/userdb-passwd-file.c | 1 - src/auth/userdb-passwd.c | 1 - src/auth/userdb-sql.c | 2 - src/auth/userdb-static.c | 1 - src/auth/userdb-vpopmail.c | 1 - 19 files changed, 172 insertions(+), 61 deletions(-) diffs (truncated from 612 to 300 lines): diff -r 0595d54ab34a -r eeadb7b5045b src/auth/auth-master-connection.c --- a/src/auth/auth-master-connection.c Sun Dec 08 19:02:12 2013 +0200 +++ b/src/auth/auth-master-connection.c Sun Dec 08 20:48:03 2013 +0200 @@ -252,7 +252,7 @@ string_t *str; const char *value; - if (auth_request->userdb_lookup_failed) + if (auth_request->userdb_lookup_tempfailed) result = USERDB_RESULT_INTERNAL_FAILURE; if (result == USERDB_RESULT_OK) { @@ -264,7 +264,7 @@ switch (result) { case USERDB_RESULT_INTERNAL_FAILURE: str_printfa(str, "FAIL\t%u", auth_request->id); - if (auth_request->userdb_lookup_failed) { + if (auth_request->userdb_lookup_tempfailed) { value = auth_fields_find(auth_request->userdb_reply, "reason"); if (value != NULL) diff -r 0595d54ab34a -r eeadb7b5045b src/auth/auth-postfix-connection.c --- a/src/auth/auth-postfix-connection.c Sun Dec 08 19:02:12 2013 +0200 +++ b/src/auth/auth-postfix-connection.c Sun Dec 08 20:48:03 2013 +0200 @@ -69,13 +69,13 @@ string_t *str; const char *value; - if (auth_request->userdb_lookup_failed) + if (auth_request->userdb_lookup_tempfailed) result = USERDB_RESULT_INTERNAL_FAILURE; str = t_str_new(128); switch (result) { case USERDB_RESULT_INTERNAL_FAILURE: - if (auth_request->userdb_lookup_failed) + if (auth_request->userdb_lookup_tempfailed) value = auth_fields_find(auth_request->userdb_reply, "reason"); else value = NULL; diff -r 0595d54ab34a -r eeadb7b5045b src/auth/auth-request-handler.c --- a/src/auth/auth-request-handler.c Sun Dec 08 19:02:12 2013 +0200 +++ b/src/auth/auth-request-handler.c Sun Dec 08 20:48:03 2013 +0200 @@ -633,14 +633,14 @@ auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED); - if (request->userdb_lookup_failed) + if (request->userdb_lookup_tempfailed) result = USERDB_RESULT_INTERNAL_FAILURE; str = t_str_new(128); switch (result) { case USERDB_RESULT_INTERNAL_FAILURE: str_printfa(str, "FAIL\t%u", request->id); - if (request->userdb_lookup_failed) { + if (request->userdb_lookup_tempfailed) { value = auth_fields_find(request->userdb_reply, "reason"); if (value != NULL) auth_str_add_keyvalue(str, "reason", value); diff -r 0595d54ab34a -r eeadb7b5045b src/auth/auth-request.c --- a/src/auth/auth-request.c Sun Dec 08 19:02:12 2013 +0200 +++ b/src/auth/auth-request.c Sun Dec 08 20:48:03 2013 +0200 @@ -507,11 +507,26 @@ } static bool +auth_request_want_skip_userdb(struct auth_request *request, + struct auth_userdb *userdb) +{ + switch (userdb->skip) { + case AUTH_USERDB_SKIP_NEVER: + return FALSE; + case AUTH_USERDB_SKIP_FOUND: + return request->userdb_success; + case AUTH_USERDB_SKIP_NOTFOUND: + return !request->userdb_success; + } + i_unreached(); +} + +static bool auth_request_handle_passdb_callback(enum passdb_result *result, struct auth_request *request) { struct auth_passdb *next_passdb; - enum auth_passdb_rule result_rule; + enum auth_db_rule result_rule; bool passdb_continue = FALSE; if (request->passdb_password != NULL) { @@ -557,22 +572,22 @@ } switch (result_rule) { - case AUTH_PASSDB_RULE_RETURN: + case AUTH_DB_RULE_RETURN: break; - case AUTH_PASSDB_RULE_RETURN_OK: + case AUTH_DB_RULE_RETURN_OK: request->passdb_success = TRUE; break; - case AUTH_PASSDB_RULE_RETURN_FAIL: + case AUTH_DB_RULE_RETURN_FAIL: request->passdb_success = FALSE; break; - case AUTH_PASSDB_RULE_CONTINUE: + case AUTH_DB_RULE_CONTINUE: passdb_continue = TRUE; break; - case AUTH_PASSDB_RULE_CONTINUE_OK: + case AUTH_DB_RULE_CONTINUE_OK: passdb_continue = TRUE; request->passdb_success = TRUE; break; - case AUTH_PASSDB_RULE_CONTINUE_FAIL: + case AUTH_DB_RULE_CONTINUE_FAIL: passdb_continue = TRUE; request->passdb_success = FALSE; break; @@ -982,26 +997,79 @@ struct auth_request *request) { struct userdb_module *userdb = request->userdb->userdb; + struct auth_userdb *next_userdb; + enum auth_db_rule result_rule; + bool userdb_continue = FALSE; - if (result != USERDB_RESULT_OK && request->userdb->next != NULL) { + switch (result) { + case USERDB_RESULT_OK: + result_rule = request->userdb->result_success; + break; + case USERDB_RESULT_INTERNAL_FAILURE: + result_rule = request->userdb->result_internalfail; + break; + case USERDB_RESULT_USER_UNKNOWN: + default: + result_rule = request->userdb->result_failure; + break; + } + + switch (result_rule) { + case AUTH_DB_RULE_RETURN: + break; + case AUTH_DB_RULE_RETURN_OK: + request->userdb_success = TRUE; + break; + case AUTH_DB_RULE_RETURN_FAIL: + request->userdb_success = FALSE; + break; + case AUTH_DB_RULE_CONTINUE: + userdb_continue = TRUE; + break; + case AUTH_DB_RULE_CONTINUE_OK: + userdb_continue = TRUE; + request->userdb_success = TRUE; + break; + case AUTH_DB_RULE_CONTINUE_FAIL: + userdb_continue = TRUE; + request->userdb_success = FALSE; + break; + } + + next_userdb = request->userdb->next; + while (next_userdb != NULL && + auth_request_want_skip_userdb(request, next_userdb)) + next_userdb = next_userdb->next; + + if (userdb_continue && next_userdb != NULL) { /* try next userdb. */ if (result == USERDB_RESULT_INTERNAL_FAILURE) request->userdbs_seen_internal_failure = TRUE; - request->userdb = request->userdb->next; + if (result == USERDB_RESULT_OK) { + /* this userdb lookup succeeded, preserve its extra + fields */ + auth_fields_snapshot(request->userdb_reply); + } else { + /* this userdb lookup failed, remove any extra fields + it set */ + auth_fields_rollback(request->userdb_reply); + } + + request->userdb = next_userdb; auth_request_lookup_user(request, request->private_callback.userdb); return; } - if (result == USERDB_RESULT_OK) + if (request->userdb_success) userdb_template_export(userdb->override_fields_tmpl, request); - else if (request->userdbs_seen_internal_failure) { + else if (request->userdbs_seen_internal_failure || + result == USERDB_RESULT_INTERNAL_FAILURE) { /* one of the userdb lookups failed. the user might have been in there, so this is an internal failure */ result = USERDB_RESULT_INTERNAL_FAILURE; - } else if (result == USERDB_RESULT_USER_UNKNOWN && - request->client_pid != 0) { + } else if (request->client_pid != 0) { /* this was an actual login attempt, the user should have been found. */ if (auth_request_get_auth(request)->userdbs->next == NULL) { @@ -1014,7 +1082,7 @@ } } - if (request->userdb_lookup_failed) { + if (request->userdb_lookup_tempfailed) { /* no caching */ } else if (result != USERDB_RESULT_INTERNAL_FAILURE) auth_request_userdb_save_cache(request, result); @@ -1044,6 +1112,8 @@ request->private_callback.userdb = callback; request->userdb_lookup = TRUE; + if (request->userdb_reply == NULL) + auth_request_init_userdb_reply(request); /* (for now) auth_cache is shared between passdb and userdb */ cache_key = passdb_cache == NULL ? NULL : userdb->cache_key; @@ -1496,19 +1566,19 @@ if (strcmp(name, "uid") == 0) { uid = userdb_parse_uid(request, value); if (uid == (uid_t)-1) { - request->userdb_lookup_failed = TRUE; + request->userdb_lookup_tempfailed = TRUE; return; } value = dec2str(uid); } else if (strcmp(name, "gid") == 0) { gid = userdb_parse_gid(request, value); if (gid == (gid_t)-1) { - request->userdb_lookup_failed = TRUE; + request->userdb_lookup_tempfailed = TRUE; return; } value = dec2str(gid); } else if (strcmp(name, "tempfail") == 0) { - request->userdb_lookup_failed = TRUE; + request->userdb_lookup_tempfailed = TRUE; return; } else if (auth_request_try_update_username(request, name, value)) { return; @@ -1549,7 +1619,7 @@ for (; *values != NULL; values++) { gid = userdb_parse_gid(request, *values); if (gid == (gid_t)-1) { - request->userdb_lookup_failed = TRUE; + request->userdb_lookup_tempfailed = TRUE; return; } diff -r 0595d54ab34a -r eeadb7b5045b src/auth/auth-request.h --- a/src/auth/auth-request.h Sun Dec 08 19:02:12 2013 +0200 +++ b/src/auth/auth-request.h Sun Dec 08 20:48:03 2013 +0200 @@ -130,10 +130,12 @@ at the end. mechanisms that don't require passdb, but do a passdb lookup anyway (e.g. GSSAPI) need to set this to TRUE by default. */ unsigned int passdb_success:1; + /* userdb equivalent of passdb_success */ + unsigned int userdb_success:1; /* the last userdb lookup failed either due to "tempfail" extra field or because one of the returned uid/gid fields couldn't be translated to a number */ - unsigned int userdb_lookup_failed:1; + unsigned int userdb_lookup_tempfailed:1; /* ... mechanism specific data ... */ }; diff -r 0595d54ab34a -r eeadb7b5045b src/auth/auth-settings.c --- a/src/auth/auth-settings.c Sun Dec 08 19:02:12 2013 +0200 +++ b/src/auth/auth-settings.c Sun Dec 08 20:48:03 2013 +0200 @@ -111,10 +111,12 @@ DEF(SET_STR, args), DEF(SET_STR, default_fields), DEF(SET_STR, override_fields), + DEF(SET_ENUM, skip), DEF(SET_ENUM, result_success), DEF(SET_ENUM, result_failure), DEF(SET_ENUM, result_internalfail), + DEF(SET_BOOL, deny), DEF(SET_BOOL, pass), DEF(SET_BOOL, master), @@ -127,10 +129,12 @@ .args = "", .default_fields = "", .override_fields = "", + .skip = "never:authenticated:unauthenticated", .result_success = "return-ok:return:return-fail:continue:continue-ok:continue-fail", .result_failure = "continue:return:return-ok:return-fail:continue-ok:continue-fail", .result_internalfail = "continue:return:return-ok:return-fail:continue-ok:continue-fail", + .deny = FALSE, From dovecot at dovecot.org Sun Dec 8 21:26:49 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sun, 08 Dec 2013 21:26:49 +0200 Subject: dovecot-2.2: lib-dict: Added "fs" wrapper dict backend, which us... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/773e9ce608ed changeset: 17043:773e9ce608ed user: Timo Sirainen date: Sun Dec 08 21:13:22 2013 +0200 description: lib-dict: Added "fs" wrapper dict backend, which uses lib-fs. Each dict key is a separate file where the file's contents are the dict value. diffstat: src/lib-dict/Makefile.am | 3 + src/lib-dict/dict-fs.c | 201 +++++++++++++++++++++++++++++++++++++++++++ src/lib-dict/dict-private.h | 1 + src/lib-dict/dict-register.c | 24 +++++ src/lib-dict/dict.c | 18 --- 5 files changed, 229 insertions(+), 18 deletions(-) diffs (295 lines): diff -r eeadb7b5045b -r 773e9ce608ed src/lib-dict/Makefile.am --- a/src/lib-dict/Makefile.am Sun Dec 08 20:48:03 2013 +0200 +++ b/src/lib-dict/Makefile.am Sun Dec 08 21:13:22 2013 +0200 @@ -6,6 +6,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ -I$(top_srcdir)/src/lib-test \ + -I$(top_srcdir)/src/lib-fs \ -I$(top_srcdir)/src/lib-sql \ -I$(top_srcdir)/src/lib-settings \ $(SQL_CFLAGS) @@ -15,9 +16,11 @@ dict-client.c \ dict-file.c \ dict-cdb.c \ + dict-fs.c \ dict-memcached.c \ dict-memcached-ascii.c \ dict-redis.c \ + dict-register.c \ dict-transaction-memory.c libdict_la_SOURCES = \ diff -r eeadb7b5045b -r 773e9ce608ed src/lib-dict/dict-fs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-dict/dict-fs.c Sun Dec 08 21:13:22 2013 +0200 @@ -0,0 +1,201 @@ +/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "fs-api.h" +#include "istream.h" +#include "str.h" +#include "dict-transaction-memory.h" +#include "dict-private.h" + +struct fs_dict { + struct dict dict; + struct fs *fs; + char *username; +}; + +static int +fs_dict_init(struct dict *driver, const char *uri, + enum dict_data_type value_type ATTR_UNUSED, + const char *username, + const char *base_dir, struct dict **dict_r, + const char **error_r) +{ + struct fs_settings fs_set; + struct fs *fs; + struct fs_dict *dict; + const char *p, *fs_driver, *fs_args; + + p = strchr(uri, ':'); + if (p == NULL) { + fs_driver = uri; + fs_args = ""; + } else { + fs_driver = t_strdup_until(uri, p); + fs_args = p+1; + } + + memset(&fs_set, 0, sizeof(fs_set)); + fs_set.base_dir = base_dir; + if (fs_init(fs_driver, fs_args, &fs_set, &fs, error_r) < 0) + return -1; + + dict = i_new(struct fs_dict, 1); + dict->dict = *driver; + dict->fs = fs; + dict->username = i_strdup(username); + + *dict_r = &dict->dict; + return 0; +} + +static void fs_dict_deinit(struct dict *_dict) +{ + struct fs_dict *dict = (struct fs_dict *)_dict; + + fs_deinit(&dict->fs); + i_free(dict->username); + i_free(dict); +} + +static const char *fs_dict_get_full_key(struct fs_dict *dict, const char *key) +{ + if (strncmp(key, DICT_PATH_SHARED, strlen(DICT_PATH_SHARED)) == 0) + return key + strlen(DICT_PATH_SHARED); + else if (strncmp(key, DICT_PATH_PRIVATE, strlen(DICT_PATH_PRIVATE)) == 0) { + return t_strdup_printf("%s/%s", dict->username, + key + strlen(DICT_PATH_PRIVATE)); + } else { + i_unreached(); + } +} + +static int fs_dict_lookup(struct dict *_dict, pool_t pool, + const char *key, const char **value_r) +{ + struct fs_dict *dict = (struct fs_dict *)_dict; + struct fs_file *file; + struct istream *input; + const unsigned char *data; + size_t size; + string_t *str; + int ret; + + file = fs_file_init(dict->fs, fs_dict_get_full_key(dict, key), + FS_OPEN_MODE_READONLY); + input = fs_read_stream(file, IO_BLOCK_SIZE); + i_stream_read(input); + + str = str_new(pool, i_stream_get_data_size(input)+1); + while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) { + str_append_n(str, data, size); + i_stream_skip(input, size); + } + i_assert(ret == -1); + + if (input->stream_errno == 0) { + *value_r = str_c(str); + ret = 1; + } else { + *value_r = NULL; + if (input->stream_errno == ENOENT) + ret = 0; + } + + i_stream_unref(&input); + fs_file_deinit(&file); + return ret; +} + +static struct dict_transaction_context * +fs_dict_transaction_init(struct dict *_dict) +{ + struct dict_transaction_memory_context *ctx; + pool_t pool; + + pool = pool_alloconly_create("file dict transaction", 2048); + ctx = p_new(pool, struct dict_transaction_memory_context, 1); + dict_transaction_memory_init(ctx, _dict, pool); + return &ctx->ctx; +} + +static int fs_dict_write_changes(struct dict_transaction_memory_context *ctx) +{ + struct fs_dict *dict = (struct fs_dict *)ctx->ctx.dict; + struct fs_file *file; + const struct dict_transaction_memory_change *change; + const char *key; + int ret = 0; + + array_foreach(&ctx->changes, change) { + key = fs_dict_get_full_key(dict, change->key); + switch (change->type) { + case DICT_CHANGE_TYPE_SET: + file = fs_file_init(dict->fs, key, + FS_OPEN_MODE_REPLACE); + if (fs_write(file, change->value.str, strlen(change->value.str)) < 0) { + i_error("fs_write(%s) failed: %s", key, + fs_file_last_error(file)); + ret = -1; + } + fs_file_deinit(&file); + break; + case DICT_CHANGE_TYPE_UNSET: + file = fs_file_init(dict->fs, key, FS_OPEN_MODE_READONLY); + if (fs_delete(file) < 0) { + i_error("fs_delete(%s) failed: %s", key, + fs_file_last_error(file)); + ret = -1; + } + fs_file_deinit(&file); + break; + case DICT_CHANGE_TYPE_APPEND: + case DICT_CHANGE_TYPE_INC: + i_unreached(); + } + if (ret < 0) + return -1; + } + return 0; +} + +static int +fs_dict_transaction_commit(struct dict_transaction_context *_ctx, + bool async ATTR_UNUSED, + dict_transaction_commit_callback_t *callback, + void *context) +{ + struct dict_transaction_memory_context *ctx = + (struct dict_transaction_memory_context *)_ctx; + int ret; + + if (fs_dict_write_changes(ctx) < 0) + ret = -1; + else + ret = 1; + pool_unref(&ctx->pool); + + if (callback != NULL) + callback(ret, context); + return ret; +} + +struct dict dict_driver_fs = { + .name = "fs", + { + fs_dict_init, + fs_dict_deinit, + NULL, + fs_dict_lookup, + NULL, + NULL, + NULL, + fs_dict_transaction_init, + fs_dict_transaction_commit, + dict_transaction_memory_rollback, + dict_transaction_memory_set, + dict_transaction_memory_unset, + NULL, + NULL + } +}; diff -r eeadb7b5045b -r 773e9ce608ed src/lib-dict/dict-private.h --- a/src/lib-dict/dict-private.h Sun Dec 08 20:48:03 2013 +0200 +++ b/src/lib-dict/dict-private.h Sun Dec 08 21:13:22 2013 +0200 @@ -56,6 +56,7 @@ extern struct dict dict_driver_client; extern struct dict dict_driver_file; +extern struct dict dict_driver_fs; extern struct dict dict_driver_memcached; extern struct dict dict_driver_memcached_ascii; extern struct dict dict_driver_redis; diff -r eeadb7b5045b -r 773e9ce608ed src/lib-dict/dict-register.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-dict/dict-register.c Sun Dec 08 21:13:22 2013 +0200 @@ -0,0 +1,24 @@ +/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "dict-private.h" + +void dict_drivers_register_builtin(void) +{ + dict_driver_register(&dict_driver_client); + dict_driver_register(&dict_driver_file); + dict_driver_register(&dict_driver_fs); + dict_driver_register(&dict_driver_memcached); + dict_driver_register(&dict_driver_memcached_ascii); + dict_driver_register(&dict_driver_redis); +} + +void dict_drivers_unregister_builtin(void) +{ + dict_driver_unregister(&dict_driver_client); + dict_driver_unregister(&dict_driver_file); + dict_driver_unregister(&dict_driver_fs); + dict_driver_unregister(&dict_driver_memcached); + dict_driver_unregister(&dict_driver_memcached_ascii); + dict_driver_unregister(&dict_driver_redis); +} diff -r eeadb7b5045b -r 773e9ce608ed src/lib-dict/dict.c --- a/src/lib-dict/dict.c Sun Dec 08 20:48:03 2013 +0200 +++ b/src/lib-dict/dict.c Sun Dec 08 21:13:22 2013 +0200 @@ -52,24 +52,6 @@ array_free(&dict_drivers); } -void dict_drivers_register_builtin(void) -{ - dict_driver_register(&dict_driver_client); - dict_driver_register(&dict_driver_file); - dict_driver_register(&dict_driver_memcached); - dict_driver_register(&dict_driver_memcached_ascii); - dict_driver_register(&dict_driver_redis); -} - -void dict_drivers_unregister_builtin(void) -{ - dict_driver_unregister(&dict_driver_client); - dict_driver_unregister(&dict_driver_file); - dict_driver_unregister(&dict_driver_memcached); - dict_driver_unregister(&dict_driver_memcached_ascii); - dict_driver_unregister(&dict_driver_redis); -} - int dict_init(const char *uri, enum dict_data_type value_type, const char *username, const char *base_dir, struct dict **dict_r, const char **error_r) From dovecot at dovecot.org Sun Dec 8 21:26:49 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sun, 08 Dec 2013 21:26:49 +0200 Subject: dovecot-2.2: lib-storage: Added mail_user->admin flag. Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/3e8f300175bb changeset: 17044:3e8f300175bb user: Timo Sirainen date: Sun Dec 08 21:22:38 2013 +0200 description: lib-storage: Added mail_user->admin flag. The previous admin-flag used to mix up "admin user" and "admin tool", while this new purpose only means "admin user". diffstat: src/lib-storage/mail-storage-service.c | 5 +++++ src/lib-storage/mail-user.h | 2 ++ 2 files changed, 7 insertions(+), 0 deletions(-) diffs (41 lines): diff -r 773e9ce608ed -r 3e8f300175bb src/lib-storage/mail-storage-service.c --- a/src/lib-storage/mail-storage-service.c Sun Dec 08 21:13:22 2013 +0200 +++ b/src/lib-storage/mail-storage-service.c Sun Dec 08 21:22:38 2013 +0200 @@ -83,6 +83,7 @@ struct setting_parser_context *set_parser; unsigned int anonymous:1; + unsigned int admin:1; }; struct module *mail_storage_service_modules = NULL; @@ -277,6 +278,9 @@ #endif } else if (strncmp(line, "auth_token=", 11) == 0) { user->auth_token = p_strdup(user->pool, line+11); + } else if (strncmp(line, "admin=", 6) == 0) { + user->admin = line[6] == 'y' || line[6] == 'Y' || + line[6] == '1'; } else T_BEGIN { ret = set_line(ctx, user, line); } T_END; @@ -621,6 +625,7 @@ mail_user->uid = priv->uid == (uid_t)-1 ? geteuid() : priv->uid; mail_user->gid = priv->gid == (gid_t)-1 ? getegid() : priv->gid; mail_user->anonymous = user->anonymous; + mail_user->admin = user->admin; mail_user->auth_token = p_strdup(mail_user->pool, user->auth_token); mail_set = mail_user_set_get_storage_set(mail_user); diff -r 773e9ce608ed -r 3e8f300175bb src/lib-storage/mail-user.h --- a/src/lib-storage/mail-user.h Sun Dec 08 21:13:22 2013 +0200 +++ b/src/lib-storage/mail-user.h Sun Dec 08 21:22:38 2013 +0200 @@ -70,6 +70,8 @@ unsigned int attr_dict_failed:1; /* We're deinitializing the user */ unsigned int deinitializing:1; + /* Enable administrator user commands for the user */ + unsigned int admin:1; }; struct mail_user_module_register { From dovecot at dovecot.org Sun Dec 8 21:26:49 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sun, 08 Dec 2013 21:26:49 +0200 Subject: dovecot-2.2: imap-quota: Admin user can (again) use GETQUOTA for... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/51edc7daf7f0 changeset: 17045:51edc7daf7f0 user: Timo Sirainen date: Sun Dec 08 21:24:10 2013 +0200 description: imap-quota: Admin user can (again) use GETQUOTA for other users' quota roots. diffstat: src/plugins/imap-quota/imap-quota-plugin.c | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diffs (19 lines): diff -r 3e8f300175bb -r 51edc7daf7f0 src/plugins/imap-quota/imap-quota-plugin.c --- a/src/plugins/imap-quota/imap-quota-plugin.c Sun Dec 08 21:22:38 2013 +0200 +++ b/src/plugins/imap-quota/imap-quota-plugin.c Sun Dec 08 21:24:10 2013 +0200 @@ -138,7 +138,6 @@ return FALSE; root = quota_root_lookup(cmd->client->user, root_name); -#if 0 if (root == NULL && cmd->client->user->admin) { /* we're an admin. see if there's a quota root for another user. */ @@ -150,7 +149,6 @@ quota_root_lookup(owner, p + 1); } } -#endif if (root == NULL) { client_send_tagline(cmd, "NO Quota root doesn't exist."); return TRUE; From dovecot at dovecot.org Sun Dec 8 21:26:49 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sun, 08 Dec 2013 21:26:49 +0200 Subject: dovecot-2.2: quota: Added support for SETQUOTA IMAP command. Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/fa84a2cd1dce changeset: 17046:fa84a2cd1dce user: Timo Sirainen date: Sun Dec 08 21:26:29 2013 +0200 description: quota: Added support for SETQUOTA IMAP command. The configuration is done via quota_set setting. Currently only dict backend is supported. For example: plugin { quota_set = dict:file:/var/lib/dovecot/quota/%u } The SETQUOTA command is available only for the "admin" user (userdb lookup must return admin=y). diffstat: src/plugins/imap-quota/imap-quota-plugin.c | 5 ++ src/plugins/quota/quota-private.h | 2 + src/plugins/quota/quota.c | 70 ++++++++++++++++++++++++++--- 3 files changed, 69 insertions(+), 8 deletions(-) diffs (150 lines): diff -r 51edc7daf7f0 -r fa84a2cd1dce src/plugins/imap-quota/imap-quota-plugin.c --- a/src/plugins/imap-quota/imap-quota-plugin.c Sun Dec 08 21:24:10 2013 +0200 +++ b/src/plugins/imap-quota/imap-quota-plugin.c Sun Dec 08 21:26:29 2013 +0200 @@ -186,6 +186,11 @@ return TRUE; } + if (!cmd->client->user->admin) { + client_send_tagline(cmd, "NO Quota can be changed only by admin."); + return TRUE; + } + for (; !IMAP_ARG_IS_EOL(list_args); list_args += 2) { if (!imap_arg_get_atom(&list_args[0], &name) || !imap_arg_get_atom(&list_args[1], &value_str) || diff -r 51edc7daf7f0 -r fa84a2cd1dce src/plugins/quota/quota-private.h --- a/src/plugins/quota/quota-private.h Sun Dec 08 21:24:10 2013 +0200 +++ b/src/plugins/quota/quota-private.h Sun Dec 08 21:26:29 2013 +0200 @@ -88,6 +88,7 @@ struct quota_rule default_rule; ARRAY(struct quota_rule) rules; ARRAY(struct quota_warning_rule) warning_rules; + const char *limit_set; /* If user is under quota before saving a mail, allow the last mail to bring the user over quota by this many bytes. */ @@ -104,6 +105,7 @@ struct quota_root_settings *set; struct quota *quota; struct quota_backend backend; + struct dict *limit_set_dict; /* this quota root applies only to this namespace. it may also be a public namespace without an owner. */ diff -r 51edc7daf7f0 -r fa84a2cd1dce src/plugins/quota/quota.c --- a/src/plugins/quota/quota.c Sun Dec 08 21:24:10 2013 +0200 +++ b/src/plugins/quota/quota.c Sun Dec 08 21:26:29 2013 +0200 @@ -7,6 +7,7 @@ #include "net.h" #include "write-full.h" #include "eacces-error.h" +#include "dict.h" #include "mailbox-list-private.h" #include "quota-private.h" #include "quota-fs.h" @@ -20,6 +21,7 @@ "Quota exceeded (mailbox for user is full)" #define RULE_NAME_DEFAULT_FORCE "*" #define RULE_NAME_DEFAULT_NONFORCE "?" +#define QUOTA_LIMIT_SET_PATH DICT_PATH_PRIVATE"quota/limit/" struct quota_root_iter { struct quota *quota; @@ -111,6 +113,26 @@ } static int +quota_root_parse_set(struct mail_user *user, const char *root_name, + struct quota_root_settings *root_set, + const char **error_r) +{ + const char *name, *value; + + name = t_strconcat(root_name, "_set", NULL); + value = mail_user_plugin_getenv(user, name); + if (value == NULL) + return 0; + + if (strncmp(value, "dict:", 5) != 0) { + *error_r = t_strdup_printf("%s supports only dict backend", name); + return -1; + } + root_set->limit_set = p_strdup(root_set->set->pool, value+5); + return 0; +} + +static int quota_root_settings_init(struct quota_settings *quota_set, const char *root_def, struct quota_root_settings **set_r, const char **error_r) @@ -182,6 +204,8 @@ return -1; if (quota_root_parse_grace(user, root_name, root_set, error_r) < 0) return -1; + if (quota_root_parse_set(user, root_name, root_set, error_r) < 0) + return -1; return 0; } @@ -246,6 +270,8 @@ { pool_t pool = root->pool; + if (root->limit_set_dict != NULL) + dict_deinit(&root->limit_set_dict); root->backend.v.deinit(root); pool_unref(&pool); } @@ -972,15 +998,43 @@ return *limit_r == 0 ? 0 : 1; } -int quota_set_resource(struct quota_root *root ATTR_UNUSED, - const char *name ATTR_UNUSED, - uint64_t value ATTR_UNUSED, const char **error_r) +int quota_set_resource(struct quota_root *root, const char *name, + uint64_t value, const char **error_r) { - /* the quota information comes from userdb (or even config file), - so there's really no way to support this until some major changes - are done */ - *error_r = MAIL_ERRSTR_NO_PERMISSION; - return -1; + struct dict_transaction_context *trans; + const char *key; + + if (root->set->limit_set == NULL) { + *error_r = MAIL_ERRSTR_NO_PERMISSION; + return -1; + } + if (strcasecmp(name, QUOTA_NAME_STORAGE_KILOBYTES) == 0) + key = "storage"; + else if (strcasecmp(name, QUOTA_NAME_STORAGE_BYTES) == 0) + key = "bytes"; + else if (strcasecmp(name, QUOTA_NAME_MESSAGES) == 0) + key = "messages"; + else { + *error_r = t_strdup_printf("Unsupported resource name: %s", name); + return -1; + } + + if (root->limit_set_dict == NULL) { + if (dict_init(root->set->limit_set, DICT_DATA_TYPE_STRING, + root->quota->user->username, + root->quota->user->set->base_dir, + &root->limit_set_dict, error_r) < 0) + return -1; + } + + trans = dict_transaction_begin(root->limit_set_dict); + key = t_strdup_printf(QUOTA_LIMIT_SET_PATH"%s", key); + dict_set(trans, key, dec2str(value)); + if (dict_transaction_commit(&trans) < 0) { + *error_r = "Internal quota limit update error"; + return -1; + } + return 0; } struct quota_transaction_context *quota_transaction_begin(struct mailbox *box) From dovecot at dovecot.org Sun Dec 8 22:21:51 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sun, 08 Dec 2013 22:21:51 +0200 Subject: dovecot-2.2: master: Finished the previous DEBUG_OUTOFMEM -> COR... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/e8efac64e081 changeset: 17048:e8efac64e081 user: Timo Sirainen date: Sun Dec 08 22:21:40 2013 +0200 description: master: Finished the previous DEBUG_OUTOFMEM -> CORE_OUTOFMEM and CORE_ERROR change. diffstat: src/master/master-settings.c | 2 +- src/master/service-process.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diffs (26 lines): diff -r 10ded3e11a8e -r e8efac64e081 src/master/master-settings.c --- a/src/master/master-settings.c Sun Dec 08 22:20:12 2013 +0200 +++ b/src/master/master-settings.c Sun Dec 08 22:21:40 2013 +0200 @@ -217,7 +217,7 @@ .state_dir = PKG_STATEDIR, .libexec_dir = PKG_LIBEXECDIR, .instance_name = PACKAGE, - .import_environment = "TZ DEBUG_OUTOFMEM" ENV_SYSTEMD ENV_GDB, + .import_environment = "TZ CORE_OUTOFMEM CORE_ERROR" ENV_SYSTEMD ENV_GDB, .protocols = "imap pop3 lmtp", .listen = "*, ::", .ssl = "yes:no:required", diff -r 10ded3e11a8e -r e8efac64e081 src/master/service-process.c --- a/src/master/service-process.c Sun Dec 08 22:20:12 2013 +0200 +++ b/src/master/service-process.c Sun Dec 08 22:21:40 2013 +0200 @@ -428,8 +428,8 @@ service->set->name, (unsigned int)(service->vsz_limit/1024/1024)); } - if (getenv("DEBUG_OUTOFMEM") == NULL) - str_append(str, " - set DEBUG_OUTOFMEM=1 environment to get core dump"); + if (getenv("CORE_OUTOFMEM") == NULL) + str_append(str, " - set CORE_OUTOFMEM=1 environment to get core dump"); return str_c(str); case FATAL_EXEC: return "exec() failed"; From dovecot at dovecot.org Sun Dec 8 22:30:25 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sun, 08 Dec 2013 22:30:25 +0200 Subject: dovecot-2.2: fts: Fixed crash with some search queries in empty ... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/d837bd49ddee changeset: 17049:d837bd49ddee user: Timo Sirainen date: Sun Dec 08 22:30:10 2013 +0200 description: fts: Fixed crash with some search queries in empty mailbox. diffstat: src/plugins/fts/fts-search.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diffs (12 lines): diff -r e8efac64e081 -r d837bd49ddee src/plugins/fts/fts-search.c --- a/src/plugins/fts/fts-search.c Sun Dec 08 22:21:40 2013 +0200 +++ b/src/plugins/fts/fts-search.c Sun Dec 08 22:30:10 2013 +0200 @@ -23,6 +23,8 @@ if (!array_is_created(seq_range)) p_array_init(seq_range, fctx->result_pool, count); for (i = 0; i < count; i++) { + if (range[i].seq1 > range[i].seq2) + continue; mailbox_get_seq_range(fctx->box, range[i].seq1, range[i].seq2, &seq1, &seq2); if (seq1 != 0) From dovecot at dovecot.org Sun Dec 8 23:04:29 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sun, 08 Dec 2013 23:04:29 +0200 Subject: dovecot-2.2: quota: Allow mailbox names in quota_rules to contai... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/78b34eb7c6c5 changeset: 17050:78b34eb7c6c5 user: Timo Sirainen date: Sun Dec 08 23:04:18 2013 +0200 description: quota: Allow mailbox names in quota_rules to contain "*" and "?" wildcards. diffstat: src/plugins/quota/quota-private.h | 2 +- src/plugins/quota/quota-storage.c | 2 +- src/plugins/quota/quota.c | 36 +++++++++++++++++++++++++----------- 3 files changed, 27 insertions(+), 13 deletions(-) diffs (112 lines): diff -r d837bd49ddee -r 78b34eb7c6c5 src/plugins/quota/quota-private.h --- a/src/plugins/quota/quota-private.h Sun Dec 08 22:30:10 2013 +0200 +++ b/src/plugins/quota/quota-private.h Sun Dec 08 23:04:18 2013 +0200 @@ -30,7 +30,7 @@ }; struct quota_rule { - const char *mailbox_name; + const char *mailbox_mask; int64_t bytes_limit, count_limit; /* relative to default_rule */ diff -r d837bd49ddee -r 78b34eb7c6c5 src/plugins/quota/quota-storage.c --- a/src/plugins/quota/quota-storage.c Sun Dec 08 22:30:10 2013 +0200 +++ b/src/plugins/quota/quota-storage.c Sun Dec 08 23:04:18 2013 +0200 @@ -610,7 +610,7 @@ } array_foreach(&root->set->rules, rule) { - name = rule->mailbox_name; + name = rule->mailbox_mask; ns = mail_namespace_find(namespaces, name); if ((ns->flags & NAMESPACE_FLAG_UNUSABLE) != 0 && !silent_errors) diff -r d837bd49ddee -r 78b34eb7c6c5 src/plugins/quota/quota.c --- a/src/plugins/quota/quota.c Sun Dec 08 22:30:10 2013 +0200 +++ b/src/plugins/quota/quota.c Sun Dec 08 23:04:18 2013 +0200 @@ -7,6 +7,7 @@ #include "net.h" #include "write-full.h" #include "eacces-error.h" +#include "wildcard-match.h" #include "dict.h" #include "mailbox-list-private.h" #include "quota-private.h" @@ -384,7 +385,20 @@ struct quota_rule *rule; array_foreach_modifiable(&root_set->rules, rule) { - if (strcmp(rule->mailbox_name, name) == 0) + if (wildcard_match(name, rule->mailbox_mask) == 0) + return rule; + } + return NULL; +} + +static struct quota_rule * +quota_root_rule_find_exact(struct quota_root_settings *root_set, + const char *name) +{ + struct quota_rule *rule; + + array_foreach_modifiable(&root_set->rules, rule) { + if (strcmp(rule->mailbox_mask, name) == 0) return rule; } return NULL; @@ -570,7 +584,7 @@ const char *rule_def, const char **error_r) { struct quota_rule *rule; - const char *p, *mailbox_name; + const char *p, *mailbox_mask; int ret = 0; p = strchr(rule_def, ':'); @@ -579,20 +593,20 @@ return -1; } - /* : */ - mailbox_name = t_strdup_until(rule_def, p++); + /* : */ + mailbox_mask = t_strdup_until(rule_def, p++); - rule = quota_root_rule_find(root_set, mailbox_name); + rule = quota_root_rule_find_exact(root_set, mailbox_mask); if (rule == NULL) { - if (strcmp(mailbox_name, RULE_NAME_DEFAULT_NONFORCE) == 0) + if (strcmp(mailbox_mask, RULE_NAME_DEFAULT_NONFORCE) == 0) rule = &root_set->default_rule; - else if (strcmp(mailbox_name, RULE_NAME_DEFAULT_FORCE) == 0) { + else if (strcmp(mailbox_mask, RULE_NAME_DEFAULT_FORCE) == 0) { rule = &root_set->default_rule; root_set->force_default_rule = TRUE; } else { rule = array_append_space(&root_set->rules); - rule->mailbox_name = strcasecmp(mailbox_name, "INBOX") == 0 ? "INBOX" : - p_strdup(root_set->set->pool, mailbox_name); + rule->mailbox_mask = strcasecmp(mailbox_mask, "INBOX") == 0 ? "INBOX" : + p_strdup(root_set->set->pool, mailbox_mask); } } @@ -600,7 +614,7 @@ rule->ignore = TRUE; if (root_set->set->debug) { i_debug("Quota rule: root=%s mailbox=%s ignored", - root_set->name, mailbox_name); + root_set->name, mailbox_mask); } return 0; } @@ -629,7 +643,7 @@ i_debug("Quota rule: root=%s mailbox=%s " "bytes=%s%lld%s messages=%s%lld%s", - root_set->name, mailbox_name, + root_set->name, mailbox_mask, rule->bytes_limit > 0 ? rule_plus : "", (long long)rule->bytes_limit, rule->bytes_percent == 0 ? "" : From dovecot at dovecot.org Sun Dec 8 23:26:53 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sun, 08 Dec 2013 23:26:53 +0200 Subject: dovecot-2.2: stats: Workaround opening /proc/self/io in processe... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/7acfc7b1b8f4 changeset: 17051:7acfc7b1b8f4 user: Timo Sirainen date: Sun Dec 08 23:26:40 2013 +0200 description: stats: Workaround opening /proc/self/io in processes that have only temporarily dropped root privileges. diffstat: src/plugins/stats/stats-plugin.c | 35 ++++++++++++++++++++++++++--------- 1 files changed, 26 insertions(+), 9 deletions(-) diffs (46 lines): diff -r 78b34eb7c6c5 -r 7acfc7b1b8f4 src/plugins/stats/stats-plugin.c --- a/src/plugins/stats/stats-plugin.c Sun Dec 08 23:04:18 2013 +0200 +++ b/src/plugins/stats/stats-plugin.c Sun Dec 08 23:26:40 2013 +0200 @@ -119,16 +119,33 @@ static int process_io_open(void) { + uid_t uid; + + if (proc_io_fd != -1) + return proc_io_fd; + + if (proc_io_disabled) + return -1; + proc_io_fd = open(PROC_IO_PATH, O_RDONLY); + if (proc_io_fd == -1 && errno == EACCES) { + /* kludge: if we're running with permissions temporarily + dropped, get them temporarily back so we can open + /proc/self/io. */ + uid = geteuid(); + if (seteuid(0) == 0) { + proc_io_fd = open(PROC_IO_PATH, O_RDONLY); + if (seteuid(uid) < 0) { + /* oops, this is bad */ + i_fatal("stats: seteuid(%s) failed", dec2str(uid)); + } + } + errno = EACCES; + } if (proc_io_fd == -1) { - if (proc_io_disabled) - return -1; - proc_io_fd = open(PROC_IO_PATH, O_RDONLY); - if (proc_io_fd == -1) { - if (errno != ENOENT) - i_error("open(%s) failed: %m", PROC_IO_PATH); - proc_io_disabled = TRUE; - return -1; - } + if (errno != ENOENT) + i_error("open(%s) failed: %m", PROC_IO_PATH); + proc_io_disabled = TRUE; + return -1; } return proc_io_fd; } From dovecot at dovecot.org Sun Dec 8 23:41:44 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sun, 08 Dec 2013 23:41:44 +0200 Subject: dovecot-2.2: lib-http: Don't try to automatically retry requests... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/353c3e3edc52 changeset: 17052:353c3e3edc52 user: Timo Sirainen date: Sun Dec 08 23:41:33 2013 +0200 description: lib-http: Don't try to automatically retry requests whose payload was already lost. Patch by Stephan Bosch. diffstat: src/lib-http/http-client-connection.c | 54 +++++++++++++++++++--------------- src/lib-http/http-client-request.c | 34 ++++++++++++--------- 2 files changed, 50 insertions(+), 38 deletions(-) diffs (124 lines): diff -r 7acfc7b1b8f4 -r 353c3e3edc52 src/lib-http/http-client-connection.c --- a/src/lib-http/http-client-connection.c Sun Dec 08 23:26:40 2013 +0200 +++ b/src/lib-http/http-client-connection.c Sun Dec 08 23:41:33 2013 +0200 @@ -596,31 +596,37 @@ if (!aborted) { bool handled = FALSE; - /* failed Expect: */ - if (response.status == 417 && req->payload_sync) { - /* drop Expect: continue */ - req->payload_sync = FALSE; - conn->output_locked = FALSE; - conn->peer->no_payload_sync = TRUE; - if (http_client_request_try_retry(req)) - handled = TRUE; - /* redirection */ - } else if (!req->client->set.no_auto_redirect && - response.status / 100 == 3 && response.status != 304 && - response.location != NULL) { - /* redirect (possibly after delay) */ - if (http_client_request_delay_from_response(req, &response) >= 0) { - http_client_request_redirect - (req, response.status, response.location); - handled = TRUE; + /* don't redirect/retry if we're sending data in small + blocks via http_client_request_send_payload() + and we're not waiting for 100 continue */ + if (!req->payload_wait || + (req->payload_sync && !conn->payload_continue)) { + /* failed Expect: */ + if (response.status == 417 && req->payload_sync) { + /* drop Expect: continue */ + req->payload_sync = FALSE; + conn->output_locked = FALSE; + conn->peer->no_payload_sync = TRUE; + if (http_client_request_try_retry(req)) + handled = TRUE; + /* redirection */ + } else if (!req->client->set.no_auto_redirect && + response.status / 100 == 3 && response.status != 304 && + response.location != NULL) { + /* redirect (possibly after delay) */ + if (http_client_request_delay_from_response(req, &response) >= 0) { + http_client_request_redirect + (req, response.status, response.location); + handled = TRUE; + } + /* service unavailable */ + } else if (response.status == 503) { + /* automatically retry after delay if indicated */ + if ( response.retry_after != (time_t)-1 && + http_client_request_delay_from_response(req, &response) > 0 && + http_client_request_try_retry(req)) + handled = TRUE; } - /* service unavailable */ - } else if (response.status == 503) { - /* automatically retry after delay if indicated */ - if ( response.retry_after != (time_t)-1 && - http_client_request_delay_from_response(req, &response) > 0 && - http_client_request_try_retry(req)) - handled = TRUE; } if (!handled) { diff -r 7acfc7b1b8f4 -r 353c3e3edc52 src/lib-http/http-client-request.c --- a/src/lib-http/http-client-request.c Sun Dec 08 23:26:40 2013 +0200 +++ b/src/lib-http/http-client-request.c Sun Dec 08 23:41:33 2013 +0200 @@ -622,21 +622,23 @@ if (!req->have_hdr_expect && req->payload_sync) { str_append(rtext, "Expect: 100-continue\r\n"); } - if (req->payload_chunked) { - // FIXME: can't do this for a HTTP/1.0 server - if (!req->have_hdr_body_spec) - str_append(rtext, "Transfer-Encoding: chunked\r\n"); - req->payload_output = - http_transfer_chunked_ostream_create(output); - } else if (req->payload_input != NULL) { - /* send Content-Length if we have specified a payload, - even if it's 0 bytes. */ - if (!req->have_hdr_body_spec) { - str_printfa(rtext, "Content-Length: %"PRIuUOFF_T"\r\n", - req->payload_size); + if (req->payload_input != NULL) { + if (req->payload_chunked) { + // FIXME: can't do this for a HTTP/1.0 server + if (!req->have_hdr_body_spec) + str_append(rtext, "Transfer-Encoding: chunked\r\n"); + req->payload_output = + http_transfer_chunked_ostream_create(output); + } else { + /* send Content-Length if we have specified a payload, + even if it's 0 bytes. */ + if (!req->have_hdr_body_spec) { + str_printfa(rtext, "Content-Length: %"PRIuUOFF_T"\r\n", + req->payload_size); + } + req->payload_output = output; + o_stream_ref(output); } - req->payload_output = output; - o_stream_ref(output); } if (!req->have_hdr_connection && req->host_url == &req->origin_url) { /* https://tools.ietf.org/html/rfc2068 @@ -814,6 +816,8 @@ struct http_url *url; const char *error, *target, *origin_url; + i_assert(!req->payload_wait); + /* parse URL */ if (http_url_parse(location, NULL, 0, pool_datastack_create(), &url, &error) < 0) { @@ -901,6 +905,8 @@ void http_client_request_resubmit(struct http_client_request *req) { + i_assert(!req->payload_wait); + http_client_request_debug(req, "Resubmitting request"); /* rewind payload stream */ From dovecot at dovecot.org Mon Dec 9 00:03:07 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Mon, 09 Dec 2013 00:03:07 +0200 Subject: dovecot-2.2: mysql: Added ssl_verify_server_cert=no|yes parameter. Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/7a7898ffe87f changeset: 17053:7a7898ffe87f user: Timo Sirainen date: Mon Dec 09 00:02:58 2013 +0200 description: mysql: Added ssl_verify_server_cert=no|yes parameter. To make sure we don't break existing installations, default to "no". For v2.3 it should default to "yes". Patch by Gareth Palmer diffstat: configure.ac | 9 +++++++++ doc/example-config/dovecot-sql.conf.ext | 16 +++++++++------- src/lib-sql/driver-mysql.c | 15 ++++++++++++++- 3 files changed, 32 insertions(+), 8 deletions(-) diffs (91 lines): diff -r 353c3e3edc52 -r 7a7898ffe87f configure.ac --- a/configure.ac Sun Dec 08 23:41:33 2013 +0200 +++ b/configure.ac Mon Dec 09 00:02:58 2013 +0200 @@ -2287,6 +2287,15 @@ mysql_set_ssl(0, 0, 0, 0, 0, 0); ], [ AC_DEFINE(HAVE_MYSQL_SSL_CIPHER,, Define if your MySQL library supports setting cipher) + + AC_TRY_COMPILE([ + $ssl_define + #include + ], [ + int i = MYSQL_OPT_SSL_VERIFY_SERVER_CERT; + ], [ + AC_DEFINE(HAVE_MYSQL_SSL_VERIFY_SERVER_CERT,, Define if your MySQL library supports verifying the name in the SSL certificate) + ]) ]) ]) diff -r 353c3e3edc52 -r 7a7898ffe87f doc/example-config/dovecot-sql.conf.ext --- a/doc/example-config/dovecot-sql.conf.ext Sun Dec 08 23:41:33 2013 +0200 +++ b/doc/example-config/dovecot-sql.conf.ext Mon Dec 09 00:02:58 2013 +0200 @@ -47,13 +47,15 @@ # host, port, user, password, dbname # # But also adds some new settings: -# client_flags - See MySQL manual -# ssl_ca, ssl_ca_path - Set either one or both to enable SSL -# ssl_cert, ssl_key - For sending client-side certificates to server -# ssl_cipher - Set minimum allowed cipher security (default: HIGH) -# option_file - Read options from the given file instead of -# the default my.cnf location -# option_group - Read options from the given group (default: client) +# client_flags - See MySQL manual +# ssl_ca, ssl_ca_path - Set either one or both to enable SSL +# ssl_cert, ssl_key - For sending client-side certificates to server +# ssl_cipher - Set minimum allowed cipher security (default: HIGH) +# ssl_verify_server_cert - Verify that the name in the server SSL certificate +# matches the host (default: no) +# option_file - Read options from the given file instead of +# the default my.cnf location +# option_group - Read options from the given group (default: client) # # You can connect to UNIX sockets by using host: host=/var/run/mysql.sock # Note that currently you can't use spaces in parameters. diff -r 353c3e3edc52 -r 7a7898ffe87f src/lib-sql/driver-mysql.c --- a/src/lib-sql/driver-mysql.c Sun Dec 08 23:41:33 2013 +0200 +++ b/src/lib-sql/driver-mysql.c Mon Dec 09 00:02:58 2013 +0200 @@ -28,6 +28,7 @@ pool_t pool; const char *user, *password, *dbname, *host, *unix_socket; const char *ssl_cert, *ssl_key, *ssl_ca, *ssl_ca_path, *ssl_cipher; + int ssl_verify_server_cert; const char *option_file, *option_group; unsigned int port, client_flags; time_t last_success; @@ -104,6 +105,10 @@ , db->ssl_cipher #endif ); +#ifdef HAVE_MYSQL_SSL_VERIFY_SERVER_CERT + mysql_options(db->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, + &db->ssl_verify_server_cert); +#endif db->ssl_set = TRUE; #else i_fatal("mysql: SSL support not compiled in " @@ -152,6 +157,7 @@ const char **field; db->ssl_cipher = "HIGH"; + db->ssl_verify_server_cert = 0; /* FIXME: change to 1 for v2.3 */ args = t_strsplit_spaces(connect_string, " "); for (; *args != NULL; args++) { @@ -187,7 +193,14 @@ field = &db->ssl_ca_path; else if (strcmp(name, "ssl_cipher") == 0) field = &db->ssl_cipher; - else if (strcmp(name, "option_file") == 0) + else if (strcmp(name, "ssl_verify_server_cert") == 0) { + if (strcmp(value, "yes") == 0) + db->ssl_verify_server_cert = 1; + else if (strcmp(value, "no") == 0) + db->ssl_verify_server_cert = 0; + else + i_fatal("mysql: Invalid boolean: %s", value); + } else if (strcmp(name, "option_file") == 0) field = &db->option_file; else if (strcmp(name, "option_group") == 0) field = &db->option_group; From dovecot at dovecot.org Mon Dec 9 15:42:35 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Mon, 09 Dec 2013 15:42:35 +0200 Subject: dovecot-2.2: quota: Fix to previous wildcard change Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/feb656fd212e changeset: 17054:feb656fd212e user: Timo Sirainen date: Mon Dec 09 15:42:20 2013 +0200 description: quota: Fix to previous wildcard change diffstat: src/plugins/quota/quota.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 7a7898ffe87f -r feb656fd212e src/plugins/quota/quota.c --- a/src/plugins/quota/quota.c Mon Dec 09 00:02:58 2013 +0200 +++ b/src/plugins/quota/quota.c Mon Dec 09 15:42:20 2013 +0200 @@ -385,7 +385,7 @@ struct quota_rule *rule; array_foreach_modifiable(&root_set->rules, rule) { - if (wildcard_match(name, rule->mailbox_mask) == 0) + if (wildcard_match(name, rule->mailbox_mask)) return rule; } return NULL; From dovecot at dovecot.org Mon Dec 9 18:41:47 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Mon, 09 Dec 2013 18:41:47 +0200 Subject: dovecot-2.2: master: Include used protocols in the "starting up"... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/e49f481af55b changeset: 17055:e49f481af55b user: Timo Sirainen date: Mon Dec 09 18:41:30 2013 +0200 description: master: Include used protocols in the "starting up" log message. diffstat: src/master/main.c | 19 ++++++++++++++----- 1 files changed, 14 insertions(+), 5 deletions(-) diffs (50 lines): diff -r feb656fd212e -r e49f481af55b src/master/main.c --- a/src/master/main.c Mon Dec 09 15:42:20 2013 +0200 +++ b/src/master/main.c Mon Dec 09 18:41:30 2013 +0200 @@ -10,6 +10,7 @@ #include "hostpid.h" #include "abspath.h" #include "ipwd.h" +#include "str.h" #include "execv-const.h" #include "mountpoint-list.h" #include "restrict-process-size.h" @@ -487,17 +488,25 @@ env_put(t_strconcat(DOVECOT_PRESERVE_ENVS_ENV"=", value, NULL)); } -static void main_log_startup(void) +static void main_log_startup(char **protocols) { #define STARTUP_STRING PACKAGE_NAME" v"DOVECOT_VERSION_FULL" starting up" + string_t *str = t_str_new(128); rlim_t core_limit; + str_append(str, STARTUP_STRING); + if (protocols[0] == NULL) + str_append(str, " without any protocols"); + else { + str_printfa(str, " for %s", + t_strarray_join((const char **)protocols, ", ")); + } + core_dumps_disabled = restrict_get_core_limit(&core_limit) == 0 && core_limit == 0; if (core_dumps_disabled) - i_info(STARTUP_STRING" (core dumps disabled)"); - else - i_info(STARTUP_STRING); + str_append(str, " (core dumps disabled)"); + i_info("%s", str_c(str)); } static void master_set_process_limit(void) @@ -529,7 +538,7 @@ /* deny file access from everyone else except owner */ (void)umask(0077); - main_log_startup(); + main_log_startup(set->protocols_split); lib_signals_init(); lib_signals_ignore(SIGPIPE, TRUE); From dovecot at dovecot.org Wed Dec 11 18:39:52 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Wed, 11 Dec 2013 18:39:52 +0200 Subject: dovecot-2.2: auth: Use refcounting for LDAPMessage to make sure ... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/d9cf369a8b6d changeset: 17057:d9cf369a8b6d user: Timo Sirainen date: Wed Dec 11 18:39:36 2013 +0200 description: auth: Use refcounting for LDAPMessage to make sure it always gets freed correctly. This may fix some memory leaks in some (error?) cases. diffstat: src/auth/db-ldap.c | 95 +++++++++++++++++++++++++++++++---------------------- src/auth/db-ldap.h | 4 +- 2 files changed, 57 insertions(+), 42 deletions(-) diffs (291 lines): diff -r 3f7cc2dd6410 -r d9cf369a8b6d src/auth/db-ldap.c --- a/src/auth/db-ldap.c Wed Dec 11 18:39:08 2013 +0200 +++ b/src/auth/db-ldap.c Wed Dec 11 18:39:36 2013 +0200 @@ -50,6 +50,11 @@ # define LDAP_OPT_SUCCESS LDAP_SUCCESS #endif +struct db_ldap_result { + int refcount; + LDAPMessage *msg; +}; + struct db_ldap_value { const char **values; bool used; @@ -475,14 +480,14 @@ } static void db_ldap_default_bind_finished(struct ldap_connection *conn, - LDAPMessage *res) + struct db_ldap_result *res) { int ret; i_assert(conn->pending_count == 0); conn->default_bind_msgid = -1; - ret = ldap_result2error(conn->ld, res, FALSE); + ret = ldap_result2error(conn->ld, res->msg, FALSE); if (db_ldap_connect_finish(conn, ret) < 0) { /* lost connection, close it */ db_ldap_conn_close(conn); @@ -551,14 +556,14 @@ static int db_ldap_fields_get_dn(struct ldap_connection *conn, struct ldap_request_search *request, - LDAPMessage *res) + struct db_ldap_result *res) { struct auth_request *auth_request = request->request.auth_request; struct ldap_request_named_result *named_res; struct db_ldap_result_iterate_context *ldap_iter; const char *name, *const *values; - ldap_iter = db_ldap_result_iterate_init_full(conn, request, res, + ldap_iter = db_ldap_result_iterate_init_full(conn, request, res->msg, TRUE, TRUE); while (db_ldap_result_iterate_next(ldap_iter, &name, &values)) { if (values[1] != NULL) { @@ -654,7 +659,7 @@ } static int db_ldap_search_save_result(struct ldap_request_search *request, - LDAPMessage *res) + struct db_ldap_result *res) { struct ldap_request_named_result *named_res; @@ -669,12 +674,13 @@ return -1; named_res->result = res; } + res->refcount++; return 0; } static int db_ldap_search_next_subsearch(struct ldap_connection *conn, struct ldap_request_search *request, - LDAPMessage *res) + struct db_ldap_result *res) { struct ldap_request_named_result *named_res; const struct ldap_field *field; @@ -716,7 +722,7 @@ static bool db_ldap_handle_request_result(struct ldap_connection *conn, struct ldap_request *request, unsigned int idx, - LDAPMessage *res) + struct db_ldap_result *res) { struct ldap_request_search *srequest = NULL; const struct ldap_request_named_result *named_res; @@ -731,7 +737,7 @@ conn->conn_state = LDAP_CONN_STATE_BOUND_AUTH; } else { srequest = (struct ldap_request_search *)request; - switch (ldap_msgtype(res)) { + switch (ldap_msgtype(res->msg)) { case LDAP_RES_SEARCH_ENTRY: case LDAP_RES_SEARCH_RESULT: break; @@ -740,16 +746,16 @@ return FALSE; default: i_error("LDAP: Reply with unexpected type %d", - ldap_msgtype(res)); + ldap_msgtype(res->msg)); return TRUE; } } - if (ldap_msgtype(res) == LDAP_RES_SEARCH_ENTRY) { + if (ldap_msgtype(res->msg) == LDAP_RES_SEARCH_ENTRY) { ret = LDAP_SUCCESS; final_result = FALSE; } else { final_result = TRUE; - ret = ldap_result2error(conn->ld, res, 0); + ret = ldap_result2error(conn->ld, res->msg, 0); } if (ret != LDAP_SUCCESS && request->type == LDAP_REQUEST_TYPE_SEARCH) { /* handle search failures here */ @@ -778,14 +784,13 @@ "LDAP search returned multiple entries"); res = NULL; } else { - /* wait for finish, don't free the result yet */ + /* wait for finish */ return FALSE; } } else { ret = db_ldap_search_next_subsearch(conn, srequest, res); if (ret > 0) { - /* free this result, but not the others */ - ldap_msgfree(res); + /* more LDAP queries left */ return FALSE; } if (ret < 0) @@ -806,9 +811,9 @@ T_BEGIN { if (res != NULL && srequest != NULL && srequest->result != NULL) - request->callback(conn, request, srequest->result); + request->callback(conn, request, srequest->result->msg); - request->callback(conn, request, res); + request->callback(conn, request, res->msg); } T_END; if (idx > 0) { @@ -820,67 +825,71 @@ return TRUE; } -static void db_ldap_request_free(struct ldap_request *request, LDAPMessage *res) +static void db_ldap_result_unref(struct db_ldap_result **_res) +{ + struct db_ldap_result *res = *_res; + + *_res = NULL; + i_assert(res->refcount > 0); + if (--res->refcount == 0) { + ldap_msgfree(res->msg); + i_free(res); + } +} + +static void +db_ldap_request_free(struct ldap_request *request) { if (request->type == LDAP_REQUEST_TYPE_SEARCH) { struct ldap_request_search *srequest = (struct ldap_request_search *)request; - const struct ldap_request_named_result *named_res; + struct ldap_request_named_result *named_res; - if (srequest->result == res) - res = NULL; - if (srequest->result != NULL) { - ldap_msgfree(srequest->result); - srequest->result = NULL; - } + if (srequest->result != NULL) + db_ldap_result_unref(&srequest->result); if (array_is_created(&srequest->named_results)) { - array_foreach(&srequest->named_results, named_res) { - if (named_res->result == res) - res = NULL; + array_foreach_modifiable(&srequest->named_results, named_res) { if (named_res->result != NULL) - ldap_msgfree(named_res->result); + db_ldap_result_unref(&named_res->result); } array_clear(&srequest->named_results); } } - if (res != NULL) - ldap_msgfree(res); } static void -db_ldap_handle_result(struct ldap_connection *conn, LDAPMessage *res) +db_ldap_handle_result(struct ldap_connection *conn, struct db_ldap_result *res) { struct auth_request *auth_request; struct ldap_request *request; unsigned int idx; int msgid; - msgid = ldap_msgid(res); + msgid = ldap_msgid(res->msg); if (msgid == conn->default_bind_msgid) { db_ldap_default_bind_finished(conn, res); - ldap_msgfree(res); return; } request = db_ldap_find_request(conn, msgid, &idx); if (request == NULL) { i_error("LDAP: Reply with unknown msgid %d", msgid); - ldap_msgfree(res); return; } /* request is allocated from auth_request's pool */ auth_request = request->auth_request; auth_request_ref(auth_request); if (db_ldap_handle_request_result(conn, request, idx, res)) - db_ldap_request_free(request, res); + db_ldap_request_free(request); auth_request_unref(&auth_request); } static void ldap_input(struct ldap_connection *conn) { struct timeval timeout; - LDAPMessage *res; + struct db_ldap_result *res; + LDAPMessage *msg; time_t prev_reply_diff; int ret; @@ -889,18 +898,22 @@ return; memset(&timeout, 0, sizeof(timeout)); - ret = ldap_result(conn->ld, LDAP_RES_ANY, 0, &timeout, &res); + ret = ldap_result(conn->ld, LDAP_RES_ANY, 0, &timeout, &msg); #ifdef OPENLDAP_ASYNC_WORKAROUND if (ret == 0) { /* try again, there may be another in buffer */ ret = ldap_result(conn->ld, LDAP_RES_ANY, 0, - &timeout, &res); + &timeout, &msg); } #endif if (ret <= 0) break; + res = i_new(struct db_ldap_result, 1); + res->refcount = 1; + res->msg = msg; db_ldap_handle_result(conn, res); + db_ldap_result_unref(&res); } while (conn->io != NULL); prev_reply_diff = ioloop_time - conn->last_reply_stamp; @@ -1502,8 +1515,10 @@ if (array_is_created(&ldap_request->named_results)) { array_foreach(&ldap_request->named_results, named_res) { suffix = t_strdup_printf("@%s", named_res->field->name); - if (named_res->result != NULL) - get_ldap_fields(ctx, conn, named_res->result, suffix); + if (named_res->result != NULL) { + get_ldap_fields(ctx, conn, + named_res->result->msg, suffix); + } } } return ctx; diff -r 3f7cc2dd6410 -r d9cf369a8b6d src/auth/db-ldap.h --- a/src/auth/db-ldap.h Wed Dec 11 18:39:08 2013 +0200 +++ b/src/auth/db-ldap.h Wed Dec 11 18:39:36 2013 +0200 @@ -110,7 +110,7 @@ struct ldap_request_named_result { const struct ldap_field *field; const char *dn; - LDAPMessage *result; + struct db_ldap_result *result; }; struct ldap_request_search { @@ -121,7 +121,7 @@ char **attributes; /* points to pass_attr_names / user_attr_names */ const ARRAY_TYPE(ldap_field) *attr_map; - LDAPMessage *result; + struct db_ldap_result *result; ARRAY(struct ldap_request_named_result) named_results; unsigned int name_idx; From dovecot at dovecot.org Wed Dec 11 18:39:52 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Wed, 11 Dec 2013 18:39:52 +0200 Subject: dovecot-2.2: auth: ldap with auth_bind=yes leaked memory Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/3f7cc2dd6410 changeset: 17056:3f7cc2dd6410 user: Timo Sirainen date: Wed Dec 11 18:39:08 2013 +0200 description: auth: ldap with auth_bind=yes leaked memory Existing LDAP search request can't just be converted into bind request before the search request is freed. So just create a new request. diffstat: src/auth/passdb-ldap.c | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-) diffs (35 lines): diff -r e49f481af55b -r 3f7cc2dd6410 src/auth/passdb-ldap.c --- a/src/auth/passdb-ldap.c Mon Dec 09 18:41:30 2013 +0200 +++ b/src/auth/passdb-ldap.c Wed Dec 11 18:39:08 2013 +0200 @@ -236,7 +236,7 @@ struct passdb_ldap_request *passdb_ldap_request = (struct passdb_ldap_request *)ldap_request; struct auth_request *auth_request = ldap_request->auth_request; - struct ldap_request_bind *brequest; + struct passdb_ldap_request *brequest; char *dn; if (res != NULL && ldap_msgtype(res) == LDAP_RES_SEARCH_ENTRY) { @@ -257,14 +257,16 @@ /* failure */ ldap_bind_lookup_dn_fail(auth_request, passdb_ldap_request, res); } else { - /* convert search request to bind request */ - brequest = &passdb_ldap_request->request.bind; - memset(brequest, 0, sizeof(*brequest)); - brequest->request.type = LDAP_REQUEST_TYPE_BIND; - brequest->request.auth_request = auth_request; + /* create a new bind request */ + brequest = p_new(auth_request->pool, + struct passdb_ldap_request, 1); brequest->dn = passdb_ldap_request->dn; + brequest->callback = passdb_ldap_request->callback; + brequest->request.bind.dn = brequest->dn; + brequest->request.bind.request.type = LDAP_REQUEST_TYPE_BIND; + brequest->request.bind.request.auth_request = auth_request; - ldap_auth_bind(conn, brequest); + ldap_auth_bind(conn, &brequest->request.bind); } } From dovecot at dovecot.org Wed Dec 11 19:39:28 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Wed, 11 Dec 2013 19:39:28 +0200 Subject: dovecot-2.2: login-*: Make sure "need to write more" flag doesn'... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/c0236d1c4a04 changeset: 17058:c0236d1c4a04 user: Timo Sirainen date: Wed Dec 11 19:39:12 2013 +0200 description: login-*: Make sure "need to write more" flag doesn't get stuck during handshake. This should prevent busy-looping in SSL_accept(). (Second attempt at doing this, first one was in e95479f439aa.) diffstat: src/login-common/ssl-proxy-openssl.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diffs (15 lines): diff -r d9cf369a8b6d -r c0236d1c4a04 src/login-common/ssl-proxy-openssl.c --- a/src/login-common/ssl-proxy-openssl.c Wed Dec 11 18:39:36 2013 +0200 +++ b/src/login-common/ssl-proxy-openssl.c Wed Dec 11 19:39:12 2013 +0200 @@ -539,8 +539,10 @@ { proxy->refcount++; - if (!proxy->handshaked) + if (!proxy->handshaked) { + ssl_set_io(proxy, SSL_REMOVE_OUTPUT); ssl_handshake(proxy); + } if (proxy->handshaked) { if (proxy->plainout_size == sizeof(proxy->plainout_buf)) From dovecot at dovecot.org Thu Dec 12 16:37:49 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 12 Dec 2013 16:37:49 +0200 Subject: dovecot-2.2: lzma: Reading until EOF without seeing LZMA_STREAM_... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/fb157c79473e changeset: 17059:fb157c79473e user: Timo Sirainen date: Thu Dec 12 16:37:37 2013 +0200 description: lzma: Reading until EOF without seeing LZMA_STREAM_END isn't an error. diffstat: src/lib-compression/istream-lzma.c | 15 ++++++++++----- 1 files changed, 10 insertions(+), 5 deletions(-) diffs (39 lines): diff -r c0236d1c4a04 -r fb157c79473e src/lib-compression/istream-lzma.c --- a/src/lib-compression/istream-lzma.c Wed Dec 11 19:39:12 2013 +0200 +++ b/src/lib-compression/istream-lzma.c Thu Dec 12 16:37:37 2013 +0200 @@ -49,6 +49,13 @@ i_error("%s", zstream->istream.iostream.error); } +static void lzma_stream_end(struct lzma_istream *zstream) +{ + zstream->eof_offset = zstream->istream.istream.v_offset + + (zstream->istream.pos - zstream->istream.skip); + zstream->stream_size = zstream->eof_offset; +} + static ssize_t i_stream_lzma_read(struct istream_private *stream) { struct lzma_istream *zstream = (struct lzma_istream *)stream; @@ -109,8 +116,8 @@ stream->parent->stream_errno; } else { i_assert(stream->parent->eof); - lzma_read_error(zstream, "unexpected EOF"); - stream->istream.stream_errno = EINVAL; + lzma_stream_end(zstream); + stream->istream.eof = TRUE; } return -1; } @@ -153,9 +160,7 @@ i_fatal_status(FATAL_OUTOFMEM, "lzma.read(%s): Out of memory", i_stream_get_name(&stream->istream)); case LZMA_STREAM_END: - zstream->eof_offset = stream->istream.v_offset + - (stream->pos - stream->skip); - zstream->stream_size = zstream->eof_offset; + lzma_stream_end(zstream); if (out_size == 0) { stream->istream.eof = TRUE; return -1; From dovecot at dovecot.org Thu Dec 12 17:59:38 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 12 Dec 2013 17:59:38 +0200 Subject: dovecot-2.2: auth: Don't crash when userdb hasn't been specified... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/eaadd1e1fea2 changeset: 17060:eaadd1e1fea2 user: Timo Sirainen date: Thu Dec 12 17:59:28 2013 +0200 description: auth: Don't crash when userdb hasn't been specified at all. diffstat: src/auth/auth-settings.c | 1 + src/auth/auth.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletions(-) diffs (28 lines): diff -r fb157c79473e -r eaadd1e1fea2 src/auth/auth-settings.c --- a/src/auth/auth-settings.c Thu Dec 12 16:37:37 2013 +0200 +++ b/src/auth/auth-settings.c Thu Dec 12 17:59:28 2013 +0200 @@ -172,6 +172,7 @@ }; static const struct auth_userdb_settings auth_userdb_default_settings = { + /* NOTE: when adding fields, update also auth.c:userdb_dummy_set */ .driver = "", .args = "", .default_fields = "", diff -r fb157c79473e -r eaadd1e1fea2 src/auth/auth.c --- a/src/auth/auth.c Thu Dec 12 16:37:37 2013 +0200 +++ b/src/auth/auth.c Thu Dec 12 17:59:28 2013 +0200 @@ -13,7 +13,12 @@ .driver = "static", .args = "", .default_fields = "", - .override_fields = "" + .override_fields = "", + + .skip = "never", + .result_success = "return-ok", + .result_failure = "continue", + .result_internalfail = "continue" }; static ARRAY(struct auth *) auths; From dovecot at dovecot.org Thu Dec 12 18:08:36 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 12 Dec 2013 18:08:36 +0200 Subject: dovecot-2.2: auth: Previous userdb changes caused userdb prefetc... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/1600e97dabbb changeset: 17061:1600e97dabbb user: Timo Sirainen date: Thu Dec 12 18:08:25 2013 +0200 description: auth: Previous userdb changes caused userdb prefetch to be used always. diffstat: src/auth/auth-request.c | 12 +++++++----- src/auth/auth-request.h | 3 +++ src/auth/userdb-prefetch.c | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diffs (62 lines): diff -r eaadd1e1fea2 -r 1600e97dabbb src/auth/auth-request.c --- a/src/auth/auth-request.c Thu Dec 12 17:59:28 2013 +0200 +++ b/src/auth/auth-request.c Thu Dec 12 18:08:25 2013 +0200 @@ -631,10 +631,12 @@ auth_fields_rollback(request->extra_fields); if (request->userdb_reply == NULL) ; - else if (!request->snapshot_has_userdb_reply) + else if (request->snapshot_has_userdb_reply) + auth_fields_rollback(request->userdb_reply); + else { request->userdb_reply = NULL; - else - auth_fields_rollback(request->userdb_reply); + request->userdb_prefetch_set = FALSE; + } } if (*result == PASSDB_RESULT_USER_UNKNOWN) { @@ -1426,6 +1428,7 @@ auth_request_validate_networks(request, value); } else if (strncmp(name, "userdb_", 7) == 0) { /* for prefetch userdb */ + request->userdb_prefetch_set = TRUE; if (request->userdb_reply == NULL) auth_request_init_userdb_reply(request); auth_request_set_userdb_field(request, name + 7, value); @@ -1478,8 +1481,7 @@ if (strncmp(name, "userdb_", 7) == 0) { /* make sure userdb prefetch is used even if all the fields were returned as NULL. */ - if (request->userdb_reply == NULL) - auth_request_init_userdb_reply(request); + request->userdb_prefetch_set = TRUE; } } diff -r eaadd1e1fea2 -r 1600e97dabbb src/auth/auth-request.h --- a/src/auth/auth-request.h Thu Dec 12 17:59:28 2013 +0200 +++ b/src/auth/auth-request.h Thu Dec 12 18:08:25 2013 +0200 @@ -136,6 +136,9 @@ or because one of the returned uid/gid fields couldn't be translated to a number */ unsigned int userdb_lookup_tempfailed:1; + /* userdb_* fields have been set by the passdb lookup, userdb prefetch + will work. */ + unsigned int userdb_prefetch_set:1; /* ... mechanism specific data ... */ }; diff -r eaadd1e1fea2 -r 1600e97dabbb src/auth/userdb-prefetch.c --- a/src/auth/userdb-prefetch.c Thu Dec 12 17:59:28 2013 +0200 +++ b/src/auth/userdb-prefetch.c Thu Dec 12 18:08:25 2013 +0200 @@ -15,7 +15,7 @@ { /* auth_request_set_field() should have already placed the userdb_* values to userdb_reply. */ - if (auth_request->userdb_reply == NULL) { + if (!auth_request->userdb_prefetch_set) { if (auth_request_get_auth(auth_request)->userdbs->next == NULL) { /* no other userdbs */ if (auth_request->userdb_lookup) { From dovecot at dovecot.org Thu Dec 12 18:21:59 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 12 Dec 2013 18:21:59 +0200 Subject: dovecot-2.2: lib-master: Show better error message when process_... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/3535659d6cc2 changeset: 17062:3535659d6cc2 user: Timo Sirainen date: Thu Dec 12 18:21:49 2013 +0200 description: lib-master: Show better error message when process_limit is reached. diffstat: src/lib-master/master-auth.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diffs (23 lines): diff -r 1600e97dabbb -r 3535659d6cc2 src/lib-master/master-auth.c --- a/src/lib-master/master-auth.c Thu Dec 12 18:08:25 2013 +0200 +++ b/src/lib-master/master-auth.c Thu Dec 12 18:21:49 2013 +0200 @@ -108,14 +108,14 @@ ret = read(conn->fd, conn->buf + conn->buf_pos, sizeof(conn->buf) - conn->buf_pos); if (ret <= 0) { - if (ret < 0) { + if (ret == 0 || errno == ECONNRESET) { + i_error("read(%s) failed: Remote closed connection " + "(service's process_limit reached?)", + conn->auth->path, conn->auth->path); + } else { if (errno == EAGAIN) return; i_error("read(%s) failed: %m", conn->auth->path); - } else { - i_error("read(%s) failed: Remote closed connection " - "(process_limit reached?)", - conn->auth->path); } master_auth_connection_deinit(&conn); return; From dovecot at dovecot.org Fri Dec 13 13:44:45 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Fri, 13 Dec 2013 13:44:45 +0200 Subject: dovecot-2.2: ldap: Added blocking=yes setting to use auth-workers. Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/89f1cefe0f89 changeset: 17063:89f1cefe0f89 user: Timo Sirainen date: Fri Dec 13 13:44:32 2013 +0200 description: ldap: Added blocking=yes setting to use auth-workers. diffstat: src/auth/db-ldap.c | 4 +++- src/auth/db-ldap.h | 1 + src/auth/passdb-ldap.c | 1 + src/auth/userdb-ldap.c | 1 + 4 files changed, 6 insertions(+), 1 deletions(-) diffs (54 lines): diff -r 3535659d6cc2 -r 89f1cefe0f89 src/auth/db-ldap.c --- a/src/auth/db-ldap.c Thu Dec 12 18:21:49 2013 +0200 +++ b/src/auth/db-ldap.c Fri Dec 13 13:44:32 2013 +0200 @@ -120,6 +120,7 @@ DEF_STR(iterate_filter), DEF_STR(default_pass_scheme), DEF_BOOL(userdb_warning_disable), + DEF_BOOL(blocking), { 0, NULL, 0 } }; @@ -155,7 +156,8 @@ .iterate_attrs = "uid=user", .iterate_filter = "(objectClass=posixAccount)", .default_pass_scheme = "crypt", - .userdb_warning_disable = FALSE + .userdb_warning_disable = FALSE, + .blocking = FALSE }; static struct ldap_connection *ldap_connections = NULL; diff -r 3535659d6cc2 -r 89f1cefe0f89 src/auth/db-ldap.h --- a/src/auth/db-ldap.h Thu Dec 12 18:21:49 2013 +0200 +++ b/src/auth/db-ldap.h Fri Dec 13 13:44:32 2013 +0200 @@ -64,6 +64,7 @@ const char *default_pass_scheme; bool userdb_warning_disable; /* deprecated for now at least */ + bool blocking; /* ... */ int ldap_deref, ldap_scope; diff -r 3535659d6cc2 -r 89f1cefe0f89 src/auth/passdb-ldap.c --- a/src/auth/passdb-ldap.c Thu Dec 12 18:21:49 2013 +0200 +++ b/src/auth/passdb-ldap.c Fri Dec 13 13:44:32 2013 +0200 @@ -421,6 +421,7 @@ db_ldap_set_attrs(conn, conn->set.pass_attrs, &conn->pass_attr_names, &conn->pass_attr_map, conn->set.auth_bind ? "password" : NULL); + module->module.blocking = conn->set.blocking; module->module.cache_key = auth_cache_parse_key(pool, t_strconcat(conn->set.base, diff -r 3535659d6cc2 -r 89f1cefe0f89 src/auth/userdb-ldap.c --- a/src/auth/userdb-ldap.c Thu Dec 12 18:21:49 2013 +0200 +++ b/src/auth/userdb-ldap.c Fri Dec 13 13:44:32 2013 +0200 @@ -272,6 +272,7 @@ db_ldap_set_attrs(conn, conn->set.iterate_attrs, &conn->iterate_attr_names, &conn->iterate_attr_map, NULL); + module->module.blocking = conn->set.blocking; module->module.cache_key = auth_cache_parse_key(pool, t_strconcat(conn->set.base, From pigeonhole at rename-it.nl Fri Dec 13 22:36:10 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Fri, 13 Dec 2013 21:36:10 +0100 Subject: dovecot-2.2-pigeonhole: Sieve extprograms plugin: Fixed fd leak ... Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/61772824b4ea changeset: 1822:61772824b4ea user: Stephan Bosch date: Fri Dec 13 21:35:58 2013 +0100 description: Sieve extprograms plugin: Fixed fd leak and handling of output shutdown. Output stream remained open, including the flush io, causing a second assert failure. Whether this fixes the problem entirely remains to be seen. diffstat: src/plugins/sieve-extprograms/script-client-local.c | 1 - src/plugins/sieve-extprograms/script-client.c | 23 +++++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diffs (65 lines): diff -r bb3fbd27372a -r 61772824b4ea src/plugins/sieve-extprograms/script-client-local.c --- a/src/plugins/sieve-extprograms/script-client-local.c Wed Nov 20 19:34:28 2013 +0100 +++ b/src/plugins/sieve-extprograms/script-client-local.c Fri Dec 13 21:35:58 2013 +0100 @@ -139,7 +139,6 @@ i_error("shutdown(%s, SHUT_WR) failed: %m", sclient->path); return -1; } - sclient->fd_out = -1; return 1; } diff -r bb3fbd27372a -r 61772824b4ea src/plugins/sieve-extprograms/script-client.c --- a/src/plugins/sieve-extprograms/script-client.c Wed Nov 20 19:34:28 2013 +0100 +++ b/src/plugins/sieve-extprograms/script-client.c Fri Dec 13 21:35:58 2013 +0100 @@ -39,6 +39,20 @@ return 1; } +static int script_client_close_output(struct script_client *sclient) +{ + int ret; + + if ( (ret=sclient->close_output(sclient)) < 0 ) + return -1; + if ( sclient->script_output != NULL ) + o_stream_destroy(&sclient->script_output); + sclient->script_output = NULL; + sclient->fd_out = -1; + + return ret; +} + static void script_client_disconnect (struct script_client *sclient, bool force) { @@ -50,7 +64,7 @@ if ( sclient->disconnected ) return; - if ( (ret=sclient->close_output(sclient)) < 0 ) + if ( (ret=script_client_close_output(sclient)) < 0 ) error = TRUE; if ( (ret=sclient->disconnect(sclient, force)) < 0 ) @@ -68,7 +82,8 @@ if (sclient->fd_in != -1 && close(sclient->fd_in) < 0) i_error("close(%s) failed: %m", sclient->path); - if (sclient->fd_out != -1 && sclient->fd_out != sclient->fd_out) + if (sclient->fd_out != -1 && sclient->fd_out != sclient->fd_in + && close(sclient->fd_out) < 0) i_error("close(%s/out) failed: %m", sclient->path); sclient->fd_in = sclient->fd_out = -1; @@ -147,8 +162,8 @@ if ( sclient->script_input == NULL ) { script_client_disconnect(sclient, FALSE); - } else { - sclient->close_output(sclient); + } else if (script_client_close_output(sclient) < 0) { + return -1; } return 0; } From dovecot at dovecot.org Sat Dec 14 14:40:24 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Sat, 14 Dec 2013 14:40:24 +0200 Subject: dovecot-2.2: Compiler warning fix Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/b31f2a0b1273 changeset: 17064:b31f2a0b1273 user: Timo Sirainen date: Sat Dec 14 14:40:13 2013 +0200 description: Compiler warning fix diffstat: src/lib-master/master-auth.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 89f1cefe0f89 -r b31f2a0b1273 src/lib-master/master-auth.c --- a/src/lib-master/master-auth.c Fri Dec 13 13:44:32 2013 +0200 +++ b/src/lib-master/master-auth.c Sat Dec 14 14:40:13 2013 +0200 @@ -111,7 +111,7 @@ if (ret == 0 || errno == ECONNRESET) { i_error("read(%s) failed: Remote closed connection " "(service's process_limit reached?)", - conn->auth->path, conn->auth->path); + conn->auth->path); } else { if (errno == EAGAIN) return; From dovecot at dovecot.org Tue Dec 17 21:33:43 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Tue, 17 Dec 2013 21:33:43 +0200 Subject: dovecot-2.2: mail-filter: If filter returns 0 bytes, treat it as... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/ba855eac00db changeset: 17065:ba855eac00db user: Timo Sirainen date: Tue Dec 17 21:33:32 2013 +0200 description: mail-filter: If filter returns 0 bytes, treat it as EIO error. diffstat: src/plugins/mail-filter/istream-ext-filter.c | 7 +++++++ src/plugins/mail-filter/ostream-ext-filter.c | 8 ++++++++ 2 files changed, 15 insertions(+), 0 deletions(-) diffs (35 lines): diff -r b31f2a0b1273 -r ba855eac00db src/plugins/mail-filter/istream-ext-filter.c --- a/src/plugins/mail-filter/istream-ext-filter.c Sat Dec 14 14:40:13 2013 +0200 +++ b/src/plugins/mail-filter/istream-ext-filter.c Tue Dec 17 21:33:32 2013 +0200 @@ -118,6 +118,13 @@ if (!stream->istream.blocking) break; } + if (ret == -1 && !i_stream_have_bytes_left(&stream->istream) && + stream->istream.v_offset == 0) { + /* EOF without any input -> assume the script is repoting + failure. pretty ugly way, but currently there's no error + reporting channel. */ + stream->istream.stream_errno = EIO; + } return ret; } diff -r b31f2a0b1273 -r ba855eac00db src/plugins/mail-filter/ostream-ext-filter.c --- a/src/plugins/mail-filter/ostream-ext-filter.c Sat Dec 14 14:40:13 2013 +0200 +++ b/src/plugins/mail-filter/ostream-ext-filter.c Tue Dec 17 21:33:32 2013 +0200 @@ -93,6 +93,14 @@ } i_assert(ret == -1); + if (!i_stream_have_bytes_left(mstream->ext_in) && + mstream->ext_in->v_offset == 0) { + /* EOF without any input -> assume the script is repoting + failure. pretty ugly way, but currently there's no error + reporting channel. */ + stream->ostream.stream_errno = EIO; + return -1; + } if (mstream->ext_in->stream_errno != 0) { stream->ostream.stream_errno = mstream->ext_in->stream_errno; return -1; From dovecot at dovecot.org Thu Dec 19 04:02:19 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 04:02:19 +0200 Subject: dovecot-2.2: pop3c: Use UIDLs as GUIDs. Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/a56ef53bd3ce changeset: 17066:a56ef53bd3ce user: Timo Sirainen date: Thu Dec 19 04:01:58 2013 +0200 description: pop3c: Use UIDLs as GUIDs. diffstat: src/lib-storage/index/pop3c/pop3c-mail.c | 2 ++ src/lib-storage/index/pop3c/pop3c-storage.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletions(-) diffs (32 lines): diff -r ba855eac00db -r a56ef53bd3ce src/lib-storage/index/pop3c/pop3c-mail.c --- a/src/lib-storage/index/pop3c/pop3c-mail.c Tue Dec 17 21:33:32 2013 +0200 +++ b/src/lib-storage/index/pop3c/pop3c-mail.c Thu Dec 19 04:01:58 2013 +0200 @@ -1,6 +1,7 @@ /* Copyright (c) 2011-2013 Dovecot authors, see the included COPYING file */ #include "lib.h" +#include "ioloop.h" #include "istream.h" #include "index-mail.h" #include "pop3c-client.h" @@ -153,6 +154,7 @@ switch (field) { case MAIL_FETCH_UIDL_BACKEND: + case MAIL_FETCH_GUID: if (mbox->msg_uidls == NULL) { if (pop3c_sync_get_uidls(mbox) < 0) return -1; diff -r ba855eac00db -r a56ef53bd3ce src/lib-storage/index/pop3c/pop3c-storage.c --- a/src/lib-storage/index/pop3c/pop3c-storage.c Tue Dec 17 21:33:32 2013 +0200 +++ b/src/lib-storage/index/pop3c/pop3c-storage.c Thu Dec 19 04:01:58 2013 +0200 @@ -280,7 +280,8 @@ struct mail_storage pop3c_storage = { .name = POP3C_STORAGE_NAME, - .class_flags = MAIL_STORAGE_CLASS_FLAG_NO_ROOT, + .class_flags = MAIL_STORAGE_CLASS_FLAG_NO_ROOT | + MAIL_STORAGE_CLASS_FLAG_HAVE_MAIL_GUIDS, .v = { pop3c_get_setting_parser_info, From dovecot at dovecot.org Thu Dec 19 04:06:01 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 04:06:01 +0200 Subject: dovecot-2.2: pop3c: Added pop3c_quick_received_date setting. Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/970ffc20b8a0 changeset: 17067:970ffc20b8a0 user: Timo Sirainen date: Thu Dec 19 04:05:52 2013 +0200 description: pop3c: Added pop3c_quick_received_date setting. With this enabled dsync no longer requires calling TOP for each message to get the metadata. diffstat: src/lib-storage/index/pop3c/pop3c-mail.c | 8 ++++++++ src/lib-storage/index/pop3c/pop3c-settings.c | 4 +++- src/lib-storage/index/pop3c/pop3c-settings.h | 1 + 3 files changed, 12 insertions(+), 1 deletions(-) diffs (58 lines): diff -r a56ef53bd3ce -r 970ffc20b8a0 src/lib-storage/index/pop3c/pop3c-mail.c --- a/src/lib-storage/index/pop3c/pop3c-mail.c Thu Dec 19 04:01:58 2013 +0200 +++ b/src/lib-storage/index/pop3c/pop3c-mail.c Thu Dec 19 04:05:52 2013 +0200 @@ -4,14 +4,22 @@ #include "ioloop.h" #include "istream.h" #include "index-mail.h" +#include "pop3c-settings.h" #include "pop3c-client.h" #include "pop3c-sync.h" #include "pop3c-storage.h" static int pop3c_mail_get_received_date(struct mail *_mail, time_t *date_r) { + struct pop3c_mailbox *mbox = (struct pop3c_mailbox *)_mail->box; int tz; + if (mbox->storage->set->pop3c_quick_received_date) { + /* we don't care about the date, just return the current date */ + *date_r = ioloop_time; + return 0; + } + /* FIXME: we could also parse the first Received: header and get the date from there, but since this code is unlikely to be called except during migration, I don't think it really matters. */ diff -r a56ef53bd3ce -r 970ffc20b8a0 src/lib-storage/index/pop3c/pop3c-settings.c --- a/src/lib-storage/index/pop3c/pop3c-settings.c Thu Dec 19 04:01:58 2013 +0200 +++ b/src/lib-storage/index/pop3c/pop3c-settings.c Thu Dec 19 04:05:52 2013 +0200 @@ -25,6 +25,7 @@ DEF(SET_BOOL, pop3c_ssl_verify), DEF(SET_STR, pop3c_rawlog_dir), + DEF(SET_BOOL, pop3c_quick_received_date), SETTING_DEFINE_LIST_END }; @@ -40,7 +41,8 @@ .pop3c_ssl = "no:pop3s:starttls", .pop3c_ssl_verify = TRUE, - .pop3c_rawlog_dir = "" + .pop3c_rawlog_dir = "", + .pop3c_quick_received_date = FALSE }; static const struct setting_parser_info pop3c_setting_parser_info = { diff -r a56ef53bd3ce -r 970ffc20b8a0 src/lib-storage/index/pop3c/pop3c-settings.h --- a/src/lib-storage/index/pop3c/pop3c-settings.h Thu Dec 19 04:01:58 2013 +0200 +++ b/src/lib-storage/index/pop3c/pop3c-settings.h Thu Dec 19 04:05:52 2013 +0200 @@ -13,6 +13,7 @@ bool pop3c_ssl_verify; const char *pop3c_rawlog_dir; + bool pop3c_quick_received_date; }; const struct setting_parser_info *pop3c_get_setting_parser_info(void); From dovecot at dovecot.org Thu Dec 19 04:18:45 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 04:18:45 +0200 Subject: dovecot-2.2: pop3c: If POP3 server doesn't support UIDLs, don't ... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/5eed62d890f7 changeset: 17068:5eed62d890f7 user: Timo Sirainen date: Thu Dec 19 04:18:30 2013 +0200 description: pop3c: If POP3 server doesn't support UIDLs, don't advertise GUID support. diffstat: src/lib-storage/index/pop3c/pop3c-storage.c | 17 ++++++++++++++++- 1 files changed, 16 insertions(+), 1 deletions(-) diffs (34 lines): diff -r 970ffc20b8a0 -r 5eed62d890f7 src/lib-storage/index/pop3c/pop3c-storage.c --- a/src/lib-storage/index/pop3c/pop3c-storage.c Thu Dec 19 04:05:52 2013 +0200 +++ b/src/lib-storage/index/pop3c/pop3c-storage.c Thu Dec 19 04:18:30 2013 +0200 @@ -213,6 +213,21 @@ return index_storage_mailbox_update(box, update); } +static int pop3c_mailbox_get_status(struct mailbox *box, + enum mailbox_status_items items, + struct mailbox_status *status_r) +{ + struct pop3c_mailbox *mbox = (struct pop3c_mailbox *)box; + + if (index_storage_get_status(box, items, status_r) < 0) + return -1; + + if ((pop3c_client_get_capabilities(mbox->client) & + POP3C_CAPABILITY_UIDL) == 0) + status_r->have_guids = FALSE; + return 0; +} + static int pop3c_mailbox_get_metadata(struct mailbox *box, enum mailbox_metadata_items items, struct mailbox_metadata *metadata_r) @@ -308,7 +323,7 @@ pop3c_mailbox_update, index_storage_mailbox_delete, index_storage_mailbox_rename, - index_storage_get_status, + pop3c_mailbox_get_status, pop3c_mailbox_get_metadata, index_storage_set_subscribed, index_storage_attribute_set, From dovecot at dovecot.org Thu Dec 19 21:26:01 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 21:26:01 +0200 Subject: dovecot-2.2: Compiler warning fix. Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/c23063144736 changeset: 17069:c23063144736 user: Timo Sirainen date: Thu Dec 19 21:21:39 2013 +0200 description: Compiler warning fix. diffstat: src/imap/cmd-getmetadata.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diffs (11 lines): diff -r 5eed62d890f7 -r c23063144736 src/imap/cmd-getmetadata.c --- a/src/imap/cmd-getmetadata.c Thu Dec 19 04:18:30 2013 +0200 +++ b/src/imap/cmd-getmetadata.c Thu Dec 19 21:21:39 2013 +0200 @@ -261,7 +261,6 @@ str_append_c(ctx->iter_entry_prefix, '/'); imap_metadata_entry2key(entry, ctx->key_prefix, &type, &key); - type = type; ctx->iter = mailbox_attribute_iter_init(ctx->box, type, key[0] == '\0' ? "" : t_strconcat(key, "/", NULL)); return 1; From dovecot at dovecot.org Thu Dec 19 21:26:01 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 21:26:01 +0200 Subject: dovecot-2.2: imap: if mailbox has non-permanent modseqs, never s... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/f5e51a926542 changeset: 17070:f5e51a926542 user: Timo Sirainen date: Thu Dec 19 21:25:08 2013 +0200 description: imap: if mailbox has non-permanent modseqs, never send HIGHESTMODSEQ/MODSEQs. diffstat: src/imap/cmd-select.c | 1 + src/imap/imap-client.h | 1 + src/imap/imap-sync.c | 6 ++++-- 3 files changed, 6 insertions(+), 2 deletions(-) diffs (45 lines): diff -r c23063144736 -r f5e51a926542 src/imap/cmd-select.c --- a/src/imap/cmd-select.c Thu Dec 19 21:21:39 2013 +0200 +++ b/src/imap/cmd-select.c Thu Dec 19 21:25:08 2013 +0200 @@ -346,6 +346,7 @@ t_strdup_printf("* OK [UIDNEXT %u] Predicted next UID", status.uidnext)); + client->nonpermanent_modseqs = status.nonpermanent_modseqs; if (status.nonpermanent_modseqs) { client_send_line(client, "* OK [NOMODSEQ] No permanent modsequences"); diff -r c23063144736 -r f5e51a926542 src/imap/imap-client.h --- a/src/imap/imap-client.h Thu Dec 19 21:21:39 2013 +0200 +++ b/src/imap/imap-client.h Thu Dec 19 21:25:08 2013 +0200 @@ -165,6 +165,7 @@ unsigned int notify_count_changes:1; unsigned int notify_flag_changes:1; unsigned int imap_metadata_enabled:1; + unsigned int nonpermanent_modseqs:1; }; struct imap_module_register { diff -r c23063144736 -r f5e51a926542 src/imap/imap-sync.c --- a/src/imap/imap-sync.c Thu Dec 19 21:21:39 2013 +0200 +++ b/src/imap/imap-sync.c Thu Dec 19 21:25:08 2013 +0200 @@ -374,7 +374,8 @@ ret = imap_sync_finish(ctx, TRUE); imap_client_notify_finished(ctx->client); - if ((ctx->client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0) + if ((ctx->client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0 && + !ctx->client->nonpermanent_modseqs) imap_sync_send_highestmodseq(ctx, sync_cmd); if (array_is_created(&ctx->search_removes)) { @@ -415,7 +416,8 @@ if (ctx->imap_flags & IMAP_SYNC_FLAG_SEND_UID) str_printfa(str, "UID %u ", ctx->mail->uid); if ((mailbox_get_enabled_features(ctx->box) & - MAILBOX_FEATURE_CONDSTORE) != 0) { + MAILBOX_FEATURE_CONDSTORE) != 0 && + !ctx->client->nonpermanent_modseqs) { imap_sync_add_modseq(ctx, str); str_append_c(str, ' '); } From dovecot at dovecot.org Thu Dec 19 21:26:01 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 21:26:01 +0200 Subject: dovecot-2.2: fs-sis: Memory leak fix. Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/4ba74eca3099 changeset: 17072:4ba74eca3099 user: Timo Sirainen date: Thu Dec 19 21:25:43 2013 +0200 description: fs-sis: Memory leak fix. diffstat: src/lib-fs/fs-sis.c | 10 ++++++++-- 1 files changed, 8 insertions(+), 2 deletions(-) diffs (44 lines): diff -r 369d8e994372 -r 4ba74eca3099 src/lib-fs/fs-sis.c --- a/src/lib-fs/fs-sis.c Thu Dec 19 21:25:28 2013 +0200 +++ b/src/lib-fs/fs-sis.c Thu Dec 19 21:25:43 2013 +0200 @@ -359,9 +359,10 @@ fs_file_last_error(_file)); } else { file->fs_output = fs_write_stream(file->super); - if (file->hash_input == NULL) + if (file->hash_input == NULL) { _file->output = file->fs_output; - else { + o_stream_ref(_file->output); + } else { /* compare if files are equal */ _file->output = o_stream_create_cmp(file->fs_output, file->hash_input); @@ -374,22 +375,27 @@ { struct sis_fs_file *file = (struct sis_fs_file *)_file; + if (o_stream_nfinish(_file->output) < 0) + success = FALSE; if (!success) { if (file->super != NULL) { fs_write_stream_abort(file->super, &file->fs_output); fs_sis_file_copy_error(file); } + o_stream_unref(&_file->output); return -1; } if (file->hash_input != NULL && o_stream_cmp_equals(_file->output) && i_stream_is_eof(file->hash_input)) { + o_stream_unref(&_file->output); if (fs_sis_try_link(file)) { fs_write_stream_abort(file->super, &file->fs_output); return 1; } } + o_stream_unref(&_file->output); if (fs_write_stream_finish(file->super, &file->fs_output) < 0) { fs_sis_file_copy_error(file); From dovecot at dovecot.org Thu Dec 19 21:26:01 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 21:26:01 +0200 Subject: dovecot-2.2: pop3c: Memory leak fixes Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/369d8e994372 changeset: 17071:369d8e994372 user: Timo Sirainen date: Thu Dec 19 21:25:28 2013 +0200 description: pop3c: Memory leak fixes diffstat: src/lib-storage/index/pop3c/pop3c-client.c | 1 + src/lib-storage/index/pop3c/pop3c-storage.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletions(-) diffs (24 lines): diff -r f5e51a926542 -r 369d8e994372 src/lib-storage/index/pop3c/pop3c-client.c --- a/src/lib-storage/index/pop3c/pop3c-client.c Thu Dec 19 21:25:08 2013 +0200 +++ b/src/lib-storage/index/pop3c/pop3c-client.c Thu Dec 19 21:25:28 2013 +0200 @@ -762,6 +762,7 @@ client->dot_input = i_stream_create_seekable(inputs, POP3C_MAX_INBUF_SIZE, seekable_fd_callback, client); + i_stream_unref(&inputs[0]); i_assert(client->io == NULL); client->io = io_add(client->fd, IO_READ, diff -r f5e51a926542 -r 369d8e994372 src/lib-storage/index/pop3c/pop3c-storage.c --- a/src/lib-storage/index/pop3c/pop3c-storage.c Thu Dec 19 21:25:08 2013 +0200 +++ b/src/lib-storage/index/pop3c/pop3c-storage.c Thu Dec 19 21:25:28 2013 +0200 @@ -185,7 +185,8 @@ if (mbox->uidl_pool != NULL) pool_unref(&mbox->uidl_pool); - i_free(mbox->msg_sizes); + i_free_and_null(mbox->msg_uids); + i_free_and_null(mbox->msg_sizes); pop3c_client_deinit(&mbox->client); index_storage_mailbox_close(box); } From dovecot at dovecot.org Thu Dec 19 21:32:12 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 21:32:12 +0200 Subject: dovecot-2.2: imap: Ignore QRESYNC parameters for SELECT when ret... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/1d8fef81d4b6 changeset: 17073:1d8fef81d4b6 user: Timo Sirainen date: Thu Dec 19 21:31:57 2013 +0200 description: imap: Ignore QRESYNC parameters for SELECT when returning NOMODSEQ. diffstat: src/imap/cmd-select.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 4ba74eca3099 -r 1d8fef81d4b6 src/imap/cmd-select.c --- a/src/imap/cmd-select.c Thu Dec 19 21:25:43 2013 +0200 +++ b/src/imap/cmd-select.c Thu Dec 19 21:31:57 2013 +0200 @@ -358,7 +358,7 @@ } if (ctx->qresync_uid_validity == status.uidvalidity && - status.uidvalidity != 0) { + status.uidvalidity != 0 && !client->nonpermanent_modseqs) { if ((ret = select_qresync(ctx)) < 0) { client_send_box_error(ctx->cmd, ctx->box); return -1; From dovecot at dovecot.org Thu Dec 19 21:37:51 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 21:37:51 +0200 Subject: dovecot-2.2: imap: If any FETCH/STORE tries to access modseqs wh... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/bd50cc9fa757 changeset: 17074:bd50cc9fa757 user: Timo Sirainen date: Thu Dec 19 21:37:28 2013 +0200 description: imap: If any FETCH/STORE tries to access modseqs when NOMODSEQ was returned, return BAD. diffstat: src/imap/cmd-fetch.c | 5 +++++ src/imap/cmd-store.c | 5 +++++ src/imap/imap-fetch.c | 4 ++++ 3 files changed, 14 insertions(+), 0 deletions(-) diffs (44 lines): diff -r 1d8fef81d4b6 -r bd50cc9fa757 src/imap/cmd-fetch.c --- a/src/imap/cmd-fetch.c Thu Dec 19 21:31:57 2013 +0200 +++ b/src/imap/cmd-fetch.c Thu Dec 19 21:37:28 2013 +0200 @@ -111,6 +111,11 @@ uint64_t modseq; if (strcmp(name, "CHANGEDSINCE") == 0) { + if (cmd->client->nonpermanent_modseqs) { + client_send_command_error(cmd, + "FETCH CHANGEDSINCE can't be used with non-permanent modseqs"); + return FALSE; + } if (!imap_arg_get_atom(*args, &str) || str_to_uint64(str, &modseq) < 0) { client_send_command_error(cmd, diff -r 1d8fef81d4b6 -r bd50cc9fa757 src/imap/cmd-store.c --- a/src/imap/cmd-store.c Thu Dec 19 21:31:57 2013 +0200 +++ b/src/imap/cmd-store.c Thu Dec 19 21:37:28 2013 +0200 @@ -57,6 +57,11 @@ } if (strcasecmp(name, "UNCHANGEDSINCE") == 0) { + if (ctx->cmd->client->nonpermanent_modseqs) { + client_send_command_error(ctx->cmd, + "STORE UNCHANGEDSINCE can't be used with non-permanent modseqs"); + return FALSE; + } if (str_to_uint64(value, &ctx->max_modseq) < 0) { client_send_command_error(ctx->cmd, "Invalid modseq"); diff -r 1d8fef81d4b6 -r bd50cc9fa757 src/imap/imap-fetch.c --- a/src/imap/imap-fetch.c Thu Dec 19 21:31:57 2013 +0200 +++ b/src/imap/imap-fetch.c Thu Dec 19 21:37:28 2013 +0200 @@ -804,6 +804,10 @@ bool imap_fetch_modseq_init(struct imap_fetch_init_context *ctx) { + if (ctx->fetch_ctx->client->nonpermanent_modseqs) { + ctx->error = "FETCH MODSEQ can't be used with non-permanent modseqs"; + return FALSE; + } (void)client_enable(ctx->fetch_ctx->client, MAILBOX_FEATURE_CONDSTORE); imap_fetch_add_handler(ctx, IMAP_FETCH_HANDLER_FLAG_BUFFERED, NULL, fetch_modseq, NULL); From dovecot at dovecot.org Thu Dec 19 23:07:03 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 23:07:03 +0200 Subject: dovecot-2.2: imap: SETMETADATA shouldn't assert-crash when entry... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/cded53530a9f changeset: 17075:cded53530a9f user: Timo Sirainen date: Thu Dec 19 23:04:55 2013 +0200 description: imap: SETMETADATA shouldn't assert-crash when entry name is invalid diffstat: src/imap/cmd-setmetadata.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diffs (13 lines): diff -r bd50cc9fa757 -r cded53530a9f src/imap/cmd-setmetadata.c --- a/src/imap/cmd-setmetadata.c Thu Dec 19 21:37:28 2013 +0200 +++ b/src/imap/cmd-setmetadata.c Thu Dec 19 23:04:55 2013 +0200 @@ -233,7 +233,8 @@ while ((ret = cmd_setmetadata_parse_entryvalue(ctx, &entry, &value)) > 0 && entry != NULL) { - ret = cmd_setmetadata_entry(ctx, entry, value); + ret = ctx->failed ? 1 : + cmd_setmetadata_entry(ctx, entry, value); imap_parser_reset(ctx->parser); if (ret <= 0) break; From dovecot at dovecot.org Thu Dec 19 23:07:20 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 23:07:20 +0200 Subject: dovecot-2.2: imap: GETMETADATA wasn't working correctly if optio... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/f64810b00b7f changeset: 17076:f64810b00b7f user: Timo Sirainen date: Thu Dec 19 23:07:15 2013 +0200 description: imap: GETMETADATA wasn't working correctly if options parameter wasn't specified. diffstat: src/imap/cmd-getmetadata.c | 11 ++++++----- 1 files changed, 6 insertions(+), 5 deletions(-) diffs (28 lines): diff -r cded53530a9f -r f64810b00b7f src/imap/cmd-getmetadata.c --- a/src/imap/cmd-getmetadata.c Thu Dec 19 23:04:55 2013 +0200 +++ b/src/imap/cmd-getmetadata.c Thu Dec 19 23:07:15 2013 +0200 @@ -344,18 +344,19 @@ if (imap_arg_get_list(&args[0], &options)) { if (!cmd_getmetadata_parse_options(ctx, options)) return TRUE; + args++; } - if (!imap_arg_get_astring(&args[1], &mailbox)) { + if (!imap_arg_get_astring(&args[0], &mailbox)) { client_send_command_error(cmd, "Invalid arguments."); return TRUE; } - if (!imap_arg_get_list(&args[2], &entries)) { - if (!imap_arg_get_astring(&args[2], &entry_name) || - !IMAP_ARG_IS_EOL(&args[3])) { + if (!imap_arg_get_list(&args[1], &entries)) { + if (!imap_arg_get_astring(&args[1], &entry_name) || + !IMAP_ARG_IS_EOL(&args[2])) { client_send_command_error(cmd, "Invalid arguments."); return TRUE; } - entries = args+2; + entries = args+1; } if (!imap_metadata_parse_entry_names(ctx, entries)) return TRUE; From dovecot at dovecot.org Thu Dec 19 23:08:10 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 23:08:10 +0200 Subject: dovecot-2.2: imap: Allow wildcards in GETMETADATA mailbox-name. Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/0c3071ebe44b changeset: 17077:0c3071ebe44b user: Timo Sirainen date: Thu Dec 19 23:08:03 2013 +0200 description: imap: Allow wildcards in GETMETADATA mailbox-name. RFC 5464 doesn't specify this, but its earlier draft did, and Kolab uses it. diffstat: src/imap/cmd-getmetadata.c | 122 ++++++++++++++++++++++++++++++++------------ 1 files changed, 89 insertions(+), 33 deletions(-) diffs (172 lines): diff -r f64810b00b7f -r 0c3071ebe44b src/imap/cmd-getmetadata.c --- a/src/imap/cmd-getmetadata.c Thu Dec 19 23:07:15 2013 +0200 +++ b/src/imap/cmd-getmetadata.c Thu Dec 19 23:08:03 2013 +0200 @@ -4,6 +4,7 @@ #include "str.h" #include "istream.h" #include "ostream.h" +#include "mailbox-list-iter.h" #include "imap-quote.h" #include "imap-metadata.h" @@ -12,6 +13,7 @@ struct mailbox *box; struct mailbox_transaction_context *trans; + struct mailbox_list_iterate_context *list_iter; ARRAY_TYPE(const_string) entries; uint32_t maxsize; @@ -30,6 +32,8 @@ bool failed; }; +static bool cmd_getmetadata_iter_next(struct imap_getmetadata_context *ctx); + static bool cmd_getmetadata_parse_options(struct imap_getmetadata_context *ctx, const struct imap_arg *options) @@ -267,14 +271,37 @@ } } +static void cmd_getmetadata_mailbox_deinit(struct imap_getmetadata_context *ctx) +{ + if (ctx->iter != NULL) + (void)mailbox_attribute_iter_deinit(&ctx->iter); + if (ctx->box != NULL) { + (void)mailbox_transaction_commit(&ctx->trans); + mailbox_free(&ctx->box); + } + ctx->first_entry_sent = FALSE; + ctx->entry_idx = 0; +} + static void cmd_getmetadata_deinit(struct imap_getmetadata_context *ctx) { - ctx->cmd->client->output_cmd_lock = NULL; + struct client_command_context *cmd = ctx->cmd; - if (ctx->iter != NULL) - (void)mailbox_attribute_iter_deinit(&ctx->iter); - (void)mailbox_transaction_commit(&ctx->trans); - mailbox_free(&ctx->box); + cmd_getmetadata_mailbox_deinit(ctx); + cmd->client->output_cmd_lock = NULL; + + if (ctx->list_iter != NULL && + mailbox_list_iter_deinit(&ctx->list_iter) < 0) + client_send_list_error(cmd, cmd->client->user->namespaces->list); + else if (ctx->failed) { + client_send_tagline(cmd, "NO Getmetadata failed to send some entries"); + } else if (ctx->largest_seen_size != 0) { + client_send_tagline(cmd, t_strdup_printf( + "OK [METADATA LONGENTRIES %"PRIuUOFF_T"] " + "Getmetadata completed.", ctx->largest_seen_size)); + } else { + client_send_tagline(cmd, "OK Getmetadata completed."); + } } static bool cmd_getmetadata_continue(struct client_command_context *cmd) @@ -308,14 +335,47 @@ if (ctx->first_entry_sent) o_stream_nsend_str(cmd->client->output, ")\r\n"); - if (ctx->failed) { - client_send_tagline(cmd, "NO Getmetadata failed to send some entries"); - } else if (ctx->largest_seen_size != 0) { - client_send_tagline(cmd, t_strdup_printf( - "OK [METADATA LONGENTRIES %"PRIuUOFF_T"] " - "Getmetadata completed.", ctx->largest_seen_size)); - } else { - client_send_tagline(cmd, "OK Getmetadata completed."); + cmd_getmetadata_mailbox_deinit(ctx); + if (ctx->list_iter != NULL) + return cmd_getmetadata_iter_next(ctx); + cmd_getmetadata_deinit(ctx); + return TRUE; +} + +static bool +cmd_getmetadata_mailbox(struct imap_getmetadata_context *ctx, + struct mail_namespace *ns, const char *mailbox) +{ + struct client_command_context *cmd = ctx->cmd; + + ctx->box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY); + if (mailbox_open(ctx->box) < 0) { + client_send_box_error(cmd, ctx->box); + mailbox_free(&ctx->box); + return TRUE; + } + ctx->trans = mailbox_transaction_begin(ctx->box, 0); + + if (ctx->depth > 0) + ctx->iter_entry_prefix = str_new(cmd->pool, 128); + + if (!cmd_getmetadata_continue(cmd)) { + cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT; + cmd->func = cmd_getmetadata_continue; + return FALSE; + } + return TRUE; +} + +static bool cmd_getmetadata_iter_next(struct imap_getmetadata_context *ctx) +{ + const struct mailbox_info *info; + + while ((info = mailbox_list_iter_next(ctx->list_iter)) != NULL) { + if ((info->flags & (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) != 0) + continue; + /* we'll get back here recursively */ + return cmd_getmetadata_mailbox(ctx, info->ns, info->vname); } cmd_getmetadata_deinit(ctx); return TRUE; @@ -365,28 +425,24 @@ /* server attribute */ ctx->key_prefix = MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER; ns = mail_namespace_find_inbox(cmd->client->user->namespaces); - mailbox = "INBOX"; - } else { + return cmd_getmetadata_mailbox(ctx, ns, "INBOX"); + } else if (strchr(mailbox, '*') == NULL && + strchr(mailbox, '%') == NULL) { ns = client_find_namespace(cmd, &mailbox); if (ns == NULL) return TRUE; + return cmd_getmetadata_mailbox(ctx, ns, mailbox); + } else { + /* wildcards in mailbox name. this isn't supported by RFC 5464, + but it was in the earlier drafts and is already used by + some software (Kolab). */ + const char *patterns[2]; + patterns[0] = mailbox; patterns[1] = NULL; + + ctx->list_iter = + mailbox_list_iter_init_namespaces( + cmd->client->user->namespaces, + patterns, MAIL_NAMESPACE_TYPE_MASK_ALL, 0); + return cmd_getmetadata_iter_next(ctx); } - - ctx->box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY); - if (mailbox_open(ctx->box) < 0) { - client_send_box_error(cmd, ctx->box); - mailbox_free(&ctx->box); - return TRUE; - } - ctx->trans = mailbox_transaction_begin(ctx->box, 0); - - if (ctx->depth > 0) - ctx->iter_entry_prefix = str_new(cmd->pool, 128); - - if (!cmd_getmetadata_continue(cmd)) { - cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT; - cmd->func = cmd_getmetadata_continue; - return FALSE; - } - return TRUE; } From dovecot at dovecot.org Thu Dec 19 23:09:55 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 23:09:55 +0200 Subject: dovecot-2.2: imap: Minor comment update: Horde uses wildcards, n... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/eb830b4196c4 changeset: 17078:eb830b4196c4 user: Timo Sirainen date: Thu Dec 19 23:09:45 2013 +0200 description: imap: Minor comment update: Horde uses wildcards, not Kolab. diffstat: src/imap/cmd-getmetadata.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 0c3071ebe44b -r eb830b4196c4 src/imap/cmd-getmetadata.c --- a/src/imap/cmd-getmetadata.c Thu Dec 19 23:08:03 2013 +0200 +++ b/src/imap/cmd-getmetadata.c Thu Dec 19 23:09:45 2013 +0200 @@ -435,7 +435,7 @@ } else { /* wildcards in mailbox name. this isn't supported by RFC 5464, but it was in the earlier drafts and is already used by - some software (Kolab). */ + some software (Horde). */ const char *patterns[2]; patterns[0] = mailbox; patterns[1] = NULL; From dovecot at dovecot.org Thu Dec 19 23:44:10 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 23:44:10 +0200 Subject: dovecot-2.2: quota-status: Allow mail to go over quota up to quo... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/be98fec32cd8 changeset: 17079:be98fec32cd8 user: Timo Sirainen date: Thu Dec 19 23:43:54 2013 +0200 description: quota-status: Allow mail to go over quota up to quota_grace. diffstat: src/plugins/quota/quota-status.c | 2 +- src/plugins/quota/quota.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diffs (24 lines): diff -r eb830b4196c4 -r be98fec32cd8 src/plugins/quota/quota-status.c --- a/src/plugins/quota/quota-status.c Thu Dec 19 23:09:45 2013 +0200 +++ b/src/plugins/quota/quota-status.c Thu Dec 19 23:43:54 2013 +0200 @@ -61,7 +61,7 @@ } ns = mail_namespace_find_inbox(user->namespaces); - box = mailbox_alloc(ns->list, "INBOX", 0); + box = mailbox_alloc(ns->list, "INBOX", MAILBOX_FLAG_POST_SESSION); ctx = quota_transaction_begin(box); ret = quota_test_alloc(ctx, I_MAX(1, mail_size), too_large_r); diff -r eb830b4196c4 -r be98fec32cd8 src/plugins/quota/quota.c --- a/src/plugins/quota/quota.c Thu Dec 19 23:09:45 2013 +0200 +++ b/src/plugins/quota/quota.c Thu Dec 19 23:43:54 2013 +0200 @@ -1084,7 +1084,7 @@ ctx->limits_set = TRUE; mailbox_name = mailbox_get_vname(ctx->box); - /* use last_mail_max_extra_bytes only for LDA/LMTP */ + /* use quota_grace only for LDA/LMTP */ use_grace = (ctx->box->flags & MAILBOX_FLAG_POST_SESSION) != 0; /* find the lowest quota limits from all roots and use them */ From dovecot at dovecot.org Thu Dec 19 23:54:37 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Thu, 19 Dec 2013 23:54:37 +0200 Subject: dovecot-2.2: auth: If LDAP server returns LDAP_OPERATIONS_ERROR,... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/ea38559ffd4e changeset: 17080:ea38559ffd4e user: Timo Sirainen date: Thu Dec 19 23:54:28 2013 +0200 description: auth: If LDAP server returns LDAP_OPERATIONS_ERROR, reconnect. Apparently the server somehow lost the bind. diffstat: src/auth/db-ldap.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (11 lines): diff -r be98fec32cd8 -r ea38559ffd4e src/auth/db-ldap.c --- a/src/auth/db-ldap.c Thu Dec 19 23:43:54 2013 +0200 +++ b/src/auth/db-ldap.c Thu Dec 19 23:54:28 2013 +0200 @@ -283,6 +283,7 @@ #endif case LDAP_LOCAL_ERROR: case LDAP_INVALID_CREDENTIALS: + case LDAP_OPERATIONS_ERROR: default: /* connection problems */ ldap_conn_reconnect(conn); From dovecot at dovecot.org Fri Dec 20 00:43:08 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Fri, 20 Dec 2013 00:43:08 +0200 Subject: dovecot-2.1: auth: Fixed non-auth passdb lookup when password ha... Message-ID: details: http://hg.dovecot.org/dovecot-2.1/rev/7c5172e0c5c7 changeset: 15007:7c5172e0c5c7 user: Timo Sirainen date: Thu Sep 19 22:43:45 2013 +0300 description: auth: Fixed non-auth passdb lookup when password had "." suffix. diffstat: src/auth/passdb.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r f572fbafb445 -r 7c5172e0c5c7 src/auth/passdb.c --- a/src/auth/passdb.c Sat Nov 02 12:25:09 2013 +0200 +++ b/src/auth/passdb.c Thu Sep 19 22:43:45 2013 +0300 @@ -92,7 +92,7 @@ /* anything goes. change the credentials_scheme to what we actually got, so blocking passdbs work. */ auth_request->credentials_scheme = - p_strdup(auth_request->pool, input_scheme); + p_strdup(auth_request->pool, t_strcut(input_scheme, '.')); return TRUE; } From dovecot at dovecot.org Fri Dec 20 01:06:08 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Fri, 20 Dec 2013 01:06:08 +0200 Subject: dovecot-2.2: imap: GETMETADATA should return nonexistent entries... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/b7b4ff5a9eec changeset: 17081:b7b4ff5a9eec user: Timo Sirainen date: Fri Dec 20 01:06:02 2013 +0200 description: imap: GETMETADATA should return nonexistent entries also with NIL values. diffstat: src/imap/cmd-getmetadata.c | 56 +++++++++++++++++++++++++++++++++------------ 1 files changed, 41 insertions(+), 15 deletions(-) diffs (95 lines): diff -r ea38559ffd4e -r b7b4ff5a9eec src/imap/cmd-getmetadata.c --- a/src/imap/cmd-getmetadata.c Thu Dec 19 23:54:28 2013 +0200 +++ b/src/imap/cmd-getmetadata.c Fri Dec 20 01:06:02 2013 +0200 @@ -98,8 +98,42 @@ return TRUE; } +static string_t * +metadata_add_entry(struct imap_getmetadata_context *ctx, const char *entry) +{ + string_t *str; + + str = t_str_new(64); + if (!ctx->first_entry_sent) { + ctx->first_entry_sent = TRUE; + str_append(str, "* METADATA "); + imap_append_astring(str, mailbox_get_vname(ctx->box)); + str_append(str, " ("); + + /* nothing can be sent until untagged METADATA is finished */ + ctx->cmd->client->output_cmd_lock = ctx->cmd; + } else { + str_append_c(str, ' '); + } + imap_append_astring(str, entry); + return str; +} + +static void +cmd_getmetadata_send_nil_reply(struct imap_getmetadata_context *ctx, + const char *entry) +{ + string_t *str; + + /* client requested a specific entry that didn't exist. + we must return it as NIL. */ + str = metadata_add_entry(ctx, entry); + str_append(str, " NIL"); + o_stream_send(ctx->cmd->client->output, str_data(str), str_len(str)); +} + static void cmd_getmetadata_send_entry(struct imap_getmetadata_context *ctx, - const char *entry) + const char *entry, bool require_reply) { enum mail_attribute_type type; struct mail_attribute_value value; @@ -115,6 +149,8 @@ /* skip over dovecot's internal attributes. (if key_prefix isn't NULL, we're getting server metadata, which is handled inside the private metadata.) */ + if (require_reply) + cmd_getmetadata_send_nil_reply(ctx, entry); return; } @@ -139,6 +175,8 @@ } } else { /* skip nonexistent entries */ + if (require_reply) + cmd_getmetadata_send_nil_reply(ctx, entry); return; } @@ -152,19 +190,7 @@ return; } - str = t_str_new(64); - if (!ctx->first_entry_sent) { - ctx->first_entry_sent = TRUE; - str_append(str, "* METADATA "); - imap_append_astring(str, mailbox_get_vname(ctx->box)); - str_append(str, " ("); - - /* nothing can be sent until untagged METADATA is finished */ - ctx->cmd->client->output_cmd_lock = ctx->cmd; - } else { - str_append_c(str, ' '); - } - imap_append_astring(str, entry); + str = metadata_add_entry(ctx, entry); if (value.value != NULL) { str_printfa(str, " {%"PRIuUOFF_T"}\r\n%s", value_len, value.value); o_stream_send(ctx->cmd->client->output, str_data(str), str_len(str)); @@ -244,7 +270,7 @@ } while (ctx->depth == 1 && strchr(key, '/') != NULL); entry = t_strconcat(str_c(ctx->iter_entry_prefix), key, NULL); } - cmd_getmetadata_send_entry(ctx, entry); + cmd_getmetadata_send_entry(ctx, entry, ctx->iter == NULL); if (ctx->cur_stream != NULL) { if (!cmd_getmetadata_stream_continue(ctx)) From dovecot at dovecot.org Fri Dec 20 04:23:15 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Fri, 20 Dec 2013 04:23:15 +0200 Subject: dovecot-2.2: imap-quota: SETQUOTA supports now also user@domain:... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/623b1d9414a6 changeset: 17082:623b1d9414a6 user: Timo Sirainen date: Fri Dec 20 04:23:04 2013 +0200 description: imap-quota: SETQUOTA supports now also user at domain:quotaroot name. diffstat: src/plugins/imap-quota/imap-quota-plugin.c | 47 +++++++++++++++++------------ 1 files changed, 28 insertions(+), 19 deletions(-) diffs (83 lines): diff -r b7b4ff5a9eec -r 623b1d9414a6 src/plugins/imap-quota/imap-quota-plugin.c --- a/src/plugins/imap-quota/imap-quota-plugin.c Fri Dec 20 01:06:02 2013 +0200 +++ b/src/plugins/imap-quota/imap-quota-plugin.c Fri Dec 20 04:23:04 2013 +0200 @@ -126,9 +126,30 @@ return TRUE; } +static bool +parse_quota_root(struct mail_user *user, const char *root_name, + struct mail_user **owner_r, struct quota_root **root_r) +{ + const char *p; + + *owner_r = user; + *root_r = quota_root_lookup(user, root_name); + if (*root_r != NULL || !user->admin) + return *root_r != NULL; + + /* we're an admin. see if there's a quota root for another user. */ + p = strchr(root_name, QUOTA_USER_SEPARATOR); + if (p != NULL) { + *owner_r = mail_user_find(user, t_strdup_until(root_name, p)); + *root_r = *owner_r == NULL ? NULL : + quota_root_lookup(*owner_r, p + 1); + } + return *root_r != NULL; +} + static bool cmd_getquota(struct client_command_context *cmd) { - struct mail_user *owner = cmd->client->user; + struct mail_user *owner; struct quota_root *root; const char *root_name; string_t *quota_reply; @@ -137,19 +158,7 @@ if (!client_read_string_args(cmd, 1, &root_name)) return FALSE; - root = quota_root_lookup(cmd->client->user, root_name); - if (root == NULL && cmd->client->user->admin) { - /* we're an admin. see if there's a quota root for another - user. */ - const char *p = strchr(root_name, QUOTA_USER_SEPARATOR); - if (p != NULL) { - owner = mail_user_find(cmd->client->user, - t_strdup_until(root_name, p)); - root = owner == NULL ? NULL : - quota_root_lookup(owner, p + 1); - } - } - if (root == NULL) { + if (!parse_quota_root(cmd->client->user, root_name, &owner, &root)) { client_send_tagline(cmd, "NO Quota root doesn't exist."); return TRUE; } @@ -166,6 +175,7 @@ static bool cmd_setquota(struct client_command_context *cmd) { struct quota_root *root; + struct mail_user *owner; const struct imap_arg *args, *list_args; const char *root_name, *name, *value_str, *error; uint64_t value; @@ -180,14 +190,13 @@ return TRUE; } - root = quota_root_lookup(cmd->client->user, root_name); - if (root == NULL) { - client_send_tagline(cmd, "NO Quota root doesn't exist."); + if (!cmd->client->user->admin) { + client_send_tagline(cmd, "NO Quota can be changed only by admin."); return TRUE; } - if (!cmd->client->user->admin) { - client_send_tagline(cmd, "NO Quota can be changed only by admin."); + if (!parse_quota_root(cmd->client->user, root_name, &owner, &root)) { + client_send_tagline(cmd, "NO Quota root doesn't exist."); return TRUE; } From dovecot at dovecot.org Fri Dec 20 04:25:22 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Fri, 20 Dec 2013 04:25:22 +0200 Subject: dovecot-2.2: Compiler warning fix. Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/f8ffa5e47e6f changeset: 17083:f8ffa5e47e6f user: Timo Sirainen date: Fri Dec 20 04:25:17 2013 +0200 description: Compiler warning fix. Older libmysqlclient uses const char * as the arg. diffstat: src/lib-sql/driver-mysql.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 623b1d9414a6 -r f8ffa5e47e6f src/lib-sql/driver-mysql.c --- a/src/lib-sql/driver-mysql.c Fri Dec 20 04:23:04 2013 +0200 +++ b/src/lib-sql/driver-mysql.c Fri Dec 20 04:25:17 2013 +0200 @@ -107,7 +107,7 @@ ); #ifdef HAVE_MYSQL_SSL_VERIFY_SERVER_CERT mysql_options(db->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, - &db->ssl_verify_server_cert); + (void *)&db->ssl_verify_server_cert); #endif db->ssl_set = TRUE; #else From dovecot at dovecot.org Fri Dec 20 05:07:56 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Fri, 20 Dec 2013 05:07:56 +0200 Subject: dovecot-2.2: Added tag 2.2.10 for changeset 614bd6600011 Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/dab38d4a4591 changeset: 17085:dab38d4a4591 user: Timo Sirainen date: Fri Dec 20 04:57:19 2013 +0200 description: Added tag 2.2.10 for changeset 614bd6600011 diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff -r 614bd6600011 -r dab38d4a4591 .hgtags --- a/.hgtags Fri Dec 20 04:57:19 2013 +0200 +++ b/.hgtags Fri Dec 20 04:57:19 2013 +0200 @@ -113,3 +113,4 @@ b5b118701aa83e7b047e53f51aa5a4622ee812df 2.2.7 095a777edc2623fad2ad9d6321ed93a804e85889 2.2.8 2852a7c55fc756e489ebff6aefcb0553f638e851 2.2.9 +614bd66000113a062c1a02751cc7d04c0fcef1d6 2.2.10 From dovecot at dovecot.org Fri Dec 20 05:07:56 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Fri, 20 Dec 2013 05:07:56 +0200 Subject: dovecot-2.2: Released v2.2.10. Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/614bd6600011 changeset: 17084:614bd6600011 user: Timo Sirainen date: Fri Dec 20 04:57:19 2013 +0200 description: Released v2.2.10. diffstat: NEWS | 31 +++++++++++++++++++++++++++++++ configure.ac | 4 ++-- 2 files changed, 33 insertions(+), 2 deletions(-) diffs (52 lines): diff -r f8ffa5e47e6f -r 614bd6600011 NEWS --- a/NEWS Fri Dec 20 04:25:17 2013 +0200 +++ b/NEWS Fri Dec 20 04:57:19 2013 +0200 @@ -1,3 +1,34 @@ +v2.2.10 2013-11-25 Timo Sirainen + + + auth: passdb/userdb dict rewrite to support much more complex + setups. See doc/example-config/dovecot-dict-auth.conf.ext. + The old settings will continue to work. + + auth: Added userdb result_success/failure/tempfail and skip + settings, similar to passdb's. See + http://wiki2.dovecot.org/UserDatabase + + imap: Implemented SETQUOTA command for admin user when quota_set is + configured. See http://master.wiki2.dovecot.org/Quota/Configuration + + quota: Support "*" and "?" wildcards in mailbox names in quota_rules + + mysql: Added ssl_verify_server_cert=no|yes parameter. This currently + defaults to "no" to make sure nothing breaks, but likely will become + "yes" in Dovecot v2.3. + + ldap: Added blocking=yes setting to use auth worker processes for + ldap lookups. This is a workaround for now to be able to use multiple + simultaneous LDAP connections. + + pop3c+dsync performance improvements + - quota-status: quota_grace was ignored + - ldap: Fixed memory leak with auth_bind=yes and without + auth_bind_userdn. + - imap: Don't send HIGHESTMODSEQ anymore on SELECT/EXAMINE when + CONDSTORE/QRESYNC has never before been enabled for the mailbox. + - imap: Fixes to handling mailboxes without permanent modseqs. + (When [NOMODSEQ] is returned by SELECT, mainly with in-memory + indexes.) + - imap: Various fixes to METADATA support. + - stats plugin: Processes that only temporarily dropped privileges + (e.g. indexer-worker) may have been logging errors about not being + able to open /proc/self/io. + v2.2.9 2013-11-25 Timo Sirainen + Full text search indexing can now be done automatically after diff -r f8ffa5e47e6f -r 614bd6600011 configure.ac --- a/configure.ac Fri Dec 20 04:25:17 2013 +0200 +++ b/configure.ac Fri Dec 20 04:57:19 2013 +0200 @@ -2,8 +2,8 @@ # Be sure to update ABI version also if anything changes that might require # recompiling plugins. Most importantly that means if any structs are changed. -AC_INIT([Dovecot],[2.2.9],[dovecot at dovecot.org]) -AC_DEFINE_UNQUOTED([DOVECOT_ABI_VERSION], "2.2.ABIv7($PACKAGE_VERSION)", [Dovecot ABI version]) +AC_INIT([Dovecot],[2.2.10],[dovecot at dovecot.org]) +AC_DEFINE_UNQUOTED([DOVECOT_ABI_VERSION], "2.2.ABIv10($PACKAGE_VERSION)", [Dovecot ABI version]) AC_CONFIG_SRCDIR([src]) From dovecot at dovecot.org Fri Dec 20 05:07:56 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Fri, 20 Dec 2013 05:07:56 +0200 Subject: dovecot-2.2: Added signature for changeset 614bd6600011 Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/bfee9f413844 changeset: 17086:bfee9f413844 user: Timo Sirainen date: Fri Dec 20 04:57:25 2013 +0200 description: Added signature for changeset 614bd6600011 diffstat: .hgsigs | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff -r dab38d4a4591 -r bfee9f413844 .hgsigs --- a/.hgsigs Fri Dec 20 04:57:19 2013 +0200 +++ b/.hgsigs Fri Dec 20 04:57:25 2013 +0200 @@ -76,3 +76,4 @@ b5b118701aa83e7b047e53f51aa5a4622ee812df 0 iEYEABECAAYFAlJ2rGIACgkQyUhSUUBVislFRwCfTgg6BYRGpKAOAvE3hhhIskLwxLUAoJjRlth0ob0ahrqIhg7du4+Z0C3j 095a777edc2623fad2ad9d6321ed93a804e85889 0 iEYEABECAAYFAlKL1YoACgkQyUhSUUBVismrpQCeP/ab1oKZp0VJ6PwmnRgDthf2hi8AoJZB+KuQIgKA5iBx3NpGcaZjmlzc 2852a7c55fc756e489ebff6aefcb0553f638e851 0 iEYEABECAAYFAlKSirAACgkQyUhSUUBVisn17ACgjsnbSktYkNMvoO2FNjA2DVBNYDwAnAtQ1Zjemwvi+Pow/px6TZ2K76J6 +614bd66000113a062c1a02751cc7d04c0fcef1d6 0 iEYEABECAAYFAlKzsg8ACgkQyUhSUUBVism5cACdEM1jR3c6gO0dGodbsgVtDMZPSxsAoKGmvyIxt7MSQkdz9cbe+Kfn2jyK From dovecot at dovecot.org Fri Dec 20 19:59:34 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Fri, 20 Dec 2013 19:59:34 +0200 Subject: dovecot-2.2: mdbox: When purging writes new data, flush them to ... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/e322c40a82a9 changeset: 17087:e322c40a82a9 user: Timo Sirainen date: Fri Dec 20 19:59:22 2013 +0200 description: mdbox: When purging writes new data, flush them to disk before locking the map index. diffstat: src/lib-storage/index/dbox-multi/mdbox-purge.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diffs (15 lines): diff -r bfee9f413844 -r e322c40a82a9 src/lib-storage/index/dbox-multi/mdbox-purge.c --- a/src/lib-storage/index/dbox-multi/mdbox-purge.c Fri Dec 20 04:57:25 2013 +0200 +++ b/src/lib-storage/index/dbox-multi/mdbox-purge.c Fri Dec 20 19:59:22 2013 +0200 @@ -383,6 +383,11 @@ "(%"PRIuUOFF_T" < %"PRIuUOFF_T")", offset, st.st_size); ret = 0; } + if (ret > 0 && ctx->append_ctx != NULL) { + /* flush writes before locking the map */ + if (mdbox_map_append_flush(ctx->append_ctx) < 0) + ret = -1; + } if (ret <= 0) ret = -1; From pigeonhole at rename-it.nl Sat Dec 21 16:09:40 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Sat, 21 Dec 2013 15:09:40 +0100 Subject: dovecot-2.2-pigeonhole: Sieve extprograms plugin: Fixed 'Bad fil... Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/8612191c5069 changeset: 1823:8612191c5069 user: Stephan Bosch date: Sat Dec 21 15:09:32 2013 +0100 description: Sieve extprograms plugin: Fixed 'Bad filedescriptor' error occurring when disconnecting script client. diffstat: src/plugins/sieve-extprograms/script-client.c | 13 +++---------- 1 files changed, 3 insertions(+), 10 deletions(-) diffs (42 lines): diff -r 61772824b4ea -r 8612191c5069 src/plugins/sieve-extprograms/script-client.c --- a/src/plugins/sieve-extprograms/script-client.c Fri Dec 13 21:35:58 2013 +0100 +++ b/src/plugins/sieve-extprograms/script-client.c Sat Dec 21 15:09:32 2013 +0100 @@ -48,7 +48,6 @@ if ( sclient->script_output != NULL ) o_stream_destroy(&sclient->script_output); sclient->script_output = NULL; - sclient->fd_out = -1; return ret; } @@ -135,10 +134,8 @@ } } while ( (ret=i_stream_read(input)) > 0 ); - if ( ret == 0 ) { - // FIXME: not supposed to happen; returning 0 will poll the input stream - return 0; - } + if ( ret == 0 ) + return 1; if ( ret < 0 ) { if ( !input->eof ) { @@ -158,16 +155,12 @@ } if ( input == NULL ) { - o_stream_unref(&sclient->script_output); - if ( sclient->script_input == NULL ) { script_client_disconnect(sclient, FALSE); } else if (script_client_close_output(sclient) < 0) { - return -1; + script_client_fail(sclient, SCRIPT_CLIENT_ERROR_IO); } - return 0; } - return 1; } From pigeonhole at rename-it.nl Sat Dec 21 22:32:25 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Sat, 21 Dec 2013 21:32:25 +0100 Subject: dovecot-2.2-pigeonhole: lib-sieve: Moved utility source modules ... Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/559621e9e633 changeset: 1824:559621e9e633 user: Stephan Bosch date: Sat Dec 21 21:10:13 2013 +0100 description: lib-sieve: Moved utility source modules to sub-directory. In the future, much of these can be moved to Dovecot. diffstat: configure.ac | 1 + src/lib-sieve/Makefile.am | 21 +- src/lib-sieve/edit-mail.c | 1924 --------------- src/lib-sieve/edit-mail.h | 49 - src/lib-sieve/plugins/editheader/Makefile.am | 3 +- src/lib-sieve/plugins/enotify/mailto/Makefile.am | 1 + src/lib-sieve/plugins/ihave/Makefile.am | 2 +- src/lib-sieve/plugins/metadata/Makefile.am | 5 +- src/lib-sieve/plugins/notify/Makefile.am | 1 + src/lib-sieve/plugins/subaddress/Makefile.am | 2 +- src/lib-sieve/plugins/vacation/Makefile.am | 3 +- src/lib-sieve/plugins/vnd.dovecot/debug/Makefile.am | 2 +- src/lib-sieve/plugins/vnd.dovecot/duplicate/Makefile.am | 2 +- src/lib-sieve/rfc2822.c | 236 - src/lib-sieve/rfc2822.h | 45 - src/lib-sieve/util/Makefile.am | 19 + src/lib-sieve/util/edit-mail.c | 1924 +++++++++++++++ src/lib-sieve/util/edit-mail.h | 49 + src/lib-sieve/util/rfc2822.c | 236 + src/lib-sieve/util/rfc2822.h | 45 + 20 files changed, 2300 insertions(+), 2270 deletions(-) diffs (truncated from 4738 to 300 lines): diff -r 8612191c5069 -r 559621e9e633 configure.ac --- a/configure.ac Sat Dec 21 15:09:32 2013 +0100 +++ b/configure.ac Sat Dec 21 21:10:13 2013 +0100 @@ -100,6 +100,7 @@ doc/rfc/Makefile src/Makefile src/lib-sieve/Makefile +src/lib-sieve/util/Makefile src/lib-sieve/plugins/Makefile src/lib-sieve/plugins/vacation/Makefile src/lib-sieve/plugins/subaddress/Makefile diff -r 8612191c5069 -r 559621e9e633 src/lib-sieve/Makefile.am --- a/src/lib-sieve/Makefile.am Sat Dec 21 15:09:32 2013 +0100 +++ b/src/lib-sieve/Makefile.am Sat Dec 21 21:10:13 2013 +0100 @@ -1,4 +1,4 @@ -SUBDIRS = plugins +SUBDIRS = util plugins dovecot_pkglib_LTLIBRARIES = libdovecot-sieve.la @@ -6,6 +6,7 @@ $(LIBDOVECOT_INCLUDE) \ $(LIBDOVECOT_LDA_INCLUDE) \ $(LIBDOVECOT_SERVICE_INCLUDE) \ + -I$(top_srcdir)/src/lib-sieve/util \ -DMODULEDIR=\""$(dovecot_moduledir)"\" tests = \ @@ -71,12 +72,20 @@ $(extdir)/vnd.dovecot/duplicate/libsieve_ext_duplicate.la \ $(unfinished_plugins) -libdovecot_sieve_la_DEPENDENCIES = $(plugins) $(LIBDOVECOT_LDA_DEPS) $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_DEPS) -libdovecot_sieve_la_LIBADD = $(plugins) $(LIBDOVECOT_LDA) $(LIBDOVECOT_STORAGE) $(LIBDOVECOT) +libdovecot_sieve_la_DEPENDENCIES = \ + $(plugins) \ + $(top_builddir)/src/lib-sieve/util/libsieve_util.la \ + $(LIBDOVECOT_LDA_DEPS) \ + $(LIBDOVECOT_STORAGE_DEPS) \ + $(LIBDOVECOT_DEPS) +libdovecot_sieve_la_LIBADD = \ + $(plugins) \ + $(top_builddir)/src/lib-sieve/util/libsieve_util.la \ + $(LIBDOVECOT_LDA) \ + $(LIBDOVECOT_STORAGE) \ + $(LIBDOVECOT) libdovecot_sieve_la_SOURCES = \ - rfc2822.c \ - edit-mail.c \ sieve-settings.c \ sieve-message.c \ sieve-smtp.c \ @@ -118,8 +127,6 @@ sieve.c headers = \ - rfc2822.h \ - edit-mail.h \ sieve-config.h \ sieve-types.h \ sieve-common.h \ diff -r 8612191c5069 -r 559621e9e633 src/lib-sieve/edit-mail.c --- a/src/lib-sieve/edit-mail.c Sat Dec 21 15:09:32 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1924 +0,0 @@ -/* Copyright (c) 2002-2013 Pigeonhole authors, see the included COPYING file - */ - -#include "lib.h" -#include "array.h" -#include "str.h" -#include "mempool.h" -#include "llist.h" -#include "istream-private.h" -#include "master-service.h" -#include "master-service-settings.h" -#include "message-parser.h" -#include "message-header-encode.h" -#include "message-header-decode.h" -#include "mail-user.h" -#include "mail-storage-private.h" -#include "index-mail.h" -#include "raw-storage.h" - -#include "rfc2822.h" - -#include "edit-mail.h" - -/* - * Forward declarations - */ - -struct _header_field_index; -struct _header_field; -struct _header_index; -struct _header; - -static struct mail_vfuncs edit_mail_vfuncs; - -struct edit_mail_istream; -struct istream *edit_mail_istream_create(struct edit_mail *edmail); - -static struct _header_index *edit_mail_header_clone - (struct edit_mail *edmail, struct _header *header); - -/* - * Raw storage - */ - -static struct mail_user *edit_mail_user = NULL; -static unsigned int edit_mail_refcount = 0; - -static struct mail_user *edit_mail_raw_storage_get(struct mail_user *mail_user) -{ - if ( edit_mail_user == NULL ) { - void **sets = master_service_settings_get_others(master_service); - - edit_mail_user = raw_storage_create_from_set(mail_user->set_info, sets[0]); - } - - edit_mail_refcount++; - - return edit_mail_user; -} - -static void edit_mail_raw_storage_drop(void) -{ - i_assert(edit_mail_refcount > 0); - - if ( --edit_mail_refcount != 0) - return; - - mail_user_unref(&edit_mail_user); - edit_mail_user = NULL; -} - -/* - * Headers - */ - -struct _header_field { - struct _header *header; - - unsigned int refcount; - - char *data; - size_t size; - size_t virtual_size; - uoff_t offset; - unsigned int lines; - - uoff_t body_offset; - - char *utf8_value; -}; - -struct _header_field_index { - struct _header_field_index *prev, *next; - - struct _header_field *field; - struct _header_index *header; -}; - -struct _header { - unsigned int refcount; - - char *name; -}; - -struct _header_index { - struct _header_index *prev, *next; - - struct _header *header; - - struct _header_field_index *first, *last; - - unsigned int count; -}; - -static inline struct _header *_header_create(const char *name) -{ - struct _header *header; - - header = i_new(struct _header, 1); - header->name = i_strdup(name); - header->refcount = 1; - - return header; -} - -static inline void _header_ref(struct _header *header) -{ - header->refcount++; -} - -static inline void _header_unref(struct _header *header) -{ - i_assert( header->refcount > 0 ); - if ( --header->refcount != 0 ) - return; - - i_free(header->name); - i_free(header); -} - -static inline struct _header_field *_header_field_create(struct _header *header) -{ - struct _header_field *hfield; - - hfield = i_new(struct _header_field, 1); - hfield->refcount = 1; - hfield->header = header; - if ( header != NULL ) - _header_ref(header); - - return hfield; -} - -static inline void _header_field_ref(struct _header_field *hfield) -{ - hfield->refcount++; -} - -static inline void _header_field_unref(struct _header_field *hfield) -{ - i_assert( hfield->refcount > 0 ); - if ( --hfield->refcount != 0 ) - return; - - if ( hfield->header != NULL ) - _header_unref(hfield->header); - - if ( hfield->data != NULL ) - i_free(hfield->data); - if ( hfield->utf8_value != NULL ) - i_free(hfield->utf8_value); - i_free(hfield); -} - -/* - * Edit mail object - */ - -struct edit_mail { - struct mail_private mail; - struct mail_private *wrapped; - - struct edit_mail *parent; - unsigned int refcount; - - struct istream *wrapped_stream; - struct istream *stream; - - struct _header_index *headers_head, *headers_tail; - struct _header_field_index *header_fields_head, *header_fields_tail; - struct message_size hdr_size, body_size; - - struct message_size wrapped_hdr_size, wrapped_body_size; - - struct _header_field_index *header_fields_appended; - struct message_size appended_hdr_size; - - unsigned int modified:1; - unsigned int snapshot_modified:1; - unsigned int crlf:1; - unsigned int eoh_crlf:1; - unsigned int headers_parsed:1; - unsigned int destroying_stream:1; -}; - -struct edit_mail *edit_mail_wrap(struct mail *mail) -{ - struct mail_private *mailp = (struct mail_private *) mail; - struct edit_mail *edmail; - struct mail_user *raw_mail_user; - struct mailbox *raw_box = NULL; - struct mailbox_transaction_context *raw_trans; - struct message_size hdr_size, body_size; - struct istream *wrapped_stream; - uoff_t size_diff; - pool_t pool; - - if ( mail_get_stream(mail, &hdr_size, &body_size, &wrapped_stream) < 0 ) { - return NULL; - } - - /* Create dummy raw mailbox for our wrapper */ - - raw_mail_user = edit_mail_raw_storage_get(mail->box->storage->user); - - if ( raw_mailbox_alloc_stream(raw_mail_user, wrapped_stream, (time_t)-1, - "editor at example.com", &raw_box) < 0 ) { - i_error("edit-mail: failed to open raw box: %s", - mailbox_get_last_error(raw_box, NULL)); - mailbox_free(&raw_box); - edit_mail_raw_storage_drop(); - return NULL; - } - From pigeonhole at rename-it.nl Sat Dec 21 22:32:25 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Sat, 21 Dec 2013 21:32:25 +0100 Subject: dovecot-2.2-pigeonhole: Moved script-client from extprograms plu... Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/f7967d104216 changeset: 1825:f7967d104216 user: Stephan Bosch date: Sat Dec 21 21:32:13 2013 +0100 description: Moved script-client from extprograms plugin to lib-sieve/util and renamed it to program-client for generic use. diffstat: src/lib-sieve/util/Makefile.am | 9 +- src/lib-sieve/util/program-client-local.c | 304 +++++++++++++ src/lib-sieve/util/program-client-private.h | 59 ++ src/lib-sieve/util/program-client-remote.c | 319 ++++++++++++++ src/lib-sieve/util/program-client.c | 337 +++++++++++++++ src/lib-sieve/util/program-client.h | 35 + src/plugins/sieve-extprograms/Makefile.am | 6 +- src/plugins/sieve-extprograms/script-client-local.c | 304 ------------- src/plugins/sieve-extprograms/script-client-private.h | 59 -- src/plugins/sieve-extprograms/script-client-remote.c | 319 -------------- src/plugins/sieve-extprograms/script-client.c | 337 --------------- src/plugins/sieve-extprograms/script-client.h | 35 - src/plugins/sieve-extprograms/sieve-extprograms-common.c | 53 +- 13 files changed, 1089 insertions(+), 1087 deletions(-) diffs (truncated from 2329 to 300 lines): diff -r 559621e9e633 -r f7967d104216 src/lib-sieve/util/Makefile.am --- a/src/lib-sieve/util/Makefile.am Sat Dec 21 21:10:13 2013 +0100 +++ b/src/lib-sieve/util/Makefile.am Sat Dec 21 21:32:13 2013 +0100 @@ -8,12 +8,17 @@ libsieve_util_la_DEPENDENCIES = $(LIBDOVECOT_STORAGE_DEPS) $(LIBDOVECOT_DEPS) libsieve_util_la_SOURCES = \ + edit-mail.c \ rfc2822.c \ - edit-mail.c + program-client-local.c \ + program-client-remote.c \ + program-client.c headers = \ + edit-mail.h \ rfc2822.h \ - edit-mail.h + program-client-private.h \ + program-client.h pkginc_libdir=$(dovecot_pkgincludedir)/sieve pkginc_lib_HEADERS = $(headers) diff -r 559621e9e633 -r f7967d104216 src/lib-sieve/util/program-client-local.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-sieve/util/program-client-local.c Sat Dec 21 21:32:13 2013 +0100 @@ -0,0 +1,304 @@ +/* Copyright (c) 2002-2013 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "lib-signals.h" +#include "env-util.h" +#include "execv-const.h" +#include "array.h" +#include "net.h" +#include "istream.h" +#include "ostream.h" + +#include "program-client-private.h" + +#include +#include +#include +#include +#include +#include + + +struct program_client_local { + struct program_client client; + + pid_t pid; +}; + +static void exec_child +(const char *bin_path, const char *const *args, const char *const *envs, + int in_fd, int out_fd) +{ + ARRAY_TYPE(const_string) exec_args; + + if ( in_fd < 0 ) { + in_fd = open("/dev/null", O_RDONLY); + + if ( in_fd == -1 ) + i_fatal("open(/dev/null) failed: %m"); + } + + if ( out_fd < 0 ) { + out_fd = open("/dev/null", O_WRONLY); + + if ( out_fd == -1 ) + i_fatal("open(/dev/null) failed: %m"); + } + + if ( dup2(in_fd, STDIN_FILENO) < 0 ) + i_fatal("dup2(stdin) failed: %m"); + if ( dup2(out_fd, STDOUT_FILENO) < 0 ) + i_fatal("dup2(stdout) failed: %m"); + + /* Close all fds */ + if ( close(in_fd) < 0 ) + i_error("close(in_fd) failed: %m"); + if ( (out_fd != in_fd) && close(out_fd) < 0 ) + i_error("close(out_fd) failed: %m"); + + t_array_init(&exec_args, 16); + array_append(&exec_args, &bin_path, 1); + if ( args != NULL ) { + for (; *args != NULL; args++) + array_append(&exec_args, args, 1); + } + (void)array_append_space(&exec_args); + + env_clean(); + if ( envs != NULL ) { + for (; *envs != NULL; envs++) + env_put(*envs); + } + + args = array_idx(&exec_args, 0); + execvp_const(args[0], args); +} + +static int program_client_local_connect +(struct program_client *pclient) +{ + struct program_client_local *slclient = + (struct program_client_local *) pclient; + int fd[2] = { -1, -1 }; + + if ( pclient->input != NULL || pclient->output != NULL ) { + if ( socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0 ) { + i_error("socketpair() failed: %m"); + return -1; + } + } + + if ( (slclient->pid = fork()) == (pid_t)-1 ) { + i_error("fork() failed: %m"); + if ( fd[0] >= 0 && close(fd[0]) < 0 ) { + i_error("close(pipe_fd[0]) failed: %m"); + } + if ( fd[1] >= 0 && close(fd[1]) < 0 ) { + i_error("close(pipe_fd[1]) failed: %m"); + } + return -1; + } + + if ( slclient->pid == 0 ) { + unsigned int count; + const char *const *envs = NULL; + + /* child */ + if ( fd[1] >= 0 && close(fd[1]) < 0 ) { + i_error("close(pipe_fd[1]) failed: %m"); + } + + if ( array_is_created(&pclient->envs) ) + envs = array_get(&pclient->envs, &count); + + exec_child(pclient->path, pclient->args, envs, + ( pclient->input != NULL ? fd[0] : -1 ), + ( pclient->output != NULL ? fd[0] : -1 )); + i_unreached(); + } + + /* parent */ + if ( fd[0] >= 0 && close(fd[0]) < 0 ) { + i_error("close(pipe_fd[0]) failed: %m"); + } + + if ( fd[1] >= 0 ) { + net_set_nonblock(fd[1], TRUE); + pclient->fd_in = ( pclient->output != NULL ? fd[1] : -1 ); + pclient->fd_out = ( pclient->input != NULL ? fd[1] : -1 ); + } + program_client_init_streams(pclient); + return program_client_connected(pclient); +} + +static int program_client_local_close_output(struct program_client *pclient) +{ + /* Shutdown output; program stdin will get EOF */ + if ( pclient->fd_out >= 0 && shutdown(pclient->fd_out, SHUT_WR) < 0 ) { + i_error("shutdown(%s, SHUT_WR) failed: %m", pclient->path); + return -1; + } + return 1; +} + +static int program_client_local_disconnect +(struct program_client *pclient, bool force) +{ + struct program_client_local *slclient = + (struct program_client_local *) pclient; + pid_t pid = slclient->pid, ret; + time_t runtime, timeout = 0; + int status; + + i_assert( pid >= 0 ); + slclient->pid = -1; + + /* Calculate timeout */ + runtime = ioloop_time - pclient->start_time; + if ( !force && pclient->set->input_idle_timeout_secs > 0 && + runtime < (time_t)pclient->set->input_idle_timeout_secs ) + timeout = pclient->set->input_idle_timeout_secs - runtime; + + if ( pclient->debug ) { + i_debug("waiting for program `%s' to finish after %llu seconds", + pclient->path, (unsigned long long int)runtime); + } + + /* Wait for child to exit */ + force = force || + (timeout == 0 && pclient->set->input_idle_timeout_secs > 0); + if ( !force ) { + alarm(timeout); + ret = waitpid(pid, &status, 0); + alarm(0); + } + if ( force || ret < 0 ) { + if ( !force && errno != EINTR ) { + i_error("waitpid(%s) failed: %m", pclient->path); + (void)kill(pid, SIGKILL); + return -1; + } + + /* Timed out */ + force = TRUE; + if ( pclient->error == PROGRAM_CLIENT_ERROR_NONE ) + pclient->error = PROGRAM_CLIENT_ERROR_RUN_TIMEOUT; + if ( pclient->debug ) { + i_debug("program `%s' execution timed out after %llu seconds: " + "sending TERM signal", pclient->path, + (unsigned long long int)pclient->set->input_idle_timeout_secs); + } + + /* Kill child gently first */ + if ( kill(pid, SIGTERM) < 0 ) { + i_error("failed to send SIGTERM signal to program `%s'", pclient->path); + (void)kill(pid, SIGKILL); + return -1; + } + + /* Wait for it to die (give it some more time) */ + alarm(5); + ret = waitpid(pid, &status, 0); + alarm(0); + if ( ret < 0 ) { + if ( errno != EINTR ) { + i_error("waitpid(%s) failed: %m", pclient->path); + (void)kill(pid, SIGKILL); + return -1; + } + + /* Timed out again */ + if ( pclient->debug ) { + i_debug("program `%s' execution timed out: sending KILL signal", + pclient->path); + } + + /* Kill it brutally now */ + if ( kill(pid, SIGKILL) < 0 ) { + i_error("failed to send SIGKILL signal to program `%s'", + pclient->path); + return -1; + } + + /* Now it will die immediately */ + if ( waitpid(pid, &status, 0) < 0 ) { + i_error("waitpid(%s) failed: %m", pclient->path); + return -1; + } + } + } + + /* Evaluate child exit status */ + pclient->exit_code = -1; + if ( WIFEXITED(status) ) { + /* Exited */ + int exit_code = WEXITSTATUS(status); + + if ( exit_code != 0 ) { + i_info("program `%s' terminated with non-zero exit code %d", + pclient->path, exit_code); + pclient->exit_code = 0; + return 0; + } + + pclient->exit_code = 1; + return 1; + + } else if ( WIFSIGNALED(status) ) { + /* Killed with a signal */ + + if ( force ) { + i_error("program `%s' was forcibly terminated with signal %d", + pclient->path, WTERMSIG(status)); + } else { + i_error("program `%s' terminated abnormally, signal %d", + pclient->path, WTERMSIG(status)); + } + return -1; + + } else if ( WIFSTOPPED(status) ) { + /* Stopped */ + i_error("program `%s' stopped, signal %d", + pclient->path, WSTOPSIG(status)); + return -1; + } + + /* Something else */ + i_error("program `%s' terminated abnormally, return status %d", + pclient->path, status); + return -1; +} + +static void program_client_local_failure From dovecot at dovecot.org Mon Dec 23 15:30:49 2013 From: dovecot at dovecot.org (dovecot at dovecot.org) Date: Mon, 23 Dec 2013 15:30:49 +0200 Subject: dovecot-2.2: imap proxy: Added proxy_nopipelining passdb setting... Message-ID: details: http://hg.dovecot.org/dovecot-2.2/rev/6b8ae0ba5959 changeset: 17088:6b8ae0ba5959 user: Timo Sirainen date: Mon Dec 23 15:30:31 2013 +0200 description: imap proxy: Added proxy_nopipelining passdb setting to work around other servers' bugs. diffstat: src/imap-login/imap-proxy.c | 15 ++++++++++++++- src/login-common/client-common-auth.c | 3 +++ src/login-common/client-common.h | 2 ++ 3 files changed, 19 insertions(+), 1 deletions(-) diffs (72 lines): diff -r e322c40a82a9 -r 6b8ae0ba5959 src/imap-login/imap-proxy.c --- a/src/imap-login/imap-proxy.c Fri Dec 20 19:59:22 2013 +0200 +++ b/src/imap-login/imap-proxy.c Mon Dec 23 15:30:31 2013 +0200 @@ -63,8 +63,13 @@ unsigned int len; const char *mech_name, *error; - if (client->proxy_backend_capability == NULL) + if (client->proxy_backend_capability == NULL) { str_append(str, "C CAPABILITY\r\n"); + if (client->common.proxy_nopipelining) { + /* authenticate only after receiving C OK reply. */ + return 0; + } + } if (client->common.proxy_mech == NULL) { /* logging in normally - use LOGIN command */ @@ -271,6 +276,14 @@ } o_stream_nsend(output, str_data(str), str_len(str)); return 1; + } else if (strncmp(line, "C OK ", 5) == 0 && + client->proxy_password != NULL) { + /* pipelining was disabled, send the login now. */ + str = t_str_new(128); + if (proxy_write_login(imap_client, str) < 0) + return -1; + o_stream_nsend(output, str_data(str), str_len(str)); + return 1; } else if (strncmp(line, "L OK ", 5) == 0) { /* Login successful. Send this line to client. */ client->proxy_state = IMAP_PROXY_STATE_LOGIN; diff -r e322c40a82a9 -r 6b8ae0ba5959 src/login-common/client-common-auth.c --- a/src/login-common/client-common-auth.c Fri Dec 20 19:59:22 2013 +0200 +++ b/src/login-common/client-common-auth.c Mon Dec 23 15:30:31 2013 +0200 @@ -107,6 +107,8 @@ reply_r->proxy_refresh_secs = atoi(value); else if (strcmp(key, "proxy_mech") == 0) reply_r->proxy_mech = value; + else if (strcmp(key, "proxy_nopipelining") == 0) + reply_r->proxy_nopipelining = TRUE; else if (strcmp(key, "master") == 0) reply_r->master_user = value; else if (strcmp(key, "ssl") == 0) { @@ -350,6 +352,7 @@ client->proxy_user = i_strdup(reply->destuser); client->proxy_master_user = i_strdup(reply->master_user); client->proxy_password = i_strdup(reply->password); + client->proxy_nopipelining = reply->proxy_nopipelining; /* disable input until authentication is finished */ if (client->io != NULL) diff -r e322c40a82a9 -r 6b8ae0ba5959 src/login-common/client-common.h --- a/src/login-common/client-common.h Fri Dec 20 19:59:22 2013 +0200 +++ b/src/login-common/client-common.h Mon Dec 23 15:30:31 2013 +0200 @@ -62,6 +62,7 @@ enum login_proxy_ssl_flags ssl_flags; unsigned int proxy:1; + unsigned int proxy_nopipelining:1; unsigned int temp:1; unsigned int nologin:1; unsigned int authz_failure:1; @@ -157,6 +158,7 @@ unsigned int auth_initializing:1; unsigned int auth_process_comm_fail:1; unsigned int proxy_auth_failed:1; + unsigned int proxy_nopipelining:1; unsigned int auth_waiting:1; unsigned int auth_user_disabled:1; unsigned int auth_pass_expired:1; From pigeonhole at rename-it.nl Wed Dec 25 22:51:29 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Wed, 25 Dec 2013 21:51:29 +0100 Subject: dovecot-2.2-pigeonhole: lib-sieve: Added path to temporary direc... Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/c3d99cdd49f1 changeset: 1826:c3d99cdd49f1 user: Stephan Bosch date: Wed Dec 25 21:36:55 2013 +0100 description: lib-sieve: Added path to temporary directory to Sieve instance object. diffstat: src/lib-sieve-tool/sieve-tool.c | 1 + src/lib-sieve/sieve-common.h | 1 + src/lib-sieve/sieve-types.h | 1 + src/lib-sieve/sieve.c | 1 + src/plugins/lda-sieve/lda-sieve-plugin.c | 1 + 5 files changed, 5 insertions(+), 0 deletions(-) diffs (55 lines): diff -r f7967d104216 -r c3d99cdd49f1 src/lib-sieve-tool/sieve-tool.c --- a/src/lib-sieve-tool/sieve-tool.c Sat Dec 21 21:32:13 2013 +0100 +++ b/src/lib-sieve-tool/sieve-tool.c Wed Dec 25 21:36:55 2013 +0100 @@ -273,6 +273,7 @@ (void)mail_user_get_home(tool->mail_user_dovecot, &svenv.home_dir); svenv.hostname = my_hostdomain(); svenv.base_dir = tool->mail_user_dovecot->set->base_dir; + svenv.temp_dir = tool->mail_user_dovecot->set->mail_temp_dir; svenv.location = SIEVE_ENV_LOCATION_MS; svenv.delivery_phase = SIEVE_DELIVERY_PHASE_POST; diff -r f7967d104216 -r c3d99cdd49f1 src/lib-sieve/sieve-common.h --- a/src/lib-sieve/sieve-common.h Sat Dec 21 21:32:13 2013 +0100 +++ b/src/lib-sieve/sieve-common.h Wed Dec 25 21:36:55 2013 +0100 @@ -159,6 +159,7 @@ const char *hostname; const char *domainname; const char *base_dir; + const char *temp_dir; /* User environment */ const char *username; diff -r f7967d104216 -r c3d99cdd49f1 src/lib-sieve/sieve-types.h --- a/src/lib-sieve/sieve-types.h Sat Dec 21 21:32:13 2013 +0100 +++ b/src/lib-sieve/sieve-types.h Wed Dec 25 21:36:55 2013 +0100 @@ -60,6 +60,7 @@ const char *base_dir; const char *username; const char *home_dir; + const char *temp_dir; enum sieve_flag flags; enum sieve_env_location location; diff -r f7967d104216 -r c3d99cdd49f1 src/lib-sieve/sieve.c --- a/src/lib-sieve/sieve.c Sat Dec 21 21:32:13 2013 +0100 +++ b/src/lib-sieve/sieve.c Wed Dec 25 21:36:55 2013 +0100 @@ -62,6 +62,7 @@ svinst->base_dir = p_strdup_empty(pool, env->base_dir); svinst->username = p_strdup_empty(pool, env->username); svinst->home_dir = p_strdup_empty(pool, env->home_dir); + svinst->temp_dir = p_strdup_empty(pool, env->temp_dir); svinst->flags = env->flags; svinst->env_location = env->location; svinst->delivery_phase = env->delivery_phase; diff -r f7967d104216 -r c3d99cdd49f1 src/plugins/lda-sieve/lda-sieve-plugin.c --- a/src/plugins/lda-sieve/lda-sieve-plugin.c Sat Dec 21 21:32:13 2013 +0100 +++ b/src/plugins/lda-sieve/lda-sieve-plugin.c Wed Dec 25 21:36:55 2013 +0100 @@ -911,6 +911,7 @@ svenv.home_dir = srctx.home_dir; svenv.hostname = mdctx->set->hostname; svenv.base_dir = mdctx->dest_user->set->base_dir; + svenv.temp_dir = mdctx->dest_user->set->mail_temp_dir; svenv.flags = SIEVE_FLAG_HOME_RELATIVE; svenv.location = SIEVE_ENV_LOCATION_MDA; svenv.delivery_phase = SIEVE_DELIVERY_PHASE_DURING; From pigeonhole at rename-it.nl Wed Dec 25 22:51:30 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Wed, 25 Dec 2013 21:51:30 +0100 Subject: dovecot-2.2-pigeonhole: sieve_extprograms plugin: Changed progra... Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/9448c8ae2f15 changeset: 1829:9448c8ae2f15 user: Stephan Bosch date: Wed Dec 25 21:45:47 2013 +0100 description: sieve_extprograms plugin: Changed program client such that the filter command only needs to create a temporary file when the program output is very large. This commit also includes a small change that makes it possible to run a program several times. diffstat: src/lib-sieve/util/program-client-local.c | 8 +- src/lib-sieve/util/program-client-private.h | 4 +- src/lib-sieve/util/program-client-remote.c | 3 +- src/lib-sieve/util/program-client.c | 98 +++++++++++- src/lib-sieve/util/program-client.h | 5 + src/plugins/sieve-extprograms/cmd-filter.c | 112 ++++---------- src/plugins/sieve-extprograms/sieve-extprograms-common.c | 18 ++ src/plugins/sieve-extprograms/sieve-extprograms-common.h | 5 + 8 files changed, 157 insertions(+), 96 deletions(-) diffs (truncated from 469 to 300 lines): diff -r 2a8bb622f17e -r 9448c8ae2f15 src/lib-sieve/util/program-client-local.c --- a/src/lib-sieve/util/program-client-local.c Wed Dec 25 21:42:05 2013 +0100 +++ b/src/lib-sieve/util/program-client-local.c Wed Dec 25 21:45:47 2013 +0100 @@ -82,7 +82,8 @@ (struct program_client_local *) pclient; int fd[2] = { -1, -1 }; - if ( pclient->input != NULL || pclient->output != NULL ) { + if ( pclient->input != NULL || pclient->output != NULL || + pclient->output_seekable ) { if ( socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0 ) { i_error("socketpair() failed: %m"); return -1; @@ -114,7 +115,7 @@ exec_child(pclient->path, pclient->args, envs, ( pclient->input != NULL ? fd[0] : -1 ), - ( pclient->output != NULL ? fd[0] : -1 )); + ( pclient->output != NULL || pclient->output_seekable ? fd[0] : -1 )); i_unreached(); } @@ -125,7 +126,8 @@ if ( fd[1] >= 0 ) { net_set_nonblock(fd[1], TRUE); - pclient->fd_in = ( pclient->output != NULL ? fd[1] : -1 ); + pclient->fd_in = + ( pclient->output != NULL || pclient->output_seekable ? fd[1] : -1 ); pclient->fd_out = ( pclient->input != NULL ? fd[1] : -1 ); } program_client_init_streams(pclient); diff -r 2a8bb622f17e -r 9448c8ae2f15 src/lib-sieve/util/program-client-private.h --- a/src/lib-sieve/util/program-client-private.h Wed Dec 25 21:42:05 2013 +0100 +++ b/src/lib-sieve/util/program-client-private.h Wed Dec 25 21:45:47 2013 +0100 @@ -28,8 +28,9 @@ struct timeout *to; time_t start_time; - struct istream *input, *program_input; + struct istream *input, *program_input, *seekable_output; struct ostream *output, *program_output; + char *temp_prefix; enum program_client_error error; int exit_code; @@ -42,6 +43,7 @@ unsigned int debug:1; unsigned int disconnected:1; + unsigned int output_seekable:1; }; void program_client_init diff -r 2a8bb622f17e -r 9448c8ae2f15 src/lib-sieve/util/program-client-remote.c --- a/src/lib-sieve/util/program-client-remote.c Wed Dec 25 21:42:05 2013 +0100 +++ b/src/lib-sieve/util/program-client-remote.c Wed Dec 25 21:45:47 2013 +0100 @@ -234,7 +234,8 @@ net_set_nonblock(fd, TRUE); - pclient->fd_in = ( slclient->noreply && pclient->output == NULL ? -1 : fd ); + pclient->fd_in = ( slclient->noreply && pclient->output == NULL && + !pclient->output_seekable ? -1 : fd ); pclient->fd_out = fd; pclient->io = io_add(fd, IO_WRITE, program_client_remote_connected, pclient); return 1; diff -r 2a8bb622f17e -r 9448c8ae2f15 src/lib-sieve/util/program-client.c --- a/src/lib-sieve/util/program-client.c Wed Dec 25 21:42:05 2013 +0100 +++ b/src/lib-sieve/util/program-client.c Wed Dec 25 21:45:47 2013 +0100 @@ -4,14 +4,18 @@ #include "lib.h" #include "ioloop.h" #include "array.h" +#include "str.h" +#include "safe-mkstemp.h" #include "istream-private.h" +#include "istream-seekable.h" #include "ostream.h" #include "program-client-private.h" #include -#define MAX_OUTBUF_SIZE 16384 +#define MAX_OUTPUT_BUFFER_SIZE 16384 +#define MAX_OUTPUT_MEMORY_BUFFER (1024*128) static void program_client_timeout(struct program_client *pclient) { @@ -35,7 +39,6 @@ program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO); return -1; } - return 1; } @@ -69,8 +72,12 @@ if ( (ret=pclient->disconnect(pclient, force)) < 0 ) error = TRUE; - if ( pclient->program_input != NULL ) - i_stream_destroy(&pclient->program_input); + if ( pclient->program_input != NULL ) { + if (pclient->output_seekable) + i_stream_unref(&pclient->program_input); + else + i_stream_destroy(&pclient->program_input); + } if ( pclient->program_output != NULL ) o_stream_destroy(&pclient->program_output); @@ -239,7 +246,7 @@ void program_client_set_input (struct program_client *pclient, struct istream *input) { - if ( pclient->input ) + if ( pclient->input != NULL ) i_stream_unref(&pclient->input); if ( input != NULL ) i_stream_ref(input); @@ -249,11 +256,33 @@ void program_client_set_output (struct program_client *pclient, struct ostream *output) { - if ( pclient->output ) + if ( pclient->output != NULL ) o_stream_unref(&pclient->output); if ( output != NULL ) o_stream_ref(output); pclient->output = output; + pclient->output_seekable = FALSE; + i_free(pclient->temp_prefix); +} + +void program_client_set_output_seekable +(struct program_client *pclient, const char *temp_prefix) +{ + if ( pclient->output != NULL ) + o_stream_unref(&pclient->output); + pclient->temp_prefix = i_strdup(temp_prefix); + pclient->output_seekable = TRUE; +} + +struct istream *program_client_get_output_seekable +(struct program_client *pclient) +{ + struct istream *input = pclient->seekable_output; + + pclient->seekable_output = NULL; + + i_stream_seek(input, 0); + return input; } void program_client_set_env @@ -268,15 +297,56 @@ array_append(&pclient->envs, &env, 1); } +static int program_client_seekable_fd_callback +(const char **path_r, void *context) +{ + struct program_client *pclient = (struct program_client *)context; + string_t *path; + int fd; + + path = t_str_new(128); + str_append(path, pclient->temp_prefix); + fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1); + if (fd == -1) { + i_error("safe_mkstemp(%s) failed: %m", str_c(path)); + return -1; + } + + /* we just want the fd, unlink it */ + if (unlink(str_c(path)) < 0) { + /* shouldn't happen.. */ + i_error("unlink(%s) failed: %m", str_c(path)); + i_close_fd(&fd); + return -1; + } + + *path_r = str_c(path); + return fd; +} + void program_client_init_streams(struct program_client *pclient) { if ( pclient->fd_out >= 0 ) { pclient->program_output = - o_stream_create_fd(pclient->fd_out, MAX_OUTBUF_SIZE, FALSE); + o_stream_create_fd(pclient->fd_out, MAX_OUTPUT_BUFFER_SIZE, FALSE); } if ( pclient->fd_in >= 0 ) { - pclient->program_input = - i_stream_create_fd(pclient->fd_in, (size_t)-1, FALSE); + struct istream *input; + + input = i_stream_create_fd(pclient->fd_in, (size_t)-1, FALSE); + + if (pclient->output_seekable) { + struct istream *input2 = input, *input_list[2]; + + input_list[0] = input2; input_list[1] = NULL; + input = i_stream_create_seekable(input_list, MAX_OUTPUT_MEMORY_BUFFER, + program_client_seekable_fd_callback, pclient); + i_stream_unref(&input2); + pclient->seekable_output = input; + i_stream_ref(pclient->seekable_output); + } + + pclient->program_input = input; pclient->io = io_add (pclient->fd_in, IO_READ, program_client_program_input, pclient); } @@ -292,11 +362,13 @@ i_stream_unref(&pclient->input); if ( pclient->output != NULL ) o_stream_unref(&pclient->output); + if ( pclient->input != NULL ) + i_stream_unref(&pclient->seekable_output); if ( pclient->io != NULL ) io_remove(&pclient->io); if ( pclient->ioloop != NULL ) io_loop_destroy(&pclient->ioloop); - + i_free(pclient->temp_prefix); pool_unref(&pclient->pool); *_pclient = NULL; } @@ -305,6 +377,12 @@ { int ret; + /* reset */ + pclient->disconnected = FALSE; + pclient->exit_code = 0; + pclient->error = PROGRAM_CLIENT_ERROR_NONE; + + pclient->ioloop = io_loop_create(); if ( program_client_connect(pclient) >= 0 ) { diff -r 2a8bb622f17e -r 9448c8ae2f15 src/lib-sieve/util/program-client.h --- a/src/lib-sieve/util/program-client.h Wed Dec 25 21:42:05 2013 +0100 +++ b/src/lib-sieve/util/program-client.h Wed Dec 25 21:45:47 2013 +0100 @@ -26,6 +26,11 @@ void program_client_set_output (struct program_client *pclient, struct ostream *output); +void program_client_set_output_seekable + (struct program_client *pclient, const char *temp_prefix); +struct istream *program_client_get_output_seekable + (struct program_client *pclient); + void program_client_set_env (struct program_client *pclient, const char *name, const char *value); diff -r 2a8bb622f17e -r 9448c8ae2f15 src/plugins/sieve-extprograms/cmd-filter.c --- a/src/plugins/sieve-extprograms/cmd-filter.c Wed Dec 25 21:42:05 2013 +0100 +++ b/src/plugins/sieve-extprograms/cmd-filter.c Wed Dec 25 21:45:47 2013 +0100 @@ -121,38 +121,6 @@ * Code execution */ -static int cmd_filter_get_tempfile -(const struct sieve_runtime_env *renv) -{ - struct sieve_instance *svinst = renv->svinst; - struct mail_user *mail_user = renv->scriptenv->user; - string_t *path; - int fd; - - path = t_str_new(128); - mail_user_set_get_temp_prefix(path, mail_user->set); - fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1); - if (fd == -1) { - sieve_sys_error(svinst, "filter action: " - "safe_mkstemp(%s) failed: %m", str_c(path)); - return -1; - } - - /* We just want the fd, unlink it */ - if (unlink(str_c(path)) < 0) { - /* Shouldn't happen.. */ - sieve_sys_error(svinst, "filter action: " - "unlink(%s) failed: %m", str_c(path)); - if ( close(fd) < 0 ) { - sieve_sys_error(svinst, "filter action: " - "close(%s) failed after error: %m", str_c(path)); - } - return -1; - } - - return fd; -} - static int cmd_filter_operation_execute From pigeonhole at rename-it.nl Wed Dec 25 22:51:29 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Wed, 25 Dec 2013 21:51:29 +0100 Subject: dovecot-2.2-pigeonhole: lib-sieve: Added method to script object... Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/cafc7f640c97 changeset: 1827:cafc7f640c97 user: Stephan Bosch date: Wed Dec 25 21:40:19 2013 +0100 description: lib-sieve: Added method to script object for obtaining the directory where the script binary is stored. diffstat: src/lib-sieve/sieve-script-dict.c | 1 + src/lib-sieve/sieve-script-file.c | 9 +++++++++ src/lib-sieve/sieve-script-private.h | 2 ++ src/lib-sieve/sieve-script.c | 14 ++++++++++++++ src/lib-sieve/sieve-script.h | 3 +++ 5 files changed, 29 insertions(+), 0 deletions(-) diffs (86 lines): diff -r c3d99cdd49f1 -r cafc7f640c97 src/lib-sieve/sieve-script-dict.c --- a/src/lib-sieve/sieve-script-dict.c Wed Dec 25 21:36:55 2013 +0100 +++ b/src/lib-sieve/sieve-script-dict.c Wed Dec 25 21:40:19 2013 +0100 @@ -289,6 +289,7 @@ sieve_dict_script_binary_write_metadata, sieve_dict_script_binary_load, sieve_dict_script_binary_save, + NULL, NULL, sieve_dict_script_equals diff -r c3d99cdd49f1 -r cafc7f640c97 src/lib-sieve/sieve-script-file.c --- a/src/lib-sieve/sieve-script-file.c Wed Dec 25 21:36:55 2013 +0100 +++ b/src/lib-sieve/sieve-script-file.c Wed Dec 25 21:40:19 2013 +0100 @@ -354,6 +354,14 @@ script->st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), error_r); } +static const char *sieve_file_script_binary_get_directory +(struct sieve_script *_script) +{ + struct sieve_file_script *script = (struct sieve_file_script *)_script; + + return script-> dirpath; +} + const struct sieve_script sieve_file_script = { .driver_name = SIEVE_FILE_SCRIPT_DRIVER_NAME, .v = { @@ -368,6 +376,7 @@ NULL, sieve_file_script_binary_load, sieve_file_script_binary_save, + sieve_file_script_binary_get_directory, sieve_file_script_get_size, diff -r c3d99cdd49f1 -r cafc7f640c97 src/lib-sieve/sieve-script-private.h --- a/src/lib-sieve/sieve-script-private.h Wed Dec 25 21:36:55 2013 +0100 +++ b/src/lib-sieve/sieve-script-private.h Wed Dec 25 21:40:19 2013 +0100 @@ -32,6 +32,8 @@ int (*binary_save) (struct sieve_script *script, struct sieve_binary *sbin, bool update, enum sieve_error *error_r); + const char *(*binary_get_directory) + (struct sieve_script *script); int (*get_size) (const struct sieve_script *script, uoff_t *size_r); diff -r c3d99cdd49f1 -r cafc7f640c97 src/lib-sieve/sieve-script.c --- a/src/lib-sieve/sieve-script.c Wed Dec 25 21:36:55 2013 +0100 +++ b/src/lib-sieve/sieve-script.c Wed Dec 25 21:40:19 2013 +0100 @@ -542,6 +542,20 @@ return script->v.binary_save(script, sbin, update, error_r); } +const char *sieve_script_binary_get_directory +(struct sieve_script *script) +{ + if ( script->bin_dir != NULL && + sieve_script_setup_bindir(script, 0700) >= 0 ) { + return script->bin_dir; + } + + if ( script->v.binary_get_directory == NULL ) + return NULL; + + return script->v.binary_get_directory(script); +} + int sieve_script_setup_bindir (struct sieve_script *script, mode_t mode) { diff -r c3d99cdd49f1 -r cafc7f640c97 src/lib-sieve/sieve-script.h --- a/src/lib-sieve/sieve-script.h Wed Dec 25 21:36:55 2013 +0100 +++ b/src/lib-sieve/sieve-script.h Wed Dec 25 21:40:19 2013 +0100 @@ -68,6 +68,9 @@ (struct sieve_script *script, struct sieve_binary *sbin, bool update, enum sieve_error *error_r); +const char *sieve_script_binary_get_directory + (struct sieve_script *script); + /* * Stream management */ From pigeonhole at rename-it.nl Wed Dec 25 22:51:30 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Wed, 25 Dec 2013 21:51:30 +0100 Subject: dovecot-2.2-pigeonhole: Fixed compiler warning. Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/570b58093003 changeset: 1830:570b58093003 user: Stephan Bosch date: Wed Dec 25 21:48:15 2013 +0100 description: Fixed compiler warning. diffstat: src/lib-sieve/plugins/ihave/ext-ihave-binary.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 9448c8ae2f15 -r 570b58093003 src/lib-sieve/plugins/ihave/ext-ihave-binary.c --- a/src/lib-sieve/plugins/ihave/ext-ihave-binary.c Wed Dec 25 21:45:47 2013 +0100 +++ b/src/lib-sieve/plugins/ihave/ext-ihave-binary.c Wed Dec 25 21:48:15 2013 +0100 @@ -115,7 +115,7 @@ static bool ext_ihave_binary_pre_save (const struct sieve_extension *ext, struct sieve_binary *sbin, - void *context, enum sieve_error *error_r) + void *context, enum sieve_error *error_r ATTR_UNUSED) { struct ext_ihave_binary_context *binctx = (struct ext_ihave_binary_context *) context; From pigeonhole at rename-it.nl Wed Dec 25 22:51:30 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Wed, 25 Dec 2013 21:51:30 +0100 Subject: dovecot-2.2-pigeonhole: lib-sieve: Added post_save hook to binar... Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/2a8bb622f17e changeset: 1828:2a8bb622f17e user: Stephan Bosch date: Wed Dec 25 21:42:05 2013 +0100 description: lib-sieve: Added post_save hook to binary object. diffstat: src/lib-sieve/plugins/ihave/ext-ihave-binary.c | 26 +++++---- src/lib-sieve/plugins/include/ext-include-binary.c | 32 +++++++----- src/lib-sieve/plugins/include/ext-include-variables.c | 3 +- src/lib-sieve/plugins/include/ext-include-variables.h | 3 +- src/lib-sieve/sieve-binary-file.c | 46 ++++++++++++++---- src/lib-sieve/sieve-binary.h | 7 ++- 6 files changed, 75 insertions(+), 42 deletions(-) diffs (246 lines): diff -r cafc7f640c97 -r 2a8bb622f17e src/lib-sieve/plugins/ihave/ext-ihave-binary.c --- a/src/lib-sieve/plugins/ihave/ext-ihave-binary.c Wed Dec 25 21:40:19 2013 +0100 +++ b/src/lib-sieve/plugins/ihave/ext-ihave-binary.c Wed Dec 25 21:42:05 2013 +0100 @@ -20,24 +20,25 @@ * Forward declarations */ -static bool ext_ihave_binary_save - (const struct sieve_extension *ext, struct sieve_binary *sbin, void *context); +static bool ext_ihave_binary_pre_save + (const struct sieve_extension *ext, struct sieve_binary *sbin, + void *context, enum sieve_error *error_r); static bool ext_ihave_binary_open - (const struct sieve_extension *ext, struct sieve_binary *sbin, void *context); + (const struct sieve_extension *ext, struct sieve_binary *sbin, + void *context); static bool ext_ihave_binary_up_to_date - (const struct sieve_extension *ext, struct sieve_binary *sbin, void *context, - enum sieve_compile_flags cpflags); + (const struct sieve_extension *ext, struct sieve_binary *sbin, + void *context, enum sieve_compile_flags cpflags); /* * Binary include extension */ const struct sieve_binary_extension ihave_binary_ext = { - &ihave_extension, - ext_ihave_binary_save, - ext_ihave_binary_open, - NULL, - ext_ihave_binary_up_to_date + .extension = &ihave_extension, + .binary_pre_save = ext_ihave_binary_pre_save, + .binary_open = ext_ihave_binary_open, + .binary_up_to_date = ext_ihave_binary_up_to_date }; /* @@ -112,8 +113,9 @@ * Binary extension */ -static bool ext_ihave_binary_save -(const struct sieve_extension *ext, struct sieve_binary *sbin, void *context) +static bool ext_ihave_binary_pre_save +(const struct sieve_extension *ext, struct sieve_binary *sbin, + void *context, enum sieve_error *error_r) { struct ext_ihave_binary_context *binctx = (struct ext_ihave_binary_context *) context; diff -r cafc7f640c97 -r 2a8bb622f17e src/lib-sieve/plugins/include/ext-include-binary.c --- a/src/lib-sieve/plugins/include/ext-include-binary.c Wed Dec 25 21:40:19 2013 +0100 +++ b/src/lib-sieve/plugins/include/ext-include-binary.c Wed Dec 25 21:42:05 2013 +0100 @@ -23,26 +23,29 @@ * Forward declarations */ -static bool ext_include_binary_save - (const struct sieve_extension *ext, struct sieve_binary *sbin, void *context); +static bool ext_include_binary_pre_save + (const struct sieve_extension *ext, struct sieve_binary *sbin, + void *context, enum sieve_error *error_r); static bool ext_include_binary_open - (const struct sieve_extension *ext, struct sieve_binary *sbin, void *context); + (const struct sieve_extension *ext, struct sieve_binary *sbin, + void *context); static bool ext_include_binary_up_to_date - (const struct sieve_extension *ext, struct sieve_binary *sbin, void *context, - enum sieve_compile_flags cpflags); + (const struct sieve_extension *ext, struct sieve_binary *sbin, + void *context, enum sieve_compile_flags cpflags); static void ext_include_binary_free - (const struct sieve_extension *ext, struct sieve_binary *sbin, void *context); + (const struct sieve_extension *ext, struct sieve_binary *sbin, + void *context); /* * Binary include extension */ const struct sieve_binary_extension include_binary_ext = { - &include_extension, - ext_include_binary_save, - ext_include_binary_open, - ext_include_binary_free, - ext_include_binary_up_to_date + .extension = &include_extension, + .binary_pre_save = ext_include_binary_pre_save, + .binary_open = ext_include_binary_open, + .binary_free = ext_include_binary_free, + .binary_up_to_date = ext_include_binary_up_to_date }; /* @@ -202,9 +205,10 @@ * Binary extension */ -static bool ext_include_binary_save +static bool ext_include_binary_pre_save (const struct sieve_extension *ext ATTR_UNUSED, - struct sieve_binary *sbin ATTR_UNUSED, void *context) + struct sieve_binary *sbin ATTR_UNUSED, void *context, + enum sieve_error *error_r) { struct ext_include_binary_context *binctx = (struct ext_include_binary_context *) context; @@ -234,7 +238,7 @@ sieve_script_binary_write_metadata(incscript->script, sblock); } - result = ext_include_variables_save(sblock, binctx->global_vars); + result = ext_include_variables_save(sblock, binctx->global_vars, error_r); return result; } diff -r cafc7f640c97 -r 2a8bb622f17e src/lib-sieve/plugins/include/ext-include-variables.c --- a/src/lib-sieve/plugins/include/ext-include-variables.c Wed Dec 25 21:40:19 2013 +0100 +++ b/src/lib-sieve/plugins/include/ext-include-variables.c Wed Dec 25 21:42:05 2013 +0100 @@ -80,7 +80,8 @@ bool ext_include_variables_save (struct sieve_binary_block *sblock, - struct sieve_variable_scope_binary *global_vars) + struct sieve_variable_scope_binary *global_vars, + enum sieve_error *error_r ATTR_UNUSED) { struct sieve_variable_scope *global_scope = sieve_variable_scope_binary_get(global_vars); diff -r cafc7f640c97 -r 2a8bb622f17e src/lib-sieve/plugins/include/ext-include-variables.h --- a/src/lib-sieve/plugins/include/ext-include-variables.h Wed Dec 25 21:40:19 2013 +0100 +++ b/src/lib-sieve/plugins/include/ext-include-variables.h Wed Dec 25 21:42:05 2013 +0100 @@ -24,7 +24,8 @@ bool ext_include_variables_save (struct sieve_binary_block *sblock, - struct sieve_variable_scope_binary *global_vars); + struct sieve_variable_scope_binary *global_vars, + enum sieve_error *error_r); bool ext_include_variables_load (const struct sieve_extension *this_ext, struct sieve_binary_block *sblock, sieve_size_t *offset, struct sieve_variable_scope_binary **global_vars_r); diff -r cafc7f640c97 -r 2a8bb622f17e src/lib-sieve/sieve-binary-file.c --- a/src/lib-sieve/sieve-binary-file.c Wed Dec 25 21:40:19 2013 +0100 +++ b/src/lib-sieve/sieve-binary-file.c Wed Dec 25 21:42:05 2013 +0100 @@ -198,23 +198,12 @@ (struct sieve_binary *sbin, struct ostream *stream) { struct sieve_binary_header header; - struct sieve_binary_extension_reg *const *regs; struct sieve_binary_block *ext_block; unsigned int ext_count, blk_count, i; uoff_t block_index; blk_count = sieve_binary_block_count(sbin); - /* Signal all extensions to finish generating their blocks */ - - regs = array_get(&sbin->extensions, &ext_count); - for ( i = 0; i < ext_count; i++ ) { - const struct sieve_binary_extension *binext = regs[i]->binext; - - if ( binext != NULL && binext->binary_save != NULL ) - binext->binary_save(regs[i]->extension, sbin, regs[i]->context); - } - /* Create header */ header.magic = SIEVE_BINARY_MAGIC; @@ -277,6 +266,8 @@ int result, fd; string_t *temp_path; struct ostream *stream; + struct sieve_binary_extension_reg *const *regs; + unsigned int ext_count, i; if ( error_r != NULL ) *error_r = SIEVE_ERROR_NONE; @@ -312,6 +303,18 @@ return -1; } + /* Signal all extensions that we're about to save the binary */ + regs = array_get(&sbin->extensions, &ext_count); + for ( i = 0; i < ext_count; i++ ) { + const struct sieve_binary_extension *binext = regs[i]->binext; + + if ( binext != NULL && binext->binary_pre_save != NULL && + !binext->binary_pre_save + (regs[i]->extension, sbin, regs[i]->context, error_r)) { + return -1; + } + } + /* Save binary */ result = 1; stream = o_stream_create_fd(fd, 0, FALSE); @@ -353,9 +356,28 @@ str_c(temp_path)); } } else { - if ( sbin->path == NULL ) { + if ( sbin->path == NULL ) sbin->path = p_strdup(sbin->pool, path); + + /* Signal all extensions that we successfully saved the binary */ + regs = array_get(&sbin->extensions, &ext_count); + for ( i = 0; i < ext_count; i++ ) { + const struct sieve_binary_extension *binext = regs[i]->binext; + + if ( binext != NULL && binext->binary_post_save != NULL && + !binext->binary_post_save + (regs[i]->extension, sbin, regs[i]->context, error_r)) { + result = -1; + break; + } } + + if ( result < 0 && unlink(path) < 0 && errno != ENOENT ) { + sieve_sys_error(sbin->svinst, + "binary save: failed to clean up after error: " + "unlink(%s) failed: %m", path); + } + sbin->path = NULL; } return result; diff -r cafc7f640c97 -r 2a8bb622f17e src/lib-sieve/sieve-binary.h --- a/src/lib-sieve/sieve-binary.h Wed Dec 25 21:40:19 2013 +0100 +++ b/src/lib-sieve/sieve-binary.h Wed Dec 25 21:42:05 2013 +0100 @@ -111,9 +111,12 @@ struct sieve_binary_extension { const struct sieve_extension_def *extension; - bool (*binary_save) + bool (*binary_pre_save) (const struct sieve_extension *ext, struct sieve_binary *sbin, - void *context); + void *context, enum sieve_error *error_r); + bool (*binary_post_save) + (const struct sieve_extension *ext, struct sieve_binary *sbin, + void *context, enum sieve_error *error_r); bool (*binary_open) (const struct sieve_extension *ext, struct sieve_binary *sbin, void *context); From pigeonhole at rename-it.nl Wed Dec 25 22:57:44 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Wed, 25 Dec 2013 21:57:44 +0100 Subject: dovecot-2.2-pigeonhole: Fixed consistent spelling mistake. Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/da0fb6e98b2f changeset: 1831:da0fb6e98b2f user: Stephan Bosch date: Wed Dec 25 21:57:38 2013 +0100 description: Fixed consistent spelling mistake. diffstat: NEWS | 20 ++++++++++---------- src/lib-sieve/mcht-matches.c | 2 +- src/lib-sieve/plugins/editheader/cmd-deleteheader.c | 12 ++++++------ src/lib-sieve/sieve-validator.c | 4 ++-- src/lib-sieve/util/edit-mail.c | 2 +- tests/compile/redirect.sieve | 2 +- 6 files changed, 21 insertions(+), 21 deletions(-) diffs (187 lines): diff -r 570b58093003 -r da0fb6e98b2f NEWS --- a/NEWS Wed Dec 25 21:48:15 2013 +0100 +++ b/NEWS Wed Dec 25 21:57:38 2013 +0100 @@ -91,14 +91,14 @@ checking. This extension is in the process of being standardized (https://tools.ietf.org/html/draft-bosch-sieve-duplicate-01). + Sieve date extension: generate warning when invalid date part is specified. - - Sieve editheader extension: fixed crash occuring when addheader :last was + - Sieve editheader extension: fixed crash occurring when addheader :last was used. - Sieve include extension: fixed missing error cleanup that caused a resource leak. - Sieve vacation extension: fixed determination of From: address for when sieve_vacation_dont_check_recipient is active. - Sieve tools: the -D option wasn't enabled and documented for all tools. - - Siev dict script storage: fixed potential segfault occuring when dict + - Siev dict script storage: fixed potential segfault occurring when dict initialization fails. - ManageSieve: fixed bug in skipping of CRLF at end of AUTHENTICATE command. - ManageSieve: fixed handling of unkown commands pre-login. @@ -296,7 +296,7 @@ notice that the default limits are too low and you need to increase them. This problem will show up in logs as "out of memory" errors. See default_vsz_limit and service { vsz_limit } settings. - - Imap4flags: fixed segfault bug occuring in multiscript context. + - Imap4flags: fixed segfault bug occurring in multiscript context. - Added version checking to the ManageSieve settings plugin. This plugin was forgotten when the LDA plugin was updated with this change in the previous release. @@ -508,7 +508,7 @@ + Body extension: implemented proper handling of the :raw transform and added various new tests to the test suite. However, :content "multipart" and :content "message/rfc822" are still not working. - + Fixed race condition occuring when multiple instances are saving the same + + Fixed race condition occurring when multiple instances are saving the same binary (patch by Timo Sirainen). + Test suite: added support for testing multiscript execution. - Made compiler more lenient towars missing CRLF at the end of the script in a @@ -519,7 +519,7 @@ - Fixed bugs in multiscript support; subsequent keep actions were not always merged correctly and implicit side effects were not always handled correctly. - - Fixed a segfault bug in the sieve-test tool occuring when compile fails. + - Fixed a segfault bug in the sieve-test tool occurring when compile fails. - Fixed segfault bug in action procesing. It was triggered while merging side effects in duplicate actions. - Fixed bug in the Sieve plugin that caused it to try to stat() a NULL path, @@ -610,7 +610,7 @@ - Fixed a potential segfault in the argument validation. It didn't surface because no command could have a :tag followed by an associated parameter as last argument. - - Fixed segfault bug occuring in envelope test when performed on null (<>) + - Fixed segfault bug occurring in envelope test when performed on null (<>) envelope path. The fix involves a rather large restructuring of the code to make sure envelope addresses are properly handled everywhere (bug reported by Nikita Koshikov) @@ -720,11 +720,11 @@ compatibility with CMUSieve. This also implements the mark/unmark commands. - Fixed bugs in the regex extension: 1) if an optional match value did not in fact match, subsequent match values would get unexpected indexes. 2) fixed - segfault bug occuring when regex is freed. + segfault bug occurring when regex is freed. - Fixed bug in the use of the :from agrument for the vacation command. If this address included a phrase part, the response would not be a valid RFC822 message. - - Plugged a theoretical security hole occuring when a directory is opened as a + - Plugged a theoretical security hole occurring when a directory is opened as a Sieve binary. - Cleaned up and fixed various log messages. - Fixed bug in the outgoing address verification. Addresses ending in ',' were @@ -789,7 +789,7 @@ + Added MAXREDIRECTS capability after login. + Implemented new script name rules specified in most recent ManageSieve draft. - - Fixed assertion failure occuring with challenge-response SASL mechanisms. + - Fixed assertion failure occurring with challenge-response SASL mechanisms. - Made configure complain about trying to compile against installed Dovecot headers alone. - Fixed compile warning for compilation against CMUSieve. @@ -912,7 +912,7 @@ managesieve. + Added short proxy configuration explanation to the README file + Added 'Known Issues' section to the README file - - Fixed assert bug in sieve-storage occuring when save is canceled. + - Fixed assert bug in sieve-storage occurring when save is canceled. v0.10.0 * Upgraded to Dovecot 1.1: diff -r 570b58093003 -r da0fb6e98b2f src/lib-sieve/mcht-matches.c --- a/src/lib-sieve/mcht-matches.c Wed Dec 25 21:48:15 2013 +0100 +++ b/src/lib-sieve/mcht-matches.c Wed Dec 25 21:57:38 2013 +0100 @@ -313,7 +313,7 @@ !cmp->def->char_match(cmp, &vp, vend, &needle, nend) ) { /* Match failed: now we have a problem. We need to backtrack to the previous - * '*' wildcard occurence and start scanning for the next possible match. + * '*' wildcard occurrence and start scanning for the next possible match. */ debug_printf(" failed fixed match\n"); diff -r 570b58093003 -r da0fb6e98b2f src/lib-sieve/plugins/editheader/cmd-deleteheader.c --- a/src/lib-sieve/plugins/editheader/cmd-deleteheader.c Wed Dec 25 21:48:15 2013 +0100 +++ b/src/lib-sieve/plugins/editheader/cmd-deleteheader.c Wed Dec 25 21:57:38 2013 +0100 @@ -453,11 +453,11 @@ sieve_runtime_trace_descend(renv); if ( index_offset != 0 ) { sieve_runtime_trace(renv, 0, - "deleting matching occurences of header `%s' at index %u%s", + "deleting matching occurrences of header `%s' at index %u%s", str_c(field_name), index_offset, ( index_last ? " from last": "")); } else { sieve_runtime_trace(renv, 0, - "deleting matching occurences of header `%s'", str_c(field_name)); + "deleting matching occurrences of header `%s'", str_c(field_name)); } } @@ -511,7 +511,7 @@ sieve_runtime_trace(renv, 0, "header `%s' not found", str_c(field_name)); } else if ( ret < 0 ) { sieve_runtime_warning(renv, NULL, "deleteheader action: " - "failed to delete occurences of header `%s' (this should not happen!)", + "failed to delete occurrences of header `%s' (this should not happen!)", str_c(field_name)); } @@ -528,15 +528,15 @@ } } - /* Delete all occurences of header */ + /* Delete all occurrences of header */ ret = edit_mail_header_delete(edmail, str_c(field_name), index); if ( ret < 0 ) { sieve_runtime_warning(renv, NULL, "deleteheader action: " - "failed to delete occurences of header `%s' (this should not happen!)", + "failed to delete occurrences of header `%s' (this should not happen!)", str_c(field_name)); } else if ( trace ) { - sieve_runtime_trace(renv, 0, "deleted %d occurences of header `%s'", + sieve_runtime_trace(renv, 0, "deleted %d occurrences of header `%s'", ret, str_c(field_name)); } diff -r 570b58093003 -r da0fb6e98b2f src/lib-sieve/sieve-validator.c --- a/src/lib-sieve/sieve-validator.c Wed Dec 25 21:48:15 2013 +0100 +++ b/src/lib-sieve/sieve-validator.c Wed Dec 25 21:57:38 2013 +0100 @@ -904,7 +904,7 @@ if ( tag_reg == NULL ) { sieve_argument_validate_error(valdtr, arg, "unknown tagged argument ':%s' for the %s %s " - "(reported only once at first occurence)", + "(reported only once at first occurrence)", sieve_ast_argument_tag(arg), sieve_command_identifier(cmd), sieve_command_type_name(cmd)); sieve_validator_register_unknown_tag @@ -1202,7 +1202,7 @@ } else { sieve_validator_error( valdtr, cmd_node->source_line, - "unknown %s '%s' (only reported once at first occurence)", + "unknown %s '%s' (only reported once at first occurrence)", sieve_ast_type_name(ast_type), cmd_node->identifier); sieve_validator_register_unknown_command(valdtr, cmd_node->identifier); diff -r 570b58093003 -r da0fb6e98b2f src/lib-sieve/util/edit-mail.c --- a/src/lib-sieve/util/edit-mail.c Wed Dec 25 21:48:15 2013 +0100 +++ b/src/lib-sieve/util/edit-mail.c Wed Dec 25 21:57:38 2013 +0100 @@ -1190,7 +1190,7 @@ return 0; } - /* Get the first occurence */ + /* Get the first occurrence */ if ( edmail->header_fields_appended == NULL ) { /* There are no appended headers, so first is found directly */ field = header_idx->first->field; diff -r 570b58093003 -r da0fb6e98b2f tests/compile/redirect.sieve --- a/tests/compile/redirect.sieve Wed Dec 25 21:48:15 2013 +0100 +++ b/tests/compile/redirect.sieve Wed Dec 25 21:57:38 2013 +0100 @@ -1,4 +1,4 @@ -# Test various white space occurences +# Test various white space occurrences redirect "stephan at example.org"; redirect " stephan at example.org"; redirect "stephan @example.org"; From pigeonhole at rename-it.nl Sat Dec 28 10:43:59 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Sat, 28 Dec 2013 09:43:59 +0100 Subject: dovecot-2.2-pigeonhole: Fixed messy documentation indent caused ... Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/2d15749f8fc6 changeset: 1834:2d15749f8fc6 user: Stephan Bosch date: Sat Dec 28 09:43:33 2013 +0100 description: Fixed messy documentation indent caused by earlier change. diffstat: doc/extensions/spamtest-virustest.txt | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diffs (16 lines): diff -r f9fd5606b3e7 -r 2d15749f8fc6 doc/extensions/spamtest-virustest.txt --- a/doc/extensions/spamtest-virustest.txt Sat Dec 28 09:41:24 2013 +0100 +++ b/doc/extensions/spamtest-virustest.txt Sat Dec 28 09:43:33 2013 +0100 @@ -43,9 +43,9 @@ This is a structured setting. The first part specifies the header field name. Optionally, an extended POSIX regular expression follows the header field - name, separated by a colon. Any whitespace directly following the colon is not - part of the regular expression. If the regular expression is omitted, any - header content is accepted and the full header value is used. When a regular + name, separated by a colon. Any whitespace directly following the colon is not + part of the regular expression. If the regular expression is omitted, any + header content is accepted and the full header value is used. When a regular expression is used, it must specify one match value (inside brackets) that yields the desired spam scanner result. If the header does not match the regular expression or if no value match is found, the spamtest will match From pigeonhole at rename-it.nl Sat Dec 28 10:41:36 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Sat, 28 Dec 2013 09:41:36 +0100 Subject: dovecot-2.2-pigeonhole: doc/extensions/spamtest-virustest.txt: C... Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/3f67c4ded9b8 changeset: 1832:3f67c4ded9b8 user: Stephan Bosch date: Sat Dec 28 09:24:42 2013 +0100 description: doc/extensions/spamtest-virustest.txt: Clarified that these extensions use the extended POSIX regular expressions. diffstat: doc/extensions/spamtest-virustest.txt | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diffs (18 lines): diff -r da0fb6e98b2f -r 3f67c4ded9b8 doc/extensions/spamtest-virustest.txt --- a/doc/extensions/spamtest-virustest.txt Wed Dec 25 21:57:38 2013 +0100 +++ b/doc/extensions/spamtest-virustest.txt Sat Dec 28 09:24:42 2013 +0100 @@ -42,10 +42,10 @@ against "0". This is a structured setting. The first part specifies the header field name. - Optionally, a POSIX regular expression follows the header field name, - separated by a colon. Any whitespace directly following the colon is not part - of the regular expression. If the regular expression is omitted, any header - content is accepted and the full header value is used. When a regular + Optionally, an extended POSIX regular expression follows the header field + name, separated by a colon. Any whitespace directly following the colon is not + part of the regular expression. If the regular expression is omitted, any + header content is accepted and the full header value is used. When a regular expression is used, it must specify one match value (inside brackets) that yields the desired spam scanner result. If the header does not match the regular expression or if no value match is found, the spamtest will match From pigeonhole at rename-it.nl Sat Dec 28 10:41:36 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Sat, 28 Dec 2013 09:41:36 +0100 Subject: dovecot-2.2-pigeonhole: lib-sieve: spamtest/virustest extensions... Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/f9fd5606b3e7 changeset: 1833:f9fd5606b3e7 user: Stephan Bosch date: Sat Dec 28 09:41:24 2013 +0100 description: lib-sieve: spamtest/virustest extensions: Tests were erroneously performed against the original message. When used together with extprograms filter to add the spam headers, the changes were not being used by the spamtest and virustest extensions. diffstat: src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c | 11 ++- tests/plugins/extprograms/bin/spamc | 6 + tests/plugins/extprograms/filter/execute.svtest | 35 +++++++++- 3 files changed, 48 insertions(+), 4 deletions(-) diffs (114 lines): diff -r 3f67c4ded9b8 -r f9fd5606b3e7 src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c --- a/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c Sat Dec 28 09:24:42 2013 +0100 +++ b/src/lib-sieve/plugins/spamvirustest/ext-spamvirustest-common.c Sat Dec 28 09:41:24 2013 +0100 @@ -454,9 +454,9 @@ struct ext_spamvirustest_data *ext_data = (struct ext_spamvirustest_data *) ext->context; struct ext_spamvirustest_header_spec *status_header, *max_header; - const struct sieve_message_data *msgdata = renv->msgdata; struct sieve_message_context *msgctx = renv->msgctx; struct ext_spamvirustest_message_context *mctx; + struct mail *mail; regmatch_t match_values[2]; const char *header_value, *error; const char *status = NULL, *max = NULL; @@ -481,10 +481,14 @@ sieve_message_context_extension_get(msgctx, ext); if ( mctx == NULL ) { + /* Create new context */ mctx = p_new(pool, struct ext_spamvirustest_message_context, 1); sieve_message_context_extension_set(msgctx, ext, (void *)mctx); } else if ( mctx->reload == ext_data->reload ) { + /* Use cached result */ return ext_spamvirustest_get_score(ext, mctx->score_ratio, percent); + } else { + /* Extension was reloaded (probably in testsuite) */ } mctx->reload = ext_data->reload; @@ -493,6 +497,7 @@ * Get max status value */ + mail = sieve_message_get_mail(renv->msgctx); status_header = &ext_data->status_header; max_header = &ext_data->max_header; @@ -500,7 +505,7 @@ if ( max_header->header_name != NULL ) { /* Get header from message */ if ( mail_get_first_header_utf8 - (msgdata->mail, max_header->header_name, &header_value) < 0 || + (mail, max_header->header_name, &header_value) < 0 || header_value == NULL ) { sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "header '%s' not found in message", @@ -553,7 +558,7 @@ /* Get header from message */ if ( mail_get_first_header_utf8 - (msgdata->mail, status_header->header_name, &header_value) < 0 || + (mail, status_header->header_name, &header_value) < 0 || header_value == NULL ) { sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "header '%s' not found in message", diff -r 3f67c4ded9b8 -r f9fd5606b3e7 tests/plugins/extprograms/bin/spamc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/plugins/extprograms/bin/spamc Sat Dec 28 09:41:24 2013 +0100 @@ -0,0 +1,6 @@ +#!/bin/sh + +echo 'X-Spam-Status: Yes, score=66.5/5.0 tests=CONTAINS_LARGE_ROOSTER' +cat + +exit 0 diff -r 3f67c4ded9b8 -r f9fd5606b3e7 tests/plugins/extprograms/filter/execute.svtest --- a/tests/plugins/extprograms/filter/execute.svtest Sat Dec 28 09:24:42 2013 +0100 +++ b/tests/plugins/extprograms/filter/execute.svtest Sat Dec 28 09:41:24 2013 +0100 @@ -3,6 +3,7 @@ require "vnd.dovecot.debug"; require "variables"; require "editheader"; +require "spamtest"; require "body"; require "fileinto"; require "mailbox"; @@ -177,4 +178,36 @@ if not header "X-E" "5" { test_fail "X-E header missing in final message"; } -} +} + +test_config_set "sieve_spamtest_status_header" + "X-Spam-Status: [^,]*, score=(-?[[:digit:]]+\\.[[:digit:]]).*"; +test_config_set "sieve_spamtest_max_value" "10"; +test_config_set "sieve_spamtest_status_type" "score"; +test_config_reload :extension "spamtest"; + +test_result_reset; +test "Spamtest" { + if exists "x-spam-status" { + test_fail "message already modified"; + } + + if not header "subject" "Frop!" { + test_fail "message is wrong"; + } + + filter "spamc"; + + if not exists "x-spam-status" { + test_fail "x-spam-score header not added"; + } + + if spamtest :is "0" { + test_fail "spamtest not configured or test failed"; + } + + if not spamtest :is "10" { + test_fail "spamtest yields incorrect value"; + } +} + From pigeonhole at rename-it.nl Mon Dec 30 18:54:32 2013 From: pigeonhole at rename-it.nl (pigeonhole at rename-it.nl) Date: Mon, 30 Dec 2013 17:54:32 +0100 Subject: dovecot-2.2-pigeonhole: lib-sieve: Added macros for argument gen... Message-ID: details: http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/cab3d18a00c9 changeset: 1835:cab3d18a00c9 user: Stephan Bosch date: Mon Dec 30 17:54:23 2013 +0100 description: lib-sieve: Added macros for argument generation errors. diffstat: src/lib-sieve/sieve-commands.h | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-) diffs (15 lines): diff -r 2d15749f8fc6 -r cab3d18a00c9 src/lib-sieve/sieve-commands.h --- a/src/lib-sieve/sieve-commands.h Sat Dec 28 09:43:33 2013 +0100 +++ b/src/lib-sieve/sieve-commands.h Mon Dec 30 17:54:23 2013 +0100 @@ -67,6 +67,11 @@ #define sieve_argument_validate_warning(validator, arg_node, ...) \ sieve_validator_warning(validator, (arg_node)->source_line, __VA_ARGS__) +#define sieve_argument_generate_error(gentr, arg_node, ...) \ + sieve_generator_error(gentr, (arg_node)->source_line, __VA_ARGS__) +#define sieve_argument_generate_warning(gentr, arg_node, ...) \ + sieve_generator_warning(gentr, (arg_node)->source_line, __VA_ARGS__) + /* Argument API */ struct sieve_argument *sieve_argument_create