diff -Nur dovecot-1.1.7+patch9/COPYING dovecot-patch/COPYING
--- dovecot-1.1.7+patch9/COPYING 2009-01-06 10:08:10.000000000 -0600
+++ dovecot-patch/COPYING 2009-01-06 10:08:19.000000000 -0600
@@ -80,6 +80,7 @@
src/auth/db-od.h
src/auth/passdb-od.c
src/auth/userdb-od.c
+src/mail-common/*
Copyright (c) 2008 Apple Inc. All rights reserved.
diff -Nur dovecot-1.1.7+patch9/configure.in dovecot-patch/configure.in
--- dovecot-1.1.7+patch9/configure.in 2009-01-06 10:08:10.000000000 -0600
+++ dovecot-patch/configure.in 2009-01-06 10:08:19.000000000 -0600
@@ -2405,6 +2405,7 @@
src/imap/Makefile
src/imap-login/Makefile
src/login-common/Makefile
+src/mail-common/Makefile
src/master/Makefile
src/pop3/Makefile
src/pop3-login/Makefile
diff -Nur dovecot-1.1.7+patch9/dovecot-example.conf dovecot-patch/dovecot-example.conf
--- dovecot-1.1.7+patch9/dovecot-example.conf 2009-01-06 10:08:10.000000000 -0600
+++ dovecot-patch/dovecot-example.conf 2009-01-06 10:08:19.000000000 -0600
@@ -516,8 +516,22 @@
# /tmp/gdbhelper.* files:
# mail_executable = /usr/libexec/dovecot/gdbhelper /usr/libexec/dovecot/imap
#
+ # (APPLE) Must use default executable when mail_process_per_connection=no
+ # to maintain compatibility with mail executables that understand only
+ # mail_process_per_connection=yes. Force override by having the last
+ # character of your executable's name be !.
#mail_executable = /usr/libexec/dovecot/imap
+ # (APPLE) Should each connected client have its own mail process
+ # (yes), or should one mail process serve multiple clients (no)? Yes
+ # is more secure, no is more scalable. Same idea as
+ # login_process_per_connection.
+ #mail_process_per_connection = yes
+
+ # (APPLE) Maximum number of concurrent connections allowed per each
+ # mail process. Meaningful only when mail_process_per_connection=no.
+ #mail_max_connections = 20
+
# Maximum IMAP command line length in bytes. Some clients generate very long
# command lines with huge mailboxes, so you may need to raise this if you get
# "Too long argument" or "IMAP command line too large" errors often.
@@ -577,8 +591,23 @@
# POP3 executable location. See IMAP's mail_executable above for examples
# how this could be changed.
+ #
+ # (APPLE) Must use default executable when mail_process_per_connection=no
+ # to maintain compatibility with mail executables that understand only
+ # mail_process_per_connection=yes. Force override by having the last
+ # character of your executable's name be !.
#mail_executable = /usr/libexec/dovecot/pop3
+ # (APPLE) Should each connected client have its own mail process
+ # (yes), or should one mail process serve multiple clients (no)? Yes
+ # is more secure, no is more scalable. Same idea as
+ # login_process_per_connection.
+ #mail_process_per_connection = yes
+
+ # (APPLE) Maximum number of concurrent connections allowed per each
+ # mail process. Meaningful only when mail_process_per_connection=no.
+ #mail_max_connections = 20
+
# Don't try to set mails non-recent or seen with POP3 sessions. This is
# mostly intended to reduce disk I/O. With maildir it doesn't move files
# from new/ to cur/, with mbox it doesn't write Status-header.
diff -Nur dovecot-1.1.7+patch9/src/Makefile.am dovecot-patch/src/Makefile.am
--- dovecot-1.1.7+patch9/src/Makefile.am 2008-10-26 10:00:45.000000000 -0500
+++ dovecot-patch/src/Makefile.am 2009-01-06 10:08:19.000000000 -0600
@@ -23,6 +23,7 @@
dict \
master \
login-common \
+ mail-common \
imap-login \
imap \
$(POP3D) \
diff -Nur dovecot-1.1.7+patch9/src/deliver/deliver.c dovecot-patch/src/deliver/deliver.c
--- dovecot-1.1.7+patch9/src/deliver/deliver.c 2009-01-06 10:08:10.000000000 -0600
+++ dovecot-patch/src/deliver/deliver.c 2009-01-06 10:08:19.000000000 -0600
@@ -810,7 +810,8 @@
const char *auth_socket;
const char *home, *destaddr, *user, *value, *errstr, *path;
ARRAY_TYPE(string) extra_fields;
- struct mail_namespace *ns, *raw_ns;
+ struct mail_user *mail_user, *raw_mail_user;
+ struct mail_namespace *raw_ns;
struct mail_storage *storage;
struct mailbox *box;
struct raw_mailbox *raw_box;
@@ -819,7 +820,6 @@
struct mailbox_header_lookup_ctx *headers_ctx;
struct mail *mail;
uid_t process_euid;
- pool_t namespace_pool;
bool stderr_rejection = FALSE;
bool keep_environment = FALSE;
bool user_auth = FALSE;
@@ -1043,13 +1043,16 @@
module_dir_init(modules);
- namespace_pool = pool_alloconly_create("namespaces", 1024);
- if (mail_namespaces_init(namespace_pool, user, &ns) < 0)
+ mail_user = mail_user_init(user, home);
+ if (mail_namespaces_init(mail_user) < 0)
i_fatal("Namespace initialization failed");
- raw_ns = mail_namespaces_init_empty(namespace_pool);
+ /* create a separate mail user for the internal namespace */
+ raw_mail_user = mail_user_init(user, NULL);
+ raw_ns = mail_namespaces_init_empty(raw_mail_user);
raw_ns->flags |= NAMESPACE_FLAG_INTERNAL;
- if (mail_storage_create(raw_ns, "raw", "/tmp", user,
+
+ if (mail_storage_create(raw_ns, "raw", "/tmp",
MAIL_STORAGE_FLAG_FULL_FS_ACCESS,
FILE_LOCK_METHOD_FCNTL, &errstr) < 0)
i_fatal("Couldn't create internal raw storage: %s", errstr);
@@ -1086,7 +1089,8 @@
if (deliver_mail == NULL)
ret = -1;
else {
- if (deliver_mail(ns, &storage, mail, destaddr, mailbox) <= 0) {
+ if (deliver_mail(mail_user->namespaces, &storage, mail,
+ destaddr, mailbox) <= 0) {
/* if message was saved, don't bounce it even though
the script failed later. */
ret = saved_mail ? 0 : -1;
@@ -1098,12 +1102,14 @@
if (ret < 0 && !tried_default_save) {
/* plugins didn't handle this. save into the default mailbox. */
- ret = deliver_save(ns, &storage, mailbox, mail, 0, NULL);
+ ret = deliver_save(mail_user->namespaces,
+ &storage, mailbox, mail, 0, NULL);
}
if (ret < 0 && strcasecmp(mailbox, "INBOX") != 0) {
/* still didn't work. try once more to save it
to INBOX. */
- ret = deliver_save(ns, &storage, "INBOX", mail, 0, NULL);
+ ret = deliver_save(mail_user->namespaces,
+ &storage, "INBOX", mail, 0, NULL);
}
if (ret < 0 ) {
@@ -1150,8 +1156,8 @@
mailbox_transaction_rollback(&t);
mailbox_close(&box);
- mail_namespaces_deinit(&raw_ns);
- mail_namespaces_deinit(&ns);
+ mail_user_deinit(&mail_user);
+ mail_user_deinit(&raw_mail_user);
module_dir_unload(&modules);
mail_storage_deinit();
diff -Nur dovecot-1.1.7+patch9/src/imap/Makefile.am dovecot-patch/src/imap/Makefile.am
--- dovecot-1.1.7+patch9/src/imap/Makefile.am 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/imap/Makefile.am 2009-01-06 10:08:19.000000000 -0600
@@ -9,6 +9,7 @@
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-storage \
+ -I$(top_srcdir)/src/mail-common \
-DMODULEDIR=\""$(moduledir)"\"
imap_LDFLAGS = -export-dynamic
@@ -23,6 +24,7 @@
../lib-storage/list/libstorage_list.a \
$(STORAGE_LIBS) \
../lib-imap/libimap.a \
+ ../mail-common/libmail-common.a \
../lib-mail/libmail.a \
../lib-dict/libdict.a \
../lib-charset/libcharset.a \
diff -Nur dovecot-1.1.7+patch9/src/imap/client.c dovecot-patch/src/imap/client.c
--- dovecot-1.1.7+patch9/src/imap/client.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/imap/client.c 2009-01-06 10:08:19.000000000 -0600
@@ -10,13 +10,16 @@
#include "var-expand.h"
#include "commands.h"
#include "mail-namespace.h"
+#include "master.h" /* APPLE */
+#include "ioloop.h" /* APPLE */
#include <stdlib.h>
#include <unistd.h>
extern struct mail_storage_callbacks mail_storage_callbacks;
-static struct client *my_client; /* we don't need more than one currently */
+static struct client *clients; /* APPLE was my_client, now list */
+static bool process_per_connection = TRUE; /* APPLE */
static bool client_handle_input(struct client *client);
@@ -27,14 +30,18 @@
client_destroy(client, "Disconnected for inactivity");
}
+static /* APPLE */
struct client *client_create(int fd_in, int fd_out,
- struct mail_namespace *namespaces)
+ struct mail_user *user,
+ unsigned int connection_id) /* APPLE */
{
struct client *client;
+ struct mail_namespace *ns;
/* always use nonblocking I/O */
net_set_nonblock(fd_in, TRUE);
- net_set_nonblock(fd_out, TRUE);
+ if (fd_out != fd_in) /* APPLE */
+ net_set_nonblock(fd_out, TRUE);
client = i_new(struct client, 1);
client->fd_in = fd_in;
@@ -50,22 +57,76 @@
client_idle_timeout, client);
client->command_pool = pool_alloconly_create("client command", 1024*12);
- client->namespaces = namespaces;
+ client->user = user;
- while (namespaces != NULL) {
- mail_storage_set_callbacks(namespaces->storage,
+ for (ns = user->namespaces; ns != NULL; ns = ns->next) {
+ mail_storage_set_callbacks(ns->storage,
&mail_storage_callbacks, client);
- namespaces = namespaces->next;
}
- i_assert(my_client == NULL);
- my_client = client;
+ /* APPLE */
+ client->connection_id = connection_id;
+ client->next = clients;
+ clients = client;
if (hook_client_created != NULL)
hook_client_created(&client);
return client;
}
+/* APPLE */
+bool client_attach(int fd_in, int fd_out, bool is_standalone)
+{
+ const char *username, *home;
+ struct mail_user *user;
+ struct client *client;
+ unsigned int connection_id;
+
+ username = getenv("USER");
+ if (username == NULL || *username == '\0') {
+ i_error("USER environment missing from client request");
+ return FALSE;
+ }
+
+ home = getenv("HOME");
+
+ user = mail_user_init(username, home);
+ if (mail_namespaces_init(user) < 0) {
+ i_error("Namespace initialization failed for user %s",
+ username);
+ mail_user_deinit(&user);
+ return FALSE;
+ }
+
+ if (process_per_connection)
+ connection_id = 0;
+ else {
+ const char *env = getenv("CONNECTION_ID");
+ if (env == NULL || *env == '\0') {
+ i_error("CONNECTION_ID environment missing from client request");
+ mail_user_deinit(&user);
+ return FALSE;
+ }
+ connection_id = strtoul(env, NULL, 10);
+ }
+ client = client_create(fd_in, fd_out, user, connection_id);
+
+ o_stream_cork(client->output);
+ if (is_standalone) {
+ client_send_line(client, t_strconcat(
+ "* PREAUTH [CAPABILITY ",
+ str_c(capability_string), "] "
+ "Logged in as ", username, NULL));
+ } else if (getenv("IMAPLOGINTAG") != NULL) {
+ /* Support for mailfront */
+ client_send_line(client, t_strconcat(getenv("IMAPLOGINTAG"),
+ " OK Logged in.", NULL));
+ }
+ o_stream_uncork(client->output);
+
+ return TRUE;
+}
+
void client_command_cancel(struct client_command_context **_cmd)
{
struct client_command_context *cmd = *_cmd;
@@ -132,14 +193,23 @@
void client_destroy(struct client *client, const char *reason)
{
struct client_command_context *cmd;
+ struct client **pos; /* APPLE */
+ unsigned int connection_id; /* APPLE */
+
i_assert(!client->destroyed);
client->destroyed = TRUE;
if (!client->disconnected) {
+ const char *prefix; /* APPLE */
+
client->disconnected = TRUE;
if (reason == NULL)
reason = client_get_disconnect_reason(client);
- i_info("%s %s", reason, client_stats(client));
+
+ /* APPLE */
+ prefix = process_per_connection ? "" :
+ t_strconcat("User ", client->user->username, ": ", NULL);
+ i_info("%s%s %s", prefix, reason, client_stats(client));
}
i_stream_close(client->input);
@@ -161,7 +231,7 @@
if (client->mailbox != NULL)
mailbox_close(&client->mailbox);
- mail_namespaces_deinit(&client->namespaces);
+ mail_user_deinit(&client->user);
if (client->free_parser != NULL)
imap_parser_destroy(&client->free_parser);
@@ -182,21 +252,47 @@
}
pool_unref(&client->command_pool);
+
+ /* APPLE */
+ for (pos = &clients; *pos != NULL; pos = &(*pos)->next) {
+ if (*pos == client) {
+ *pos = client->next;
+ break;
+ }
+ }
+ io_env_clean();
+ connection_id = client->connection_id;
+
i_free(client);
- /* quit the program */
- my_client = NULL;
- io_loop_stop(ioloop);
+ if (process_per_connection) { /* APPLE */
+ /* quit the program */
+ i_assert(clients == NULL);
+ io_loop_stop(ioloop);
+ } else {
+ /* (APPLE) run until master says stop, or can't say stop
+ and there are no more clients. otherwise there's a
+ race if there's an incoming request from the master. */
+ if (!master_send_disconnect(connection_id) &&
+ clients == NULL)
+ io_loop_stop(ioloop);
+ }
}
void client_disconnect(struct client *client, const char *reason)
{
+ const char *prefix; /* APPLE */
+
i_assert(reason != NULL);
if (client->disconnected)
return;
- i_info("Disconnected: %s %s", reason, client_stats(client));
+ /* APPLE */
+ prefix = process_per_connection ? "" :
+ t_strconcat("User ", client->user->username, ": ", NULL);
+ i_info("%sDisconnected: %s %s", prefix, reason, client_stats(client));
+
client->disconnected = TRUE;
(void)o_stream_flush(client->output);
@@ -809,15 +905,51 @@
}
}
-void clients_init(void)
+void clients_init(bool persistent_mail_process) /* APPLE */
{
- my_client = NULL;
+ clients = NULL;
+ process_per_connection = !persistent_mail_process; /* APPLE */
}
void clients_deinit(void)
{
- if (my_client != NULL) {
- client_send_line(my_client, "* BYE Server shutting down.");
- client_destroy(my_client, "Server shutting down");
+ struct client *next;
+
+ /* APPLE */
+ while (clients != NULL) {
+ next = clients->next;
+ client_send_line(clients, "* BYE Server shutting down.");
+ client_destroy(clients, "Server shutting down");
+ clients = next;
+ }
+}
+
+/* APPLE */
+bool clients_connected(void)
+{
+ return clients != NULL;
+}
+
+/* APPLE */
+void clients_info(string_t *str)
+{
+ struct client *client;
+ int n;
+
+ n = 0;
+ for (client = clients; client != NULL; client = client->next)
+ ++n;
+
+ str_printfa(str, "%d connected user%s", n, n == 1 ? "" : "s");
+
+ if (n > 0) {
+ str_append(str, " (");
+ n = 0;
+ for (client = clients; client != NULL; client = client->next) {
+ if (n++ > 0)
+ str_append(str, ", ");
+ str_append(str, client->user->username);
+ }
+ str_append_c(str, ')');
}
}
diff -Nur dovecot-1.1.7+patch9/src/imap/client.h dovecot-patch/src/imap/client.h
--- dovecot-1.1.7+patch9/src/imap/client.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/imap/client.h 2009-01-06 10:08:19.000000000 -0600
@@ -56,14 +56,28 @@
unsigned int temp_executed:1; /* temporary execution state tracking */
};
+/* APPLE moved from imap-fetch-body.c */
+#include "message-size.h"
+struct partial_cache {
+ unsigned int select_counter;
+ unsigned int uid;
+
+ uoff_t physical_start;
+ bool cr_skipped;
+ struct message_size pos;
+};
+
struct client {
+ struct client *next; /* APPLE */
+ unsigned int connection_id; /* APPLE */
+
int fd_in, fd_out;
struct io *io;
struct istream *input;
struct ostream *output;
struct timeout *to_idle, *to_idle_output;
- struct mail_namespace *namespaces;
+ struct mail_user *user;
struct mailbox *mailbox;
struct mailbox_keywords keywords;
unsigned int select_counter; /* increased when mailbox is changed */
@@ -84,6 +98,9 @@
struct client_command_context *input_lock;
struct client_command_context *output_lock;
+ /* APPLE made per-client, was global */
+ struct partial_cache last_partial;
+
/* syncing marks this TRUE when it sees \Deleted flags. this is by
EXPUNGE for Outlook-workaround. */
unsigned int sync_seen_deletes:1;
@@ -96,10 +113,9 @@
found a new line */
};
-/* Create new client with specified input/output handles. socket specifies
- if the handle is a socket. */
-struct client *client_create(int fd_in, int fd_out,
- struct mail_namespace *namespaces);
+/* Create new client with specified input/output handles.
+ APPLE was client_create() */
+bool client_attach(int fd_in, int fd_out, bool is_standalone);
void client_destroy(struct client *client, const char *reason);
/* Disconnect client connection */
@@ -125,8 +141,10 @@
bool client_read_string_args(struct client_command_context *cmd,
unsigned int count, ...);
-void clients_init(void);
+void clients_init(bool persistent_mail_process); /* APPLE */
void clients_deinit(void);
+bool clients_connected(void); /* APPLE */
+void clients_info(string_t *str); /* APPLE */
void client_command_cancel(struct client_command_context **cmd);
void client_command_free(struct client_command_context **cmd);
diff -Nur dovecot-1.1.7+patch9/src/imap/cmd-list.c dovecot-patch/src/imap/cmd-list.c
--- dovecot-1.1.7+patch9/src/imap/cmd-list.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/imap/cmd-list.c 2009-01-06 10:08:19.000000000 -0600
@@ -185,7 +185,7 @@
}
/* find the INBOX flags */
- ns = mail_namespace_find_inbox(ctx->cmd->client->namespaces);
+ ns = mail_namespace_find_inbox(ctx->cmd->client->user->namespaces);
list_iter = mailbox_list_iter_init(ns->list, "INBOX", 0);
info = mailbox_list_iter_next(list_iter);
if (info != NULL) {
@@ -738,13 +738,13 @@
/* Special request to return the hierarchy delimiter and mailbox root
name. If namespace has a prefix, it's returned as the mailbox root.
Otherwise we'll emulate UW-IMAP behavior. */
- ns = mail_namespace_find_visible(client->namespaces, &ref);
+ ns = mail_namespace_find_visible(client->user->namespaces, &ref);
if (ns != NULL) {
ns_prefix = ns->prefix;
ns_sep = ns->sep;
} else {
ns_prefix = "";
- ns_sep = mail_namespace_get_root_sep(client->namespaces);
+ ns_sep = mail_namespace_get_root_sep(client->user->namespaces);
}
str = t_str_new(64);
@@ -788,7 +788,7 @@
ctx = p_new(cmd->pool, struct cmd_list_context, 1);
ctx->cmd = cmd;
- ctx->ns = client->namespaces;
+ ctx->ns = client->user->namespaces;
ctx->lsub = lsub;
cmd->context = ctx;
diff -Nur dovecot-1.1.7+patch9/src/imap/cmd-namespace.c dovecot-patch/src/imap/cmd-namespace.c
--- dovecot-1.1.7+patch9/src/imap/cmd-namespace.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/imap/cmd-namespace.c 2009-01-06 10:08:19.000000000 -0600
@@ -42,11 +42,11 @@
str = t_str_new(256);
str_append(str, "* NAMESPACE ");
- list_namespaces(client->namespaces, NAMESPACE_PRIVATE, str);
+ list_namespaces(client->user->namespaces, NAMESPACE_PRIVATE, str);
str_append_c(str, ' ');
- list_namespaces(client->namespaces, NAMESPACE_SHARED, str);
+ list_namespaces(client->user->namespaces, NAMESPACE_SHARED, str);
str_append_c(str, ' ');
- list_namespaces(client->namespaces, NAMESPACE_PUBLIC, str);
+ list_namespaces(client->user->namespaces, NAMESPACE_PUBLIC, str);
client_send_line(client, str_c(str));
client_send_tagline(cmd, "OK Namespace completed.");
diff -Nur dovecot-1.1.7+patch9/src/imap/cmd-subscribe.c dovecot-patch/src/imap/cmd-subscribe.c
--- dovecot-1.1.7+patch9/src/imap/cmd-subscribe.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/imap/cmd-subscribe.c 2009-01-06 10:08:19.000000000 -0600
@@ -35,7 +35,7 @@
return FALSE;
verify_name = mailbox;
- ns = mail_namespace_find_subscribable(cmd->client->namespaces,
+ ns = mail_namespace_find_subscribable(cmd->client->user->namespaces,
&mailbox);
if (ns == NULL) {
client_send_tagline(cmd, "NO Unknown namespace.");
@@ -49,7 +49,7 @@
verify_name = t_strndup(verify_name, strlen(verify_name)-1);
}
- if (have_listable_namespace_prefix(cmd->client->namespaces,
+ if (have_listable_namespace_prefix(cmd->client->user->namespaces,
verify_name)) {
/* subscribing to a listable namespace prefix, allow it. */
} else {
diff -Nur dovecot-1.1.7+patch9/src/imap/commands-util.c dovecot-patch/src/imap/commands-util.c
--- dovecot-1.1.7+patch9/src/imap/commands-util.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/imap/commands-util.c 2009-01-06 10:08:19.000000000 -0600
@@ -23,7 +23,7 @@
{
struct mail_namespace *ns;
- ns = mail_namespace_find(cmd->client->namespaces, mailbox);
+ ns = mail_namespace_find(cmd->client->user->namespaces, mailbox);
if (ns != NULL)
return ns;
diff -Nur dovecot-1.1.7+patch9/src/imap/imap-fetch-body.c dovecot-patch/src/imap/imap-fetch-body.c
--- dovecot-1.1.7+patch9/src/imap/imap-fetch-body.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/imap/imap-fetch-body.c 2009-01-06 10:08:19.000000000 -0600
@@ -32,16 +32,7 @@
unsigned int peek:1;
};
-struct partial_cache {
- unsigned int select_counter;
- unsigned int uid;
-
- uoff_t physical_start;
- bool cr_skipped;
- struct message_size pos;
-};
-
-static struct partial_cache last_partial = { 0, 0, 0, 0, { 0, 0, 0 } };
+/* APPLE made last_partial per-client */
static bool seek_partial(unsigned int select_counter, unsigned int uid,
struct partial_cache *partial, struct istream *stream,
@@ -224,10 +215,11 @@
ctx->cur_offset += ret;
if (ctx->update_partial) {
- last_partial.cr_skipped = ctx->skip_cr != 0;
- last_partial.pos.physical_size =
- ctx->cur_input->v_offset - last_partial.physical_start;
- last_partial.pos.virtual_size += ret;
+ /* APPLE made last_partial per-client */
+ ctx->client->last_partial.cr_skipped = ctx->skip_cr != 0;
+ ctx->client->last_partial.pos.physical_size =
+ ctx->cur_input->v_offset - ctx->client->last_partial.physical_start;
+ ctx->client->last_partial.pos.virtual_size += ret;
}
return ctx->cur_offset == ctx->cur_size;
@@ -312,7 +304,8 @@
} else {
ctx->skip_cr =
seek_partial(ctx->select_counter, ctx->cur_mail->uid,
- &last_partial, ctx->cur_input, body->skip);
+ &ctx->client->last_partial, ctx->cur_input, body->skip);
+ /* APPLE made last_partial per-client */
}
return fetch_stream(ctx, size);
diff -Nur dovecot-1.1.7+patch9/src/imap/main.c dovecot-patch/src/imap/main.c
--- dovecot-1.1.7+patch9/src/imap/main.c 2008-11-15 11:33:28.000000000 -0600
+++ dovecot-patch/src/imap/main.c 2009-01-06 10:08:19.000000000 -0600
@@ -16,6 +16,8 @@
#include "commands.h"
#include "mail-namespace.h"
#include "imap-thread.h"
+#include "master.h" /* APPLE */
+#include "env-util.h" /* APPLE */
#include <stdio.h>
#include <stdlib.h>
@@ -25,6 +27,9 @@
#define IS_STANDALONE() \
(getenv("LOGGED_IN") == NULL && getenv("IMAPLOGINTAG") == NULL)
+/* APPLE */
+#define IS_PERSISTENT() (getenv("PERSISTENT_MAIL_PROCESS") != NULL)
+
struct client_workaround_list {
const char *name;
enum client_workarounds num;
@@ -46,7 +51,6 @@
static struct io *log_io = NULL;
static struct module *modules = NULL;
static char log_prefix[128]; /* syslog() needs this to be permanent */
-static pool_t namespace_pool;
void (*hook_client_created)(struct client **client) = NULL;
@@ -61,6 +65,21 @@
io_loop_stop(ioloop);
}
+/* APPLE */
+#ifdef SIGINFO
+static void sig_info(int signo ATTR_UNUSED, void *context ATTR_UNUSED)
+{
+ string_t *msg;
+
+ msg = t_str_new(512);
+ clients_info(msg);
+ str_append(msg, "; ");
+ master_info(msg);
+
+ i_info("IMAP process %d: %s", getpid(), str_c(msg));
+}
+#endif
+
static void log_error_callback(void *context ATTR_UNUSED)
{
io_loop_stop(ioloop);
@@ -162,9 +181,8 @@
static void main_init(void)
{
- struct client *client;
- struct mail_namespace *ns;
const char *user, *str;
+ int fd_in, fd_out; /* APPLE */
lib_signals_init();
lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
@@ -178,6 +196,7 @@
user = getlogin();
if (user == NULL)
i_fatal("USER environment missing");
+ env_put(i_strconcat("USER=", user, NULL)); /* APPLE */
}
if (getenv("DEBUG") != NULL) {
@@ -202,9 +221,17 @@
mail_storage_init();
mail_storage_register_all();
mailbox_list_register_all();
- clients_init();
+ clients_init(IS_PERSISTENT()); /* APPLE */
commands_init();
+ /* APPLE */
+ master_init(IS_PERSISTENT() ? 0 : -1,
+ ioloop, client_attach, clients_connected);
+#ifdef SIGINFO
+ if (IS_PERSISTENT())
+ lib_signals_set_handler(SIGINFO, TRUE, sig_info, NULL);
+#endif
+
module_dir_init(modules);
if (getenv("DUMP_CAPABILITY") != NULL) {
@@ -230,27 +257,22 @@
parse_workarounds();
- namespace_pool = pool_alloconly_create("namespaces", 1024);
- if (mail_namespaces_init(namespace_pool, user, &ns) < 0)
- i_fatal("Namespace initialization failed");
- client = client_create(0, 1, ns);
-
- o_stream_cork(client->output);
- if (IS_STANDALONE()) {
- client_send_line(client, t_strconcat(
- "* PREAUTH [CAPABILITY ",
- str_c(capability_string), "] "
- "Logged in as ", user, NULL));
- } else if (getenv("IMAPLOGINTAG") != NULL) {
- /* Support for mailfront */
- client_send_line(client, t_strconcat(getenv("IMAPLOGINTAG"),
- " OK Logged in.", NULL));
+ /* APPLE */
+ if (IS_PERSISTENT())
+ fd_in = fd_out = 3;
+ else {
+ fd_in = 0;
+ fd_out = 1;
}
- o_stream_uncork(client->output);
+
+ if (!client_attach(fd_in, fd_out, IS_STANDALONE()))
+ i_fatal("Failed to initialize for client");
}
static void main_deinit(void)
{
+ master_deinit(); /* APPLE */
+
if (log_io != NULL)
io_remove(&log_io);
clients_deinit();
@@ -260,7 +282,6 @@
mail_storage_deinit();
dict_driver_unregister(&dict_driver_client);
random_deinit();
- pool_unref(&namespace_pool);
str_free(&capability_string);
@@ -271,8 +292,10 @@
int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
{
#ifdef DEBUG
- if (getenv("LOGGED_IN") != NULL && getenv("GDB") == NULL)
- fd_debug_verify_leaks(3, 1024);
+ if (getenv("LOGGED_IN") != NULL && getenv("GDB") == NULL) {
+ int base = IS_PERSISTENT() ? 4 : 3; /* APPLE */
+ fd_debug_verify_leaks(base, 1024);
+ }
#endif
if (IS_STANDALONE() && getuid() == 0 &&
net_getpeername(1, NULL, NULL) == 0) {
@@ -286,6 +309,10 @@
lib_init();
drop_privileges();
+ /* APPLE */
+ if (IS_PERSISTENT())
+ io_env_enable();
+
process_title_init(argv, envp);
ioloop = io_loop_create();
diff -Nur dovecot-1.1.7+patch9/src/lib/env-util.c dovecot-patch/src/lib/env-util.c
--- dovecot-1.1.7+patch9/src/lib/env-util.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/env-util.c 2009-01-06 10:08:19.000000000 -0600
@@ -5,35 +5,141 @@
#include <stdlib.h>
+extern char **environ; /* APPLE */
+
static pool_t pool = NULL;
+static bool use_private_environ; /* APPLE */
+static int private_environ_alloc; /* APPLE */
+static int private_environ_used; /* APPLE */
+
+/* APPLE - Home grown version of putenv that allocates only from the
+ environment pool. Mixing putenv() with env_clean() leaks heap. */
+static int private_putenv(char *env)
+{
+ char *eq;
+ size_t cmplen;
+ char **epp;
+
+ if ((eq = strchr(env, '=')) == NULL || eq == env) {
+ errno = EINVAL;
+ return -1;
+ }
+ cmplen = eq - env + 1;
+
+ /* remove all matching keys from environ */
+ epp = environ;
+ while (*epp) {
+ if (strncmp(*epp, env, cmplen) == 0) {
+ /* found a match, remove it */
+ char **xpp = epp;
+ p_free(pool, *xpp);
+ do
+ *xpp = *(xpp + 1);
+ while (*xpp++);
+ --private_environ_used;
+
+ /* be defensive: keep looking */
+ } else
+ ++epp;
+ }
+
+ /* make room for the new entry */
+ if (private_environ_used >= private_environ_alloc) {
+ int new_alloc = private_environ_used + 10;
+ char **new_environ = p_realloc(pool, environ,
+ private_environ_alloc * sizeof *environ,
+ new_alloc * sizeof *environ);
+ if (new_environ == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ environ = new_environ;
+ private_environ_alloc = new_alloc;
+ }
+
+ /* append the entry */
+ i_assert(private_environ_used > 0);
+ epp = &environ[private_environ_used++ - 1];
+ i_assert(*epp == NULL);
+ *epp++ = env;
+ *epp = NULL;
+
+ return 0;
+}
void env_put(const char *env)
{
+ int error; /* APPLE */
+
if (pool == NULL) {
pool = pool_alloconly_create(MEMPOOL_GROWING"Environment",
- 2048);
+ 4096); /* APPLE */
}
- if (putenv(p_strdup(pool, env)) != 0)
+
+ /* APPLE */
+ error = use_private_environ ? private_putenv(p_strdup(pool, env)) :
+ putenv(p_strdup(pool, env));
+ if (error != 0)
i_fatal("putenv(%s) failed: %m", env);
}
void env_clean(void)
{
-#ifdef HAVE_CLEARENV
- if (clearenv() < 0)
- i_fatal("clearenv() failed");
-#else
- extern char **environ;
-
- /* Try to clear the environment.
-
- a) environ = NULL crashes on OS X.
- b) *environ = NULL doesn't work on FreeBSD 7.0.
- c) environ = emptyenv doesn't work on Haiku OS
- d) environ = calloc() should work everywhere
- */
- environ = calloc(1, sizeof(*environ));
-#endif
- /* don't clear the env_pool, otherwise the environment would get
- corrupted if we failed to clear it. */
+ env_clean_private(FALSE); /* APPLE */
+}
+
+void env_clean_private(bool private_env) /* APPLE */
+{
+ /* APPLE - clean environ without clobbering what it currently
+ points to because we will need it later */
+
+ if (pool != NULL)
+ pool_unref(&pool);
+
+ pool = pool_alloconly_create("Environment", 4096);
+ use_private_environ = private_env;
+ private_environ_alloc = private_env ? 100 : 1;
+ private_environ_used = 1;
+ environ = p_new(pool, char *, private_environ_alloc);
+ *environ = NULL;
+}
+
+/* APPLE - rest of file */
+
+static char **env_dup(pool_t p, char * const *env)
+{
+ char * const *end;
+ char **copy, **to;
+
+ for (end = env; *end != NULL; ++end)
+ ;
+
+ copy = p_new(p, char *, end - env + 1);
+ for (to = copy; env != end; ++to, ++env)
+ *to = p_strdup(p, *env);
+ *to = NULL;
+
+ return copy;
+}
+
+char **env_capture(pool_t p)
+{
+ return env_dup(p, environ);
+}
+
+void env_switch(pool_t newpool, char **newenv)
+{
+ /* this doesn't switch private_environ_{alloc,used} */
+ i_assert(!use_private_environ);
+
+ if (environ == newenv)
+ return;
+
+ if (pool != NULL)
+ pool_unref(&pool);
+
+ pool = newpool;
+ environ = newenv;
+
+ pool_ref(pool);
}
diff -Nur dovecot-1.1.7+patch9/src/lib/env-util.h dovecot-patch/src/lib/env-util.h
--- dovecot-1.1.7+patch9/src/lib/env-util.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/env-util.h 2009-01-06 10:08:19.000000000 -0600
@@ -6,5 +6,13 @@
void env_put(const char *env);
/* Clear all environment variables. */
void env_clean(void);
+/* (APPLE) Clean the environment and allocate all future environment strings
+ from a private pool (until the next env_clean*() call). */
+void env_clean_private(bool private_env);
+
+/* (APPLE) Clone the environment */
+char **env_capture(pool_t pool);
+/* (APPLE) Replace environ with env */
+void env_switch(pool_t envpool, char **env);
#endif
diff -Nur dovecot-1.1.7+patch9/src/lib/ioloop-epoll.c dovecot-patch/src/lib/ioloop-epoll.c
--- dovecot-1.1.7+patch9/src/lib/ioloop-epoll.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/ioloop-epoll.c 2009-01-06 10:08:19.000000000 -0600
@@ -200,6 +200,7 @@
if (call) {
t_id = t_push();
+ io_env_switch(&io->io.env); /* APPLE */
io->io.callback(io->io.context);
if (t_pop() != t_id) {
i_panic("Leaked a t_pop() call in "
diff -Nur dovecot-1.1.7+patch9/src/lib/ioloop-internal.h dovecot-patch/src/lib/ioloop-internal.h
--- dovecot-1.1.7+patch9/src/lib/ioloop-internal.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/ioloop-internal.h 2009-01-06 10:08:19.000000000 -0600
@@ -3,6 +3,7 @@
#include "priorityq.h"
#include "ioloop.h"
+#include "restrict-access.h" /* APPLE */
#ifndef IOLOOP_INITIAL_FD_COUNT
# define IOLOOP_INITIAL_FD_COUNT 128
@@ -21,11 +22,20 @@
unsigned int running:1;
};
+/* APPLE */
+struct io_env {
+ pool_t pool;
+ char **env;
+ struct restrict_access_cred cred;
+};
+
struct io {
enum io_condition condition;
io_callback_t *callback;
void *context;
+
+ struct io_env env; /* APPLE */
};
struct io_file {
@@ -46,6 +56,8 @@
timeout_callback_t *callback;
void *context;
+
+ struct io_env env; /* APPLE */
};
int io_loop_get_wait_time(struct ioloop *ioloop, struct timeval *tv_r,
@@ -63,4 +75,9 @@
void io_loop_notify_remove(struct ioloop *ioloop, struct io *io);
void io_loop_notify_handler_deinit(struct ioloop *ioloop);
+/* (APPLE) I/O environment switching */
+void io_env_init(struct io_env *env);
+void io_env_switch(struct io_env *env);
+void io_env_deinit(struct io_env *env);
+
#endif
diff -Nur dovecot-1.1.7+patch9/src/lib/ioloop-kqueue.c dovecot-patch/src/lib/ioloop-kqueue.c
--- dovecot-1.1.7+patch9/src/lib/ioloop-kqueue.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/ioloop-kqueue.c 2009-01-06 10:08:19.000000000 -0600
@@ -147,6 +147,7 @@
/* callback is NULL if io_remove() was already called */
if (io->io.callback != NULL) {
t_id = t_push();
+ io_env_switch(&io->io.env); /* APPLE */
io->io.callback(io->io.context);
if (t_pop() != t_id) {
i_panic("Leaked a t_pop() call in "
diff -Nur dovecot-1.1.7+patch9/src/lib/ioloop-notify-dn.c dovecot-patch/src/lib/ioloop-notify-dn.c
--- dovecot-1.1.7+patch9/src/lib/ioloop-notify-dn.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/ioloop-notify-dn.c 2009-01-06 10:08:19.000000000 -0600
@@ -86,8 +86,10 @@
for (i = 0; i < ret; i++) {
io = io_notify_fd_find(&ctx->fd_ctx, fd_buf[i]);
- if (io != NULL)
+ if (io != NULL) {
+ io_env_switch(&io->io.env); /* APPLE */
io->io.callback(io->io.context);
+ }
}
}
diff -Nur dovecot-1.1.7+patch9/src/lib/ioloop-notify-fd.c dovecot-patch/src/lib/ioloop-notify-fd.c
--- dovecot-1.1.7+patch9/src/lib/ioloop-notify-fd.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/ioloop-notify-fd.c 2009-01-06 10:08:19.000000000 -0600
@@ -15,6 +15,7 @@
io->io.condition = IO_NOTIFY;
io->io.callback = callback;
io->io.context = context;
+ io_env_init(&io->io.env); /* APPLE */
io->fd = fd;
if (ctx->notifies != NULL) {
diff -Nur dovecot-1.1.7+patch9/src/lib/ioloop-notify-inotify.c dovecot-patch/src/lib/ioloop-notify-inotify.c
--- dovecot-1.1.7+patch9/src/lib/ioloop-notify-inotify.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/ioloop-notify-inotify.c 2009-01-06 10:08:19.000000000 -0600
@@ -69,6 +69,7 @@
EINVAL */
io->fd = -1;
}
+ io_env_switch(&io->io.env); /* APPLE */
io->io.callback(io->io.context);
}
}
diff -Nur dovecot-1.1.7+patch9/src/lib/ioloop-notify-kqueue.c dovecot-patch/src/lib/ioloop-notify-kqueue.c
--- dovecot-1.1.7+patch9/src/lib/ioloop-notify-kqueue.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/ioloop-notify-kqueue.c 2009-01-06 10:08:19.000000000 -0600
@@ -70,8 +70,10 @@
io = (void *)events[i].udata;
/* there can be multiple events for a single io.
call the callback only once if that happens. */
- if (io->refcount == 2 && io->io.callback != NULL)
+ if (io->refcount == 2 && io->io.callback != NULL) {
+ io_env_switch(&io->io.env); /* APPLE */
io->io.callback(io->io.context);
+ }
if (--io->refcount == 0)
i_free(io);
@@ -130,6 +132,7 @@
io->io.condition = IO_NOTIFY;
io->io.callback = callback;
io->io.context = context;
+ io_env_init(&io->io.env); /* APPLE */
io->refcount = 1;
io->fd = fd;
diff -Nur dovecot-1.1.7+patch9/src/lib/ioloop-poll.c dovecot-patch/src/lib/ioloop-poll.c
--- dovecot-1.1.7+patch9/src/lib/ioloop-poll.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/ioloop-poll.c 2009-01-06 10:08:19.000000000 -0600
@@ -201,6 +201,7 @@
if (call) {
t_id = t_push();
+ io_env_switch(&io->io.env); /* APPLE */
io->io.callback(io->io.context);
if (t_pop() != t_id) {
i_panic("Leaked a t_pop() call in "
diff -Nur dovecot-1.1.7+patch9/src/lib/ioloop-select.c dovecot-patch/src/lib/ioloop-select.c
--- dovecot-1.1.7+patch9/src/lib/ioloop-select.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/ioloop-select.c 2009-01-06 10:08:19.000000000 -0600
@@ -139,6 +139,7 @@
ret--;
t_id = t_push();
+ io_env_switch(&io->io.env); /* APPLE */
io->io.callback(io->io.context);
if (t_pop() != t_id) {
i_panic("Leaked a t_pop() call in "
diff -Nur dovecot-1.1.7+patch9/src/lib/ioloop.c dovecot-patch/src/lib/ioloop.c
--- dovecot-1.1.7+patch9/src/lib/ioloop.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/ioloop.c 2009-01-06 10:08:19.000000000 -0600
@@ -2,6 +2,7 @@
#include "lib.h"
#include "ioloop-internal.h"
+#include "env-util.h" /* APPLE */
#include <unistd.h>
@@ -33,6 +34,7 @@
io->io.condition = condition;
io->io.callback = callback;
io->io.context = context;
+ io_env_init(&io->io.env); /* APPLE */
io->refcount = 1;
io->fd = fd;
@@ -75,6 +77,7 @@
/* make sure the callback doesn't get called anymore.
kqueue code relies on this. */
io->callback = NULL;
+ io_env_deinit(&io->env); /* APPLE */
if ((io->condition & IO_NOTIFY) != 0)
io_loop_notify_remove(current_ioloop, io);
@@ -132,6 +135,7 @@
timeout->callback = callback;
timeout->context = context;
+ io_env_init(&timeout->env); /* APPLE */
timeout_update_next(timeout, current_ioloop->running ?
NULL : &ioloop_timeval);
@@ -144,6 +148,7 @@
struct timeout *timeout = *_timeout;
*_timeout = NULL;
+ io_env_deinit(&timeout->env); /* APPLE */
priorityq_remove(current_ioloop->timeouts, &timeout->item);
i_free(timeout);
}
@@ -295,6 +300,7 @@
timeout_reset_timeval(timeout, &tv_call);
t_id = t_push();
+ io_env_switch(&timeout->env); /* APPLE */
timeout->callback(timeout->context);
if (t_pop() != t_id) {
i_panic("Leaked a t_pop() call in timeout handler %p",
@@ -375,6 +381,7 @@
struct timeout *to = (struct timeout *)item;
i_warning("Timeout leak: %p", (void *)to->callback);
+ io_env_deinit(&to->env); /* APPLE */
i_free(to);
}
priorityq_deinit(&ioloop->timeouts);
@@ -388,3 +395,51 @@
i_free(ioloop);
}
+
+/* APPLE - rest of file */
+
+static bool io_env_enabled = FALSE;
+
+void io_env_enable(void)
+{
+ i_assert(current_ioloop == NULL);
+
+ io_env_enabled = TRUE;
+}
+
+void io_env_init(struct io_env *env)
+{
+ if (!io_env_enabled)
+ return;
+
+ env->pool = pool_alloconly_create("io_env", 8192);
+ env->env = env_capture(env->pool);
+ restrict_access_cred_init(&env->cred);
+}
+
+void io_env_switch(struct io_env *env)
+{
+ if (!io_env_enabled)
+ return;
+
+ env_switch(env->pool, env->env);
+ restrict_access_cred_switch(&env->cred);
+}
+
+void io_env_clean(void)
+{
+ if (!io_env_enabled)
+ return;
+
+ env_clean();
+ restrict_access_cred_clean();
+}
+
+void io_env_deinit(struct io_env *env)
+{
+ if (!io_env_enabled)
+ return;
+
+ pool_unref(&env->pool);
+ restrict_access_cred_deinit(&env->cred);
+}
diff -Nur dovecot-1.1.7+patch9/src/lib/ioloop.h dovecot-patch/src/lib/ioloop.h
--- dovecot-1.1.7+patch9/src/lib/ioloop.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/ioloop.h 2009-01-06 10:08:19.000000000 -0600
@@ -91,4 +91,8 @@
/* Destroy I/O loop and set ioloop pointer to NULL. */
void io_loop_destroy(struct ioloop **ioloop);
+/* (APPLE) I/O environment switching */
+void io_env_enable(void);
+void io_env_clean(void);
+
#endif
diff -Nur dovecot-1.1.7+patch9/src/lib/network.c dovecot-patch/src/lib/network.c
--- dovecot-1.1.7+patch9/src/lib/network.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/network.c 2009-01-06 10:08:19.000000000 -0600
@@ -272,6 +272,12 @@
#endif
}
+/* APPLE */
+int net_set_sndbuf(int fd, int size)
+{
+ return setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof size);
+}
+
void net_get_ip_any4(struct ip_addr *ip)
{
ip->family = AF_INET;
diff -Nur dovecot-1.1.7+patch9/src/lib/network.h dovecot-patch/src/lib/network.h
--- dovecot-1.1.7+patch9/src/lib/network.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/network.h 2009-01-06 10:08:19.000000000 -0600
@@ -57,6 +57,8 @@
/* Set TCP_CORK if supported, ie. don't send out partial frames.
Returns 0 if ok, -1 if failed. */
int net_set_cork(int fd, bool cork);
+/* (APPLE) Set socket send buffer size. */
+int net_set_sndbuf(int fd, int size);
/* Set IP to contain INADDR_ANY for IPv4 or IPv6. The IPv6 any address may
include IPv4 depending on the system (Linux yes, BSD no). */
diff -Nur dovecot-1.1.7+patch9/src/lib/restrict-access.c dovecot-patch/src/lib/restrict-access.c
--- dovecot-1.1.7+patch9/src/lib/restrict-access.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/restrict-access.c 2009-01-06 11:31:00.000000000 -0600
@@ -13,23 +13,55 @@
#include <time.h>
#include <grp.h>
-static gid_t process_primary_gid = (gid_t)-1;
+/* APPLE significant refactoring around global state variables.
+ process_primary_gid and process_using_priv_gid folded into struct
+ restrict_access_cred. */
+
+static struct restrict_access_cred global_cred;
+static struct restrict_access_cred *current_cred;
+static bool allow_switching;
+
static gid_t process_privileged_gid = (gid_t)-1;
-static bool process_using_priv_gid = FALSE;
+
+/* APPLE */
+static void restrict_access_init(void)
+{
+ size_t i;
+
+ global_cred.uid = (uid_t) -1;
+ global_cred.gid = (gid_t) -1;
+ global_cred.ngroups = 0;
+ for (i = 0; i < N_ELEMENTS(global_cred.gidset); i++)
+ global_cred.gidset[i] = (gid_t) -1;
+ global_cred.primary_gid = (gid_t) -1;
+ global_cred.using_priv_gid = FALSE;
+
+ current_cred = &global_cred;
+ allow_switching = FALSE;
+}
void restrict_access_set_env(const char *user, uid_t uid,
gid_t gid, gid_t privileged_gid,
const char *chroot_dir,
gid_t first_valid_gid, gid_t last_valid_gid,
- const char *extra_groups)
+ const char *extra_groups,
+ bool lenient) /* APPLE */
{
if (user != NULL && *user != '\0')
env_put(t_strconcat("RESTRICT_USER=", user, NULL));
if (chroot_dir != NULL && *chroot_dir != '\0')
env_put(t_strconcat("RESTRICT_CHROOT=", chroot_dir, NULL));
+ if (lenient) /* APPLE */
+ env_put(t_strdup_printf("ADVISE_SETUID=%s", dec2str(uid)));
+ else /* APPLE reduce code deltas */
env_put(t_strdup_printf("RESTRICT_SETUID=%s", dec2str(uid)));
+
+ if (lenient) /* APPLE */
+ env_put(t_strdup_printf("ADVISE_SETGID=%s", dec2str(gid)));
+ else /* APPLE reduce code deltas */
env_put(t_strdup_printf("RESTRICT_SETGID=%s", dec2str(gid)));
+
if (privileged_gid != (gid_t)-1) {
env_put(t_strdup_printf("RESTRICT_SETGID_PRIV=%s",
dec2str(privileged_gid)));
@@ -158,11 +190,13 @@
const char *const *tmp, *empty = NULL;
unsigned int i, gid_count;
bool add_primary_gid;
+ gid_t process_primary_gid; /* APPLE reduce code deltas */
/* if we're using a privileged GID, we can temporarily drop our
effective GID. we still want to be able to use its privileges,
so add it to supplementary groups. */
add_primary_gid = process_privileged_gid != (gid_t)-1;
+ process_primary_gid = global_cred.primary_gid; /* APPLE */
tmp = extra_groups == NULL ? &empty :
t_strsplit_spaces(extra_groups, ", ");
@@ -217,15 +251,40 @@
void restrict_access_by_env(bool disallow_root)
{
+ const char *restrict_setgid, *advise_setgid; /* APPLE */
+ const char *restrict_setuid, *advise_setuid; /* APPLE */
const char *env;
uid_t uid;
bool is_root, have_root_group, preserve_groups = FALSE;
bool allow_root_gid;
+ gid_t process_primary_gid; /* APPLE reduce code deltas */
+
+ /* APPLE */
+ if (current_cred == NULL)
+ restrict_access_init();
is_root = geteuid() == 0;
+ /* APPLE */
+ restrict_setgid = getenv("RESTRICT_SETGID");
+ advise_setgid = getenv("ADVISE_SETGID");
+ restrict_setuid = getenv("RESTRICT_SETUID");
+ advise_setuid = getenv("ADVISE_SETUID");
+
+ /* APPLE */
+ allow_switching =
+ restrict_setgid == NULL && restrict_setuid == NULL &&
+ advise_setgid != NULL && advise_setuid != NULL;
+ if (allow_switching && !is_root) {
+ if (seteuid(0) < 0)
+ i_fatal("seteuid(0) to allow switching failed "
+ "with uid=%u, euid=%u: %m",
+ getuid(), geteuid());
+ }
+ i_assert(!global_cred.using_priv_gid);
+
/* set the primary/privileged group */
- env = getenv("RESTRICT_SETGID");
+ env = restrict_setgid != NULL ? restrict_setgid : advise_setgid;
process_primary_gid = env == NULL || *env == '\0' ? (gid_t)-1 :
(gid_t)strtoul(env, NULL, 10);
env = getenv("RESTRICT_SETGID_PRIV");
@@ -237,6 +296,14 @@
process_privileged_gid != (gid_t)-1) {
if (process_primary_gid == (gid_t)-1)
process_primary_gid = getegid();
+
+ /* APPLE */
+ if (allow_switching) {
+ if (setgid(process_primary_gid) < 0)
+ i_fatal("setgid(%u) to allow switching failed "
+ "with euid=%u: %m",
+ process_primary_gid, geteuid());
+ } else /* APPLE reduce code deltas */
restrict_init_groups(process_primary_gid,
process_privileged_gid);
} else {
@@ -244,6 +311,10 @@
process_primary_gid = getegid();
}
+ /* APPLE */
+ global_cred.primary_gid = process_primary_gid;
+ global_cred.gid = process_primary_gid;
+
/* set system user's groups */
env = getenv("RESTRICT_USER");
if (env != NULL && *env != '\0' && is_root) {
@@ -261,6 +332,17 @@
fix_groups_list(env, preserve_groups, &have_root_group);
} T_END;
+ /* APPLE */
+ global_cred.ngroups = getgroups(N_ELEMENTS(global_cred.gidset),
+ global_cred.gidset);
+ if (global_cred.ngroups < 0)
+ i_fatal("getgroups() failed: %m");
+ else {
+ size_t i = global_cred.ngroups;
+ while (i < N_ELEMENTS(global_cred.gidset))
+ global_cred.gidset[i++] = (gid_t) -1;
+ }
+
/* chrooting */
env = getenv("RESTRICT_CHROOT");
if (env != NULL && *env != '\0') {
@@ -286,16 +368,32 @@
}
/* uid last */
- env = getenv("RESTRICT_SETUID");
+ env = restrict_setuid != NULL ? restrict_setuid : advise_setuid;
uid = env == NULL || *env == '\0' ? 0 : (uid_t)strtoul(env, NULL, 10);
if (uid != 0) {
+ /* APPLE */
+ if (allow_switching) {
+ if (seteuid(uid) < 0)
+ i_fatal("seteuid(%u) to allow switching failed "
+ "with uid=%u, euid=%u: %m",
+ uid, getuid(), geteuid());
+ } else /* APPLE reduce code deltas */
if (setuid(uid) != 0) {
i_fatal("setuid(%s) failed with euid=%s: %m",
dec2str(uid), dec2str(geteuid()));
}
}
+ /* APPLE */
+ global_cred.uid = uid;
+
/* verify that we actually dropped the privileges */
+
+ /* APPLE */
+ if (allow_switching) {
+ if (geteuid() == 0)
+ i_fatal("Running as user root isn't permitted");
+ } else /* APPLE reduce code deltas */
if (uid != 0 || disallow_root) {
if (setuid(0) == 0) {
if (uid == 0)
@@ -312,6 +410,11 @@
else
allow_root_gid = FALSE;
+ /* APPLE */
+ if (allow_switching) {
+ if (getgid() == 0 || getegid() == 0)
+ i_fatal("Running as group 0 isn't permitted");
+ } else /* APPLE reduce code deltas */
if (!allow_root_gid && uid != 0) {
if (getgid() == 0 || getegid() == 0 || setgid(0) == 0) {
if (process_primary_gid == 0)
@@ -323,15 +426,20 @@
}
}
+ /* APPLE */
+ current_cred = &global_cred;
+
/* clear the environment, so we don't fail if we get back here */
env_put("RESTRICT_USER=");
env_put("RESTRICT_CHROOT=");
env_put("RESTRICT_SETUID=");
+ env_put("ADVISE_SETUID="); /* APPLE */
if (process_privileged_gid == (gid_t)-1) {
/* if we're dropping privileges before executing and
a privileged group is set, the groups must be fixed
after exec */
env_put("RESTRICT_SETGID=");
+ env_put("ADVISE_SETGID="); /* APPLE */
env_put("RESTRICT_SETGID_PRIV=");
}
env_put("RESTRICT_SETEXTRAGROUPS=");
@@ -341,7 +449,12 @@
int restrict_access_use_priv_gid(void)
{
- i_assert(!process_using_priv_gid);
+ /* APPLE */
+ if (current_cred == NULL)
+ restrict_access_init();
+ i_assert(!allow_switching || current_cred != &global_cred);
+
+ i_assert(!current_cred->using_priv_gid);
if (process_privileged_gid == (gid_t)-1)
return 0;
@@ -349,21 +462,99 @@
i_error("setegid(privileged) failed: %m");
return -1;
}
- process_using_priv_gid = TRUE;
+ current_cred->using_priv_gid = TRUE;
return 0;
}
void restrict_access_drop_priv_gid(void)
{
- if (!process_using_priv_gid)
+ /* APPLE */
+ if (current_cred == NULL)
+ restrict_access_init();
+ i_assert(!allow_switching || current_cred != &global_cred);
+
+ if (!current_cred->using_priv_gid)
return;
- if (setegid(process_primary_gid) < 0)
+ if (setegid(current_cred->primary_gid) < 0)
i_fatal("setegid(primary) failed: %m");
- process_using_priv_gid = FALSE;
+ current_cred->using_priv_gid = FALSE;
}
bool restrict_access_have_priv_gid(void)
{
+ /* APPLE */
+ if (current_cred == NULL)
+ restrict_access_init();
+
return process_privileged_gid != (gid_t)-1;
}
+
+/* APPLE - rest of file */
+
+void restrict_access_cred_init(struct restrict_access_cred *cred)
+{
+ i_assert(cred != current_cred);
+
+ *cred = *current_cred;
+}
+
+void restrict_access_cred_switch(struct restrict_access_cred *cred)
+{
+ gid_t gid, current_gid;
+ bool switch_gid, switch_groups, switch_uid;
+
+ if (current_cred == cred)
+ return;
+
+ gid = cred->using_priv_gid ? process_privileged_gid : cred->primary_gid;
+ current_gid = current_cred->using_priv_gid ? process_privileged_gid : current_cred->primary_gid;
+ switch_gid = gid != current_gid;
+ switch_groups = cred->ngroups != current_cred->ngroups ||
+ memcmp(cred->gidset, current_cred->gidset,
+ cred->ngroups * sizeof cred->gidset[0]) != 0;
+ switch_uid = cred->uid != current_cred->uid;
+
+ if (switch_gid || switch_groups || switch_uid) {
+ if (seteuid(0) < 0)
+ i_fatal("seteuid(0) to switch cred failed "
+ "with uid=%u, euid=%u: %m",
+ getuid(), geteuid());
+ }
+ if (switch_gid) {
+ if (setegid(gid) < 0)
+ i_fatal("setegid(%u) failed with euid=%u: %m",
+ gid, geteuid());
+ }
+ if (switch_groups) {
+ if (setgroups(cred->ngroups, cred->gidset) < 0)
+ i_fatal("setgroups() failed with euid=%u: %m",
+ geteuid());
+ }
+ if (switch_gid || switch_groups || switch_uid) {
+ if (seteuid(cred->uid) < 0)
+ i_fatal("seteuid(%u) failed with uid=%u, euid=%u: %m",
+ cred->uid, getuid(), geteuid());
+ }
+
+ current_cred = cred;
+
+ if (getuid() != 0 || geteuid() != cred->uid || getegid() != gid)
+ i_panic("pid %d: restrict_access_cred_switch failed;"
+ " uid=%u euid=%u gid=%u egid=%u", getpid(), getuid(),
+ geteuid(), getgid(), getegid());
+}
+
+void restrict_access_cred_clean(void)
+{
+ restrict_access_cred_switch(&global_cred);
+}
+
+void restrict_access_cred_deinit(struct restrict_access_cred *cred)
+{
+ i_assert(cred != &global_cred);
+ if (current_cred == cred) {
+ global_cred = *cred;
+ current_cred = &global_cred;
+ }
+}
diff -Nur dovecot-1.1.7+patch9/src/lib/restrict-access.h dovecot-patch/src/lib/restrict-access.h
--- dovecot-1.1.7+patch9/src/lib/restrict-access.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib/restrict-access.h 2009-01-06 10:08:19.000000000 -0600
@@ -1,6 +1,16 @@
#ifndef RESTRICT_ACCESS_H
#define RESTRICT_ACCESS_H
+/* APPLE */
+struct restrict_access_cred {
+ uid_t uid;
+ gid_t gid;
+ int ngroups;
+ gid_t gidset[NGROUPS_MAX];
+ gid_t primary_gid;
+ unsigned int using_priv_gid:1;
+};
+
/* set environment variables so they can be read with
restrict_access_by_env(). If privileged_gid != (gid_t)-1,
the privileged GID can be temporarily enabled/disabled. */
@@ -8,7 +18,8 @@
gid_t gid, gid_t privileged_gid,
const char *chroot_dir,
gid_t first_valid_gid, gid_t last_valid_gid,
- const char *extra_groups);
+ const char *extra_groups,
+ bool lenient); /* APPLE */
/* chroot, setuid() and setgid() based on environment variables.
If disallow_roots is TRUE, we'll kill ourself if we didn't have the
@@ -22,4 +33,10 @@
/* Returns TRUE if privileged GID exists for this process. */
bool restrict_access_have_priv_gid(void);
+/* (APPLE) Credential switching */
+void restrict_access_cred_init(struct restrict_access_cred *cred);
+void restrict_access_cred_switch(struct restrict_access_cred *cred);
+void restrict_access_cred_clean(void);
+void restrict_access_cred_deinit(struct restrict_access_cred *cred);
+
#endif
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/Makefile.am dovecot-patch/src/lib-storage/Makefile.am
--- dovecot-1.1.7+patch9/src/lib-storage/Makefile.am 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib-storage/Makefile.am 2009-01-06 10:08:19.000000000 -0600
@@ -15,6 +15,7 @@
mail-namespace.c \
mail-search.c \
mail-storage.c \
+ mail-user.c \
mailbox-list.c \
mailbox-tree.c \
mailbox-uidvalidity.c
@@ -26,6 +27,7 @@
mail-search.h \
mail-storage.h \
mail-storage-private.h \
+ mail-user.h \
mailbox-list.h \
mailbox-list-private.h \
mailbox-tree.h \
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/index/cydir/cydir-storage.c dovecot-patch/src/lib-storage/index/cydir/cydir-storage.c
--- dovecot-1.1.7+patch9/src/lib-storage/index/cydir/cydir-storage.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib-storage/index/cydir/cydir-storage.c 2009-01-06 10:08:19.000000000 -0600
@@ -34,10 +34,10 @@
static int
cydir_get_list_settings(struct mailbox_list_settings *list_set,
- const char *data, enum mail_storage_flags flags,
+ const char *data, struct mail_storage *storage,
const char **layout_r, const char **error_r)
{
- bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
*layout_r = "fs";
@@ -55,8 +55,8 @@
if (debug)
i_info("cydir: data=%s", data);
- return mailbox_list_settings_parse(data, list_set, layout_r, NULL,
- error_r);
+ return mailbox_list_settings_parse(data, list_set, storage->ns,
+ layout_r, NULL, error_r);
}
static struct mail_storage *cydir_alloc(void)
@@ -80,7 +80,7 @@
struct stat st;
const char *layout;
- if (cydir_get_list_settings(&list_set, data, _storage->flags,
+ if (cydir_get_list_settings(&list_set, data, _storage,
&layout, error_r) < 0)
return -1;
list_set.mail_storage_flags = &_storage->flags;
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/index/dbox/dbox-storage.c dovecot-patch/src/lib-storage/index/dbox/dbox-storage.c
--- dovecot-1.1.7+patch9/src/lib-storage/index/dbox/dbox-storage.c 2008-11-15 10:34:22.000000000 -0600
+++ dovecot-patch/src/lib-storage/index/dbox/dbox-storage.c 2009-01-06 10:08:19.000000000 -0600
@@ -46,11 +46,11 @@
static int
dbox_get_list_settings(struct mailbox_list_settings *list_set,
- const char *data, enum mail_storage_flags flags,
+ const char *data, struct mail_storage *storage,
const char **layout_r, const char **alt_dir_r,
const char **error_r)
{
- bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
*layout_r = "fs";
@@ -68,8 +68,8 @@
if (debug)
i_info("dbox: data=%s", data);
- return mailbox_list_settings_parse(data, list_set, layout_r, alt_dir_r,
- error_r);
+ return mailbox_list_settings_parse(data, list_set, storage->ns,
+ layout_r, alt_dir_r, error_r);
}
static struct mail_storage *dbox_alloc(void)
@@ -93,7 +93,7 @@
struct stat st;
const char *layout, *alt_dir;
- if (dbox_get_list_settings(&list_set, data, _storage->flags,
+ if (dbox_get_list_settings(&list_set, data, _storage,
&layout, &alt_dir, error_r) < 0)
return -1;
list_set.mail_storage_flags = &_storage->flags;
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/index/maildir/maildir-storage.c dovecot-patch/src/lib-storage/index/maildir/maildir-storage.c
--- dovecot-1.1.7+patch9/src/lib-storage/index/maildir/maildir-storage.c 2008-11-15 10:47:56.000000000 -0600
+++ dovecot-patch/src/lib-storage/index/maildir/maildir-storage.c 2009-01-06 10:08:19.000000000 -0600
@@ -5,7 +5,6 @@
#include "array.h"
#include "hostpid.h"
#include "str.h"
-#include "home-expand.h"
#include "mkdir-parents.h"
#include "unlink-directory.h"
#include "unlink-old-files.h"
@@ -63,11 +62,13 @@
static int
maildir_get_list_settings(struct mailbox_list_settings *list_set,
- const char *data, enum mail_storage_flags flags,
+ const char *data, struct mail_storage *storage,
const char **layout_r, const char **error_r)
{
+ enum mail_storage_flags flags = storage->flags;
+ struct mail_user *user = storage->ns->user;
bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
- const char *home, *path;
+ const char *path;
*layout_r = MAILDIR_PLUSPLUS_DRIVER_NAME;
@@ -82,9 +83,9 @@
}
/* we'll need to figure out the maildir location ourself.
- It's $HOME/Maildir unless we are chrooted. */
- if ((home = getenv("HOME")) != NULL) {
- path = t_strconcat(home, "/Maildir", NULL);
+ It's ~/Maildir unless we are chrooted. */
+ if (user->home != NULL) {
+ path = t_strconcat(user->home, "/Maildir", NULL);
if (access(path, R_OK|W_OK|X_OK) == 0) {
if (debug) {
i_info("maildir: root exists (%s)",
@@ -99,7 +100,7 @@
}
} else {
if (debug)
- i_info("maildir: HOME not set");
+ i_info("maildir: Home directory not set");
}
if (access("/cur", R_OK|W_OK|X_OK) == 0) {
@@ -110,8 +111,8 @@
} else {
if (debug)
i_info("maildir: data=%s", data);
- if (mailbox_list_settings_parse(data, list_set, layout_r, NULL,
- error_r) < 0)
+ if (mailbox_list_settings_parse(data, list_set, storage->ns,
+ layout_r, NULL, error_r) < 0)
return -1;
}
@@ -194,7 +195,7 @@
const char *layout;
struct stat st;
- if (maildir_get_list_settings(&list_set, data, flags, &layout,
+ if (maildir_get_list_settings(&list_set, data, _storage, &layout,
error_r) < 0)
return -1;
list_set.mail_storage_flags = &_storage->flags;
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/index/mbox/mbox-save.c dovecot-patch/src/lib-storage/index/mbox/mbox-save.c
--- dovecot-1.1.7+patch9/src/lib-storage/index/mbox/mbox-save.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib-storage/index/mbox/mbox-save.c 2009-01-06 10:08:19.000000000 -0600
@@ -136,9 +136,11 @@
const char *line;
if (from_envelope == NULL) {
- from_envelope =
- t_strconcat(ctx->mbox->storage->storage.user,
- "@", my_hostdomain, NULL);
+ struct mail_storage *storage =
+ &ctx->mbox->storage->storage;
+
+ from_envelope = t_strconcat(storage->ns->user->username,
+ "@", my_hostdomain, NULL);
}
/* save in local timezone, no matter what it was given with */
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/index/mbox/mbox-storage.c dovecot-patch/src/lib-storage/index/mbox/mbox-storage.c
--- dovecot-1.1.7+patch9/src/lib-storage/index/mbox/mbox-storage.c 2008-11-15 09:52:45.000000000 -0600
+++ dovecot-patch/src/lib-storage/index/mbox/mbox-storage.c 2009-01-06 10:08:19.000000000 -0600
@@ -7,7 +7,6 @@
#include "restrict-access.h"
#include "mkdir-parents.h"
#include "unlink-directory.h"
-#include "home-expand.h"
#include "mbox-storage.h"
#include "mbox-lock.h"
#include "mbox-file.h"
@@ -186,12 +185,12 @@
return FALSE;
}
-static const char *get_root_dir(enum mail_storage_flags flags)
+static const char *get_root_dir(struct mail_storage *storage)
{
const char *home, *path;
- bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
- home = getenv("HOME");
+ home = storage->ns->user->home;
if (home != NULL) {
path = t_strconcat(home, "/mail", NULL);
if (access(path, R_OK|W_OK|X_OK) == 0) {
@@ -214,7 +213,7 @@
if (debug)
i_info("mbox: checking if we are chrooted:");
- if (mbox_autodetect("", flags))
+ if (mbox_autodetect("", storage->flags))
return "/";
if (debug)
@@ -224,11 +223,12 @@
}
static const char *
-get_inbox_file(const char *root_dir, bool only_root, bool debug)
+get_inbox_file(const char *user, const char *root_dir,
+ bool only_root, bool debug)
{
- const char *user, *path;
+ const char *path;
- if (!only_root && (user = getenv("USER")) != NULL) {
+ if (!only_root) {
path = t_strconcat("/var/mail/", user, NULL);
if (access(path, R_OK|W_OK) == 0) {
if (debug)
@@ -254,11 +254,12 @@
return path;
}
-static const char *create_root_dir(bool debug, const char **error_r)
+static const char *create_root_dir(struct mail_storage *storage,
+ const char **error_r)
{
const char *home, *path;
- home = getenv("HOME");
+ home = storage->ns->user->home;
if (home == NULL) {
*error_r = "Root mail directory not set and "
"home directory is missing";
@@ -271,16 +272,17 @@
return NULL;
}
- if (debug)
+ if ((storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0)
i_info("mbox: root directory created: %s", path);
return path;
}
static int
mbox_get_list_settings(struct mailbox_list_settings *list_set,
- const char *data, enum mail_storage_flags flags,
+ const char *data, struct mail_storage *storage,
const char **layout_r, const char **error_r)
{
+ enum mail_storage_flags flags = storage->flags;
bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
const char *p;
struct stat st;
@@ -301,8 +303,8 @@
/* we'll need to figure out the mail location ourself.
it's root dir if we've already chroot()ed, otherwise
- either $HOME/mail or $HOME/Mail */
- list_set->root_dir = get_root_dir(flags);
+ either ~/mail or ~/Mail */
+ list_set->root_dir = get_root_dir(storage);
} else {
if (debug)
i_info("mbox: data=%s", data);
@@ -310,11 +312,11 @@
if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) == 0 &&
p == NULL && data[strlen(data)-1] != '/') {
/* if the data points to a file, treat it as an INBOX */
- data = home_expand(data);
+ data = mail_user_home_expand(storage->ns->user, data);
if (stat(data, &st) < 0 || S_ISDIR(st.st_mode))
list_set->root_dir = data;
else {
- list_set->root_dir = get_root_dir(flags);
+ list_set->root_dir = get_root_dir(storage);
list_set->inbox_path = data;
}
} else if (strncmp(data, "INBOX=", 6) == 0) {
@@ -323,6 +325,7 @@
return -1;
} else {
if (mailbox_list_settings_parse(data, list_set,
+ storage->ns,
layout_r, NULL,
error_r) < 0)
return -1;
@@ -335,7 +338,7 @@
return -1;
}
- list_set->root_dir = create_root_dir(debug, error_r);
+ list_set->root_dir = create_root_dir(storage, error_r);
if (list_set->root_dir == NULL)
return -1;
} else {
@@ -365,7 +368,8 @@
if (list_set->inbox_path == NULL) {
list_set->inbox_path =
- get_inbox_file(list_set->root_dir, !autodetect, debug);
+ get_inbox_file(storage->ns->user->username,
+ list_set->root_dir, !autodetect, debug);
}
return 0;
}
@@ -437,8 +441,8 @@
struct mailbox_list_settings list_set;
const char *layout;
- if (mbox_get_list_settings(&list_set, data,
- _storage->flags, &layout, error_r) < 0)
+ if (mbox_get_list_settings(&list_set, data, _storage,
+ &layout, error_r) < 0)
return -1;
list_set.mail_storage_flags = &_storage->flags;
list_set.lock_method = &_storage->lock_method;
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/index/raw/raw-storage.c dovecot-patch/src/lib-storage/index/raw/raw-storage.c
--- dovecot-1.1.7+patch9/src/lib-storage/index/raw/raw-storage.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib-storage/index/raw/raw-storage.c 2009-01-06 10:08:19.000000000 -0600
@@ -27,10 +27,10 @@
static int
raw_get_list_settings(struct mailbox_list_settings *list_set,
- const char *data, enum mail_storage_flags flags,
+ const char *data, struct mail_storage *storage,
const char **layout_r, const char **error_r)
{
- bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
*layout_r = "fs";
@@ -48,8 +48,8 @@
if (debug)
i_info("raw: data=%s", data);
- return mailbox_list_settings_parse(data, list_set, layout_r, NULL,
- error_r);
+ return mailbox_list_settings_parse(data, list_set, storage->ns,
+ layout_r, NULL, error_r);
}
static struct mail_storage *raw_alloc(void)
@@ -73,7 +73,7 @@
struct stat st;
const char *layout;
- if (raw_get_list_settings(&list_set, data, _storage->flags,
+ if (raw_get_list_settings(&list_set, data, _storage,
&layout, error_r) < 0)
return -1;
list_set.mail_storage_flags = &_storage->flags;
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/mail-namespace.c dovecot-patch/src/lib-storage/mail-namespace.c
--- dovecot-1.1.7+patch9/src/lib-storage/mail-namespace.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib-storage/mail-namespace.c 2009-01-06 10:08:19.000000000 -0600
@@ -28,14 +28,14 @@
}
static struct mail_namespace *
-namespace_add_env(pool_t pool, const char *data, unsigned int num,
- const char *user, enum mail_storage_flags flags,
+namespace_add_env(const char *data, unsigned int num,
+ struct mail_user *user, enum mail_storage_flags flags,
enum file_lock_method lock_method)
{
struct mail_namespace *ns;
const char *sep, *type, *prefix, *error;
- ns = p_new(pool, struct mail_namespace, 1);
+ ns = p_new(user->pool, struct mail_namespace, 1);
sep = getenv(t_strdup_printf("NAMESPACE_%u_SEP", num));
type = getenv(t_strdup_printf("NAMESPACE_%u_TYPE", num));
@@ -76,9 +76,10 @@
if (sep != NULL)
ns->sep = *sep;
- ns->prefix = p_strdup(pool, prefix);
+ ns->prefix = p_strdup(user->pool, prefix);
+ ns->user = user;
- if (mail_storage_create(ns, NULL, data, user, flags, lock_method,
+ if (mail_storage_create(ns, NULL, data, flags, lock_method,
&error) < 0) {
i_error("Namespace '%s': %s", ns->prefix, error);
return NULL;
@@ -159,26 +160,7 @@
return TRUE;
}
-static struct mail_namespace *
-namespaces_sort(struct mail_namespace *src)
-{
- struct mail_namespace **tmp, *next, *dest = NULL;
-
- for (; src != NULL; src = next) {
- next = src->next;
-
- for (tmp = &dest; *tmp != NULL; tmp = &(*tmp)->next) {
- if (strlen(src->prefix) < strlen((*tmp)->prefix))
- break;
- }
- src->next = *tmp;
- *tmp = src;
- }
- return dest;
-}
-
-int mail_namespaces_init(pool_t pool, const char *user,
- struct mail_namespace **namespaces_r)
+int mail_namespaces_init(struct mail_user *user)
{
struct mail_namespace *namespaces, *ns, **ns_p;
enum mail_storage_flags flags;
@@ -199,7 +181,7 @@
break;
T_BEGIN {
- *ns_p = namespace_add_env(pool, data, i, user, flags,
+ *ns_p = namespace_add_env(data, i, user, flags,
lock_method);
} T_END;
@@ -212,8 +194,7 @@
if (namespaces != NULL) {
if (!namespaces_check(namespaces))
return -1;
- namespaces = namespaces_sort(namespaces);
- *namespaces_r = namespaces;
+ mail_user_add_namespace(user, namespaces);
if (hook_mail_namespaces_created != NULL) {
T_BEGIN {
@@ -232,13 +213,14 @@
mail = t_strconcat("maildir:", mail, NULL);
}
- ns = p_new(pool, struct mail_namespace, 1);
+ ns = p_new(user->pool, struct mail_namespace, 1);
ns->type = NAMESPACE_PRIVATE;
ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST |
NAMESPACE_FLAG_SUBSCRIPTIONS;
ns->prefix = "";
+ ns->user = user;
- if (mail_storage_create(ns, NULL, mail, user, flags, lock_method,
+ if (mail_storage_create(ns, NULL, mail, flags, lock_method,
&error) < 0) {
if (mail != NULL && *mail != '\0')
i_error("mail_location: %s", error);
@@ -248,7 +230,7 @@
}
return -1;
}
- *namespaces_r = ns;
+ user->namespaces = ns;
if (hook_mail_namespaces_created != NULL) {
T_BEGIN {
@@ -258,14 +240,17 @@
return 0;
}
-struct mail_namespace *mail_namespaces_init_empty(pool_t pool)
+struct mail_namespace *
+mail_namespaces_init_empty(struct mail_user *user)
{
struct mail_namespace *ns;
- ns = p_new(pool, struct mail_namespace, 1);
+ ns = p_new(user->pool, struct mail_namespace, 1);
+ ns->user = user;
ns->prefix = "";
ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST |
NAMESPACE_FLAG_SUBSCRIPTIONS;
+ user->namespaces = ns;
return ns;
}
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/mail-namespace.h dovecot-patch/src/lib-storage/mail-namespace.h
--- dovecot-1.1.7+patch9/src/lib-storage/mail-namespace.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib-storage/mail-namespace.h 2009-01-06 10:08:19.000000000 -0600
@@ -1,6 +1,8 @@
#ifndef MAIL_NAMESPACE_H
#define MAIL_NAMESPACE_H
+#include "mail-user.h"
+
enum namespace_type {
NAMESPACE_PRIVATE,
NAMESPACE_SHARED,
@@ -32,6 +34,7 @@
const char *prefix;
size_t prefix_len;
+ struct mail_user *user;
struct mailbox_list *list;
/* FIXME: we should support multiple storages in one namespace */
struct mail_storage *storage;
@@ -40,9 +43,8 @@
/* Called after namespaces has been created */
extern void (*hook_mail_namespaces_created)(struct mail_namespace *namespaces);
-int mail_namespaces_init(pool_t pool, const char *user,
- struct mail_namespace **namespaces_r);
-struct mail_namespace *mail_namespaces_init_empty(pool_t pool);
+int mail_namespaces_init(struct mail_user *user);
+struct mail_namespace *mail_namespaces_init_empty(struct mail_user *user);
void mail_namespaces_deinit(struct mail_namespace **namespaces);
/* Update hierarchy separators in given name to real_sep characters. */
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/mail-storage-private.h dovecot-patch/src/lib-storage/mail-storage-private.h
--- dovecot-1.1.7+patch9/src/lib-storage/mail-storage-private.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib-storage/mail-storage-private.h 2009-01-06 10:08:19.000000000 -0600
@@ -59,7 +59,6 @@
struct mail_namespace *ns;
struct mailbox_list *list;
- const char *user; /* name of user accessing the storage */
enum mail_storage_flags flags;
enum file_lock_method lock_method;
unsigned int keyword_max_len;
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/mail-storage.c dovecot-patch/src/lib-storage/mail-storage.c
--- dovecot-1.1.7+patch9/src/lib-storage/mail-storage.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib-storage/mail-storage.c 2009-01-06 10:08:19.000000000 -0600
@@ -167,8 +167,7 @@
}
int mail_storage_create(struct mail_namespace *ns, const char *driver,
- const char *data, const char *user,
- enum mail_storage_flags flags,
+ const char *data, enum mail_storage_flags flags,
enum file_lock_method lock_method,
const char **error_r)
{
@@ -212,7 +211,6 @@
storage = classes[i]->v.alloc();
storage->flags = flags;
storage->lock_method = lock_method;
- storage->user = p_strdup(storage->pool, user);
storage->ns = ns;
storage->callbacks =
@@ -237,7 +235,7 @@
return -1;
}
- home = getenv("HOME");
+ home = ns->user->home;
if (home == NULL || *home == '\0') home = "(not set)";
*error_r = t_strdup_printf(
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/mail-storage.h dovecot-patch/src/lib-storage/mail-storage.h
--- dovecot-1.1.7+patch9/src/lib-storage/mail-storage.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib-storage/mail-storage.h 2009-01-06 10:08:19.000000000 -0600
@@ -219,8 +219,7 @@
from data. If data is NULL, it uses the first storage that exists.
The storage is put into ns->storage. */
int mail_storage_create(struct mail_namespace *ns, const char *driver,
- const char *data, const char *user,
- enum mail_storage_flags flags,
+ const char *data, enum mail_storage_flags flags,
enum file_lock_method lock_method,
const char **error_r);
void mail_storage_destroy(struct mail_storage **storage);
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/mail-user.c dovecot-patch/src/lib-storage/mail-user.c
--- dovecot-1.1.7+patch9/src/lib-storage/mail-user.c 1969-12-31 18:00:00.000000000 -0600
+++ dovecot-patch/src/lib-storage/mail-user.c 2009-01-06 10:08:19.000000000 -0600
@@ -0,0 +1,79 @@
+/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "mail-namespace.h"
+#include "mail-user.h"
+
+struct mail_user_module_register mail_user_module_register = { 0 };
+void (*hook_mail_user_created)(struct mail_user *user) = NULL;
+
+static void mail_user_deinit_base(struct mail_user *user)
+{
+ mail_namespaces_deinit(&user->namespaces);
+ pool_unref(&user->pool);
+}
+
+struct mail_user *mail_user_init(const char *username, const char *home)
+{
+ struct mail_user *user;
+ pool_t pool;
+
+ i_assert(username != NULL);
+
+ pool = pool_alloconly_create("mail user", 512);
+ user = p_new(pool, struct mail_user, 1);
+ user->pool = pool;
+ user->username = p_strdup(pool, username);
+ user->home = p_strdup(pool, home);
+ user->v.deinit = mail_user_deinit_base;
+ p_array_init(&user->module_contexts, user->pool, 5);
+
+ if (hook_mail_user_created != NULL)
+ hook_mail_user_created(user);
+ return user;
+}
+
+void mail_user_deinit(struct mail_user **_user)
+{
+ struct mail_user *user = *_user;
+
+ *_user = NULL;
+ user->v.deinit(user);
+}
+
+void mail_user_add_namespace(struct mail_user *user, struct mail_namespace *ns)
+{
+ struct mail_namespace **tmp, *next;
+
+ for (; ns != NULL; ns = next) {
+ next = ns->next;
+
+ tmp = &user->namespaces;
+ for (; *tmp != NULL; tmp = &(*tmp)->next) {
+ if (strlen(ns->prefix) < strlen((*tmp)->prefix))
+ break;
+ }
+ ns->next = *tmp;
+ *tmp = ns;
+ }
+}
+
+const char *mail_user_home_expand(struct mail_user *user, const char *path)
+{
+ (void)mail_user_try_home_expand(user, &path);
+ return path;
+}
+
+int mail_user_try_home_expand(struct mail_user *user, const char **pathp)
+{
+ const char *path = *pathp;
+
+ if (path[0] == '~' && (path[1] == '/' || path[1] == '\0')) {
+ if (user->home == NULL)
+ return -1;
+
+ *pathp = t_strconcat(user->home, path + 1, NULL);
+ }
+ return 0;
+}
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/mail-user.h dovecot-patch/src/lib-storage/mail-user.h
--- dovecot-1.1.7+patch9/src/lib-storage/mail-user.h 1969-12-31 18:00:00.000000000 -0600
+++ dovecot-patch/src/lib-storage/mail-user.h 2009-01-06 10:08:19.000000000 -0600
@@ -0,0 +1,47 @@
+#ifndef MAIL_USER_H
+#define MAIL_USER_H
+
+struct mail_user;
+
+struct mail_user_vfuncs {
+ void (*deinit)(struct mail_user *user);
+};
+
+struct mail_user {
+ pool_t pool;
+ struct mail_user_vfuncs v;
+
+ const char *username;
+ const char *home;
+
+ struct mail_namespace *namespaces;
+
+ /* Module-specific contexts. See mail_storage_module_id. */
+ ARRAY_DEFINE(module_contexts, union mail_user_module_context *);
+};
+
+struct mail_user_module_register {
+ unsigned int id;
+};
+
+union mail_user_module_context {
+ struct mail_user_vfuncs super;
+ struct mail_user_module_register *reg;
+};
+extern struct mail_user_module_register mail_user_module_register;
+
+/* Called after user has been created */
+extern void (*hook_mail_user_created)(struct mail_user *user);
+
+struct mail_user *mail_user_init(const char *username, const char *home);
+void mail_user_deinit(struct mail_user **user);
+
+/* Add a new namespace to user's namespaces. */
+void mail_user_add_namespace(struct mail_user *user, struct mail_namespace *ns);
+
+/* Replace ~/ at the beginning of the path with the user's home directory. */
+const char *mail_user_home_expand(struct mail_user *user, const char *path);
+/* Returns 0 if ok, -1 if home directory isn't set. */
+int mail_user_try_home_expand(struct mail_user *user, const char **path);
+
+#endif
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/mailbox-list-private.h dovecot-patch/src/lib-storage/mailbox-list-private.h
--- dovecot-1.1.7+patch9/src/lib-storage/mailbox-list-private.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/lib-storage/mailbox-list-private.h 2009-01-06 10:08:19.000000000 -0600
@@ -116,6 +116,7 @@
int mailbox_list_settings_parse(const char *data,
struct mailbox_list_settings *set,
+ struct mail_namespace *ns,
const char **layout, const char **alt_dir_r,
const char **error_r);
diff -Nur dovecot-1.1.7+patch9/src/lib-storage/mailbox-list.c dovecot-patch/src/lib-storage/mailbox-list.c
--- dovecot-1.1.7+patch9/src/lib-storage/mailbox-list.c 2008-11-21 13:30:02.000000000 -0600
+++ dovecot-patch/src/lib-storage/mailbox-list.c 2009-01-06 10:08:19.000000000 -0600
@@ -100,17 +100,18 @@
return 0;
}
-static const char *fix_path(const char *path)
+static const char *fix_path(struct mail_namespace *ns, const char *path)
{
size_t len = strlen(path);
if (len > 1 && path[len-1] == '/')
path = t_strndup(path, len-1);
- return home_expand(path);
+ return mail_user_home_expand(ns->user, path);
}
int mailbox_list_settings_parse(const char *data,
struct mailbox_list_settings *set,
+ struct mail_namespace *ns,
const char **layout, const char **alt_dir_r,
const char **error_r)
{
@@ -124,7 +125,7 @@
/* <root dir> */
tmp = t_strsplit(data, ":");
- set->root_dir = fix_path(*tmp);
+ set->root_dir = fix_path(ns, *tmp);
tmp++;
for (; *tmp != NULL; tmp++) {
@@ -138,17 +139,17 @@
}
if (strcmp(key, "INBOX") == 0)
- set->inbox_path = fix_path(value);
+ set->inbox_path = fix_path(ns, value);
else if (strcmp(key, "INDEX") == 0)
- set->index_dir = fix_path(value);
+ set->index_dir = fix_path(ns, value);
else if (strcmp(key, "CONTROL") == 0)
- set->control_dir = fix_path(value);
+ set->control_dir = fix_path(ns, value);
else if (strcmp(key, "ALT") == 0 && alt_dir_r != NULL)
- *alt_dir_r = fix_path(value);
+ *alt_dir_r = fix_path(ns, value);
else if (strcmp(key, "LAYOUT") == 0)
*layout = value;
else if (strcmp(key, "SUBSCRIPTIONS") == 0)
- set->subscription_fname = fix_path(value);
+ set->subscription_fname = fix_path(ns, value);
else if (strcmp(key, "DIRNAME") == 0)
set->maildir_name = value;
else {
diff -Nur dovecot-1.1.7+patch9/src/mail-common/Makefile.am dovecot-patch/src/mail-common/Makefile.am
--- dovecot-1.1.7+patch9/src/mail-common/Makefile.am 1969-12-31 18:00:00.000000000 -0600
+++ dovecot-patch/src/mail-common/Makefile.am 2009-01-06 10:08:19.000000000 -0600
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# 3. Neither the name of Apple Inc. ("Apple") nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+noinst_LIBRARIES = libmail-common.a
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib \
+ -DPKG_RUNDIR=\""$(rundir)"\" \
+ -DSBINDIR=\""$(sbindir)"\"
+
+libmail_common_a_SOURCES = \
+ master.c
+
+noinst_HEADERS = \
+ master.h \
+ persistent-mail-master-interface.h
diff -Nur dovecot-1.1.7+patch9/src/mail-common/Makefile.in dovecot-patch/src/mail-common/Makefile.in
--- dovecot-1.1.7+patch9/src/mail-common/Makefile.in 1969-12-31 18:00:00.000000000 -0600
+++ dovecot-patch/src/mail-common/Makefile.in 2009-01-06 10:08:19.000000000 -0600
@@ -0,0 +1,509 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+#
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# 3. Neither the name of Apple Inc. ("Apple") nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/mail-common
+DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libmail_common_a_AR = $(AR) $(ARFLAGS)
+libmail_common_a_LIBADD =
+am_libmail_common_a_OBJECTS = master.$(OBJEXT)
+libmail_common_a_OBJECTS = $(am_libmail_common_a_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libmail_common_a_SOURCES)
+DIST_SOURCES = $(libmail_common_a_SOURCES)
+HEADERS = $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTH_CFLAGS = @AUTH_CFLAGS@
+AUTH_LIBS = @AUTH_LIBS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DICT_LIBS = @DICT_LIBS@
+DSYMUTIL = @DSYMUTIL@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KRB5CONFIG = @KRB5CONFIG@
+KRB5_CFLAGS = @KRB5_CFLAGS@
+KRB5_LIBS = @KRB5_LIBS@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBCAP = @LIBCAP@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MODULE_LIBS = @MODULE_LIBS@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+NMEDIT = @NMEDIT@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_CFLAGS = @PGSQL_CFLAGS@
+PGSQL_LIBS = @PGSQL_LIBS@
+PKG_CONFIG = @PKG_CONFIG@
+RAND_LIBS = @RAND_LIBS@
+RANLIB = @RANLIB@
+RPCGEN = @RPCGEN@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE_CFLAGS = @SQLITE_CFLAGS@
+SQLITE_LIBS = @SQLITE_LIBS@
+SQL_CFLAGS = @SQL_CFLAGS@
+SQL_LIBS = @SQL_LIBS@
+SSL_CFLAGS = @SSL_CFLAGS@
+SSL_LIBS = @SSL_LIBS@
+STORAGE_LIBS = @STORAGE_LIBS@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+dict_drivers = @dict_drivers@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mail_storages = @mail_storages@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rundir = @rundir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sql_drivers = @sql_drivers@
+srcdir = @srcdir@
+ssldir = @ssldir@
+statedir = @statedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LIBRARIES = libmail-common.a
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib \
+ -DPKG_RUNDIR=\""$(rundir)"\" \
+ -DSBINDIR=\""$(sbindir)"\"
+
+libmail_common_a_SOURCES = \
+ master.c
+
+noinst_HEADERS = \
+ master.h \
+ persistent-mail-master-interface.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/mail-common/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/mail-common/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libmail-common.a: $(libmail_common_a_OBJECTS) $(libmail_common_a_DEPENDENCIES)
+ -rm -f libmail-common.a
+ $(libmail_common_a_AR) libmail-common.a $(libmail_common_a_OBJECTS) $(libmail_common_a_LIBADD)
+ $(RANLIB) libmail-common.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/master.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff -Nur dovecot-1.1.7+patch9/src/mail-common/master.c dovecot-patch/src/mail-common/master.c
--- dovecot-1.1.7+patch9/src/mail-common/master.c 1969-12-31 18:00:00.000000000 -0600
+++ dovecot-patch/src/mail-common/master.c 2009-01-06 10:08:19.000000000 -0600
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "ostream.h"
+#include "master.h"
+#include "network.h"
+#include "persistent-mail-master-interface.h"
+#include "str-sanitize.h"
+#include "fdpass.h"
+#include "env-util.h"
+#include "restrict-access.h"
+#include "str.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+static int master_fd = -1;
+static struct io *master_io;
+static struct ostream *master_out;
+static struct ioloop *mail_ioloop;
+static bool (*mail_client_attach)(int fd_in, int fd_out, bool is_standalone);
+static bool (*mail_clients_connected)(void);
+
+static struct {
+ uint32_t len; /* length of body */
+ size_t len_off; /* how much of len we've read */
+ char body[32]; /* body of message */
+ size_t body_off; /* how much of body we've read */
+ unsigned int have_len:1;
+ unsigned int have_body:1;
+ unsigned int done:1;
+} master_handshake;
+
+static const char hotpotato[] = HOTPOTATO;
+static struct {
+ char spud[PERSISTENT_MAIL_MASTER_MESSAGE_SIZE]; /* message passed with client fd */
+ unsigned int connection_id; /* receipt id */
+ int fd; /* connected client */
+ uint32_t len; /* length of environment */
+ size_t len_off; /* how much of len we've read */
+ char env[4096]; /* environment */
+ size_t env_off; /* how much of env we've read */
+ unsigned int have_fd:1;
+ unsigned int have_len:1;
+ unsigned int have_env:1;
+} master_request;
+
+static ssize_t master_read_resid(void *buf, size_t *off, size_t *resid)
+{
+ while (*resid > 0) {
+ ssize_t r = read(master_fd, (char *) buf + *off, *resid);
+ if (r > 0) {
+ *off += r;
+ *resid -= r;
+ if (*resid == 0)
+ break;
+ } else if (r == 0) {
+ if (getenv("DEBUG"))
+ i_info("Master disconnected (pid %s)",
+ dec2str(getpid()));
+ master_deinit();
+ break;
+ } else {
+ if (r < 0 && errno != EAGAIN)
+ return -1;
+ break;
+ }
+ }
+ return 0;
+}
+
+static bool master_shake(void)
+{
+ size_t resid;
+ ssize_t r;
+
+ if (!master_handshake.have_len) {
+ resid = sizeof master_handshake.len - master_handshake.len_off;
+ r = master_read_resid(&master_handshake.len,
+ &master_handshake.len_off,
+ &resid);
+ if (r < 0) {
+ i_error("Error reading master handshake length: %m");
+ master_deinit();
+ return FALSE;
+ }
+ if (resid > 0) /* need more */
+ return FALSE;
+
+ /* have the complete len */
+ master_handshake.len = ntohl(master_handshake.len);
+ if (master_handshake.len >= sizeof master_handshake.body) {
+ i_error("Bogus handshake length %u",
+ master_handshake.len);
+ master_deinit();
+ return FALSE;
+ }
+
+ master_handshake.have_len = TRUE;
+ }
+
+ if (!master_handshake.have_body) {
+ i_assert(master_handshake.len < sizeof master_handshake.body);
+ resid = master_handshake.len - master_handshake.body_off;
+ r = master_read_resid(master_handshake.body,
+ &master_handshake.body_off,
+ &resid);
+ if (r < 0) {
+ i_error("Error reading master handshake body: %m");
+ master_deinit();
+ return FALSE;
+ }
+ if (resid > 0) /* need more */
+ return FALSE;
+
+ /* have the complete body */
+ master_handshake.body[master_handshake.len] = '\0';
+ if (master_handshake.len < 8 ||
+ strncmp(master_handshake.body, "VERSION\t", 8) != 0 ||
+ atoi(t_strcut(&master_handshake.body[8], '\t')) !=
+ PERSISTENT_MAIL_MASTER_PROTOCOL_MAJOR_VERSION) {
+ i_error("Bad handshake from master: \"%s\"; "
+ "expected \"VERSION\t%u\t...\"",
+ str_sanitize(master_handshake.body,
+ master_handshake.len),
+ PERSISTENT_MAIL_MASTER_PROTOCOL_MAJOR_VERSION);
+ master_deinit();
+ return FALSE;
+ }
+
+ master_handshake.have_body = TRUE;
+ }
+
+ return TRUE;
+}
+
+static void master_request_reset(void)
+{
+ memset(master_request.spud, 0, sizeof master_request.spud);
+ master_request.connection_id = 0;
+ master_request.fd = -1;
+ master_request.len = 0;
+ master_request.len_off = 0;
+ master_request.env[0] = '\0';
+ master_request.env_off = 0;
+ master_request.have_fd = FALSE;
+ master_request.have_len = FALSE;
+ master_request.have_env = FALSE;
+}
+
+static bool master_receive_fd(void)
+{
+ ssize_t r;
+
+ r = fd_read(master_fd, master_request.spud,
+ sizeof master_request.spud, &master_request.fd);
+ if (r < 0 && errno == EAGAIN)
+ return FALSE;
+
+ if (r != sizeof master_request.spud ||
+ strncmp(master_request.spud, hotpotato, sizeof hotpotato - 1) != 0 ||
+ master_request.fd < 0) {
+ if (r < 0)
+ i_error("Error receiving client request fd: %m");
+ else if (r == 0) {
+ if (getenv("DEBUG"))
+ i_info("Master disconnected (pid %s)",
+ dec2str(getpid()));
+ } else
+ i_error("Invalid client request fd received");
+ master_deinit();
+ return FALSE;
+ }
+
+ memcpy(&master_request.connection_id,
+ &master_request.spud[sizeof hotpotato - 1],
+ sizeof master_request.connection_id);
+ master_request.connection_id = ntohl(master_request.connection_id);
+
+ return TRUE;
+}
+
+static bool master_receive_len(void)
+{
+ size_t resid;
+ ssize_t r;
+
+ resid = sizeof master_request.len - master_request.len_off;
+ r = master_read_resid(&master_request.len, &master_request.len_off,
+ &resid);
+ if (r < 0) {
+ i_error("Error reading client env length: %m");
+ master_deinit();
+ return FALSE;
+ }
+ if (resid > 0) /* need more */
+ return FALSE;
+
+ /* have the complete len */
+ master_request.len = ntohl(master_request.len);
+ if (master_request.len >= sizeof master_request.env) {
+ i_error("Client env too large (%u >= %u)",
+ (unsigned int) master_request.len,
+ (unsigned int) sizeof master_request.env);
+ master_deinit();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool master_receive_env(void)
+{
+ size_t resid;
+ ssize_t r;
+
+ i_assert(master_request.len < sizeof master_request.env);
+ resid = master_request.len - master_request.env_off;
+ r = master_read_resid(master_request.env, &master_request.env_off,
+ &resid);
+ if (r < 0) {
+ i_error("Error reading client env: %m");
+ master_deinit();
+ return FALSE;
+ }
+ if (resid > 0) /* need more */
+ return FALSE;
+
+ /* have the complete env */
+ master_request.env[master_request.len] = '\0';
+
+ return TRUE;
+}
+
+static bool master_send_ack(unsigned int id)
+{
+ const char *message;
+
+ if (master_fd < 0)
+ return FALSE;
+
+ message = t_strdup_printf("ACK\t%u\n", id);
+ o_stream_send(master_out, message, strlen(message));
+ if (o_stream_flush(master_out) < 0) {
+ master_deinit();
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool master_send_disconnect(unsigned int connection_id)
+{
+ const char *message;
+
+ if (master_fd < 0)
+ return FALSE;
+
+ message = t_strdup_printf("DISCONNECTED\t%u\n", connection_id);
+ o_stream_send(master_out, message, strlen(message));
+ if (o_stream_flush(master_out) < 0) {
+ master_deinit();
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void master_input(void *context ATTR_UNUSED)
+{
+ const char **env;
+
+ if (!master_handshake.done) {
+ if (master_shake())
+ master_handshake.done = TRUE;
+ else
+ return;
+ }
+
+ if (!master_request.have_fd) {
+ if (master_receive_fd())
+ master_request.have_fd = TRUE;
+ else
+ return;
+
+ if (!master_send_ack(master_request.connection_id))
+ return;
+ }
+
+ if (!master_request.have_len) {
+ if (master_receive_len())
+ master_request.have_len = TRUE;
+ else
+ return;
+ }
+
+ if (!master_request.have_env) {
+ if (master_receive_env())
+ master_request.have_env = TRUE;
+ else
+ return;
+ }
+
+ /* have complete request. temporarily install the new environ,
+ but detach it before returning */
+ env = t_strsplit(master_request.env, "\n");
+ env_switch(unsafe_data_stack_pool, (char **) env);
+ restrict_access_by_env(TRUE);
+ if (!mail_client_attach(master_request.fd, master_request.fd, FALSE))
+ close(master_request.fd);
+ io_env_clean();
+
+ master_request_reset();
+}
+
+void master_init(int fd, struct ioloop *ioloop,
+ bool (*client_attach)(int fd_in, int fd_out, bool is_standalone),
+ bool (*clients_connected)(void))
+{
+ const char *handshake;
+
+ master_fd = fd;
+ if (master_fd < 0)
+ return;
+
+ net_set_nonblock(master_fd, TRUE);
+ master_io = io_add(master_fd, IO_READ, master_input, NULL);
+ master_out = o_stream_create_fd(master_fd, 8192, FALSE);
+ mail_ioloop = ioloop;
+ mail_client_attach = client_attach;
+ mail_clients_connected = clients_connected;
+
+ memset(&master_handshake, 0, sizeof master_handshake);
+
+ master_request_reset();
+
+ handshake = t_strdup_printf("VERSION\t%u\t%u\n",
+ PERSISTENT_MAIL_MASTER_PROTOCOL_MAJOR_VERSION,
+ PERSISTENT_MAIL_MASTER_PROTOCOL_MINOR_VERSION);
+ (void) o_stream_send_str(master_out, handshake);
+ o_stream_flush(master_out);
+}
+
+void master_deinit(void)
+{
+ if (master_fd < 0)
+ return;
+
+ o_stream_destroy(&master_out);
+ io_remove(&master_io);
+ if (close(master_fd) < 0)
+ i_error("close(master) failed: %m");
+ master_fd = -1;
+
+ if (!mail_clients_connected())
+ io_loop_stop(mail_ioloop);
+ /* else run until they disconnect */
+}
+
+void master_info(string_t *str)
+{
+ if (master_fd < 0)
+ str_append(str, "disconnected from master");
+ else
+ str_append(str, "connected to master");
+}
diff -Nur dovecot-1.1.7+patch9/src/mail-common/master.h dovecot-patch/src/mail-common/master.h
--- dovecot-1.1.7+patch9/src/mail-common/master.h 1969-12-31 18:00:00.000000000 -0600
+++ dovecot-patch/src/mail-common/master.h 2009-01-06 10:08:19.000000000 -0600
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef MASTER_H
+#define MASTER_H
+
+void master_init(int fd, struct ioloop *ioloop,
+ bool (*client_attach)(int fd_in, int fd_out, bool is_standalone),
+ bool (*clients_connected)(void));
+void master_deinit(void);
+bool master_send_disconnect(unsigned int connection_id);
+void master_info(string_t *str);
+
+#endif
diff -Nur dovecot-1.1.7+patch9/src/mail-common/persistent-mail-master-interface.h dovecot-patch/src/mail-common/persistent-mail-master-interface.h
--- dovecot-1.1.7+patch9/src/mail-common/persistent-mail-master-interface.h 1969-12-31 18:00:00.000000000 -0600
+++ dovecot-patch/src/mail-common/persistent-mail-master-interface.h 2009-01-06 10:08:19.000000000 -0600
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef PERSISTENT_MAIL_MASTER_INTERFACE_H
+#define PERSISTENT_MAIL_MASTER_INTERFACE_H
+
+/* Major version changes are not backwards compatible,
+ minor version numbers can be ignored. */
+#define PERSISTENT_MAIL_MASTER_PROTOCOL_MAJOR_VERSION 1
+#define PERSISTENT_MAIL_MASTER_PROTOCOL_MINOR_VERSION 0
+
+#define HOTPOTATO "HOTPOTATO\n"
+
+#define PERSISTENT_MAIL_MASTER_MESSAGE_SIZE \
+ (sizeof (HOTPOTATO) - 1 + sizeof (uint32_t))
+
+#endif
diff -Nur dovecot-1.1.7+patch9/src/master/Makefile.am dovecot-patch/src/master/Makefile.am
--- dovecot-1.1.7+patch9/src/master/Makefile.am 2008-10-29 11:51:28.000000000 -0500
+++ dovecot-patch/src/master/Makefile.am 2009-01-06 10:08:19.000000000 -0600
@@ -6,6 +6,7 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-settings \
+ -I$(top_srcdir)/src/mail-common \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
-DPKG_RUNDIR=\""$(rundir)"\" \
-DPKG_STATEDIR=\""$(statedir)"\" \
diff -Nur dovecot-1.1.7+patch9/src/master/auth-process.c dovecot-patch/src/master/auth-process.c
--- dovecot-1.1.7+patch9/src/master/auth-process.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/master/auth-process.c 2009-01-06 10:08:19.000000000 -0600
@@ -435,7 +435,8 @@
/* setup access environment */
restrict_access_set_env(set->user, set->uid, set->gid,
- (gid_t)-1, set->chroot, 0, 0, NULL);
+ (gid_t)-1, set->chroot, 0, 0, NULL,
+ FALSE); /* APPLE */
/* set other environment */
env_put("DOVECOT_MASTER=1");
diff -Nur dovecot-1.1.7+patch9/src/master/child-process.c dovecot-patch/src/master/child-process.c
--- dovecot-1.1.7+patch9/src/master/child-process.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/master/child-process.c 2009-01-06 10:08:19.000000000 -0600
@@ -42,10 +42,15 @@
void child_process_init_env(void)
{
+ child_process_init_env_private(FALSE); /* APPLE */
+}
+
+void child_process_init_env_private(bool private_env) /* APPLE */
+{
int facility;
/* remove all environment, we don't need them */
- env_clean();
+ env_clean_private(private_env); /* APPLE */
/* we'll log through master process */
env_put("LOG_TO_MASTER=1");
diff -Nur dovecot-1.1.7+patch9/src/master/child-process.h dovecot-patch/src/master/child-process.h
--- dovecot-1.1.7+patch9/src/master/child-process.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/master/child-process.h 2009-01-06 10:08:19.000000000 -0600
@@ -31,6 +31,7 @@
void child_process_remove(pid_t pid);
void child_process_init_env(void);
+void child_process_init_env_private(bool private_env); /* APPLE */
void client_process_exec(const char *cmd, const char *title);
void client_process_exec_argv(const char *executable, const char **argv);
diff -Nur dovecot-1.1.7+patch9/src/master/login-process.c dovecot-patch/src/master/login-process.c
--- dovecot-1.1.7+patch9/src/master/login-process.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/master/login-process.c 2009-01-06 10:08:19.000000000 -0600
@@ -520,7 +520,8 @@
restrict_access_set_env(NULL, set->login_uid,
set->server->login_gid, (gid_t)-1,
set->login_chroot ? set->login_dir : NULL,
- 0, 0, NULL);
+ 0, 0, NULL,
+ FALSE); /* APPLE */
env_put("DOVECOT_MASTER=1");
diff -Nur dovecot-1.1.7+patch9/src/master/mail-process.c dovecot-patch/src/master/mail-process.c
--- dovecot-1.1.7+patch9/src/master/mail-process.c 2008-11-15 11:36:54.000000000 -0600
+++ dovecot-patch/src/master/mail-process.c 2009-01-06 11:18:03.000000000 -0600
@@ -33,6 +33,18 @@
many seconds to finish. */
#define CHDIR_WARN_SECS 10
+/* APPLE */
+struct mail_process {
+ pid_t pid;
+ time_t connected_at;
+};
+
+/* APPLE */
+struct mail_connection {
+ unsigned int connection_id;
+ time_t connected_at;
+};
+
struct mail_process_group {
/* process.type + user + remote_ip identifies this process group */
struct child_process process;
@@ -40,13 +52,281 @@
struct ip_addr remote_ip;
/* processes array acts also as refcount */
- ARRAY_DEFINE(processes, pid_t);
+ ARRAY_DEFINE(processes, struct mail_process); /* APPLE */
+
+ /* APPLE */
+ ARRAY_DEFINE(connections, struct mail_connection);
+ unsigned int children;
};
+/* APPLE begin */
+#include "ioloop.h"
+#include "istream.h"
+#include "ostream.h"
+#include "fdpass.h"
+#include "persistent-mail-master-interface.h"
+
+#define MAX_INBUF_SIZE 1024
+#define MAX_OUTBUF_SIZE (512*1024)
+
+struct persistent_mail_process_group {
+ struct persistent_mail_process_group *next;
+
+ struct settings *set;
+
+ struct persistent_mail_process *processes;
+};
+static struct persistent_mail_process_group *persistent_mail_process_groups;
+
+struct persistent_mail_process {
+ struct persistent_mail_process *next;
+
+ struct persistent_mail_process_group *group;
+
+ pid_t pid;
+ int fd;
+ struct io *io;
+ struct istream *input;
+ struct ostream *output;
+
+ ARRAY_DEFINE(connections, unsigned int); /* includes pending ones */
+ struct hash_table *pending;
+ unsigned int version_received:1;
+};
+
+struct persistent_mail_pender {
+ int socket_fd;
+};
+
+static unsigned int next_connection_id;
+
+struct hash_table *mail_connections;
+/* APPLE end */
+
/* type+user -> struct mail_process_group */
static struct hash_table *mail_process_groups;
static unsigned int mail_process_count = 0;
+/* APPLE */
+static void mail_process_group_dump(const char *pfx, const struct mail_process_group *group)
+{
+ string_t *msg;
+ unsigned int i, count;
+ const struct mail_process *processes;
+ const struct mail_connection *connections;
+
+ msg = t_str_new(512);
+
+ processes = array_get(&group->processes, &count);
+ str_printfa(msg, "%d pid(s)", count);
+ if (count > 0) {
+ str_append(msg, " (");
+ for (i = 0; i < count; i++) {
+ if (i > 0)
+ str_append(msg, ", ");
+ str_printfa(msg, "%d since %.15s",
+ processes[i].pid,
+ ctime(&processes[i].connected_at) + 4);
+ }
+ str_append_c(msg, ')');
+ }
+
+ connections = array_get(&group->connections, &count);
+ str_printfa(msg, " and %d connection(s)", count);
+ if (count > 0) {
+ str_append(msg, " (");
+ for (i = 0; i < count; i++) {
+ if (i > 0)
+ str_append(msg, ", ");
+ str_printfa(msg, "%u since %.15s",
+ connections[i].connection_id,
+ ctime(&connections[i].connected_at) + 4);
+ }
+ str_append_c(msg, ')');
+ }
+
+ i_info("master: %s: mail_process_group %p user=%s/addr=%s/type=%d"
+ " children=%u has %s", pfx, group, group->user,
+ inet_ntoa(group->remote_ip.u.ip4), group->process.type,
+ group->children, str_c(msg));
+}
+
+/* APPLE */
+static void persistent_mail_process_dump(const char *pfx, const struct persistent_mail_process *process)
+{
+ string_t *msg;
+ unsigned int i, count;
+ const unsigned int *connections;
+
+ msg = t_str_new(512);
+
+ connections = array_get(&process->connections, &count);
+ str_printfa(msg, "%d connection(s)", count);
+ if (count > 0) {
+ str_append(msg, " (");
+ for (i = 0; i < count; i++) {
+ if (i > 0)
+ str_append(msg, ", ");
+ str_printfa(msg, "%u", connections[i]);
+ }
+ str_append_c(msg, ')');
+ }
+
+ i_info("master: %s: persistent_mail_process pid=%d proto=%d has %s",
+ pfx, process->pid, process->group->set->protocol, str_c(msg));
+}
+
+/* APPLE */
+static void mail_connections_dump(const char *pfx)
+{
+ string_t *msg;
+ struct hash_iterate_context *iter;
+ void *key, *value;
+
+ msg = t_str_new(512);
+
+ str_printfa(msg, "%d entries", hash_count(mail_connections));
+ if (hash_count(mail_connections) > 0) {
+ int i = 0;
+
+ str_append(msg, " (");
+ iter = hash_iterate_init(mail_connections);
+ while (hash_iterate(iter, &key, &value)) {
+ unsigned int connection_id = POINTER_CAST_TO(key, unsigned int);
+ struct mail_process_group *group = (struct mail_process_group *) value;
+ if (i++ > 0)
+ str_append(msg, ", ");
+ str_printfa(msg, "connID=%u -> group %p user=%s/addr=%s/type=%d", connection_id, group, group->user, inet_ntoa(group->remote_ip.u.ip4), group->process.type);
+ }
+ hash_iterate_deinit(&iter);
+ str_append_c(msg, ')');
+ }
+
+ i_info("master: %s: mail_connections has %s", pfx, str_c(msg));
+}
+
+#ifdef APPLE_OS_X_SERVER
+#include "fcntl.h"
+static void dump_connected_users ( void )
+{
+ int fd;
+ int pop3_cnt = 0;
+ int imap_cnt = 0;
+ string_t *msg_str = NULL;
+ void *key;
+ void *value;
+ const char *file_path = "/var/db/.mailusers.plist";
+ struct hash_iterate_context *iter;
+
+ fd = open( file_path, O_RDWR );
+ if ( fd == -1 )
+ {
+ /* we don't care if it doesn't open, it is created by Server Admin */
+ return;
+ }
+
+ msg_str = t_str_new( 512 );
+ str_append( msg_str, "<dict>\n\t<key>usersArray</key>\n\t<array>\n" );
+
+ iter = hash_iterate_init( mail_process_groups );
+ while ( hash_iterate( iter, &key, &value ) )
+ {
+ struct mail_process_group *group = (struct mail_process_group *)value;
+ int *cnt;
+ time_t earliest_connected_at;
+ unsigned int process_count, connection_count, i;
+ const struct mail_process *processes;
+ const struct mail_connection *connections;
+
+ if ( group->process.type == PROCESS_TYPE_IMAP )
+ {
+ cnt = &imap_cnt;
+ str_append( msg_str, "\t\t<dict>\n\t\t\t<key>type</key>\n\t\t\t<string>imap</string>\n" );
+ }
+ else if ( group->process.type == PROCESS_TYPE_POP3 )
+ {
+ cnt = &pop3_cnt;
+ str_append( msg_str, "\t\t<dict>\n\t\t\t<key>type</key>\n\t\t\t<string>pop3</string>\n" );
+ }
+ else
+ {
+ continue;
+ }
+
+ str_printfa( msg_str, "\t\t\t<key>name</key>\n\t\t\t<string>%s</string>\n", group->user );
+ str_printfa( msg_str, "\t\t\t<key>ipAddress</key>\n\t\t\t<string>%s</string>\n", inet_ntoa(group->remote_ip.u.ip4) );
+
+ earliest_connected_at = ioloop_time;
+ processes = array_get(&group->processes, &process_count);
+ for (i = 0; i < process_count; ++i)
+ if (earliest_connected_at > processes[i].connected_at)
+ earliest_connected_at = processes[i].connected_at;
+ connections = array_get(&group->connections, &connection_count);
+ for (i = 0; i < connection_count; ++i)
+ if (earliest_connected_at > connections[i].connected_at)
+ earliest_connected_at = connections[i].connected_at;
+
+ *cnt += process_count + connection_count;
+ str_printfa(msg_str, "\t\t\t<key>connections</key>\n\t\t\t<integer>%d</integer>\n",
+ process_count + connection_count);
+ str_printfa(msg_str, "\t\t\t<key>connectionElapsedTime</key>\n\t\t\t<integer>%d</integer>\n",
+ (int) (ioloop_time - earliest_connected_at));
+
+ str_append( msg_str, "\t\t</dict>\n" );
+ }
+ hash_iterate_deinit( &iter );
+
+ str_printfa( msg_str, "\t</array>\n\t<key>imapRequests</key>\n\t<integer>%d</integer>\n", imap_cnt );
+ str_printfa( msg_str, "\t<key>popRequests</key>\n\t<integer>%d</integer>\n", pop3_cnt );
+ str_printfa( msg_str, "\t<key>totalRequests</key>\n\t<integer>%d</integer>\n", pop3_cnt + imap_cnt );
+ str_append( msg_str, "</dict>\n" );
+
+ if ( lseek(fd, 0, SEEK_SET) == 0 && ftruncate(fd, 0) == 0 )
+ {
+ write( fd, str_c( msg_str ), str_len( msg_str ) );
+ }
+ close( fd );
+}
+#endif
+
+/* APPLE */
+#ifdef SIGINFO
+#include "lib-signals.h"
+static void sig_info(int signo ATTR_UNUSED, void *context ATTR_UNUSED)
+{
+ struct hash_iterate_context *iter;
+ void *key, *value;
+ struct persistent_mail_process_group *group;
+
+ i_info("Mail process status:");
+ mail_connections_dump("status");
+#ifdef APPLE_OS_X_SERVER
+ dump_connected_users();
+#endif
+
+ i_info("Persistent mail process groups:");
+ for (group = persistent_mail_process_groups; group != NULL;
+ group = group->next) {
+ struct persistent_mail_process *process;
+
+ i_info("pmp_group \"%s\":", group->set->server->name);
+ for (process = group->processes; process != NULL;
+ process = process->next)
+ persistent_mail_process_dump("status", process);
+ }
+
+ i_info("User+IP mail process groups:");
+ iter = hash_iterate_init(mail_process_groups);
+ while (hash_iterate(iter, &key, &value)) {
+ struct mail_process_group *group = value;
+ mail_process_group_dump("status", group);
+ }
+ hash_iterate_deinit(&iter);
+
+ i_info("End");
+}
+#endif
+
static unsigned int mail_process_group_hash(const void *p)
{
const struct mail_process_group *group = p;
@@ -93,25 +373,599 @@
group->remote_ip = *ip;
i_array_init(&group->processes, 10);
+ i_array_init(&group->connections, 10); /* APPLE */
hash_insert(mail_process_groups, group, group);
return group;
}
static void
-mail_process_group_add(struct mail_process_group *group, pid_t pid)
+mail_process_group_add(struct mail_process_group *group, pid_t pid,
+ /* APPLE */
+ unsigned int connection_id, bool is_persistent)
{
mail_process_count++;
- array_append(&group->processes, &pid, 1);
+
+ /* APPLE */
+ group->children += 1;
+ if (is_persistent) {
+ struct mail_connection *conn =
+ array_append_space(&group->connections);
+ conn->connection_id = connection_id;
+ conn->connected_at = ioloop_time;
+ } else {
+ struct mail_process *proc =
+ array_append_space(&group->processes);
+ proc->pid = pid;
+ proc->connected_at = ioloop_time;
+ }
+
child_process_add(pid, &group->process);
}
static void mail_process_group_free(struct mail_process_group *group)
{
+ array_free(&group->connections); /* APPLE */
array_free(&group->processes);
i_free(group->user);
i_free(group);
}
+/* APPLE begin */
+static struct persistent_mail_pender *
+persistent_mail_pender_new(int socket_fd)
+{
+ struct persistent_mail_pender *pender;
+
+ pender = i_new(struct persistent_mail_pender, 1);
+ pender->socket_fd = socket_fd;
+
+ return pender;
+}
+
+static void
+persistent_mail_pender_destroy(struct persistent_mail_pender *pender)
+{
+ close(pender->socket_fd);
+ i_free(pender);
+}
+
+static void persistent_mail_process_group_create(struct settings *set)
+{
+ struct persistent_mail_process_group *group;
+
+ group = i_new(struct persistent_mail_process_group, 1);
+ group->set = set;
+
+ group->next = persistent_mail_process_groups;
+ persistent_mail_process_groups = group;
+}
+
+static bool
+persistent_mail_process_disconnect(struct persistent_mail_process *process,
+ unsigned int connection_id)
+{
+ struct mail_process_group *group;
+ const struct mail_connection *conns;
+ const unsigned int *ids;
+ unsigned int i, count;
+
+ group = hash_lookup(mail_connections, POINTER_CAST(connection_id));
+ i_assert(group != NULL);
+ hash_remove(mail_connections, POINTER_CAST(connection_id));
+
+ conns = array_get(&group->connections, &count);
+ for (i = 0; i < count; i++)
+ if (conns[i].connection_id == connection_id)
+ break;
+ i_assert(i != count);
+ array_delete(&group->connections, i, 1);
+ if (--count == 0 && group->children == 0 &&
+ array_count(&group->processes) == 0) {
+ hash_remove(mail_process_groups, group);
+ mail_process_group_free(group);
+ }
+
+ ids = array_get(&process->connections, &count);
+ for (i = 0; i < count; i++)
+ if (ids[i] == connection_id)
+ break;
+ i_assert(i != count);
+ array_delete(&process->connections, i, 1);
+ return --count > 0;
+}
+
+static void
+persistent_mail_process_destroy(struct persistent_mail_process *process)
+{
+ struct persistent_mail_process **pos;
+ struct hash_iterate_context *iter;
+ void *key, *value;
+ const unsigned int *ids;
+ unsigned int count;
+
+ for (pos = &process->group->processes; *pos != NULL;
+ pos = &(*pos)->next) {
+ if (*pos == process) {
+ *pos = process->next;
+ break;
+ }
+ }
+
+ iter = hash_iterate_init(process->pending);
+ while (hash_iterate(iter, &key, &value))
+ persistent_mail_pender_destroy(value);
+ hash_iterate_deinit(&iter);
+ hash_table_destroy(&process->pending);
+
+ for (ids = array_get(&process->connections, &count); count > 0;
+ ids = array_get(&process->connections, &count))
+ persistent_mail_process_disconnect(process, ids[0]);
+ array_free(&process->connections);
+
+ o_stream_destroy(&process->output);
+ i_stream_destroy(&process->input);
+ io_remove(&process->io);
+ if (close(process->fd) < 0)
+ i_error("close(persistent_mail_process) failed: %m");
+ i_free(process);
+}
+
+static void
+persistent_mail_process_group_destroy(struct persistent_mail_process_group *group)
+{
+ struct persistent_mail_process *next;
+
+ while (group->processes != NULL) {
+ next = group->processes->next;
+ persistent_mail_process_destroy(group->processes);
+ group->processes = next;
+ }
+
+ i_free(group);
+}
+
+void persistent_mail_processes_destroy_all(void)
+{
+ struct persistent_mail_process_group *next;
+
+ while (persistent_mail_process_groups != NULL) {
+ next = persistent_mail_process_groups->next;
+ persistent_mail_process_group_destroy(persistent_mail_process_groups);
+ persistent_mail_process_groups = next;
+ }
+}
+
+static void persistent_mail_process_groups_create(void)
+{
+ struct server_settings *server;
+
+ for (server = settings_root; server != NULL; server = server->next) {
+ if (server->imap != NULL)
+ persistent_mail_process_group_create(server->imap);
+ if (server->pop3 != NULL)
+ persistent_mail_process_group_create(server->pop3);
+ }
+}
+
+static struct persistent_mail_process_group *
+persistent_mail_process_group_find(struct settings *set)
+{
+ struct persistent_mail_process_group *group;
+
+ if (persistent_mail_process_groups == NULL)
+ persistent_mail_process_groups_create();
+
+ for (group = persistent_mail_process_groups; group != NULL;
+ group = group->next)
+ if (group->set->protocol == set->protocol &&
+ strcmp(group->set->server->name, set->server->name) == 0)
+ break;
+
+ return group;
+}
+
+static bool
+persistent_mail_process_input_ack(struct persistent_mail_process *process,
+ const char *args)
+{
+ unsigned int connection_id;
+ struct persistent_mail_pender *pender;
+
+ connection_id = strtoul(args, NULL, 10);
+ if (connection_id == 0) {
+ i_error("BUG: Persistent mail process %s sent ack for "
+ "illegal connection ID 0",
+ dec2str(process->pid));
+ return FALSE;
+ }
+
+ pender = hash_lookup(process->pending, POINTER_CAST(connection_id));
+ if (pender == NULL) {
+ i_error("BUG: Persistent mail process %s sent ack for "
+ "nonexistent connection ID %u",
+ dec2str(process->pid), connection_id);
+ return FALSE;
+ }
+ persistent_mail_pender_destroy(pender);
+ hash_remove(process->pending, POINTER_CAST(connection_id));
+ return TRUE;
+}
+
+static bool
+persistent_mail_process_input_disconnected(struct persistent_mail_process *process,
+ const char *args)
+{
+ unsigned int connection_id;
+
+ connection_id = strtoul(args, NULL, 10);
+ if (connection_id == 0) {
+ i_error("BUG: Persistent mail process %s sent disconnect for "
+ "illegal connection ID 0",
+ dec2str(process->pid));
+ return FALSE;
+ }
+
+ return persistent_mail_process_disconnect(process, connection_id);
+}
+
+static bool
+persistent_mail_process_input_line(struct persistent_mail_process *process,
+ const char *line)
+{
+ if (strncmp(line, "ACK\t", 4) == 0)
+ return persistent_mail_process_input_ack(process,
+ line + 4);
+ else if (strncmp(line, "DISCONNECTED\t", 13) == 0)
+ return persistent_mail_process_input_disconnected(process,
+ line + 13);
+ else
+ return TRUE;
+}
+
+/* simply copied from auth_process_input() */
+static void
+persistent_mail_process_input(struct persistent_mail_process *process)
+{
+ const char *line;
+ bool ret;
+
+ switch (i_stream_read(process->input)) {
+ case 0:
+ return;
+ case -1:
+ /* disconnected */
+ persistent_mail_process_destroy(process);
+ return;
+ case -2:
+ /* buffer full */
+ i_error("BUG: Persistent mail process %s sent us more than %d "
+ "bytes of data", dec2str(process->pid),
+ (int)MAX_INBUF_SIZE);
+ persistent_mail_process_destroy(process);
+ return;
+ }
+
+ if (!process->version_received) {
+ line = i_stream_next_line(process->input);
+ if (line == NULL)
+ return;
+
+ /* make sure the major version matches */
+ if (strncmp(line, "VERSION\t", 8) != 0 ||
+ atoi(t_strcut(line + 8, '\t')) !=
+ PERSISTENT_MAIL_MASTER_PROTOCOL_MAJOR_VERSION) {
+ i_error("Persistent mail process %s not compatible with master "
+ "process (mixed old and new binaries?)",
+ dec2str(process->pid));
+ persistent_mail_process_destroy(process);
+ return;
+ }
+ process->version_received = TRUE;
+ }
+
+ while ((line = i_stream_next_line(process->input)) != NULL) {
+ T_BEGIN {
+ ret = persistent_mail_process_input_line(process, line);
+ } T_END;
+ if (!ret) {
+ persistent_mail_process_destroy(process);
+ break;
+ }
+ }
+}
+
+static struct persistent_mail_process *
+persistent_mail_process_new(pid_t pid, int fd,
+ struct persistent_mail_process_group *group)
+{
+ struct persistent_mail_process *process;
+ uint32_t len;
+ struct const_iovec iov[2];
+ ssize_t w;
+
+ process = i_new(struct persistent_mail_process, 1);
+ process->group = group;
+ process->pid = pid;
+ process->fd = fd;
+ process->io = io_add(fd, IO_READ, persistent_mail_process_input,
+ process);
+ process->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
+ /* unlimited buffering to preserve stream integrity, but
+ persistent_mail_process_request() enforces a limit */
+ process->output = o_stream_create_fd(fd, (size_t) -1, FALSE);
+ i_array_init(&process->connections, 10);
+ process->pending = hash_table_create(default_pool, default_pool, 0, NULL,
+ NULL);
+
+ process->next = group->processes;
+ group->processes = process;
+
+ /* send handshake. version string comes second */
+ iov[1].iov_base = t_strdup_printf("VERSION\t%u\t%u\n",
+ PERSISTENT_MAIL_MASTER_PROTOCOL_MAJOR_VERSION,
+ PERSISTENT_MAIL_MASTER_PROTOCOL_MINOR_VERSION);
+ iov[1].iov_len = strlen(iov[1].iov_base);
+
+ /* length of version string comes first */
+ len = iov[1].iov_len;
+ len = htonl(len);
+ iov[0].iov_base = &len;
+ iov[0].iov_len = sizeof len;
+
+ w = o_stream_sendv(process->output, iov, 2);
+ if (w != (ssize_t) (iov[0].iov_len + iov[1].iov_len)) {
+ if (w < 0)
+ i_error("Can't write handshake to "
+ "persistent mail process %s: %m",
+ dec2str(pid));
+ else
+ i_error("New persistent mail process %s transmit "
+ "buffer full",
+ dec2str(pid));
+ persistent_mail_process_destroy(process);
+ process = NULL;
+ }
+
+ return process;
+}
+
+static void persistent_mail_process_destroyed(pid_t pid)
+{
+ struct persistent_mail_process_group *group;
+
+ for (group = persistent_mail_process_groups; group != NULL;
+ group = group->next) {
+ struct persistent_mail_process *process;
+
+ for (process = group->processes; process != NULL;
+ process = process->next) {
+ if (process->pid == pid) {
+ persistent_mail_process_destroy(process);
+ return;
+ }
+ }
+ }
+}
+
+/* reduce arg count to mail_process_init_env() and
+ persistent_mail_process_request() */
+struct mail_env_bits {
+ unsigned int connection_id;
+ struct settings *set;
+ const char *system_user;
+ uid_t uid;
+ gid_t gid;
+ const char *chroot_dir;
+ const char *mail;
+ const char *home_dir;
+ const char *user;
+ const char *addr;
+ const char *local_ip;
+ const struct var_expand_table *var_expand_table;
+ const ARRAY_TYPE(const_string) *extra_args;
+ unsigned int dump_capability:1;
+ unsigned int persistent_mail_process:1;
+};
+
+/* "constructor" helps find missing/forgotten initializers */
+static void mail_env_bits_init(struct mail_env_bits *bits,
+ unsigned int connection_id,
+ struct settings *set, const char *system_user,
+ uid_t uid, gid_t gid, const char *chroot_dir,
+ const char *mail, const char *home_dir,
+ const char *user, const char *addr, const char *local_ip,
+ const struct var_expand_table *var_expand_table,
+ const ARRAY_TYPE(const_string) *extra_args,
+ bool dump_capability,
+ bool persistent_mail_process)
+{
+ memset(bits, 0, sizeof *bits);
+ bits->connection_id = connection_id;
+ bits->set = set;
+ bits->system_user = system_user;
+ bits->uid = uid;
+ bits->gid = gid;
+ bits->chroot_dir = chroot_dir;
+ bits->mail = mail;
+ bits->home_dir = home_dir;
+ bits->user = user;
+ bits->addr = addr;
+ bits->local_ip = local_ip;
+ bits->var_expand_table = var_expand_table;
+ bits->extra_args = extra_args;
+ bits->dump_capability = dump_capability;
+ bits->persistent_mail_process = persistent_mail_process;
+}
+
+static void mail_process_set_environment(struct settings *, const char *,
+ const struct var_expand_table *, bool);
+
+static void
+mail_process_init_env(const struct mail_env_bits *bits, bool private_env)
+{
+ unsigned int i, count;
+ const char *const *args, *p;
+
+ child_process_init_env_private(private_env);
+
+ /* setup environment - set the most important environment first
+ (paranoia about filling up environment without noticing) */
+ restrict_access_set_env(bits->system_user, bits->uid, bits->gid,
+ bits->set->mail_priv_gid_t, bits->chroot_dir,
+ bits->set->first_valid_gid,
+ bits->set->last_valid_gid,
+ bits->set->mail_access_groups,
+ bits->persistent_mail_process);
+
+ if (bits->dump_capability)
+ env_put("DUMP_CAPABILITY=1");
+
+ mail_process_set_environment(bits->set, bits->mail,
+ bits->var_expand_table,
+ bits->dump_capability);
+
+ /* extra args. uppercase key value. */
+ args = array_get(bits->extra_args, &count);
+ for (i = 0; i < count; i++) {
+ if (*args[i] == '=') {
+ /* Should be caught by dovecot-auth already */
+ i_fatal("Userdb returned data with empty key (%s)",
+ args[i]);
+ }
+ p = strchr(args[i], '=');
+ if (p == NULL) {
+ /* boolean */
+ env_put(t_strconcat(t_str_ucase(args[i]), "=1", NULL));
+
+ } else {
+ /* key=value */
+ env_put(t_strconcat(t_str_ucase(
+ t_strdup_until(args[i], p)), p, NULL));
+ }
+ }
+
+ env_put("LOGGED_IN=1");
+ env_put(t_strconcat("HOME=", bits->home_dir, NULL));
+ env_put(t_strconcat("USER=", bits->user, NULL));
+ env_put(t_strconcat("IP=", bits->addr, NULL));
+ env_put(t_strconcat("LOCAL_IP=", bits->local_ip, NULL));
+
+ if (bits->persistent_mail_process) {
+ env_put("PERSISTENT_MAIL_PROCESS=1");
+ env_put(t_strdup_printf("CONNECTION_ID=%u",
+ bits->connection_id));
+ }
+}
+
+static void
+persistent_mail_process_buffer_env(buffer_t *buffer,
+ const struct mail_env_bits *bits)
+{
+ extern char **environ;
+ char **env;
+
+ /* Allocate all of the environment strings from env-util's private
+ pool, which is all then released at the env_clean() below. If
+ we used the system's putenv() instead, all the strings it mallocs
+ would be leaked. */
+ mail_process_init_env(bits, TRUE);
+
+ for (env = environ; *env != NULL; env++) {
+ buffer_append(buffer, *env, strlen(*env));
+ if (env[1] != NULL)
+ buffer_append_c(buffer, '\n');
+ }
+
+ env_clean();
+}
+
+static int
+persistent_mail_process_request(struct persistent_mail_process *process,
+ int socket_fd,
+ const struct mail_env_bits *bits)
+{
+ static const char hotpotato[] = HOTPOTATO;
+ uint32_t id;
+ char message[PERSISTENT_MAIL_MASTER_MESSAGE_SIZE];
+ ssize_t sent;
+
+ if (o_stream_get_buffer_used_size(process->output) >=
+ MAX_OUTBUF_SIZE) {
+ i_warning("Persistent mail process %s transmit buffer full; "
+ "skipping",
+ dec2str(process->pid));
+ return 0;
+ }
+
+ /* The login process passed the fd to us, now we hand it to the
+ persistent mail process. It's a hot potato. Here the
+ connection_id doubles as a receipt for the fd; see below. */
+ id = htonl(bits->connection_id);
+ memcpy(message, hotpotato, sizeof hotpotato - 1);
+ memcpy(&message[sizeof hotpotato - 1], &id, sizeof id);
+ sent = fd_send(process->fd, socket_fd, message, sizeof message);
+ if (sent == sizeof message) {
+ buffer_t *buffer;
+ const void *data;
+ size_t data_len;
+ uint32_t env_len;
+
+ buffer = buffer_create_dynamic(pool_datastack_create(), 2048);
+ env_len = 0;
+ buffer_append(buffer, &env_len, sizeof env_len);
+ persistent_mail_process_buffer_env(buffer, bits);
+
+ data = buffer_get_data(buffer, &data_len);
+ i_assert(data_len >= sizeof env_len);
+ env_len = data_len - sizeof env_len;
+ env_len = htonl(env_len);
+ buffer_write(buffer, 0, &env_len, sizeof env_len);
+
+ sent = o_stream_send(process->output, data, data_len);
+ if (sent == (ssize_t) data_len) {
+ int pending_fd;
+
+ /* can't close socket (on MacOSX) until receiver
+ has it so stick a copy of it in the pending
+ list. could stash without dup but that would
+ change too much other code. */
+ pending_fd = dup(socket_fd);
+ if (pending_fd >= 0)
+ fd_close_on_exec(pending_fd, TRUE);
+ /* else don't sweat if dup failed. this is just
+ a temporary(?) workaround anyway */
+
+ hash_insert(process->pending,
+ POINTER_CAST(bits->connection_id),
+ persistent_mail_pender_new(pending_fd));
+ return 1;
+ }
+ }
+
+ if (sent < 0)
+ i_error("Error sending request to "
+ "persistent mail process %s: %m",
+ dec2str(process->pid));
+ else
+ i_error("Persistent mail process %s "
+ "transmit buffer full; detaching",
+ dec2str(process->pid));
+ persistent_mail_process_destroy(process);
+ return -1;
+}
+
+static int persistent_mail_process_cmp(const void *a, const void *b)
+{
+ const struct persistent_mail_process * const *app = a;
+ const struct persistent_mail_process * const *bpp = b;
+ const struct persistent_mail_process *process_a = *app;
+ const struct persistent_mail_process *process_b = *bpp;
+ int count_a = array_count(&process_a->connections);
+ int count_b = array_count(&process_b->connections);
+ return count_a - count_b;
+}
+/* APPLE end */
+
static bool validate_uid_gid(struct settings *set, uid_t uid, gid_t gid,
const char *user)
{
@@ -167,11 +1021,12 @@
return FALSE;
}
+/* APPLE changed type of pid/uid args*/
static const struct var_expand_table *
get_var_expand_table(const char *protocol,
const char *user, const char *home,
const char *local_ip, const char *remote_ip,
- pid_t pid, uid_t uid)
+ const char *pid, const char *uid)
{
#define VAR_EXPAND_HOME_IDX 4
static struct var_expand_table static_tab[] = {
@@ -199,8 +1054,8 @@
tab[VAR_EXPAND_HOME_IDX].value = home;
tab[5].value = local_ip;
tab[6].value = remote_ip;
- tab[7].value = dec2str(pid);
- tab[8].value = dec2str(uid);
+ tab[7].value = pid;
+ tab[8].value = uid;
return tab;
}
@@ -467,7 +1322,7 @@
get_var_expand_table(protocol, getenv("USER"), getenv("HOME"),
getenv("TCPLOCALIP"),
getenv("TCPREMOTEIP"),
- getpid(), geteuid());
+ dec2str(getpid()), dec2str(geteuid()));
/* set up logging */
env_put(t_strconcat("LOG_TIMESTAMP=", set->log_timestamp, NULL));
@@ -550,15 +1405,24 @@
pid_t pid;
uid_t uid;
gid_t gid;
- ARRAY_DEFINE(extra_args, const char *);
- unsigned int i, len, count, left, process_count, throttle;
+ ARRAY_TYPE(const_string) extra_args; /* APPLE new decl, same type */
+ unsigned int i, len, left, process_count, throttle;
int ret, log_fd, nice_value, chdir_errno;
bool home_given, nfs_check;
+ /* APPLE begin */
+ unsigned int connection_id;
+ const char *mail_location;
+ struct persistent_mail_process_group *pmp_group;
+ int pmp_fd[2];
+ const struct var_expand_table *pmp_var_expand_table;
+ struct mail_env_bits bits;
+ /* APPLE end */
i_assert(process_type == PROCESS_TYPE_IMAP ||
process_type == PROCESS_TYPE_POP3);
- if (mail_process_count == set->max_mail_processes) {
+ if (set->mail_process_per_connection && /* APPLE */
+ mail_process_count == set->max_mail_processes) {
i_error("Maximum number of mail processes exceeded "
"(see max_mail_processes setting)");
return MASTER_LOGIN_STATUS_INTERNAL_ERROR;
@@ -605,7 +1469,9 @@
process_group = dump_capability ? NULL :
mail_process_group_lookup(process_type, user, remote_ip);
process_count = process_group == NULL ? 0 :
- array_count(&process_group->processes);
+ array_count(&process_group->processes) +
+ array_count(&process_group->connections); /* APPLE */
+ /* APPLE process_count is really count of connections */
if (process_count >= set->mail_max_userip_connections &&
set->mail_max_userip_connections != 0 &&
master_user == NULL)
@@ -669,9 +1535,115 @@
home_dir += len - 2;
}
+ /* APPLE begin */
+ do
+ connection_id = ++next_connection_id;
+ while (connection_id == 0 ||
+ (!dump_capability &&
+ hash_lookup(mail_connections,
+ POINTER_CAST(connection_id)) != NULL));
+ /* managesieve patches in a new process_type; keep it out of pmp */
+ if ((process_type == PROCESS_TYPE_IMAP ||
+ process_type == PROCESS_TYPE_POP3) &&
+ !set->mail_process_per_connection && !dump_capability) {
+ struct persistent_mail_process *process, **process_vec;
+ ARRAY_DEFINE(process_arr, struct persistent_mail_process *);
+
+ if (*chroot_dir != '\0' &&
+ strcmp(chroot_dir, set->mail_chroot) != 0) {
+ i_error("Can't chroot to directory '%s' (user %s) "
+ "with mail_process_per_connection=no",
+ chroot_dir, user);
+ return MASTER_LOGIN_STATUS_INTERNAL_ERROR;
+ }
+#ifdef HAVE_SETPRIORITY
+ if (nice_value != 0)
+ i_warning("Can't adjust nice %+d (user %s) "
+ "with mail_process_per_connection=no; "
+ "ignoring nice setting",
+ nice_value, user);
+#endif
+
+ pmp_group = persistent_mail_process_group_find(set);
+ i_assert(pmp_group != NULL); /* here's hoping */
+
+ /* use pmp with fewest connections */
+ t_array_init(&process_arr, mail_process_count);
+ for (process = pmp_group->processes; process != NULL;
+ process = process->next)
+ array_append(&process_arr, &process, 1);
+ process_vec = array_get_modifiable(&process_arr,
+ &process_count);
+ qsort(process_vec, process_count, sizeof *process_vec,
+ persistent_mail_process_cmp);
+ for (i = 0; i < process_count; i++) {
+ unsigned int connection_count;
+
+ process = process_vec[i];
+
+ connection_count = array_count(&process->connections);
+ if (connection_count == 0 ||
+ connection_count >= set->mail_max_connections)
+ continue;
+
+ var_expand_table =
+ get_var_expand_table(process_names[process_type],
+ user, home_given ? home_dir : NULL,
+ net_ip2addr(local_ip),
+ net_ip2addr(remote_ip),
+ dec2str(process->pid),
+ dec2str(uid));
+ addr = net_ip2addr(remote_ip);
+ mail_env_bits_init(&bits, connection_id, set,
+ system_user, uid, gid, chroot_dir,
+ mail, home_dir, user, addr, net_ip2addr(local_ip),
+ var_expand_table, &extra_args,
+ dump_capability, TRUE);
+ ret = persistent_mail_process_request(process,
+ socket_fd,
+ &bits);
+ if (ret > 0) {
+ struct mail_connection *conn;
+
+ if (process_group == NULL) {
+ process_group =
+ mail_process_group_create(process_type,
+ user,
+ remote_ip);
+ }
+
+ conn = array_append_space(&process_group->connections);
+ conn->connection_id = connection_id;
+ conn->connected_at = ioloop_time;
+
+ array_append(&process->connections,
+ &connection_id, 1);
+ hash_insert(mail_connections,
+ POINTER_CAST(connection_id),
+ process_group);
+
+ return MASTER_LOGIN_STATUS_OK;
+ } else if (ret < 0)
+ return MASTER_LOGIN_STATUS_INTERNAL_ERROR;
+ }
+ /* fall through to make a new persistent mail process */
+ } else
+ pmp_group = NULL;
+ if (mail_process_count == set->max_mail_processes) {
+ i_error("Maximum number of mail processes exceeded "
+ "(see max_mail_processes setting)");
+ return MASTER_LOGIN_STATUS_INTERNAL_ERROR;
+ }
+ /* APPLE end */
+
if (!dump_capability) {
throttle = set->mail_debug ? 0 :
set->mail_log_max_lines_per_sec;
+
+ /* APPLE */
+ if (pmp_group != NULL)
+ throttle *= set->mail_max_connections;
+
log_fd = log_create_pipe(&log, throttle);
if (log_fd == -1)
return MASTER_LOGIN_STATUS_INTERNAL_ERROR;
@@ -690,13 +1662,35 @@
if (set->nfs_check && !set->mail_nfs_index && !dump_capability) {
set->nfs_check = FALSE;
nfs_check = TRUE;
+
+ /* APPLE moved this chunk */
+ /* ideally we should check all of the namespaces,
+ but for now don't bother. need to read environment
+ before clobbering it below. */
+ mail_location = getenv("NAMESPACE_1");
+ if (mail_location == NULL)
+ mail_location = getenv("MAIL");
} else {
nfs_check = FALSE;
+ mail_location = NULL; /* APPLE hush compiler */
}
+ /* APPLE */
+ if (pmp_group) {
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pmp_fd) < 0) {
+ i_error("socketpair() failed: %m");
+ return MASTER_LOGIN_STATUS_INTERNAL_ERROR;
+ }
+ } else
+ pmp_fd[0] = pmp_fd[1] = -1;
+
pid = fork();
if (pid < 0) {
i_error("fork() failed: %m");
+ if (pmp_fd[0] >= 0) { /* APPLE */
+ (void) close(pmp_fd[0]);
+ (void) close(pmp_fd[1]);
+ }
(void)close(log_fd);
return MASTER_LOGIN_STATUS_INTERNAL_ERROR;
}
@@ -706,12 +1700,22 @@
user, home_given ? home_dir : NULL,
net_ip2addr(local_ip),
net_ip2addr(remote_ip),
- pid != 0 ? pid : getpid(), uid);
+ dec2str(pid != 0 ? pid : getpid()),
+ dec2str(uid));
+ /* APPLE */
+ pmp_var_expand_table = pmp_group == NULL ? NULL :
+ get_var_expand_table(process_names[process_type],
+ "*", "*", "*", "*",
+ dec2str(pid != 0 ? pid : getpid()),
+ "*");
+
str = t_str_new(128);
if (pid != 0) {
/* master */
- var_expand(str, set->mail_log_prefix, var_expand_table);
+ var_expand(str, set->mail_log_prefix,
+ pmp_group == NULL ? /* APPLE */
+ var_expand_table : pmp_var_expand_table);
if (!dump_capability) {
log_set_prefix(log, str_c(str));
@@ -722,7 +1726,28 @@
user,
remote_ip);
}
- mail_process_group_add(process_group, pid);
+ mail_process_group_add(process_group, pid,
+ connection_id, /* APPLE */
+ pmp_group != NULL); /* APPLE */
+
+ /* APPLE */
+ if (pmp_group != NULL) {
+ struct persistent_mail_process *pmp;
+
+ net_set_nonblock(pmp_fd[0], TRUE);
+ fd_close_on_exec(pmp_fd[0], TRUE);
+ net_set_sndbuf(pmp_fd[0], MAX_OUTBUF_SIZE);
+ pmp = persistent_mail_process_new(pid,
+ pmp_fd[0],
+ pmp_group);
+ (void) close(pmp_fd[1]);
+
+ array_append(&pmp->connections,
+ &connection_id, 1);
+ hash_insert(mail_connections,
+ POINTER_CAST(connection_id),
+ process_group);
+ }
}
(void)close(log_fd);
return MASTER_LOGIN_STATUS_OK;
@@ -737,36 +1762,60 @@
if (!dump_capability) {
str_append(str, "master-");
- var_expand(str, set->mail_log_prefix, var_expand_table);
+ var_expand(str, set->mail_log_prefix,
+ pmp_group == NULL ? /* APPLE */
+ var_expand_table : pmp_var_expand_table);
log_set_prefix(log, str_c(str));
}
- child_process_init_env();
+ if (pmp_group != NULL) { /* APPLE */
+ /* move master communication handle to 0 */
+ if (dup2(pmp_fd[1], 0) < 0)
+ i_fatal("dup2(stdin) failed: %m");
+
+ (void) close(pmp_fd[0]);
+ (void) close(pmp_fd[1]);
+ pmp_fd[0] = pmp_fd[1] = -1;
+
+ /* set stdout to /dev/null to ignore output */
+ if (dup2(null_fd, 1) < 0)
+ i_fatal("dup2(stdout) failed: %m");
+
+ /* stderr = log, 3 = client socket */
+ if (dup2(log_fd, 2) < 0)
+ i_fatal("dup2(stderr) failed: %m");
+ if (socket_fd != 3) {
+ if (dup2(socket_fd, 3) < 0)
+ i_fatal("dup2(3) failed: %m");
+ }
- /* move the client socket into stdin and stdout fds, log to stderr */
- if (dup2(dump_capability ? null_fd : socket_fd, 0) < 0)
- i_fatal("dup2(stdin) failed: %m");
- if (dup2(socket_fd, 1) < 0)
- i_fatal("dup2(stdout) failed: %m");
- if (dup2(log_fd, 2) < 0)
- i_fatal("dup2(stderr) failed: %m");
+ for (i = 0; i <= 3; i++)
+ fd_close_on_exec(i, FALSE);
+ } else {
+ /* move the client socket into stdin and stdout fds, log to stderr */
+ if (dup2(dump_capability ? null_fd : socket_fd, 0) < 0)
+ i_fatal("dup2(stdin) failed: %m");
+ if (dup2(socket_fd, 1) < 0)
+ i_fatal("dup2(stdout) failed: %m");
+ if (dup2(log_fd, 2) < 0)
+ i_fatal("dup2(stderr) failed: %m");
- for (i = 0; i < 3; i++)
- fd_close_on_exec(i, FALSE);
+ for (i = 0; i < 3; i++)
+ fd_close_on_exec(i, FALSE);
+ }
- /* setup environment - set the most important environment first
- (paranoia about filling up environment without noticing) */
- restrict_access_set_env(system_user, uid, gid, set->mail_priv_gid_t,
- chroot_dir,
- set->first_valid_gid, set->last_valid_gid,
- set->mail_access_groups);
+ /* APPLE significant reordering/refactoring of environment code */
+ addr = net_ip2addr(remote_ip);
+ mail_env_bits_init(&bits, connection_id, set, system_user, uid, gid,
+ chroot_dir, mail, home_dir, user, addr, net_ip2addr(local_ip),
+ var_expand_table, &extra_args, dump_capability,
+ pmp_group != NULL);
+ mail_process_init_env(&bits, FALSE);
restrict_process_size(set->mail_process_size, (unsigned int)-1);
- if (dump_capability)
- env_put("DUMP_CAPABILITY=1");
-
- if (*home_dir == '\0' && *chroot_dir == '\0') {
+ if ((*home_dir == '\0' && *chroot_dir == '\0') ||
+ pmp_group != NULL) { /* APPLE */
full_home_dir = "";
ret = -1;
} else {
@@ -814,48 +1863,11 @@
i_fatal("chdir(/tmp) failed: %m");
}
- mail_process_set_environment(set, mail, var_expand_table,
- dump_capability);
-
- /* extra args. uppercase key value. */
- args = array_get(&extra_args, &count);
- for (i = 0; i < count; i++) {
- if (*args[i] == '=') {
- /* Should be caught by dovecot-auth already */
- i_fatal("Userdb returned data with empty key (%s)",
- args[i]);
- }
- p = strchr(args[i], '=');
- if (p == NULL) {
- /* boolean */
- env_put(t_strconcat(t_str_ucase(args[i]), "=1", NULL));
-
- } else {
- /* key=value */
- env_put(t_strconcat(t_str_ucase(
- t_strdup_until(args[i], p)), p, NULL));
- }
- }
-
- if (nfs_check) {
- /* ideally we should check all of the namespaces,
- but for now don't bother. */
- const char *mail_location = getenv("NAMESPACE_1");
-
- if (mail_location == NULL)
- mail_location = getenv("MAIL");
+ if (nfs_check)
nfs_warn_if_found(mail_location, full_home_dir);
- }
- env_put("LOGGED_IN=1");
- env_put(t_strconcat("HOME=", home_dir, NULL));
- env_put(t_strconcat("USER=", user, NULL));
-
- addr = net_ip2addr(remote_ip);
- env_put(t_strconcat("IP=", addr, NULL));
- env_put(t_strconcat("LOCAL_IP=", net_ip2addr(local_ip), NULL));
-
- if (!set->verbose_proctitle)
+ if (!set->verbose_proctitle ||
+ pmp_group != NULL) /* APPLE */
title[0] = '\0';
else {
if (addr == NULL)
@@ -889,25 +1901,32 @@
pid_t pid, bool abnormal_exit ATTR_UNUSED)
{
struct mail_process_group *group = (struct mail_process_group *)process;
- const pid_t *pids;
+ const struct mail_process *processes;
unsigned int i, count;
- pids = array_get(&group->processes, &count);
- if (count == 1) {
- /* last process in this group */
- i_assert(pids[0] == pid);
- hash_remove(mail_process_groups, group);
- mail_process_group_free(group);
- } else {
- for (i = 0; i < count; i++) {
- if (pids[i] == pid)
- break;
- }
- i_assert(i != count);
+ processes = array_get(&group->processes, &count);
+
+ /* APPLE reworked to support processes and connections arrays */
+ i_assert(group->children > 0);
+ for (i = 0; i < count; i++)
+ if (processes[i].pid == pid)
+ break;
+ if (i != count)
array_delete(&group->processes, i, 1);
- }
+ else
+ i_assert(count == 0);
mail_process_count--;
+
+ persistent_mail_process_destroyed(pid);
+
+ group->children -= 1;
+ if (group->children == 0 &&
+ array_count(&group->processes) == 0 &&
+ array_count(&group->connections) == 0) {
+ hash_remove(mail_process_groups, group);
+ mail_process_group_free(group);
+ }
}
void mail_processes_init(void)
@@ -916,6 +1935,14 @@
mail_process_group_hash,
mail_process_group_cmp);
+ /* APPLE */
+ persistent_mail_process_groups = NULL;
+ mail_connections = hash_table_create(default_pool, default_pool, 0, NULL,
+ NULL);
+#ifdef SIGINFO
+ lib_signals_set_handler(SIGINFO, TRUE, sig_info, NULL);
+#endif
+
child_process_set_destroy_callback(PROCESS_TYPE_IMAP,
mail_process_destroyed);
child_process_set_destroy_callback(PROCESS_TYPE_POP3,
@@ -927,6 +1954,15 @@
struct hash_iterate_context *iter;
void *key, *value;
+ /* APPLE */
+ while (persistent_mail_process_groups != NULL) {
+ struct persistent_mail_process_group *group = persistent_mail_process_groups;
+
+ persistent_mail_process_groups = group->next;
+ persistent_mail_process_group_destroy(group);
+ }
+ hash_table_destroy(&mail_connections);
+
iter = hash_iterate_init(mail_process_groups);
while (hash_iterate(iter, &key, &value)) {
struct mail_process_group *group = value;
diff -Nur dovecot-1.1.7+patch9/src/master/mail-process.h dovecot-patch/src/master/mail-process.h
--- dovecot-1.1.7+patch9/src/master/mail-process.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/master/mail-process.h 2009-01-06 10:08:19.000000000 -0600
@@ -18,4 +18,6 @@
void mail_processes_init(void);
void mail_processes_deinit(void);
+void persistent_mail_processes_destroy_all(void); /* APPLE */
+
#endif
diff -Nur dovecot-1.1.7+patch9/src/master/main.c dovecot-patch/src/master/main.c
--- dovecot-1.1.7+patch9/src/master/main.c 2009-01-06 10:08:10.000000000 -0600
+++ dovecot-patch/src/master/main.c 2009-01-06 10:08:19.000000000 -0600
@@ -148,6 +148,7 @@
i_warning("SIGHUP received - reloading configuration");
/* restart auth and login processes */
+ persistent_mail_processes_destroy_all(); /* APPLE */
login_processes_destroy_all();
auth_processes_destroy_all();
dict_process_kill();
diff -Nur dovecot-1.1.7+patch9/src/master/master-settings-defs.c dovecot-patch/src/master/master-settings-defs.c
--- dovecot-1.1.7+patch9/src/master/master-settings-defs.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/master/master-settings-defs.c 2009-01-06 10:08:19.000000000 -0600
@@ -103,6 +103,8 @@
DEF_BOOL(mail_drop_priv_before_exec),
DEF_STR(mail_executable),
+ DEF_BOOL(mail_process_per_connection), /* APPLE */
+ DEF_INT(mail_max_connections), /* APPLE */
DEF_INT(mail_process_size),
DEF_STR(mail_plugins),
DEF_STR(mail_plugin_dir),
diff -Nur dovecot-1.1.7+patch9/src/master/master-settings.c dovecot-patch/src/master/master-settings.c
--- dovecot-1.1.7+patch9/src/master/master-settings.c 2008-11-15 11:13:18.000000000 -0600
+++ dovecot-patch/src/master/master-settings.c 2009-01-06 11:32:21.000000000 -0600
@@ -269,6 +269,8 @@
MEMBER(mail_drop_priv_before_exec) FALSE,
MEMBER(mail_executable) PKG_LIBEXECDIR"/imap",
+ MEMBER(mail_process_per_connection) TRUE, /* APPLE */
+ MEMBER(mail_max_connections) 20, /* APPLE */
MEMBER(mail_process_size) 256,
MEMBER(mail_plugins) "",
MEMBER(mail_plugin_dir) MODULEDIR"/imap",
@@ -812,6 +814,27 @@
return FALSE;
}
+ /* APPLE */
+ if (!set->mail_process_per_connection &&
+ ((set->protocol == MAIL_PROTOCOL_IMAP &&
+ strcmp(set->mail_executable, PKG_LIBEXECDIR"/imap") != 0) ||
+ (set->protocol == MAIL_PROTOCOL_POP3 &&
+ strcmp(set->mail_executable, PKG_LIBEXECDIR"/pop3") != 0))) {
+ /* mail_process_per_connection=no changes the interface
+ between the master and the mail processes. Don't
+ break unaware scripts. Force with trailing !.*/
+ size_t len = strlen(set->mail_executable);
+ if (len <= 0 || set->mail_executable[len - 1] != '!') {
+ i_error("mail_executable must be the default when "
+ "mail_process_per_connection=no; force with !");
+ return FALSE;
+ }
+ }
+ if (set->mail_max_connections < 1) {
+ i_error("mail_max_connections must be at least 1");
+ return FALSE;
+ }
+
if (set->last_valid_uid != 0 &&
set->first_valid_uid > set->last_valid_uid) {
i_error("first_valid_uid can't be larger than last_valid_uid");
diff -Nur dovecot-1.1.7+patch9/src/master/master-settings.h dovecot-patch/src/master/master-settings.h
--- dovecot-1.1.7+patch9/src/master/master-settings.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/master/master-settings.h 2009-01-06 10:08:19.000000000 -0600
@@ -115,6 +115,8 @@
bool mail_drop_priv_before_exec;
const char *mail_executable;
+ bool mail_process_per_connection; /* APPLE */
+ unsigned int mail_max_connections; /* APPLE */
unsigned int mail_process_size;
const char *mail_plugins;
const char *mail_plugin_dir;
diff -Nur dovecot-1.1.7+patch9/src/plugins/acl/acl-mailbox-list.c dovecot-patch/src/plugins/acl/acl-mailbox-list.c
--- dovecot-1.1.7+patch9/src/plugins/acl/acl-mailbox-list.c 2008-10-31 10:46:10.000000000 -0500
+++ dovecot-patch/src/plugins/acl/acl-mailbox-list.c 2009-01-06 10:08:19.000000000 -0600
@@ -404,10 +404,7 @@
acl_env = getenv("ACL");
i_assert(acl_env != NULL);
- owner_username = getenv("USER");
- if (owner_username == NULL)
- i_fatal("ACL: USER environment not set");
-
+ owner_username = list->ns->user->username;
current_username = getenv("MASTER_USER");
if (current_username == NULL)
current_username = owner_username;
diff -Nur dovecot-1.1.7+patch9/src/plugins/convert/convert-plugin.c dovecot-patch/src/plugins/convert/convert-plugin.c
--- dovecot-1.1.7+patch9/src/plugins/convert/convert-plugin.c 2008-11-15 11:21:03.000000000 -0600
+++ dovecot-patch/src/plugins/convert/convert-plugin.c 2009-01-06 10:08:19.000000000 -0600
@@ -19,11 +19,7 @@
struct convert_settings set;
memset(&set, 0, sizeof(set));
- set.user = getenv("USER");
- if (set.user == NULL)
- i_fatal("convert plugin: USER unset");
- set.home = getenv("HOME");
- if (set.home == NULL)
+ if (namespaces->user->home == NULL)
i_fatal("convert plugin: HOME unset");
set.skip_broken_mailboxes =
diff -Nur dovecot-1.1.7+patch9/src/plugins/convert/convert-storage.c dovecot-patch/src/plugins/convert/convert-storage.c
--- dovecot-1.1.7+patch9/src/plugins/convert/convert-storage.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/plugins/convert/convert-storage.c 2009-01-06 10:08:19.000000000 -0600
@@ -390,6 +390,7 @@
struct mail_namespace *dest_namespaces,
const struct convert_settings *set)
{
+ struct mail_user *user = dest_namespaces->user;
struct mail_namespace *source_ns, *dest_inbox_ns;
struct dotlock *dotlock;
enum mail_storage_flags src_flags;
@@ -397,19 +398,19 @@
const char *path, *error;
int ret;
- source_ns = mail_namespaces_init_empty(pool_datastack_create());
+ source_ns = mail_namespaces_init_empty(user);
dest_inbox_ns = mail_namespace_find_inbox(dest_namespaces);
src_flags = dest_inbox_ns->storage->flags;
lock_method = dest_inbox_ns->storage->lock_method;
src_flags |= MAIL_STORAGE_FLAG_NO_AUTOCREATE;
- if (mail_storage_create(source_ns, NULL, source_data, set->user,
+ if (mail_storage_create(source_ns, NULL, source_data,
src_flags, lock_method, &error) < 0) {
/* No need for conversion. */
return 0;
}
- path = t_strconcat(set->home, "/"CONVERT_LOCK_FILENAME, NULL);
+ path = t_strconcat(user->home, "/"CONVERT_LOCK_FILENAME, NULL);
dotlock_settings.use_excl_lock =
(source_ns->storage->flags &
MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
@@ -428,7 +429,7 @@
/* just in case if another process just had converted the mailbox,
reopen the source storage */
mail_storage_destroy(&source_ns->storage);
- if (mail_storage_create(source_ns, NULL, source_data, set->user,
+ if (mail_storage_create(source_ns, NULL, source_data,
src_flags, lock_method, &error) < 0) {
/* No need for conversion anymore. */
file_dotlock_delete(&dotlock);
diff -Nur dovecot-1.1.7+patch9/src/plugins/convert/convert-storage.h dovecot-patch/src/plugins/convert/convert-storage.h
--- dovecot-1.1.7+patch9/src/plugins/convert/convert-storage.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/plugins/convert/convert-storage.h 2009-01-06 10:08:19.000000000 -0600
@@ -4,8 +4,6 @@
struct mail_namespace;
struct convert_settings {
- const char *user;
- const char *home;
bool skip_broken_mailboxes;
bool skip_dotdirs;
char alt_hierarchy_char;
diff -Nur dovecot-1.1.7+patch9/src/plugins/convert/convert-tool.c dovecot-patch/src/plugins/convert/convert-tool.c
--- dovecot-1.1.7+patch9/src/plugins/convert/convert-tool.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/plugins/convert/convert-tool.c 2009-01-06 10:08:19.000000000 -0600
@@ -18,6 +18,7 @@
{
struct ioloop *ioloop;
struct convert_settings set;
+ struct mail_user *user;
struct mail_namespace *dest_ns;
enum mail_storage_flags dest_flags;
enum file_lock_method lock_method;
@@ -37,9 +38,6 @@
ioloop = io_loop_create();
memset(&set, 0, sizeof(set));
- set.user = argv[1];
- set.home = argv[2];
-
for (i = 5; i < argc; i++) {
if (strcmp(argv[i], "skip_broken_mailboxes") != 0)
set.skip_broken_mailboxes = TRUE;
@@ -50,8 +48,10 @@
}
mail_storage_parse_env(&dest_flags, &lock_method);
- dest_ns = mail_namespaces_init_empty(pool_datastack_create());
- if (mail_storage_create(dest_ns, NULL, argv[4], set.user,
+ user = mail_user_init(argv[1], argv[2]);
+ dest_ns = mail_namespaces_init_empty(user);
+
+ if (mail_storage_create(dest_ns, NULL, argv[4],
dest_flags, lock_method, &error) < 0) {
i_fatal("Failed to create destination "
"mail storage with data '%s': %s", argv[4], error);
@@ -64,7 +64,7 @@
i_error("Source storage not found");
else
i_error("Internal failure");
- mail_namespaces_deinit(&dest_ns);
+ mail_user_deinit(&user);
io_loop_destroy(&ioloop);
mail_storage_deinit();
diff -Nur dovecot-1.1.7+patch9/src/plugins/expire/expire-plugin.c dovecot-patch/src/plugins/expire/expire-plugin.c
--- dovecot-1.1.7+patch9/src/plugins/expire/expire-plugin.c 2008-11-15 11:21:05.000000000 -0600
+++ dovecot-patch/src/plugins/expire/expire-plugin.c 2009-01-06 11:31:00.000000000 -0600
@@ -289,6 +289,11 @@
{
const char *expunge_env, *altmove_env, *dict_uri;
+ /* APPLE XXX teach this plugin about persistent mail processes */
+ if (getenv("PERSISTENT_MAIL_PROCESS") != NULL)
+ i_fatal("expire plugin incompatible with "
+ "mail_process_per_connection=no");
+
expunge_env = getenv("EXPIRE");
altmove_env = getenv("EXPIRE_ALTMOVE");
if (expunge_env != NULL || altmove_env != NULL) {
diff -Nur dovecot-1.1.7+patch9/src/plugins/expire/expire-tool.c dovecot-patch/src/plugins/expire/expire-tool.c
--- dovecot-1.1.7+patch9/src/plugins/expire/expire-tool.c 2008-11-05 12:01:47.000000000 -0600
+++ dovecot-patch/src/plugins/expire/expire-tool.c 2009-01-06 10:08:19.000000000 -0600
@@ -2,6 +2,7 @@
#include "lib.h"
#include "ioloop.h"
+#include "env-util.h"
#include "file-lock.h"
#include "randgen.h"
#include "lib-signals.h"
@@ -25,8 +26,7 @@
struct auth_connection *auth_conn;
char *user;
- pool_t namespace_pool;
- struct mail_namespace *ns;
+ struct mail_user *mail_user;
bool testrun;
};
@@ -34,6 +34,7 @@
{
int ret;
+ env_clean();
if ((ret = auth_client_put_user_env(ctx->auth_conn, user)) <= 0) {
if (ret < 0)
return ret;
@@ -42,16 +43,16 @@
return 0;
}
- if (mail_namespaces_init(ctx->namespace_pool, user, &ctx->ns) < 0)
+ ctx->mail_user = mail_user_init(user, getenv("HOME"));
+ if (mail_namespaces_init(ctx->mail_user) < 0)
return -1;
return 1;
}
static void user_deinit(struct expire_context *ctx)
{
- mail_namespaces_deinit(&ctx->ns);
+ mail_user_deinit(&ctx->mail_user);
i_free_and_null(ctx->user);
- p_clear(ctx->namespace_pool);
}
static int
@@ -90,7 +91,7 @@
search_arg.next = NULL;
ns_mailbox = mailbox;
- ns = mail_namespace_find(ctx->ns, &ns_mailbox);
+ ns = mail_namespace_find(ctx->mail_user->namespaces, &ns_mailbox);
if (ns == NULL) {
/* entire namespace no longer exists, remove the entry */
if (ctx->testrun)
@@ -203,7 +204,6 @@
memset(&ctx, 0, sizeof(ctx));
ctx.testrun = testrun;
ctx.auth_conn = auth_connection_init(auth_socket);
- ctx.namespace_pool = pool_alloconly_create("namespaces", 1024);
env = expire_env_init(getenv("EXPIRE"), getenv("EXPIRE_ALTMOVE"));
dict = dict_init(getenv("EXPIRE_DICT"), DICT_DATA_TYPE_UINT32, "");
if (dict == NULL)
diff -Nur dovecot-1.1.7+patch9/src/plugins/fts-solr/fts-backend-solr.c dovecot-patch/src/plugins/fts-solr/fts-backend-solr.c
--- dovecot-1.1.7+patch9/src/plugins/fts-solr/fts-backend-solr.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/plugins/fts-solr/fts-backend-solr.c 2009-01-06 10:08:19.000000000 -0600
@@ -4,6 +4,7 @@
#include "array.h"
#include "str.h"
#include "mail-storage-private.h"
+#include "mail-namespace.h"
#include "solr-connection.h"
#include "fts-solr-plugin.h"
@@ -93,7 +94,7 @@
str_printfa(str, "uidv:%u%%20box:", status.uidvalidity);
solr_quote_str(str, backend->box->name);
str_append(str, "%20user:");
- solr_quote_str(str, backend->box->storage->user);
+ solr_quote_str(str, backend->box->storage->ns->user->username);
t_array_init(&uids, 1);
if (solr_connection_select(solr_conn, str_c(str), &uids, NULL) < 0)
@@ -160,11 +161,11 @@
str_append(cmd, "<field name=\"box\">");
xml_encode(cmd, box->name);
str_append(cmd, "</field><field name=\"user\">");
- xml_encode(cmd, box->storage->user);
+ xml_encode(cmd, box->storage->ns->user->username);
str_printfa(cmd, "</field><field name=\"id\">%u/%u/",
uid, ctx->uid_validity);
- xml_encode(cmd, box->storage->user);
+ xml_encode(cmd, box->storage->ns->user->username);
str_append_c(cmd, '/');
xml_encode(cmd, box->name);
str_append(cmd, "</field>");
@@ -228,7 +229,7 @@
cmd = t_str_new(256);
str_printfa(cmd, "<delete><id>%u/%u/",
mail->uid, status.uidvalidity);
- xml_encode(cmd, mail->box->storage->user);
+ xml_encode(cmd, mail->box->storage->ns->user->username);
str_append_c(cmd, '/');
xml_encode(cmd, mail->box->name);
str_append(cmd, "</id></delete>");
@@ -300,7 +301,7 @@
str_printfa(str, "&fq=uidv:%u%%20box:", status.uidvalidity);
solr_quote_str(str, box->name);
str_append(str, "%20user:");
- solr_quote_str(str, box->storage->user);
+ solr_quote_str(str, box->storage->ns->user->username);
array_clear(maybe_uids);
return solr_connection_select(solr_conn, str_c(str),
diff -Nur dovecot-1.1.7+patch9/src/plugins/imap-quota/imap-quota-plugin.c dovecot-patch/src/plugins/imap-quota/imap-quota-plugin.c
--- dovecot-1.1.7+patch9/src/plugins/imap-quota/imap-quota-plugin.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/plugins/imap-quota/imap-quota-plugin.c 2009-01-06 10:08:19.000000000 -0600
@@ -49,6 +49,7 @@
{
struct mail_storage *storage;
struct mailbox *box;
+ struct quota_settings *quota_set; /* APPLE */
struct quota_root_iter *iter;
struct quota_root *root;
const char *orig_mailbox, *mailbox;
@@ -71,6 +72,7 @@
return TRUE;
}
+ quota_set = quota_settings_find(cmd->client->user); /* APPLE */
if (quota_set == NULL) {
mailbox_close(&box);
client_send_tagline(cmd, "OK No quota.");
@@ -82,7 +84,7 @@
str_append(str, "* QUOTAROOT ");
imap_quote_append_string(str, orig_mailbox, FALSE);
- iter = quota_root_iter_init(quota_set, box);
+ iter = quota_root_iter_init(box);
while ((root = quota_root_iter_next(iter)) != NULL) {
str_append_c(str, ' ');
imap_quote_append_string(str, quota_root_get_name(root), FALSE);
@@ -91,7 +93,7 @@
client_send_line(cmd->client, str_c(str));
/* send QUOTA reply for each quotaroot */
- iter = quota_root_iter_init(quota_set, box);
+ iter = quota_root_iter_init(box);
while ((root = quota_root_iter_next(iter)) != NULL)
quota_send(cmd, root);
quota_root_iter_deinit(&iter);
@@ -104,18 +106,20 @@
static bool cmd_getquota(struct client_command_context *cmd)
{
const char *root_name;
+ struct quota_settings *quota_set; /* APPLE */
struct quota_root *root;
/* <quota root> */
if (!client_read_string_args(cmd, 1, &root_name))
return FALSE;
+ quota_set = quota_settings_find(cmd->client->user); /* APPLE */
if (quota_set == NULL) {
client_send_tagline(cmd, "OK No quota.");
return TRUE;
}
- root = quota_root_lookup(quota_set, root_name);
+ root = quota_root_lookup(cmd->client->user, root_name);
if (root == NULL) {
client_send_tagline(cmd, "NO Quota root doesn't exist.");
return TRUE;
@@ -132,6 +136,7 @@
const struct imap_arg *args, *arg;
const char *root_name, *name, *error;
uint64_t value;
+ struct quota_settings *quota_set; /* APPLE */
/* <quota root> <resource limits> */
if (!client_read_args(cmd, 2, 0, &args))
@@ -143,12 +148,13 @@
return TRUE;
}
+ quota_set = quota_settings_find(cmd->client->user); /* APPLE */
if (quota_set == NULL) {
client_send_tagline(cmd, "OK No quota.");
return TRUE;
}
- root = quota_root_lookup(quota_set, root_name);
+ root = quota_root_lookup(cmd->client->user, root_name);
if (root == NULL) {
client_send_tagline(cmd, "NO Quota root doesn't exist.");
return TRUE;
diff -Nur dovecot-1.1.7+patch9/src/plugins/lazy-expunge/lazy-expunge-plugin.c dovecot-patch/src/plugins/lazy-expunge/lazy-expunge-plugin.c
--- dovecot-1.1.7+patch9/src/plugins/lazy-expunge/lazy-expunge-plugin.c 2008-11-23 16:03:43.000000000 -0600
+++ dovecot-patch/src/plugins/lazy-expunge/lazy-expunge-plugin.c 2009-01-06 10:08:19.000000000 -0600
@@ -19,6 +19,8 @@
MODULE_CONTEXT(obj, lazy_expunge_mail_storage_module)
#define LAZY_EXPUNGE_LIST_CONTEXT(obj) \
MODULE_CONTEXT(obj, lazy_expunge_mailbox_list_module)
+#define LAZY_EXPUNGE_USER_CONTEXT(obj) \
+ MODULE_CONTEXT(obj, lazy_expunge_mail_user_module)
enum lazy_namespace {
LAZY_NAMESPACE_EXPUNGE,
@@ -28,6 +30,12 @@
LAZY_NAMESPACE_COUNT
};
+struct lazy_expunge_mail_user {
+ union mail_user_module_context module_ctx;
+
+ struct mail_namespace *lazy_ns[LAZY_NAMESPACE_COUNT];
+};
+
struct lazy_expunge_mailbox_list {
union mailbox_list_module_context module_ctx;
@@ -57,6 +65,7 @@
(struct mail_storage *storage);
static void (*lazy_expunge_next_hook_mailbox_list_created)
(struct mailbox_list *list);
+static void (*lazy_expunge_next_hook_mail_user_created)(struct mail_user *user);
static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_storage_module,
&mail_storage_module_register);
@@ -64,8 +73,8 @@
&mail_module_register);
static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mailbox_list_module,
&mailbox_list_module_register);
-
-static struct mail_namespace *lazy_namespaces[LAZY_NAMESPACE_COUNT];
+static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_user_module,
+ &mail_user_module_register);
static struct mailbox *
mailbox_open_or_create(struct mail_storage *storage, const char *name)
@@ -95,12 +104,14 @@
static void lazy_expunge_mail_expunge(struct mail *_mail)
{
+ struct lazy_expunge_mail_user *luser =
+ LAZY_EXPUNGE_USER_CONTEXT(_mail->box->storage->ns->user);
struct lazy_expunge_transaction *lt =
LAZY_EXPUNGE_CONTEXT(_mail->transaction);
struct mail_storage *deststorage;
if (lt->expunge_box == NULL) {
- deststorage = lazy_namespaces[LAZY_NAMESPACE_EXPUNGE]->storage;
+ deststorage = luser->lazy_ns[LAZY_NAMESPACE_EXPUNGE]->storage;
lt->expunge_box = mailbox_open_or_create(deststorage,
_mail->box->name);
if (lt->expunge_box == NULL) {
@@ -414,6 +425,8 @@
static int
lazy_expunge_mailbox_list_delete(struct mailbox_list *list, const char *name)
{
+ struct lazy_expunge_mail_user *luser =
+ LAZY_EXPUNGE_USER_CONTEXT(list->ns->user);
struct lazy_expunge_mailbox_list *llist =
LAZY_EXPUNGE_LIST_CONTEXT(list);
struct lazy_expunge_mail_storage *lstorage;
@@ -455,7 +468,7 @@
destname = t_strconcat(name, "-", timestamp, NULL);
/* first move the actual mailbox */
- dest_list = lazy_namespaces[LAZY_NAMESPACE_DELETE]->storage->list;
+ dest_list = luser->lazy_ns[LAZY_NAMESPACE_DELETE]->storage->list;
if ((ret = mailbox_move(list, name, dest_list, &destname)) < 0)
return -1;
if (ret == 0) {
@@ -465,9 +478,9 @@
}
/* next move the expunged messages mailbox, if it exists */
- list = lazy_namespaces[LAZY_NAMESPACE_EXPUNGE]->storage->list;
+ list = luser->lazy_ns[LAZY_NAMESPACE_EXPUNGE]->storage->list;
dest_list =
- lazy_namespaces[LAZY_NAMESPACE_DELETE_EXPUNGE]->storage->list;
+ luser->lazy_ns[LAZY_NAMESPACE_DELETE_EXPUNGE]->storage->list;
(void)mailbox_move(list, name, dest_list, &destname);
return 0;
}
@@ -526,6 +539,8 @@
static void
lazy_expunge_hook_mail_namespaces_created(struct mail_namespace *namespaces)
{
+ struct lazy_expunge_mail_user *luser =
+ LAZY_EXPUNGE_USER_CONTEXT(namespaces->user);
struct lazy_expunge_mail_storage *lstorage;
const char *const *p;
int i;
@@ -537,18 +552,18 @@
if (name == NULL)
i_fatal("lazy_expunge: Missing namespace #%d", i + 1);
- lazy_namespaces[i] =
+ luser->lazy_ns[i] =
mail_namespace_find_prefix(namespaces, name);
- if (lazy_namespaces[i] == NULL)
+ if (luser->lazy_ns[i] == NULL)
i_fatal("lazy_expunge: Unknown namespace: '%s'", name);
- if (strcmp(lazy_namespaces[i]->storage->name, "maildir") != 0) {
+ if (strcmp(luser->lazy_ns[i]->storage->name, "maildir") != 0) {
i_fatal("lazy_expunge: Namespace must be in maildir "
"format: %s", name);
}
/* we don't want to override these namespaces' expunge/delete
operations. */
- lstorage = LAZY_EXPUNGE_CONTEXT(lazy_namespaces[i]->storage);
+ lstorage = LAZY_EXPUNGE_CONTEXT(luser->lazy_ns[i]->storage);
lstorage->internal_namespace = TRUE;
}
@@ -556,6 +571,19 @@
lazy_expunge_next_hook_mail_namespaces_created(namespaces);
}
+static void lazy_expunge_mail_user_created(struct mail_user *user)
+{
+ struct lazy_expunge_mail_user *luser;
+
+ luser = p_new(user->pool, struct lazy_expunge_mail_user, 1);
+ luser->module_ctx.super = user->v;
+
+ MODULE_CONTEXT_SET(user, lazy_expunge_mail_user_module, luser);
+
+ if (lazy_expunge_next_hook_mail_user_created != NULL)
+ lazy_expunge_next_hook_mail_user_created(user);
+}
+
void lazy_expunge_plugin_init(void)
{
if (getenv("LAZY_EXPUNGE") == NULL) {
@@ -576,6 +604,9 @@
lazy_expunge_next_hook_mailbox_list_created = hook_mailbox_list_created;
hook_mailbox_list_created = lazy_expunge_mailbox_list_created;
+
+ lazy_expunge_next_hook_mail_user_created = hook_mail_user_created;
+ hook_mail_user_created = lazy_expunge_mail_user_created;
}
void lazy_expunge_plugin_deinit(void)
@@ -587,4 +618,5 @@
lazy_expunge_hook_mail_namespaces_created;
hook_mail_storage_created = lazy_expunge_next_hook_mail_storage_created;
hook_mailbox_list_created = lazy_expunge_next_hook_mailbox_list_created;
+ hook_mail_user_created = lazy_expunge_next_hook_mail_user_created;
}
diff -Nur dovecot-1.1.7+patch9/src/plugins/mbox-snarf/mbox-snarf-plugin.c dovecot-patch/src/plugins/mbox-snarf/mbox-snarf-plugin.c
--- dovecot-1.1.7+patch9/src/plugins/mbox-snarf/mbox-snarf-plugin.c 2008-11-15 11:21:09.000000000 -0600
+++ dovecot-patch/src/plugins/mbox-snarf/mbox-snarf-plugin.c 2009-01-06 10:08:19.000000000 -0600
@@ -167,10 +167,11 @@
static void mbox_snarf_mail_storage_created(struct mail_storage *storage)
{
struct mbox_snarf_mail_storage *mstorage;
+ const char *path;
+ path = mail_user_home_expand(storage->ns->user, getenv("MBOX_SNARF"));
mstorage = p_new(storage->pool, struct mbox_snarf_mail_storage, 1);
- mstorage->snarf_inbox_path =
- p_strdup(storage->pool, home_expand(getenv("MBOX_SNARF")));
+ mstorage->snarf_inbox_path = p_strdup(storage->pool, path);
mstorage->module_ctx.super = storage->v;
storage->v.mailbox_open = mbox_snarf_mailbox_open;
diff -Nur dovecot-1.1.7+patch9/src/plugins/quota/quota-count.c dovecot-patch/src/plugins/quota/quota-count.c
--- dovecot-1.1.7+patch9/src/plugins/quota/quota-count.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/plugins/quota/quota-count.c 2009-01-06 10:08:19.000000000 -0600
@@ -19,7 +19,7 @@
uoff_t size;
int ret = 0;
- rule = quota_root_rule_find(root, name);
+ rule = quota_root_rule_find(root->set, name);
if (rule != NULL && rule->ignore) {
/* mailbox not included in quota */
return 0;
diff -Nur dovecot-1.1.7+patch9/src/plugins/quota/quota-dict.c dovecot-patch/src/plugins/quota/quota-dict.c
--- dovecot-1.1.7+patch9/src/plugins/quota/quota-dict.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/plugins/quota/quota-dict.c 2009-01-06 10:08:19.000000000 -0600
@@ -3,6 +3,7 @@
#include "lib.h"
#include "str.h"
#include "dict.h"
+#include "mail-user.h"
#include "quota-private.h"
#include <stdlib.h>
@@ -48,9 +49,9 @@
}
if (*username == '\0')
- username = getenv("USER");
+ username = _root->quota->user->username;
- if (getenv("DEBUG") != NULL) {
+ if (_root->quota->set->debug) {
i_info("dict quota: user=%s, uri=%s, enforcing=%d",
username, args, _root->no_enforcing);
}
diff -Nur dovecot-1.1.7+patch9/src/plugins/quota/quota-fs.c dovecot-patch/src/plugins/quota/quota-fs.c
--- dovecot-1.1.7+patch9/src/plugins/quota/quota-fs.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/plugins/quota/quota-fs.c 2009-01-06 10:08:19.000000000 -0600
@@ -251,7 +251,7 @@
dir = mail_storage_get_mailbox_path(storage, "", &is_file);
mount = fs_quota_mountpoint_get(dir);
if (mount != NULL) {
- if (getenv("DEBUG") != NULL) {
+ if (quota->set->debug) {
i_info("fs quota add storage dir = %s", dir);
i_info("fs quota block device = %s", mount->device_path);
i_info("fs quota mount point = %s", mount->mount_path);
@@ -310,7 +310,7 @@
host = t_strdup_until(mount->device_path, path);
path++;
- if (getenv("DEBUG") != NULL) {
+ if (root->root.quota->set->debug) {
i_info("quota-fs: host=%s, path=%s, uid=%s",
host, path, dec2str(root->uid));
}
@@ -366,7 +366,7 @@
*limit_r = rq->rq_fsoftlimit;
}
}
- if (getenv("DEBUG") != NULL) {
+ if (root->root.quota->set->debug) {
i_info("quota-fs: uid=%s, value=%llu, "
"limit=%llu, active=%d", dec2str(root->uid),
(unsigned long long)*value_r,
@@ -375,7 +375,7 @@
return 1;
}
case Q_NOQUOTA:
- if (getenv("DEBUG") != NULL) {
+ if (root->root.quota->set->debug) {
i_info("quota-fs: uid=%s, limit=unlimited",
dec2str(root->uid));
}
@@ -632,9 +632,9 @@
/* update limit */
if (bytes)
- _root->default_rule.bytes_limit = limit;
+ _root->bytes_limit = limit;
else
- _root->default_rule.count_limit = limit;
+ _root->count_limit = limit;
return 1;
}
diff -Nur dovecot-1.1.7+patch9/src/plugins/quota/quota-maildir.c dovecot-patch/src/plugins/quota/quota-maildir.c
--- dovecot-1.1.7+patch9/src/plugins/quota/quota-maildir.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/plugins/quota/quota-maildir.c 2009-01-06 10:08:19.000000000 -0600
@@ -150,7 +150,7 @@
if (ctx->info == NULL)
return NULL;
- rule = quota_root_rule_find(&ctx->root->root,
+ rule = quota_root_rule_find(ctx->root->root.set,
ctx->info->name);
if (rule != NULL && rule->ignore) {
/* mailbox not included in quota */
@@ -218,7 +218,7 @@
static int maildirsize_write(struct maildir_quota_root *root, const char *path)
{
- const struct quota_rule *rule = &root->root.default_rule;
+ struct quota_root *_root = &root->root;
struct dotlock *dotlock;
const char *p, *dir;
string_t *str;
@@ -253,15 +253,15 @@
str = t_str_new(128);
/* if we have no limits, write 0S instead of an empty line */
- if (rule->bytes_limit != 0 || rule->count_limit == 0) {
+ if (_root->bytes_limit != 0 || _root->count_limit == 0) {
str_printfa(str, "%lluS",
- (unsigned long long)rule->bytes_limit);
+ (unsigned long long)_root->bytes_limit);
}
- if (rule->count_limit != 0) {
+ if (_root->count_limit != 0) {
if (str_len(str) > 0)
str_append_c(str, ',');
str_printfa(str, "%lluC",
- (unsigned long long)rule->count_limit);
+ (unsigned long long)_root->count_limit);
}
str_printfa(str, "\n%llu %llu\n",
(unsigned long long)root->total_bytes,
@@ -315,7 +315,7 @@
static void maildirsize_rebuild_later(struct maildir_quota_root *root)
{
- if (!root->root.force_default_rule) {
+ if (!root->root.set->force_default_rule) {
/* FIXME: can't unlink(), because the limits would be lost. */
return;
}
@@ -406,7 +406,7 @@
static int maildirsize_parse(struct maildir_quota_root *root,
int fd, const char *const *lines)
{
- struct quota_rule *rule = &root->root.default_rule;
+ struct quota_root *_root = &root->root;
uint64_t message_bytes_limit, message_count_limit;
long long bytes_diff, total_bytes;
int count_diff, total_count;
@@ -425,18 +425,18 @@
if (message_count_limit >= (1ULL << 63))
message_count_limit = (1ULL << 63) - 1;
- if (rule->bytes_limit == (int64_t)message_bytes_limit &&
- rule->count_limit == (int64_t)message_count_limit) {
+ if (root->root.bytes_limit == (int64_t)message_bytes_limit &&
+ root->root.count_limit == (int64_t)message_count_limit) {
/* limits haven't changed */
- } else if (root->root.force_default_rule) {
+ } else if (root->root.set->force_default_rule) {
/* we know the limits and they've changed.
the file must be rewritten. */
return 0;
} else {
/* we're using limits from the file. */
- rule->bytes_limit = message_bytes_limit;
- rule->count_limit = message_count_limit;
- quota_root_recalculate_relative_rules(&root->root);
+ root->root.bytes_limit = message_bytes_limit;
+ root->root.count_limit = message_count_limit;
+ quota_root_recalculate_relative_rules(root->root.set);
}
if (*lines == NULL) {
@@ -459,8 +459,8 @@
return -1;
}
- if ((total_bytes > rule->bytes_limit && rule->bytes_limit != 0) ||
- (total_count > rule->count_limit && rule->count_limit != 0)) {
+ if ((total_bytes > _root->bytes_limit && _root->bytes_limit != 0) ||
+ (total_count > _root->count_limit && _root->count_limit != 0)) {
/* we're over quota. don't trust these values if the file
contains more than the initial summary line, or if the file
is older than 15 minutes. */
@@ -606,10 +606,10 @@
ret = maildirsize_read(root);
} T_END;
if (ret == 0) {
- if (root->root.default_rule.bytes_limit == 0 &&
- root->root.default_rule.count_limit == 0) {
+ if (root->root.set->default_rule.bytes_limit == 0 &&
+ root->root.set->default_rule.count_limit == 0) {
/* no quota */
- if (!root->root.force_default_rule)
+ if (!root->root.set->force_default_rule)
return 0;
/* explicitly specified 0 as quota. keep the quota
updated even if it's not enforced. */
@@ -667,7 +667,7 @@
}
static bool
-maildir_quota_parse_rule(struct quota_root *root ATTR_UNUSED,
+maildir_quota_parse_rule(struct quota_root_settings *root_set ATTR_UNUSED,
struct quota_rule *rule,
const char *str, const char **error_r)
{
diff -Nur dovecot-1.1.7+patch9/src/plugins/quota/quota-plugin.c dovecot-patch/src/plugins/quota/quota-plugin.c
--- dovecot-1.1.7+patch9/src/plugins/quota/quota-plugin.c 2008-11-15 11:21:11.000000000 -0600
+++ dovecot-patch/src/plugins/quota/quota-plugin.c 2009-01-06 10:08:19.000000000 -0600
@@ -5,20 +5,23 @@
#include "mailbox-list-private.h"
#include "quota.h"
#include "quota-plugin.h"
+#include "quota-private.h" /* APPLE */
+#include "hash.h" /* APPLE */
#include <stdlib.h>
/* defined by imap, pop3, lda */
extern void (*hook_mail_storage_created)(struct mail_storage *storage);
+void (*quota_next_hook_mail_user_created)(struct mail_user *user);
void (*quota_next_hook_mail_storage_created)(struct mail_storage *storage);
void (*quota_next_hook_mailbox_list_created)(struct mailbox_list *list);
const char *quota_plugin_version = PACKAGE_VERSION;
-struct quota *quota_set;
+struct hash_table *quota_settings; /* APPLE */
static void quota_root_add_rules(const char *root_name,
- struct quota_root *root)
+ struct quota_root_settings *root_set)
{
const char *rule_name, *rule, *error;
unsigned int i;
@@ -30,7 +33,7 @@
if (rule == NULL)
break;
- if (quota_root_add_rule(root, rule, &error) < 0) {
+ if (quota_root_add_rule(root_set, rule, &error) < 0) {
i_fatal("Quota root %s: Invalid rule %s: %s",
root_name, rule, error);
}
@@ -39,7 +42,7 @@
}
static void quota_root_add_warning_rules(const char *root_name,
- struct quota_root *root)
+ struct quota_root_settings *root_set)
{
const char *rule_name, *rule, *error;
unsigned int i;
@@ -51,7 +54,7 @@
if (rule == NULL)
break;
- if (quota_root_add_warning_rule(root, rule, &error) < 0) {
+ if (quota_root_add_warning_rule(root_set, rule, &error) < 0) {
i_fatal("Quota root %s: Invalid warning rule: %s",
root_name, rule);
}
@@ -61,8 +64,6 @@
void quota_plugin_init(void)
{
- struct quota_root *root;
- unsigned int i;
const char *env;
env = getenv("QUOTA");
@@ -72,13 +73,41 @@
return;
}
- quota_set = quota_init();
+ /* APPLE */
+ quota_settings = hash_table_create(default_pool, default_pool, 5, str_hash,
+ (hash_cmp_callback_t *) strcmp);
+ if (quota_settings_create() == NULL)
+ i_fatal("Couldn't create quota settings");
- root = quota_root_init(quota_set, env);
- if (root == NULL)
- i_fatal("Couldn't create quota root: %s", env);
- quota_root_add_rules("QUOTA", root);
- quota_root_add_warning_rules("QUOTA", root);
+ quota_next_hook_mail_user_created = hook_mail_user_created;
+ hook_mail_user_created = quota_mail_user_created;
+
+ quota_next_hook_mail_storage_created = hook_mail_storage_created;
+ hook_mail_storage_created = quota_mail_storage_created;
+
+ quota_next_hook_mailbox_list_created = hook_mailbox_list_created;
+ hook_mailbox_list_created = quota_mailbox_list_created;
+}
+
+/* APPLE */
+struct quota_settings *quota_settings_create()
+{
+ struct quota_settings *quota_set;
+ struct quota_root_settings *root_set;
+ unsigned int i;
+ const char *env;
+
+ quota_set = quota_settings_init();
+
+ env = getenv("QUOTA");
+ root_set = quota_root_settings_init(quota_set, env);
+ if (root_set == NULL) {
+ i_error("Couldn't create quota root: %s", env);
+ quota_settings_deinit("a_set);
+ return NULL;
+ }
+ quota_root_add_rules("QUOTA", root_set);
+ quota_root_add_warning_rules("QUOTA", root_set);
for (i = 2;; i++) {
const char *root_name;
@@ -89,27 +118,55 @@
if (env == NULL)
break;
- root = quota_root_init(quota_set, env);
- if (root == NULL)
- i_fatal("Couldn't create quota root: %s", env);
- quota_root_add_rules(root_name, root);
- quota_root_add_warning_rules(root_name, root);
+ root_set = quota_root_settings_init(quota_set, env);
+ if (root_set == NULL) {
+ i_error("Couldn't create quota root: %s", env);
+ quota_settings_deinit("a_set);
+ return NULL;
+ }
+ quota_root_add_rules(root_name, root_set);
+ quota_root_add_warning_rules(root_name, root_set);
}
- quota_next_hook_mail_storage_created = hook_mail_storage_created;
- hook_mail_storage_created = quota_mail_storage_created;
+ env = getenv("USER");
+ i_assert(env != NULL && *env != '\0');
+ hash_insert(quota_settings, p_strdup(quota_set->pool, env), quota_set);
- quota_next_hook_mailbox_list_created = hook_mailbox_list_created;
- hook_mailbox_list_created = quota_mailbox_list_created;
+ return quota_set;
+}
+
+/* APPLE */
+struct quota_settings *quota_settings_find(const struct mail_user *user)
+{
+ return hash_lookup(quota_settings, user->username);
+}
+
+/* APPLE */
+void quota_settings_ref(struct quota_settings *quota_set)
+{
+ ++quota_set->refcount;
+}
+
+/* APPLE */
+void quota_settings_unref(struct quota_settings **_quota_set)
+{
+ struct quota_settings *quota_set = *_quota_set;
+
+ *_quota_set = NULL;
+ if (--quota_set->refcount > 0)
+ return;
+
+ hash_remove(quota_settings, quota_set->username);
}
void quota_plugin_deinit(void)
{
- if (quota_set != NULL) {
+ if (quota_settings != NULL) { /* APPLE */
+ hook_mail_user_created = quota_next_hook_mail_user_created;
hook_mail_storage_created =
quota_next_hook_mail_storage_created;
hook_mailbox_list_created =
quota_next_hook_mailbox_list_created;
- quota_deinit("a_set);
+ hash_table_destroy("a_settings); /* APPLE */
}
}
diff -Nur dovecot-1.1.7+patch9/src/plugins/quota/quota-plugin.h dovecot-patch/src/plugins/quota/quota-plugin.h
--- dovecot-1.1.7+patch9/src/plugins/quota/quota-plugin.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/plugins/quota/quota-plugin.h 2009-01-06 10:08:19.000000000 -0600
@@ -3,14 +3,18 @@
struct mail_storage;
+extern void (*quota_next_hook_mail_user_created)(struct mail_user *user);
extern void (*quota_next_hook_mail_storage_created)
(struct mail_storage *storage);
extern void (*quota_next_hook_mailbox_list_created)(struct mailbox_list *list);
-/* "quota" symbol already exists in OSX, so we'll use this slightly uglier
- name. */
-extern struct quota *quota_set;
+/* APPLE */
+struct quota_settings *quota_settings_create();
+struct quota_settings *quota_settings_find(const struct mail_user *user);
+void quota_settings_ref(struct quota_settings *quota_set);
+void quota_settings_unref(struct quota_settings **_quota_set);
+void quota_mail_user_created(struct mail_user *user);
void quota_mail_storage_created(struct mail_storage *storage);
void quota_mailbox_list_created(struct mailbox_list *list);
diff -Nur dovecot-1.1.7+patch9/src/plugins/quota/quota-private.h dovecot-patch/src/plugins/quota/quota-private.h
--- dovecot-1.1.7+patch9/src/plugins/quota/quota-private.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/plugins/quota/quota-private.h 2009-01-06 10:08:19.000000000 -0600
@@ -9,11 +9,20 @@
extern unsigned int quota_module_id;
struct quota {
+ struct mail_user *user;
+ struct quota_settings *set;
+
ARRAY_DEFINE(roots, struct quota_root *);
ARRAY_DEFINE(storages, struct mail_storage *);
+};
+
+struct quota_settings {
+ pool_t pool;
+ const char *username; /* APPLE */
+ int refcount; /* APPLE */
- int (*test_alloc)(struct quota_transaction_context *ctx,
- uoff_t size, bool *too_large_r);
+ ARRAY_DEFINE(root_sets, struct quota_root_settings *);
+ /* APPLE moved test_alloc to global quota_settings_test_alloc */
const char *quota_exceeded_msg;
unsigned int debug:1;
@@ -41,7 +50,8 @@
int (*init)(struct quota_root *root, const char *args);
void (*deinit)(struct quota_root *root);
- bool (*parse_rule)(struct quota_root *root, struct quota_rule *rule,
+ bool (*parse_rule)(struct quota_root_settings *root_set,
+ struct quota_rule *rule,
const char *str, const char **error_r);
/* called once for each backend */
@@ -49,8 +59,8 @@
struct mail_storage *storage);
const char *const *(*get_resources)(struct quota_root *root);
- int (*get_resource)(struct quota_root *root, const char *name,
- uint64_t *value_r);
+ int (*get_resource)(struct quota_root *root,
+ const char *name, uint64_t *value_r);
int (*update)(struct quota_root *root,
struct quota_transaction_context *ctx);
@@ -62,27 +72,39 @@
struct quota_backend_vfuncs v;
};
-struct quota_root {
- pool_t pool;
-
+struct quota_root_settings {
/* Unique quota root name. */
const char *name;
- /* pointer to the quota that owns this root */
- struct quota *quota;
+ struct quota_settings *set;
+ const char *args;
- struct quota_backend backend;
+ const struct quota_backend *backend;
struct quota_rule default_rule;
ARRAY_DEFINE(rules, struct quota_rule);
ARRAY_DEFINE(warning_rules, struct quota_warning_rule);
+ /* Limits in default_rule override backend's quota limits */
+ unsigned int force_default_rule:1;
+};
+
+struct quota_root {
+ pool_t pool;
+
+ struct quota_root_settings *set;
+ struct quota *quota;
+ struct quota_backend backend;
+
+ /* initially the same as set->default_rule.*_limit, but some backends
+ may change these by reading the limits elsewhere (e.g. Maildir++,
+ FS quota) */
+ int64_t bytes_limit, count_limit;
+
/* Module-specific contexts. See quota_module_id. */
ARRAY_DEFINE(quota_module_contexts, void);
/* don't enforce quota when saving */
unsigned int no_enforcing:1;
- /* Limits in default_rule override backend's quota limits */
- unsigned int force_default_rule:1;
};
struct quota_transaction_context {
@@ -103,13 +125,18 @@
/* Register storage to all user's quota roots. */
void quota_add_user_storage(struct quota *quota, struct mail_storage *storage);
-void quota_remove_user_storage(struct quota *quota,
- struct mail_storage *storage);
+void quota_remove_user_storage(struct mail_storage *storage);
+
+struct quota *quota_get_mail_user_quota(struct mail_user *user);
struct quota_rule *
-quota_root_rule_find(struct quota_root *root, const char *name);
+quota_root_rule_find(struct quota_root_settings *root_set, const char *name);
-void quota_root_recalculate_relative_rules(struct quota_root *root);
+void quota_root_recalculate_relative_rules(struct quota_root_settings *root_set);
int quota_count(struct quota_root *root, uint64_t *bytes_r, uint64_t *count_r);
+/* APPLE was test_alloc in quota_settings */
+extern int (*quota_settings_test_alloc)(struct quota_transaction_context *ctx,
+ uoff_t size, bool *too_large_r);
+
#endif
diff -Nur dovecot-1.1.7+patch9/src/plugins/quota/quota-storage.c dovecot-patch/src/plugins/quota/quota-storage.c
--- dovecot-1.1.7+patch9/src/plugins/quota/quota-storage.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/plugins/quota/quota-storage.c 2009-01-06 10:08:19.000000000 -0600
@@ -17,6 +17,14 @@
MODULE_CONTEXT(obj, quota_mail_module)
#define QUOTA_LIST_CONTEXT(obj) \
MODULE_CONTEXT(obj, quota_mailbox_list_module)
+#define QUOTA_USER_CONTEXT(obj) \
+ MODULE_CONTEXT(obj, quota_user_module)
+
+struct quota_user {
+ union mail_user_module_context module_ctx;
+
+ struct quota *quota;
+};
struct quota_mailbox_list {
union mailbox_list_module_context module_ctx;
@@ -41,6 +49,8 @@
static MODULE_CONTEXT_DEFINE_INIT(quota_mail_module, &mail_module_register);
static MODULE_CONTEXT_DEFINE_INIT(quota_mailbox_list_module,
&mailbox_list_module_register);
+static MODULE_CONTEXT_DEFINE_INIT(quota_user_module,
+ &mail_user_module_register);
static void quota_mail_expunge(struct mail *_mail)
{
@@ -74,7 +84,7 @@
struct quota_transaction_context *qt;
t = qbox->module_ctx.super.transaction_begin(box, flags);
- qt = quota_transaction_begin(quota_set, box);
+ qt = quota_transaction_begin(box);
MODULE_CONTEXT_SET(t, quota_storage_module, qt);
return t;
@@ -150,7 +160,7 @@
return 0;
else if (ret == 0) {
mail_storage_set_error(t->box->storage, MAIL_ERROR_NOSPACE,
- qt->quota->quota_exceeded_msg);
+ qt->quota->set->quota_exceeded_msg);
return -1;
} else {
mail_storage_set_critical(t->box->storage,
@@ -215,7 +225,7 @@
if (ret == 0) {
mail_storage_set_error(t->box->storage,
MAIL_ERROR_NOSPACE,
- qt->quota->quota_exceeded_msg);
+ qt->quota->set->quota_exceeded_msg);
return -1;
} else if (ret < 0) {
mail_storage_set_critical(t->box->storage,
@@ -310,7 +320,7 @@
}
if (qbox->expunge_qt == NULL)
- qbox->expunge_qt = quota_transaction_begin(quota_set, box);
+ qbox->expunge_qt = quota_transaction_begin(box);
if (i != count) {
/* we already know the size */
@@ -469,16 +479,56 @@
{
union mail_storage_module_context *qstorage = QUOTA_CONTEXT(storage);
- quota_remove_user_storage(quota_set, storage);
+ quota_remove_user_storage(storage);
if (qstorage->super.destroy != NULL)
qstorage->super.destroy(storage);
}
+struct quota *quota_get_mail_user_quota(struct mail_user *user)
+{
+ struct quota_user *quser = QUOTA_USER_CONTEXT(user);
+
+ return quser->quota;
+}
+
+static void quota_user_deinit(struct mail_user *user)
+{
+ struct quota_user *quser = QUOTA_USER_CONTEXT(user);
+
+ quota_deinit(&quser->quota);
+ quser->module_ctx.super.deinit(user);
+}
+
+void quota_mail_user_created(struct mail_user *user)
+{
+ struct quota_settings *quota_set; /* APPLE */
+ struct quota_user *quser;
+
+ /* APPLE */
+ quota_set = quota_settings_find(user);
+ if (quota_set == NULL) {
+ quota_set = quota_settings_create();
+ if (quota_set == NULL)
+ return;
+ }
+
+ quser = p_new(user->pool, struct quota_user, 1);
+ quser->module_ctx.super = user->v;
+ user->v.deinit = quota_user_deinit;
+ quser->quota = quota_init(quota_set, user);
+
+ MODULE_CONTEXT_SET(user, quota_user_module, quser);
+
+ if (quota_next_hook_mail_user_created != NULL)
+ quota_next_hook_mail_user_created(user);
+}
+
void quota_mail_storage_created(struct mail_storage *storage)
{
struct quota_mailbox_list *qlist = QUOTA_LIST_CONTEXT(storage->list);
union mail_storage_module_context *qstorage;
+ struct quota *quota;
qlist->storage = storage;
@@ -492,7 +542,8 @@
if (storage->ns->type == NAMESPACE_PRIVATE &&
(storage->ns->flags & NAMESPACE_FLAG_INTERNAL) == 0) {
/* register to user's quota roots */
- quota_add_user_storage(quota_set, storage);
+ quota = quota_get_mail_user_quota(storage->ns->user);
+ quota_add_user_storage(quota, storage);
}
if (quota_next_hook_mail_storage_created != NULL)
diff -Nur dovecot-1.1.7+patch9/src/plugins/quota/quota.c dovecot-patch/src/plugins/quota/quota.c
--- dovecot-1.1.7+patch9/src/plugins/quota/quota.c 2008-10-29 11:40:46.000000000 -0500
+++ dovecot-patch/src/plugins/quota/quota.c 2009-01-06 10:08:19.000000000 -0600
@@ -42,38 +42,35 @@
static int quota_default_test_alloc(struct quota_transaction_context *ctx,
uoff_t size, bool *too_large_r);
+/* APPLE */
+int (*quota_settings_test_alloc)(struct quota_transaction_context *ctx,
+ uoff_t size, bool *too_large_r) =
+ quota_default_test_alloc;
-struct quota *quota_init(void)
+struct quota_settings *quota_settings_init(void)
{
- struct quota *quota;
-
- quota = i_new(struct quota, 1);
- quota->test_alloc = quota_default_test_alloc;
- quota->debug = getenv("DEBUG") != NULL;
- quota->quota_exceeded_msg = getenv("QUOTA_EXCEEDED_MESSAGE");
- if (quota->quota_exceeded_msg == NULL)
- quota->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG;
- i_array_init("a->roots, 4);
- i_array_init("a->storages, 8);
+ struct quota_settings *quota_set;
+ pool_t pool;
- return quota;
+ pool = pool_alloconly_create("quota settings", 256);
+ quota_set = p_new(pool, struct quota_settings, 1);
+ quota_set->pool = pool;
+ quota_set->username = p_strdup(pool, getenv("USER")); /* APPLE */
+ quota_set->debug = getenv("DEBUG") != NULL;
+ quota_set->quota_exceeded_msg = getenv("QUOTA_EXCEEDED_MESSAGE");
+ if (quota_set->quota_exceeded_msg == NULL)
+ quota_set->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG;
+ p_array_init("a_set->root_sets, pool, 4);
+ return quota_set;
}
-void quota_deinit(struct quota **_quota)
+void quota_settings_deinit(struct quota_settings **_quota_set)
{
- struct quota *quota = *_quota;
- struct quota_root **root_p, *root;
+ struct quota_settings *quota_set = *_quota_set;
- *_quota = NULL;
- while (array_count("a->roots) > 0) {
- root_p = array_idx_modifiable("a->roots, 0);
- root = *root_p;
- quota_root_deinit(&root);
- }
+ *_quota_set = NULL;
- array_free("a->roots);
- array_free("a->storages);
- i_free(quota);
+ pool_unref("a_set->pool);
}
static const struct quota_backend *quota_backend_find(const char *name)
@@ -88,11 +85,12 @@
return NULL;
}
-struct quota_root *quota_root_init(struct quota *quota, const char *root_def)
+struct quota_root_settings *
+quota_root_settings_init(struct quota_settings *quota_set, const char *root_def)
{
- struct quota_root *root;
+ struct quota_root_settings *root_set;
const struct quota_backend *backend;
- const char *p, *args, *backend_name, *const *tmp;
+ const char *p, *args, *backend_name;
/* <backend>[:<quota root name>[:<backend args>]] */
p = strchr(root_def, ':');
@@ -108,44 +106,59 @@
if (backend == NULL)
i_fatal("Unknown quota backend: %s", backend_name);
- root = backend->v.alloc();
- root->quota = quota;
- root->backend = *backend;
- root->pool = pool_alloconly_create("quota root", 512);
+ root_set = p_new(quota_set->pool, struct quota_root_settings, 1);
+ root_set->set = quota_set;
+ root_set->backend = backend;
if (args != NULL) {
/* save root's name */
p = strchr(args, ':');
if (p == NULL) {
- root->name = p_strdup(root->pool, args);
+ root_set->name = p_strdup(quota_set->pool, args);
args = NULL;
} else {
- root->name = p_strdup_until(root->pool, args, p);
+ root_set->name =
+ p_strdup_until(quota_set->pool, args, p);
args = p + 1;
}
} else {
- root->name = "";
+ root_set->name = "";
}
+ root_set->args = p_strdup(quota_set->pool, args);
- if (quota->debug) {
+ if (quota_set->debug) {
i_info("Quota root: name=%s backend=%s args=%s",
- root->name, backend_name, args == NULL ? "" : args);
+ root_set->name, backend_name, args == NULL ? "" : args);
}
- i_array_init(&root->rules, 4);
- i_array_init(&root->warning_rules, 4);
- array_create(&root->quota_module_contexts, default_pool,
- sizeof(void *), 5);
+ p_array_init(&root_set->rules, quota_set->pool, 4);
+ p_array_init(&root_set->warning_rules, quota_set->pool, 4);
+ array_append("a_set->root_sets, &root_set, 1);
+ return root_set;
+}
- array_append("a->roots, &root, 1);
+static struct quota_root *
+quota_root_init(struct quota_root_settings *root_set, struct quota *quota)
+{
+ struct quota_root *root;
+ const char *const *tmp;
- if (backend->v.init != NULL) {
- if (backend->v.init(root, args) < 0) {
- quota_root_deinit(&root);
- return NULL;
- }
- } else if (args != NULL) {
- tmp = t_strsplit_spaces(args, " ");
+ root = root_set->backend->v.alloc();
+ root->pool = pool_alloconly_create("quota root", 512);
+ root->set = root_set;
+ root->quota = quota;
+ root->backend = *root_set->backend;
+ root->bytes_limit = root_set->default_rule.bytes_limit;
+ root->count_limit = root_set->default_rule.count_limit;
+
+ array_create(&root->quota_module_contexts, root->pool,
+ sizeof(void *), 10);
+
+ if (root->backend.v.init != NULL) {
+ if (root->backend.v.init(root, root_set->args) < 0)
+ i_fatal("Quota root %s init() failed", root_set->name);
+ } else if (root_set->args != NULL) {
+ tmp = t_strsplit_spaces(root_set->args, " ");
for (; *tmp != NULL; tmp++) {
if (strcmp(*tmp, "noenforcing") == 0)
root->no_enforcing = TRUE;
@@ -155,49 +168,70 @@
if (*tmp != NULL) {
i_fatal("Quota root %s backend %s: "
"Unknown parameter: %s",
- root->name, backend_name, *tmp);
+ root_set->name, root->backend.name, *tmp);
}
}
return root;
}
-void quota_root_deinit(struct quota_root **_root)
+static void quota_root_deinit(struct quota_root *root)
{
- struct quota_root *root = *_root;
pool_t pool = root->pool;
- struct quota_root *const *roots;
- struct quota_warning_rule *warnings;
+
+ root->backend.v.deinit(root);
+ pool_unref(&pool);
+}
+
+struct quota *quota_init(struct quota_settings *quota_set,
+ struct mail_user *user)
+{
+ struct quota *quota;
+ struct quota_root *root;
+ struct quota_root_settings *const *root_sets;
unsigned int i, count;
- *_root = NULL;
+ quota_settings_ref(quota_set); /* APPLE */
- roots = array_get(&root->quota->roots, &count);
+ quota = i_new(struct quota, 1);
+ quota->user = user;
+ quota->set = quota_set;
+ i_array_init("a->roots, 8);
+
+ root_sets = array_get("a_set->root_sets, &count);
+ i_array_init("a->storages, count);
for (i = 0; i < count; i++) {
- if (roots[i] == root) {
- array_delete(&root->quota->roots, i, 1);
- break;
- }
+ root = quota_root_init(root_sets[i], quota);
+ array_append("a->roots, &root, 1);
}
+ return quota;
+}
- warnings = array_get_modifiable(&root->warning_rules, &count);
+void quota_deinit(struct quota **_quota)
+{
+ struct quota *quota = *_quota;
+ struct quota_root *const *roots;
+ unsigned int i, count;
+
+ *_quota = NULL;
+
+ roots = array_get("a->roots, &count);
for (i = 0; i < count; i++)
- i_free(warnings[i].command);
- array_free(&root->warning_rules);
+ quota_root_deinit(roots[i]);
+ array_free("a->roots);
+ array_free("a->storages);
- array_free(&root->rules);
- array_free(&root->quota_module_contexts);
+ quota_settings_unref("a->set); /* APPLE */
- root->backend.v.deinit(root);
- pool_unref(&pool);
+ i_free(quota);
}
struct quota_rule *
-quota_root_rule_find(struct quota_root *root, const char *name)
+quota_root_rule_find(struct quota_root_settings *root_set, const char *name)
{
struct quota_rule *rules;
unsigned int i, count;
- rules = array_get_modifiable(&root->rules, &count);
+ rules = array_get_modifiable(&root_set->rules, &count);
for (i = 0; i < count; i++) {
if (strcmp(rules[i].mailbox_name, name) == 0)
return &rules[i];
@@ -206,18 +240,19 @@
}
static int
-quota_rule_parse_percentage(struct quota_root *root, struct quota_rule *rule,
+quota_rule_parse_percentage(struct quota_root_settings *root_set,
+ struct quota_rule *rule,
int64_t *limit, const char **error_r)
{
int64_t percentage = *limit;
if (percentage <= 0 || percentage >= -1U) {
- *error_r = p_strdup_printf(root->pool,
+ *error_r = p_strdup_printf(root_set->set->pool,
"Invalid rule percentage: %lld", (long long)percentage);
return -1;
}
- if (rule == &root->default_rule) {
+ if (rule == &root_set->default_rule) {
*error_r = "Default rule can't be a percentage";
return -1;
}
@@ -245,29 +280,29 @@
}
}
-void quota_root_recalculate_relative_rules(struct quota_root *root)
+void quota_root_recalculate_relative_rules(struct quota_root_settings *root_set)
{
struct quota_rule *rules;
struct quota_warning_rule *warning_rules;
unsigned int i, count;
- rules = array_get_modifiable(&root->rules, &count);
+ rules = array_get_modifiable(&root_set->rules, &count);
for (i = 0; i < count; i++) {
quota_rule_recalculate_relative_rules(&rules[i],
- &root->default_rule);
+ &root_set->default_rule);
}
- warning_rules = array_get_modifiable(&root->warning_rules, &count);
+ warning_rules = array_get_modifiable(&root_set->warning_rules, &count);
for (i = 0; i < count; i++) {
quota_rule_recalculate_relative_rules(&warning_rules[i].rule,
- &root->default_rule);
+ &root_set->default_rule);
}
}
static int
-quota_rule_parse_limits(struct quota_root *root, struct quota_rule *rule,
- const char *limits, bool allow_negative,
- const char **error_r)
+quota_rule_parse_limits(struct quota_root_settings *root_set,
+ struct quota_rule *rule, const char *limits,
+ bool allow_negative, const char **error_r)
{
const char **args;
char *p;
@@ -289,7 +324,7 @@
limit = &rule->count_limit;
*limit = strtoll(*args + 9, &p, 10);
} else {
- *error_r = p_strdup_printf(root->pool,
+ *error_r = p_strdup_printf(root_set->set->pool,
"Unknown rule limit name: %s", *args);
return -1;
}
@@ -315,12 +350,12 @@
break;
case '%':
multiply = 0;
- if (quota_rule_parse_percentage(root, rule, limit,
+ if (quota_rule_parse_percentage(root_set, rule, limit,
error_r) < 0)
return -1;
break;
default:
- *error_r = p_strdup_printf(root->pool,
+ *error_r = p_strdup_printf(root_set->set->pool,
"Invalid rule limit value: %s", *args);
return -1;
}
@@ -339,8 +374,8 @@
return 0;
}
-int quota_root_add_rule(struct quota_root *root, const char *rule_def,
- const char **error_r)
+int quota_root_add_rule(struct quota_root_settings *root_set,
+ const char *rule_def, const char **error_r)
{
struct quota_rule *rule;
const char *p, *mailbox_name;
@@ -355,43 +390,45 @@
/* <mailbox name>:<quota limits> */
mailbox_name = t_strdup_until(rule_def, p++);
- rule = quota_root_rule_find(root, mailbox_name);
+ rule = quota_root_rule_find(root_set, mailbox_name);
if (rule == NULL) {
if (strcmp(mailbox_name, RULE_NAME_DEFAULT_NONFORCE) == 0)
- rule = &root->default_rule;
+ rule = &root_set->default_rule;
else if (strcmp(mailbox_name, RULE_NAME_DEFAULT_FORCE) == 0) {
- rule = &root->default_rule;
- root->force_default_rule = TRUE;
+ rule = &root_set->default_rule;
+ root_set->force_default_rule = TRUE;
} else {
- rule = array_append_space(&root->rules);
- rule->mailbox_name = p_strdup(root->pool, mailbox_name);
+ rule = array_append_space(&root_set->rules);
+ rule->mailbox_name =
+ p_strdup(root_set->set->pool, mailbox_name);
}
}
if (strcmp(p, "ignore") == 0) {
rule->ignore = TRUE;
- if (root->quota->debug) {
+ if (root_set->set->debug) {
i_info("Quota rule: root=%s mailbox=%s ignored",
- root->name, mailbox_name);
+ root_set->name, mailbox_name);
}
return 0;
}
if (strncmp(p, "backend=", 8) == 0) {
- if (!root->backend.v.parse_rule(root, rule, p + 8, error_r))
+ if (!root_set->backend->v.parse_rule(root_set, rule,
+ p + 8, error_r))
ret = -1;
} else {
- bool allow_negative = rule != &root->default_rule;
+ bool allow_negative = rule != &root_set->default_rule;
- if (quota_rule_parse_limits(root, rule, p,
+ if (quota_rule_parse_limits(root_set, rule, p,
allow_negative, error_r) < 0)
ret = -1;
}
- quota_root_recalculate_relative_rules(root);
- if (root->quota->debug) {
+ quota_root_recalculate_relative_rules(root_set);
+ if (root_set->set->debug) {
i_info("Quota rule: root=%s mailbox=%s "
- "bytes=%lld (%u%%) messages=%lld (%u%%)", root->name,
+ "bytes=%lld (%u%%) messages=%lld (%u%%)", root_set->name,
mailbox_name,
(long long)rule->bytes_limit, rule->bytes_percent,
(long long)rule->count_limit, rule->count_percent);
@@ -408,14 +445,14 @@
int64_t bytes_limit, count_limit;
bool found;
- bytes_limit = root->default_rule.bytes_limit;
- count_limit = root->default_rule.count_limit;
+ bytes_limit = root->bytes_limit;
+ count_limit = root->count_limit;
/* if default rule limits are 0, this rule applies only to specific
mailboxes */
found = bytes_limit != 0 || count_limit != 0;
- rule = quota_root_rule_find(root, mailbox_name);
+ rule = quota_root_rule_find(root->set, mailbox_name);
if (rule != NULL) {
if (!rule->ignore) {
bytes_limit += rule->bytes_limit;
@@ -490,12 +527,18 @@
}
}
-void quota_remove_user_storage(struct quota *quota,
- struct mail_storage *storage)
+void quota_remove_user_storage(struct mail_storage *storage)
{
+ struct quota *quota;
struct mail_storage *const *storages;
unsigned int i, count;
-
+
+ quota = quota_get_mail_user_quota(storage->ns->user);
+ if (quota == NULL) {
+ /* no quota for this storage */
+ return;
+ }
+
storages = array_get("a->storages, &count);
for (i = 0; i < count; i++) {
if (storages[i] == storage) {
@@ -505,8 +548,8 @@
}
}
-int quota_root_add_warning_rule(struct quota_root *root, const char *rule_def,
- const char **error_r)
+int quota_root_add_warning_rule(struct quota_root_settings *root_set,
+ const char *rule_def, const char **error_r)
{
struct quota_warning_rule *warning;
struct quota_rule rule;
@@ -520,17 +563,18 @@
}
memset(&rule, 0, sizeof(rule));
- ret = quota_rule_parse_limits(root, &rule, t_strdup_until(rule_def, p),
+ ret = quota_rule_parse_limits(root_set, &rule,
+ t_strdup_until(rule_def, p),
TRUE, error_r);
if (ret < 0)
return -1;
- warning = array_append_space(&root->warning_rules);
+ warning = array_append_space(&root_set->warning_rules);
warning->command = i_strdup(p+1);
warning->rule = rule;
- quota_root_recalculate_relative_rules(root);
- if (root->quota->debug) {
+ quota_root_recalculate_relative_rules(root_set);
+ if (root_set->set->debug) {
i_info("Quota warning: bytes=%llu (%u%%) "
"messages=%llu (%u%%) command=%s",
(unsigned long long)warning->rule.bytes_limit,
@@ -542,12 +586,13 @@
}
struct quota_root_iter *
-quota_root_iter_init(struct quota *quota, struct mailbox *box)
+quota_root_iter_init(struct mailbox *box)
{
+ struct mail_user *user = box->storage->ns->user;
struct quota_root_iter *iter;
iter = i_new(struct quota_root_iter, 1);
- iter->quota = quota;
+ iter->quota = quota_get_mail_user_quota(user);
iter->box = box;
return iter;
}
@@ -590,14 +635,16 @@
i_free(iter);
}
-struct quota_root *quota_root_lookup(struct quota *quota, const char *name)
+struct quota_root *quota_root_lookup(struct mail_user *user, const char *name)
{
+ struct quota *quota;
struct quota_root *const *roots;
unsigned int i, count;
+ quota = quota_get_mail_user_quota(user);
roots = array_get("a->roots, &count);
for (i = 0; i < count; i++) {
- if (strcmp(roots[i]->name, name) == 0)
+ if (strcmp(roots[i]->set->name, name) == 0)
return roots[i];
}
return NULL;
@@ -605,7 +652,7 @@
const char *quota_root_get_name(struct quota_root *root)
{
- return root->name;
+ return root->set->name;
}
const char *const *quota_root_get_resources(struct quota_root *root)
@@ -658,13 +705,13 @@
return -1;
}
-struct quota_transaction_context *quota_transaction_begin(struct quota *quota,
- struct mailbox *box)
+struct quota_transaction_context *quota_transaction_begin(struct mailbox *box)
{
+ struct mail_user *user = box->storage->ns->user;
struct quota_transaction_context *ctx;
ctx = i_new(struct quota_transaction_context, 1);
- ctx->quota = quota;
+ ctx->quota = quota_get_mail_user_quota(user);
ctx->box = box;
ctx->bytes_left = (uint64_t)-1;
ctx->count_left = (uint64_t)-1;
@@ -718,14 +765,10 @@
return 0;
}
-static void quota_warning_execute(struct quota_root *root, const char *cmd)
+static void quota_warning_execute(const char *cmd)
{
- int ret;
-
- if (root->quota->debug)
- i_info("quota: Executing warning: %s", cmd);
+ int ret = system(cmd);
- ret = system(cmd);
if (ret < 0) {
i_error("system(%s) failed: %m", cmd);
} else if (WIFSIGNALED(ret)) {
@@ -744,7 +787,7 @@
uint64_t bytes_current, bytes_before, bytes_limit;
uint64_t count_current, count_before, count_limit;
- warnings = array_get_modifiable(&root->warning_rules, &count);
+ warnings = array_get_modifiable(&root->set->warning_rules, &count);
if (count == 0)
return;
@@ -762,7 +805,7 @@
bytes_current >= (uint64_t)warnings[i].rule.bytes_limit) ||
(count_before < (uint64_t)warnings[i].rule.count_limit &&
count_current >= (uint64_t)warnings[i].rule.count_limit)) {
- quota_warning_execute(root, warnings[i].command);
+ quota_warning_execute(warnings[i].command);
break;
}
}
@@ -786,7 +829,8 @@
mailbox_name = mailbox_get_name(ctx->box);
roots = array_get(&ctx->quota->roots, &count);
for (i = 0; i < count; i++) {
- rule = quota_root_rule_find(roots[i], mailbox_name);
+ rule = quota_root_rule_find(roots[i]->set,
+ mailbox_name);
if (rule != NULL && rule->ignore) {
/* mailbox not included in quota */
continue;
@@ -841,7 +885,7 @@
if (quota_transaction_set_limits(ctx) < 0)
return -1;
}
- return ctx->quota->test_alloc(ctx, size, too_large_r);
+ return quota_settings_test_alloc(ctx, size, too_large_r); /* APPLE */
}
static int quota_default_test_alloc(struct quota_transaction_context *ctx,
diff -Nur dovecot-1.1.7+patch9/src/plugins/quota/quota.h dovecot-patch/src/plugins/quota/quota.h
--- dovecot-1.1.7+patch9/src/plugins/quota/quota.h 2008-11-18 10:12:38.000000000 -0600
+++ dovecot-patch/src/plugins/quota/quota.h 2009-01-06 10:08:19.000000000 -0600
@@ -3,6 +3,7 @@
struct mail;
struct mailbox;
+struct mail_user;
/* Message storage size kilobytes. */
#define QUOTA_NAME_STORAGE_KILOBYTES "STORAGE"
@@ -16,29 +17,35 @@
struct quota_root_iter;
struct quota_transaction_context;
-struct quota *quota_init(void);
-void quota_deinit(struct quota **quota);
+struct quota_settings *quota_settings_init(void);
+void quota_settings_deinit(struct quota_settings **quota_set);
-/* Create a new quota root. */
-struct quota_root *quota_root_init(struct quota *quota, const char *root_def);
-void quota_root_deinit(struct quota_root **root);
+/* Set up a new quota root. */
+struct quota_root_settings *
+quota_root_settings_init(struct quota_settings *quota_set,
+ const char *root_def);
+void quota_root_settings_deinit(struct quota_root_settings **root_set);
/* Add a new rule too the quota root. Returns 0 if ok, -1 if rule is invalid. */
-int quota_root_add_rule(struct quota_root *root, const char *rule_def,
- const char **error_r);
+int quota_root_add_rule(struct quota_root_settings *root_set,
+ const char *rule_def, const char **error_r);
/* Add a new warning rule for the quota root. Returns 0 if ok, -1 if rule is
invalid. */
-int quota_root_add_warning_rule(struct quota_root *root, const char *rule_def,
- const char **error_r);
+int quota_root_add_warning_rule(struct quota_root_settings *root_set,
+ const char *rule_def, const char **error_r);
+
+/* Initialize quota for the given user. */
+struct quota *quota_init(struct quota_settings *quota_set,
+ struct mail_user *user);
+void quota_deinit(struct quota **quota);
/* List all quota roots. Returned quota roots are freed by quota_deinit(). */
-struct quota_root_iter *
-quota_root_iter_init(struct quota *quota, struct mailbox *box);
+struct quota_root_iter *quota_root_iter_init(struct mailbox *box);
struct quota_root *quota_root_iter_next(struct quota_root_iter *iter);
void quota_root_iter_deinit(struct quota_root_iter **iter);
/* Return quota root or NULL. */
-struct quota_root *quota_root_lookup(struct quota *quota, const char *name);
+struct quota_root *quota_root_lookup(struct mail_user *user, const char *name);
/* Returns name of the quota root. */
const char *quota_root_get_name(struct quota_root *root);
@@ -53,8 +60,7 @@
uint64_t value, const char **error_r);
/* Start a new quota transaction. */
-struct quota_transaction_context *quota_transaction_begin(struct quota *quota,
- struct mailbox *box);
+struct quota_transaction_context *quota_transaction_begin(struct mailbox *box);
/* Commit quota transaction. Returns 0 if ok, -1 if failed. */
int quota_transaction_commit(struct quota_transaction_context **ctx);
/* Rollback quota transaction changes. */
diff -Nur dovecot-1.1.7+patch9/src/plugins/trash/trash-plugin.c dovecot-patch/src/plugins/trash/trash-plugin.c
--- dovecot-1.1.7+patch9/src/plugins/trash/trash-plugin.c 2008-11-23 16:04:30.000000000 -0600
+++ dovecot-patch/src/plugins/trash/trash-plugin.c 2009-01-06 10:08:19.000000000 -0600
@@ -3,7 +3,6 @@
#include "lib.h"
#include "array.h"
#include "istream.h"
-#include "home-expand.h"
#include "mail-namespace.h"
#include "mail-search.h"
#include "quota-private.h"
@@ -17,6 +16,9 @@
#define INIT_TRASH_MAILBOX_COUNT 4
#define MAX_RETRY_COUNT 3
+#define TRASH_USER_CONTEXT(obj) \
+ MODULE_CONTEXT(obj, trash_user_module)
+
struct trash_mailbox {
const char *name;
int priority; /* lower number = higher priority */
@@ -33,17 +35,22 @@
unsigned int mail_set:1;
};
+struct trash_user {
+ union mail_user_module_context module_ctx;
+
+ /* ordered by priority, highest first */
+ ARRAY_DEFINE(trash_boxes, struct trash_mailbox);
+};
+
const char *trash_plugin_version = PACKAGE_VERSION;
+static MODULE_CONTEXT_DEFINE_INIT(trash_user_module,
+ &mail_user_module_register);
static void (*trash_next_hook_mail_namespaces_created)
(struct mail_namespace *namespaces);
static int (*trash_next_quota_test_alloc)(struct quota_transaction_context *,
uoff_t, bool *);
-static pool_t config_pool;
-/* trash_boxes ordered by priority, highest first */
-static ARRAY_DEFINE(trash_boxes, struct trash_mailbox);
-
static int trash_clean_mailbox_open(struct trash_mailbox *trash)
{
trash->box = mailbox_open(trash->storage, trash->name, NULL,
@@ -90,13 +97,14 @@
static int trash_try_clean_mails(struct quota_transaction_context *ctx,
uint64_t size_needed)
{
+ struct trash_user *tuser = TRASH_USER_CONTEXT(ctx->quota->user);
struct trash_mailbox *trashes;
unsigned int i, j, count, oldest_idx;
time_t oldest, received = 0;
uint64_t size, size_expunged = 0, expunged_count = 0;
int ret = 0;
- trashes = array_get_modifiable(&trash_boxes, &count);
+ trashes = array_get_modifiable(&tuser->trash_boxes, &count);
for (i = 0; i < count; ) {
/* expunge oldest mails first in all trash boxes with
same priority */
@@ -209,19 +217,18 @@
return 0;
}
-static bool trash_find_storage(struct trash_mailbox *trash)
+static bool trash_find_storage(struct mail_user *user,
+ struct trash_mailbox *trash)
{
- struct mail_storage *const *storages;
- unsigned int i, count;
+ struct mail_namespace *ns;
const char *name;
- storages = array_get("a_set->storages, &count);
- for (i = 0; i < count; i++) {
+ for (ns = user->namespaces; ns != NULL; ns = ns->next) {
name = trash->name;
- if (mail_namespace_update_name(storages[i]->ns, &name)) {
+ if (mail_namespace_update_name(ns, &name)) {
if (name != trash->name)
- trash->name = p_strdup(config_pool, name);
- trash->storage = storages[i];
+ trash->name = p_strdup(user->pool, name);
+ trash->storage = ns->storage;
return TRUE;
}
}
@@ -235,8 +242,9 @@
return t1->priority - t2->priority;
}
-static int read_configuration(const char *path)
+static int read_configuration(struct mail_user *user, const char *path)
{
+ struct trash_user *tuser = TRASH_USER_CONTEXT(user);
struct istream *input;
const char *line, *name;
struct trash_mailbox *trash;
@@ -249,8 +257,7 @@
return -1;
}
- p_clear(config_pool);
- p_array_init(&trash_boxes, config_pool, INIT_TRASH_MAILBOX_COUNT);
+ p_array_init(&tuser->trash_boxes, user->pool, INIT_TRASH_MAILBOX_COUNT);
input = i_stream_create_fd(fd, (size_t)-1, FALSE);
i_stream_set_return_partial_line(input, TRUE);
@@ -260,12 +267,12 @@
if (name == NULL || name[1] == '\0' || *line == '#')
continue;
- trash = array_append_space(&trash_boxes);
- trash->name = p_strdup(config_pool, name+1);
+ trash = array_append_space(&tuser->trash_boxes);
+ trash->name = p_strdup(user->pool, name+1);
trash->priority = atoi(t_strdup_until(line, name));
trash->search_arg.type = SEARCH_ALL;
- if (!trash_find_storage(trash)) {
+ if (!trash_find_storage(user, trash)) {
i_error("trash: Namespace not found for mailbox '%s'",
trash->name);
ret = -1;
@@ -279,7 +286,7 @@
i_stream_destroy(&input);
(void)close(fd);
- trash = array_get_modifiable(&trash_boxes, &count);
+ trash = array_get_modifiable(&tuser->trash_boxes, &count);
qsort(trash, count, sizeof(*trash), trash_mailbox_priority_cmp);
return ret;
}
@@ -287,23 +294,26 @@
static void
trash_hook_mail_namespaces_created(struct mail_namespace *namespaces)
{
+ struct mail_user *user = namespaces->user;
+ struct trash_user *tuser;
const char *env;
+ struct quota_settings *quota_set; /* APPLE */
env = getenv("TRASH");
if (env == NULL) {
if (getenv("DEBUG") != NULL)
i_info("trash: No trash setting - plugin disabled");
- } else if (quota_set == NULL) {
+ } else if ((quota_set = quota_settings_find(user)) == NULL) { /* APPLE */
i_error("trash plugin: quota plugin not initialized");
} else {
- config_pool = pool_alloconly_create("trash config",
- sizeof(trash_boxes) +
- BUFFER_APPROX_SIZE +
- INIT_TRASH_MAILBOX_COUNT *
- (sizeof(struct trash_mailbox) + 32));
- if (read_configuration(env) == 0) {
- trash_next_quota_test_alloc = quota_set->test_alloc;
- quota_set->test_alloc = trash_quota_test_alloc;
+ tuser = p_new(user->pool, struct trash_user, 1);
+ tuser->module_ctx.super = user->v;
+ MODULE_CONTEXT_SET(user, trash_user_module, tuser);
+
+ if (read_configuration(user, env) == 0) {
+ /* APPLE */
+ trash_next_quota_test_alloc = quota_settings_test_alloc;
+ quota_settings_test_alloc = trash_quota_test_alloc;
}
}
@@ -320,8 +330,6 @@
void trash_plugin_deinit(void)
{
hook_mail_namespaces_created = trash_hook_mail_namespaces_created;
- quota_set->test_alloc = trash_next_quota_test_alloc;
-
- if (config_pool != NULL)
- pool_unref(&config_pool);
+ /* APPLE */
+ quota_settings_test_alloc = trash_next_quota_test_alloc;
}
diff -Nur dovecot-1.1.7+patch9/src/pop3/Makefile.am dovecot-patch/src/pop3/Makefile.am
--- dovecot-1.1.7+patch9/src/pop3/Makefile.am 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/pop3/Makefile.am 2009-01-06 10:08:19.000000000 -0600
@@ -7,6 +7,7 @@
-I$(top_srcdir)/src/lib-dict \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-storage \
+ -I$(top_srcdir)/src/mail-common \
-DMODULEDIR=\""$(moduledir)"\"
pop3_LDFLAGS = -export-dynamic
@@ -21,6 +22,7 @@
../lib-storage/list/libstorage_list.a \
$(STORAGE_LIBS) \
../lib-imap/libimap.a \
+ ../mail-common/libmail-common.a \
../lib-mail/libmail.a \
../lib-dict/libdict.a \
../lib-charset/libcharset.a \
diff -Nur dovecot-1.1.7+patch9/src/pop3/client.c dovecot-patch/src/pop3/client.c
--- dovecot-1.1.7+patch9/src/pop3/client.c 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/pop3/client.c 2009-01-06 10:08:19.000000000 -0600
@@ -12,6 +12,8 @@
#include "commands.h"
#include "mail-search.h"
#include "mail-namespace.h"
+#include "master.h" /* APPLE */
+#include "ioloop.h" /* APPLE */
#include <stdlib.h>
#include <unistd.h>
@@ -29,7 +31,8 @@
/* Disconnect client after idling this many milliseconds */
#define CLIENT_IDLE_TIMEOUT_MSECS (10*60*1000)
-static struct client *my_client; /* we don't need more than one currently */
+static struct client *clients; /* APPLE was my_client, now list */
+static bool process_per_connection = TRUE; /* APPLE */
static void client_input(struct client *client);
static int client_output(struct client *client);
@@ -136,8 +139,10 @@
return FALSE;
}
+static /* APPLE */
struct client *client_create(int fd_in, int fd_out,
- struct mail_namespace *namespaces)
+ struct mail_user *user,
+ unsigned int connection_id) /* APPLE */
{
struct mail_storage *storage;
const char *inbox;
@@ -148,7 +153,8 @@
/* always use nonblocking I/O */
net_set_nonblock(fd_in, TRUE);
- net_set_nonblock(fd_out, TRUE);
+ if (fd_out != fd_in) /* APPLE */
+ net_set_nonblock(fd_out, TRUE);
client = i_new(struct client, 1);
client->fd_in = fd_in;
@@ -162,10 +168,15 @@
client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
client_idle_timeout, client);
- client->namespaces = namespaces;
+ client->user = user;
+
+ /* APPLE */
+ client->connection_id = connection_id;
+ client->next = clients;
+ clients = client;
inbox = "INBOX";
- client->inbox_ns = mail_namespace_find(namespaces, &inbox);
+ client->inbox_ns = mail_namespace_find(user->namespaces, &inbox);
if (client->inbox_ns == NULL) {
client_send_line(client, "-ERR No INBOX namespace for user.");
client_destroy(client, "No INBOX namespace for user.");
@@ -196,14 +207,49 @@
return NULL;
}
- i_assert(my_client == NULL);
- my_client = client;
-
if (hook_client_created != NULL)
hook_client_created(&client);
return client;
}
+/* APPLE */
+bool client_attach(int fd_in, int fd_out, bool is_standalone ATTR_UNUSED)
+{
+ const char *username, *home;
+ struct mail_user *user;
+ unsigned int connection_id;
+
+ username = getenv("USER");
+ if (username == NULL || *username == '\0') {
+ i_error("USER environment missing from client request");
+ return FALSE;
+ }
+
+ home = getenv("HOME");
+
+ user = mail_user_init(username, home);
+ if (mail_namespaces_init(user) < 0) {
+ i_error("Namespace initialization failed for user %s",
+ username);
+ mail_user_deinit(&user);
+ return FALSE;
+ }
+
+ if (process_per_connection)
+ connection_id = 0;
+ else {
+ const char *env = getenv("CONNECTION_ID");
+ if (env == NULL || *env == '\0') {
+ i_error("CONNECTION_ID environment missing from client request");
+ mail_user_deinit(&user);
+ return FALSE;
+ }
+ connection_id = strtoul(env, NULL, 10);
+ }
+
+ return client_create(fd_in, fd_out, user, connection_id) != NULL;
+}
+
static const char *client_stats(struct client *client)
{
static struct var_expand_table static_tab[] = {
@@ -250,10 +296,18 @@
void client_destroy(struct client *client, const char *reason)
{
+ struct client **pos; /* APPLE */
+ unsigned int connection_id; /* APPLE */
+
if (!client->disconnected) {
+ const char *prefix; /* APPLE */
+
if (reason == NULL)
reason = client_get_disconnect_reason(client);
- i_info("%s %s", reason, client_stats(client));
+ /* APPLE */
+ prefix = process_per_connection ? "" :
+ t_strconcat("User ", client->user->username, ": ", NULL);
+ i_info("%s%s %s", prefix, reason, client_stats(client));
}
if (client->cmd != NULL) {
@@ -271,7 +325,7 @@
}
if (client->mailbox != NULL)
mailbox_close(&client->mailbox);
- mail_namespaces_deinit(&client->namespaces);
+ mail_user_deinit(&client->user);
i_free(client->message_sizes);
i_free(client->deleted_bitmask);
@@ -290,21 +344,45 @@
i_error("close(client out) failed: %m");
}
+ /* APPLE */
+ for (pos = &clients; *pos != NULL; pos = &(*pos)->next) {
+ if (*pos == client) {
+ *pos = client->next;
+ break;
+ }
+ }
+ io_env_clean();
+ connection_id = client->connection_id;
+
i_free(client);
- /* quit the program */
- my_client = NULL;
- io_loop_stop(ioloop);
+ if (process_per_connection) { /* APPLE */
+ /* quit the program */
+ i_assert(clients == NULL);
+ io_loop_stop(ioloop);
+ } else {
+ /* (APPLE) run until master says stop, or can't say stop
+ and there are no more clients. otherwise there's a
+ race if there's an incoming request from the master. */
+ if (!master_send_disconnect(connection_id) &&
+ clients == NULL)
+ io_loop_stop(ioloop);
+ }
}
void client_disconnect(struct client *client, const char *reason)
{
+ const char *prefix; /* APPLE */
+
if (client->disconnected)
return;
- client->disconnected = TRUE;
- i_info("Disconnected: %s %s", reason, client_stats(client));
+ /* APPLE */
+ prefix = process_per_connection ? "" :
+ t_strconcat("User ", client->user->username, ": ", NULL);
+ i_info("%sDisconnected: %s %s", prefix, reason, client_stats(client));
+ client->disconnected = TRUE;
(void)o_stream_flush(client->output);
i_stream_close(client->input);
@@ -464,15 +542,51 @@
return client->cmd == NULL;
}
-void clients_init(void)
+void clients_init(bool persistent_mail_process) /* APPLE */
{
- my_client = NULL;
+ clients = NULL;
+ process_per_connection = !persistent_mail_process; /* APPLE */
}
void clients_deinit(void)
{
- if (my_client != NULL) {
- client_send_line(my_client, "-ERR Server shutting down.");
- client_destroy(my_client, "Server shutting down");
+ struct client *next;
+
+ /* APPLE */
+ while (clients != NULL) {
+ next = clients->next;
+ client_send_line(clients, "-ERR Server shutting down.");
+ client_destroy(clients, "Server shutting down");
+ clients = next;
+ }
+}
+
+/* APPLE */
+bool clients_connected(void)
+{
+ return clients != NULL;
+}
+
+/* APPLE */
+void clients_info(string_t *str)
+{
+ struct client *client;
+ int n;
+
+ n = 0;
+ for (client = clients; client != NULL; client = client->next)
+ ++n;
+
+ str_printfa(str, "%d connected user%s", n, n == 1 ? "" : "s");
+
+ if (n > 0) {
+ str_append(str, " (");
+ n = 0;
+ for (client = clients; client != NULL; client = client->next) {
+ if (n++ > 0)
+ str_append(str, ", ");
+ str_append(str, client->user->username);
+ }
+ str_append_c(str, ')');
}
}
diff -Nur dovecot-1.1.7+patch9/src/pop3/client.h dovecot-patch/src/pop3/client.h
--- dovecot-1.1.7+patch9/src/pop3/client.h 2008-10-26 10:03:45.000000000 -0500
+++ dovecot-patch/src/pop3/client.h 2009-01-06 10:08:19.000000000 -0600
@@ -7,6 +7,9 @@
typedef void command_func_t(struct client *client);
struct client {
+ struct client *next; /* APPLE */
+ unsigned int connection_id; /* APPLE */
+
int fd_in, fd_out;
struct io *io;
struct istream *input;
@@ -16,7 +19,8 @@
command_func_t *cmd;
void *cmd_context;
- struct mail_namespace *namespaces, *inbox_ns;
+ struct mail_user *user;
+ struct mail_namespace *inbox_ns;
struct mailbox *mailbox;
struct mailbox_transaction_context *trans;
@@ -47,10 +51,9 @@
unsigned int waiting_input:1;
};
-/* Create new client with specified input/output handles. socket specifies
- if the handle is a socket. */
-struct client *client_create(int fd_in, int fd_out,
- struct mail_namespace *namespaces);
+/* Create new client with specified input/output handles.
+ APPLE was client_create() */
+bool client_attach(int fd_in, int fd_out, bool is_standalone);
void client_destroy(struct client *client, const char *reason);
/* Disconnect client connection */
@@ -61,7 +64,9 @@
ATTR_FORMAT(2, 3);
void client_send_storage_error(struct client *client);
-void clients_init(void);
+void clients_init(bool persistent_mail_process); /* APPLE */
void clients_deinit(void);
+bool clients_connected(void); /* APPLE */
+void clients_info(string_t *str); /* APPLE */
#endif
diff -Nur dovecot-1.1.7+patch9/src/pop3/main.c dovecot-patch/src/pop3/main.c
--- dovecot-1.1.7+patch9/src/pop3/main.c 2008-11-05 12:01:47.000000000 -0600
+++ dovecot-patch/src/pop3/main.c 2009-01-06 10:08:19.000000000 -0600
@@ -14,6 +14,9 @@
#include "dict-client.h"
#include "mail-storage.h"
#include "mail-namespace.h"
+#include "master.h" /* APPLE */
+#include "env-util.h" /* APPLE */
+#include "str.h" /* APPLE */
#include <stdio.h>
#include <stdlib.h>
@@ -23,6 +26,9 @@
#define IS_STANDALONE() \
(getenv("LOGGED_IN") == NULL)
+/* APPLE */
+#define IS_PERSISTENT() (getenv("PERSISTENT_MAIL_PROCESS") != NULL)
+
struct client_workaround_list {
const char *name;
enum client_workarounds num;
@@ -39,7 +45,6 @@
void (*hook_client_created)(struct client **client) = NULL;
static struct module *modules = NULL;
-static pool_t namespace_pool;
static char log_prefix[128]; /* syslog() needs this to be permanent */
static struct io *log_io = NULL;
@@ -60,6 +65,21 @@
io_loop_stop(ioloop);
}
+/* APPLE */
+#ifdef SIGINFO
+static void sig_info(int signo ATTR_UNUSED, void *context ATTR_UNUSED)
+{
+ string_t *msg;
+
+ msg = t_str_new(512);
+ clients_info(msg);
+ str_append(msg, "; ");
+ master_info(msg);
+
+ i_info("POP3 process %d: %s", getpid(), str_c(msg));
+}
+#endif
+
static void log_error_callback(void *context ATTR_UNUSED)
{
io_loop_stop(ioloop);
@@ -182,7 +202,7 @@
static int main_init(void)
{
- struct mail_namespace *ns;
+ int fd_in, fd_out; /* APPLE */
lib_signals_init();
lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
@@ -208,7 +228,15 @@
mail_storage_init();
mail_storage_register_all();
mailbox_list_register_all();
- clients_init();
+ clients_init(IS_PERSISTENT()); /* APPLE */
+
+ /* APPLE */
+ master_init(IS_PERSISTENT() ? 0 : -1,
+ ioloop, client_attach, clients_connected);
+#ifdef SIGINFO
+ if (IS_PERSISTENT())
+ lib_signals_set_handler(SIGINFO, TRUE, sig_info, NULL);
+#endif
module_dir_init(modules);
@@ -229,14 +257,21 @@
i_fatal("pop3_uidl_format setting doesn't contain any "
"%% variables.");
- namespace_pool = pool_alloconly_create("namespaces", 1024);
- if (mail_namespaces_init(namespace_pool, getenv("USER"), &ns) < 0)
- i_fatal("Namespace initialization failed");
- return client_create(0, 1, ns) != NULL;
+ /* APPLE */
+ if (IS_PERSISTENT())
+ fd_in = fd_out = 3;
+ else {
+ fd_in = 0;
+ fd_out = 1;
+ }
+
+ return client_attach(fd_in, fd_out, IS_STANDALONE());
}
static void main_deinit(void)
{
+ master_deinit(); /* APPLE */
+
if (log_io != NULL)
io_remove(&log_io);
clients_deinit();
@@ -253,8 +288,10 @@
int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
{
#ifdef DEBUG
- if (getenv("LOGGED_IN") != NULL && getenv("GDB") == NULL)
- fd_debug_verify_leaks(3, 1024);
+ if (getenv("LOGGED_IN") != NULL && getenv("GDB") == NULL) {
+ int base = IS_PERSISTENT() ? 4 : 3; /* APPLE */
+ fd_debug_verify_leaks(base, 1024);
+ }
#endif
if (IS_STANDALONE() && getuid() == 0 &&
net_getpeername(1, NULL, NULL) == 0) {
@@ -268,6 +305,10 @@
lib_init();
drop_privileges();
+ /* APPLE */
+ if (IS_PERSISTENT())
+ io_env_enable();
+
process_title_init(argv, envp);
ioloop = io_loop_create();