# --- SDE-COPYRIGHT-NOTE-BEGIN --- # This copyright note is auto-generated by ./scripts/Create-CopyPatch. # # Filename: package/.../dovecot/dovecot-2.2.2-0000-upstream-fixes.patch # Copyright (C) 2013 The OpenSDE Project # # More information can be found in the files COPYING and README. # # This patch file is dual-licensed. It is available under the license the # patched project is licensed under, as long as it is an OpenSource license # as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms # of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # --- SDE-COPYRIGHT-NOTE-END --- From 5dcc6d180aec16d34d60719248a17ec026425fa8 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Mon, 20 May 2013 17:30:23 +0300 Subject: [PATCH] dsync: Fixed unsubscribing from an already deleted mailbox. diff --git a/src/doveadm/dsync/dsync-brain-mailbox-tree.c b/src/doveadm/dsync/dsync-brain-mailbox-tree.c index 6c878da..6354038 100644 --- a/src/doveadm/dsync/dsync-brain-mailbox-tree.c +++ b/src/doveadm/dsync/dsync-brain-mailbox-tree.c @@ -371,11 +371,24 @@ dsync_brain_mailbox_tree_add_delete(struct dsync_mailbox_tree *tree, if (node == NULL) return; - if (!other_del->delete_mailbox && - other_del->timestamp <= node->last_renamed_or_created) { - /* we don't want to delete this directory, we already have a - newer timestamp for it */ - return; + switch (other_del->type) { + case DSYNC_MAILBOX_DELETE_TYPE_MAILBOX: + /* mailbox is always deleted */ + break; + case DSYNC_MAILBOX_DELETE_TYPE_DIR: + if (other_del->timestamp <= node->last_renamed_or_created) { + /* we don't want to delete this directory, we already + have a newer timestamp for it */ + return; + } + break; + case DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE: + if (other_del->timestamp <= node->last_subscription_change) { + /* we don't want to unsubscribe, since we already have + a newer subscription timestamp */ + return; + } + break; } /* make a node for it in the other mailbox tree */ @@ -384,20 +397,25 @@ dsync_brain_mailbox_tree_add_delete(struct dsync_mailbox_tree *tree, if (!guid_128_is_empty(other_node->mailbox_guid) || (other_node->existence == DSYNC_MAILBOX_NODE_EXISTS && - !other_del->delete_mailbox)) { + other_del->type != DSYNC_MAILBOX_DELETE_TYPE_MAILBOX)) { /* other side has already created a new mailbox or directory with this name, we can't delete it */ return; } /* ok, mark the other node deleted */ - if (other_del->delete_mailbox) { + if (other_del->type == DSYNC_MAILBOX_DELETE_TYPE_MAILBOX) { memcpy(other_node->mailbox_guid, node->mailbox_guid, sizeof(other_node->mailbox_guid)); } i_assert(other_node->ns == NULL || other_node->ns == node->ns); other_node->ns = node->ns; - other_node->existence = DSYNC_MAILBOX_NODE_DELETED; + if (other_del->type != DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE) + other_node->existence = DSYNC_MAILBOX_NODE_DELETED; + else { + other_node->last_subscription_change = other_del->timestamp; + other_node->subscribed = FALSE; + } if (dsync_mailbox_tree_guid_hash_add(other_tree, other_node, &old_node) < 0) diff --git a/src/doveadm/dsync/dsync-ibc-stream.c b/src/doveadm/dsync/dsync-ibc-stream.c index 729a972..462815a 100644 --- a/src/doveadm/dsync/dsync-ibc-stream.c +++ b/src/doveadm/dsync/dsync-ibc-stream.c @@ -90,7 +90,7 @@ static const struct { { .name = "mailbox_delete", .chr = 'D', .required_keys = "hierarchy_sep", - .optional_keys = "mailboxes dirs" + .optional_keys = "mailboxes dirs unsubscribes" }, { .name = "mailbox", .chr = 'B', @@ -936,6 +936,28 @@ dsync_ibc_stream_recv_mailbox_tree_node(struct dsync_ibc *_ibc, } static void +dsync_ibc_stream_encode_delete(string_t *str, + struct dsync_serializer_encoder *encoder, + const struct dsync_mailbox_delete *deletes, + unsigned int count, const char *key, + enum dsync_mailbox_delete_type type) +{ + unsigned int i; + + str_truncate(str, 0); + for (i = 0; i < count; i++) { + if (deletes[i].type == type) { + str_append(str, guid_128_to_string(deletes[i].guid)); + str_printfa(str, " %ld ", (long)deletes[i].timestamp); + } + } + if (str_len(str) > 0) { + str_truncate(str, str_len(str)-1); + dsync_serializer_encode_add(encoder, key, str_c(str)); + } +} + +static void dsync_ibc_stream_send_mailbox_deletes(struct dsync_ibc *_ibc, const struct dsync_mailbox_delete *deletes, unsigned int count, char hierarchy_sep) @@ -944,7 +966,6 @@ dsync_ibc_stream_send_mailbox_deletes(struct dsync_ibc *_ibc, struct dsync_serializer_encoder *encoder; string_t *str, *substr; char sep[2]; - unsigned int i; str = t_str_new(128); str_append_c(str, items[ITEM_MAILBOX_DELETE].chr); @@ -954,29 +975,15 @@ dsync_ibc_stream_send_mailbox_deletes(struct dsync_ibc *_ibc, dsync_serializer_encode_add(encoder, "hierarchy_sep", sep); substr = t_str_new(128); - for (i = 0; i < count; i++) { - if (deletes[i].delete_mailbox) { - str_append(substr, guid_128_to_string(deletes[i].guid)); - str_printfa(substr, " %ld ", (long)deletes[i].timestamp); - } - } - if (str_len(substr) > 0) { - str_truncate(substr, str_len(substr)-1); - dsync_serializer_encode_add(encoder, "mailboxes", - str_c(substr)); - } - - str_truncate(substr, 0); - for (i = 0; i < count; i++) { - if (!deletes[i].delete_mailbox) { - str_append(substr, guid_128_to_string(deletes[i].guid)); - str_printfa(substr, " %ld ", (long)deletes[i].timestamp); - } - } - if (str_len(substr) > 0) { - str_truncate(substr, str_len(substr)-1); - dsync_serializer_encode_add(encoder, "dirs", str_c(substr)); - } + dsync_ibc_stream_encode_delete(substr, encoder, deletes, count, + "mailboxes", + DSYNC_MAILBOX_DELETE_TYPE_MAILBOX); + dsync_ibc_stream_encode_delete(substr, encoder, deletes, count, + "dirs", + DSYNC_MAILBOX_DELETE_TYPE_DIR); + dsync_ibc_stream_encode_delete(substr, encoder, deletes, count, + "unsubscribes", + DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE); dsync_serializer_encode_finish(&encoder, str); dsync_ibc_stream_send_string(ibc, str); } @@ -984,7 +991,7 @@ dsync_ibc_stream_send_mailbox_deletes(struct dsync_ibc *_ibc, ARRAY_DEFINE_TYPE(dsync_mailbox_delete, struct dsync_mailbox_delete); static int decode_mailbox_deletes(ARRAY_TYPE(dsync_mailbox_delete) *deletes, - const char *value, bool delete_mailbox) + const char *value, enum dsync_mailbox_delete_type type) { struct dsync_mailbox_delete *del; const char *const *tmp; @@ -993,7 +1000,7 @@ decode_mailbox_deletes(ARRAY_TYPE(dsync_mailbox_delete) *deletes, tmp = t_strsplit(value, " "); for (i = 0; tmp[i] != NULL; i += 2) { del = array_append_space(deletes); - del->delete_mailbox = delete_mailbox; + del->type = type; if (guid_128_from_string(tmp[i], del->guid) < 0) return -1; if (tmp[i+1] == NULL || @@ -1029,12 +1036,20 @@ dsync_ibc_stream_recv_mailbox_deletes(struct dsync_ibc *_ibc, *hierarchy_sep_r = value[0]; if (dsync_deserializer_decode_try(decoder, "mailboxes", &value) && - decode_mailbox_deletes(&deletes, value, TRUE) < 0) { + decode_mailbox_deletes(&deletes, value, + DSYNC_MAILBOX_DELETE_TYPE_MAILBOX) < 0) { dsync_ibc_input_error(ibc, decoder, "Invalid mailboxes"); return DSYNC_IBC_RECV_RET_TRYAGAIN; } if (dsync_deserializer_decode_try(decoder, "dirs", &value) && - decode_mailbox_deletes(&deletes, value, FALSE) < 0) { + decode_mailbox_deletes(&deletes, value, + DSYNC_MAILBOX_DELETE_TYPE_DIR) < 0) { + dsync_ibc_input_error(ibc, decoder, "Invalid dirs"); + return DSYNC_IBC_RECV_RET_TRYAGAIN; + } + if (dsync_deserializer_decode_try(decoder, "unsubscribes", &value) && + decode_mailbox_deletes(&deletes, value, + DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE) < 0) { dsync_ibc_input_error(ibc, decoder, "Invalid dirs"); return DSYNC_IBC_RECV_RET_TRYAGAIN; } diff --git a/src/doveadm/dsync/dsync-mailbox-tree-fill.c b/src/doveadm/dsync/dsync-mailbox-tree-fill.c index ddf2ebb..9480ebb 100644 --- a/src/doveadm/dsync/dsync-mailbox-tree-fill.c +++ b/src/doveadm/dsync/dsync-mailbox-tree-fill.c @@ -163,7 +163,7 @@ dsync_mailbox_tree_add_change_timestamps(struct dsync_mailbox_tree *tree, break; } del = array_append_space(&tree->deletes); - del->delete_mailbox = TRUE; + del->type = DSYNC_MAILBOX_DELETE_TYPE_MAILBOX; del->timestamp = timestamp; memcpy(del->guid, rec->mailbox_guid, sizeof(del->guid)); break; @@ -177,6 +177,7 @@ dsync_mailbox_tree_add_change_timestamps(struct dsync_mailbox_tree *tree, dsync side, it can match this deletion to the name. */ del = array_append_space(&tree->deletes); + del->type = DSYNC_MAILBOX_DELETE_TYPE_DIR; del->timestamp = timestamp; memcpy(del->guid, rec->mailbox_guid, sizeof(del->guid)); break; @@ -195,10 +196,22 @@ dsync_mailbox_tree_add_change_timestamps(struct dsync_mailbox_tree *tree, node->last_renamed_or_created = timestamp; break; case MAILBOX_LOG_RECORD_SUBSCRIBE: - case MAILBOX_LOG_RECORD_UNSUBSCRIBE: if (node != NULL) node->last_subscription_change = timestamp; break; + case MAILBOX_LOG_RECORD_UNSUBSCRIBE: + if (node != NULL) { + node->last_subscription_change = timestamp; + break; + } + /* The mailbox is already deleted, but it may still + exist on the other side (even the subscription + alone). */ + del = array_append_space(&tree->deletes); + del->type = DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE; + del->timestamp = timestamp; + memcpy(del->guid, rec->mailbox_guid, sizeof(del->guid)); + break; } } if (mailbox_log_iter_deinit(&iter) < 0) { diff --git a/src/doveadm/dsync/dsync-mailbox-tree.c b/src/doveadm/dsync/dsync-mailbox-tree.c index 0fa036d..cd8aa9f 100644 --- a/src/doveadm/dsync/dsync-mailbox-tree.c +++ b/src/doveadm/dsync/dsync-mailbox-tree.c @@ -359,7 +359,7 @@ dsync_mailbox_tree_find_delete(struct dsync_mailbox_tree *tree, i_assert(hash_table_is_created(tree->guid_hash)); i_assert(tree->remote_sep != '\0'); - if (del->delete_mailbox) { + if (del->type == DSYNC_MAILBOX_DELETE_TYPE_MAILBOX) { /* find node by GUID */ return hash_table_lookup(tree->guid_hash, guid_p); } diff --git a/src/doveadm/dsync/dsync-mailbox-tree.h b/src/doveadm/dsync/dsync-mailbox-tree.h index 58e4531..5a84b0e 100644 --- a/src/doveadm/dsync/dsync-mailbox-tree.h +++ b/src/doveadm/dsync/dsync-mailbox-tree.h @@ -63,10 +63,17 @@ ARRAY_DEFINE_TYPE(dsync_mailbox_node, struct dsync_mailbox_node *); #define dsync_mailbox_node_is_dir(node) \ guid_128_is_empty((node)->mailbox_guid) +enum dsync_mailbox_delete_type { + /* Delete mailbox by given GUID */ + DSYNC_MAILBOX_DELETE_TYPE_MAILBOX = 1, + /* Delete mailbox directory by given SHA1 name */ + DSYNC_MAILBOX_DELETE_TYPE_DIR, + /* Unsubscribe mailbox by given SHA1 name */ + DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE, +}; + struct dsync_mailbox_delete { - /* true: guid = mailbox GUID - false: guid = sha1 of directory name */ - bool delete_mailbox; + enum dsync_mailbox_delete_type type; guid_128_t guid; time_t timestamp; }; -- 1.7.10.2 From 25c76e24f77e4f66cdbc3a60be390bbeb2230c9c Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Mon, 20 May 2013 18:26:16 +0300 Subject: [PATCH] dsync: Previous have_save_guids change somewhat broke compatibility with earlier dsync versions. diff --git a/src/doveadm/dsync/dsync-ibc-stream.c b/src/doveadm/dsync/dsync-ibc-stream.c index 462815a..3dab919 100644 --- a/src/doveadm/dsync/dsync-ibc-stream.c +++ b/src/doveadm/dsync/dsync-ibc-stream.c @@ -28,10 +28,11 @@ #define DSYNC_IBC_STREAM_OUTBUF_THROTTLE_SIZE (1024*128) #define DSYNC_PROTOCOL_VERSION_MAJOR 3 -#define DSYNC_PROTOCOL_VERSION_MINOR 1 +#define DSYNC_PROTOCOL_VERSION_MINOR 2 #define DSYNC_HANDSHAKE_VERSION "VERSION\tdsync\t3\t1\n" #define DSYNC_PROTOCOL_MINOR_HAVE_ATTRIBUTES 1 +#define DSYNC_PROTOCOL_MINOR_HAVE_SAVE_GUID 2 enum item_type { ITEM_NONE, @@ -1227,7 +1228,8 @@ dsync_ibc_stream_recv_mailbox(struct dsync_ibc *_ibc, box->mailbox_lost = TRUE; if (dsync_deserializer_decode_try(decoder, "have_guids", &value)) box->have_guids = TRUE; - if (dsync_deserializer_decode_try(decoder, "have_save_guids", &value)) + if (dsync_deserializer_decode_try(decoder, "have_save_guids", &value) || + (box->have_guids && ibc->minor_version < DSYNC_PROTOCOL_MINOR_HAVE_SAVE_GUID)) box->have_save_guids = TRUE; value = dsync_deserializer_decode_get(decoder, "uid_validity"); if (str_to_uint32(value, &box->uid_validity) < 0) { -- 1.7.10.2 From b926a5783dc35da61af12d6a4de992ff2964b0e7 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Tue, 21 May 2013 17:09:37 +0300 Subject: [PATCH] auth: Fixed crash if LDAP query returned multiple results. diff --git a/src/auth/db-ldap.c b/src/auth/db-ldap.c index 955e2e6..c61af85 100644 --- a/src/auth/db-ldap.c +++ b/src/auth/db-ldap.c @@ -825,8 +825,10 @@ static void db_ldap_request_free(struct ldap_request *request, LDAPMessage *res) if (srequest->result == res) res = NULL; - if (srequest->result != NULL) + if (srequest->result != NULL) { ldap_msgfree(srequest->result); + srequest->result = NULL; + } if (array_is_created(&srequest->named_results)) { array_foreach(&srequest->named_results, named_res) { @@ -835,6 +837,7 @@ static void db_ldap_request_free(struct ldap_request *request, LDAPMessage *res) if (named_res->result != NULL) ldap_msgfree(named_res->result); } + array_clear(&srequest->named_results); } } if (res != NULL) -- 1.7.10.2 From adc71ee1cfc1eaa18b88c15c3eac475bac740076 Mon Sep 17 00:00:00 2001 From: Stephan Bosch Date: Tue, 21 May 2013 22:55:12 +0300 Subject: [PATCH] lib-imap-urlauth: Fixed local URLAUTH fetches that didn't immediately finish handling content. Local requests are now also properly counted. diff --git a/src/lib-imap-urlauth/imap-urlauth-fetch.c b/src/lib-imap-urlauth/imap-urlauth-fetch.c index 9801822..eb438a7 100644 --- a/src/lib-imap-urlauth/imap-urlauth-fetch.c +++ b/src/lib-imap-urlauth/imap-urlauth-fetch.c @@ -55,8 +55,10 @@ static void imap_urlauth_fetch_abort_local(struct imap_urlauth_fetch *ufetch) { struct imap_urlauth_fetch_url *url, *url_next; - if (ufetch->local_url != NULL) + if (ufetch->local_url != NULL) { + ufetch->pending_requests--; imap_msgpart_url_free(&ufetch->local_url); + } i_free_and_null(ufetch->pending_reply.url); i_free_and_null(ufetch->pending_reply.bodypartstruct); @@ -153,7 +155,6 @@ imap_urlauth_fetch_local(struct imap_urlauth_fetch *ufetch, const char *url, struct imap_msgpart_url *mpurl = NULL; int ret; - ufetch->pending_requests--; success = TRUE; if (debug) @@ -226,6 +227,7 @@ imap_urlauth_fetch_local(struct imap_urlauth_fetch *ufetch, const char *url, } if (!success && ret < 0) { + ufetch->pending_requests--; (void)ufetch->callback(NULL, TRUE, ufetch->context); imap_urlauth_fetch_fail(ufetch); return; @@ -242,12 +244,14 @@ imap_urlauth_fetch_local(struct imap_urlauth_fetch *ufetch, const char *url, reply.size = mpresult.size; reply.input = mpresult.input; - ret = ufetch->callback(&reply, ufetch->pending_requests == 0, + ret = ufetch->callback(&reply, ufetch->pending_requests == 1, ufetch->context); if (ret == 0) { ufetch->local_url = mpurl; ufetch->waiting = TRUE; } else { + ufetch->pending_requests--; + if (mpurl != NULL) imap_msgpart_url_free(&mpurl); if (ret < 0) @@ -302,26 +306,30 @@ imap_urlauth_fetch_request_callback(struct imap_urlauth_fetch_reply *reply, int imap_urlauth_fetch_url(struct imap_urlauth_fetch *ufetch, const char *url, enum imap_urlauth_fetch_flags url_flags) { + struct imap_urlauth_context *uctx = ufetch->uctx; enum imap_url_parse_flags url_parse_flags = IMAP_URL_PARSE_ALLOW_URLAUTH; - struct imap_urlauth_context *uctx = ufetch->uctx; struct mail_user *mail_user = uctx->user; - struct imap_url *imap_url = NULL; + struct imap_url *imap_url; const char *error, *errormsg; - ufetch->failed = FALSE; - ufetch->pending_requests++; - /* parse the url */ if (imap_url_parse(url, NULL, url_parse_flags, &imap_url, &error) < 0) { errormsg = t_strdup_printf( "Failed to fetch URLAUTH \"%s\": %s", url, error); if (mail_user->mail_debug) i_debug("%s", errormsg); + ufetch->pending_requests++; imap_urlauth_fetch_error(ufetch, url, url_flags, errormsg); - + return 1; + } + + ufetch->failed = FALSE; + ufetch->pending_requests++; + /* if access user and target user match, handle fetch request locally */ - } else if (strcmp(mail_user->username, imap_url->userid) == 0) { + if (imap_url->userid != NULL && + strcmp(mail_user->username, imap_url->userid) == 0) { if (ufetch->waiting) { struct imap_urlauth_fetch_url *url_local; @@ -352,15 +360,11 @@ int imap_urlauth_fetch_url(struct imap_urlauth_fetch *ufetch, const char *url, (void)imap_urlauth_request_new(uctx->conn, imap_url->userid, url, url_flags, imap_urlauth_fetch_request_callback, ufetch); - } - - if (ufetch->pending_requests > 0) { i_assert(uctx->conn != NULL); if (imap_urlauth_connection_connect(uctx->conn) < 0) return -1; - return 0; } - return 1; + return (ufetch->pending_requests > 0 ? 0 : 1); } bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch) @@ -377,8 +381,10 @@ bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch) return ufetch->pending_requests > 0; } - if (ufetch->local_url != NULL) + if (ufetch->local_url != NULL) { + ufetch->pending_requests--; imap_msgpart_url_free(&ufetch->local_url); + } ufetch->waiting = FALSE; /* handle pending remote reply */ diff --git a/src/lib-imap-urlauth/imap-urlauth-fetch.h b/src/lib-imap-urlauth/imap-urlauth-fetch.h index 27a96f2..3c5275c 100644 --- a/src/lib-imap-urlauth/imap-urlauth-fetch.h +++ b/src/lib-imap-urlauth/imap-urlauth-fetch.h @@ -31,7 +31,7 @@ struct imap_urlauth_fetch_reply { /* Callback to handle fetch reply. Returns 1 if handled completely and ready for next reply, 0 if not all data was processed, and -1 for error. If a - callback returns 0, imap_urlauth_connection_continue() must be called once + callback returns 0, imap_urlauth_fetch_continue() must be called once new replies may be processed. If this is the last request to yield a reply, argument last is TRUE. The callback must not call imap_urlauth_fetch_deinit(). */ @@ -45,7 +45,7 @@ imap_urlauth_fetch_init(struct imap_urlauth_context *uctx, void imap_urlauth_fetch_deinit(struct imap_urlauth_fetch **_ufetch); int imap_urlauth_fetch_url(struct imap_urlauth_fetch *ufetch, const char *url, - enum imap_urlauth_fetch_flags flags); + enum imap_urlauth_fetch_flags url_flags); bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch); #endif -- 1.7.10.2 From b65589285715ab3ecbde9053948e96d6d0b0daa5 Mon Sep 17 00:00:00 2001 From: Stephan Bosch Date: Tue, 21 May 2013 22:55:17 +0300 Subject: [PATCH] lib-imap-urlauth: Fixed resuming in URLAUTH fetch handler. Fixed URLAUTH fetch handler to properly resume the URLAUTH connection, even when it is deinitialized. diff --git a/src/lib-imap-urlauth/imap-urlauth-fetch.c b/src/lib-imap-urlauth/imap-urlauth-fetch.c index eb438a7..18cd342 100644 --- a/src/lib-imap-urlauth/imap-urlauth-fetch.c +++ b/src/lib-imap-urlauth/imap-urlauth-fetch.c @@ -48,7 +48,8 @@ struct imap_urlauth_fetch { } pending_reply; unsigned int failed:1; - unsigned int waiting:1; + unsigned int waiting_local:1; + unsigned int waiting_service:1; }; static void imap_urlauth_fetch_abort_local(struct imap_urlauth_fetch *ufetch) @@ -112,6 +113,10 @@ void imap_urlauth_fetch_deinit(struct imap_urlauth_fetch **_ufetch) *_ufetch = NULL; imap_urlauth_fetch_abort(ufetch); + + /* dont leave the connection in limbo; make sure resume is called */ + if (ufetch->waiting_service) + imap_urlauth_connection_continue(ufetch->uctx->conn); i_free(ufetch); } @@ -137,7 +142,7 @@ imap_urlauth_fetch_error(struct imap_urlauth_fetch *ufetch, const char *url, } T_END; if (ret == 0) - ufetch->waiting = TRUE; + ufetch->waiting_local = TRUE; else if (ret < 0) imap_urlauth_fetch_fail(ufetch); } @@ -248,7 +253,7 @@ imap_urlauth_fetch_local(struct imap_urlauth_fetch *ufetch, const char *url, ufetch->context); if (ret == 0) { ufetch->local_url = mpurl; - ufetch->waiting = TRUE; + ufetch->waiting_local = TRUE; } else { ufetch->pending_requests--; @@ -267,7 +272,7 @@ imap_urlauth_fetch_request_callback(struct imap_urlauth_fetch_reply *reply, (struct imap_urlauth_fetch *)context; int ret = 1; - if (ufetch->waiting && reply != NULL) { + if (ufetch->waiting_local && reply != NULL) { i_assert(ufetch->pending_reply.url == NULL); ufetch->pending_reply.url = i_strdup(reply->url); ufetch->pending_reply.flags = reply->flags; @@ -284,7 +289,7 @@ imap_urlauth_fetch_request_callback(struct imap_urlauth_fetch_reply *reply, return 0; } - ufetch->waiting = FALSE; + ufetch->waiting_local = FALSE; ufetch->pending_requests--; if (!ufetch->failed) { @@ -297,6 +302,8 @@ imap_urlauth_fetch_request_callback(struct imap_urlauth_fetch_reply *reply, if (!ufetch->failed) imap_urlauth_fetch_abort_local(ufetch); ufetch->failed = TRUE; + } else if (ret == 0) { + ufetch->waiting_service = TRUE; } if (ret != 0) imap_urlauth_fetch_deinit(&ufetch); @@ -331,7 +338,7 @@ int imap_urlauth_fetch_url(struct imap_urlauth_fetch *ufetch, const char *url, if (imap_url->userid != NULL && strcmp(mail_user->username, imap_url->userid) == 0) { - if (ufetch->waiting) { + if (ufetch->waiting_local) { struct imap_urlauth_fetch_url *url_local; url_local = i_new(struct imap_urlauth_fetch_url, 1); @@ -375,17 +382,22 @@ bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch) if (ufetch->failed) return FALSE; - if (!ufetch->waiting) { + if (!ufetch->waiting_local && !ufetch->waiting_service) + return ufetch->pending_requests > 0; + + if (!ufetch->waiting_local) { /* not waiting for local request handling */ + ufetch->waiting_service = FALSE; imap_urlauth_connection_continue(ufetch->uctx->conn); return ufetch->pending_requests > 0; } + /* finished local request */ if (ufetch->local_url != NULL) { ufetch->pending_requests--; imap_msgpart_url_free(&ufetch->local_url); } - ufetch->waiting = FALSE; + ufetch->waiting_local = FALSE; /* handle pending remote reply */ if (ufetch->pending_reply.url != NULL) { @@ -419,11 +431,9 @@ bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch) imap_urlauth_fetch_fail(ufetch); return FALSE; } - - imap_urlauth_connection_continue(ufetch->uctx->conn); if (ret == 0) { - ufetch->waiting = TRUE; + ufetch->waiting_service = TRUE; return TRUE; } } @@ -440,7 +450,7 @@ bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch) &ufetch->local_urls_tail, url); i_free(url->url); i_free(url); - if (ufetch->waiting) + if (ufetch->waiting_local) return TRUE; url = url_next; } -- 1.7.10.2 From 421ec8d0a4072b5f0d2aa63c5aef354a7a1dd659 Mon Sep 17 00:00:00 2001 From: Stephan Bosch Date: Tue, 21 May 2013 22:55:23 +0300 Subject: [PATCH] lib-imap-urlauth: Fixed deinitialization of the URLAUTH fetch handler. Added reference counting to make sure callbacks will not deinitialize the handler prematurely. diff --git a/src/imap/cmd-urlfetch.c b/src/imap/cmd-urlfetch.c index 2826cb0..c3fac61 100644 --- a/src/imap/cmd-urlfetch.c +++ b/src/imap/cmd-urlfetch.c @@ -284,7 +284,6 @@ cmd_urlfetch_url_callback(struct imap_urlauth_fetch_reply *reply, if ((last && cmd->state == CLIENT_COMMAND_STATE_WAIT_EXTERNAL) || ret < 0) { - ctx->ufetch = NULL; cmd_urlfetch_finish(cmd); client_command_free(&cmd); } diff --git a/src/lib-imap-urlauth/imap-urlauth-fetch.c b/src/lib-imap-urlauth/imap-urlauth-fetch.c index 18cd342..0ba4dfa 100644 --- a/src/lib-imap-urlauth/imap-urlauth-fetch.c +++ b/src/lib-imap-urlauth/imap-urlauth-fetch.c @@ -22,6 +22,7 @@ struct imap_urlauth_fetch_url { }; struct imap_urlauth_fetch { + unsigned int refcount; struct imap_urlauth_context *uctx; imap_urlauth_fetch_callback_t *callback; @@ -100,17 +101,28 @@ imap_urlauth_fetch_init(struct imap_urlauth_context *uctx, struct imap_urlauth_fetch *ufetch; ufetch = i_new(struct imap_urlauth_fetch, 1); + ufetch->refcount = 1; ufetch->uctx = uctx; ufetch->callback = callback; ufetch->context = context; return ufetch; } -void imap_urlauth_fetch_deinit(struct imap_urlauth_fetch **_ufetch) +static void imap_urlauth_fetch_ref(struct imap_urlauth_fetch *ufetch) +{ + i_assert(ufetch->refcount > 0); + ufetch->refcount++; +} + +static void imap_urlauth_fetch_unref(struct imap_urlauth_fetch **_ufetch) { struct imap_urlauth_fetch *ufetch = *_ufetch; + i_assert(ufetch->refcount > 0); + *_ufetch = NULL; + if (--ufetch->refcount > 0) + return; imap_urlauth_fetch_abort(ufetch); @@ -120,6 +132,11 @@ void imap_urlauth_fetch_deinit(struct imap_urlauth_fetch **_ufetch) i_free(ufetch); } +void imap_urlauth_fetch_deinit(struct imap_urlauth_fetch **_ufetch) +{ + imap_urlauth_fetch_unref(_ufetch); +} + static void imap_urlauth_fetch_error(struct imap_urlauth_fetch *ufetch, const char *url, enum imap_urlauth_fetch_flags url_flags, @@ -232,6 +249,8 @@ imap_urlauth_fetch_local(struct imap_urlauth_fetch *ufetch, const char *url, } if (!success && ret < 0) { + if (mpurl != NULL) + imap_msgpart_url_free(&mpurl); ufetch->pending_requests--; (void)ufetch->callback(NULL, TRUE, ufetch->context); imap_urlauth_fetch_fail(ufetch); @@ -292,6 +311,8 @@ imap_urlauth_fetch_request_callback(struct imap_urlauth_fetch_reply *reply, ufetch->waiting_local = FALSE; ufetch->pending_requests--; + imap_urlauth_fetch_ref(ufetch); + if (!ufetch->failed) { bool last = ufetch->pending_requests == 0 || reply == NULL; ret = ufetch->callback(reply, last, ufetch->context); @@ -305,8 +326,8 @@ imap_urlauth_fetch_request_callback(struct imap_urlauth_fetch_reply *reply, } else if (ret == 0) { ufetch->waiting_service = TRUE; } - if (ret != 0) - imap_urlauth_fetch_deinit(&ufetch); + + imap_urlauth_fetch_unref(&ufetch); return ret; } @@ -319,6 +340,7 @@ int imap_urlauth_fetch_url(struct imap_urlauth_fetch *ufetch, const char *url, struct mail_user *mail_user = uctx->user; struct imap_url *imap_url; const char *error, *errormsg; + int ret = 0; /* parse the url */ if (imap_url_parse(url, NULL, url_parse_flags, &imap_url, &error) < 0) { @@ -327,13 +349,17 @@ int imap_urlauth_fetch_url(struct imap_urlauth_fetch *ufetch, const char *url, if (mail_user->mail_debug) i_debug("%s", errormsg); ufetch->pending_requests++; + imap_urlauth_fetch_ref(ufetch); imap_urlauth_fetch_error(ufetch, url, url_flags, errormsg); + imap_urlauth_fetch_unref(&ufetch); return 1; } ufetch->failed = FALSE; ufetch->pending_requests++; + imap_urlauth_fetch_ref(ufetch); + /* if access user and target user match, handle fetch request locally */ if (imap_url->userid != NULL && strcmp(mail_user->username, imap_url->userid) == 0) { @@ -364,17 +390,22 @@ int imap_urlauth_fetch_url(struct imap_urlauth_fetch *ufetch, const char *url, /* create request for url */ if (imap_url != NULL && imap_url->userid != NULL) { + i_assert(uctx->conn != NULL); (void)imap_urlauth_request_new(uctx->conn, imap_url->userid, url, url_flags, imap_urlauth_fetch_request_callback, ufetch); i_assert(uctx->conn != NULL); if (imap_urlauth_connection_connect(uctx->conn) < 0) - return -1; + ret = -1; } - return (ufetch->pending_requests > 0 ? 0 : 1); + if (ret >= 0) + ret = (ufetch->pending_requests > 0 ? 0 : 1); + + imap_urlauth_fetch_unref(&ufetch); + return ret; } -bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch) +static bool imap_urlauth_fetch_do_continue(struct imap_urlauth_fetch *ufetch) { struct imap_urlauth_fetch_url *url, *url_next; int ret; @@ -390,7 +421,7 @@ bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch) ufetch->waiting_service = FALSE; imap_urlauth_connection_continue(ufetch->uctx->conn); return ufetch->pending_requests > 0; - } + } /* finished local request */ if (ufetch->local_url != NULL) { @@ -457,3 +488,15 @@ bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch) return ufetch->pending_requests > 0; } + +bool imap_urlauth_fetch_continue(struct imap_urlauth_fetch *ufetch) +{ + bool pending; + + imap_urlauth_fetch_ref(ufetch); + pending = imap_urlauth_fetch_do_continue(ufetch); + imap_urlauth_fetch_unref(&ufetch); + + return pending; +} + diff --git a/src/lib-imap-urlauth/imap-urlauth-fetch.h b/src/lib-imap-urlauth/imap-urlauth-fetch.h index 3c5275c..55398af 100644 --- a/src/lib-imap-urlauth/imap-urlauth-fetch.h +++ b/src/lib-imap-urlauth/imap-urlauth-fetch.h @@ -33,8 +33,7 @@ struct imap_urlauth_fetch_reply { for next reply, 0 if not all data was processed, and -1 for error. If a callback returns 0, imap_urlauth_fetch_continue() must be called once new replies may be processed. If this is the last request to yield a reply, - argument last is TRUE. The callback must not call - imap_urlauth_fetch_deinit(). */ + argument last is TRUE. */ typedef int imap_urlauth_fetch_callback_t(struct imap_urlauth_fetch_reply *reply, bool last, void *context); @@ -42,7 +41,7 @@ imap_urlauth_fetch_callback_t(struct imap_urlauth_fetch_reply *reply, struct imap_urlauth_fetch * imap_urlauth_fetch_init(struct imap_urlauth_context *uctx, imap_urlauth_fetch_callback_t *callback, void *context); -void imap_urlauth_fetch_deinit(struct imap_urlauth_fetch **_ufetch); +void imap_urlauth_fetch_deinit(struct imap_urlauth_fetch **ufetch); int imap_urlauth_fetch_url(struct imap_urlauth_fetch *ufetch, const char *url, enum imap_urlauth_fetch_flags url_flags); -- 1.7.10.2 From 6547c94d39f42d25dc07f50d52f4e6cd8b57d91c Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Tue, 21 May 2013 22:57:06 +0300 Subject: [PATCH] *-login: If auth failed with a specified reason, the reason wasn't actually shown to client. diff --git a/src/login-common/client-common-auth.c b/src/login-common/client-common-auth.c index 356d1c4..485a7d3 100644 --- a/src/login-common/client-common-auth.c +++ b/src/login-common/client-common-auth.c @@ -538,7 +538,7 @@ sasl_callback(struct client *client, enum sasl_server_reply sasl_reply, } else { client_auth_result(client, CLIENT_AUTH_RESULT_AUTHFAILED_REASON, NULL, - AUTH_FAILED_MSG); + data); } if (!client->destroyed) -- 1.7.10.2 From e5c91a786027aef441b2d63ec25835bb3b664be7 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Wed, 22 May 2013 14:56:41 +0300 Subject: [PATCH] dsync: Don't notify replicator process about successful dsync if the dsync failed. diff --git a/src/doveadm/dsync/doveadm-dsync.c b/src/doveadm/dsync/doveadm-dsync.c index 1568302..73cfe60 100644 --- a/src/doveadm/dsync/doveadm-dsync.c +++ b/src/doveadm/dsync/doveadm-dsync.c @@ -949,7 +949,7 @@ cmd_dsync_server_run(struct doveadm_mail_cmd_context *_ctx, o_stream_close(_ctx->conn->output); } - if (ctx->replicator_notify) + if (ctx->replicator_notify && _ctx->exit_code == 0) dsync_replicator_notify(ctx, sync_type, str_c(state_str)); return _ctx->exit_code == 0 ? 0 : -1; } -- 1.7.10.2 From 711b2555ff0257b17f155d783ac3053e21b7ecd7 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Wed, 22 May 2013 15:16:22 +0300 Subject: [PATCH] dsync: Fixed unsubscribing from mailbox within same session as the mailbox's deletion. diff --git a/src/doveadm/dsync/dsync-brain-mailbox-tree.c b/src/doveadm/dsync/dsync-brain-mailbox-tree.c index 6354038..fb13444 100644 --- a/src/doveadm/dsync/dsync-brain-mailbox-tree.c +++ b/src/doveadm/dsync/dsync-brain-mailbox-tree.c @@ -395,8 +395,8 @@ dsync_brain_mailbox_tree_add_delete(struct dsync_mailbox_tree *tree, name = dsync_mailbox_node_get_full_name(tree, node); other_node = dsync_mailbox_tree_get(other_tree, name); - if (!guid_128_is_empty(other_node->mailbox_guid) || - (other_node->existence == DSYNC_MAILBOX_NODE_EXISTS && + if (other_node->existence == DSYNC_MAILBOX_NODE_EXISTS && + (!guid_128_is_empty(other_node->mailbox_guid) || other_del->type != DSYNC_MAILBOX_DELETE_TYPE_MAILBOX)) { /* other side has already created a new mailbox or directory with this name, we can't delete it */ -- 1.7.10.2 From 9eeaa264e047900b8f3ce836c95e2256cf35de76 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Wed, 22 May 2013 15:44:05 +0300 Subject: [PATCH] lib-storage: Optimize SEARCH_MODSEQ query if it's higher than HIGHESTMODSEQ. diff --git a/src/lib-storage/index/index-search.c b/src/lib-storage/index/index-search.c index 9278b6d..0f10a04 100644 --- a/src/lib-storage/index/index-search.c +++ b/src/lib-storage/index/index-search.c @@ -904,12 +904,13 @@ static void search_limit_lowwater(struct index_search_context *ctx, *first_seq = seq1; } -static bool search_limit_by_flags(struct index_search_context *ctx, - struct mail_search_arg *args, - uint32_t *seq1, uint32_t *seq2) +static bool search_limit_by_hdr(struct index_search_context *ctx, + struct mail_search_arg *args, + uint32_t *seq1, uint32_t *seq2) { const struct mail_index_header *hdr; enum mail_flags pvt_flags_mask; + uint64_t highest_modseq; hdr = mail_index_get_header(ctx->view); /* we can't trust that private view's header is fully up to date, @@ -918,12 +919,23 @@ static bool search_limit_by_flags(struct index_search_context *ctx, mailbox_get_private_flags_mask(ctx->box); for (; args != NULL; args = args->next) { - if (args->type != SEARCH_FLAGS) { - if (args->type == SEARCH_ALL) { - if (args->match_not) - return FALSE; + switch (args->type) { + case SEARCH_ALL: + if (args->match_not) { + /* NOT ALL - pointless noop query */ + return FALSE; } continue; + case SEARCH_MODSEQ: + /* MODSEQ higher than current HIGHESTMODSEQ? */ + highest_modseq = mail_index_modseq_get_highest(ctx->view); + if (args->value.modseq->modseq > highest_modseq) + return FALSE; + continue; + default: + continue; + case SEARCH_FLAGS: + break; } if ((args->value.flags & MAIL_SEEN) != 0 && (pvt_flags_mask & MAIL_SEEN) == 0) { @@ -995,8 +1007,10 @@ static void search_get_seqset(struct index_search_context *ctx, return; } - /* UNSEEN and DELETED in root search level may limit the range */ - if (!search_limit_by_flags(ctx, args, &ctx->seq1, &ctx->seq2)) { + /* See if this search query can never match based on data in index's + header. We'll scan only the root level args, which is usually + enough. */ + if (!search_limit_by_hdr(ctx, args, &ctx->seq1, &ctx->seq2)) { /* no matches */ ctx->seq1 = 1; ctx->seq2 = 0; -- 1.7.10.2 From fd553002dbc884a1c38fadde0c5aa2a62dc0cbf5 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Wed, 22 May 2013 15:57:13 +0300 Subject: [PATCH] *-login: ssl=required should imply disable_plaintext_auth=yes diff --git a/src/imap-login/client.c b/src/imap-login/client.c index 55f38fd..c5d7097 100644 --- a/src/imap-login/client.c +++ b/src/imap-login/client.c @@ -12,6 +12,7 @@ #include "imap-id.h" #include "imap-resp-code.h" #include "master-service.h" +#include "master-service-ssl-settings.h" #include "master-auth.h" #include "client.h" #include "client-authenticate.h" @@ -64,7 +65,8 @@ static const char *get_capability(struct client *client) if (client_is_tls_enabled(client) && !client->tls) str_append(cap_str, " STARTTLS"); - if (client->set->disable_plaintext_auth && !client->secured) + if (!client->secured & (client->set->disable_plaintext_auth || + strcmp(client->ssl_set->ssl, "required") == 0)) str_append(cap_str, " LOGINDISABLED"); client_authenticate_get_capabilities(client, cap_str); diff --git a/src/login-common/client-common-auth.c b/src/login-common/client-common-auth.c index 485a7d3..99c7f34 100644 --- a/src/login-common/client-common-auth.c +++ b/src/login-common/client-common-auth.c @@ -615,7 +615,8 @@ int client_auth_begin(struct client *client, const char *mech_name, bool client_check_plaintext_auth(struct client *client, bool pass_sent) { - if (client->secured || !client->set->disable_plaintext_auth) + if (client->secured || (!client->set->disable_plaintext_auth && + strcmp(client->ssl_set->ssl, "required") != 0)) return TRUE; if (client->set->auth_verbose) { -- 1.7.10.2 From 2918910f33939a19322897061ebfb4b0865aa801 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Wed, 22 May 2013 15:59:38 +0300 Subject: [PATCH] *-login: If ssl=required, don't list any SASL mechanisms before STARTTLS. diff --git a/src/login-common/sasl-server.c b/src/login-common/sasl-server.c index 78735a6..3fbc560 100644 --- a/src/login-common/sasl-server.c +++ b/src/login-common/sasl-server.c @@ -13,6 +13,7 @@ #include "auth-client.h" #include "ssl-proxy.h" #include "master-service.h" +#include "master-service-ssl-settings.h" #include "master-interface.h" #include "master-auth.h" #include "client-common.h" @@ -38,7 +39,8 @@ sasl_server_get_advertised_mechs(struct client *client, unsigned int *count_r) unsigned int i, j, count; mech = auth_client_get_available_mechs(auth_client, &count); - if (count == 0) { + if (count == 0 || (!client->secured && + strcmp(client->ssl_set->ssl, "required") == 0)) { *count_r = 0; return NULL; } -- 1.7.10.2 From 43eeeb4d96640c49ad342e050f7590aca7ad21d6 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Thu, 23 May 2013 17:36:54 +0300 Subject: [PATCH] lib-http: Added ssl_cert|key|key_password settings to be passed to ssl-iostream. These are used for sending client's SSL certificate. diff --git a/src/lib-http/http-client.c b/src/lib-http/http-client.c index b6846f0..f153b51 100644 --- a/src/lib-http/http-client.c +++ b/src/lib-http/http-client.c @@ -86,6 +86,9 @@ struct http_client *http_client_init(const struct http_client_settings *set) client->set.ssl_ca = p_strdup(pool, set->ssl_ca); client->set.ssl_crypto_device = p_strdup(pool, set->ssl_crypto_device); client->set.ssl_allow_invalid_cert = set->ssl_allow_invalid_cert; + client->set.ssl_cert = p_strdup(pool, set->ssl_cert); + client->set.ssl_key = p_strdup(pool, set->ssl_key); + client->set.ssl_key_password = p_strdup(pool, set->ssl_key_password); client->set.max_idle_time_msecs = set->max_idle_time_msecs; client->set.max_parallel_connections = (set->max_parallel_connections > 0 ? set->max_parallel_connections : 1); @@ -197,6 +200,9 @@ int http_client_init_ssl_ctx(struct http_client *client, const char **error_r) ssl_set.ca = client->set.ssl_ca; ssl_set.verify_remote_cert = TRUE; ssl_set.crypto_device = client->set.ssl_crypto_device; + ssl_set.cert = client->set.ssl_cert; + ssl_set.key = client->set.ssl_key; + ssl_set.key_password = client->set.ssl_key_password; ssl_set.verbose = client->set.debug; ssl_set.verbose_invalid_cert = client->set.debug; diff --git a/src/lib-http/http-client.h b/src/lib-http/http-client.h index 69cb448..9c8d131 100644 --- a/src/lib-http/http-client.h +++ b/src/lib-http/http-client.h @@ -36,6 +36,8 @@ struct http_client_settings { const char *ssl_ca_dir, *ssl_ca_file, *ssl_ca; const char *ssl_crypto_device; bool ssl_allow_invalid_cert; + /* user cert */ + const char *ssl_cert, *ssl_key, *ssl_key_password; const char *rawlog_dir; -- 1.7.10.2