aboutsummaryrefslogtreecommitdiff
path: root/mailutils/sendmail.c
diff options
context:
space:
mode:
Diffstat (limited to 'mailutils/sendmail.c')
-rw-r--r--mailutils/sendmail.c103
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
93static char *sane_address(char *str) 93static 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
112static 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
107static void rcptto(const char *s) 128static 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
138static 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
114int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 162int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
115int sendmail_main(int argc UNUSED_PARAM, char **argv) 163int 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