Files
bongo/src/agents/pop/protocol.c
T
Mario Fetka 12ee80a466
Debian Trixie package bundle / packages (push) Successful in 20m44s
Harden IMAP and POP TLS state handling
2026-07-21 10:32:45 +02:00

262 lines
7.8 KiB
C

/****************************************************************************
* <Novell-copyright>
* Copyright (c) 2001 Novell, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact Novell, Inc.
*
* To contact Novell about this file by physical or electronic mail, you
* may find current contact information at www.novell.com.
* </Novell-copyright>
****************************************************************************/
#include "protocol.h"
#include <ctype.h>
#include <limits.h>
#include <string.h>
static const char *
SkipSpace(const char *cursor)
{
while (*cursor == ' ' || *cursor == '\t') cursor++;
return cursor;
}
static int
ParseUnsigned(const char **cursor, uint32_t *value)
{
uint32_t parsed = 0;
const char *current = *cursor;
if (!isdigit((unsigned char)*current)) return 0;
do {
unsigned int digit = (unsigned int)(*current - '0');
if (parsed > (UINT32_MAX - digit) / 10) return 0;
parsed = parsed * 10 + digit;
current++;
} while (isdigit((unsigned char)*current));
*cursor = current;
*value = parsed;
return 1;
}
int
POP3ArgumentsEmpty(const char *arguments)
{
return arguments && *arguments == '\0';
}
POP3STLSStatus
POP3STLSCheck(int authorization_state, int tls_active, int utf8_active,
int tls_available)
{
if (!authorization_state || tls_active || utf8_active)
return POP3_STLS_INVALID_STATE;
if (!tls_available) return POP3_STLS_UNAVAILABLE;
return POP3_STLS_READY;
}
int
POP3ParseMessageNumber(const char *arguments, uint32_t *message_number)
{
const char *cursor;
uint32_t parsed;
if (!arguments || !message_number ||
(*arguments != ' ' && *arguments != '\t')) return 0;
cursor = SkipSpace(arguments);
if (!ParseUnsigned(&cursor, &parsed) || parsed == 0 || *cursor != '\0')
return 0;
*message_number = parsed;
return 1;
}
int
POP3ParseTopArguments(const char *arguments, uint32_t *message_number,
uint32_t *line_count)
{
const char *cursor;
uint32_t parsed_message;
uint32_t parsed_lines;
if (!arguments || !message_number || !line_count ||
(*arguments != ' ' && *arguments != '\t')) return 0;
cursor = SkipSpace(arguments);
if (!ParseUnsigned(&cursor, &parsed_message) || parsed_message == 0 ||
(*cursor != ' ' && *cursor != '\t')) return 0;
cursor = SkipSpace(cursor);
if (!ParseUnsigned(&cursor, &parsed_lines) || *cursor != '\0') return 0;
*message_number = parsed_message;
*line_count = parsed_lines;
return 1;
}
int
POP3UserNameValid(const char *user, size_t user_size, int allow_utf8)
{
const unsigned char *cursor = (const unsigned char *)user;
size_t length = 0;
if (!user || user_size == 0 || !*cursor) return 0;
while (*cursor) {
if (*cursor <= 0x20 || *cursor == 0x7f ||
(!allow_utf8 && *cursor >= 0x80) || length + 1 >= user_size) {
return 0;
}
length++;
cursor++;
}
return !allow_utf8 || POP3UTF8Valid(user, length);
}
int
POP3ParseUserArgument(const char *arguments, char *user, size_t user_size,
int allow_utf8)
{
const char *cursor;
size_t length;
if (!arguments || !user || user_size == 0 ||
(*arguments != ' ' && *arguments != '\t')) return 0;
cursor = SkipSpace(arguments);
length = strlen(cursor);
if (length >= user_size ||
!POP3UserNameValid(cursor, user_size, allow_utf8)) {
user[0] = '\0';
return 0;
}
memcpy(user, cursor, length + 1);
return 1;
}
void
POP3MultilineWriterInit(POP3MultilineWriter *writer)
{
if (!writer) return;
writer->at_line_start = 1;
writer->has_data = 0;
writer->ends_in_lf = 0;
writer->ends_in_cr = 0;
}
int
POP3Contains8Bit(const void *data, size_t length)
{
const unsigned char *cursor = data;
size_t i;
if (!data && length) return 0;
for (i = 0; i < length; i++) {
if (cursor[i] >= 0x80) return 1;
}
return 0;
}
int
POP3UTF8Valid(const void *data, size_t length)
{
const unsigned char *cursor = data;
size_t i = 0;
if (!data && length) return 0;
while (i < length) {
unsigned char first = cursor[i++];
if (first <= 0x7f) continue;
if (first >= 0xc2 && first <= 0xdf) {
if (i >= length || cursor[i] < 0x80 || cursor[i] > 0xbf)
return 0;
i++;
} else if (first >= 0xe0 && first <= 0xef) {
unsigned char second;
if (length - i < 2) return 0;
second = cursor[i++];
if ((first == 0xe0 && (second < 0xa0 || second > 0xbf)) ||
(first == 0xed && (second < 0x80 || second > 0x9f)) ||
((first != 0xe0 && first != 0xed) &&
(second < 0x80 || second > 0xbf)) ||
cursor[i] < 0x80 || cursor[i] > 0xbf) return 0;
i++;
} else if (first >= 0xf0 && first <= 0xf4) {
unsigned char second;
if (length - i < 3) return 0;
second = cursor[i++];
if ((first == 0xf0 && (second < 0x90 || second > 0xbf)) ||
(first == 0xf4 && (second < 0x80 || second > 0x8f)) ||
((first != 0xf0 && first != 0xf4) &&
(second < 0x80 || second > 0xbf)) ||
cursor[i] < 0x80 || cursor[i] > 0xbf ||
cursor[i + 1] < 0x80 || cursor[i + 1] > 0xbf) return 0;
i += 2;
} else {
return 0;
}
}
return 1;
}
int
POP3MultilineWriterWrite(POP3MultilineWriter *writer, const void *data,
size_t length, POP3WriteFunction write_function,
void *context)
{
const unsigned char *cursor = data;
size_t start = 0;
size_t i;
if (!writer || (!data && length) || !write_function) return 0;
for (i = 0; i < length; i++) {
if (writer->at_line_start && cursor[i] == '.') {
if (i > start && !write_function(context, cursor + start, i - start))
return 0;
if (!write_function(context, ".", 1)) return 0;
start = i;
}
if (cursor[i] == '\n' && !writer->ends_in_cr) {
if (i > start && !write_function(context, cursor + start, i - start))
return 0;
if (!write_function(context, "\r", 1)) return 0;
start = i;
}
writer->at_line_start = cursor[i] == '\n';
writer->has_data = 1;
writer->ends_in_lf = writer->at_line_start;
writer->ends_in_cr = cursor[i] == '\r';
}
return start == length ||
write_function(context, cursor + start, length - start);
}
int
POP3MultilineWriterFinish(POP3MultilineWriter *writer,
POP3WriteFunction write_function, void *context)
{
if (!writer || !write_function) return 0;
if (!writer->has_data) {
if (!write_function(context, "\r\n", 2)) return 0;
} else if (!writer->ends_in_lf) {
if (writer->ends_in_cr) {
if (!write_function(context, "\n", 1)) return 0;
} else if (!write_function(context, "\r\n", 2)) {
return 0;
}
}
if (!write_function(context, ".\r\n", 3)) return 0;
writer->at_line_start = 1;
writer->has_data = 0;
writer->ends_in_lf = 0;
writer->ends_in_cr = 0;
return 1;
}