Thus said David Levine on Thu, 10 Nov 2022 05:51:12 -0800:
> Andy, are you able to create patches against HEAD?
Attached is a new patch that applies cleanly against master (17734c9c).
I had trouble compiling on OpenBSD, but I eventually got it working
after a bit of hacking, however, I did not include those bits in my
patch since they are not specific to the long line problem (I'll bring
up in a different thread).
The new patch compiles and I tested inc using 3 malformed messages and
it worked fine. I did not test imaptest.c nor the changes for smtp.c,
but the changes there were merely to preserve the original behavior of
the functions modified (function signature changed).
Thanks,
Andy
diff --git a/h/netsec.h b/h/netsec.h
index 6c69c82c..73e9585b 100644
--- a/h/netsec.h
+++ b/h/netsec.h
@@ -139,19 +139,20 @@ void netsec_set_timeout(netsec_context *ns_context, int timeout);
* Read a "line" from the network. This reads one CR/LF terminated line.
* Returns a pointer to a NUL-terminated string. This memory is valid
* until the next call to any read function. Will return an error if
- * the line does not terminate with a CR/LF.
+ * the line does not terminate with a CR/LF unless strict is false.
*
* Arguments:
*
* ns_context - Network security context
* length - Returned length of string
* errstr - Error string
+ * strict - Strict CR/LF checking
*
* Returns pointer to string, or NULL on error.
*/
char *netsec_readline(netsec_context *ns_context, size_t *length,
- char **errstr);
+ char **errstr, bool strict);
/*
* Read bytes from the network.
diff --git a/mts/smtp/smtp.c b/mts/smtp/smtp.c
index bf338b12..20722bfd 100644
--- a/mts/smtp/smtp.c
+++ b/mts/smtp/smtp.c
@@ -817,7 +817,7 @@ again: ;
rc = sizeof(sm_reply.text) - 1;
for (more = false; (buffer = netsec_readline(nsc, &buflen,
- &errstr)) != NULL ; ) {
+ &errstr, true)) != NULL ; ) {
if (doingEHLO
&& has_prefix(buffer, "250")
@@ -1035,7 +1035,7 @@ sm_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata,
netsec_set_snoop_callback(nsc, netsec_b64_snoop_decoder, &snoopoffset);
snoopoffset = 4;
- line = netsec_readline(nsc, &len, errstr);
+ line = netsec_readline(nsc, &len, errstr, true);
netsec_set_snoop_callback(nsc, NULL, NULL);
if (line == NULL)
@@ -1093,7 +1093,7 @@ sm_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata,
/*
* Finish the protocol; we're looking for a 235 message.
*/
- line = netsec_readline(nsc, &len, errstr);
+ line = netsec_readline(nsc, &len, errstr, true);
if (line == NULL)
return NOTOK;
diff --git a/sbr/netsec.c b/sbr/netsec.c
index bf0ff9cf..12cae575 100644
--- a/sbr/netsec.c
+++ b/sbr/netsec.c
@@ -50,6 +50,8 @@ static SSL_CTX *sslctx = NULL; /* SSL Context */
/* I'm going to hardcode this for now; maybe make it adjustable later? */
#define NETSEC_BUFSIZE 65536
+bool addnl;
+
/*
* Our context structure, which holds all of the relevant information
* about a connection.
@@ -434,7 +436,7 @@ netsec_read(netsec_context *nsc, void *buffer, size_t size, char **errstr)
*/
char *
-netsec_readline(netsec_context *nsc, size_t *len, char **errstr)
+netsec_readline(netsec_context *nsc, size_t *len, char **errstr, bool strict)
{
unsigned char *ptr = nsc->ns_inptr;
size_t count = 0, offset;
@@ -443,10 +445,12 @@ retry:
/*
* Search through our existing buffer for a LF
*/
+ addnl = false;
- while (count < nsc->ns_inbuflen) {
+ while (count < nsc->ns_inbuflen && count < BUFSIZ - 2) {
count++;
if (*ptr++ == '\n') {
+ addnl = true;
char *sptr = (char *) nsc->ns_inptr;
if (count > 1 && *(ptr - 2) == '\r')
ptr--;
@@ -478,14 +482,30 @@ retry:
}
/*
- * Hm, we didn't find a \n. If we've already searched half of the input
+ * Hm, we didn't find a \n. Return half of a BUFSIZ buffer it not strictly
+ * searching for \n.
+ * Otherwise, if we've already searched half of the input
* buffer, return an error.
*/
- if (count >= nsc->ns_inbufsize / 2) {
- netsec_err(errstr, "Unable to find a line terminator after %zu bytes",
- count);
- return NULL;
+ if (strict == true) {
+ if (count >= nsc->ns_inbufsize / 2) {
+ netsec_err(errstr,
+ "Unable to find a line terminator after %zu bytes",
+ count);
+ return NULL;
+ }
+ } else {
+ if (count) {
+ count = min(BUFSIZ / 2, count);
+ ptr = nsc->ns_inptr + count;
+ char *sptr = (char *) nsc->ns_inptr;
+ if (len)
+ *len = ptr - nsc->ns_inptr;
+ nsc->ns_inptr += count;
+ nsc->ns_inbuflen -= count;
+ return sptr;
+ }
}
/*
diff --git a/uip/imaptest.c b/uip/imaptest.c
index 9e19aac6..938c2506 100644
--- a/uip/imaptest.c
+++ b/uip/imaptest.c
@@ -291,7 +291,7 @@ main (int argc, char **argv)
die("%s", errstr);
}
- if ((cp = netsec_readline(nsc, &len, &errstr)) == NULL) {
+ if ((cp = netsec_readline(nsc, &len, &errstr, true)) == NULL) {
die("%s", errstr);
}
@@ -600,7 +600,7 @@ imap_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata,
rc = send_imap_command(nsc, 0, errstr, "AUTHENTICATE %s", mech);
if (rc != OK)
return NOTOK;
- line = netsec_readline(nsc, &len, errstr);
+ line = netsec_readline(nsc, &len, errstr, true);
if (! line)
return NOTOK;
/*
@@ -636,7 +636,7 @@ imap_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata,
case NETSEC_SASL_READ:
netsec_set_snoop_callback(nsc, netsec_b64_snoop_decoder, &snoopoffset);
snoopoffset = 2;
- line = netsec_readline(nsc, &len, errstr);
+ line = netsec_readline(nsc, &len, errstr, true);
netsec_set_snoop_callback(nsc, NULL, NULL);
if (line == NULL)
@@ -919,7 +919,7 @@ get_imap_response(netsec_context *nsc, const char *token, char **tokenresponse,
getline:
while (cmdqueue) {
- if (!(line = netsec_readline(nsc, NULL, errstr)))
+ if (!(line = netsec_readline(nsc, NULL, errstr, true)))
return NOTOK;
if (has_prefix(line, "* ") && *(line + 2) != '\0') {
if (token && tokenresponse && has_prefix(line + 2, token)) {
diff --git a/uip/inc.c b/uip/inc.c
index 0f41551d..c939318e 100644
--- a/uip/inc.c
+++ b/uip/inc.c
@@ -127,6 +127,8 @@ static struct Maildir_entry *Maildir;
static int num_maildir_entries;
static bool snoop;
+extern bool addnl;
+
typedef struct {
FILE *mailout;
long written;
@@ -900,7 +902,11 @@ pop_action(void *closure, char *s)
int n;
pc = closure;
- n = fprintf(pc->mailout, "%s\n", s);
+ if (addnl == true) {
+ n = fprintf(pc->mailout, "%s\n", s);
+ } else {
+ n = fprintf(pc->mailout, "%s", s);
+ }
if (n < 0)
return NOTOK;
pc->written += n; /* Count linefeed too. */
diff --git a/uip/popsbr.c b/uip/popsbr.c
index 8a064ff5..bedf6afb 100644
--- a/uip/popsbr.c
+++ b/uip/popsbr.c
@@ -30,12 +30,12 @@ static netsec_context *nsc = NULL;
*/
static int command(const char *, ...) CHECK_PRINTF(1, 2);
-static int multiline(void);
+static int multiline(bool);
static int traverse(int (*)(void *, char *), void *closure,
const char *, ...) CHECK_PRINTF(3, 4);
static int vcommand(const char *, va_list) CHECK_PRINTF(1, 0);
-static int pop_getline (char *, int, netsec_context *);
+static int pop_getline (char *, int, netsec_context *, bool);
static int pop_sasl_callback(enum sasl_message_type, unsigned const char *,
unsigned int, unsigned char **, unsigned int *,
void *, char **);
@@ -60,7 +60,7 @@ check_mech(char *server_mechs, size_t server_mechs_size)
return NOTOK;
}
- while ((status = multiline()) != DONE) {
+ while ((status = multiline(true)) != DONE) {
if (status == NOTOK)
return NOTOK;
@@ -100,7 +100,7 @@ pop_start_tls(void)
return NOTOK;
}
- while ((status = multiline()) != DONE) {
+ while ((status = multiline(true)) != DONE) {
if (status == NOTOK)
return NOTOK;
@@ -285,7 +285,7 @@ pop_init (char *host, char *port, char *user, char *proxy, int snoop,
}
}
- switch (pop_getline (response, sizeof response, nsc)) {
+ switch (pop_getline (response, sizeof response, nsc, true)) {
case OK:
if (poprint)
fprintf (stderr, "<--- %s\n", response);
@@ -385,7 +385,7 @@ pop_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata,
return NOTOK;
if (netsec_flush(nsc, errstr) != OK)
return NOTOK;
- line = netsec_readline(nsc, &len, errstr);
+ line = netsec_readline(nsc, &len, errstr, true);
if (! line)
return NOTOK;
/*
@@ -436,7 +436,7 @@ pop_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata,
case NETSEC_SASL_READ:
netsec_set_snoop_callback(nsc, netsec_b64_snoop_decoder, &snoopoffset);
snoopoffset = 2;
- line = netsec_readline(nsc, &len, errstr);
+ line = netsec_readline(nsc, &len, errstr, true);
netsec_set_snoop_callback(nsc, NULL, NULL);
if (line == NULL)
@@ -504,7 +504,7 @@ pop_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata,
*/
case NETSEC_SASL_FINISH:
- line = netsec_readline(nsc, &len, errstr);
+ line = netsec_readline(nsc, &len, errstr, true);
if (line == NULL)
return NOTOK;
@@ -565,6 +565,7 @@ static int
traverse (int (*action)(void *, char *), void *closure, const char *fmt, ...)
{
int result, snoopstate;
+ bool seenhdr = false;
va_list ap;
char buffer[sizeof(response)];
@@ -580,8 +581,10 @@ traverse (int (*action)(void *, char *), void *closure, const char *fmt, ...)
netsec_set_snoop(nsc, 0);
for (;;) {
- result = multiline();
+ result = multiline(seenhdr ? false : true);
if (result == OK) {
+ if (seenhdr != true && strnlen(response,sizeof(response)) == 0)
+ seenhdr = true;
result = (*action)(closure, response);
if (result == OK)
continue;
@@ -667,7 +670,7 @@ vcommand (const char *fmt, va_list ap)
return NOTOK;
}
- switch (pop_getline (response, sizeof response, nsc)) {
+ switch (pop_getline (response, sizeof response, nsc, true)) {
case OK:
if (poprint)
fprintf (stderr, "<--- %s\n", response);
@@ -687,11 +690,11 @@ vcommand (const char *fmt, va_list ap)
static int
-multiline (void)
+multiline (bool strict)
{
char buffer[BUFSIZ + LEN(TRM)];
- if (pop_getline (buffer, sizeof buffer, nsc) != OK)
+ if (pop_getline (buffer, sizeof buffer, nsc, strict) != OK)
return NOTOK;
if (has_prefix(buffer, TRM)) {
if (buffer[LEN(TRM)] == 0)
@@ -709,7 +712,7 @@ multiline (void)
*/
static int
-pop_getline (char *s, int n, netsec_context *ns)
+pop_getline (char *s, int n, netsec_context *ns, bool strict)
{
/* int c = -2; */
char *p;
@@ -717,7 +720,7 @@ pop_getline (char *s, int n, netsec_context *ns)
/* int rc; */
char *errstr;
- p = netsec_readline(ns, &len, &errstr);
+ p = netsec_readline(ns, &len, &errstr, strict);
if (p == NULL) {
strncpy(response, errstr, sizeof(response));