dovecot: Initial implementation for mail_max_user_connections se...

dovecot at dovecot.org dovecot at dovecot.org
Sat Jun 30 21:16:32 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/21e529b8a701
changeset: 5846:21e529b8a701
user:      Timo Sirainen <tss at iki.fi>
date:      Sat Jun 30 19:14:08 2007 +0300
description:
Initial implementation for mail_max_user_connections setting.

diffstat:

18 files changed, 232 insertions(+), 61 deletions(-)
dovecot-example.conf                 |    7 +
src/imap-login/client-authenticate.c |    8 +
src/login-common/master.c            |    7 -
src/login-common/master.h            |    3 
src/login-common/sasl-server.c       |   21 +++-
src/master/child-process.c           |    6 -
src/master/child-process.h           |    4 
src/master/dict-process.c            |    1 
src/master/login-process.c           |    9 -
src/master/mail-process.c            |  178 +++++++++++++++++++++++++++-------
src/master/mail-process.h            |   13 +-
src/master/main.c                    |    6 -
src/master/master-login-interface.h  |    9 +
src/master/master-settings-defs.c    |    1 
src/master/master-settings.c         |    9 +
src/master/master-settings.h         |    1 
src/master/ssl-init.c                |    2 
src/pop3-login/client-authenticate.c |    8 +

diffs (truncated from 645 to 300 lines):

diff -r 9265c13c4103 -r 21e529b8a701 dovecot-example.conf
--- a/dovecot-example.conf	Sat Jun 30 19:01:06 2007 +0300
+++ b/dovecot-example.conf	Sat Jun 30 19:14:08 2007 +0300
@@ -333,6 +333,13 @@
 # Maximum number of running mail processes. When this limit is reached,
 # new users aren't allowed to log in.
 #max_mail_processes = 1024
+
+# Maximum number of connections allowed for a user. The limits are enforced
+# separately for IMAP and POP3 connections, so you can move this setting
+# inside protocol {} to have separate settings for them. NOTE: The user names
+# are compared case-sensitively, so make sure your userdb returns usernames
+# always using the same casing so users can't bypass this limit!
+#mail_max_user_connections = 10
 
 # Set max. process size in megabytes. Most of the memory goes to mmap()ing
 # files, so it shouldn't harm much even if this limit is set pretty high.
diff -r 9265c13c4103 -r 21e529b8a701 src/imap-login/client-authenticate.c
--- a/src/imap-login/client-authenticate.c	Sat Jun 30 19:01:06 2007 +0300
+++ b/src/imap-login/client-authenticate.c	Sat Jun 30 19:14:08 2007 +0300
@@ -222,7 +222,13 @@ static void sasl_callback(struct client 
 		}
 		break;
 	case SASL_SERVER_REPLY_MASTER_FAILED:
-		client_destroy_internal_failure(client);
+		if (data == NULL)
+			client_destroy_internal_failure(client);
+		else {
+			client_send_tagline(client,
+					    t_strconcat("NO ", data, NULL));
+			client_destroy(client, data);
+		}
 		break;
 	case SASL_SERVER_REPLY_CONTINUE:
 		data_len = strlen(data);
diff -r 9265c13c4103 -r 21e529b8a701 src/login-common/master.c
--- a/src/login-common/master.c	Sat Jun 30 19:01:06 2007 +0300
+++ b/src/login-common/master.c	Sat Jun 30 19:14:08 2007 +0300
@@ -22,7 +22,8 @@ static char master_buf[sizeof(struct mas
 static char master_buf[sizeof(struct master_login_reply)];
 static struct client destroyed_client;
 
-static void client_call_master_callback(struct client *client, bool success)
+static void client_call_master_callback(struct client *client,
+					enum master_login_status status)
 {
 	master_callback_t *master_callback;
 
@@ -30,7 +31,7 @@ static void client_call_master_callback(
 	client->master_tag = 0;
 	client->master_callback = NULL;
 
-	master_callback(client, success);
+	master_callback(client, status);
 }
 
 static void request_handle(struct master_login_reply *reply)
@@ -50,7 +51,7 @@ static void request_handle(struct master
 
 	hash_remove(master_requests, POINTER_CAST(reply->tag));
 	if (client != &destroyed_client) {
-		client_call_master_callback(client, reply->success);
+		client_call_master_callback(client, reply->status);
 		/* NOTE: client may be destroyed now */
 	}
 }
diff -r 9265c13c4103 -r 21e529b8a701 src/login-common/master.h
--- a/src/login-common/master.h	Sat Jun 30 19:01:06 2007 +0300
+++ b/src/login-common/master.h	Sat Jun 30 19:14:08 2007 +0300
@@ -5,7 +5,8 @@ struct client;
 
 #include "../master/master-login-interface.h"
 
-typedef void master_callback_t(struct client *client, bool success);
+typedef void master_callback_t(struct client *client,
+			       enum master_login_status status);
 
 void master_request_login(struct client *client, master_callback_t *callback,
 			  unsigned int auth_pid, unsigned int auth_id);
diff -r 9265c13c4103 -r 21e529b8a701 src/login-common/sasl-server.c
--- a/src/login-common/sasl-server.c	Sat Jun 30 19:01:06 2007 +0300
+++ b/src/login-common/sasl-server.c	Sat Jun 30 19:14:08 2007 +0300
@@ -37,11 +37,24 @@ call_client_callback(struct client *clie
 	/* NOTE: client may be destroyed now */
 }
 
-static void master_callback(struct client *client, bool success)
-{
+static void
+master_callback(struct client *client, enum master_login_status status)
+{
+	enum sasl_server_reply reply = SASL_SERVER_REPLY_MASTER_FAILED;
+	const char *data = NULL;
+
 	client->authenticating = FALSE;
-	call_client_callback(client, success ? SASL_SERVER_REPLY_SUCCESS :
-			     SASL_SERVER_REPLY_MASTER_FAILED, NULL, NULL);
+	switch (status) {
+	case MASTER_LOGIN_STATUS_OK:
+		reply = SASL_SERVER_REPLY_SUCCESS;
+		break;
+	case MASTER_LOGIN_STATUS_INTERNAL_ERROR:
+		break;
+	case MASTER_LOGIN_STATUS_MAX_CONNECTIONS:
+		data = "Maximum number of connections exceeded";
+		break;
+	}
+	call_client_callback(client, reply, data, NULL);
 }
 
 static void authenticate_callback(struct auth_request *request, int status,
diff -r 9265c13c4103 -r 21e529b8a701 src/master/child-process.c
--- a/src/master/child-process.c	Sat Jun 30 19:01:06 2007 +0300
+++ b/src/master/child-process.c	Sat Jun 30 19:14:08 2007 +0300
@@ -153,8 +153,10 @@ static void sigchld_handler(int signo __
 				WTERMSIG(status));
 		}
 
-		if (destroy_callbacks[process_type] != NULL)
-			destroy_callbacks[process_type](process, abnormal_exit);
+		if (destroy_callbacks[process_type] != NULL) {
+			destroy_callbacks[process_type](process, pid,
+							abnormal_exit);
+		}
 	}
 
 	if (pid == -1 && errno != EINTR && errno != ECHILD)
diff -r 9265c13c4103 -r 21e529b8a701 src/master/child-process.h
--- a/src/master/child-process.h	Sat Jun 30 19:01:06 2007 +0300
+++ b/src/master/child-process.h	Sat Jun 30 19:14:08 2007 +0300
@@ -18,8 +18,8 @@ struct child_process {
 	enum process_type type;
 };
 
-typedef void child_process_destroy_callback_t(struct child_process *,
-					      bool abnormal_exit);
+typedef void child_process_destroy_callback_t(struct child_process *process,
+					      pid_t pid, bool abnormal_exit);
 
 extern const char *process_names[];
 extern struct hash_table *processes;
diff -r 9265c13c4103 -r 21e529b8a701 src/master/dict-process.c
--- a/src/master/dict-process.c	Sat Jun 30 19:01:06 2007 +0300
+++ b/src/master/dict-process.c	Sat Jun 30 19:14:08 2007 +0300
@@ -159,6 +159,7 @@ static void dict_process_unlisten(struct
 
 static void
 dict_process_destroyed(struct child_process *process,
+		       pid_t pid __attr_unused__,
 		       bool abnormal_exit __attr_unused__)
 {
 	struct dict_process *p = (struct dict_process *)process;
diff -r 9265c13c4103 -r 21e529b8a701 src/master/login-process.c
--- a/src/master/login-process.c	Sat Jun 30 19:01:06 2007 +0300
+++ b/src/master/login-process.c	Sat Jun 30 19:14:08 2007 +0300
@@ -94,12 +94,12 @@ void auth_master_callback(const char *us
 
 	memset(&master_reply, 0, sizeof(master_reply));
 	if (user == NULL)
-		master_reply.success = FALSE;
+		master_reply.status = MASTER_LOGIN_STATUS_INTERNAL_ERROR;
 	else {
 		struct login_group *group = request->process->group;
 
 		t_push();
-		master_reply.success =
+		master_reply.status =
 			create_mail_process(group->mail_process_type,
 					    group->set,
 					    request->fd, &request->local_ip,
@@ -683,7 +683,8 @@ static pid_t create_login_process(struct
 }
 
 static void
-login_process_destroyed(struct child_process *process, bool abnormal_exit)
+login_process_destroyed(struct child_process *process,
+			pid_t pid __attr_unused__, bool abnormal_exit)
 {
 	struct login_process *p = (struct login_process *)process;
 
@@ -910,8 +911,6 @@ void login_processes_init(void)
 
 void login_processes_deinit(void)
 {
-        login_processes_destroy_all();
-
 	if (to != NULL)
 		timeout_remove(&to);
 	if (io_listen != NULL)
diff -r 9265c13c4103 -r 21e529b8a701 src/master/mail-process.c
--- a/src/master/mail-process.c	Sat Jun 30 19:01:06 2007 +0300
+++ b/src/master/mail-process.c	Sat Jun 30 19:14:08 2007 +0300
@@ -1,7 +1,8 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002 Timo Sirainen */
 
 #include "common.h"
 #include "array.h"
+#include "hash.h"
 #include "fd-close-on-exec.h"
 #include "env-util.h"
 #include "str.h"
@@ -12,6 +13,7 @@
 #include "home-expand.h"
 #include "var-expand.h"
 #include "mail-process.h"
+#include "master-login-interface.h"
 #include "login-process.h"
 #include "log.h"
 
@@ -31,10 +33,76 @@
    many seconds to finish. */
 #define CHDIR_WARN_SECS 10
 
-static struct child_process imap_child_process = { PROCESS_TYPE_IMAP };
-static struct child_process pop3_child_process = { PROCESS_TYPE_POP3 };
-
+struct mail_process_group {
+	/* process.type / user identifies this process group */
+	struct child_process process;
+	char *user;
+
+	/* processes array acts also as refcount */
+	ARRAY_DEFINE(processes, pid_t);
+};
+
+/* type+user -> struct mail_process_group */
+static struct hash_table *mail_process_groups;
 static unsigned int mail_process_count = 0;
+
+static unsigned int mail_process_group_hash(const void *p)
+{
+	const struct mail_process_group *group = p;
+
+	return str_hash(group->user) ^ group->process.type;
+}
+
+static int mail_process_group_cmp(const void *p1, const void *p2)
+{
+	const struct mail_process_group *group1 = p1, *group2 = p2;
+	int ret;
+
+	ret = strcmp(group1->user, group2->user);
+	if (ret == 0)
+		ret = group1->process.type - group2->process.type;
+	return ret;
+}
+
+static struct mail_process_group *
+mail_process_group_lookup(enum process_type type, const char *user)
+{
+	struct mail_process_group lookup_group;
+
+	lookup_group.process.type = type;
+	lookup_group.user = t_strdup_noconst(user);
+
+	return hash_lookup(mail_process_groups, &lookup_group);
+}
+
+static struct mail_process_group *
+mail_process_group_create(enum process_type type, const char *user)
+{
+	struct mail_process_group *group;
+
+	group = i_new(struct mail_process_group, 1);
+	group->process.type = type;
+	group->user = i_strdup(user);
+
+	i_array_init(&group->processes, 10);
+	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_count++;
+	array_append(&group->processes, &pid, 1);
+	child_process_add(pid, &group->process);
+}
+
+static void mail_process_group_free(struct mail_process_group *group)
+{
+	array_free(&group->processes);
+	i_free(group->user);
+	i_free(group);
+}
 
 static bool validate_uid_gid(struct settings *set, uid_t uid, gid_t gid,
 			     const char *user)
@@ -422,15 +490,17 @@ static void nfs_warn_if_found(const char
 		"If you're sure this check was wrong, set nfs_check=no.", path);
 }
 
-bool create_mail_process(enum process_type process_type, struct settings *set,
-			 int socket, const struct ip_addr *local_ip,
-			 const struct ip_addr *remote_ip,
-			 const char *user, const char *const *args,
-			 bool dump_capability)
+enum master_login_status


More information about the dovecot-cvs mailing list