changeset 805:5ac361acb316 HEAD

Marked all non-trivial buffer modifications with @UNSAFE tag. Several cleanups and a couple of minor bugfixes.
author Timo Sirainen <tss@iki.fi>
date Wed, 18 Dec 2002 17:15:41 +0200
parents bf38c8f30a4c
children 5e42a1dbcd0c
files configure.in src/auth/auth-digest-md5.c src/auth/userinfo-pam.c src/auth/userinfo-passwd-file.c src/auth/userinfo-passwd.c src/auth/userinfo-shadow.c src/auth/userinfo-vpopmail.c src/imap/client.c src/lib-imap/imap-envelope.c src/lib-imap/imap-match.c src/lib-imap/imap-match.h src/lib-imap/imap-message-cache.c src/lib-imap/imap-parser.c src/lib-imap/imap-util.c src/lib-index/mail-index-update.c src/lib-index/mbox/mbox-index.c src/lib-index/mbox/mbox-rewrite.c src/lib-mail/message-body-search.c src/lib-mail/message-header-search.c src/lib-mail/message-size.c src/lib-mail/message-size.h src/lib-mail/rfc822-tokenize.c src/lib-storage/subscription-file/subscription-file.c src/lib/buffer.c src/lib/buffer.h src/lib/compat.c src/lib/compat.h src/lib/data-stack.c src/lib/hex-binary.c src/lib/ioloop-poll.c src/lib/istream-file.c src/lib/istream.c src/lib/md5.c src/lib/mempool-alloconly.c src/lib/mempool-datastack.c src/lib/mempool-system.c src/lib/mmap-anon.c src/lib/network.c src/lib/network.h src/lib/ostream-file.c src/lib/randgen.c src/lib/strfuncs.c src/lib/temp-string.c src/lib/unlink-directory.c src/login/auth-connection.c src/login/client-authenticate.c src/login/client.c src/login/master.c src/login/ssl-proxy-gnutls.c src/login/ssl-proxy-openssl.c src/master/auth-process.c src/master/imap-process.c src/master/login-process.c src/master/main.c src/master/settings.c src/master/ssl-init.c
diffstat 56 files changed, 304 insertions(+), 224 deletions(-) [+]
line wrap: on
line diff
--- a/configure.in	Wed Dec 18 12:40:43 2002 +0200
+++ b/configure.in	Wed Dec 18 17:15:41 2002 +0200
@@ -166,7 +166,7 @@
 
 dnl * after -lsocket and -lnsl tests, inet_aton() may be in them
 AC_CHECK_FUNCS(fcntl flock inet_aton sigaction getpagesize madvise \
-               strcasecmp stricmp vsnprintf memmove vsyslog writev setrlimit \
+               strcasecmp stricmp vsnprintf vsyslog writev setrlimit \
 	       setproctitle)
 
 dnl * poll/select?
--- a/src/auth/auth-digest-md5.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/auth/auth-digest-md5.c	Wed Dec 18 17:15:41 2002 +0200
@@ -218,6 +218,7 @@
 
 static int parse_next(char **data, char **key, char **value)
 {
+	/* @UNSAFE */
 	char *p, *dest;
 
 	p = *data;
@@ -271,6 +272,7 @@
 /* remove leading and trailing whitespace */
 static char *trim(char *str)
 {
+	/* @UNSAFE */
 	char *ret;
 
 	while (IS_LWS(*str)) str++;
--- a/src/auth/userinfo-pam.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/auth/userinfo-pam.c	Wed Dec 18 17:15:41 2002 +0200
@@ -60,6 +60,7 @@
 static int pam_userpass_conv(int num_msg, linux_const struct pam_message **msg,
 	struct pam_response **resp, void *appdata_ptr)
 {
+	/* @UNSAFE */
 	pam_userpass_t *userpass = (pam_userpass_t *)appdata_ptr;
 #ifdef AUTH_PAM_USERPASS
 	pamc_bp_t prompt;
--- a/src/auth/userinfo-passwd-file.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/auth/userinfo-passwd-file.c	Wed Dec 18 17:15:41 2002 +0200
@@ -312,7 +312,7 @@
 {
 	IStream *input;
 	char *const *args;
-	char *line;
+	const char *line;
 
 	input = i_stream_create_file(pw->fd, default_pool, 2048, FALSE);
 	for (;;) {
--- a/src/auth/userinfo-passwd.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/auth/userinfo-passwd.c	Wed Dec 18 17:15:41 2002 +0200
@@ -31,7 +31,6 @@
 			       AuthCookieReplyData *reply)
 {
 	struct passwd *pw;
-	char *passdup;
 	int result;
 
 	pw = getpwnam(user);
@@ -39,11 +38,9 @@
 		return FALSE;
 
 	/* check if the password is valid */
-        passdup = t_strdup_noconst(password);
-	result = strcmp(mycrypt(passdup, pw->pw_passwd), pw->pw_passwd) == 0;
+	result = strcmp(mycrypt(password, pw->pw_passwd), pw->pw_passwd) == 0;
 
 	/* clear the passwords from memory */
-	safe_memset(passdup, 0, strlen(passdup));
 	safe_memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
 
 	if (!result)
--- a/src/auth/userinfo-shadow.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/auth/userinfo-shadow.c	Wed Dec 18 17:15:41 2002 +0200
@@ -20,7 +20,6 @@
 {
 	struct passwd *pw;
 	struct spwd *spw;
-	char *passdup;
 	int result;
 
 	spw = getspnam(user);
@@ -28,11 +27,9 @@
 		return FALSE;
 
 	/* check if the password is valid */
-        passdup = t_strdup_noconst(password);
-	result = strcmp(mycrypt(passdup, spw->sp_pwdp), spw->sp_pwdp) == 0;
+	result = strcmp(mycrypt(password, spw->sp_pwdp), spw->sp_pwdp) == 0;
 
 	/* clear the passwords from memory */
-	safe_memset(passdup, 0, strlen(passdup));
 	safe_memset(spw->sp_pwdp, 0, strlen(spw->sp_pwdp));
 
 	if (!result)
--- a/src/auth/userinfo-vpopmail.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/auth/userinfo-vpopmail.c	Wed Dec 18 17:15:41 2002 +0200
@@ -26,7 +26,6 @@
 {
 	char vpop_user[VPOPMAIL_LIMIT], vpop_domain[VPOPMAIL_LIMIT];
 	struct vqpasswd *vpw;
-	char *passdup;
 	int result;
 
 	/* vpop_user must be zero-filled or parse_email() leaves an extra
@@ -77,10 +76,7 @@
 	}
 
 	/* verify password */
-        passdup = t_strdup_noconst(password);
-	result = strcmp(crypt(passdup, vpw->pw_passwd), vpw->pw_passwd) == 0;
-
-	safe_memset(passdup, 0, strlen(passdup));
+	result = strcmp(crypt(password, vpw->pw_passwd), vpw->pw_passwd) == 0;
 	safe_memset(vpw->pw_passwd, 0, strlen(vpw->pw_passwd));
 
 	if (!result) {
--- a/src/imap/client.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/imap/client.c	Wed Dec 18 17:15:41 2002 +0200
@@ -63,10 +63,6 @@
 	client->output = o_stream_create_file(hout, default_pool, 4096,
 					      IO_PRIORITY_DEFAULT, FALSE);
 
-	/* always use nonblocking I/O */
-	net_set_nonblock(hin, TRUE);
-	net_set_nonblock(hout, TRUE);
-
 	/* set timeout for reading expected data (eg. APPEND). This is
 	   different from the actual idle time. */
 	i_stream_set_blocking(client->input, CLIENT_CMDINPUT_TIMEOUT,
--- a/src/lib-imap/imap-envelope.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-imap/imap-envelope.c	Wed Dec 18 17:15:41 2002 +0200
@@ -21,12 +21,7 @@
 static Rfc822Address *parse_address(Pool pool, const char *value,
 				    size_t value_len)
 {
-	Rfc822Address *ret;
-
-	t_push();
-	ret = rfc822_address_parse(pool, t_strndup(value, value_len));
-	t_pop();
-	return ret;
+	return rfc822_address_parse(pool, t_strndup(value, value_len));
 }
 
 void imap_envelope_parse_header(Pool pool, MessagePartEnvelopeData **data,
@@ -38,6 +33,8 @@
 		(*data)->pool = pool;
 	}
 
+	t_push();
+
 	if (strcasecmp(name, "Date") == 0 && (*data)->date == NULL)
 		(*data)->date = imap_quote_value(pool, value, value_len);
 	else if (strcasecmp(name, "Subject") == 0 && (*data)->subject == NULL)
@@ -60,6 +57,8 @@
 	else if (strcasecmp(name, "Message-Id") == 0 &&
 		 (*data)->message_id == NULL)
 		(*data)->message_id = imap_quote_value(pool, value, value_len);
+
+	t_pop();
 }
 
 static void imap_write_address(TempString *str, Rfc822Address *addr)
--- a/src/lib-imap/imap-match.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-imap/imap-match.c	Wed Dec 18 17:15:41 2002 +0200
@@ -21,33 +21,34 @@
 static const char inbox[] = "INBOX";
 #define INBOXLEN (sizeof(inbox) - 1)
 
-ImapMatchGlob *imap_match_init(const char *str, int inboxcase, char separator)
+ImapMatchGlob *imap_match_init(const char *mask, int inboxcase, char separator)
 {
 	ImapMatchGlob *glob;
 	const char *p, *inboxp;
 	char *dst;
 
 	/* +1 from struct */
-	glob = t_malloc(sizeof(ImapMatchGlob) + strlen(str));
+	glob = t_malloc(sizeof(ImapMatchGlob) + strlen(mask));
 	glob->sep_char = separator;
 
+	/* @UNSAFE: compress the mask */
 	dst = glob->mask;
-	while (*str != '\0') {
-		if (*str == '*' || *str == '%') {
+	while (*mask != '\0') {
+		if (*mask == '*' || *mask == '%') {
 			/* remove duplicate hierarchy wildcards */
-			while (*str == '%') str++;
+			while (*mask == '%') mask++;
 
 			/* "%*" -> "*" */
-			if (*str == '*') {
+			if (*mask == '*') {
 				/* remove duplicate wildcards */
-				while (*str == '*' || *str == '%')
-					str++;
+				while (*mask == '*' || *mask == '%')
+					mask++;
 				*dst++ = '*';
 			} else {
 				*dst++ = '%';
 			}
 		} else {
-			*dst++ = *str++;
+			*dst++ = *mask++;
 		}
 	}
 	*dst++ = '\0';
--- a/src/lib-imap/imap-match.h	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-imap/imap-match.h	Wed Dec 18 17:15:41 2002 +0200
@@ -5,7 +5,7 @@
 
 /* If inboxcase is TRUE, the "INBOX" string at the beginning of line is
    compared case-insensitively */
-ImapMatchGlob *imap_match_init(const char *str, int inboxcase, char separator);
+ImapMatchGlob *imap_match_init(const char *mask, int inboxcase, char separator);
 
 /* Returns 1 if matched, 0 if it didn't match, but could match with additional
    hierarchies, -1 if definitely didn't match */
--- a/src/lib-imap/imap-message-cache.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-imap/imap-message-cache.c	Wed Dec 18 17:15:41 2002 +0200
@@ -228,7 +228,8 @@
 			   do it only if the file isn't open already, since
 			   this takes more CPU than parsing message headers. */
 			value = cache->iface->get_cached_field(
-				IMAP_CACHE_BODYSTRUCTURE, cache->context);
+						IMAP_CACHE_BODYSTRUCTURE,
+						cache->context);
 			if (value != NULL) {
 				value = imap_body_parse_from_bodystructure(
 									value);
--- a/src/lib-imap/imap-parser.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-imap/imap-parser.c	Wed Dec 18 17:15:41 2002 +0200
@@ -136,6 +136,7 @@
 
 	i_assert(parser->cur_list != NULL);
 
+	/* @UNSAFE */
 	if (parser->cur_list->size == parser->cur_list->alloc)
 		imap_args_realloc(parser, parser->cur_list->alloc * 2);
 
--- a/src/lib-imap/imap-util.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-imap/imap-util.c	Wed Dec 18 17:15:41 2002 +0200
@@ -63,7 +63,7 @@
 	if (esc == 0)
 		return str;
 
-	/* escape them */
+	/* @UNSAFE: escape them */
 	p = ret = t_malloc(i + esc + 1);
 	for (; *str != '\0'; str++) {
 		if (IS_ESCAPED_CHAR(str[i]))
--- a/src/lib-index/mail-index-update.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-index/mail-index-update.c	Wed Dec 18 17:15:41 2002 +0200
@@ -207,7 +207,7 @@
 	return TRUE;
 }
 
-/* Replace the whole block - assumes there's enoguh space to do it */
+/* Replace the whole block - assumes there's enough space to do it */
 static void update_by_replace_block(MailIndexUpdate *update, size_t extra_size)
 {
 	MailIndexDataRecordHeader *data_hdr;
--- a/src/lib-index/mbox/mbox-index.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-index/mbox/mbox-index.c	Wed Dec 18 17:15:41 2002 +0200
@@ -119,7 +119,8 @@
 	mbox_file_close_stream(index);
 
 	if (index->mbox_fd != -1) {
-		close(index->mbox_fd);
+		if (close(index->mbox_fd) < 0)
+			i_error("close(mbox) failed: %m");
 		index->mbox_fd = -1;
 	}
 }
--- a/src/lib-index/mbox/mbox-rewrite.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-index/mbox/mbox-rewrite.c	Wed Dec 18 17:15:41 2002 +0200
@@ -199,7 +199,7 @@
 static const char *strip_chars(const char *value, size_t value_len,
 			       const char *list)
 {
-	/* leave only unknown flags, very likely none */
+	/* @UNSAFE: leave only unknown flags, very likely none */
 	char *ret, *p;
 	size_t i;
 
--- a/src/lib-mail/message-body-search.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-mail/message-body-search.c	Wed Dec 18 17:15:41 2002 +0200
@@ -32,9 +32,7 @@
 	CharsetTranslation *translation;
 
 	Buffer *decode_buf;
-
-	size_t *matches;
-	ssize_t match_count;
+	Buffer *match_buf;
 
 	char *content_type;
 	char *content_charset;
@@ -156,30 +154,31 @@
 static int message_search_decoded_block(PartSearchContext *ctx, Buffer *block)
 {
 	const unsigned char *p, *end, *key;
-	size_t key_len, block_size;
+	size_t key_len, block_size, *matches, match_count, value;
 	ssize_t i;
 
 	key = (const unsigned char *) ctx->body_ctx->key;
 	key_len = ctx->body_ctx->key_len;
 
+	matches = buffer_get_modifyable_data(ctx->match_buf, &match_count);
+	match_count /= sizeof(size_t);
+
 	p = buffer_get_data(block, &block_size);
 	end = p + block_size;
 	for (; p != end; p++) {
-		for (i = ctx->match_count-1; i >= 0; i--) {
-			if (key[ctx->matches[i]] == *p) {
-				if (++ctx->matches[i] == key_len) {
+		for (i = match_count-1; i >= 0; i--) {
+			if (key[matches[i]] == *p) {
+				if (++matches[i] == key_len) {
 					/* full match */
 					p++;
 					return TRUE;
 				}
 			} else {
 				/* non-match */
-				ctx->match_count--;
-				if (i != ctx->match_count) {
-					memmove(ctx->matches + i,
-						ctx->matches + i + 1,
-						ctx->match_count - i);
-				}
+				buffer_delete(ctx->match_buf,
+					      i * sizeof(size_t),
+					      sizeof(size_t));
+				match_count--;
 			}
 		}
 
@@ -190,8 +189,9 @@
 				return TRUE;
 			}
 
-			i_assert((size_t)ctx->match_count < key_len);
-			ctx->matches[ctx->match_count++] = 1;
+			value = 1;
+			buffer_append(ctx->match_buf, &value, sizeof(value));
+			match_count++;
 		}
 	}
 
@@ -284,9 +284,9 @@
 		ctx->translation = charset_to_utf8_begin("ascii", NULL);
 
 	ctx->decode_buf = buffer_create_static(data_stack_pool, 256);
-
-	ctx->match_count = 0;
-	ctx->matches = t_malloc(sizeof(size_t) * ctx->body_ctx->key_len);
+	ctx->match_buf = buffer_create_static_hard(data_stack_pool,
+						   sizeof(size_t) *
+						   ctx->body_ctx->key_len);
 
 	i_stream_skip(input, part->physical_pos +
 		      part->header_size.physical_size - input->v_offset);
--- a/src/lib-mail/message-header-search.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-mail/message-header-search.c	Wed Dec 18 17:15:41 2002 +0200
@@ -18,8 +18,7 @@
 	size_t key_len;
 	char *key_charset;
 
-	size_t *matches; /* size of strlen(key) */
-	ssize_t match_count;
+	Buffer *match_buf;
 
 	unsigned int found:1;
 	unsigned int last_newline:1;
@@ -48,7 +47,6 @@
 
 	if (key == NULL) {
 		/* invalid key */
-		t_pop();
 		return NULL;
 	}
 
@@ -66,7 +64,8 @@
 	}
 
 	i_assert(ctx->key_len <= SSIZE_T_MAX/sizeof(size_t));
-	ctx->matches = p_new(pool, size_t, ctx->key_len);
+	ctx->match_buf = buffer_create_static_hard(pool, sizeof(size_t) *
+						   ctx->key_len);
 	return ctx;
 }
 
@@ -74,10 +73,11 @@
 {
 	Pool pool;
 
+	buffer_free(ctx->match_buf);
+
 	pool = ctx->pool;
 	p_free(pool, ctx->key);
 	p_free(pool, ctx->key_charset);
-	p_free(pool, ctx->matches);
 	p_free(pool, ctx);
 }
 
@@ -112,11 +112,14 @@
 static void search_loop(const unsigned char *data, size_t size,
 			HeaderSearchContext *ctx)
 {
-	size_t pos;
+	size_t pos, *matches, match_count, value;
 	ssize_t i;
 	unsigned char chr;
 	int last_newline;
 
+	matches = buffer_get_modifyable_data(ctx->match_buf, &match_count);
+	match_count /= sizeof(size_t);
+
 	last_newline = ctx->last_newline;
 	for (pos = 0; pos < size; pos++) {
 		chr = data[pos];
@@ -137,7 +140,8 @@
 		if (last_newline && !ctx->submatch) {
 			if (!IS_LWSP(chr)) {
 				/* not a long header, reset matches */
-				ctx->match_count = 0;
+				buffer_set_used_size(ctx->match_buf, 0);
+				match_count = 0;
 			}
 			chr = ' ';
 		}
@@ -146,21 +150,19 @@
 		if (chr == '\r' || chr == '\n')
 			continue;
 
-		for (i = ctx->match_count-1; i >= 0; i--) {
-			if (ctx->key[ctx->matches[i]] == chr) {
-				if (++ctx->matches[i] == ctx->key_len) {
+		for (i = match_count-1; i >= 0; i--) {
+			if (ctx->key[matches[i]] == chr) {
+				if (++matches[i] == ctx->key_len) {
 					/* full match */
 					ctx->found = TRUE;
 					return;
 				}
 			} else {
 				/* non-match */
-				ctx->match_count--;
-				if (i != ctx->match_count) {
-					memmove(ctx->matches + i,
-						ctx->matches + i + 1,
-						ctx->match_count - i);
-				}
+				buffer_delete(ctx->match_buf,
+					      i * sizeof(size_t),
+					      sizeof(size_t));
+				match_count--;
 			}
 		}
 
@@ -170,8 +172,10 @@
 				ctx->found = TRUE;
 				break;
 			}
-			i_assert((size_t)ctx->match_count < ctx->key_len);
-			ctx->matches[ctx->match_count++] = 1;
+
+			value = 1;
+			buffer_append(ctx->match_buf, &value, sizeof(value));
+			match_count++;
 		}
 	}
 
@@ -205,6 +209,6 @@
 
 void message_header_search_reset(HeaderSearchContext *ctx)
 {
-	ctx->match_count = 0;
+	buffer_set_used_size(ctx->match_buf, 0);
 	ctx->found = FALSE;
 }
--- a/src/lib-mail/message-size.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-mail/message-size.c	Wed Dec 18 17:15:41 2002 +0200
@@ -161,7 +161,7 @@
 	}
 }
 
-void message_size_add(MessageSize *dest, MessageSize *src)
+void message_size_add(MessageSize *dest, const MessageSize *src)
 {
 	dest->virtual_size += src->virtual_size;
 	dest->physical_size += src->physical_size;
--- a/src/lib-mail/message-size.h	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-mail/message-size.h	Wed Dec 18 17:15:41 2002 +0200
@@ -18,6 +18,6 @@
 			  MessageSize *msg_size, int *cr_skipped);
 
 /* Sum contents of src into dest. */
-void message_size_add(MessageSize *dest, MessageSize *src);
+void message_size_add(MessageSize *dest, const MessageSize *src);
 
 #endif
--- a/src/lib-mail/rfc822-tokenize.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-mail/rfc822-tokenize.c	Wed Dec 18 17:15:41 2002 +0200
@@ -23,6 +23,7 @@
 {
 	Rfc822Token *token;
 
+	/* @UNSAFE */
 	if (*pos+1 >= INITIAL_COUNT)
 		*tokens = t_buffer_reget_type(*tokens, Rfc822Token, *pos + 2);
 
@@ -180,6 +181,7 @@
 	if (tokens_count != NULL)
 		*tokens_count = pos;
 
+	/* @UNSAFE */
 	first_token[pos++].token = 0;
 	t_buffer_alloc(sizeof(Rfc822Token) * pos);
 	return first_token;
@@ -187,6 +189,7 @@
 
 const char *rfc822_tokens_get_value(const Rfc822Token *tokens, int count)
 {
+	/* @UNSAFE */
 	char *buf;
 	size_t i, len, buf_size;
 	int last_atom;
@@ -249,6 +252,7 @@
 const char *rfc822_tokens_get_value_quoted(const Rfc822Token *tokens,
 					   int count)
 {
+	/* @UNSAFE */
 	char *buf;
 	size_t len, buf_size;
 	int last_atom;
--- a/src/lib-storage/subscription-file/subscription-file.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib-storage/subscription-file/subscription-file.c	Wed Dec 18 17:15:41 2002 +0200
@@ -74,6 +74,7 @@
 	if (lseek(fd, 0, SEEK_END) < 0)
 		return subsfile_set_syscall_error(storage, "lseek()", path);
 
+	/* @UNSAFE */
 	buf = t_buffer_get(len+2);
 	buf[0] = '\n';
 	memcpy(buf+1, name, len);
--- a/src/lib/buffer.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/buffer.c	Wed Dec 18 17:15:41 2002 +0200
@@ -21,6 +21,8 @@
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
+/* @UNSAFE: whole file */
+
 #include "lib.h"
 #include "buffer.h"
 
@@ -212,6 +214,58 @@
 	return data_size;
 }
 
+size_t buffer_insert(Buffer *buf, size_t pos,
+		     const void *data, size_t data_size)
+{
+	size_t move_size, size;
+
+	move_size = buf->used - buf->start_pos;
+	i_assert(pos <= move_size);
+	move_size -= pos;
+
+	if (data_size < (size_t)-1 - move_size)
+		size = data_size + move_size;
+	else
+		size = (size_t)-1;
+
+	if (!buffer_check_write(buf, &pos, &size, TRUE))
+		return 0;
+
+	i_assert(size >= move_size);
+	size -= move_size;
+
+	memmove(buf->w_buffer + pos + size, buf->w_buffer + pos, move_size);
+	memcpy(buf->w_buffer + pos, data, size);
+	return size;
+}
+
+size_t buffer_delete(Buffer *buf, size_t pos, size_t size)
+{
+	size_t end_size;
+
+	if (buf->readonly)
+		return 0;
+
+	end_size = buf->used - buf->start_pos;
+	i_assert(pos <= end_size);
+	end_size -= pos;
+
+	if (size < end_size) {
+		/* delete from between */
+		memmove(buf->w_buffer + buf->start_pos + pos,
+			buf->w_buffer + buf->start_pos + pos + size,
+			end_size - size);
+		end_size = size;
+	} else {
+		/* delete the rest of the buffer */
+		size = end_size;
+		end_size = 0;
+	}
+
+	buffer_set_used_size(buf, pos + end_size);
+	return size;
+}
+
 size_t buffer_copy(Buffer *dest, size_t dest_pos,
 		   const Buffer *src, size_t src_pos, size_t copy_size)
 {
--- a/src/lib/buffer.h	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/buffer.h	Wed Dec 18 17:15:41 2002 +0200
@@ -29,6 +29,12 @@
 /* Append character to buffer, returns 1 if written, 0 if not. */
 size_t buffer_append_c(Buffer *buf, char chr);
 
+/* Insert data to buffer, returns number of bytes inserted. */
+size_t buffer_insert(Buffer *buf, size_t pos,
+		     const void *data, size_t data_size);
+/* Delete data from buffer, returns number of bytes deleted. */
+size_t buffer_delete(Buffer *buf, size_t pos, size_t size);
+
 /* Copy data from buffer to another. The buffers may be same in which case
    it's internal copying, possibly with overlapping positions (ie. memmove()
    like functionality). copy_size may be set to (size_t)-1 to copy the rest of
--- a/src/lib/compat.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/compat.c	Wed Dec 18 17:15:41 2002 +0200
@@ -34,34 +34,6 @@
 #  define INADDR_NONE INADDR_BROADCAST
 #endif
 
-#ifndef HAVE_MEMMOVE
-void *my_memmove(void *dest, const void *src, size_t size)
-{
-	char *destp = dest;
-        const char *srcp = src;
-
-	if (destp < srcp) {
-		/* dest = 1234, src=234 */
-		destp = dest;
-                srcp = src;
-		while (size > 0) {
-			*destp++ = *srcp++;
-                        size--;
-		}
-	} else if (destp > srcp) {
-		/* dest = 234, src=123 */
-		destp += size-1;
-                srcp += size-1;
-		while (size > 0) {
-			*destp-- = *srcp--;
-                        size--;
-		}
-	}
-
-        return dest;
-}
-#endif
-
 #if !defined (HAVE_STRCASECMP) && !defined (HAVE_STRICMP)
 int my_strcasecmp(const char *s1, const char *s2)
 {
--- a/src/lib/compat.h	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/compat.h	Wed Dec 18 17:15:41 2002 +0200
@@ -38,12 +38,6 @@
 #  error I do not know how to compare dev_t
 #endif
 
-/* memmove() */
-#ifndef HAVE_MEMMOVE
-#  define memmove my_memmove
-void *my_memmove(void *dest, const void *src, size_t n);
-#endif
-
 /* strcasecmp(), strncasecmp() */
 #ifndef HAVE_STRCASECMP
 #  ifdef HAVE_STRICMP
--- a/src/lib/data-stack.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/data-stack.c	Wed Dec 18 17:15:41 2002 +0200
@@ -23,6 +23,8 @@
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
+/* @UNSAFE: whole file */
+
 #include "lib.h"
 #include "data-stack.h"
 
--- a/src/lib/hex-binary.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/hex-binary.c	Wed Dec 18 17:15:41 2002 +0200
@@ -33,6 +33,8 @@
 	size_t i;
 	int value;
 
+	/* @UNSAFE */
+
 	buf = p = t_malloc(size * 2 + 1);
 	for (i = 0; i < size; i++) {
 		value = data[i] >> 4;
--- a/src/lib/ioloop-poll.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/ioloop-poll.c	Wed Dec 18 17:15:41 2002 +0200
@@ -23,6 +23,8 @@
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
+/* @UNSAFE: whole file */
+
 #include "lib.h"
 #include "ioloop-internal.h"
 
--- a/src/lib/istream-file.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/istream-file.c	Wed Dec 18 17:15:41 2002 +0200
@@ -23,6 +23,8 @@
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
+/* @UNSAFE: whole file */
+
 #include "lib.h"
 #include "alarm-hup.h"
 #include "istream-internal.h"
--- a/src/lib/istream.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/istream.c	Wed Dec 18 17:15:41 2002 +0200
@@ -167,6 +167,7 @@
 		return NULL;
 	}
 
+	/* @UNSAFE */
 	ret_buf = NULL;
 	for (i = _stream->cr_lookup_pos; i < _stream->pos; i++) {
 		if (_stream->buffer[i] == 10) {
--- a/src/lib/md5.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/md5.c	Wed Dec 18 17:15:41 2002 +0200
@@ -186,6 +186,7 @@
 
 void md5_update(MD5Context *ctx, const void *data, size_t size)
 {
+	/* @UNSAFE */
 	MD5_u32plus saved_lo;
 	unsigned long used, free;
 
@@ -220,6 +221,7 @@
 
 void md5_final(MD5Context *ctx, unsigned char result[16])
 {
+	/* @UNSAFE */
 	unsigned long used, free;
 
 	used = ctx->lo & 0x3f;
--- a/src/lib/mempool-alloconly.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/mempool-alloconly.c	Wed Dec 18 17:15:41 2002 +0200
@@ -24,6 +24,8 @@
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
+/* @UNSAFE: whole file */
+
 #include "lib.h"
 #include "mempool.h"
 
--- a/src/lib/mempool-datastack.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/mempool-datastack.c	Wed Dec 18 17:15:41 2002 +0200
@@ -95,6 +95,7 @@
 static void *pool_data_stack_realloc_min(Pool pool __attr_unused__,
 					 void *mem, size_t size)
 {
+	/* @UNSAFE */
 	PoolAlloc *alloc, *new_alloc;
         size_t old_size;
 	unsigned char *rmem;
--- a/src/lib/mempool-system.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/mempool-system.c	Wed Dec 18 17:15:41 2002 +0200
@@ -23,6 +23,8 @@
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
+/* @UNSAFE: whole file */
+
 #include "lib.h"
 #include "mempool.h"
 
--- a/src/lib/mmap-anon.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/mmap-anon.c	Wed Dec 18 17:15:41 2002 +0200
@@ -21,6 +21,8 @@
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
+/* @UNSAFE: whole file */
+
 #include "lib.h"
 #include "mmap-util.h"
 
--- a/src/lib/network.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/network.c	Wed Dec 18 17:15:41 2002 +0200
@@ -120,7 +120,7 @@
 static inline void close_save_errno(int fd)
 {
 	int old_errno = errno;
-	close(fd);
+	(void)close(fd);
 	errno = old_errno;
 }
 
@@ -420,6 +420,7 @@
    to be free'd. Returns 0 = ok, others = error code for net_gethosterror() */
 int net_gethostbyname(const char *addr, IPADDR **ips, int *ips_count)
 {
+	/* @UNSAFE */
 #ifdef HAVE_IPV6
 	union sockaddr_union *so;
 	struct addrinfo hints, *ai, *origai;
@@ -508,25 +509,28 @@
 	return 0;
 }
 
-int net_ip2host(const IPADDR *ip, char *host)
+const char *net_ip2host(const IPADDR *ip)
 {
 #ifdef HAVE_IPV6
-	if (!inet_ntop(ip->family, &ip->ip, host, MAX_IP_LEN))
-		return -1;
+	char host[MAX_IP_LEN+1];
+
+	host[MAX_IP_LEN] = '\0';
+	if (inet_ntop(ip->family, &ip->ip, host, MAX_IP_LEN) == NULL)
+		return NULL;
+
+	return t_strdup(host);
 #else
 	unsigned long ip4;
 
-	if (ip->family != AF_INET) {
-		strcpy(host, "0.0.0.0");
-		return -1;
-	}
+	if (ip->family != AF_INET)
+		return NULL;
 
 	ip4 = ntohl(ip->ip.s_addr);
-	i_snprintf(host, MAX_IP_LEN, "%lu.%lu.%lu.%lu",
-		   (ip4 & 0xff000000UL) >> 24,
-		   (ip4 & 0x00ff0000) >> 16,
-		   (ip4 & 0x0000ff00) >> 8,
-		   (ip4 & 0x000000ff));
+	return t_strdup_printf("%lu.%lu.%lu.%lu",
+			       (ip4 & 0xff000000UL) >> 24,
+			       (ip4 & 0x00ff0000) >> 16,
+			       (ip4 & 0x0000ff00) >> 8,
+			       (ip4 & 0x000000ff));
 #endif
 	return 0;
 }
--- a/src/lib/network.h	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/network.h	Wed Dec 18 17:15:41 2002 +0200
@@ -89,8 +89,8 @@
 /* Get socket address/port */
 int net_getsockname(int fd, IPADDR *addr, unsigned int *port);
 
-/* IPADDR -> char* translation. `host' must be at least MAX_IP_LEN bytes */
-int net_ip2host(const IPADDR *ip, char *host);
+/* Returns IPADDR as string, or NULL if ip is invalid. */
+const char *net_ip2host(const IPADDR *ip);
 /* char* -> IPADDR translation. */
 int net_host2ip(const char *host, IPADDR *ip);
 
--- a/src/lib/ostream-file.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/ostream-file.c	Wed Dec 18 17:15:41 2002 +0200
@@ -23,6 +23,8 @@
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
+/* @UNSAFE: whole file */
+
 #include "lib.h"
 #include "alarm-hup.h"
 #include "ioloop.h"
--- a/src/lib/randgen.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/randgen.c	Wed Dec 18 17:15:41 2002 +0200
@@ -56,8 +56,8 @@
 	urandom_fd = open("/dev/urandom", O_RDONLY);
 	if (urandom_fd == -1) {
 		if (errno == ENOENT) {
-			i_fatal("/dev/urandom doesn't exist, currently we "
-				"require it");
+			i_fatal("/dev/urandom doesn't exist, "
+				"currently we require it");
 		} else {
 			i_fatal("Can't open /dev/urandom: %m");
 		}
--- a/src/lib/strfuncs.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/strfuncs.c	Wed Dec 18 17:15:41 2002 +0200
@@ -24,6 +24,8 @@
     Boston, MA 02111-1307, USA.
 */
 
+/* @UNSAFE: whole file */
+
 #include "lib.h"
 #include "strfuncs.h"
 
--- a/src/lib/temp-string.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/temp-string.c	Wed Dec 18 17:15:41 2002 +0200
@@ -23,6 +23,8 @@
     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
+/* @UNSAFE: whole file */
+
 #include "lib.h"
 #include "temp-string.h"
 
--- a/src/lib/unlink-directory.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/lib/unlink-directory.c	Wed Dec 18 17:15:41 2002 +0200
@@ -51,15 +51,17 @@
 
 		i_snprintf(path, sizeof(path), "%s/%s", dir, d->d_name);
 
-		if (unlink(path) == -1) {
+		if (unlink(path) == -1 && errno != ENOENT) {
+			int old_errno = errno;
+
 			if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
 				if (!unlink_directory(path))
 					return FALSE;
 			} else {
 				/* so it wasn't a directory, unlink() again
 				   to get correct errno */
-				if (unlink(path) == -1)
-					return FALSE;
+				errno = old_errno;
+				return FALSE;
 			}
 		}
 	}
--- a/src/login/auth-connection.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/login/auth-connection.c	Wed Dec 18 17:15:41 2002 +0200
@@ -119,7 +119,8 @@
 	hash_foreach(conn->requests, request_hash_destroy, NULL);
 	hash_destroy(conn->requests);
 
-	(void)close(conn->fd);
+	if (close(conn->fd) < 0)
+		i_error("close(imap-auth) failed: %m");
 	io_remove(conn->io);
 	i_stream_unref(conn->input);
 	o_stream_unref(conn->output);
--- a/src/login/client-authenticate.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/login/client-authenticate.c	Wed Dec 18 17:15:41 2002 +0200
@@ -251,8 +251,6 @@
 		return;
 	}
 
-	t_push();
-
 	linelen = strlen(line);
 	buf = buffer_create_static_hard(data_stack_pool, linelen);
 
@@ -272,8 +270,6 @@
 
 	bufsize = buffer_get_used_size(buf);
 	safe_memset(buffer_free_without_data(buf), 0, bufsize);
-
-	t_pop();
 }
 
 int cmd_authenticate(Client *client, const char *method_name)
--- a/src/login/client.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/login/client.c	Wed Dec 18 17:15:41 2002 +0200
@@ -27,13 +27,14 @@
 
 static void client_set_title(Client *client)
 {
-	char host[MAX_IP_LEN];
+	const char *host;
 
 	if (!verbose_proctitle || !process_per_connection)
 		return;
 
-	if (net_ip2host(&client->ip, host) < 0)
-		strcpy(host, "??");
+	host = net_ip2host(&client->ip);
+	if (host == NULL)
+		host = "??";
 
 	process_title_set(t_strdup_printf(client->tls ? "[%s TLS]" : "[%s]",
 					  host));
@@ -133,36 +134,39 @@
 	}
 }
 
-static char *get_next_arg(char **line)
+static char *get_next_arg(char **linep)
 {
-	char *start;
+	char *line, *start;
 	int quoted;
 
-	while (**line == ' ') (*line)++;
-
-	if (**line == '"') {
-		quoted = TRUE;
-		(*line)++;
+	line = *linep;
+	while (*line == ' ') line++;
 
-		start = *line;
-		while (**line != '\0' && **line != '"') {
-			if (**line == '\\' && (*line)[1] != '\0')
-				(*line)++;
-			(*line)++;
+	/* @UNSAFE: get next argument, unescape arg if it's quoted */
+	if (*line == '"') {
+		quoted = TRUE;
+		line++;
+
+		start = line;
+		while (*line != '\0' && *line != '"') {
+			if (*line == '\\' && line[1] != '\0')
+				line++;
+			line++;
 		}
 
-		if (**line == '"')
-			*(*line)++ = '\0';
+		if (*line == '"')
+			*line++ = '\0';
 		string_remove_escapes(start);
 	} else {
-		start = *line;
-		while (**line != '\0' && **line != ' ')
-			(*line)++;
+		start = line;
+		while (*line != '\0' && *line != ' ')
+			line++;
 
-		if (**line == ' ')
-			*(*line)++ = '\0';
+		if (*line == ' ')
+			*line++ = '\0';
 	}
 
+	*linep = line;
 	return start;
 }
 
@@ -237,16 +241,17 @@
 				       void *context)
 {
 	Client *client = key;
-	Client **destroy_clients = context;
-	int i;
+	Buffer *destroy_buf = context;
+	Client *const *destroy_clients;
+	size_t i, count;
 
-	for (i = 0; i < CLIENT_DESTROY_OLDEST_COUNT; i++) {
-		if (destroy_clients[i] == NULL ||
-		    destroy_clients[i]->created > client->created) {
-			memmove(destroy_clients+i+1, destroy_clients+i,
-				sizeof(Client *) *
-				(CLIENT_DESTROY_OLDEST_COUNT - i-1));
-			destroy_clients[i] = client;
+	destroy_clients = buffer_get_data(destroy_buf, &count);
+	count /= sizeof(Client *);
+
+	for (i = 0; i < count; i++) {
+		if (destroy_clients[i]->created > client->created) {
+			buffer_insert(destroy_buf, i * sizeof(Client *),
+				      &client, sizeof(client));
 			break;
 		}
 	}
@@ -254,13 +259,21 @@
 
 static void client_destroy_oldest(void)
 {
-	Client *destroy_clients[CLIENT_DESTROY_OLDEST_COUNT];
-	int i;
+	Buffer *destroy_buf;
+	Client *const *destroy_clients;
+	size_t i, count;
 
-	memset(destroy_clients, 0, sizeof(destroy_clients));
-	hash_foreach(clients, client_hash_destroy_oldest, destroy_clients);
+	/* find the oldest clients and put them to destroy-buffer */
+	destroy_buf = buffer_create_static_hard(data_stack_pool,
+						sizeof(Client *) *
+						CLIENT_DESTROY_OLDEST_COUNT);
+	hash_foreach(clients, client_hash_destroy_oldest, destroy_buf);
 
-	for (i = 0; i < CLIENT_DESTROY_OLDEST_COUNT; i++) {
+	/* then kill them */
+	destroy_clients = buffer_get_data(destroy_buf, &count);
+	count /= sizeof(Client *);
+
+	for (i = 0; i < count; i++) {
 		client_destroy(destroy_clients[i],
 			       "Disconnected: Connection queue full");
 	}
@@ -357,10 +370,11 @@
 
 void client_syslog(Client *client, const char *text)
 {
-	char host[MAX_IP_LEN];
+	const char *host;
 
-	if (net_ip2host(&client->ip, host) == -1)
-		host[0] = '\0';
+	host = net_ip2host(&client->ip);
+	if (host == NULL)
+		host = "??";
 
 	syslog(LOG_INFO, "%s [%s]", text, host);
 }
--- a/src/login/master.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/login/master.c	Wed Dec 18 17:15:41 2002 +0200
@@ -111,7 +111,8 @@
 
 	clients_destroy_all();
 
-	(void)close(LOGIN_MASTER_SOCKET_FD);
+	if (close(LOGIN_MASTER_SOCKET_FD) < 0)
+		i_fatal("close(master) failed: %m");
 
 	io_remove(io_master);
 	io_master = NULL;
--- a/src/login/ssl-proxy-gnutls.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/login/ssl-proxy-gnutls.c	Wed Dec 18 17:15:41 2002 +0200
@@ -448,17 +448,11 @@
 static void gcrypt_log_handler(void *context __attr_unused__, int level,
 			       const char *fmt, va_list args)
 {
-	char *buf;
-
-	t_push();
-
-	buf = t_malloc(printf_string_upper_bound(fmt, args));
-	vsprintf(buf, fmt, args);
-
-	if (level == GCRY_LOG_FATAL)
-		i_error("gcrypt fatal: %s", buf);
-
-	t_pop();
+	if (level == GCRY_LOG_FATAL) {
+		t_push();
+		i_error("gcrypt fatal: %s", t_strdup_vprintf(fmt, args));
+		t_pop();
+	}
 }
 
 void ssl_proxy_init(void)
--- a/src/login/ssl-proxy-openssl.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/login/ssl-proxy-openssl.c	Wed Dec 18 17:15:41 2002 +0200
@@ -135,14 +135,15 @@
 {
 	unsigned long err;
 	char *buf;
+	size_t err_size = 256;
 
 	err = ERR_get_error();
 	if (err == 0)
 		return strerror(errno);
 
-	buf = t_malloc(256);
-	buf[255] = '\0';
-	ERR_error_string_n(err, buf, 255);
+	buf = t_malloc(err_size);
+	buf[err_size-1] = '\0';
+	ERR_error_string_n(err, buf, err_size-1);
 	return buf;
 }
 
--- a/src/master/auth-process.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/master/auth-process.c	Wed Dec 18 17:15:41 2002 +0200
@@ -163,7 +163,8 @@
 
 	o_stream_unref(p->output);
 	io_remove(p->io);
-	(void)close(p->fd);
+	if (close(p->fd) < 0)
+		i_error("close(auth) failed: %m");
 	i_free(p->name);
 	i_free(p);
 }
@@ -205,6 +206,7 @@
 	path = t_strconcat(set_login_dir, "/", config->name, NULL);
 	(void)unlink(path);
         (void)umask(0177); /* we want 0600 mode for the socket */
+
 	listen_fd = net_listen_unix(path);
 	if (listen_fd < 0)
 		i_fatal("Can't listen in UNIX socket %s: %m", path);
@@ -212,11 +214,14 @@
 	i_assert(listen_fd > 2);
 
 	/* set correct permissions */
-	(void)chown(path, set_login_uid, set_login_gid);
+	if (chown(path, set_login_uid, set_login_gid) < 0) {
+		i_fatal("login: chown(%s, %d, %d) failed: %m",
+			path, (int)set_login_uid, (int)set_login_gid);
+	}
 
 	/* move master communication handle to 0 */
 	if (dup2(fd[1], 0) < 0)
-		i_fatal("login: dup2() failed: %m");
+		i_fatal("login: dup2(0) failed: %m");
 
 	(void)close(fd[0]);
 	(void)close(fd[1]);
@@ -224,9 +229,9 @@
 	/* set /dev/null handle into 1 and 2, so if something is printed into
 	   stdout/stderr it can't go anywhere where it could cause harm */
 	if (dup2(null_fd, 1) < 0)
-		i_fatal("login: dup2() failed: %m");
+		i_fatal("login: dup2(1) failed: %m");
 	if (dup2(null_fd, 2) < 0)
-		i_fatal("login: dup2() failed: %m");
+		i_fatal("login: dup2(2) failed: %m");
 
 	clean_child_process();
 
--- a/src/master/imap-process.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/master/imap-process.c	Wed Dec 18 17:15:41 2002 +0200
@@ -109,9 +109,10 @@
 				      const char *login_tag)
 {
 	static char *argv[] = { NULL, NULL, NULL };
-	char host[MAX_IP_LEN], title[1024];
+	const char *host;
+	char title[1024];
 	pid_t pid;
-	int i, j, err;
+	int i, err;
 
 	if (imap_process_count == set_max_imap_processes) {
 		i_error("Maximum number of imap processes exceeded");
@@ -134,7 +135,8 @@
 		/* master */
 		imap_process_count++;
 		PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_IMAP);
-		(void)close(socket);
+		if (close(socket) < 0)
+			i_error("close(imap client) failed: %m");
 		return MASTER_RESULT_SUCCESS;
 	}
 
@@ -142,15 +144,12 @@
 
 	/* move the imap socket into stdin, stdout and stderr fds */
 	for (i = 0; i < 3; i++) {
-		if (dup2(socket, i) < 0) {
-			err = errno;
-			for (j = 0; j < i; j++)
-				(void)close(j);
-			(void)close(socket);
-			i_fatal("imap: dup2() failed: %m");
-		}
+		if (dup2(socket, i) < 0)
+			i_fatal("imap: dup2(%d) failed: %m", i);
 	}
-	(void)close(socket);
+
+	if (close(socket) < 0)
+		i_error("imap: close(imap client) failed: %m");
 
 	/* setup environment - set the most important environment first
 	   (paranoia about filling up environment without noticing) */
@@ -197,7 +196,11 @@
 	env_put(t_strconcat("USER=", virtual_user, NULL));
 	env_put(t_strconcat("LOGIN_TAG=", login_tag, NULL));
 
-	if (set_verbose_proctitle && net_ip2host(ip, host) == 0) {
+	if (set_verbose_proctitle) {
+		host = net_ip2host(ip);
+		if (host == NULL)
+			host = "??";
+
 		i_snprintf(title, sizeof(title), "[%s %s]", virtual_user, host);
 		argv[1] = title;
 	}
--- a/src/master/login-process.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/master/login-process.c	Wed Dec 18 17:15:41 2002 +0200
@@ -79,7 +79,8 @@
 	if (o_stream_send(process->output, &reply, sizeof(reply)) < 0)
 		login_process_destroy(process);
 
-	(void)close(request->fd);
+	if (close(request->fd) < 0)
+		i_error("close(imap client) failed: %m");
 	login_process_unref(process);
 	i_free(request);
 }
@@ -212,7 +213,8 @@
 
 	o_stream_close(p->output);
 	io_remove(p->io);
-	(void)close(p->fd);
+	if (close(p->fd) < 0)
+		i_error("close(login) failed: %m");
 
 	if (!p->listening)
 		login_process_remove_from_lists(p);
@@ -270,17 +272,17 @@
 
 	/* move communication handle */
 	if (dup2(fd[1], LOGIN_MASTER_SOCKET_FD) < 0)
-		i_fatal("login: dup2() failed: %m");
+		i_fatal("login: dup2(master) failed: %m");
 	fd_close_on_exec(LOGIN_MASTER_SOCKET_FD, FALSE);
 
 	/* move the listen handle */
 	if (dup2(imap_fd, LOGIN_IMAP_LISTEN_FD) < 0)
-		i_fatal("login: dup2() failed: %m");
+		i_fatal("login: dup2(imap) failed: %m");
 	fd_close_on_exec(LOGIN_IMAP_LISTEN_FD, FALSE);
 
 	/* move the SSL listen handle */
 	if (dup2(imaps_fd, LOGIN_IMAPS_LISTEN_FD) < 0)
-		i_fatal("login: dup2() failed: %m");
+		i_fatal("login: dup2(imaps) failed: %m");
 	fd_close_on_exec(LOGIN_IMAPS_LISTEN_FD, FALSE);
 
 	/* imap_fd and imaps_fd are closed by clean_child_process() */
@@ -297,10 +299,8 @@
 
 	if (!set_login_chroot) {
 		/* no chrooting, but still change to the directory */
-		if (chdir(set_login_dir) < 0) {
-			i_fatal("chdir(%s) failed: %m",
-				set_login_dir);
-		}
+		if (chdir(set_login_dir) < 0)
+			i_fatal("chdir(%s) failed: %m", set_login_dir);
 	}
 
 	if (!set_ssl_disable) {
--- a/src/master/main.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/master/main.c	Wed Dec 18 17:15:41 2002 +0200
@@ -164,9 +164,12 @@
 		return ip;
 	}
 
+	/* Return the first IP if there happens to be multiple. */
 	ret = net_gethostbyname(name, &ip, &ips_count);
-	if (ret != 0)
-		i_fatal("Can't resolve address: %s", name);
+	if (ret != 0) {
+		i_fatal("Can't resolve address %s: %s",
+			name, net_gethosterror(ret));
+	}
 
 	if (ips_count < 1)
 		i_fatal("No IPs for address: %s", name);
@@ -245,9 +248,12 @@
 
 	timeout_remove(to);
 
-	(void)close(null_fd);
-	(void)close(imap_fd);
-	(void)close(imaps_fd);
+	if (close(null_fd) < 0)
+		i_error("close(null_fd) failed: %m");
+	if (close(imap_fd) < 0)
+		i_error("close(imap_fd) failed: %m");
+	if (close(imaps_fd) < 0)
+		i_error("close(imaps_fd) failed: %m");
 
 	hash_destroy(pids);
 	closelog();
--- a/src/master/settings.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/master/settings.c	Wed Dec 18 17:15:41 2002 +0200
@@ -457,6 +457,8 @@
 		}
 		linenum++;
 
+		/* @UNSAFE: line is modified */
+
 		/* skip whitespace */
 		while (IS_WHITE(*line))
 			line++;
--- a/src/master/ssl-init.c	Wed Dec 18 12:40:43 2002 +0200
+++ b/src/master/ssl-init.c	Wed Dec 18 17:15:41 2002 +0200
@@ -32,7 +32,7 @@
 	_ssl_generate_parameters(fd, temp_fname);
 
 	if (close(fd) < 0)
-		i_fatal("close() failed for %s: %m", temp_fname);
+		i_fatal("close(%s) failed: %m", temp_fname);
 
 	if (rename(temp_fname, fname) < 0)
 		i_fatal("rename(%s, %s) failed: %m", temp_fname, fname);