sendmail: update by Vladimir

function                                             old     new   delta
sendmail_main                                        897     939     +42
rcptto                                                17      40     +23

Signed-off-by: Vladimir Dronnikov <dronnikov@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Vladimir Dronnikov 2009-10-15 23:50:48 +02:00 committed by Denys Vlasenko
parent f5a295d5a8
commit 944d275175

View File

@ -9,6 +9,10 @@
#include "libbb.h" #include "libbb.h"
#include "mail.h" #include "mail.h"
// limit maximum allowed number of headers to prevent overflows.
// set to 0 to not limit
#define MAX_HEADERS 256
static int smtp_checkp(const char *fmt, const char *param, int code) static int smtp_checkp(const char *fmt, const char *param, int code)
{ {
char *answer; char *answer;
@ -55,7 +59,9 @@ static char *sane_address(char *str)
static void rcptto(const char *s) static void rcptto(const char *s)
{ {
smtp_checkp("RCPT TO:<%s>", s, 250); // N.B. we don't die if recipient is rejected, for the other recipients may be accepted
if (250 != smtp_checkp("RCPT TO:<%s>", s, -1))
bb_error_msg("Bad recipient: <%s>", s);
} }
int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@ -66,6 +72,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
char *s; char *s;
llist_t *list = NULL; llist_t *list = NULL;
char *domain = sane_address(safe_getdomainname()); char *domain = sane_address(safe_getdomainname());
unsigned nheaders = 0;
int code; int code;
enum { enum {
@ -197,6 +204,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
// and then use the rest of stdin as message body // and then use the rest of stdin as message body
code = 0; // set "analyze headers" mode code = 0; // set "analyze headers" mode
while ((s = xmalloc_fgetline(G.fp0)) != NULL) { while ((s = xmalloc_fgetline(G.fp0)) != NULL) {
dump:
// put message lines doubling leading dots // put message lines doubling leading dots
if (code) { if (code) {
// escape leading dots // escape leading dots
@ -215,41 +223,62 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
// To: or Cc: headers add recipients // To: or Cc: headers add recipients
if (0 == strncasecmp("To: ", s, 4) || 0 == strncasecmp("Bcc: " + 1, s, 4)) { if (0 == strncasecmp("To: ", s, 4) || 0 == strncasecmp("Bcc: " + 1, s, 4)) {
rcptto(sane_address(s+4)); rcptto(sane_address(s+4));
// goto addh; goto addheader;
llist_add_to_end(&list, s);
// Bcc: header adds blind copy (hidden) recipient // Bcc: header adds blind copy (hidden) recipient
} else if (0 == strncasecmp("Bcc: ", s, 5)) { } else if (0 == strncasecmp("Bcc: ", s, 5)) {
rcptto(sane_address(s+5)); rcptto(sane_address(s+5));
free(s); free(s);
// N.B. Bcc: vanishes from headers! // N.B. Bcc: vanishes from headers!
// other headers go verbatim // other headers go verbatim
} else if (s[0]) { // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks
// addh: } else if (strchr(s, ':')) {
addheader:
if (MAX_HEADERS && ++nheaders >= MAX_HEADERS)
goto bail;
llist_add_to_end(&list, s); llist_add_to_end(&list, s);
// the empty line stops analyzing headers // a line without ":" (an empty line too, by definition) doesn't look like a valid header
// so stop "analyze headers" mode
} else { } else {
free(s); reenter:
// put recipients specified on cmdline // put recipients specified on cmdline
while (*argv) { while (*argv) {
s = sane_address(*argv); char *t = sane_address(*argv);
rcptto(s); rcptto(t);
llist_add_to_end(&list, xasprintf("To: %s", s)); //if (MAX_HEADERS && ++nheaders >= MAX_HEADERS)
// goto bail;
llist_add_to_end(&list, xasprintf("To: %s", t));
argv++; argv++;
} }
// enter "put message" mode // enter "put message" mode
smtp_check("DATA", 354); // N.B. DATA fails iff no recipients were accepted (or even provided)
// in this case just bail out gracefully
if (354 != smtp_check("DATA", -1))
goto bail;
// dump the headers // dump the headers
while (list) { while (list) {
printf("%s\r\n", (char *) llist_pop(&list)); printf("%s\r\n", (char *) llist_pop(&list));
} }
printf("%s\r\n" + 2); // quirk for format string to be reused
// stop analyzing headers // stop analyzing headers
code++; code++;
// N.B. !s means: we read nothing, and nothing to be read in the future.
// just dump empty line and break the loop
if (!s) {
puts("\r");
break;
}
// go dump message body
// N.B. "s" already contains the first non-header line, so pretend we read it from input
goto dump;
} }
} }
// odd case: we didn't stop "analyze headers" mode -> message body is empty. Reenter the loop
// N.B. after reenter code will be > 0
if (!code)
goto reenter;
// finalize the message // finalize the message
smtp_check(".", 250); smtp_check(".", 250);
bail:
// ... and say goodbye // ... and say goodbye
smtp_check("QUIT", 221); smtp_check("QUIT", 221);
// cleanup // cleanup