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));

Reply via email to