Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/mailutils/sendmail.c
- Timestamp:
- Dec 20, 2016, 4:07:32 PM (7 years ago)
- Location:
- branches/3.3
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/3.3/mindi-busybox/mailutils/sendmail.c
r3232 r3621 16 16 //usage: "\nStandard options:" 17 17 //usage: "\n -t Read additional recipients from message body" 18 //usage: "\n -f SENDER Sender (required)" 18 //usage: "\n -f SENDER For use in MAIL FROM:<sender>. Can be empty string" 19 //usage: "\n Default: -auUSER, or username of current UID" 19 20 //usage: "\n -o OPTIONS Various options. -oi implied, others are ignored" 20 21 //usage: "\n -i -oi synonym. implied and ignored" … … 41 42 //usage: ) 42 43 44 /* Currently we don't sanitize or escape user-supplied SENDER and RECIPIENT_EMAILs. 45 * We may need to do so. For one, '.' in usernames seems to require escaping! 46 * 47 * From http://cr.yp.to/smtp/address.html: 48 * 49 * SMTP offers three ways to encode a character inside an address: 50 * 51 * "safe": the character, if it is not <>()[].,;:@, backslash, 52 * double-quote, space, or an ASCII control character; 53 * "quoted": the character, if it is not \012, \015, backslash, 54 * or double-quote; or 55 * "slashed": backslash followed by the character. 56 * 57 * An encoded box part is either (1) a sequence of one or more slashed 58 * or safe characters or (2) a double quote, a sequence of zero or more 59 * slashed or quoted characters, and a double quote. It represents 60 * the concatenation of the characters encoded inside it. 61 * 62 * For example, the encoded box parts 63 * angels 64 * \a\n\g\e\l\s 65 * "\a\n\g\e\l\s" 66 * "angels" 67 * "ang\els" 68 * all represent the 6-byte string "angels", and the encoded box parts 69 * a\,comma 70 * \a\,\c\o\m\m\a 71 * "a,comma" 72 * all represent the 7-byte string "a,comma". 73 * 74 * An encoded address contains 75 * the byte <; 76 * optionally, a route followed by a colon; 77 * an encoded box part, the byte @, and a domain; and 78 * the byte >. 79 * 80 * It represents an Internet mail address, given by concatenating 81 * the string represented by the encoded box part, the byte @, 82 * and the domain. For example, the encoded addresses 83 * <God@heaven.af.mil> 84 * <\God@heaven.af.mil> 85 * <"God"@heaven.af.mil> 86 * <@gateway.af.mil,@uucp.local:"\G\o\d"@heaven.af.mil> 87 * all represent the Internet mail address "God@heaven.af.mil". 88 */ 89 43 90 #include "libbb.h" 44 91 #include "mail.h" … … 93 140 static char *sane_address(char *str) 94 141 { 95 char *s = str; 96 char *p = s; 142 char *s; 143 144 trim(str); 145 s = str; 97 146 while (*s) { 98 if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) { 99 *p++ = *s; 147 if (!isalnum(*s) && !strchr("_-.@", *s)) { 148 bb_error_msg("bad address '%s'", str); 149 /* returning "": */ 150 str[0] = '\0'; 151 return str; 100 152 } 101 153 s++; 102 154 } 103 *p = '\0';104 155 return str; 105 156 } 106 157 158 // check for an address inside angle brackets, if not found fall back to normal 159 static char *angle_address(char *str) 160 { 161 char *s, *e; 162 163 trim(str); 164 e = last_char_is(str, '>'); 165 if (e) { 166 s = strrchr(str, '<'); 167 if (s) { 168 *e = '\0'; 169 str = s + 1; 170 } 171 } 172 return sane_address(str); 173 } 174 107 175 static void rcptto(const char *s) 108 176 { 177 if (!*s) 178 return; 109 179 // N.B. we don't die if recipient is rejected, for the other recipients may be accepted 110 180 if (250 != smtp_checkp("RCPT TO:<%s>", s, -1)) … … 112 182 } 113 183 184 // send to a list of comma separated addresses 185 static void rcptto_list(const char *list) 186 { 187 char *str = xstrdup(list); 188 char *s = str; 189 char prev = 0; 190 int in_quote = 0; 191 192 while (*s) { 193 char ch = *s++; 194 195 if (ch == '"' && prev != '\\') { 196 in_quote = !in_quote; 197 } else if (!in_quote && ch == ',') { 198 s[-1] = '\0'; 199 rcptto(angle_address(str)); 200 str = s; 201 } 202 prev = ch; 203 } 204 if (prev != ',') 205 rcptto(angle_address(str)); 206 free(str); 207 } 208 114 209 int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 115 210 int sendmail_main(int argc UNUSED_PARAM, char **argv) 116 211 { 117 212 char *opt_connect = opt_connect; 118 char *opt_from ;213 char *opt_from = NULL; 119 214 char *s; 120 215 llist_t *list = NULL; … … 122 217 unsigned nheaders = 0; 123 218 int code; 219 enum { 220 HDR_OTHER = 0, 221 HDR_TOCC, 222 HDR_BCC, 223 } last_hdr = 0; 224 int check_hdr; 225 int has_to = 0; 124 226 125 227 enum { … … 145 247 146 248 // parse options 147 // -v is a counter, - f is required. -H and -S are mutually exclusive, -a is a list148 opt_complementary = "vv: f:w+:H--S:S--H:a::";249 // -v is a counter, -H and -S are mutually exclusive, -a is a list 250 opt_complementary = "vv:w+:H--S:S--H:a::"; 149 251 // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect 150 252 // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility, … … 169 271 } 170 272 // N.B. list == NULL here 171 //bb_ info_msg("OPT[%x] AU[%s], AP[%s], AM[%s], ARGV[%s]", opts, au, ap, am, *argv);273 //bb_error_msg("OPT[%x] AU[%s], AP[%s], AM[%s], ARGV[%s]", opts, au, ap, am, *argv); 172 274 173 275 // connect to server … … 225 327 if (250 != smtp_checkp("EHLO %s", host, -1)) 226 328 smtp_checkp("HELO %s", host, 250); 227 free(host);228 329 229 330 // perform authentication … … 250 351 // file descriptor (e.g. 4), or again from a secured file. 251 352 252 // got no sender address? -> use system username as a resort 253 // N.B. we marked -f as required option! 254 //if (!G.user) { 255 // // N.B. IMHO getenv("USER") can be way easily spoofed! 256 // G.user = xuid2uname(getuid()); 257 // opt_from = xasprintf("%s@%s", G.user, domain); 258 //} 353 // got no sender address? use auth name, then UID username as a last resort 354 if (!opt_from) { 355 opt_from = xasprintf("%s@%s", 356 G.user ? G.user : xuid2uname(getuid()), 357 xgethostbyname(host)->h_name); 358 } 359 free(host); 360 259 361 smtp_checkp("MAIL FROM:<%s>", opt_from, 250); 260 362 … … 274 376 // whether it is single or not character on the line 275 377 if ('.' == s[0] /*&& '\0' == s[1] */) 276 printf(".");378 bb_putchar('.'); 277 379 // dump read line 278 380 send_r_n(s); … … 283 385 // analyze headers 284 386 // To: or Cc: headers add recipients 387 check_hdr = (0 == strncasecmp("To:", s, 3)); 388 has_to |= check_hdr; 285 389 if (opts & OPT_t) { 286 if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { 287 rcptto(sane_address(s+3)); 390 if (check_hdr || 0 == strncasecmp("Bcc:" + 1, s, 3)) { 391 rcptto_list(s+3); 392 last_hdr = HDR_TOCC; 288 393 goto addheader; 289 394 } 290 395 // Bcc: header adds blind copy (hidden) recipient 291 396 if (0 == strncasecmp("Bcc:", s, 4)) { 292 rcptto (sane_address(s+4));397 rcptto_list(s+4); 293 398 free(s); 399 last_hdr = HDR_BCC; 294 400 continue; // N.B. Bcc: vanishes from headers! 295 401 } 296 402 } 297 if (strchr(s, ':') || (list && isspace(s[0]))) { 403 check_hdr = (list && isspace(s[0])); 404 if (strchr(s, ':') || check_hdr) { 298 405 // other headers go verbatim 299 406 // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. 300 407 // Continuation is denoted by prefixing additional lines with whitespace(s). 301 408 // Thanks (stefan.seyfried at googlemail.com) for pointing this out. 409 if (check_hdr && last_hdr != HDR_OTHER) { 410 rcptto_list(s+1); 411 if (last_hdr == HDR_BCC) 412 continue; 413 // N.B. Bcc: vanishes from headers! 414 } else { 415 last_hdr = HDR_OTHER; 416 } 302 417 addheader: 303 418 // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks … … 310 425 reenter: 311 426 // put recipients specified on cmdline 427 check_hdr = 1; 312 428 while (*argv) { 313 429 char *t = sane_address(*argv); … … 315 431 //if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) 316 432 // goto bail; 317 llist_add_to_end(&list, xasprintf("To: %s", t)); 433 if (!has_to) { 434 const char *hdr; 435 436 if (check_hdr && argv[1]) 437 hdr = "To: %s,"; 438 else if (check_hdr) 439 hdr = "To: %s"; 440 else if (argv[1]) 441 hdr = "To: %s," + 3; 442 else 443 hdr = "To: %s" + 3; 444 llist_add_to_end(&list, 445 xasprintf(hdr, t)); 446 check_hdr = 0; 447 } 318 448 argv++; 319 449 }
Note:
See TracChangeset
for help on using the changeset viewer.