Skip to content

Commit

Permalink
imapd.c: also emit a NO [TOOBIG] response for oversized no-sync APPEND
Browse files Browse the repository at this point in the history
  • Loading branch information
ksmurchison authored and elliefm committed May 1, 2024
1 parent ea57ff7 commit c2741fc
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 17 deletions.
30 changes: 21 additions & 9 deletions cassandane/Cassandane/Cyrus/IMAPLimits.pm
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ $email =~ s/\r?\n/\r\n/gs;

my $toobig_email = $email . "X" x 100;

# Check that we got an untagged BYE [TOOBIG] response
sub assert_bye_toobig
{
my ($self, $store) = @_;
Expand All @@ -79,11 +80,11 @@ sub assert_bye_toobig
}
};

# Check that we got a BYE [TOOBIG] response
$store->idle_response($handlers, 1);
$self->assert_num_equals(1, $got_toobig);
}

# Send a command and expect an untagged BYE [TOOBIG] response
sub assert_cmd_bye_toobig
{
my $self = shift;
Expand All @@ -97,30 +98,39 @@ sub assert_cmd_bye_toobig
$self->assert_bye_toobig();
}

sub assert_cmd_no_toobig
# Check that we got a tagged NO [TOOBIG] response
sub assert_no_toobig
{
my $self = shift;
my $talk = shift;
my $cmd = shift;
my ($self, $talk) = @_;

my $got_toobig = 0;
my $handlers =
{
'no' => sub
{
# Pick out the [TOOBIG] response code
my (undef, $resp) = @_;
$got_toobig = 1 if (uc($resp->[0]) eq '[TOOBIG]');
}
};

$talk->_imap_cmd($cmd, 0, $handlers, @_);
eval {
$talk->_parse_response($handlers);
};

# Check that we got a NO [TOOBIG] response
$self->assert_str_equals('no', $talk->get_last_completion_response());
$self->assert_num_equals(1, $got_toobig);
}

# Send a command and expect a tagged NO [TOOBIG] response
sub assert_cmd_no_toobig
{
my $self = shift;
my $talk = shift;
my $cmd = shift;

$talk->_send_cmd($cmd, @_);
$self->assert_no_toobig($talk);
}

sub new
{
my $class = shift;
Expand Down Expand Up @@ -544,6 +554,7 @@ sub test_maxmessagesize_nosync_literal
my $talk = $self->{store}->get_client();
# Do this by brute force until we have IMAPTalk v4.06+
$talk->_imap_socket_out($talk->{CmdId}++ . " APPEND INBOX {101+}\015\012");
$self->assert_no_toobig($talk);
$self->assert_bye_toobig();
}

Expand All @@ -553,6 +564,7 @@ sub test_literal_minus

my $talk = $self->{store}->get_client();
$talk->_imap_socket_out($talk->{CmdId}++ . " APPEND INBOX {4097+}\015\012");
$self->assert_no_toobig($talk);
$self->assert_bye_toobig();
}

Expand Down
23 changes: 15 additions & 8 deletions imap/imapd.c
Original file line number Diff line number Diff line change
Expand Up @@ -3780,7 +3780,7 @@ static int isokflag(char *s, int *isseen)
}
}

static int getliteralsize(const char *p, int c, size_t maxsize,
static int getliteralsize(const char *tag, const char *p, int c, size_t maxsize,
unsigned *size, int *binary, const char **parseerr)

{
Expand Down Expand Up @@ -3812,10 +3812,14 @@ static int getliteralsize(const char *p, int c, size_t maxsize,
/* LITERAL- says maximum size is 4096! */
if (lminus && num > 4096) {
/* Fail per RFC 7888, Section 4, choice 2 */
prot_printf(imapd_out, "%s NO %s\r\n", tag,
error_message(IMAP_LITERAL_MINUS_TOO_LARGE));
fatal(error_message(IMAP_LITERAL_MINUS_TOO_LARGE), EX_IOERR);
}
if (num > maxsize) {
/* Fail per RFC 7888, Section 4, choice 2 */
prot_printf(imapd_out, "%s NO %s\r\n", tag,
error_message(IMAP_MESSAGE_TOOBIG));
fatal(error_message(IMAP_MESSAGE_TOOBIG), EX_IOERR);
}
isnowait++;
Expand Down Expand Up @@ -3845,8 +3849,8 @@ static int getliteralsize(const char *p, int c, size_t maxsize,
return 0;
}

static int catenate_text(FILE *f, size_t maxsize, unsigned *totalsize, int *binary,
const char **parseerr)
static int catenate_text(const char *tag, FILE *f, size_t maxsize,
unsigned *totalsize, int *binary, const char **parseerr)
{
int c;
static struct buf arg;
Expand All @@ -3858,7 +3862,8 @@ static int catenate_text(FILE *f, size_t maxsize, unsigned *totalsize, int *bina
c = getword(imapd_in, &arg);

/* Read size from literal */
r = getliteralsize(arg.s, c, maxsize - *totalsize, &size, binary, parseerr);
r = getliteralsize(tag, arg.s, c, maxsize - *totalsize,
&size, binary, parseerr);
if (r) return r;

/* Catenate message part to stage */
Expand Down Expand Up @@ -4004,7 +4009,8 @@ static int catenate_url(const char *s, const char *cur_name, FILE *f,
return r;
}

static int append_catenate(FILE *f, const char *cur_name, size_t maxsize, unsigned *totalsize,
static int append_catenate(const char *tag, FILE *f, const char *cur_name,
size_t maxsize, unsigned *totalsize,
int *binary, const char **parseerr, const char **url)
{
int c, r = 0;
Expand All @@ -4018,7 +4024,7 @@ static int append_catenate(FILE *f, const char *cur_name, size_t maxsize, unsign
}

if (!strcasecmp(arg.s, "TEXT")) {
int r1 = catenate_text(f, maxsize, totalsize, binary, parseerr);
int r1 = catenate_text(tag, f, maxsize, totalsize, binary, parseerr);
if (r1) return r1;

/* if we see a SP, we're trying to catenate more than one part */
Expand Down Expand Up @@ -4295,13 +4301,14 @@ static int cmd_append(char *tag, char *name, const char *cur_name, int isreplace

/* Catenate the message part(s) to stage */
size = 0;
r = append_catenate(curstage->f, cur_name, maxmsgsize, &size,
r = append_catenate(tag, curstage->f, cur_name, maxmsgsize, &size,
&(curstage->binary), &parseerr, &url);
if (r) goto done;
}
else {
/* Read size from literal */
r = getliteralsize(arg.s, c, maxmsgsize, &size, &(curstage->binary), &parseerr);
r = getliteralsize(tag, arg.s, c, maxmsgsize,
&size, &(curstage->binary), &parseerr);
if (!r && size == 0) r = IMAP_ZERO_LENGTH_LITERAL;
if (r) goto done;

Expand Down

0 comments on commit c2741fc

Please sign in to comment.