Hi, smtpd currently ignores the server capabilities advertised on a singleline or the last line of a multiline response:
[...] <<< 220 mail.tako.de ESMTP >>> EHLO something.tako.de <<< 250-mail.tako.de <<< 250-PIPELINING <<< 250-8BITMIME <<< 250-SIZE 0 <<< 250 AUTH LOGIN PLAIN CRAM-MD5 mta: leaving smtp phase mta: new status for [email protected]: AUTH not available [...] Note that although AUTH is advertised, smtpd misses it. I have included a patch that fixes the problem and that also only parses the server reply (for AUTH and STARTTLS) during the EHLO phase. Nils Index: client.c =================================================================== RCS file: /cvs/src/usr.sbin/smtpd/client.c,v retrieving revision 1.9 diff -u -r1.9 client.c --- client.c 25 Oct 2009 20:43:29 -0000 1.9 +++ client.c 9 Nov 2009 20:00:02 -0000 @@ -859,7 +859,12 @@ sp->reply[0] = '\0'; - /* get a reply, dealing with multiline responses */ + /* get a reply, dealing with multiline responses + * multiline responses are provided by 3 digits followed by '-', and + * are terminated the same as single line responses: either 3 digits, + * or 3 digits followed by ' '. + * all responses can have additional data starting at the 4th char. + */ for (;;) { errno = 0; if ((ln = buf_getln(&sp->r)) == NULL) { @@ -875,17 +880,28 @@ if (sp->verbose) fprintf(sp->verbose, "<<< %s\n", ln); - if (strlen(ln) == 3 || ln[3] == ' ') + /* if we have 3 chars, there's no multiline or data string */ + if (strlen(ln) == 3) break; - else if (ln[3] != '-') { - cause = "150 garbled multiline reply"; + else if (strlen(ln) < 4 || (ln[3] != ' ' && ln[3] != '-')) { + /* we didn't get the entire smtp reply code, + * or we got a wrong single-/multiline character. + */ + cause = "150 garbled smtp reply"; goto done; } - if (strcmp(ln + 4, "STARTTLS") == 0) - sp->exts[CLIENT_EXT_STARTTLS].have = 1; - if (strncmp(ln + 4, "AUTH", 4) == 0) - sp->exts[CLIENT_EXT_AUTH].have = 1; + /* save some useful server capabilities during ehlo reply */ + if (sp->state == CLIENT_EHLO) { + if (strcmp(ln + 4, "STARTTLS") == 0) + sp->exts[CLIENT_EXT_STARTTLS].have = 1; + else if (strncmp(ln + 4, "AUTH", 4) == 0) + sp->exts[CLIENT_EXT_AUTH].have = 1; + } + + /* this is either single line or the last multiline reply */ + if (ln[3] == ' ') + break; } /* validate reply code */
