コード例 #1
0
int cmd_login(struct imap_client *imap_client, const struct imap_arg *args)
{
	struct client *client = &imap_client->common;
	const char *user, *pass;
	string_t *plain_login, *base64;

	/* two arguments: username and password */
	if (!imap_arg_get_astring(&args[0], &user) ||
	    !imap_arg_get_astring(&args[1], &pass) ||
	    !IMAP_ARG_IS_EOL(&args[2]))
		return -1;

	if (!client_check_plaintext_auth(client, TRUE))
		return 1;

	/* authorization ID \0 authentication ID \0 pass */
	plain_login = buffer_create_dynamic(pool_datastack_create(), 64);
	buffer_append_c(plain_login, '\0');
	buffer_append(plain_login, user, strlen(user));
	buffer_append_c(plain_login, '\0');
	buffer_append(plain_login, pass, strlen(pass));

	base64 = buffer_create_dynamic(pool_datastack_create(),
        			MAX_BASE64_ENCODED_SIZE(plain_login->used));
	base64_encode(plain_login->data, plain_login->used, base64);
	return imap_client_auth_begin(imap_client, "PLAIN", str_c(base64));
}
コード例 #2
0
ファイル: password-scheme-rpa.c プロジェクト: manuelm/dovecot
/*
 * Convert string to big-endian ucs2.
 */
void *ucs2be_str(pool_t pool, const char *str, size_t *size)
{
	buffer_t *buf = buffer_create_dynamic(pool, 32);

	while (*str != '\0') {
		buffer_append_c(buf, '\0');
		buffer_append_c(buf, *str++);
	}

	*size = buf->used;
	return buffer_free_without_data(&buf);
}
コード例 #3
0
void checkpassword_child_output(struct chkpw_auth_request *request)
{
	/* Send: username \0 password \0 timestamp \0.
	   Must be 512 bytes or less. The "timestamp" parameter is actually
	   useful only for APOP authentication. We don't support it, so
	   keep it empty */
	struct auth_request *auth_request = request->request;
	buffer_t *buf;
	const unsigned char *data;
	size_t size;
	ssize_t ret;

	buf = buffer_create_dynamic(pool_datastack_create(), 512+1);
	buffer_append(buf, auth_request->user, strlen(auth_request->user)+1);
        if (request->password != NULL)
                buffer_append(buf, request->password, strlen(request->password)+1);
        else
                buffer_append_c(buf, '\0');
	buffer_append_c(buf, '\0');
	data = buffer_get_data(buf, &size);

	if (size > 512) {
		auth_request_log_error(request->request, "checkpassword",
			"output larger than 512 bytes: %"PRIuSIZE_T, size);
		request->finish_callback(request,
					 request->internal_failure_code);
		return;
	}

	ret = write(request->fd_out, data + request->write_pos,
		    size - request->write_pos);
	if (ret <= 0) {
		if (ret < 0) {
			auth_request_log_error(request->request,
				"checkpassword", "write() failed: %m");
		}
		request->finish_callback(request,
					 request->internal_failure_code);
		return;
	}

	request->write_pos += ret;
	if (request->write_pos < size)
		return;

	io_remove(&request->io_out);

	if (close(request->fd_out) < 0)
		i_error("checkpassword: close() failed: %m");
	request->fd_out = -1;
}
コード例 #4
0
ファイル: ntlm-encrypt.c プロジェクト: via/dovecot-clouddb
static unsigned char *
t_unicode_str(const char *src, bool ucase, size_t *size)
{
    buffer_t *wstr;

    wstr = buffer_create_dynamic(unsafe_data_stack_pool, 32);
    for ( ; *src; src++) {
        buffer_append_c(wstr, ucase ? i_toupper(*src) : *src);
        buffer_append_c(wstr, '\0');
    }

    *size = buffer_get_used_size(wstr);
    return buffer_free_without_data(&wstr);
}
コード例 #5
0
ファイル: test-buffer.c プロジェクト: bdraco/core
static void test_foo(void)
{
	buffer_t *buf = buffer_create_dynamic(default_pool, 100);

	for (int i = 1; i <= 24; i++) {
		buffer_set_used_size(buf, 0);
		buffer_append_c(buf, 0xff);
		buffer_append_c(buf, 0xff);
		buffer_append_c(buf, 0xff);
		buffer_truncate_rshift_bits(buf, i);
		printf("%2d bits: %24s %s\n", i,
		       binary_to_hex(buf->data, buf->used),
		       binary_to_10(buf->data, buf->used));
	}
}
コード例 #6
0
static void put_uint32(buffer_t *output, uint32_t num)
{
	buffer_append_c(output, num & 0xff);
	buffer_append_c(output, (num >> 8) & 0xff);
	buffer_append_c(output, (num >> 16) & 0xff);
	buffer_append_c(output, (num >> 24) & 0xff);
}
コード例 #7
0
const char *client_get_session_id(struct client *client)
{
	buffer_t *buf, *base64_buf;
	struct timeval tv;
	uint64_t timestamp;
	unsigned int i;

	if (client->session_id != NULL)
		return client->session_id;

	buf = buffer_create_dynamic(pool_datastack_create(), 24);
	base64_buf = buffer_create_dynamic(pool_datastack_create(), 24*2);

	if (gettimeofday(&tv, NULL) < 0)
		i_fatal("gettimeofday(): %m");
	timestamp = tv.tv_usec + (long long)tv.tv_sec * 1000ULL*1000ULL;

	/* add lowest 48 bits of the timestamp. this gives us a bit less than
	   9 years until it wraps */
	for (i = 0; i < 48; i += 8)
		buffer_append_c(buf, (timestamp >> i) & 0xff);

	buffer_append_c(buf, client->remote_port & 0xff);
	buffer_append_c(buf, (client->remote_port >> 16) & 0xff);
#ifdef HAVE_IPV6
	if (IPADDR_IS_V6(&client->ip))
		buffer_append(buf, &client->ip.u.ip6, sizeof(client->ip.u.ip6));
	else
#endif
		buffer_append(buf, &client->ip.u.ip4, sizeof(client->ip.u.ip4));
	base64_encode(buf->data, buf->used, base64_buf);
	client->session_id = p_strdup(client->pool, str_c(base64_buf));
	return client->session_id;
}
コード例 #8
0
ファイル: imap-base-subject.c プロジェクト: Raffprta/core
static bool remove_subj_fwd_hdr(buffer_t *buf, size_t *start_pos,
				bool *is_reply_or_forward_r)
{
	const char *data;
	size_t size;

	/* subj-fwd        = subj-fwd-hdr subject subj-fwd-trl
	   subj-fwd-hdr    = "[fwd:"
	   subj-fwd-trl    = "]" */
	data = buffer_get_data(buf, &size);

	if (strncmp(data + *start_pos, "[FWD:", 5) != 0)
		return FALSE;

	if (data[size-2] != ']')
		return FALSE;

	*is_reply_or_forward_r = TRUE;

	buffer_set_used_size(buf, size-2);
	buffer_append_c(buf, '\0');

	*start_pos += 5;
	return TRUE;
}
コード例 #9
0
ファイル: hex-binary.c プロジェクト: aosm/dovecot
int hex_to_binary(const char *data, buffer_t *dest)
{
	int value;

	while (*data != '\0') {
		if (*data >= '0' && *data <= '9')
			value = (*data - '0') << 4;
		else if (*data >= 'a' && *data <= 'f')
			value = (*data - 'a' + 10) << 4;
		else if (*data >= 'A' && *data <= 'F')
			value = (*data - 'A' + 10) << 4;
		else
			return -1;

		data++;
		if (*data >= '0' && *data <= '9')
			value |= *data - '0';
		else if (*data >= 'a' && *data <= 'f')
			value |= *data - 'a' + 10;
		else if (*data >= 'A' && *data <= 'F')
			value |= *data - 'A' + 10;
		else
			return -1;

		buffer_append_c(dest, value);
		data++;
	}

	return 0;
}
コード例 #10
0
ファイル: imap-base-subject.c プロジェクト: Raffprta/core
static void remove_subj_trailers(buffer_t *buf, size_t start_pos,
				 bool *is_reply_or_forward_r)
{
	const char *data;
	size_t orig_size, size;

	/* subj-trailer    = "(fwd)" / WSP */
	data = buffer_get_data(buf, &orig_size);

	if (orig_size < 1) /* size includes trailing \0 */
		return;

	for (size = orig_size-1; size > start_pos; ) {
		if (data[size-1] == ' ')
			size--;
		else if (size >= 5 &&
			 memcmp(data + size - 5, "(FWD)", 5) == 0) {
			*is_reply_or_forward_r = TRUE;
			size -= 5;
		} else {
			break;
		}
	}

	if (size != orig_size-1) {
		buffer_set_used_size(buf, size);
		buffer_append_c(buf, '\0');
	}
}
コード例 #11
0
ファイル: message-decoder.c プロジェクト: IvanKharpalev/core
static bool message_decode_header(struct message_decoder_context *ctx,
				  struct message_header_line *hdr,
				  struct message_block *output)
{
	size_t value_len;

	if (hdr->continues) {
		hdr->use_full_value = TRUE;
		return FALSE;
	}

	T_BEGIN {
		if (hdr->name_len == 12 &&
		    strcasecmp(hdr->name, "Content-Type") == 0)
			parse_content_type(ctx, hdr);
		if (hdr->name_len == 25 &&
		    strcasecmp(hdr->name, "Content-Transfer-Encoding") == 0)
			ctx->message_cte = message_decoder_parse_cte(hdr);
	} T_END;

	buffer_set_used_size(ctx->buf, 0);
	message_header_decode_utf8(hdr->full_value, hdr->full_value_len,
				   ctx->buf, ctx->normalizer);
	value_len = ctx->buf->used;

	if (ctx->normalizer != NULL) {
		(void)ctx->normalizer(hdr->name, hdr->name_len, ctx->buf);
		buffer_append_c(ctx->buf, '\0');
	} else {
		if (!uni_utf8_get_valid_data((const unsigned char *)hdr->name,
					     hdr->name_len, ctx->buf))
			buffer_append_c(ctx->buf, '\0');
	}

	ctx->hdr = *hdr;
	ctx->hdr.full_value = ctx->buf->data;
	ctx->hdr.full_value_len = value_len;
	ctx->hdr.value_len = 0;
	if (ctx->buf->used != value_len) {
		ctx->hdr.name = CONST_PTR_OFFSET(ctx->buf->data,
						 ctx->hdr.full_value_len);
		ctx->hdr.name_len = ctx->buf->used - 1 - value_len;
	}

	output->hdr = &ctx->hdr;
	return TRUE;
}
コード例 #12
0
ファイル: askpass.c プロジェクト: Raffprta/core
void askpass(const char *prompt, char *buf, size_t buf_size)
{
	buffer_t str;

	buffer_create_from_data(&str, buf, buf_size);
	askpass_str(prompt, &str);
	buffer_append_c(&str, '\0');
}
コード例 #13
0
ファイル: mech-digest-md5.c プロジェクト: bsmr-dovecot/core
static string_t *get_digest_challenge(struct digest_auth_request *request)
{
	const struct auth_settings *set = request->auth_request.set;
	buffer_t buf;
	string_t *str;
	const char *const *tmp;
	unsigned char nonce[16];
	unsigned char nonce_base64[MAX_BASE64_ENCODED_SIZE(sizeof(nonce))+1];
	int i;
	bool first_qop;

	/*
	   realm="hostname" (multiple allowed)
	   nonce="randomized data, at least 64bit"
	   qop="auth,auth-int,auth-conf"
	   maxbuf=number (with auth-int, auth-conf, defaults to 64k)
	   charset="utf-8" (iso-8859-1 if it doesn't exist)
	   algorithm="md5-sess"
	   cipher="3des,des,rc4-40,rc4,rc4-56" (with auth-conf)
	*/

	/* get 128bit of random data as nonce */
	random_fill(nonce, sizeof(nonce));

	buffer_create_from_data(&buf, nonce_base64, sizeof(nonce_base64));
	base64_encode(nonce, sizeof(nonce), &buf);
	buffer_append_c(&buf, '\0');
	request->nonce = p_strdup(request->pool, buf.data);

	str = t_str_new(256);
	if (*set->realms_arr == NULL) {
		/* If no realms are given, at least Cyrus SASL client defaults
		   to destination host name */
		str_append(str, "realm=\"\",");
	} else {
		for (tmp = set->realms_arr; *tmp != NULL; tmp++)
			str_printfa(str, "realm=\"%s\",", *tmp);
	}

	str_printfa(str, "nonce=\"%s\",", request->nonce);

	str_append(str, "qop=\""); first_qop = TRUE;
	for (i = 0; i < QOP_COUNT; i++) {
		if (request->qop & (1 << i)) {
			if (first_qop)
				first_qop = FALSE;
			else
				str_append_c(str, ',');
			str_append(str, qop_names[i]);
		}
	}
	str_append(str, "\",");

	str_append(str, "charset=\"utf-8\","
		   "algorithm=\"md5-sess\"");
	return str;
}
コード例 #14
0
const char *imap_get_base_subject_cased(pool_t pool, const char *subject,
					bool *is_reply_or_forward_r)
{
	buffer_t *buf;
	size_t start_pos, subject_len;
	bool found;

	if (is_reply_or_forward_r != NULL)
		*is_reply_or_forward_r = FALSE;

	subject_len = strlen(subject);
	buf = buffer_create_dynamic(pool, subject_len);

	/* (1) Convert any RFC 2047 encoded-words in the subject to
	   UTF-8.  Convert all tabs and continuations to space.
	   Convert all multiple spaces to a single space. */
	message_header_decode_utf8((const unsigned char *)subject, subject_len,
				   buf, TRUE);
	buffer_append_c(buf, '\0');

	pack_whitespace(buf);

	start_pos = 0;
	do {
		/* (2) Remove all trailing text of the subject that matches
		   the subj-trailer ABNF, repeat until no more matches are
		   possible. */
		remove_subj_trailers(buf, start_pos, is_reply_or_forward_r);

		do {
			/* (3) Remove all prefix text of the subject that
			   matches the subj-leader ABNF. */
			found = remove_subj_leader(buf, &start_pos,
						   is_reply_or_forward_r);

			/* (4) If there is prefix text of the subject that
			   matches the subj-blob ABNF, and removing that prefix
			   leaves a non-empty subj-base, then remove the prefix
			   text. */
			found = remove_blob_when_nonempty(buf, &start_pos) ||
				found;

			/* (5) Repeat (3) and (4) until no matches remain. */
		} while (found);

		/* (6) If the resulting text begins with the subj-fwd-hdr ABNF
		   and ends with the subj-fwd-trl ABNF, remove the
		   subj-fwd-hdr and subj-fwd-trl and repeat from step (2). */
	} while (remove_subj_fwd_hdr(buf, &start_pos, is_reply_or_forward_r));

	/* (7) The resulting text is the "base subject" used in the
	   SORT. */
	return (const char *)buf->data + start_pos;
}
コード例 #15
0
ファイル: askpass.c プロジェクト: Raffprta/core
static void askpass_str(const char *prompt, buffer_t *pass)
{
        struct termios old_tio, tio;
	bool tty, restore_tio = FALSE;
	char ch;
	int fd;

	tty = isatty(STDIN_FILENO);
	if (tty) {
		fputs(prompt, stderr);
		fflush(stderr);

		fd = open("/dev/tty", O_RDONLY);
		if (fd < 0)
			i_fatal("open(/dev/tty) failed: %m");

		/* turn off echo */
		if (tcgetattr(fd, &old_tio) == 0) {
			restore_tio = TRUE;
			tio = old_tio;
			tio.c_lflag &= ~(ECHO | ECHONL);
			(void)tcsetattr(fd, TCSAFLUSH, &tio);
		}
	} else {
		/* read it from stdin without showing a prompt */
		fd = STDIN_FILENO;
	}

	/* read the password */
	while (read(fd, &ch, 1) > 0) {
		if (ch == '\n' || ch == '\r')
			break;
		buffer_append_c(pass, ch);
	}

	if (tty) {
		if (restore_tio)
			(void)tcsetattr(fd, TCSAFLUSH, &old_tio);

		fputs("\n", stderr); fflush(stderr);
		i_close_fd(&fd);
	}
}
コード例 #16
0
ファイル: quoted-printable.c プロジェクト: Distrotech/dovecot
int quoted_printable_q_decode(const unsigned char *src, size_t src_size,
			      buffer_t *dest)
{
	char hexbuf[3];
	size_t src_pos, next;
	bool errors = FALSE;

	hexbuf[2] = '\0';

	next = 0;
	for (src_pos = 0; src_pos < src_size; src_pos++) {
		if (src[src_pos] != '_' && src[src_pos] != '=')
			continue;

		buffer_append(dest, src + next, src_pos - next);
		next = src_pos;

		if (src[src_pos] == '_') {
			buffer_append_c(dest, ' ');
			next++;
			continue;
		}

		if (src_pos+2 >= src_size)
			break;

		/* =<hex> */
		hexbuf[0] = src[src_pos+1];
		hexbuf[1] = src[src_pos+2];

		if (hex_to_binary(hexbuf, dest) == 0) {
			src_pos += 2;
			next = src_pos+1;
		} else {
			/* non-hex data, show as-is */
			errors = TRUE;
			next = src_pos;
		}
	}
	buffer_append(dest, src + next, src_size - next);
	return errors ? -1 : 0;
}
コード例 #17
0
ファイル: imap-base-subject.c プロジェクト: zatsepin/core
static bool remove_subj_fwd_hdr(buffer_t *buf, size_t *start_pos,
				bool *is_reply_or_forward_r)
{
	const char *data = buf->data;
	size_t size = buf->used;

	/* subj-fwd        = subj-fwd-hdr subject subj-fwd-trl
	   subj-fwd-hdr    = "[fwd:"
	   subj-fwd-trl    = "]" */

	if (!str_begins(data + *start_pos, "[FWD:"))
		return FALSE;

	if (data[size-2] != ']')
		return FALSE;

	*is_reply_or_forward_r = TRUE;

	buffer_set_used_size(buf, size-2);
	buffer_append_c(buf, '\0');

	*start_pos += 5;
	return TRUE;
}
コード例 #18
0
ファイル: str.c プロジェクト: dhultin/dovecot-pop-uidl-proxy
void str_append_c(string_t *str, unsigned char chr)
{
	buffer_append_c(str, chr);
}
コード例 #19
0
int message_parse_header_next(struct message_header_parser_ctx *ctx,
			      struct message_header_line **hdr_r)
{
        struct message_header_line *line = &ctx->line;
	const unsigned char *msg;
	size_t i, size, startpos, colon_pos, parse_size;
	int ret;
	bool continued, continues, last_no_newline, last_crlf;
	bool no_newline, crlf_newline;

	*hdr_r = NULL;
	if (line->eoh)
		return -1;

	if (ctx->skip > 0) {
		i_stream_skip(ctx->input, ctx->skip);
		ctx->skip = 0;
	}

	if (line->continues)
		colon_pos = 0;
	else {
		/* new header line */
		line->name_offset = ctx->input->v_offset;
		colon_pos = UINT_MAX;
		buffer_set_used_size(ctx->value_buf, 0);
	}

	no_newline = FALSE;
	crlf_newline = FALSE;
	continued = line->continues;
	continues = FALSE;

	for (startpos = 0;;) {
		ret = i_stream_read_data(ctx->input, &msg, &size, startpos+1);
		if (ret >= 0) {
			/* we want to know one byte in advance to find out
			   if it's multiline header */
			parse_size = size == 0 ? 0 : size-1;
		} else {
			parse_size = size;
		}

		if (ret <= 0 && startpos == parse_size) {
			if (ret == -1) {
				if (startpos > 0) {
					/* header ended unexpectedly. */
					no_newline = TRUE;
					ctx->skip = startpos;
					break;
				}
				/* error / EOF with no bytes */
				return -1;
			}

			if (size > 0 && !ctx->skip_line && !continued &&
			    (msg[0] == '\n' ||
			     (msg[0] == '\r' && size > 1 && msg[1] == '\n'))) {
				/* end of headers - this mostly happens just
				   with mbox where headers are read separately
				   from body */
				size = 0;
				if (ctx->hdr_size != NULL)
					ctx->hdr_size->lines++;
				if (msg[0] == '\r') {
					ctx->skip = 2;
					crlf_newline = TRUE;
				} else {
					ctx->skip = 1;
					if (ctx->hdr_size != NULL)
						ctx->hdr_size->virtual_size++;
				}
				break;
			}
			if (ret == 0 && !ctx->input->eof) {
				/* stream is nonblocking - need more data */
				return 0;
			}
			i_assert(size > 0);

			/* a) line is larger than input buffer
			   b) header ended unexpectedly */
			if (ret == -2) {
				/* go back to last LWSP if found. */
				size_t min_pos = !continued ? colon_pos : 0;
				for (i = size-1; i > min_pos; i--) {
					if (IS_LWSP(msg[i])) {
						size = i;
						break;
					}
				}
				if (i == min_pos && (msg[size-1] == '\r' ||
						     msg[size-1] == '\n')) {
					/* we may or may not have a full header,
					   but we don't know until we get the
					   next character. leave out the
					   linefeed and finish the header on
					   the next run. */
					size--;
					if (size > 0 && msg[size-1] == '\r')
						size--;
				}
				/* the buffer really has to be more than 2 to
				   avoid CRLF looping forever */
				i_assert(size > 0);

				continues = TRUE;
			}
			no_newline = TRUE;
			ctx->skip = size;
			break;
		}

		/* find ':' */
		if (colon_pos == UINT_MAX) {
			for (i = startpos; i < parse_size; i++) {
				if (msg[i] > ':')
					continue;

				if (msg[i] == ':' && !ctx->skip_line) {
					colon_pos = i;
					line->full_value_offset =
						ctx->input->v_offset + i + 1;
					break;
				}
				if (msg[i] == '\n') {
					/* end of headers, or error */
					break;
				}

				if (msg[i] == '\0')
					ctx->has_nuls = TRUE;
			}
		} else {
			i = startpos;
		}

		/* find '\n' */
		for (; i < parse_size; i++) {
			if (msg[i] <= '\n') {
				if (msg[i] == '\n')
					break;
				if (msg[i] == '\0')
					ctx->has_nuls = TRUE;
			}
		}

		if (i < parse_size && i+1 == size && ret == -2) {
			/* we don't know if the line continues. */
			i++;
		} else if (i < parse_size) {
			/* got a line */
			if (ctx->skip_line) {
				/* skipping a line with a huge header name */
				if (ctx->hdr_size != NULL) {
					ctx->hdr_size->lines++;
					ctx->hdr_size->physical_size += i + 1;
					ctx->hdr_size->virtual_size += i + 1;
				}
				if (i == 0 || msg[i-1] != '\r') {
					/* missing CR */
					if (ctx->hdr_size != NULL)
						ctx->hdr_size->virtual_size++;
				}

				i_stream_skip(ctx->input, i + 1);
				startpos = 0;
				ctx->skip_line = FALSE;
				continue;
			}
			continues = i+1 < size && IS_LWSP(msg[i+1]);

			if (ctx->hdr_size != NULL)
				ctx->hdr_size->lines++;
			if (i == 0 || msg[i-1] != '\r') {
				/* missing CR */
				if (ctx->hdr_size != NULL)
					ctx->hdr_size->virtual_size++;
				size = i;
			} else {
				size = i-1;
				crlf_newline = TRUE;
			}

			ctx->skip = i+1;
			break;
		}

		startpos = i;
	}

	last_crlf = line->crlf_newline &&
		(ctx->flags & MESSAGE_HEADER_PARSER_FLAG_DROP_CR) == 0;
	last_no_newline = line->no_newline ||
		(ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) != 0;

	line->continues = continues;
	line->continued = continued;
	line->crlf_newline = crlf_newline;
	line->no_newline = no_newline;
	if (size == 0 && !continued) {
		/* end of headers */
		line->eoh = TRUE;
		line->name_len = line->value_len = line->full_value_len = 0;
		line->name = ""; line->value = line->full_value = NULL;
		line->middle = NULL; line->middle_len = 0;
		line->full_value_offset = line->name_offset;
		line->continues = FALSE;
	} else if (line->continued) {
		line->value = msg;
		line->value_len = size;
	} else if (colon_pos == UINT_MAX) {
		/* missing ':', assume the whole line is name */
		line->value = NULL;
		line->value_len = 0;

		str_truncate(ctx->name, 0);
		buffer_append(ctx->name, msg, size);
		line->name = str_c(ctx->name);
		line->name_len = str_len(ctx->name);

		line->middle = NULL;
		line->middle_len = 0;
	} else {
		size_t pos;

		line->value = msg + colon_pos+1;
		line->value_len = size - colon_pos - 1;
		if (ctx->flags & MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP) {
			/* get value. skip all LWSP after ':'. Note that
			   RFC2822 doesn't say we should, but history behind
			   it..

			   Exception to this is if the value consists only of
			   LWSP, then skip only the one LWSP after ':'. */
			for (pos = 0; pos < line->value_len; pos++) {
				if (!IS_LWSP(line->value[pos]))
					break;
			}

			if (pos == line->value_len) {
				/* everything was LWSP */
				if (line->value_len > 0 &&
				    IS_LWSP(line->value[0]))
					pos = 1;
			}
		} else {
			pos = line->value_len > 0 &&
				IS_LWSP(line->value[0]) ? 1 : 0;
		}

		line->value += pos;
		line->value_len -= pos;
		line->full_value_offset += pos;

		/* get name, skip LWSP before ':' */
		while (colon_pos > 0 && IS_LWSP(msg[colon_pos-1]))
			colon_pos--;

		str_truncate(ctx->name, 0);
		/* use buffer_append() so the name won't be truncated if there
		   are NULs. */
		buffer_append(ctx->name, msg, colon_pos);
		str_append_c(ctx->name, '\0');

		/* keep middle stored also in ctx->name so it's available
		   with use_full_value */
		line->middle = msg + colon_pos;
		line->middle_len = (size_t)(line->value - line->middle);
		str_append_n(ctx->name, line->middle, line->middle_len);

		line->name = str_c(ctx->name);
		line->name_len = colon_pos;
		line->middle = str_data(ctx->name) + line->name_len + 1;
	}

	if (!line->continued) {
		/* first header line. make a copy of the line since we can't
		   really trust input stream not to lose it. */
		buffer_append(ctx->value_buf, line->value, line->value_len);
		line->value = line->full_value = ctx->value_buf->data;
		line->full_value_len = line->value_len;
	} else if (line->use_full_value) {
		/* continue saving the full value. */
		if (last_no_newline) {
			/* line is longer than fit into our buffer, so we
			   were forced to break it into multiple
			   message_header_lines */
		} else {
			if (last_crlf)
				buffer_append_c(ctx->value_buf, '\r');
			buffer_append_c(ctx->value_buf, '\n');
		}
		if ((ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) &&
		    line->value_len > 0 && line->value[0] != ' ' &&
		    IS_LWSP(line->value[0])) {
			buffer_append_c(ctx->value_buf, ' ');
			buffer_append(ctx->value_buf,
				      line->value + 1, line->value_len - 1);
		} else {
			buffer_append(ctx->value_buf,
				      line->value, line->value_len);
		}
		line->full_value = buffer_get_data(ctx->value_buf,
						   &line->full_value_len);
	} else {
		/* we didn't want full_value, and this is a continued line. */
		line->full_value = NULL;
		line->full_value_len = 0;
	}

	/* always reset it */
	line->use_full_value = FALSE;

	if (ctx->hdr_size != NULL) {
		ctx->hdr_size->physical_size += ctx->skip;
		ctx->hdr_size->virtual_size += ctx->skip;
	}

	*hdr_r = line;
	return 1;
}
コード例 #20
0
static int http_header_parse(struct http_header_parser *parser)
{
	int ret;

	/* RFC 7230, Section 3.2: Header Fields

	   'header'       = *( header-field CRLF ) CRLF
	                  ; Actually part of HTTP-message syntax

	   header-field   = field-name ":" OWS field-value OWS
	   field-name     = token
	   field-value    = *( field-content / obs-fold )
	   field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
	   field-vchar    = VCHAR / obs-text
	   obs-fold       = CRLF 1*( SP / HTAB )
	                  ; obsolete line folding
	                  ; see Section 3.2.4
	 */

	for (;;) {
		switch (parser->state) {
		case HTTP_HEADER_PARSE_STATE_INIT:
			buffer_set_used_size(parser->value_buf, 0);
			str_truncate(parser->name, 0);
			if (*parser->cur == '\r') {
				/* last CRLF */
				parser->cur++;
				parser->state = HTTP_HEADER_PARSE_STATE_EOH;
				if (parser->cur == parser->end)
					return 0;
				break;
			} else if (*parser->cur == '\n') {
				/* last LF */
				parser->state = HTTP_HEADER_PARSE_STATE_EOH;
				break;
			}
			/* next line */
			parser->state = HTTP_HEADER_PARSE_STATE_NAME;
			/* fall through */
		case HTTP_HEADER_PARSE_STATE_NAME:
			if ((ret=http_header_parse_name(parser)) <= 0)
				return ret;
			parser->state = HTTP_HEADER_PARSE_STATE_COLON;
			/* fall through */
		case HTTP_HEADER_PARSE_STATE_COLON:
			if (*parser->cur != ':') {
				parser->error = t_strdup_printf
					("Expected ':' after header field name '%s', but found %s",
						str_sanitize(str_c(parser->name),64),
						_chr_sanitize(*parser->cur));
				return -1;
			}
			parser->cur++;
			if (str_len(parser->name) == 0) {
				parser->error = "Empty header field name";
				return -1;
			}
			if (++parser->field_count > parser->limits.max_fields) {
				parser->error = "Excessive number of header fields";
				return -1;
			}
			parser->state = HTTP_HEADER_PARSE_STATE_OWS;
			/* fall through */
		case HTTP_HEADER_PARSE_STATE_OWS:
			if ((ret=http_header_parse_ows(parser)) <= 0)
				return ret;
			parser->state = HTTP_HEADER_PARSE_STATE_CONTENT;
			/* fall through */
		case HTTP_HEADER_PARSE_STATE_CONTENT:
			if ((ret=http_header_parse_content(parser)) <= 0)
				return ret;
			parser->state = HTTP_HEADER_PARSE_STATE_CR;
			/* fall through */
		case HTTP_HEADER_PARSE_STATE_CR:
			if (*parser->cur == '\r') {
				parser->cur++;
			} else if (*parser->cur != '\n') {
				parser->error = t_strdup_printf
					("Invalid character %s in content of header field '%s'",
						_chr_sanitize(*parser->cur),
						str_sanitize(str_c(parser->name),64));
				return -1;
			}
			parser->state = HTTP_HEADER_PARSE_STATE_LF;
			if (parser->cur == parser->end)
				return 0;
			/* fall through */
		case HTTP_HEADER_PARSE_STATE_LF:
			if (*parser->cur != '\n') {
				parser->error = t_strdup_printf
					("Expected LF after CR at end of header field '%s', but found %s",
						str_sanitize(str_c(parser->name),64),
						_chr_sanitize(*parser->cur));
				return -1;
			}
			parser->cur++;
			parser->state = HTTP_HEADER_PARSE_STATE_NEW_LINE;
			if (parser->cur == parser->end)
				return 0;
			/* fall through */
		case HTTP_HEADER_PARSE_STATE_NEW_LINE:
			if (*parser->cur == ' ' || *parser->cur == '\t') {
				/* obs-fold */
				buffer_append_c(parser->value_buf, ' ');
				parser->state = HTTP_HEADER_PARSE_STATE_OWS;
				break;
			} 
			/* next header line */
			parser->state = HTTP_HEADER_PARSE_STATE_INIT;
			return 1;
		case HTTP_HEADER_PARSE_STATE_EOH:
			if (*parser->cur != '\n') {
				parser->error = t_strdup_printf
					("Encountered stray CR at beginning of header line, followed by %s",
						_chr_sanitize(*parser->cur));
				return -1;
			}
			/* header fully parsed */
			parser->cur++;
			return 1;

		default:
			i_unreached();
		}
	}

	i_unreached();
	return -1;
}
コード例 #21
0
ファイル: quoted-printable.c プロジェクト: Distrotech/dovecot
static int
quoted_printable_decode_full(const unsigned char *src, size_t src_size,
			     size_t *src_pos_r, buffer_t *dest, bool eof)
{
	char hexbuf[3];
	size_t src_pos, pos, next;
	bool errors = FALSE;
	int ret;

	hexbuf[2] = '\0';

	next = 0;
	for (src_pos = 0; src_pos < src_size; src_pos++) {
		if (src[src_pos] != '=' && src[src_pos] != '\n')
			continue;

		if (src[src_pos] == '\n') {
			/* drop trailing whitespace */
			pos = src_pos;
			if (pos > 0 && src[pos-1] == '\r')
				pos--;
			while (pos > 0 && QP_IS_TRAILING_SPACE(src[pos-1]))
				pos--;
			buffer_append(dest, src + next, pos - next);
			next = src_pos+1;
			buffer_append_c(dest, '\r');
			buffer_append_c(dest, '\n');
			continue;
		}

		/* '=' */
		buffer_append(dest, src + next, src_pos - next);
		next = src_pos;

		if ((ret = qp_is_end_of_line(src, &src_pos, src_size)) > 0) {
			/* =[whitespace][\r]\n */
			next = src_pos+1;
			continue;
		}
		if (ret < 0) {
			/* '=' was followed only by whitespace */
			break;
		}
		if (src_pos+2 >= src_size) {
			/* '=' was followed by non-whitespace */
			if (eof)
				errors = TRUE;
			break;
		}

		/* =<hex> */
		hexbuf[0] = src[src_pos+1];
		hexbuf[1] = src[src_pos+2];

		if (hex_to_binary(hexbuf, dest) == 0) {
			src_pos += 2;
			next = src_pos + 1;
		} else {
			/* non-hex data, show as-is */
			errors = TRUE;
			next = src_pos;
		}
	}
	if (src_pos == src_size) {
		/* add everything but trailing spaces */
		if (src_pos > 0 && src[src_pos-1] == '\r')
			src_pos--;
		while (src_pos > 0 && QP_IS_TRAILING_SPACE(src[src_pos-1]))
			src_pos--;
		buffer_append(dest, src + next, src_pos - next);
		next = src_pos;
	}
	*src_pos_r = next;
	return errors ? -1 : 0;
}