[dovecot-cvs] dovecot/src/login Makefile.am,1.3,1.4 client-authenticate.c,1.29,1.30 client-authenticate.h,1.2,1.3 client.c,1.24,1.25 client.h,1.9,1.10

cras at procontrol.fi cras at procontrol.fi
Tue Jan 7 19:45:40 EET 2003


Update of /home/cvs/dovecot/src/login
In directory danu:/tmp/cvs-serv29994

Modified Files:
	Makefile.am client-authenticate.c client-authenticate.h 
	client.c client.h 
Log Message:
Login process now uses the same imap-parser as the imap process itself. This
fixes the problem of literals not working before logging in.



Index: Makefile.am
===================================================================
RCS file: /home/cvs/dovecot/src/login/Makefile.am,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- Makefile.am	24 Nov 2002 20:05:06 -0000	1.3
+++ Makefile.am	7 Jan 2003 17:45:38 -0000	1.4
@@ -3,10 +3,12 @@
 pkglibexec_PROGRAMS = imap-login
 
 INCLUDES = \
-	-I$(top_srcdir)/src/lib
+	-I$(top_srcdir)/src/lib \
+	-I$(top_srcdir)/src/lib-imap
 
 imap_login_LDADD = \
 	../lib/liblib.a \
+	../lib-imap/imap-parser.o \
 	$(SSL_LIBS)
 
 imap_login_SOURCES = \

Index: client-authenticate.c
===================================================================
RCS file: /home/cvs/dovecot/src/login/client-authenticate.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- client-authenticate.c	6 Jan 2003 15:44:48 -0000	1.29
+++ client-authenticate.c	7 Jan 2003 17:45:38 -0000	1.30
@@ -8,6 +8,7 @@
 #include "ostream.h"
 #include "safe-memset.h"
 #include "str.h"
+#include "imap-parser.h"
 #include "auth-connection.h"
 #include "../auth/auth-mech-desc.h"
 #include "client.h"
@@ -128,7 +129,7 @@
 	case AUTH_RESULT_SUCCESS:
 		client->auth_request = NULL;
 
-		master_request_imap(client->fd, auth_process, client->tag,
+		master_request_imap(client->fd, auth_process, client->cmd_tag,
 				    request->cookie, &client->ip,
 				    master_callback, client);
 
@@ -180,9 +181,20 @@
 	}
 }
 
-int cmd_login(struct client *client, const char *user, const char *pass)
+int cmd_login(struct client *client, struct imap_arg *args)
 {
-	const char *error;
+	const char *user, *pass, *error;
+
+	/* two arguments: username and password */
+	if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
+		return FALSE;
+	if (args[1].type != IMAP_ARG_ATOM && args[1].type != IMAP_ARG_STRING)
+		return FALSE;
+	if (args[2].type != IMAP_ARG_EOL)
+		return FALSE;
+
+	user = IMAP_ARG_STR(&args[0]);
+	pass = IMAP_ARG_STR(&args[1]);
 
 	if (!client->tls && disable_plaintext_auth) {
 		client_send_tagline(client,
@@ -239,6 +251,7 @@
 	if (!client_read(client))
 		return;
 
+	/* @UNSAFE */
 	line = i_stream_next_line(client->input);
 	if (line == NULL)
 		return;
@@ -270,11 +283,18 @@
 	safe_memset(buffer_free_without_data(buf), 0, bufsize);
 }
 
-int cmd_authenticate(struct client *client, const char *mech_name)
+int cmd_authenticate(struct client *client, struct imap_arg *args)
 {
 	struct auth_mech_desc *mech;
-	const char *error;
+	const char *mech_name, *error;
 
+	/* we want only one argument: authentication mechanism name */
+	if (args[0].type != IMAP_ARG_ATOM && args[0].type != IMAP_ARG_STRING)
+		return FALSE;
+	if (args[1].type != IMAP_ARG_EOL)
+		return FALSE;
+
+	mech_name = IMAP_ARG_STR(&args[0]);
 	if (*mech_name == '\0')
 		return FALSE;
 

Index: client-authenticate.h
===================================================================
RCS file: /home/cvs/dovecot/src/login/client-authenticate.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- client-authenticate.h	5 Jan 2003 13:09:53 -0000	1.2
+++ client-authenticate.h	7 Jan 2003 17:45:38 -0000	1.3
@@ -3,7 +3,7 @@
 
 const char *client_authenticate_get_capabilities(void);
 
-int cmd_login(struct client *client, const char *user, const char *pass);
-int cmd_authenticate(struct client *client, const char *method_name);
+int cmd_login(struct client *client, struct imap_arg *args);
+int cmd_authenticate(struct client *client, struct imap_arg *args);
 
 #endif

Index: client.c
===================================================================
RCS file: /home/cvs/dovecot/src/login/client.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- client.c	5 Jan 2003 13:09:53 -0000	1.24
+++ client.c	7 Jan 2003 17:45:38 -0000	1.25
@@ -9,12 +9,20 @@
 #include "process-title.h"
 #include "safe-memset.h"
 #include "strescape.h"
+#include "imap-parser.h"
 #include "client.h"
 #include "client-authenticate.h"
 #include "ssl-proxy.h"
 
 #include <syslog.h>
 
+/* max. size of one parameter in line */
+#define MAX_INBUF_SIZE 512
+
+/* max. number of IMAP argument elements to accept. The maximum memory usage
+   for command from user is around MAX_INBUF_SIZE * MAX_IMAP_ARG_ELEMENTS */
+#define MAX_IMAP_ARG_ELEMENTS 4
+
 /* Disconnect client after idling this many seconds */
 #define CLIENT_LOGIN_IDLE_TIMEOUT 60
 
@@ -118,122 +126,127 @@
 	return TRUE;
 }
 
-int client_read(struct client *client)
+static int client_command_execute(struct client *client, const char *cmd,
+				  struct imap_arg *args)
 {
-	switch (i_stream_read(client->input)) {
-	case -2:
-		/* buffer full */
-		client_send_line(client, "* BYE Input buffer full, aborting");
-		client_destroy(client, "Disconnected: Input buffer full");
-		return FALSE;
-	case -1:
-		/* disconnected */
-		client_destroy(client, "Disconnected");
-		return FALSE;
-	default:
-		/* something was read */
-		return TRUE;
-	}
+	cmd = str_ucase(t_strdup_noconst(cmd));
+	if (strcmp(cmd, "LOGIN") == 0)
+		return cmd_login(client, args);
+	if (strcmp(cmd, "AUTHENTICATE") == 0)
+		return cmd_authenticate(client, args);
+	if (strcmp(cmd, "CAPABILITY") == 0)
+		return cmd_capability(client);
+	if (strcmp(cmd, "STARTTLS") == 0)
+		return cmd_starttls(client);
+	if (strcmp(cmd, "NOOP") == 0)
+		return cmd_noop(client);
+	if (strcmp(cmd, "LOGOUT") == 0)
+		return cmd_logout(client);
+
+	return FALSE;
 }
 
-static char *get_next_arg(char **linep)
+/* Skip incoming data until newline is found,
+   returns TRUE if newline was found. */
+static int client_skip_line(struct client *client)
 {
-	char *line, *start;
-	int quoted;
-
-	line = *linep;
-	while (*line == ' ') line++;
+	const unsigned char *data;
+	size_t i, data_size;
 
-	/* @UNSAFE: get next argument, unescape arg if it's quoted */
-	if (*line == '"') {
-		quoted = TRUE;
-		line++;
+	data = i_stream_get_data(client->input, &data_size);
 
-		start = line;
-		while (*line != '\0' && *line != '"') {
-			if (*line == '\\' && line[1] != '\0')
-				line++;
-			line++;
+	for (i = 0; i < data_size; i++) {
+		if (data[i] == '\n') {
+			i_stream_skip(client->input, i+1);
+			return TRUE;
 		}
-
-		if (*line == '"')
-			*line++ = '\0';
-		str_unescape(start);
-	} else {
-		start = line;
-		while (*line != '\0' && *line != ' ')
-			line++;
-
-		if (*line == ' ')
-			*line++ = '\0';
 	}
 
-	*linep = line;
-	return start;
+	return FALSE;
 }
 
-static int client_command_execute(struct client *client, char *line)
+static void client_handle_input(struct client *client)
 {
-	char *cmd;
-	int ret;
+	struct imap_arg *args;
 
-	cmd = get_next_arg(&line);
-	str_ucase(cmd);
+	if (client->cmd_finished) {
+		/* clear the previous command from memory. don't do this
+		   immediately after handling command since we need the
+		   cmd_tag to stay some time after authentication commands. */
+		client->cmd_tag = NULL;
+		client->cmd_name = NULL;
+		imap_parser_reset(client->parser);
 
-	if (strcmp(cmd, "LOGIN") == 0) {
-		char *user, *pass;
+		/* remove \r\n */
+		if (!client_skip_line(client))
+			return;
 
-		user = get_next_arg(&line);
-		pass = get_next_arg(&line);
-		ret = cmd_login(client, user, pass);
+		client->cmd_finished = FALSE;
+	}
 
-		safe_memset(pass, 0, strlen(pass));
-		return ret;
+	if (client->cmd_tag == NULL) {
+                client->cmd_tag = imap_parser_read_word(client->parser);
+		if (client->cmd_tag == NULL)
+			return; /* need more data */
 	}
-	if (strcmp(cmd, "AUTHENTICATE") == 0)
-		return cmd_authenticate(client, get_next_arg(&line));
-	if (strcmp(cmd, "CAPABILITY") == 0)
-		return cmd_capability(client);
-	if (strcmp(cmd, "STARTTLS") == 0)
-		return cmd_starttls(client);
-	if (strcmp(cmd, "NOOP") == 0)
-		return cmd_noop(client);
-	if (strcmp(cmd, "LOGOUT") == 0)
-		return cmd_logout(client);
 
-	return FALSE;
+	if (client->cmd_name == NULL) {
+                client->cmd_name = imap_parser_read_word(client->parser);
+		if (client->cmd_name == NULL)
+			return; /* need more data */
+	}
+
+	switch (imap_parser_read_args(client->parser, 0, 0, &args)) {
+	case -1:
+		/* error */
+		client_destroy(client, NULL);
+		return;
+	case -2:
+		/* not enough data */
+		return;
+	}
+
+	if (*client->cmd_tag == '\0' ||
+	    !client_command_execute(client, client->cmd_name, args)) {
+		client_send_tagline(client,
+			"BAD Error in IMAP command received by server.");
+	}
+
+	client->cmd_finished = TRUE;
+}
+
+int client_read(struct client *client)
+{
+	switch (i_stream_read(client->input)) {
+	case -2:
+		/* buffer full */
+		client_send_line(client, "* BYE Input buffer full, aborting");
+		client_destroy(client, "Disconnected: Input buffer full");
+		return FALSE;
+	case -1:
+		/* disconnected */
+		client_destroy(client, "Disconnected");
+		return FALSE;
+	default:
+		/* something was read */
+		return TRUE;
+	}
 }
 
 void client_input(void *context, int fd __attr_unused__,
 		  struct io *io __attr_unused__)
 {
 	struct client *client = context;
-	char *line;
 
 	client->last_input = ioloop_time;
 
-	i_free(client->tag);
-	client->tag = i_strdup("*");
-
 	if (!client_read(client))
 		return;
 
 	client_ref(client);
-	o_stream_cork(client->output);
 
-	while ((line = i_stream_next_line(client->input)) != NULL) {
-		/* split the arguments, make sure we have at
-		   least tag + command */
-		i_free(client->tag);
-		client->tag = i_strdup(get_next_arg(&line));
-
-		if (*client->tag == '\0' ||
-		    !client_command_execute(client, line)) {
-			/* error */
-			client_send_tagline(client, "BAD Error in IMAP command "
-					    "received by server.");
-		}
-	}
+	o_stream_cork(client->output);
+	client_handle_input(client);
 
 	if (client_unref(client))
 		o_stream_flush(client->output);
@@ -306,7 +319,11 @@
 	client->input = i_stream_create_file(fd, default_pool, 8192, FALSE);
 	client->output = o_stream_create_file(fd, default_pool, 1024,
 					      IO_PRIORITY_DEFAULT, FALSE);
+	client->parser = imap_parser_create(client->input, client->output,
+					    MAX_INBUF_SIZE,
+					    MAX_IMAP_ARG_ELEMENTS);
 	client->plain_login = buffer_create_dynamic(system_pool, 128, 8192);
+
 	client->last_input = ioloop_time;
 	hash_insert(clients, client, client);
 
@@ -324,6 +341,7 @@
 
 	hash_remove(clients, client);
 
+	imap_parser_destroy(client->parser);
 	i_stream_close(client->input);
 	o_stream_close(client->output);
 
@@ -351,7 +369,6 @@
 	i_stream_unref(client->input);
 	o_stream_unref(client->output);
 
-	i_free(client->tag);
 	buffer_free(client->plain_login);
 	i_free(client);
 
@@ -367,7 +384,7 @@
 
 void client_send_tagline(struct client *client, const char *line)
 {
-	client_send_line(client, t_strconcat(client->tag, " ", line, NULL));
+	client_send_line(client, t_strconcat(client->cmd_tag, " ", line, NULL));
 }
 
 void client_syslog(struct client *client, const char *text)

Index: client.h
===================================================================
RCS file: /home/cvs/dovecot/src/login/client.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- client.h	5 Jan 2003 13:09:53 -0000	1.9
+++ client.h	7 Jan 2003 17:45:38 -0000	1.10
@@ -12,14 +12,16 @@
 	struct io *io;
 	struct istream *input;
 	struct ostream *output;
+	struct imap_parser *parser;
 
 	time_t last_input;
-	char *tag;
+	const char *cmd_tag, *cmd_name;
 
 	buffer_t *plain_login;
 	struct auth_request *auth_request;
 
 	unsigned int tls:1;
+	unsigned int cmd_finished:1;
 };
 
 struct client *client_create(int fd, struct ip_addr *ip, int imaps);




More information about the dovecot-cvs mailing list