diff options
Diffstat (limited to 'mailutils/sendmail.c')
-rw-r--r-- | mailutils/sendmail.c | 103 |
1 files changed, 93 insertions, 10 deletions
diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index c426e9d85..b5aa1d17b 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c | |||
@@ -92,25 +92,73 @@ static int smtp_check(const char *fmt, int code) | |||
92 | // strip argument of bad chars | 92 | // strip argument of bad chars |
93 | static char *sane_address(char *str) | 93 | static char *sane_address(char *str) |
94 | { | 94 | { |
95 | char *s = str; | 95 | char *s; |
96 | char *p = s; | 96 | |
97 | trim(str); | ||
98 | s = str; | ||
97 | while (*s) { | 99 | while (*s) { |
98 | if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) { | 100 | if (!isalnum(*s) && !strchr("_-.@", *s)) { |
99 | *p++ = *s; | 101 | bb_error_msg("bad address '%s'", str); |
102 | /* returning "": */ | ||
103 | str[0] = '\0'; | ||
104 | return str; | ||
100 | } | 105 | } |
101 | s++; | 106 | s++; |
102 | } | 107 | } |
103 | *p = '\0'; | ||
104 | return str; | 108 | return str; |
105 | } | 109 | } |
106 | 110 | ||
111 | // check for an address inside angle brackets, if not found fall back to normal | ||
112 | static char *angle_address(char *str) | ||
113 | { | ||
114 | char *s, *e; | ||
115 | |||
116 | trim(str); | ||
117 | e = last_char_is(str, '>'); | ||
118 | if (e) { | ||
119 | s = strrchr(str, '<'); | ||
120 | if (s) { | ||
121 | *e = '\0'; | ||
122 | str = s + 1; | ||
123 | } | ||
124 | } | ||
125 | return sane_address(str); | ||
126 | } | ||
127 | |||
107 | static void rcptto(const char *s) | 128 | static void rcptto(const char *s) |
108 | { | 129 | { |
130 | if (!*s) | ||
131 | return; | ||
109 | // N.B. we don't die if recipient is rejected, for the other recipients may be accepted | 132 | // N.B. we don't die if recipient is rejected, for the other recipients may be accepted |
110 | if (250 != smtp_checkp("RCPT TO:<%s>", s, -1)) | 133 | if (250 != smtp_checkp("RCPT TO:<%s>", s, -1)) |
111 | bb_error_msg("Bad recipient: <%s>", s); | 134 | bb_error_msg("Bad recipient: <%s>", s); |
112 | } | 135 | } |
113 | 136 | ||
137 | // send to a list of comma separated addresses | ||
138 | static void rcptto_list(const char *list) | ||
139 | { | ||
140 | char *str = xstrdup(list); | ||
141 | char *s = str; | ||
142 | char prev = 0; | ||
143 | int in_quote = 0; | ||
144 | |||
145 | while (*s) { | ||
146 | char ch = *s++; | ||
147 | |||
148 | if (ch == '"' && prev != '\\') { | ||
149 | in_quote = !in_quote; | ||
150 | } else if (!in_quote && ch == ',') { | ||
151 | s[-1] = '\0'; | ||
152 | rcptto(angle_address(str)); | ||
153 | str = s; | ||
154 | } | ||
155 | prev = ch; | ||
156 | } | ||
157 | if (prev != ',') | ||
158 | rcptto(angle_address(str)); | ||
159 | free(str); | ||
160 | } | ||
161 | |||
114 | int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 162 | int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
115 | int sendmail_main(int argc UNUSED_PARAM, char **argv) | 163 | int sendmail_main(int argc UNUSED_PARAM, char **argv) |
116 | { | 164 | { |
@@ -121,6 +169,13 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) | |||
121 | char *host = sane_address(safe_gethostname()); | 169 | char *host = sane_address(safe_gethostname()); |
122 | unsigned nheaders = 0; | 170 | unsigned nheaders = 0; |
123 | int code; | 171 | int code; |
172 | enum { | ||
173 | HDR_OTHER = 0, | ||
174 | HDR_TOCC, | ||
175 | HDR_BCC, | ||
176 | } last_hdr = 0; | ||
177 | int check_hdr; | ||
178 | int has_to = 0; | ||
124 | 179 | ||
125 | enum { | 180 | enum { |
126 | //--- standard options | 181 | //--- standard options |
@@ -282,23 +337,36 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) | |||
282 | 337 | ||
283 | // analyze headers | 338 | // analyze headers |
284 | // To: or Cc: headers add recipients | 339 | // To: or Cc: headers add recipients |
340 | check_hdr = (0 == strncasecmp("To:", s, 3)); | ||
341 | has_to |= check_hdr; | ||
285 | if (opts & OPT_t) { | 342 | if (opts & OPT_t) { |
286 | if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { | 343 | if (check_hdr || 0 == strncasecmp("Bcc:" + 1, s, 3)) { |
287 | rcptto(sane_address(s+3)); | 344 | rcptto_list(s+3); |
345 | last_hdr = HDR_TOCC; | ||
288 | goto addheader; | 346 | goto addheader; |
289 | } | 347 | } |
290 | // Bcc: header adds blind copy (hidden) recipient | 348 | // Bcc: header adds blind copy (hidden) recipient |
291 | if (0 == strncasecmp("Bcc:", s, 4)) { | 349 | if (0 == strncasecmp("Bcc:", s, 4)) { |
292 | rcptto(sane_address(s+4)); | 350 | rcptto_list(s+4); |
293 | free(s); | 351 | free(s); |
352 | last_hdr = HDR_BCC; | ||
294 | continue; // N.B. Bcc: vanishes from headers! | 353 | continue; // N.B. Bcc: vanishes from headers! |
295 | } | 354 | } |
296 | } | 355 | } |
297 | if (strchr(s, ':') || (list && isspace(s[0]))) { | 356 | check_hdr = (list && isspace(s[0])); |
357 | if (strchr(s, ':') || check_hdr) { | ||
298 | // other headers go verbatim | 358 | // other headers go verbatim |
299 | // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. | 359 | // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. |
300 | // Continuation is denoted by prefixing additional lines with whitespace(s). | 360 | // Continuation is denoted by prefixing additional lines with whitespace(s). |
301 | // Thanks (stefan.seyfried at googlemail.com) for pointing this out. | 361 | // Thanks (stefan.seyfried at googlemail.com) for pointing this out. |
362 | if (check_hdr && last_hdr != HDR_OTHER) { | ||
363 | rcptto_list(s+1); | ||
364 | if (last_hdr == HDR_BCC) | ||
365 | continue; | ||
366 | // N.B. Bcc: vanishes from headers! | ||
367 | } else { | ||
368 | last_hdr = HDR_OTHER; | ||
369 | } | ||
302 | addheader: | 370 | addheader: |
303 | // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks | 371 | // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks |
304 | if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) | 372 | if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) |
@@ -309,12 +377,27 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) | |||
309 | // so stop "analyze headers" mode | 377 | // so stop "analyze headers" mode |
310 | reenter: | 378 | reenter: |
311 | // put recipients specified on cmdline | 379 | // put recipients specified on cmdline |
380 | check_hdr = 1; | ||
312 | while (*argv) { | 381 | while (*argv) { |
313 | char *t = sane_address(*argv); | 382 | char *t = sane_address(*argv); |
314 | rcptto(t); | 383 | rcptto(t); |
315 | //if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) | 384 | //if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) |
316 | // goto bail; | 385 | // goto bail; |
317 | llist_add_to_end(&list, xasprintf("To: %s", t)); | 386 | if (!has_to) { |
387 | const char *hdr; | ||
388 | |||
389 | if (check_hdr && argv[1]) | ||
390 | hdr = "To: %s,"; | ||
391 | else if (check_hdr) | ||
392 | hdr = "To: %s"; | ||
393 | else if (argv[1]) | ||
394 | hdr = "To: %s," + 3; | ||
395 | else | ||
396 | hdr = "To: %s" + 3; | ||
397 | llist_add_to_end(&list, | ||
398 | xasprintf(hdr, t)); | ||
399 | check_hdr = 0; | ||
400 | } | ||
318 | argv++; | 401 | argv++; |
319 | } | 402 | } |
320 | // enter "put message" mode | 403 | // enter "put message" mode |