changeset 877:7935347f54f1 HEAD

Don't access ImapArg's union members directly - too easy to mess up. Fixes a crash with feeding non-string parameters to SEARCH/SORT commands.
author Timo Sirainen <tss@iki.fi>
date Thu, 02 Jan 2003 10:09:26 +0200
parents ad8f7d2107b4
children cc1cf8161203
files src/imap/cmd-append.c src/imap/cmd-fetch.c src/imap/cmd-search.c src/imap/cmd-sort.c src/imap/cmd-status.c src/imap/cmd-store.c src/imap/commands-util.c src/lib-imap/imap-bodystructure.c src/lib-imap/imap-envelope.c src/lib-imap/imap-parser.c src/lib-imap/imap-parser.h src/lib-storage/mail-search.c
diffstat 12 files changed, 131 insertions(+), 64 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/cmd-append.c	Sun Dec 29 21:44:37 2002 +0200
+++ b/src/imap/cmd-append.c	Thu Jan 02 10:09:26 2003 +0200
@@ -44,16 +44,16 @@
 					     internal_date, msg_size, 4);
 
 		if (args[1].type == IMAP_ARG_LIST)
-			*flags = args[1].data.list;
+			*flags = IMAP_ARG_LIST(&args[1]);
 		else if (args[1].type == IMAP_ARG_STRING)
-			*internal_date = args[1].data.str;
+			*internal_date = IMAP_ARG_STR(&args[1]);
 		else
 			return -1;
 		break;
 	case 4:
 		/* we have all parameters */
-		*flags = args[1].data.list;
-		*internal_date = args[2].data.str;
+		*flags = IMAP_ARG_LIST(&args[1]);
+		*internal_date = IMAP_ARG_STR(&args[2]);
 		break;
 	default:
                 i_unreached();
@@ -67,7 +67,7 @@
 	if (args[count-1].type != IMAP_ARG_LITERAL_SIZE)
 		return -1;
 
-	*msg_size = args[count-1].data.literal_size;
+	*msg_size = IMAP_ARG_LITERAL_SIZE(&args[count-1]);
 	return 1;
 }
 
--- a/src/imap/cmd-fetch.c	Sun Dec 29 21:44:37 2002 +0200
+++ b/src/imap/cmd-fetch.c	Thu Jan 02 10:09:26 2003 +0200
@@ -105,8 +105,7 @@
 		return FALSE;
 	}
 
-	item = arg->data.str;
-	str_ucase(item);
+	item = str_ucase(IMAP_ARG_STR(arg));
 
 	switch (*item) {
 	case 'A':
@@ -215,7 +214,7 @@
 	if (item == NULL) {
 		/* unknown item */
 		client_send_tagline(client, t_strconcat(
-			"BAD Invalid item ", arg->data.str, NULL));
+			"BAD Invalid item ", IMAP_ARG_STR(arg), NULL));
 		return FALSE;
 	}
 
@@ -248,7 +247,7 @@
 		if (!parse_arg(client, &args[1], &data))
 			return TRUE;
 	} else {
-		listargs = args[1].data.list->args;
+		listargs = IMAP_ARG_LIST(&args[1])->args;
 		while (listargs->type != IMAP_ARG_EOL) {
 			if (!parse_arg(client, listargs, &data))
 				return TRUE;
--- a/src/imap/cmd-search.c	Sun Dec 29 21:44:37 2002 +0200
+++ b/src/imap/cmd-search.c	Thu Jan 02 10:09:26 2003 +0200
@@ -26,7 +26,7 @@
 		return TRUE;
 
 	if (args->type == IMAP_ARG_ATOM &&
-	    strcasecmp(args->data.str, "CHARSET") == 0) {
+	    strcasecmp(IMAP_ARG_STR(args), "CHARSET") == 0) {
 		/* CHARSET specified */
 		args++;
 		if (args->type != IMAP_ARG_ATOM &&
@@ -36,7 +36,7 @@
 			return TRUE;
 		}
 
-		charset = args->data.str;
+		charset = IMAP_ARG_STR(args);
 		args++;
 	} else {
 		charset = NULL;
--- a/src/imap/cmd-sort.c	Sun Dec 29 21:44:37 2002 +0200
+++ b/src/imap/cmd-sort.c	Thu Jan 02 10:09:26 2003 +0200
@@ -34,7 +34,7 @@
 				    (size_t)-1);
 
 	while (args->type == IMAP_ARG_ATOM || args->type == IMAP_ARG_STRING) {
-		const char *arg = args->data.str;
+		const char *arg = IMAP_ARG_STR(args);
 
 		for (i = 0; sort_names[i].type != MAIL_SORT_END; i++) {
 			if (strcasecmp(arg, sort_names[i].name) == 0)
@@ -91,7 +91,7 @@
 		return TRUE;
 	}
 
-	sorting = get_sort_program(client, args->data.list->args);
+	sorting = get_sort_program(client, IMAP_ARG_LIST(args)->args);
 	if (sorting == NULL)
 		return TRUE;
 	args++;
@@ -101,7 +101,7 @@
 		client_send_command_error(client,
 					  "Invalid charset argument.");
 	}
-	charset = args->data.str;
+	charset = IMAP_ARG_STR(args);
 	args++;
 
 	pool = pool_alloconly_create("MailSortArgs", 2048);
--- a/src/imap/cmd-status.c	Sun Dec 29 21:44:37 2002 +0200
+++ b/src/imap/cmd-status.c	Thu Jan 02 10:09:26 2003 +0200
@@ -19,8 +19,7 @@
 			return -1;
 		}
 
-		str_ucase(args->data.str);
-		item = args->data.str;
+		item = str_ucase(IMAP_ARG_STR(args));
 
 		if (strcmp(item, "MESSAGES") == 0)
 			items |= STATUS_MESSAGES;
@@ -95,7 +94,7 @@
 	}
 
 	/* get the items client wants */
-	items = get_status_items(client, args[1].data.list->args);
+	items = get_status_items(client, IMAP_ARG_LIST(&args[1])->args);
 	if (items == (MailboxStatusItems)-1) {
 		/* error */
 		return TRUE;
--- a/src/imap/cmd-store.c	Sun Dec 29 21:44:37 2002 +0200
+++ b/src/imap/cmd-store.c	Thu Jan 02 10:09:26 2003 +0200
@@ -60,8 +60,9 @@
 		return TRUE;
 
 	if (args[2].type == IMAP_ARG_LIST) {
-		if (!client_parse_mail_flags(client, args[2].data.list->args,
-					     args[2].data.list->size,
+		if (!client_parse_mail_flags(client,
+					     IMAP_ARG_LIST(&args[2])->args,
+					     IMAP_ARG_LIST(&args[2])->size,
 					     &flags, custflags))
 			return TRUE;
 	} else {
--- a/src/imap/commands-util.c	Sun Dec 29 21:44:37 2002 +0200
+++ b/src/imap/commands-util.c	Thu Jan 02 10:09:26 2003 +0200
@@ -129,7 +129,7 @@
 			return FALSE;
 		}
 
-		atom = args[pos].data.str;
+		atom = IMAP_ARG_STR(&args[pos]);
 		if (*atom == '\\') {
 			/* system flag */
 			str_ucase(atom);
--- a/src/lib-imap/imap-bodystructure.c	Sun Dec 29 21:44:37 2002 +0200
+++ b/src/lib-imap/imap-bodystructure.c	Thu Jan 02 10:09:26 2003 +0200
@@ -456,15 +456,15 @@
 			str_append(str, "NIL");
 			break;
 		case IMAP_ARG_ATOM:
-			str_append(str, args->data.str);
+			str_append(str, IMAP_ARG_STR(args));
 			break;
 		case IMAP_ARG_STRING:
 			str_append_c(str, '"');
-			str_append(str, args->data.str);
+			str_append(str, IMAP_ARG_STR(args));
 			str_append_c(str, '"');
 			break;
 		case IMAP_ARG_LIST:
-			if (!imap_write_list(args->data.list->args, str))
+			if (!imap_write_list(IMAP_ARG_LIST(args)->args, str))
 				return FALSE;
 			break;
 		default:
@@ -482,12 +482,14 @@
 static int imap_parse_bodystructure_args(const ImapArg *args, String *str)
 {
 	ImapArg *subargs;
+	ImapArgList *list;
 	int i, multipart, text, message_rfc822;
 
 	multipart = FALSE;
 	while (args->type == IMAP_ARG_LIST) {
 		str_append_c(str, '(');
-		if (!imap_parse_bodystructure_args(args->data.list->args, str))
+		list = IMAP_ARG_LIST(args);
+		if (!imap_parse_bodystructure_args(list->args, str))
 			return FALSE;
 		str_append_c(str, ')');
 
@@ -500,7 +502,7 @@
 		if (args->type != IMAP_ARG_STRING)
 			return FALSE;
 
-		str_printfa(str, " \"%s\"", args->data.str);
+		str_printfa(str, " \"%s\"", IMAP_ARG_STR(args));
 		return TRUE;
 	}
 
@@ -508,24 +510,26 @@
 	if (args[0].type != IMAP_ARG_STRING || args[1].type != IMAP_ARG_STRING)
 		return FALSE;
 
-	text = strcasecmp(args[0].data.str, "text") == 0;
-	message_rfc822 = strcasecmp(args[0].data.str, "message") == 0 &&
-		strcasecmp(args[1].data.str, "rfc822") == 0;
+	text = strcasecmp(IMAP_ARG_STR(&args[0]), "text") == 0;
+	message_rfc822 = strcasecmp(IMAP_ARG_STR(&args[0]), "message") == 0 &&
+		strcasecmp(IMAP_ARG_STR(&args[1]), "rfc822") == 0;
 
-	str_printfa(str, "\"%s\" \"%s\"", args[0].data.str, args[1].data.str);
+	str_printfa(str, "\"%s\" \"%s\"", IMAP_ARG_STR(&args[0]),
+		    IMAP_ARG_STR(&args[1]));
 	args += 2;
 
 	/* ("content type param key" "value" ...) | NIL */
 	if (args->type == IMAP_ARG_LIST) {
 		str_append(str, " (");
-                subargs = args->data.list->args;
+                subargs = IMAP_ARG_LIST(args)->args;
 		for (; subargs->type != IMAP_ARG_EOL; ) {
 			if (subargs[0].type != IMAP_ARG_STRING ||
 			    subargs[1].type != IMAP_ARG_STRING)
 				return FALSE;
 
 			str_printfa(str, "\"%s\" \"%s\"",
-				    subargs[0].data.str, subargs[1].data.str);
+				    IMAP_ARG_STR(&subargs[0]),
+				    IMAP_ARG_STR(&subargs[1]));
 
 			subargs += 2;
 			if (subargs->type == IMAP_ARG_EOL)
@@ -546,9 +550,9 @@
 			str_append(str, " NIL");
 		} else if (args->type == IMAP_ARG_ATOM) {
 			str_append_c(str, ' ');
-			str_append(str, args->data.str);
+			str_append(str, IMAP_ARG_STR(args));
 		} else if (args->type == IMAP_ARG_STRING) {
-			str_printfa(str, " \"%s\"", args->data.str);
+			str_printfa(str, " \"%s\"", IMAP_ARG_STR(args));
 		} else {
 			return FALSE;
 		}
@@ -560,7 +564,7 @@
 			return FALSE;
 
 		str_append_c(str, ' ');
-		str_append(str, args->data.str);
+		str_append(str, IMAP_ARG_STR(args));
 	} else if (message_rfc822) {
 		/* message/rfc822 - envelope + bodystructure + text lines */
 		if (args[0].type != IMAP_ARG_LIST ||
@@ -570,17 +574,18 @@
 
 		str_append_c(str, ' ');
 
-		if (!imap_write_list(args[0].data.list->args, str))
+		list = IMAP_ARG_LIST(&args[0]);
+		if (!imap_write_list(list->args, str))
 			return FALSE;
 
 		str_append_c(str, ' ');
 
-		if (!imap_parse_bodystructure_args(args[1].data.list->args,
-						   str))
+		list = IMAP_ARG_LIST(&args[1]);
+		if (!imap_parse_bodystructure_args(list->args, str))
 			return FALSE;
 
 		str_append_c(str, ' ');
-		str_append(str, args[2].data.str);
+		str_append(str, IMAP_ARG_STR(&args[2]));
 	}
 
 	return TRUE;
--- a/src/lib-imap/imap-envelope.c	Sun Dec 29 21:44:37 2002 +0200
+++ b/src/lib-imap/imap-envelope.c	Thu Jan 02 10:09:26 2003 +0200
@@ -128,7 +128,7 @@
 
 	if (arg->type != IMAP_ARG_LIST)
 		return FALSE;
-	list = arg->data.list;
+	list = IMAP_ARG_LIST(arg);
 
 	/* we require 4 arguments, strings or NILs */
 	if (list->size < 4)
@@ -137,8 +137,9 @@
 	for (i = 0; i < 4; i++) {
 		if (list->args[i].type == IMAP_ARG_NIL)
 			args[i] = NULL;
-		else if (list->args[i].type == IMAP_ARG_STRING)
-			args[i] = list->args[i].data.str;
+		else if (list->args[i].type == IMAP_ARG_STRING ||
+			 list->args[i].type == IMAP_ARG_ATOM)
+			args[i] = IMAP_ARG_STR(&list->args[i]);
 		else
 			return FALSE;
 	}
@@ -200,7 +201,7 @@
 	in_group = FALSE;
 	str = t_str_new(128);
 
-        list = arg->data.list;
+        list = IMAP_ARG_LIST(arg);
 	for (i = 0; i < list->size; i++) {
 		if (!imap_address_arg_append(&list->args[i], str, &in_group))
 			return NULL;
@@ -211,18 +212,25 @@
 
 static const char *imap_envelope_parse_first_mailbox(ImapArg *arg)
 {
+	ImapArgList *list;
+
 	/* ((name route mailbox domain) ...) */
 	if (arg->type != IMAP_ARG_LIST)
 		return NULL;
 
-	if (arg->data.list->size == 0)
+	list = IMAP_ARG_LIST(arg);
+	if (list->size == 0)
 		return "";
 
-	arg = arg->data.list->args;
-	if (arg->type != IMAP_ARG_LIST || arg->data.list->size != 4)
+	arg = IMAP_ARG_LIST(arg)->args;
+	if (arg->type != IMAP_ARG_LIST)
 		return NULL;
 
-	return t_strdup(arg->data.list->args[2].data.str);
+	list = IMAP_ARG_LIST(arg);
+	if (list->size != 4)
+		return NULL;
+
+	return t_strdup(imap_arg_string(&list->args[2]));
 }
 
 static const char *
@@ -238,8 +246,8 @@
 	case IMAP_ENVELOPE_RESULT_STRING:
 		if (field >= IMAP_ENVELOPE_FROM && field <= IMAP_ENVELOPE_BCC)
 			value = imap_envelope_parse_address(arg);
-		else if (arg->type == IMAP_ARG_STRING || arg->type == IMAP_ARG_ATOM)
-			value = t_strdup(arg->data.str);
+		else
+			value = t_strdup(imap_arg_string(arg));
 		break;
 	case IMAP_ENVELOPE_RESULT_FIRST_MAILBOX:
 		i_assert(field >= IMAP_ENVELOPE_FROM &&
--- a/src/lib-imap/imap-parser.c	Sun Dec 29 21:44:37 2002 +0200
+++ b/src/lib-imap/imap-parser.c	Thu Jan 02 10:09:26 2003 +0200
@@ -57,7 +57,7 @@
 	if (parser->list_arg == NULL)
 		parser->root_list = parser->cur_list;
 	else
-		parser->list_arg->data.list = parser->cur_list;
+		parser->list_arg->_data.list = parser->cur_list;
 }
 
 ImapParser *imap_parser_create(IStream *input, OStream *output,
@@ -156,7 +156,7 @@
 	imap_args_realloc(parser, LIST_ALLOC_SIZE);
 
 	parser->list_arg->type = IMAP_ARG_LIST;
-	parser->list_arg->data.list = parser->cur_list;
+	parser->list_arg->_data.list = parser->cur_list;
 
 	parser->cur_type = ARG_PARSE_NONE;
 }
@@ -179,7 +179,7 @@
 	if (parser->list_arg == NULL) {
 		parser->cur_list = parser->root_list;
 	} else {
-		parser->cur_list = parser->list_arg->data.list;
+		parser->cur_list = parser->list_arg->_data.list;
 	}
 
 	parser->cur_type = ARG_PARSE_NONE;
@@ -201,7 +201,7 @@
 		} else {
 			/* simply save the string */
 			arg->type = IMAP_ARG_ATOM;
-			arg->data.str = p_strndup(parser->pool, data, lastpos);
+			arg->_data.str = p_strndup(parser->pool, data, lastpos);
 		}
 		break;
 	case ARG_PARSE_STRING:
@@ -209,13 +209,13 @@
 		i_assert(lastpos > 0);
 
 		arg->type = IMAP_ARG_STRING;
-		arg->data.str = p_strndup(parser->pool, data+1, lastpos-1);
+		arg->_data.str = p_strndup(parser->pool, data+1, lastpos-1);
 
 		/* remove the escapes */
 		if (parser->str_first_escape >= 0 &&
 		    (parser->flags & IMAP_PARSE_FLAG_NO_UNESCAPE) == 0) {
 			/* -1 because we skipped the '"' prefix */
-			str_remove_escapes(arg->data.str +
+			str_remove_escapes(arg->_data.str +
 					   parser->str_first_escape-1);
 		}
 		break;
@@ -223,11 +223,11 @@
 		if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) == 0) {
 			/* simply save the string */
 			arg->type = IMAP_ARG_STRING;
-			arg->data.str = p_strndup(parser->pool, data, lastpos);
+			arg->_data.str = p_strndup(parser->pool, data, lastpos);
 		} else {
 			/* save literal size */
 			arg->type = IMAP_ARG_LITERAL_SIZE;
-			arg->data.literal_size = parser->literal_size;
+			arg->_data.literal_size = parser->literal_size;
 		}
 		break;
 	default:
@@ -596,9 +596,27 @@
 
 	case IMAP_ARG_ATOM:
 	case IMAP_ARG_STRING:
-		return arg->data.str;
+		return arg->_data.str;
 
 	default:
 		return NULL;
 	}
 }
+
+char *_imap_arg_str_error(const ImapArg *arg)
+{
+	i_panic("Tried to access ImapArg type %d as string", arg->type);
+	return NULL;
+}
+
+uoff_t _imap_arg_literal_size_error(const ImapArg *arg)
+{
+	i_panic("Tried to access ImapArg type %d as literal size", arg->type);
+	return 0;
+}
+
+ImapArgList *_imap_arg_list_error(const ImapArg *arg)
+{
+	i_panic("Tried to access ImapArg type %d as list", arg->type);
+	return NULL;
+}
--- a/src/lib-imap/imap-parser.h	Sun Dec 29 21:44:37 2002 +0200
+++ b/src/lib-imap/imap-parser.h	Thu Jan 02 10:09:26 2003 +0200
@@ -33,9 +33,23 @@
 		char *str;
 		uoff_t literal_size;
 		ImapArgList *list;
-	} data;
+	} _data;
 };
 
+#define IMAP_ARG_STR(arg) \
+	((arg)->type == IMAP_ARG_NIL ? NULL : \
+	 (arg)->type == IMAP_ARG_ATOM || (arg)->type == IMAP_ARG_STRING ? \
+	 (arg)->_data.str : _imap_arg_str_error(arg))
+
+#define IMAP_ARG_LITERAL_SIZE(arg) \
+	((arg)->type == IMAP_ARG_LITERAL_SIZE ? \
+	 (arg)->_data.literal_size : _imap_arg_literal_size_error(arg))
+
+#define IMAP_ARG_LIST(arg) \
+	((arg)->type == IMAP_ARG_NIL ? NULL : \
+	 (arg)->type == IMAP_ARG_LIST ? \
+	 (arg)->_data.list : _imap_arg_list_error(arg))
+
 struct _ImapArgList {
 	size_t size, alloc;
 	ImapArg args[1]; /* variable size */
@@ -78,4 +92,9 @@
 /* Returns the imap argument as string. NIL returns "" and list returns NULL. */
 const char *imap_arg_string(ImapArg *arg);
 
+/* Error functions */
+char *_imap_arg_str_error(const ImapArg *arg);
+uoff_t _imap_arg_literal_size_error(const ImapArg *arg);
+ImapArgList *_imap_arg_list_error(const ImapArg *arg);
+
 #endif
--- a/src/lib-storage/mail-search.c	Sun Dec 29 21:44:37 2002 +0200
+++ b/src/lib-storage/mail-search.c	Thu Jan 02 10:09:26 2003 +0200
@@ -36,7 +36,13 @@
 		return FALSE;
 	}
 
-	sarg->value.str = str_ucase((*args)->data.str);
+	if ((*args)->type != IMAP_ARG_ATOM &&
+	    (*args)->type != IMAP_ARG_STRING) {
+		data->error = "Invalid parameter for argument";
+		return FALSE;
+	}
+
+	sarg->value.str = str_ucase(IMAP_ARG_STR(*args));
 	*args += 1;
 
 	/* second arg */
@@ -46,8 +52,14 @@
 			return FALSE;
 		}
 
+		if ((*args)->type != IMAP_ARG_ATOM &&
+		    (*args)->type != IMAP_ARG_STRING) {
+			data->error = "Invalid parameter for argument";
+			return FALSE;
+		}
+
                 sarg->hdr_field_name = sarg->value.str;
-		sarg->value.str = str_ucase((*args)->data.str);
+		sarg->value.str = str_ucase(IMAP_ARG_STR(*args));
 		*args += 1;
 	}
 
@@ -75,7 +87,7 @@
 	}
 
 	if (arg->type == IMAP_ARG_LIST) {
-		ImapArg *listargs = arg->data.list->args;
+		ImapArg *listargs = IMAP_ARG_LIST(arg)->args;
 
 		*next_sarg = search_arg_new(data->pool, SEARCH_SUB);
 		subargs = &(*next_sarg)->value.subargs;
@@ -93,7 +105,7 @@
 		 arg->type == IMAP_ARG_STRING);
 
 	/* string argument - get the name and jump to next */
-	str = arg->data.str;
+	str = IMAP_ARG_STR(arg);
 	*args += 1;
 	str_ucase(str);
 
@@ -145,7 +157,13 @@
 				data->error = "Missing parameter for HEADER";
 				return FALSE;
 			}
-			key = str_ucase((*args)->data.str);
+			if ((*args)->type != IMAP_ARG_ATOM &&
+			    (*args)->type != IMAP_ARG_STRING) {
+				data->error = "Invalid parameter for HEADER";
+				return FALSE;
+			}
+
+			key = str_ucase(IMAP_ARG_STR(*args));
 
 			if (strcmp(key, "FROM") == 0) {
 				*args += 1;
@@ -221,7 +239,7 @@
 					break;
 
 				if ((*args)->type != IMAP_ARG_ATOM ||
-				    strcasecmp((*args)->data.str, "OR") != 0)
+				    strcasecmp(IMAP_ARG_STR(*args), "OR") != 0)
 					break;
 
 				*args += 1;