Mercurial > dovecot > core-2.2
changeset 12860:3984231cd873
Merged changes from v2.0 tree.
line wrap: on
line diff
--- a/.hgsigs Thu Mar 10 18:44:20 2011 +0200 +++ b/.hgsigs Thu Mar 17 16:37:22 2011 +0200 @@ -23,3 +23,5 @@ d0d3aca1c9587887a32a890548ec7db76c3bbbe2 0 iEYEABECAAYFAkzYU0oACgkQyUhSUUBVismeNwCaAua5XzOT/BgfeOVrBpscYz4M/jYAnRAc11iVkEeXr32o4YVL37DCPOv/ 51e41fcc78560b1eb5e3e1d026151e2cbe007486 0 iEYEABECAAYFAkz5RxcACgkQyUhSUUBViskcyQCcDetyEXnLHc1nCSFQ5LdlxgoNDE4AoKS8ZtsrUFdeT3/dfnJT1K7b5ski 440fcf8cb33815e86e5cb9701965000230338ac8 0 iEYEABECAAYFAk0u33kACgkQyUhSUUBVislxBwCeNfszo3Ivr5182ugeAXheEX33qDgAni6UFG9soLT2P5p1wpL2p/Bq4ACG +755c63ff089f434d18801d1864e5ce98d60f5ca9 0 iEYEABECAAYFAk1xNpAACgkQyUhSUUBVisn4HgCggcSxHEZGjRlCJQubqYquZMrnYckAoIKy+zTG+JMEez2pAtZdKse3uCjQ +3355b4bbd4acf5eb004cacbaa3bcc873ad818b80 0 iEYEABECAAYFAk10DCoACgkQyUhSUUBVislFAwCfUyZb1gwaGuSweAs1eUwIpIAAWTkAn2M2MDMIjmZduTZgcmbQPlWScNGP
--- a/.hgtags Thu Mar 10 18:44:20 2011 +0200 +++ b/.hgtags Thu Mar 17 16:37:22 2011 +0200 @@ -60,3 +60,5 @@ d0d3aca1c9587887a32a890548ec7db76c3bbbe2 2.0.7 51e41fcc78560b1eb5e3e1d026151e2cbe007486 2.0.8 440fcf8cb33815e86e5cb9701965000230338ac8 2.0.9 +755c63ff089f434d18801d1864e5ce98d60f5ca9 2.0.10 +3355b4bbd4acf5eb004cacbaa3bcc873ad818b80 2.0.11
--- a/NEWS Thu Mar 10 18:44:20 2011 +0200 +++ b/NEWS Thu Mar 17 16:37:22 2011 +0200 @@ -14,6 +14,26 @@ (e.g. copy multiple messages). - dsync: Saved messages' save-date was set to 1970-01-01. + + Added submission_host setting to send mails via SMTP instead of + via sendmail binary. + + Added doveadm acl get/set/delete commands for ACL manipulation, + similar to how IMAP ACL extension works. + + Added doveadm acl debug command to help debug and fix problems + with why shared mailboxes aren't working as expected. + - IMAP: Fixed hangs with COMPRESS extension + - IMAP: Fixed a hang when trying to COPY to a nonexistent mailbox. + - IMAP: Fixed hang/crash with SEARCHRES + pipelining $. + - IMAP: Fixed assert-crash if IDLE+DONE is sent in same TCP packet. + - LMTP: Fixed sending multiple messages in a session. + - doveadm: Fixed giving parameters to mail commands. + - doveadm import: Settings weren't correctly used for the + import storage. + - dsync: Fixed somewhat random failures with saving messages to + remote dsync. + - v2.0.9: Config reload didn't notify running processes with + shutdown_clients=no, so they could have kept serving new clients + with old settings. + v2.0.9 2011-01-13 Timo Sirainen <tss@iki.fi> - Linux: Fixed a high system CPU usage / high context switch count
--- a/doc/example-config/conf.d/20-imap.conf Thu Mar 10 18:44:20 2011 +0200 +++ b/doc/example-config/conf.d/20-imap.conf Thu Mar 17 16:37:22 2011 +0200 @@ -48,6 +48,11 @@ # With mbox storage a mailbox can contain either mails or submailboxes, # but not both. Thunderbird separates these two by forcing server to # accept '/' suffix in mailbox names in subscriptions list. + # tb-lsub-flags: + # Show \Noselect flags for LSUB replies with LAYOUT=fs (e.g. mbox). + # This makes Thunderbird realize they aren't selectable and show them + # greyed out, instead of only later giving "not selectable" popup error. + # # The list is space-separated. #imap_client_workarounds = }
--- a/doc/example-config/dovecot.conf Thu Mar 10 18:44:20 2011 +0200 +++ b/doc/example-config/dovecot.conf Thu Mar 17 16:37:22 2011 +0200 @@ -57,6 +57,11 @@ # UNIX socket or host:port used for connecting to doveadm server #doveadm_socket_path = doveadm-server +# Space separated list of environment variables that are preserved on Dovecot +# startup and passed down to all of its child processes. You can also give +# key=value pairs to always set specific settings. +#import_environment = TZ + ## ## Dictionary server settings ##
--- a/src/auth/auth-penalty.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/auth/auth-penalty.c Thu Mar 17 16:37:22 2011 +0200 @@ -123,7 +123,7 @@ const char *ident; ident = auth_penalty_get_ident(auth_request); - if (penalty->disabled || ident == NULL) { + if (penalty->disabled || ident == NULL || auth_request->no_penalty) { callback(0, auth_request); return; } @@ -155,7 +155,7 @@ const char *ident; ident = auth_penalty_get_ident(auth_request); - if (penalty->disabled || ident == NULL) + if (penalty->disabled || ident == NULL || auth_request->no_penalty) return; if (value > AUTH_PENALTY_MAX_PENALTY) {
--- a/src/auth/auth-request.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/auth/auth-request.c Thu Mar 17 16:37:22 2011 +0200 @@ -197,6 +197,8 @@ auth_stream_reply_add(reply, "skip_password_check", "1"); if (request->valid_client_cert) auth_stream_reply_add(reply, "valid-client-cert", "1"); + if (request->no_penalty) + auth_stream_reply_add(reply, "no-penalty", "1"); if (request->mech_name != NULL) auth_stream_reply_add(reply, "mech", request->mech_name); } @@ -235,6 +237,8 @@ request->no_login = TRUE; else if (strcmp(key, "valid-client-cert") == 0) request->valid_client_cert = TRUE; + else if (strcmp(key, "no-penalty") == 0) + request->no_penalty = TRUE; else if (strcmp(key, "skip_password_check") == 0) { i_assert(request->master_user != NULL); request->skip_password_check = TRUE; @@ -1308,10 +1312,7 @@ if (*values == NULL) return; - if (strcmp(name, "uid") == 0) { - /* there can be only one. use the first one. */ - auth_request_set_userdb_field(request, name, *values); - } else if (strcmp(name, "gid") == 0) { + if (strcmp(name, "gid") == 0) { /* convert gids to comma separated list */ string_t *value; gid_t gid; @@ -1332,6 +1333,11 @@ str_c(value)); } else { /* add only one */ + if (values[1] != NULL) { + auth_request_log_warning(request, "userdb", + "Multiple values found for '%s', " + "using value '%s'", name, *values); + } auth_request_set_userdb_field(request, name, *values); } } @@ -1672,6 +1678,19 @@ va_end(va); } +void auth_request_log_warning(struct auth_request *auth_request, + const char *subsystem, + const char *format, ...) +{ + va_list va; + + va_start(va, format); + T_BEGIN { + i_warning("%s", get_log_str(auth_request, subsystem, format, va)); + } T_END; + va_end(va); +} + void auth_request_log_error(struct auth_request *auth_request, const char *subsystem, const char *format, ...)
--- a/src/auth/auth-request.h Thu Mar 10 18:44:20 2011 +0200 +++ b/src/auth/auth-request.h Thu Mar 17 16:37:22 2011 +0200 @@ -106,6 +106,7 @@ unsigned int proxy:1; unsigned int proxy_maybe:1; unsigned int valid_client_cert:1; + unsigned int no_penalty:1; unsigned int cert_username:1; unsigned int userdb_lookup:1; unsigned int userdb_lookup_failed:1; @@ -192,6 +193,9 @@ void auth_request_log_info(struct auth_request *auth_request, const char *subsystem, const char *format, ...) ATTR_FORMAT(3, 4); +void auth_request_log_warning(struct auth_request *auth_request, + const char *subsystem, + const char *format, ...); void auth_request_log_error(struct auth_request *auth_request, const char *subsystem, const char *format, ...) ATTR_FORMAT(3, 4);
--- a/src/auth/db-ldap.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/auth/db-ldap.c Thu Mar 17 16:37:22 2011 +0200 @@ -58,12 +58,11 @@ struct var_expand_table *var_table; char *attr, **vals; - const char *name, *value, *template, *val_1_arr[2]; + const char *name, *template, *val_1_arr[2]; const char *const *static_attrs; BerElement *ber; string_t *var, *debug; - unsigned int value_idx; }; struct db_ldap_sasl_bind_context { @@ -1111,6 +1110,8 @@ static void db_ldap_result_change_attr(struct db_ldap_result_iterate_context *ctx) { + i_assert(ctx->vals == NULL); + ctx->name = hash_table_lookup(ctx->attr_map, ctx->attr); ctx->template = NULL; @@ -1119,10 +1120,8 @@ ctx->name != NULL ? ctx->name : "?unknown?"); } - if (ctx->name == NULL || *ctx->name == '\0') { - ctx->value = NULL; + if (ctx->name == NULL || *ctx->name == '\0') return; - } if (strchr(ctx->name, '%') != NULL && (ctx->template = strchr(ctx->name, '=')) != NULL) { @@ -1138,31 +1137,35 @@ ctx->vals = ldap_get_values(ctx->conn->ld, ctx->entry, ctx->attr); - ctx->value = ctx->vals[0]; - ctx->value_idx = 0; } static void db_ldap_result_return_value(struct db_ldap_result_iterate_context *ctx) { - bool first = ctx->value_idx == 0; + unsigned int i; if (ctx->template != NULL) { - ctx->var_table[0].value = ctx->value; + if (ctx->vals[1] != NULL) { + auth_request_log_warning(ctx->auth_request, "ldap", + "Multiple values found for '%s', " + "using value '%s'", ctx->name, ctx->vals[0]); + } + ctx->var_table[0].value = ctx->vals[0]; str_truncate(ctx->var, 0); var_expand(ctx->var, ctx->template, ctx->var_table); - ctx->value = str_c(ctx->var); + ctx->val_1_arr[0] = str_c(ctx->var); } - if (ctx->debug != NULL) { - if (!first) - str_append_c(ctx->debug, '/'); - if (ctx->auth_request->set->debug_passwords || - (strcmp(ctx->name, "password") != 0 && - strcmp(ctx->name, "password_noscheme") != 0)) - str_append(ctx->debug, ctx->value); - else - str_append(ctx->debug, PASSWORD_HIDDEN_STR); + if (ctx->debug == NULL) { + /* no debugging */ + } else if (ctx->auth_request->set->debug_passwords || + (strcmp(ctx->name, "password") != 0 && + strcmp(ctx->name, "password_noscheme") != 0)) { + str_append(ctx->debug, ctx->vals[0]); + for (i = 1; ctx->vals[i] != NULL; i++) + str_printfa(ctx->debug, ", %s", ctx->vals[i]); + } else { + str_append(ctx->debug, PASSWORD_HIDDEN_STR); } } @@ -1172,17 +1175,11 @@ while (ctx->attr != NULL) { if (ctx->vals == NULL) { - /* a new attribute */ db_ldap_result_change_attr(ctx); - } else { - /* continuing existing attribute */ - if (ctx->value != NULL) - ctx->value = ctx->vals[++ctx->value_idx]; - } - - if (ctx->value != NULL) { - db_ldap_result_return_value(ctx); - return TRUE; + if (ctx->vals != NULL) { + db_ldap_result_return_value(ctx); + return TRUE; + } } ldap_value_free(ctx->vals); ctx->vals = NULL; @@ -1195,14 +1192,13 @@ p = strchr(*ctx->static_attrs, '='); if (p == NULL) { ctx->name = *ctx->static_attrs; - ctx->value = ""; + ctx->val_1_arr[0] = ""; } else { ctx->name = t_strdup_until(*ctx->static_attrs, p); - ctx->value = p + 1; + ctx->val_1_arr[0] = p + 1; } - /* make _next_all() return correct values */ + /* make _next() return correct values */ ctx->template = ""; - ctx->val_1_arr[0] = ctx->value; ctx->static_attrs++; return TRUE; } @@ -1212,31 +1208,18 @@ } bool db_ldap_result_iterate_next(struct db_ldap_result_iterate_context *ctx, - const char **name_r, const char **value_r) -{ - if (!db_ldap_result_int_next(ctx)) - return FALSE; - - *name_r = ctx->name; - *value_r = ctx->value; - return TRUE; -} - -bool db_ldap_result_iterate_next_all(struct db_ldap_result_iterate_context *ctx, - const char **name_r, - const char *const **values_r) + const char **name_r, + const char *const **values_r) { if (!db_ldap_result_int_next(ctx)) return FALSE; if (ctx->template != NULL) { /* we can use only one value with templates */ - ctx->val_1_arr[0] = ctx->value; *values_r = ctx->val_1_arr; } else { *values_r = (const char *const *)ctx->vals; } - ctx->value = NULL; *name_r = ctx->name; return TRUE; }
--- a/src/auth/db-ldap.h Thu Mar 10 18:44:20 2011 +0200 +++ b/src/auth/db-ldap.h Thu Mar 17 16:37:22 2011 +0200 @@ -178,9 +178,7 @@ struct auth_request *auth_request, struct hash_table *attr_map); bool db_ldap_result_iterate_next(struct db_ldap_result_iterate_context *ctx, - const char **name_r, const char **value_r); -bool db_ldap_result_iterate_next_all(struct db_ldap_result_iterate_context *ctx, - const char **name_r, - const char *const **values_r); + const char **name_r, + const char *const **values_r); #endif
--- a/src/auth/passdb-bsdauth.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/auth/passdb-bsdauth.c Thu Mar 17 16:37:22 2011 +0200 @@ -7,23 +7,28 @@ #include "safe-memset.h" #include "auth-cache.h" +#include "ipwd.h" #include "mycrypt.h" #include <login_cap.h> #include <bsd_auth.h> -#include <pwd.h> static void bsdauth_verify_plain(struct auth_request *request, const char *password, verify_plain_callback_t *callback) { - struct passwd *pw; + struct passwd pw; int result; auth_request_log_debug(request, "bsdauth", "lookup"); - pw = getpwnam(request->user); - if (pw == NULL) { + switch (i_getpwnam(request->user, &pw)) { + case -1: + auth_request_log_error(request, "bsdauth", + "getpwnam() failed: %m"); + callback(PASSDB_RESULT_INTERNAL_FAILURE, request); + return; + case 0: auth_request_log_info(request, "bsdauth", "unknown user"); callback(PASSDB_RESULT_USER_UNKNOWN, request); return; @@ -34,7 +39,7 @@ t_strdup_noconst(password)); /* clear the passwords from memory */ - safe_memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); + safe_memset(pw.pw_passwd, 0, strlen(pw.pw_passwd)); if (result == 0) { auth_request_log_password_mismatch(request, "bsdauth"); @@ -43,7 +48,7 @@ } /* make sure we're using the username exactly as it's in the database */ - auth_request_set_field(request, "user", pw->pw_name, NULL); + auth_request_set_field(request, "user", pw.pw_name, NULL); callback(PASSDB_RESULT_OK, request); }
--- a/src/auth/passdb-ldap.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/auth/passdb-ldap.c Thu Mar 17 16:37:22 2011 +0200 @@ -43,12 +43,17 @@ LDAPMessage *entry, struct auth_request *auth_request) { struct db_ldap_result_iterate_context *ldap_iter; - const char *name, *value; + const char *name, *const *values; ldap_iter = db_ldap_result_iterate_init(conn, entry, auth_request, conn->pass_attr_map); - while (db_ldap_result_iterate_next(ldap_iter, &name, &value)) { - auth_request_set_field(auth_request, name, value, + while (db_ldap_result_iterate_next(ldap_iter, &name, &values)) { + if (values[1] != NULL) { + auth_request_log_warning(auth_request, "ldap", + "Multiple values found for '%s', " + "using value '%s'", name, values[0]); + } + auth_request_set_field(auth_request, name, values[0], conn->set.default_pass_scheme); } }
--- a/src/auth/passdb-passwd.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/auth/passdb-passwd.c Thu Mar 17 16:37:22 2011 +0200 @@ -6,8 +6,7 @@ #ifdef PASSDB_PASSWD #include "safe-memset.h" - -#include <pwd.h> +#include "ipwd.h" #define PASSWD_CACHE_KEY "%u" #define PASSWD_PASS_SCHEME "CRYPT" @@ -16,35 +15,40 @@ passwd_verify_plain(struct auth_request *request, const char *password, verify_plain_callback_t *callback) { - struct passwd *pw; + struct passwd pw; int ret; auth_request_log_debug(request, "passwd", "lookup"); - pw = getpwnam(request->user); - if (pw == NULL) { + switch (i_getpwnam(request->user, &pw)) { + case -1: + auth_request_log_error(request, "passwd", + "getpwnam() failed: %m"); + callback(PASSDB_RESULT_INTERNAL_FAILURE, request); + return; + case 0: auth_request_log_info(request, "passwd", "unknown user"); callback(PASSDB_RESULT_USER_UNKNOWN, request); return; } - if (!IS_VALID_PASSWD(pw->pw_passwd)) { + if (!IS_VALID_PASSWD(pw.pw_passwd)) { auth_request_log_info(request, "passwd", - "invalid password field '%s'", pw->pw_passwd); + "invalid password field '%s'", pw.pw_passwd); callback(PASSDB_RESULT_USER_DISABLED, request); return; } /* save the password so cache can use it */ - auth_request_set_field(request, "password", pw->pw_passwd, + auth_request_set_field(request, "password", pw.pw_passwd, PASSWD_PASS_SCHEME); /* check if the password is valid */ - ret = auth_request_password_verify(request, password, pw->pw_passwd, + ret = auth_request_password_verify(request, password, pw.pw_passwd, PASSWD_PASS_SCHEME, "passwd"); /* clear the passwords from memory */ - safe_memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); + safe_memset(pw.pw_passwd, 0, strlen(pw.pw_passwd)); if (ret <= 0) { callback(PASSDB_RESULT_PASSWORD_MISMATCH, request); @@ -52,7 +56,7 @@ } /* make sure we're using the username exactly as it's in the database */ - auth_request_set_field(request, "user", pw->pw_name, NULL); + auth_request_set_field(request, "user", pw.pw_name, NULL); callback(PASSDB_RESULT_OK, request); }
--- a/src/auth/userdb-ldap.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/auth/userdb-ldap.c Thu Mar 17 16:37:22 2011 +0200 @@ -52,7 +52,7 @@ ldap_iter = db_ldap_result_iterate_init(conn, entry, auth_request, conn->user_attr_map); - while (db_ldap_result_iterate_next_all(ldap_iter, &name, &values)) { + while (db_ldap_result_iterate_next(ldap_iter, &name, &values)) { auth_request_set_userdb_field_values(auth_request, name, values); } @@ -168,7 +168,7 @@ ldap_iter = db_ldap_result_iterate_init(conn, res, request->auth_request, conn->iterate_attr_map); - while (db_ldap_result_iterate_next_all(ldap_iter, &name, &values)) { + while (db_ldap_result_iterate_next(ldap_iter, &name, &values)) { if (strcmp(name, "user") != 0) { i_warning("ldap: iterate: " "Ignoring field not named 'user': %s", name);
--- a/src/auth/userdb-passwd.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/auth/userdb-passwd.c Thu Mar 17 16:37:22 2011 +0200 @@ -6,10 +6,9 @@ #ifdef USERDB_PASSWD #include "ioloop.h" +#include "ipwd.h" #include "userdb-static.h" -#include <pwd.h> - #define USER_CACHE_KEY "%u" struct passwd_userdb_module { @@ -32,18 +31,23 @@ struct userdb_module *_module = auth_request->userdb->userdb; struct passwd_userdb_module *module = (struct passwd_userdb_module *)_module; - struct passwd *pw; + struct passwd pw; auth_request_log_debug(auth_request, "passwd", "lookup"); - pw = getpwnam(auth_request->user); - if (pw == NULL) { + switch (i_getpwnam(auth_request->user, &pw)) { + case -1: + auth_request_log_error(auth_request, "passwd", + "getpwnam() failed: %m"); + callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request); + return; + case 0: auth_request_log_info(auth_request, "passwd", "unknown user"); callback(USERDB_RESULT_USER_UNKNOWN, auth_request); return; } - auth_request_set_field(auth_request, "user", pw->pw_name, NULL); + auth_request_set_field(auth_request, "user", pw.pw_name, NULL); auth_request_init_userdb_reply(auth_request); userdb_static_template_export(module->tmpl, auth_request); @@ -53,18 +57,18 @@ !userdb_static_template_isset(module->tmpl, "system_user")) { auth_request_set_userdb_field(auth_request, "system_groups_user", - pw->pw_name); + pw.pw_name); } if (!userdb_static_template_isset(module->tmpl, "uid")) { auth_request_set_userdb_field(auth_request, - "uid", dec2str(pw->pw_uid)); + "uid", dec2str(pw.pw_uid)); } if (!userdb_static_template_isset(module->tmpl, "gid")) { auth_request_set_userdb_field(auth_request, - "gid", dec2str(pw->pw_gid)); + "gid", dec2str(pw.pw_gid)); } if (!userdb_static_template_isset(module->tmpl, "home")) - auth_request_set_userdb_field(auth_request, "home", pw->pw_dir); + auth_request_set_userdb_field(auth_request, "home", pw.pw_dir); callback(USERDB_RESULT_OK, auth_request); }
--- a/src/auth/userdb.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/auth/userdb.c Thu Mar 17 16:37:22 2011 +0200 @@ -2,12 +2,11 @@ #include "auth-common.h" #include "array.h" +#include "ipwd.h" #include "auth-worker-server.h" #include "userdb.h" #include <stdlib.h> -#include <pwd.h> -#include <grp.h> static ARRAY_DEFINE(userdb_interfaces, struct userdb_module_interface *); static ARRAY_DEFINE(userdb_modules, struct userdb_module *); @@ -61,7 +60,7 @@ uid_t userdb_parse_uid(struct auth_request *request, const char *str) { - struct passwd *pw; + struct passwd pw; uid_t uid; if (str == NULL) @@ -70,20 +69,24 @@ if (str_to_uid(str, &uid) == 0) return uid; - pw = getpwnam(str); - if (pw == NULL) { + switch (i_getpwnam(str, &pw)) { + case -1: + i_error("getpwnam() failed: %m"); + return (uid_t)-1; + case 0: if (request != NULL) { auth_request_log_error(request, "userdb", "Invalid UID value '%s'", str); } return (uid_t)-1; + default: + return pw.pw_uid; } - return pw->pw_uid; } gid_t userdb_parse_gid(struct auth_request *request, const char *str) { - struct group *gr; + struct group gr; gid_t gid; if (str == NULL) @@ -92,15 +95,19 @@ if (str_to_gid(str, &gid) == 0) return gid; - gr = getgrnam(str); - if (gr == NULL) { + switch (i_getgrnam(str, &gr)) { + case -1: + i_error("getgrnam() failed: %m"); + return (gid_t)-1; + case 0: if (request != NULL) { auth_request_log_error(request, "userdb", "Invalid GID value '%s'", str); } return (gid_t)-1; + default: + return gr.gr_gid; } - return gr->gr_gid; } static struct userdb_module *
--- a/src/config/old-set-parser.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/config/old-set-parser.c Thu Mar 17 16:37:22 2011 +0200 @@ -357,7 +357,8 @@ return TRUE; } if (strcmp(key, "login_process_size") == 0) { - config_apply_login_set(ctx, old_section, key, "vsz_limit", value); + config_apply_login_set(ctx, old_section, key, "vsz_limit", + t_strconcat(value, " M", NULL)); return TRUE; } if (strcmp(key, "login_process_per_connection") == 0) { @@ -378,7 +379,8 @@ return TRUE; } if (strcmp(key, "login_process_size") == 0) { - config_apply_login_set(ctx, old_section, key, "vsz_limit", value); + config_apply_login_set(ctx, old_section, key, "vsz_limit", + t_strconcat(value, " M", NULL)); return TRUE; } @@ -391,7 +393,8 @@ return TRUE; } if (strcmp(key, "mail_process_size") == 0) { - config_apply_mail_set(ctx, old_section, key, "vsz_limit", value); + config_apply_mail_set(ctx, old_section, key, "vsz_limit", + t_strconcat(value, " M", NULL)); return TRUE; } if (strcmp(key, "mail_drop_priv_before_exec") == 0) { @@ -409,7 +412,8 @@ return TRUE; } if (strcmp(key, "auth_process_size") == 0) { - config_apply_auth_set(ctx, key, "vsz_limit", value); + config_apply_auth_set(ctx, key, "vsz_limit", + t_strconcat(value, " M", NULL)); return TRUE; } if (strcmp(key, "auth_user") == 0) {
--- a/src/doveadm/doveadm-mail-import.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/doveadm/doveadm-mail-import.c Thu Mar 17 16:37:22 2011 +0200 @@ -187,13 +187,13 @@ static struct doveadm_mail_cmd_context *cmd_import_alloc(void) { - struct doveadm_mail_cmd_context *ctx; + struct import_cmd_context *ctx; - ctx = doveadm_mail_cmd_alloc(struct doveadm_mail_cmd_context); - ctx->v.init = cmd_import_init; - ctx->v.deinit = cmd_import_deinit; - ctx->v.run = cmd_import_run; - return ctx; + ctx = doveadm_mail_cmd_alloc(struct import_cmd_context); + ctx->ctx.v.init = cmd_import_init; + ctx->ctx.v.deinit = cmd_import_deinit; + ctx->ctx.v.run = cmd_import_run; + return &ctx->ctx; } struct doveadm_mail_cmd cmd_import = {
--- a/src/doveadm/doveadm-mail.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/doveadm/doveadm-mail.c Thu Mar 17 16:37:22 2011 +0200 @@ -248,7 +248,6 @@ i_fatal("%s", error); else if (ret == 0) i_fatal("User doesn't exist"); - mail_storage_service_deinit(&ctx->storage_service); } static void sig_die(const siginfo_t *si, void *context ATTR_UNUSED) @@ -319,7 +318,6 @@ i_set_failure_prefix("doveadm: "); if (ret < 0) i_error("Failed to iterate through some users"); - mail_storage_service_deinit(&ctx->storage_service); } static void @@ -420,12 +418,18 @@ service_flags |= MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP; doveadm_mail_all_users(ctx, argv, wildcard_user, service_flags); } + if (ctx->search_args != NULL) + mail_search_args_unref(&ctx->search_args); doveadm_mail_server_flush(); ctx->v.deinit(ctx); doveadm_print_flush(); + /* service deinit unloads mail plugins, so do it late */ + mail_storage_service_deinit(&ctx->storage_service); + if (ctx->failed) exit(FATAL_DEFAULT); + pool_unref(&ctx->pool); } static bool
--- a/src/dsync/dsync-brain.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/dsync/dsync-brain.c Thu Mar 17 16:37:22 2011 +0200 @@ -290,6 +290,7 @@ case DSYNC_BRAIN_MAILBOX_ACTION_CREATE: new_box = *action_box; new_box.uid_next = action_box->uid_validity == 0 ? 0 : 1; + new_box.first_recent_uid = 0; new_box.highest_modseq = 0; dsync_worker_create_mailbox(action_worker, &new_box); break; @@ -667,8 +668,9 @@ brain_box->box = *src_boxes[src]; brain_box->src = src_boxes[src]; if (brain->verbose) { - i_info("%s: only in source", - brain_box->box.name); + i_info("%s: only in source (guid=%s)", + brain_box->box.name, + dsync_guid_to_str(&brain_box->box.mailbox_guid)); } } src++; @@ -679,8 +681,9 @@ brain_box->box = *dest_boxes[dest]; brain_box->dest = dest_boxes[dest]; if (brain->verbose) { - i_info("%s: only in dest", - brain_box->box.name); + i_info("%s: only in dest (guid=%s)", + brain_box->box.name, + dsync_guid_to_str(&brain_box->box.mailbox_guid)); } } dest++; @@ -694,8 +697,11 @@ brain_box = array_append_space(brain_boxes); brain_box->box = *src_boxes[src]; brain_box->src = src_boxes[src]; - if (brain->verbose) - i_info("%s: only in source", brain_box->box.name); + if (brain->verbose) { + i_info("%s: only in source (guid=%s)", + brain_box->box.name, + dsync_guid_to_str(&brain_box->box.mailbox_guid)); + } } for (; dest < dest_count; dest++) { if ((dest_boxes[dest]->flags & @@ -705,8 +711,11 @@ brain_box = array_append_space(brain_boxes); brain_box->box = *dest_boxes[dest]; brain_box->dest = dest_boxes[dest]; - if (brain->verbose) - i_info("%s: only in dest", brain_box->box.name); + if (brain->verbose) { + i_info("%s: only in dest (guid=%s)", + brain_box->box.name, + dsync_guid_to_str(&brain_box->box.mailbox_guid)); + } } }
--- a/src/dsync/dsync-data.h Thu Mar 10 18:44:20 2011 +0200 +++ b/src/dsync/dsync-data.h Thu Mar 17 16:37:22 2011 +0200 @@ -22,7 +22,7 @@ /* Mailbox's GUID. Full of zero with \Noselect mailboxes. */ mailbox_guid_t mailbox_guid; - uint32_t uid_validity, uid_next, message_count; + uint32_t uid_validity, uid_next, message_count, first_recent_uid; uint64_t highest_modseq; /* if mailbox is deleted, this is the deletion timestamp. otherwise it's the last rename timestamp. */
--- a/src/dsync/dsync-proxy-client.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/dsync/dsync-proxy-client.c Thu Mar 17 16:37:22 2011 +0200 @@ -364,8 +364,10 @@ /* proxy_client_worker_msg_save() hasn't finished yet. */ o_stream_cork(worker->output); proxy_client_send_stream(worker); - if (worker->save_input != NULL) - return 1; + if (worker->save_input != NULL) { + /* still unfinished, make sure we get called again */ + return 0; + } } if (worker->worker.output_callback != NULL) @@ -385,7 +387,21 @@ static void proxy_client_worker_timeout(struct proxy_client_dsync_worker *worker) { - i_error("proxy client timed out"); + const char *reason; + + if (worker->save_io != NULL) + reason = " (waiting for more input from mail being saved)"; + else if (worker->save_input != NULL) { + size_t bytes = o_stream_get_buffer_used_size(worker->output); + + reason = t_strdup_printf(" (waiting for output stream to flush, " + "%"PRIuSIZE_T" bytes left)", bytes); + } else if (worker->msg_get_data.input != NULL) { + reason = " (waiting for MSG-GET message from remote)"; + } else { + reason = ""; + } + i_error("proxy client timed out%s", reason); proxy_client_fail(worker); } @@ -397,7 +413,7 @@ worker->worker.v = proxy_client_dsync_worker; worker->fd_in = fd_in; worker->fd_out = fd_out; - worker->to = timeout_add(DSYNC_PROXY_TIMEOUT_MSECS, + worker->to = timeout_add(DSYNC_PROXY_CLIENT_TIMEOUT_MSECS, proxy_client_worker_timeout, worker); worker->io = io_add(fd_in, IO_READ, proxy_client_worker_input, worker); worker->input = i_stream_create_fd(fd_in, (size_t)-1, FALSE); @@ -455,7 +471,7 @@ struct proxy_client_dsync_worker *worker = (struct proxy_client_dsync_worker *)_worker; - if (worker->save_io != NULL) { + if (worker->save_input != NULL) { /* we haven't finished sending a message save, so we're full. */ return TRUE; }
--- a/src/dsync/dsync-proxy-server.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/dsync/dsync-proxy-server.c Thu Mar 17 16:37:22 2011 +0200 @@ -108,7 +108,6 @@ return; } - timeout_reset(server->to); o_stream_cork(server->output); while (proxy_server_read_line(server, &line) > 0) { T_BEGIN { @@ -123,6 +122,7 @@ if (ret < 0) master_service_stop(master_service); + timeout_reset(server->to); } static int proxy_server_output(struct dsync_proxy_server *server) @@ -130,7 +130,6 @@ struct ostream *output = server->output; int ret; - timeout_reset(server->to); if ((ret = o_stream_flush(output)) < 0) ret = 1; else if (server->cur_cmd != NULL) { @@ -149,6 +148,7 @@ } if (output->closed) master_service_stop(master_service); + timeout_reset(server->to); return ret; } @@ -172,7 +172,7 @@ server->io = io_add(fd_in, IO_READ, proxy_server_input, server); server->input = i_stream_create_fd(fd_in, (size_t)-1, FALSE); server->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE); - server->to = timeout_add(DSYNC_PROXY_TIMEOUT_MSECS, + server->to = timeout_add(DSYNC_PROXY_SERVER_TIMEOUT_MSECS, dsync_proxy_server_timeout, NULL); o_stream_set_flush_callback(server->output, proxy_server_output, server);
--- a/src/dsync/dsync-proxy.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/dsync/dsync-proxy.c Thu Mar 17 16:37:22 2011 +0200 @@ -174,9 +174,10 @@ str_append_c(str, '\t'); dsync_proxy_mailbox_guid_export(str, &box->mailbox_guid); - str_printfa(str, "\t%u\t%u\t%u\t%llu", + str_printfa(str, "\t%u\t%u\t%u\t%llu\t%u", box->uid_validity, box->uid_next, box->message_count, - (unsigned long long)box->highest_modseq); + (unsigned long long)box->highest_modseq, + box->first_recent_uid); dsync_proxy_strings_export(str, &box->cache_fields); } @@ -261,6 +262,12 @@ return -1; } + box_r->first_recent_uid = strtoul(args[i++], &p, 10); + if (*p != '\0') { + *error_r = "Invalid mailbox first_recent_uid"; + return -1; + } + args += i; count -= i; p_array_init(&box_r->cache_fields, pool, count + 1);
--- a/src/dsync/dsync-proxy.h Thu Mar 10 18:44:20 2011 +0200 +++ b/src/dsync/dsync-proxy.h Thu Mar 17 16:37:22 2011 +0200 @@ -3,7 +3,9 @@ #include "dsync-data.h" -#define DSYNC_PROXY_TIMEOUT_MSECS (15*60*1000) +#define DSYNC_PROXY_CLIENT_TIMEOUT_MSECS (14*60*1000) +#define DSYNC_PROXY_SERVER_TIMEOUT_MSECS (15*60*1000) + #define DSYNC_PROXY_CLIENT_GREETING_LINE "dsync-client\t1" #define DSYNC_PROXY_SERVER_GREETING_LINE "dsync-server\t1"
--- a/src/dsync/dsync-worker-local.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/dsync/dsync-worker-local.c Thu Mar 17 16:37:22 2011 +0200 @@ -514,7 +514,7 @@ MAILBOX_FLAG_READONLY | MAILBOX_FLAG_KEEP_RECENT; const enum mailbox_status_items status_items = STATUS_UIDNEXT | STATUS_UIDVALIDITY | - STATUS_HIGHESTMODSEQ; + STATUS_HIGHESTMODSEQ | STATUS_FIRST_RECENT_UID; const enum mailbox_metadata_items metadata_items = MAILBOX_METADATA_CACHE_FIELDS | MAILBOX_METADATA_GUID; const struct mailbox_info *info; @@ -579,6 +579,7 @@ dsync_box_r->uid_validity = status.uidvalidity; dsync_box_r->uid_next = status.uidnext; dsync_box_r->message_count = status.messages; + dsync_box_r->first_recent_uid = status.first_recent_uid; dsync_box_r->highest_modseq = status.highest_modseq; p_clear(iter->ret_pool); @@ -994,6 +995,7 @@ sizeof(update_r->mailbox_guid)); update_r->uid_validity = dsync_box->uid_validity; update_r->min_next_uid = dsync_box->uid_next; + update_r->min_first_recent_uid = dsync_box->first_recent_uid; update_r->min_highest_modseq = dsync_box->highest_modseq; }
--- a/src/dsync/test-dsync-brain.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/dsync/test-dsync-brain.c Thu Mar 17 16:37:22 2011 +0200 @@ -111,28 +111,28 @@ static void test_dsync_brain(void) { static struct dsync_mailbox src_boxes[] = { - { "box1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box2", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box3", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box4", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box5", '/', { { 0, } }, { { 0, } }, 1234567890, 5433, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box6", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123124ULL, 3636, 0, ARRAY_INIT }, - { "boxx", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "boxd1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "boxd2", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, DSYNC_MAILBOX_FLAG_DELETED_MAILBOX, ARRAY_INIT }, - { NULL, 0, { { 0, } }, { { 0, } }, 0, 0, 0, 0, 0, 0, ARRAY_INIT } + { "box1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box2", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box3", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box4", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box5", '/', { { 0, } }, { { 0, } }, 1234567890, 5433, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box6", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123124ULL, 3636, 0, ARRAY_INIT }, + { "boxx", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "boxd1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "boxd2", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, DSYNC_MAILBOX_FLAG_DELETED_MAILBOX, ARRAY_INIT }, + { NULL, 0, { { 0, } }, { { 0, } }, 0, 0, 0, 0, 0, 0, 0, ARRAY_INIT } }; static struct dsync_mailbox dest_boxes[] = { - { "box1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box2", '/', { { 0, } }, { { 0, } }, 1234567891, 5432, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box3", '/', { { 0, } }, { { 0, } }, 1234567890, 5433, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box4", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123124ULL, 3636, 0, ARRAY_INIT }, - { "box5", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "box6", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "boxy", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { "boxd1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, DSYNC_MAILBOX_FLAG_DELETED_MAILBOX, ARRAY_INIT }, - { "boxd2", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 3636, 0, ARRAY_INIT }, - { NULL, 0, { { 0, } }, { { 0, } }, 0, 0, 0, 0, 0, 0, ARRAY_INIT } + { "box1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box2", '/', { { 0, } }, { { 0, } }, 1234567891, 5432, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box3", '/', { { 0, } }, { { 0, } }, 1234567890, 5433, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box4", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123124ULL, 3636, 0, ARRAY_INIT }, + { "box5", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "box6", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "boxy", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { "boxd1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, DSYNC_MAILBOX_FLAG_DELETED_MAILBOX, ARRAY_INIT }, + { "boxd2", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 3636, 0, ARRAY_INIT }, + { NULL, 0, { { 0, } }, { { 0, } }, 0, 0, 0, 0, 0, 0, 0, ARRAY_INIT } }; struct dsync_brain *brain; struct dsync_worker *src_worker, *dest_worker; @@ -225,8 +225,8 @@ static void test_dsync_brain_full(void) { static struct dsync_mailbox boxes[] = { - { "box1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 123123123123ULL, 2352, 0, ARRAY_INIT }, - { NULL, 0, { { 0, } }, { { 0, } }, 0, 0, 0, 0, 0, 0, ARRAY_INIT } + { "box1", '/', { { 0, } }, { { 0, } }, 1234567890, 5432, 0, 1, 123123123123ULL, 2352, 0, ARRAY_INIT }, + { NULL, 0, { { 0, } }, { { 0, } }, 0, 0, 0, 0, 0, 0, 0, ARRAY_INIT } }; struct dsync_brain *brain; struct dsync_worker *src_worker, *dest_worker;
--- a/src/dsync/test-dsync-proxy-server-cmd.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/dsync/test-dsync-proxy-server-cmd.c Thu Mar 17 16:37:22 2011 +0200 @@ -92,6 +92,7 @@ box.uid_next = 4023233417; box.message_count = 4525; box.highest_modseq = 18080787909545915012ULL; + box.first_recent_uid = 353; test_worker->box_iter.next_box = &box; test_assert(run_more() == 0); @@ -101,7 +102,8 @@ "4275878552\t" "4023233417\t" "4525\t" - "18080787909545915012\n") == 0); + "18080787909545915012\t" + "353\n") == 0); out_clear(); /* last mailbox */ @@ -231,7 +233,7 @@ test_assert(run_cmd("BOX-CREATE", "selectable", "?", "61", "2", TEST_MAILBOX_GUID2, "1234567890", "9876", - "4610", "28427847284728", NULL) == 1); + "4610", "28427847284728", "853", NULL) == 1); test_assert(test_dsync_worker_next_box_event(test_worker, &event)); test_assert(event.type == LAST_BOX_TYPE_CREATE); test_assert(strcmp(event.box.name, "selectable") == 0); @@ -242,6 +244,7 @@ test_assert(event.box.uid_next == 9876); test_assert(event.box.message_count == 4610); test_assert(event.box.highest_modseq == 28427847284728); + test_assert(event.box.first_recent_uid == 853); test_assert(event.box.last_change == 61); test_end(); @@ -299,7 +302,7 @@ test_assert(run_cmd("BOX-UPDATE", "updated", "/", "53", "2", TEST_MAILBOX_GUID1, "34343", "22", - "58293", "2238427847284728", NULL) == 1); + "58293", "2238427847284728", "2482", NULL) == 1); test_assert(test_dsync_worker_next_box_event(test_worker, &event)); test_assert(event.type == LAST_BOX_TYPE_UPDATE); test_assert(strcmp(event.box.name, "updated") == 0); @@ -310,6 +313,7 @@ test_assert(event.box.uid_next == 22); test_assert(event.box.message_count == 58293); test_assert(event.box.highest_modseq == 2238427847284728); + test_assert(event.box.first_recent_uid == 2482); test_assert(event.box.last_change == 53); test_end();
--- a/src/imap-login/client.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/imap-login/client.c Thu Mar 17 16:37:22 2011 +0200 @@ -94,7 +94,8 @@ imap_client->client_ignores_capability_resp_code = TRUE; client_send_raw(client, t_strconcat( "* CAPABILITY ", get_capability(client), "\r\n", NULL)); - client_send_line(client, CLIENT_CMD_REPLY_OK, "Capability completed."); + client_send_line(client, CLIENT_CMD_REPLY_OK, + "Pre-login capabilities listed, post-login capabilities have more."); return 1; }
--- a/src/imap/cmd-list.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/imap/cmd-list.c Thu Mar 17 16:37:22 2011 +0200 @@ -946,10 +946,13 @@ } if (lsub) { - /* LSUB - we don't care about flags */ + /* LSUB - we don't care about flags except if + tb-lsub-flags workaround is explicitly set */ ctx->list_flags |= MAILBOX_LIST_ITER_SELECT_SUBSCRIBED | - MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH | - MAILBOX_LIST_ITER_RETURN_NO_FLAGS; + MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH; + if ((cmd->client->set->parsed_workarounds & + WORKAROUND_TB_LSUB_FLAGS) == 0) + ctx->list_flags |= MAILBOX_LIST_ITER_RETURN_NO_FLAGS; } else if (!ctx->used_listext) { /* non-extended LIST - return children flags always */ ctx->list_flags |= MAILBOX_LIST_ITER_RETURN_CHILDREN;
--- a/src/imap/imap-settings.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/imap/imap-settings.c Thu Mar 17 16:37:22 2011 +0200 @@ -116,6 +116,7 @@ static const struct imap_client_workaround_list imap_client_workaround_list[] = { { "delay-newmail", WORKAROUND_DELAY_NEWMAIL }, { "tb-extra-mailbox-sep", WORKAROUND_TB_EXTRA_MAILBOX_SEP }, + { "tb-lsub-flags", WORKAROUND_TB_LSUB_FLAGS }, { NULL, 0 } };
--- a/src/imap/imap-settings.h Thu Mar 10 18:44:20 2011 +0200 +++ b/src/imap/imap-settings.h Thu Mar 17 16:37:22 2011 +0200 @@ -6,7 +6,8 @@ /* <settings checks> */ enum imap_client_workarounds { WORKAROUND_DELAY_NEWMAIL = 0x01, - WORKAROUND_TB_EXTRA_MAILBOX_SEP = 0x08 + WORKAROUND_TB_EXTRA_MAILBOX_SEP = 0x08, + WORKAROUND_TB_LSUB_FLAGS = 0x10 }; /* </settings checks> */
--- a/src/lda/main.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lda/main.c Thu Mar 17 16:37:22 2011 +0200 @@ -10,6 +10,7 @@ #include "abspath.h" #include "safe-mkstemp.h" #include "eacces-error.h" +#include "ipwd.h" #include "mkdir-parents.h" #include "str.h" #include "str-sanitize.h" @@ -30,7 +31,6 @@ #include <stdio.h> #include <stdlib.h> -#include <pwd.h> #include <sysexits.h> #define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON" @@ -314,18 +314,21 @@ ; else if (process_euid != 0) { /* we're non-root. get our username and possibly our home. */ - struct passwd *pw; + struct passwd pw; const char *home; home = getenv("HOME"); if (user != NULL && home != NULL) { /* no need for a pw lookup */ user_source = "USER environment"; - } else if ((pw = getpwuid(process_euid)) != NULL) { - user = t_strdup(pw->pw_name); + } else if ((ret = i_getpwuid(process_euid, &pw)) > 0) { + user = t_strdup(pw.pw_name); if (home == NULL) - env_put(t_strconcat("HOME=", pw->pw_dir, NULL)); + env_put(t_strconcat("HOME=", pw.pw_dir, NULL)); user_source = "passwd lookup for process euid"; + } else if (ret < 0) { + /* temporary failure */ + i_fatal("getpwuid() failed: %m"); } else if (user == NULL) { i_fatal_status(EX_USAGE, "Couldn't lookup our username (uid=%s)",
--- a/src/lib-auth/auth-client-request.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-auth/auth-client-request.c Thu Mar 17 16:37:22 2011 +0200 @@ -36,6 +36,8 @@ if ((info->flags & AUTH_REQUEST_FLAG_SECURED) != 0) str_append(str, "\tsecured"); + if ((info->flags & AUTH_REQUEST_FLAG_NO_PENALTY) != 0) + str_append(str, "\tno-penalty"); if ((info->flags & AUTH_REQUEST_FLAG_VALID_CLIENT_CERT) != 0) str_append(str, "\tvalid-client-cert");
--- a/src/lib-auth/auth-client.h Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-auth/auth-client.h Thu Mar 17 16:37:22 2011 +0200 @@ -9,7 +9,9 @@ enum auth_request_flags { AUTH_REQUEST_FLAG_SECURED = 0x01, - AUTH_REQUEST_FLAG_VALID_CLIENT_CERT = 0x02 + AUTH_REQUEST_FLAG_VALID_CLIENT_CERT = 0x02, + /* Skip penalty checks for this request */ + AUTH_REQUEST_FLAG_NO_PENALTY = 0x04 }; enum auth_request_status {
--- a/src/lib-auth/auth-master.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-auth/auth-master.c Thu Mar 17 16:37:22 2011 +0200 @@ -372,6 +372,7 @@ if (conn->output->stream_errno != 0) { errno = conn->output->stream_errno; i_error("write(auth socket) failed: %m"); + conn->aborted = TRUE; } else { io_loop_run(conn->ioloop); }
--- a/src/lib-charset/charset-iconv.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-charset/charset-iconv.c Thu Mar 17 16:37:22 2011 +0200 @@ -104,10 +104,7 @@ else { /* should be EILSEQ */ *result = CHARSET_RET_INVALID_INPUT; - if (!dtcase) - buffer_set_used_size(dest, dest->used - destleft); - uni_ucs4_to_utf8_c(UNICODE_REPLACEMENT_CHAR, dest); - return TRUE; + ret = FALSE; } *src_size -= srcleft; @@ -132,6 +129,7 @@ bool dtcase = (t->flags & CHARSET_FLAG_DECOMP_TITLECASE) != 0; enum charset_result result; size_t pos, used, size, prev_pos = 0, prev_used = 0; + size_t prev_invalid_pos = (size_t)-1; bool ret; for (pos = 0;;) { @@ -139,12 +137,17 @@ ret = charset_to_utf8_try(t, src + pos, &size, dest, &result); pos += size; - if (ret) { - *src_size = pos; - return result; - } + if (ret) + break; - if (!dtcase) { + if (result == CHARSET_RET_INVALID_INPUT) { + if (prev_invalid_pos != dest->used) { + uni_ucs4_to_utf8_c(UNICODE_REPLACEMENT_CHAR, + dest); + prev_invalid_pos = dest->used; + } + pos++; + } else if (!dtcase) { /* force buffer to grow */ used = dest->used; size = buffer_get_size(dest) - used + 1; @@ -156,6 +159,12 @@ prev_used = dest->used; } } + + if (prev_invalid_pos != (size_t)-1) + result = CHARSET_RET_INVALID_INPUT; + + *src_size = pos; + return result; } #endif
--- a/src/lib-imap/imap-id.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-imap/imap-id.c Thu Mar 17 16:37:22 2011 +0200 @@ -164,6 +164,7 @@ str_append_c(reply, '='); str_append(reply, str_sanitize(value, 80)); } + args++; } return str_len(reply) == 0 ? NULL : str_c(reply); }
--- a/src/lib-master/anvil-client.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-master/anvil-client.c Thu Mar 17 16:37:22 2011 +0200 @@ -21,6 +21,9 @@ struct ostream *output; struct io *io; + struct timeout *to_reconnect; + time_t last_reconnect; + ARRAY_DEFINE(queries_arr, struct anvil_query); struct aqueue *queries; @@ -30,6 +33,7 @@ #define ANVIL_HANDSHAKE "VERSION\tanvil\t1\t0\n" #define ANVIL_INBUF_SIZE 1024 +#define ANVIL_RECONNECT_MIN_SECS 5 static void anvil_client_disconnect(struct anvil_client *client); @@ -59,6 +63,7 @@ array_free(&client->queries_arr); aqueue_deinit(&client->queries); i_free(client->path); + i_assert(client->to_reconnect == NULL); i_free(client); } @@ -71,7 +76,17 @@ return; } } - (void)anvil_client_connect(client, FALSE); + + if (ioloop_time - client->last_reconnect < ANVIL_RECONNECT_MIN_SECS) { + if (client->to_reconnect == NULL) { + client->to_reconnect = + timeout_add(ANVIL_RECONNECT_MIN_SECS, + anvil_reconnect, client); + } + } else { + client->last_reconnect = ioloop_time; + (void)anvil_client_connect(client, FALSE); + } } static void anvil_input(struct anvil_client *client) @@ -119,6 +134,9 @@ return -1; } + if (client->to_reconnect != NULL) + timeout_remove(&client->to_reconnect); + client->fd = fd; client->input = i_stream_create_fd(fd, ANVIL_INBUF_SIZE, FALSE); client->output = o_stream_create_fd(fd, (size_t)-1, FALSE); @@ -142,15 +160,16 @@ static void anvil_client_disconnect(struct anvil_client *client) { - if (client->fd == -1) - return; - - anvil_client_cancel_queries(client); - io_remove(&client->io); - i_stream_destroy(&client->input); - o_stream_destroy(&client->output); - net_disconnect(client->fd); - client->fd = -1; + if (client->fd != -1) { + anvil_client_cancel_queries(client); + io_remove(&client->io); + i_stream_destroy(&client->input); + o_stream_destroy(&client->output); + net_disconnect(client->fd); + client->fd = -1; + } + if (client->to_reconnect != NULL) + timeout_remove(&client->to_reconnect); } static int anvil_client_send(struct anvil_client *client, const char *cmd)
--- a/src/lib-sql/driver-mysql.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-sql/driver-mysql.c Thu Mar 17 16:37:22 2011 +0200 @@ -52,6 +52,11 @@ extern const struct sql_result driver_mysql_result; extern const struct sql_result driver_mysql_error_result; +static const char *mysql_prefix(struct mysql_db *db) +{ + return t_strdup_printf("mysql(%s)", db->host); +} + static int driver_mysql_connect(struct sql_db *_db) { struct mysql_db *db = (struct mysql_db *)_db; @@ -105,15 +110,14 @@ alarm(0); if (failed) { sql_db_set_state(&db->api, SQL_DB_STATE_DISCONNECTED); - i_error("mysql: Connect failed to %s (%s): %s - " + i_error("%s: Connect failed to database (%s): %s - " "waiting for %u seconds before retry", - host != NULL ? host : unix_socket, db->dbname, + mysql_prefix(db), db->dbname, mysql_error(db->mysql), db->api.connect_delay); return -1; } else { - i_info("mysql: Connected to %s%s (%s)", - host != NULL ? host : unix_socket, - db->ssl_set ? " using SSL" : "", db->dbname); + i_info("%s: Connected to database %s%s", mysql_prefix(db), + db->dbname, db->ssl_set ? " using SSL" : ""); sql_db_set_state(&db->api, SQL_DB_STATE_IDLE); return 1; @@ -266,8 +270,8 @@ struct mysql_db *db = (struct mysql_db *)_db; if (driver_mysql_do_query(db, query) < 0) { - i_error("mysql: Query '%s' failed: %s", - query, mysql_error(db->mysql)); + i_error("%s: Query '%s' failed: %s", + mysql_prefix(db), query, mysql_error(db->mysql)); } }
--- a/src/lib-sql/driver-pgsql.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-sql/driver-pgsql.c Thu Mar 17 16:37:22 2011 +0200 @@ -73,6 +73,12 @@ static void result_finish(struct pgsql_result *result); +static const char *pgsql_prefix(struct pgsql_db *db) +{ + return db->host == NULL ? "pgsql" : + t_strdup_printf("pgsql(%s)", db->host); +} + static void driver_pgsql_set_state(struct pgsql_db *db, enum sql_db_state state) { i_assert(state == SQL_DB_STATE_BUSY || db->cur_result == NULL); @@ -150,8 +156,8 @@ case PGRES_POLLING_OK: break; case PGRES_POLLING_FAILED: - i_error("pgsql: Connect failed to %s: %s", - PQdb(db->pg), last_error(db)); + i_error("%s: Connect failed to database %s: %s", + pgsql_prefix(db), PQdb(db->pg), last_error(db)); driver_pgsql_close(db); return; } @@ -162,7 +168,8 @@ } if (io_dir == 0) { - i_info("pgsql: Connected to %s", PQdb(db->pg)); + i_info("%s: Connected to database %s", + pgsql_prefix(db), PQdb(db->pg)); if (db->to_connect != NULL) timeout_remove(&db->to_connect); driver_pgsql_set_state(db, SQL_DB_STATE_IDLE); @@ -176,11 +183,10 @@ static void driver_pgsql_connect_timeout(struct pgsql_db *db) { - const char *dbname = PQdb(db->pg); unsigned int secs = ioloop_time - db->api.last_connect_try; - i_error("pgsql: Connect failed to %s: Timeout after %u seconds", - dbname != NULL ? dbname : db->host, secs); + i_error("%s: Connect failed: Timeout after %u seconds", + pgsql_prefix(db), secs); driver_pgsql_close(db); } @@ -191,19 +197,21 @@ i_assert(db->api.state == SQL_DB_STATE_DISCONNECTED); db->pg = PQconnectStart(db->connect_string); - if (db->pg == NULL) - i_fatal("pgsql: PQconnectStart() failed (out of memory)"); + if (db->pg == NULL) { + i_fatal("%s: PQconnectStart() failed (out of memory)", + pgsql_prefix(db)); + } if (PQstatus(db->pg) == CONNECTION_BAD) { - i_error("pgsql: Connect failed to %s: %s", - PQdb(db->pg), last_error(db)); + i_error("%s: Connect failed to database %s: %s", + pgsql_prefix(db), PQdb(db->pg), last_error(db)); driver_pgsql_close(db); return -1; } /* nonblocking connecting begins. */ if (PQsetnonblocking(db->pg, 1) < 0) - i_error("pgsql: PQsetnonblocking() failed"); + i_error("%s: PQsetnonblocking() failed", pgsql_prefix(db)); i_assert(db->to_connect == NULL); db->to_connect = timeout_add(SQL_CONNECT_TIMEOUT_SECS * 1000, driver_pgsql_connect_timeout, db); @@ -428,7 +436,7 @@ driver_pgsql_stop_io(db); - i_error("pgsql: Query timed out, aborting"); + i_error("%s: Query timed out, aborting", pgsql_prefix(db)); result->timeout = TRUE; result_finish(result); } @@ -442,6 +450,7 @@ i_assert(db->cur_result == NULL); i_assert(db->io == NULL); + driver_pgsql_set_state(db, SQL_DB_STATE_BUSY); db->cur_result = result; result->to = timeout_add(SQL_QUERY_TIMEOUT_SECS * 1000, query_timeout, result); @@ -453,7 +462,6 @@ return; } - driver_pgsql_set_state(db, SQL_DB_STATE_BUSY); if (ret > 0) { /* write blocks */ db->io = io_add(PQsocket(db->pg), IO_WRITE, @@ -494,7 +502,7 @@ { struct pgsql_db *db = (struct pgsql_db *)_result->db; - i_error("pgsql: sql_exec() failed: %s", last_error(db)); + i_error("%s: sql_exec() failed: %s", pgsql_prefix(db), last_error(db)); } static void driver_pgsql_exec(struct sql_db *db, const char *query)
--- a/src/lib-sql/driver-sqlpool.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-sql/driver-sqlpool.c Thu Mar 17 16:37:22 2011 +0200 @@ -356,6 +356,8 @@ if (conn == NULL) { /* still nothing. try creating new connections */ conn = sqlpool_add_new_connection(db); + if (conn != NULL) + (void)sql_connect(conn->db); if (conn == NULL || !SQL_DB_IS_READY(conn->db)) return FALSE; }
--- a/src/lib-storage/index/dbox-common/dbox-attachment.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/index/dbox-common/dbox-attachment.c Thu Mar 17 16:37:22 2011 +0200 @@ -139,7 +139,8 @@ static int dbox_attachment_file_get_stream_from(struct dbox_file *file, const char *ext_refs, - struct istream **stream) + struct istream **stream, + const char **error_r) { ARRAY_TYPE(mail_attachment_extref) extrefs_arr; ARRAY_DEFINE(streams, struct istream *); @@ -150,10 +151,14 @@ unsigned int i; int ret = 1; + *error_r = NULL; + t_array_init(&extrefs_arr, 16); if (!dbox_attachment_parse_extref_real(ext_refs, pool_datastack_create(), - &extrefs_arr)) + &extrefs_arr)) { + *error_r = "Broken ext-refs string"; return 0; + } psize = dbox_file_get_plaintext_size(file); t_array_init(&streams, 8); @@ -165,13 +170,17 @@ if (extref->start_offset != last_voffset) { uoff_t part_size = extref->start_offset - last_voffset; + if ((*stream)->v_offset + part_size > psize) { + *error_r = t_strdup_printf( + "ext-refs point outside message " + "(%"PRIuUOFF_T" + %"PRIuUOFF_T" > %"PRIuUOFF_T")", + (*stream)->v_offset, part_size, psize); + ret = 0; + } + input = i_stream_create_limit(*stream, part_size); array_append(&streams, &input, 1); i_stream_seek(*stream, (*stream)->v_offset + part_size); - if ((*stream)->v_offset + part_size > psize) { - /* extrefs point outside message */ - ret = 0; - } last_voffset += part_size; } @@ -192,8 +201,11 @@ } if (psize != (*stream)->v_offset) { - if (psize < (*stream)->v_offset) { - /* extrefs point outside message */ + if ((*stream)->v_offset > psize) { + *error_r = t_strdup_printf( + "ext-refs point outside message " + "(%"PRIuUOFF_T" > %"PRIuUOFF_T")", + (*stream)->v_offset, psize); ret = 0; } else { uoff_t trailer_size = psize - (*stream)->v_offset; @@ -215,7 +227,7 @@ int dbox_attachment_file_get_stream(struct dbox_file *file, struct istream **stream) { - const char *ext_refs; + const char *ext_refs, *error; int ret; /* need to read metadata in case there are external references */ @@ -231,11 +243,12 @@ /* we have external references. */ T_BEGIN { ret = dbox_attachment_file_get_stream_from(file, ext_refs, - stream); + stream, &error); + if (ret == 0) { + dbox_file_set_corrupted(file, + "Corrupted ext-refs metadata %s: %s", + ext_refs, error); + } } T_END; - if (ret == 0) { - dbox_file_set_corrupted(file, "Ext refs metadata corrupted: %s", - ext_refs); - } return ret; }
--- a/src/lib-storage/index/dbox-common/dbox-file.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/index/dbox-common/dbox-file.c Thu Mar 17 16:37:22 2011 +0200 @@ -437,13 +437,13 @@ *offset_r = file->cur_offset; return ret; } + if (i_stream_is_eof(file->input)) { + *last_r = TRUE; + return 0; + } } *offset_r = offset; - if (i_stream_is_eof(file->input)) { - *last_r = TRUE; - return 0; - } *last_r = FALSE; ret = dbox_file_seek(file, offset);
--- a/src/lib-storage/index/dbox-multi/mdbox-map.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/index/dbox-multi/mdbox-map.c Thu Mar 17 16:37:22 2011 +0200 @@ -1098,6 +1098,23 @@ return 0; } +static void +mdbox_map_append_close_if_unneeded(struct mdbox_map *map, + struct dbox_file_append_context *append_ctx) +{ + struct mdbox_file *mfile = + (struct mdbox_file *)append_ctx->file; + uoff_t end_offset = append_ctx->output->offset; + + /* if this file is now large enough not to fit any other + mails and we created it, close its fd since it's not + needed anymore. */ + if (end_offset > map->set->mdbox_rotate_size && + mfile->file_id == 0 && + dbox_file_append_flush(append_ctx) == 0) + dbox_file_close(append_ctx->file); +} + void mdbox_map_append_finish(struct mdbox_map_append_context *ctx) { struct mdbox_map_append *appends, *last; @@ -1113,6 +1130,8 @@ i_assert(cur_offset >= last->offset); last->size = cur_offset - last->offset; dbox_file_append_checkpoint(last->file_append); + + mdbox_map_append_close_if_unneeded(ctx->map, last->file_append); } void mdbox_map_append_abort(struct mdbox_map_append_context *ctx)
--- a/src/lib-storage/index/dbox-multi/mdbox-purge.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/index/dbox-multi/mdbox-purge.c Thu Mar 17 16:37:22 2011 +0200 @@ -222,7 +222,13 @@ out_file_append->file->cur_path); return -1; } - i_assert(ret == (off_t)msg_size); + if (ret != (off_t)msg_size) { + i_assert(ret < (off_t)msg_size); + i_assert(i_stream_is_eof(file->input)); + + dbox_file_set_corrupted(file, "truncated message at EOF"); + return 0; + } /* copy metadata */ if ((ret = mdbox_file_metadata_copy(file, output)) <= 0) @@ -366,10 +372,9 @@ } else { /* non-expunged message. write it to output file. */ i_stream_seek(file->input, offset); - if (mdbox_purge_save_msg(ctx, file, &msgs[i]) < 0) { - ret = -1; + ret = mdbox_purge_save_msg(ctx, file, &msgs[i]); + if (ret <= 0) break; - } array_append(&copied_map_uids, &msgs[i].map_uid, 1); } offset = file->input->v_offset;
--- a/src/lib-storage/index/dbox-multi/mdbox-storage.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/index/dbox-multi/mdbox-storage.c Thu Mar 17 16:37:22 2011 +0200 @@ -232,6 +232,14 @@ offsetof(struct mail_index_header, next_uid), &uid_next, sizeof(uid_next), TRUE); } + if (update != NULL && update->min_first_recent_uid != 0 && + hdr->first_recent_uid < update->min_first_recent_uid) { + uint32_t first_recent_uid = update->min_first_recent_uid; + + mail_index_update_header(trans, + offsetof(struct mail_index_header, first_recent_uid), + &first_recent_uid, sizeof(first_recent_uid), FALSE); + } if (update != NULL && update->min_highest_modseq != 0 && mail_index_modseq_get_highest(box->view) < update->min_highest_modseq) {
--- a/src/lib-storage/index/dbox-single/sdbox-save.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/index/dbox-single/sdbox-save.c Thu Mar 17 16:37:22 2011 +0200 @@ -265,8 +265,12 @@ i_assert(ctx->ctx.finished); - if (array_count(&ctx->files) == 0) + if (array_count(&ctx->files) == 0) { + /* the mail must be freed in the commit_pre() */ + if (ctx->ctx.mail != NULL) + mail_free(&ctx->ctx.mail); return 0; + } if (sdbox_sync_begin(ctx->mbox, SDBOX_SYNC_FLAG_FORCE | SDBOX_SYNC_FLAG_FSYNC, &ctx->sync_ctx) < 0) {
--- a/src/lib-storage/index/dbox-single/sdbox-storage.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/index/dbox-single/sdbox-storage.c Thu Mar 17 16:37:22 2011 +0200 @@ -153,6 +153,14 @@ offsetof(struct mail_index_header, next_uid), &uid_next, sizeof(uid_next), TRUE); } + if (update != NULL && update->min_first_recent_uid != 0 && + hdr->first_recent_uid < update->min_first_recent_uid) { + uint32_t first_recent_uid = update->min_first_recent_uid; + + mail_index_update_header(trans, + offsetof(struct mail_index_header, first_recent_uid), + &first_recent_uid, sizeof(first_recent_uid), FALSE); + } if (update != NULL && update->min_highest_modseq != 0 && mail_index_modseq_get_highest(box->view) < update->min_highest_modseq) { @@ -216,6 +224,11 @@ return 0; } + if (box->creating) { + /* wait for mailbox creation to initialize the index */ + return 0; + } + /* get/generate mailbox guid */ if (sdbox_read_header(mbox, &hdr, FALSE) < 0) { /* it's possible that this mailbox is just now being created
--- a/src/lib-storage/index/index-status.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/index/index-status.c Thu Mar 17 16:37:22 2011 +0200 @@ -32,6 +32,7 @@ status_r->unseen = hdr->messages_count - hdr->seen_messages_count; status_r->uidvalidity = hdr->uid_validity; status_r->uidnext = hdr->next_uid; + status_r->first_recent_uid = hdr->first_recent_uid; status_r->nonpermanent_modseqs = mail_index_is_in_memory(box->index); if ((items & STATUS_HIGHESTMODSEQ) != 0) { status_r->highest_modseq =
--- a/src/lib-storage/index/index-storage.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/index/index-storage.c Thu Mar 17 16:37:22 2011 +0200 @@ -429,6 +429,14 @@ offsetof(struct mail_index_header, next_uid), &next_uid, sizeof(next_uid), FALSE); } + if (update->min_first_recent_uid != 0 && + hdr->first_recent_uid < update->min_first_recent_uid) { + uint32_t first_recent_uid = update->min_first_recent_uid; + + mail_index_update_header(trans, + offsetof(struct mail_index_header, first_recent_uid), + &first_recent_uid, sizeof(first_recent_uid), FALSE); + } if (update->min_highest_modseq != 0 && mail_index_modseq_get_highest(view) < update->min_highest_modseq) { mail_index_modseq_enable(box->index);
--- a/src/lib-storage/index/maildir/maildir-save.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/index/maildir/maildir-save.c Thu Mar 17 16:37:22 2011 +0200 @@ -927,8 +927,12 @@ i_assert(_ctx->output == NULL); i_assert(ctx->last_save_finished); - if (ctx->files_count == 0) + if (ctx->files_count == 0) { + /* the mail must be freed in the commit_pre() */ + if (ctx->mail != NULL) + mail_free(&ctx->mail); return 0; + } sync_flags = MAILDIR_UIDLIST_SYNC_PARTIAL | MAILDIR_UIDLIST_SYNC_NOREFRESH;
--- a/src/lib-storage/index/mbox/mbox-lock.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/index/mbox/mbox-lock.c Thu Mar 17 16:37:22 2011 +0200 @@ -4,6 +4,7 @@ #include "eacces-error.h" #include "restrict-access.h" #include "nfs-workarounds.h" +#include "ipwd.h" #include "mail-index-private.h" #include "mbox-storage.h" #include "istream-raw-mbox.h" @@ -15,7 +16,6 @@ #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> -#include <grp.h> #ifdef HAVE_FLOCK # include <sys/file.h> @@ -341,9 +341,9 @@ static void mbox_dotlock_log_eacces_error(struct mbox_mailbox *mbox, const char *path) { - const char *dir, *errmsg; + const char *dir, *errmsg, *name; struct stat st; - const struct group *group; + struct group group; int orig_errno = errno; errmsg = eacces_error_get_creating("file_dotlock_create", path); @@ -365,10 +365,12 @@ } else if (stat(dir, &st) == 0 && (st.st_mode & 02) == 0 && /* not world-writable */ (st.st_mode & 020) != 0) { /* group-writable */ - group = getgrgid(st.st_gid); + if (i_getgrgid(st.st_gid, &group) <= 0) + name = dec2str(st.st_gid); + else + name = group.gr_name; mail_storage_set_critical(&mbox->storage->storage, - "%s (set mail_privileged_group=%s)", errmsg, - group == NULL ? dec2str(st.st_gid) : group->gr_name); + "%s (set mail_privileged_group=%s)", errmsg, name); } else { mail_storage_set_critical(&mbox->storage->storage, "%s (nonstandard permissions in %s)", errmsg, dir);
--- a/src/lib-storage/mail-storage-service.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/mail-storage-service.c Thu Mar 17 16:37:22 2011 +0200 @@ -7,6 +7,7 @@ #include "module-dir.h" #include "restrict-access.h" #include "eacces-error.h" +#include "ipwd.h" #include "str.h" #include "var-expand.h" #include "dict.h" @@ -22,8 +23,6 @@ #include <stdlib.h> #include <sys/stat.h> -#include <pwd.h> -#include <grp.h> #ifdef HAVE_SYS_TIME_H # include <sys/time.h> @@ -271,34 +270,44 @@ return ret; } -static bool parse_uid(const char *str, uid_t *uid_r) +static bool parse_uid(const char *str, uid_t *uid_r, const char **error_r) { - struct passwd *pw; + struct passwd pw; if (str_to_uid(str, uid_r) == 0) return TRUE; - pw = getpwnam(str); - if (pw == NULL) + switch (i_getpwnam(str, &pw)) { + case -1: + *error_r = t_strdup_printf("getpwnam(%s) failed: %m", str); return FALSE; - - *uid_r = pw->pw_uid; - return TRUE; + case 0: + *error_r = t_strconcat("Unknown UNIX UID user: ", str, NULL); + return FALSE; + default: + *uid_r = pw.pw_uid; + return TRUE; + } } -static bool parse_gid(const char *str, gid_t *gid_r) +static bool parse_gid(const char *str, gid_t *gid_r, const char **error_r) { - struct group *gr; + struct group gr; if (str_to_gid(str, gid_r) == 0) return TRUE; - gr = getgrnam(str); - if (gr == NULL) + switch (i_getgrnam(str, &gr)) { + case -1: + *error_r = t_strdup_printf("getgrnam(%s) failed: %m", str); return FALSE; - - *gid_r = gr->gr_gid; - return TRUE; + case 0: + *error_r = t_strconcat("Unknown UNIX GID group: ", str, NULL); + return FALSE; + default: + *gid_r = gr.gr_gid; + return TRUE; + } } static int @@ -310,24 +319,24 @@ { struct restrict_access_settings rset; uid_t current_euid, setuid_uid = 0; - const char *cur_chroot; + const char *cur_chroot, *error; current_euid = geteuid(); restrict_access_init(&rset); restrict_access_get_env(&rset); if (*set->mail_uid != '\0') { - if (!parse_uid(set->mail_uid, &rset.uid)) { - *error_r = t_strdup_printf("Unknown mail_uid user: %s", - set->mail_uid); + if (!parse_uid(set->mail_uid, &rset.uid, &error)) { + *error_r = t_strdup_printf("%s (from %s)", error, + user->uid_source); return -1; } if (rset.uid < (uid_t)set->first_valid_uid || (set->last_valid_uid != 0 && rset.uid > (uid_t)set->last_valid_uid)) { *error_r = t_strdup_printf( - "Mail access for users with UID %s " - "not permitted (see first_valid_uid in config file).", - dec2str(rset.uid)); + "Mail access for users with UID %s not permitted " + "(see first_valid_uid in config file, uid from %s).", + dec2str(rset.uid), user->uid_source); return -1; } rset.uid_source = user->uid_source; @@ -337,18 +346,18 @@ return -1; } if (*set->mail_gid != '\0') { - if (!parse_gid(set->mail_gid, &rset.gid)) { - *error_r = t_strdup_printf("Unknown mail_gid group: %s", - set->mail_gid); + if (!parse_gid(set->mail_gid, &rset.gid, &error)) { + *error_r = t_strdup_printf("%s (from %s)", error, + user->gid_source); return -1; } if (rset.gid < (gid_t)set->first_valid_gid || (set->last_valid_gid != 0 && rset.gid > (gid_t)set->last_valid_gid)) { *error_r = t_strdup_printf( - "Mail access for users with GID %s " - "not permitted (see first_valid_gid in config file).", - dec2str(rset.gid)); + "Mail access for users with GID %s not permitted " + "(see first_valid_gid in config file, gid from %s).", + dec2str(rset.gid), user->gid_source); return -1; } rset.gid_source = user->gid_source; @@ -358,10 +367,10 @@ return -1; } if (*set->mail_privileged_group != '\0') { - if (!parse_gid(set->mail_privileged_group, &rset.privileged_gid)) { + if (!parse_gid(set->mail_privileged_group, &rset.privileged_gid, + &error)) { *error_r = t_strdup_printf( - "Unknown mail_privileged_group: %s", - set->mail_gid); + "%s (in mail_privileged_group setting)", error); return -1; } }
--- a/src/lib-storage/mail-storage-settings.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/mail-storage-settings.c Thu Mar 17 16:37:22 2011 +0200 @@ -65,7 +65,7 @@ .mail_save_crlf = FALSE, .mail_fsync = "optimized:never:always", .mmap_disable = FALSE, - .dotlock_use_excl = FALSE, + .dotlock_use_excl = TRUE, .mail_nfs_storage = FALSE, .mail_nfs_index = FALSE, .mailbox_list_index = FALSE,
--- a/src/lib-storage/mail-storage.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/mail-storage.c Thu Mar 17 16:37:22 2011 +0200 @@ -803,6 +803,10 @@ int mailbox_update(struct mailbox *box, const struct mailbox_update *update) { + i_assert(update->min_next_uid == 0 || + update->min_first_recent_uid == 0 || + update->min_first_recent_uid <= update->min_next_uid); + return box->v.update(box, update); }
--- a/src/lib-storage/mail-storage.h Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib-storage/mail-storage.h Thu Mar 17 16:37:22 2011 +0200 @@ -70,7 +70,8 @@ STATUS_UNSEEN = 0x10, STATUS_FIRST_UNSEEN_SEQ = 0x20, STATUS_KEYWORDS = 0x40, - STATUS_HIGHESTMODSEQ = 0x80 + STATUS_HIGHESTMODSEQ = 0x80, + STATUS_FIRST_RECENT_UID = 0x400 }; enum mailbox_metadata_items { @@ -194,6 +195,7 @@ uint32_t uidnext; uint32_t first_unseen_seq; + uint32_t first_recent_uid; uint64_t highest_modseq; const ARRAY_TYPE(keywords) *keywords; @@ -215,6 +217,7 @@ uint8_t mailbox_guid[MAIL_GUID_128_SIZE]; uint32_t uid_validity; uint32_t min_next_uid; + uint32_t min_first_recent_uid; uint64_t min_highest_modseq; /* Add these fields to be temporarily cached, if they aren't already. */ const char *const *cache_fields;
--- a/src/lib/Makefile.am Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib/Makefile.am Thu Mar 17 16:37:22 2011 +0200 @@ -45,6 +45,7 @@ home-expand.c \ hostpid.c \ imem.c \ + ipwd.c \ iostream.c \ istream.c \ istream-base64-encoder.c \ @@ -157,6 +158,7 @@ home-expand.h \ hostpid.h \ imem.h \ + ipwd.h \ iostream-internal.h \ istream.h \ istream-base64-encoder.h \
--- a/src/lib/eacces-error.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib/eacces-error.c Thu Mar 17 16:37:22 2011 +0200 @@ -3,13 +3,12 @@ #include "lib.h" #include "str.h" #include "abspath.h" +#include "ipwd.h" #include "restrict-access.h" #include "eacces-error.h" #include <sys/stat.h> #include <unistd.h> -#include <pwd.h> -#include <grp.h> static bool is_in_group(gid_t gid) { @@ -86,8 +85,8 @@ { const char *prev_path = path, *dir, *p; const char *pw_name = NULL, *gr_name = NULL; - const struct passwd *pw; - const struct group *group; + struct passwd pw; + struct group group; string_t *errmsg; struct stat st, dir_st; int orig_errno, ret = -1; @@ -107,32 +106,43 @@ str_printfa(errmsg, " failed: Permission denied (euid=%s", dec2str(geteuid())); - pw = getpwuid(geteuid()); - if (pw != NULL) { - pw_name = t_strdup(pw->pw_name); + switch (i_getpwuid(geteuid(), &pw)) { + case -1: + str_append(errmsg, "(<getpwuid() error>)"); + break; + case 0: + str_append(errmsg, "(<unknown>)"); + break; + default: + pw_name = t_strdup(pw.pw_name); str_printfa(errmsg, "(%s)", pw_name); - } else { - str_append(errmsg, "(<unknown>)"); + break; } str_printfa(errmsg, " egid=%s", dec2str(getegid())); - group = getgrgid(getegid()); - if (group != NULL) { - gr_name = t_strdup(group->gr_name); + switch (i_getgrgid(getegid(), &group)) { + case -1: + str_append(errmsg, "(<getgrgid() error>)"); + break; + case 0: + str_append(errmsg, "(<unknown>)"); + break; + default: + gr_name = t_strdup(group.gr_name); str_printfa(errmsg, "(%s)", gr_name); - } else { - str_append(errmsg, "(<unknown>)"); + break; } memset(&dir_st, 0, sizeof(dir_st)); while ((p = strrchr(prev_path, '/')) != NULL) { - dir = t_strdup_until(prev_path, p); + dir = p == prev_path ? "/" : t_strdup_until(prev_path, p); ret = stat(dir, &st); if (ret == 0) break; - if (errno == EACCES) { + if (errno == EACCES && strcmp(dir, "/") != 0) { /* see if we have access to parent directory */ - } else if (errno == ENOENT && creating) { + } else if (errno == ENOENT && creating && + strcmp(dir, "/") != 0) { /* probably mkdir_parents() failed here, find the first parent directory we couldn't create */ } else { @@ -168,9 +178,8 @@ "some security policy wrong?"); } if (dir_st.st_uid != geteuid()) { - if (pw_name != NULL && - (pw = getpwuid(dir_st.st_uid)) != NULL && - strcmp(pw->pw_name, pw_name) == 0) { + if (pw_name != NULL && i_getpwuid(dir_st.st_uid, &pw) > 0 && + strcmp(pw.pw_name, pw_name) == 0) { str_printfa(errmsg, ", conflicting dir uid=%s(%s)", dec2str(dir_st.st_uid), pw_name); } else { @@ -180,8 +189,8 @@ str_append(errmsg, ", euid is dir owner"); } if (gr_name != NULL && dir_st.st_gid != getegid()) { - group = getgrgid(dir_st.st_gid); - if (group != NULL && strcmp(group->gr_name, gr_name) == 0) { + if (i_getgrgid(dir_st.st_gid, &group) > 0 && + strcmp(group.gr_name, gr_name) == 0) { str_printfa(errmsg, ", conflicting dir gid=%s(%s)", dec2str(dir_st.st_gid), gr_name); }
--- a/src/lib/home-expand.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib/home-expand.c Thu Mar 17 16:37:22 2011 +0200 @@ -1,16 +1,16 @@ /* Copyright (c) 2003-2011 Dovecot authors, see the included COPYING file */ #include "lib.h" +#include "ipwd.h" #include "home-expand.h" #include <stdlib.h> -#include <pwd.h> int home_try_expand(const char **_path) { const char *path = *_path; - const char *home, *p; - struct passwd *pw; + const char *name, *home, *p; + struct passwd pw; if (path == NULL || *path != '~') return 0; @@ -22,14 +22,24 @@ } else { p = strchr(path, '/'); if (p == NULL) { - pw = getpwnam(path); + name = path; path = ""; } else { - pw = getpwnam(t_strdup_until(path, p)); + name = t_strdup_until(path, p); path = p+1; } - - home = pw == NULL ? NULL : pw->pw_dir; + switch (i_getpwnam(name, &pw)) { + case -1: + i_error("getpwnam(%s) failed: %m", name); + home = NULL; + break; + case 0: + home = NULL; + break; + default: + home = pw.pw_dir; + break; + } } if (home == NULL)
--- a/src/lib/ioloop-notify-inotify.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib/ioloop-notify-inotify.c Thu Mar 17 16:37:22 2011 +0200 @@ -11,11 +11,11 @@ #include "ioloop-notify-fd.h" #include "buffer.h" #include "network.h" +#include "ipwd.h" #include <stdio.h> #include <unistd.h> #include <fcntl.h> -#include <pwd.h> #include <sys/ioctl.h> #include <sys/inotify.h> @@ -149,16 +149,15 @@ static void ioloop_inotify_user_limit_exceeded(void) { - const struct passwd *pw; + struct passwd pw; const char *name; uid_t uid = geteuid(); - pw = getpwuid(uid); - if (pw == NULL) + if (i_getpwuid(uid, &pw) <= 0) name = t_strdup_printf("UID %s", dec2str(uid)); else { name = t_strdup_printf("%s (UID %s)", - dec2str(uid), pw->pw_name); + dec2str(uid), pw.pw_name); } i_warning("Inotify instance limit for user %s exceeded, disabling. " "Increase /proc/sys/fs/inotify/max_user_instances", name);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/ipwd.c Thu Mar 17 16:37:22 2011 +0200 @@ -0,0 +1,90 @@ +/* Copyright (c) 2011 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ipwd.h" + +#include <unistd.h> + +#define DEFAULT_PWBUF_SIZE 16384 +#define DEFAULT_GRBUF_SIZE 16384 + +static void *pwbuf = NULL, *grbuf = NULL; +static size_t pwbuf_size, grbuf_size; + +static void pw_init(void) +{ + long size; + + if (pwbuf == NULL) { + size = sysconf(_SC_GETPW_R_SIZE_MAX); + if (size < 0) + size = DEFAULT_PWBUF_SIZE; + + pwbuf_size = size; + pwbuf = i_malloc(pwbuf_size); + } +} + +static void gr_init(void) +{ + long size; + + if (grbuf == NULL) { + size = sysconf(_SC_GETGR_R_SIZE_MAX); + if (size < 0) + size = DEFAULT_GRBUF_SIZE; + + grbuf_size = size; + grbuf = i_malloc(grbuf_size); + } +} + +void ipwd_deinit(void) +{ + i_free_and_null(pwbuf); + i_free_and_null(grbuf); +} + +int i_getpwnam(const char *name, struct passwd *pwd_r) +{ + struct passwd *result; + + pw_init(); + errno = getpwnam_r(name, pwd_r, pwbuf, pwbuf_size, &result); + if (result != NULL) + return 1; + return errno == 0 ? 0 : -1; +} + +int i_getpwuid(uid_t uid, struct passwd *pwd_r) +{ + struct passwd *result; + + pw_init(); + errno = getpwuid_r(uid, pwd_r, pwbuf, pwbuf_size, &result); + if (result != NULL) + return 1; + return errno == 0 ? 0 : -1; +} + +int i_getgrnam(const char *name, struct group *grp_r) +{ + struct group *result; + + gr_init(); + errno = getgrnam_r(name, grp_r, grbuf, grbuf_size, &result); + if (result != NULL) + return 1; + return errno == 0 ? 0 : -1; +} + +int i_getgrgid(gid_t gid, struct group *grp_r) +{ + struct group *result; + + gr_init(); + errno = getgrgid_r(gid, grp_r, grbuf, grbuf_size, &result); + if (result != NULL) + return 1; + return errno == 0 ? 0 : -1; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/ipwd.h Thu Mar 17 16:37:22 2011 +0200 @@ -0,0 +1,23 @@ +#ifndef IPWD_H +#define IPWD_H + +#include <pwd.h> +#include <grp.h> + +/* Replacements for standard getpw/gr*(), fixing their ability to report errors + properly. As with standard getpw/gr*(), second call overwrites data used + by the first one. + + Functions return 1 if user/group is found, 0 if not or + -1 if error (with errno set). */ + +int i_getpwnam(const char *name, struct passwd *pwd_r); +int i_getpwuid(uid_t uid, struct passwd *pwd_r); + +int i_getgrnam(const char *name, struct group *grp_r); +int i_getgrgid(gid_t gid, struct group *grp_r); + +/* Free memory used by above functions. */ +void ipwd_deinit(void); + +#endif
--- a/src/lib/lib.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib/lib.c Thu Mar 17 16:37:22 2011 +0200 @@ -3,6 +3,7 @@ #include "lib.h" #include "env-util.h" #include "hostpid.h" +#include "ipwd.h" #include "process-title.h" #include <stdlib.h> @@ -34,6 +35,7 @@ void lib_deinit(void) { + ipwd_deinit(); data_stack_deinit(); env_deinit(); failures_deinit();
--- a/src/lib/mkdir-parents.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib/mkdir-parents.c Thu Mar 17 16:37:22 2011 +0200 @@ -4,11 +4,10 @@ #include "str.h" #include "eacces-error.h" #include "mkdir-parents.h" +#include "ipwd.h" #include <sys/stat.h> #include <unistd.h> -#include <pwd.h> -#include <grp.h> static int mkdir_chown_full(const char *path, mode_t mode, uid_t uid, @@ -48,19 +47,19 @@ str_printfa(str, "chown(%s, %ld", path, uid == (uid_t)-1 ? -1L : (long)uid); if (uid != (uid_t)-1) { - struct passwd *pw = getpwuid(uid); + struct passwd pw; - if (pw != NULL) - str_printfa(str, "(%s)", pw->pw_name); + if (i_getpwuid(uid, &pw) > 0) + str_printfa(str, "(%s)", pw.pw_name); } str_printfa(str, ", %ld", gid == (gid_t)-1 ? -1L : (long)gid); if (gid != (gid_t)-1) { - struct group *gr = getgrgid(uid); + struct group gr; - if (gr != NULL) - str_printfa(str, "(%s)", gr->gr_name); + if (i_getgrgid(uid, &gr) > 0) + str_printfa(str, "(%s)", gr.gr_name); } errno = orig_errno; i_error("%s) failed: %m", str_c(str));
--- a/src/lib/restrict-access.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/lib/restrict-access.c Thu Mar 17 16:37:22 2011 +0200 @@ -9,11 +9,10 @@ #include "str.h" #include "restrict-access.h" #include "env-util.h" +#include "ipwd.h" #include <stdlib.h> #include <time.h> -#include <pwd.h> -#include <grp.h> #ifdef HAVE_PR_SET_DUMPABLE # include <sys/prctl.h> #endif @@ -34,30 +33,28 @@ static const char *get_uid_str(uid_t uid) { - const struct passwd *pw; + struct passwd pw; const char *ret; int old_errno = errno; - pw = getpwuid(uid); - if (pw == NULL) + if (i_getpwuid(uid, &pw) <= 0) ret = dec2str(uid); else - ret = t_strdup_printf("%s(%s)", dec2str(uid), pw->pw_name); + ret = t_strdup_printf("%s(%s)", dec2str(uid), pw.pw_name); errno = old_errno; return ret; } static const char *get_gid_str(gid_t gid) { - const struct group *group; + struct group group; const char *ret; int old_errno = errno; - group = getgrgid(gid); - if (group == NULL) + if (i_getgrgid(gid, &group) <= 0) ret = dec2str(gid); else - ret = t_strdup_printf("%s(%s)", dec2str(gid), group->gr_name); + ret = t_strdup_printf("%s(%s)", dec2str(gid), group.gr_name); errno = old_errno; return ret; } @@ -158,16 +155,20 @@ static gid_t get_group_id(const char *name) { - struct group *group; + struct group group; gid_t gid; if (str_to_gid(name, &gid) == 0) return gid; - group = getgrnam(name); - if (group == NULL) + switch (i_getgrnam(name, &group)) { + case -1: + i_fatal("getgrnam(%s) failed: %m", name); + case 0: i_fatal("unknown group name in extra_groups: %s", name); - return group->gr_gid; + default: + return group.gr_gid; + } } static void fix_groups_list(const struct restrict_access_settings *set,
--- a/src/login-common/sasl-server.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/login-common/sasl-server.c Thu Mar 17 16:37:22 2011 +0200 @@ -67,6 +67,10 @@ auth_flags |= AUTH_REQUEST_FLAG_VALID_CLIENT_CERT; if (client->secured) auth_flags |= AUTH_REQUEST_FLAG_SECURED; + if (client->trusted) { + /* e.g. webmail */ + auth_flags |= AUTH_REQUEST_FLAG_NO_PENALTY; + } return auth_flags; }
--- a/src/master/common.h Thu Mar 10 18:44:20 2011 +0200 +++ b/src/master/common.h Thu Mar 17 16:37:22 2011 +0200 @@ -9,7 +9,7 @@ extern gid_t master_gid; extern bool core_dumps_disabled; extern const char *ssl_manual_key_password; -extern int null_fd, master_dead_pipe_fd[2]; +extern int null_fd, global_master_dead_pipe_fd[2]; extern struct service_list *services; void process_exec(const char *cmd, const char *extra_args[]) ATTR_NORETURN;
--- a/src/master/main.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/master/main.c Thu Mar 17 16:37:22 2011 +0200 @@ -9,6 +9,7 @@ #include "env-util.h" #include "hostpid.h" #include "abspath.h" +#include "ipwd.h" #include "execv-const.h" #include "restrict-process-size.h" #include "master-service.h" @@ -28,8 +29,6 @@ #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> -#include <pwd.h> -#include <grp.h> #define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf" @@ -42,7 +41,7 @@ gid_t master_gid; bool core_dumps_disabled; const char *ssl_manual_key_password; -int null_fd, master_dead_pipe_fd[2]; +int null_fd, global_master_dead_pipe_fd[2]; struct service_list *services; static char *pidfile_path; @@ -87,7 +86,7 @@ int get_uidgid(const char *user, uid_t *uid_r, gid_t *gid_r, const char **error_r) { - struct passwd *pw; + struct passwd pw; if (*user == '\0') { *uid_r = (uid_t)-1; @@ -95,32 +94,40 @@ return 0; } - if ((pw = getpwnam(user)) == NULL) { + switch (i_getpwnam(user, &pw)) { + case -1: + *error_r = t_strdup_printf("getpwnam(%s) failed: %m", user); + return -1; + case 0: *error_r = t_strdup_printf("User doesn't exist: %s", user); return -1; + default: + *uid_r = pw.pw_uid; + *gid_r = pw.pw_gid; + return 0; } - - *uid_r = pw->pw_uid; - *gid_r = pw->pw_gid; - return 0; } int get_gid(const char *group, gid_t *gid_r, const char **error_r) { - struct group *gr; + struct group gr; if (*group == '\0') { *gid_r = (gid_t)-1; return 0; } - if ((gr = getgrnam(group)) == NULL) { + switch (i_getgrnam(group, &gr)) { + case -1: + *error_r = t_strdup_printf("getgrnam(%s) failed: %m", group); + return -1; + case 0: *error_r = t_strdup_printf("Group doesn't exist: %s", group); return -1; + default: + *gid_r = gr.gr_gid; + return 0; } - - *gid_r = gr->gr_gid; - return 0; } static void ATTR_NORETURN ATTR_FORMAT(2, 0) @@ -725,10 +732,10 @@ i_fatal("Can't open /dev/null: %m"); fd_close_on_exec(null_fd, TRUE); } while (null_fd <= STDERR_FILENO); - if (pipe(master_dead_pipe_fd) < 0) + if (pipe(global_master_dead_pipe_fd) < 0) i_fatal("pipe() failed: %m"); - fd_close_on_exec(master_dead_pipe_fd[0], TRUE); - fd_close_on_exec(master_dead_pipe_fd[1], TRUE); + fd_close_on_exec(global_master_dead_pipe_fd[0], TRUE); + fd_close_on_exec(global_master_dead_pipe_fd[1], TRUE); set = master_settings_read(); if (ask_key_pass) { @@ -774,8 +781,12 @@ if (chdir(set->base_dir) < 0) i_fatal("chdir(%s) failed: %m", set->base_dir); - if (dup2(null_fd, STDERR_FILENO) < 0) - i_fatal("dup2(null_fd) failed: %m"); + if (strcmp(services->service_set->log_path, "/dev/stderr") != 0 && + strcmp(services->service_set->info_log_path, "/dev/stderr") != 0 && + strcmp(services->service_set->debug_log_path, "/dev/stderr") != 0) { + if (dup2(null_fd, STDERR_FILENO) < 0) + i_fatal("dup2(null_fd) failed: %m"); + } i_set_fatal_handler(master_fatal_callback); i_set_error_handler(orig_error_callback);
--- a/src/master/master-settings.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/master/master-settings.c Thu Mar 17 16:37:22 2011 +0200 @@ -457,12 +457,8 @@ service_set_login_dump_core(service); } set->protocols_split = p_strsplit_spaces(pool, set->protocols, " "); - if (set->protocols_split[0] == NULL) { - *error_r = "No protocols defined, " - "if you don't want any use protocols=none"; - return FALSE; - } - if (strcmp(set->protocols_split[0], "none") == 0 && + if (set->protocols_split[0] != NULL && + strcmp(set->protocols_split[0], "none") == 0 && set->protocols_split[1] == NULL) set->protocols_split[0] = NULL;
--- a/src/master/service-monitor.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/master/service-monitor.c Thu Mar 17 16:37:22 2011 +0200 @@ -344,6 +344,11 @@ services_log_init(service_list); service_anvil_monitor_start(service_list); + if (pipe(service_list->master_dead_pipe_fd) < 0) + i_error("pipe() failed: %m"); + fd_close_on_exec(service_list->master_dead_pipe_fd[0], TRUE); + fd_close_on_exec(service_list->master_dead_pipe_fd[1], TRUE); + array_foreach(&service_list->services, services) { struct service *service = *services; @@ -422,6 +427,15 @@ { struct service *const *services; + if (service_list->master_dead_pipe_fd[0] != -1) { + if (close(service_list->master_dead_pipe_fd[0]) < 0) + i_error("close(master dead pipe) failed: %m"); + if (close(service_list->master_dead_pipe_fd[1]) < 0) + i_error("close(master dead pipe) failed: %m"); + service_list->master_dead_pipe_fd[0] = -1; + service_list->master_dead_pipe_fd[1] = -1; + } + array_foreach(&service_list->services, services) service_monitor_stop(*services);
--- a/src/master/service-process.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/master/service-process.c Thu Mar 17 16:37:22 2011 +0200 @@ -26,8 +26,6 @@ #include "service-process-notify.h" #include "service-process.h" -#include <grp.h> -#include <pwd.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> @@ -116,7 +114,13 @@ break; } dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD); - dup2_append(&dups, master_dead_pipe_fd[1], MASTER_DEAD_FD); + if (service->type != SERVICE_TYPE_ANVIL) { + dup2_append(&dups, service->list->master_dead_pipe_fd[1], + MASTER_DEAD_FD); + } else { + dup2_append(&dups, global_master_dead_pipe_fd[1], + MASTER_DEAD_FD); + } if (service->type == SERVICE_TYPE_LOG) { /* keep stderr as-is. this is especially important when
--- a/src/master/service.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/master/service.c Thu Mar 17 16:37:22 2011 +0200 @@ -426,18 +426,16 @@ return FALSE; } -int services_create(const struct master_settings *set, - struct service_list **services_r, const char **error_r) +static int +services_create_real(const struct master_settings *set, pool_t pool, + struct service_list **services_r, const char **error_r) { struct service_list *service_list; struct service *service; struct service_settings *const *service_settings; - pool_t pool; const char *error; unsigned int i, count; - pool = pool_alloconly_create("services pool", 4096); - service_list = p_new(pool, struct service_list, 1); service_list->refcount = 1; service_list->pool = pool; @@ -446,6 +444,8 @@ service_list->set = set; service_list->master_log_fd[0] = -1; service_list->master_log_fd[1] = -1; + service_list->master_dead_pipe_fd[0] = -1; + service_list->master_dead_pipe_fd[1] = -1; service_settings = array_get(&set->services, &count); p_array_init(&service_list->services, pool, count); @@ -504,6 +504,19 @@ return 0; } +int services_create(const struct master_settings *set, + struct service_list **services_r, const char **error_r) +{ + pool_t pool; + + pool = pool_alloconly_create("services pool", 4096); + if (services_create_real(set, pool, services_r, error_r) < 0) { + pool_unref(&pool); + return -1; + } + return 0; +} + void service_signal(struct service *service, int signo) { struct service_process *process = service->processes;
--- a/src/master/service.h Thu Mar 10 18:44:20 2011 +0200 +++ b/src/master/service.h Thu Mar 17 16:37:22 2011 +0200 @@ -119,6 +119,8 @@ int master_log_fd[2]; struct service_process_notify *log_byes; + int master_dead_pipe_fd[2]; + ARRAY_DEFINE(services, struct service *); unsigned int destroyed:1;
--- a/src/plugins/acl/doveadm-acl.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/plugins/acl/doveadm-acl.c Thu Mar 17 16:37:22 2011 +0200 @@ -218,6 +218,17 @@ return ctx; } +static bool is_standard_right(const char *name) +{ + unsigned int i; + + for (i = 0; all_mailbox_rights[i] != NULL; i++) { + if (strcmp(all_mailbox_rights[i], name) == 0) + return TRUE; + } + return FALSE; +} + static void cmd_acl_set_run(struct doveadm_mail_cmd_context *ctx, struct mail_user *user) { @@ -250,9 +261,17 @@ right++; dest = &dest_neg_rights; } - if (strcmp(right, "all") != 0) - array_append(dest, &right, 1); - else { + if (strcmp(right, "all") != 0) { + if (*right == ':') { + /* non-standard right */ + right++; + array_append(dest, &right, 1); + } else if (is_standard_right(right)) { + array_append(dest, &right, 1); + } else { + i_fatal("Invalid right '%s'", right); + } + } else { for (j = 0; all_mailbox_rights[j] != NULL; j++) array_append(dest, &all_mailbox_rights[j], 1); }
--- a/src/plugins/expire/expire-plugin.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/plugins/expire/expire-plugin.c Thu Mar 17 16:37:22 2011 +0200 @@ -90,12 +90,34 @@ } } +static void first_save_timestamp(struct mailbox *box, time_t *stamp_r) +{ + struct mailbox_transaction_context *t; + const struct mail_index_header *hdr; + struct mail *mail; + + *stamp_r = ioloop_time; + + t = mailbox_transaction_begin(box, 0); + mail = mail_alloc(t, 0, NULL); + + /* find the first non-expunged mail. we're here because the first + mail was expunged, so don't bother checking it. */ + hdr = mail_index_get_header(box->view); + if (hdr->messages_count > 0) { + mail_set_seq(mail, 1); + (void)mail_get_save_date(mail, stamp_r); + } + mail_free(&mail); + (void)mailbox_transaction_commit(&t); +} + static int expire_mailbox_transaction_commit(struct mailbox_transaction_context *t, struct mail_transaction_commit_changes *changes_r) { - struct expire_mail_user *euser = - EXPIRE_USER_CONTEXT(t->box->storage->user); + struct mail_user *user = t->box->storage->user; + struct expire_mail_user *euser = EXPIRE_USER_CONTEXT(user); struct expire_mailbox *xpr_box = EXPIRE_CONTEXT(t->box); struct expire_transaction_context *xt = EXPIRE_CONTEXT(t); struct mailbox *box = t->box; @@ -106,6 +128,16 @@ if (xt->first_expunged) { /* first mail expunged. dict needs updating. */ first_nonexpunged_timestamp(t, &new_stamp); + if (new_stamp == 0 && xt->saves) { + /* everything was expunged, but also within this + transaction a new message was saved */ + new_stamp = ioloop_time; + } + if (user->mail_debug) { + i_debug("expire: Expunging first message in %s, " + "updating timestamp to %ld", + box->vname, (long)new_stamp); + } update_dict = TRUE; } @@ -123,31 +155,39 @@ box->storage->user->username, "/", mailbox_get_vname(box), NULL); if (xt->first_expunged) { - if (new_stamp == 0 && xt->saves) - new_stamp = ioloop_time; + /* new_stamp is already set */ } else { i_assert(xt->saves); /* saved new mails. dict needs to be updated only if this is the first mail in the database */ ret = dict_lookup(euser->db, pool_datastack_create(), key, &value); - update_dict = ret == 0 || - (ret > 0 && strtoul(value, NULL, 10) == 0); - /* may not be exactly the first message's save time - but a few second difference doesn't matter */ - new_stamp = ioloop_time; + if (ret == 0) { + /* first time saving here with expire enabled */ + first_save_timestamp(box, &new_stamp); + update_dict = TRUE; + } else if (strcmp(value, "0") == 0) { + /* we're saving the first mail to this mailbox. + ioloop_time may not be exactly the first + message's save time, but a few seconds + difference doesn't matter */ + new_stamp = ioloop_time; + update_dict = TRUE; + } else { + /* already exists */ + } + if (user->mail_debug && update_dict) { + i_debug("expire: Saving first message to %s, " + "updating timestamp to %ld", + box->vname, (long)new_stamp); + } } if (update_dict) { struct dict_transaction_context *dctx; dctx = dict_transaction_begin(euser->db); - if (new_stamp == 0) { - /* everything expunged */ - dict_unset(dctx, key); - } else { - dict_set(dctx, key, dec2str(new_stamp)); - } + dict_set(dctx, key, dec2str(new_stamp)); dict_transaction_commit(&dctx); } } T_END;
--- a/src/plugins/virtual/virtual-config.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/plugins/virtual/virtual-config.c Thu Mar 17 16:37:22 2011 +0200 @@ -135,7 +135,7 @@ if (strcasecmp(line, "INBOX") == 0) line = "INBOX"; bbox->name = p_strdup(ctx->pool, line); - if (*line == '-' || *line == '!') line++; + if (*line == '-' || *line == '+' || *line == '!') line++; bbox->ns = strcasecmp(line, "INBOX") == 0 ? mail_namespace_find_inbox(user->namespaces) : mail_namespace_find(user->namespaces, line); @@ -149,6 +149,11 @@ bbox->name); return -1; } + if (bbox->name[0] == '+') { + bbox->name++; + bbox->clear_recent = TRUE; + } + if (strchr(bbox->name, '*') != NULL || strchr(bbox->name, '%') != NULL) { name = bbox->name[0] == '-' ? bbox->name + 1 : bbox->name;
--- a/src/plugins/virtual/virtual-storage.c Thu Mar 10 18:44:20 2011 +0200 +++ b/src/plugins/virtual/virtual-storage.c Thu Mar 17 16:37:22 2011 +0200 @@ -165,7 +165,8 @@ i_assert(bbox->box == NULL); - flags |= MAILBOX_FLAG_KEEP_RECENT; + if (!bbox->clear_recent) + flags |= MAILBOX_FLAG_KEEP_RECENT; mailbox = bbox->name; ns = mail_namespace_find(user->namespaces, mailbox);
--- a/src/plugins/virtual/virtual-storage.h Thu Mar 10 18:44:20 2011 +0200 +++ b/src/plugins/virtual/virtual-storage.h Thu Mar 17 16:37:22 2011 +0200 @@ -95,6 +95,7 @@ unsigned int sync_seen:1; unsigned int wildcard:1; + unsigned int clear_recent:1; unsigned int uids_nonsorted:1; }; ARRAY_DEFINE_TYPE(virtual_backend_box, struct virtual_backend_box *);