Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/mailutils/sendmail.c
- Timestamp:
- Jan 1, 2014, 12:47:38 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3.2/mindi-busybox/mailutils/sendmail.c
r2725 r3232 7 7 * Licensed under GPLv2, see file LICENSE in this source tree. 8 8 */ 9 10 //kbuild:lib-$(CONFIG_SENDMAIL) += sendmail.o mail.o 11 12 //usage:#define sendmail_trivial_usage 13 //usage: "[OPTIONS] [RECIPIENT_EMAIL]..." 14 //usage:#define sendmail_full_usage "\n\n" 15 //usage: "Read email from stdin and send it\n" 16 //usage: "\nStandard options:" 17 //usage: "\n -t Read additional recipients from message body" 18 //usage: "\n -f SENDER Sender (required)" 19 //usage: "\n -o OPTIONS Various options. -oi implied, others are ignored" 20 //usage: "\n -i -oi synonym. implied and ignored" 21 //usage: "\n" 22 //usage: "\nBusybox specific options:" 23 //usage: "\n -v Verbose" 24 //usage: "\n -w SECS Network timeout" 25 //usage: "\n -H 'PROG ARGS' Run connection helper" 26 //usage: "\n Examples:" 27 //usage: "\n -H 'exec openssl s_client -quiet -tls1 -starttls smtp" 28 //usage: "\n -connect smtp.gmail.com:25' <email.txt" 29 //usage: "\n [4<username_and_passwd.txt | -auUSER -apPASS]" 30 //usage: "\n -H 'exec openssl s_client -quiet -tls1" 31 //usage: "\n -connect smtp.gmail.com:465' <email.txt" 32 //usage: "\n [4<username_and_passwd.txt | -auUSER -apPASS]" 33 //usage: "\n -S HOST[:PORT] Server" 34 //usage: "\n -auUSER Username for AUTH LOGIN" 35 //usage: "\n -apPASS Password for AUTH LOGIN" 36 ////usage: "\n -amMETHOD Authentication method. Ignored. LOGIN is implied" 37 //usage: "\n" 38 //usage: "\nOther options are silently ignored; -oi -t is implied" 39 //usage: IF_MAKEMIME( 40 //usage: "\nUse makemime to create emails with attachments" 41 //usage: ) 42 9 43 #include "libbb.h" 10 44 #include "mail.h" … … 14 48 #define MAX_HEADERS 256 15 49 50 static void send_r_n(const char *s) 51 { 52 if (verbose) 53 bb_error_msg("send:'%s'", s); 54 printf("%s\r\n", s); 55 } 56 16 57 static int smtp_checkp(const char *fmt, const char *param, int code) 17 58 { 18 59 char *answer; 19 c onst char *msg =command(fmt, param);60 char *msg = send_mail_command(fmt, param); 20 61 // read stdin 21 // if the string has a form \d\d\d- -- read next string. E.g. EHLO response62 // if the string has a form NNN- -- read next string. E.g. EHLO response 22 63 // parse first bytes to a number 23 64 // if code = -1 then just return this number 24 65 // if code != -1 then checks whether the number equals the code 25 66 // if not equal -> die saying msg 26 while ((answer = xmalloc_fgetline(stdin)) != NULL) 67 while ((answer = xmalloc_fgetline(stdin)) != NULL) { 68 if (verbose) 69 bb_error_msg("recv:'%.*s'", (int)(strchrnul(answer, '\r') - answer), answer); 27 70 if (strlen(answer) <= 3 || '-' != answer[3]) 28 71 break; 72 free(answer); 73 } 29 74 if (answer) { 30 75 int n = atoi(answer); … … 32 77 alarm(0); 33 78 free(answer); 34 if (-1 == code || n == code) 79 if (-1 == code || n == code) { 80 free(msg); 35 81 return n; 82 } 36 83 } 37 84 bb_error_msg_and_die("%s failed", msg); … … 72 119 char *s; 73 120 llist_t *list = NULL; 74 char * domain = sane_address(safe_getdomainname());121 char *host = sane_address(safe_gethostname()); 75 122 unsigned nheaders = 0; 76 123 int code; … … 87 134 OPT_S = 1 << 6, // specify connection string 88 135 OPT_a = 1 << 7, // authentication tokens 136 OPT_v = 1 << 8, // verbosity 89 137 }; 90 138 … … 97 145 98 146 // parse options 99 // - f is required. -H and -S are mutually exclusive100 opt_complementary = " f:w+:H--S:S--H:a::";147 // -v is a counter, -f is required. -H and -S are mutually exclusive, -a is a list 148 opt_complementary = "vv:f:w+:H--S:S--H:a::"; 101 149 // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect 102 150 // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility, 103 151 // it is still under development. 104 opts = getopt32(argv, "tf:o:iw:H:S:a::", &opt_from, NULL, &timeout, &opt_connect, &opt_connect, &list); 152 opts = getopt32(argv, "tf:o:iw:H:S:a::v", &opt_from, NULL, 153 &timeout, &opt_connect, &opt_connect, &list, &verbose); 105 154 //argc -= optind; 106 155 argv += optind; … … 129 178 // plug it in 130 179 launch_helper(args); 131 // vanilla connection 180 // Now: 181 // our stdout will go to helper's stdin, 182 // helper's stdout will be available on our stdin. 183 184 // Wait for initial server message. 185 // If helper (such as openssl) invokes STARTTLS, the initial 220 186 // is swallowed by helper (and not repeated after TLS is initiated). 187 // We will send NOOP cmd to server and check the response. 188 // We should get 220+250 on plain connection, 250 on STARTTLSed session. 189 // 190 // The problem here is some servers delay initial 220 message, 191 // and consider client to be a spammer if it starts sending cmds 192 // before 220 reached it. The code below is unsafe in this regard: 193 // in non-STARTTLSed case, we potentially send NOOP before 220 194 // is sent by server. 195 // Ideas? (--delay SECS opt? --assume-starttls-helper opt?) 196 code = smtp_check("NOOP", -1); 197 if (code == 220) 198 // we got 220 - this is not STARTTLSed connection, 199 // eat 250 response to our NOOP 200 smtp_check(NULL, 250); 201 else 202 if (code != 250) 203 bb_error_msg_and_die("SMTP init failed"); 132 204 } else { 205 // vanilla connection 133 206 int fd; 134 207 // host[:port] not explicitly specified? -> use $SMTPHOST 135 // no $SMTPHOST 208 // no $SMTPHOST? -> use localhost 136 209 if (!(opts & OPT_S)) { 137 210 opt_connect = getenv("SMTPHOST"); … … 144 217 xmove_fd(fd, STDIN_FILENO); 145 218 xdup2(STDIN_FILENO, STDOUT_FILENO); 146 } 147 // N.B. from now we know nothing about network :) 148 149 // wait for initial server OK 150 // N.B. if we used openssl the initial 220 answer is already swallowed during openssl TLS init procedure 151 // so we need to kick the server to see whether we are ok 152 code = smtp_check("NOOP", -1); 153 // 220 on plain connection, 250 on openssl-helped TLS session 154 if (220 == code) 155 smtp_check(NULL, 250); // reread the code to stay in sync 156 else if (250 != code) 157 bb_error_msg_and_die("INIT failed"); 219 220 // Wait for initial server 220 message 221 smtp_check(NULL, 220); 222 } 158 223 159 224 // we should start with modern EHLO 160 if (250 != smtp_checkp("EHLO %s", domain, -1)) { 161 smtp_checkp("HELO %s", domain, 250); 162 } 163 if (ENABLE_FEATURE_CLEAN_UP) 164 free(domain); 225 if (250 != smtp_checkp("EHLO %s", host, -1)) 226 smtp_checkp("HELO %s", host, 250); 227 free(host); 165 228 166 229 // perform authentication … … 177 240 178 241 // set sender 179 // N.B. we have here a very loosely defined algo tythm242 // N.B. we have here a very loosely defined algorythm 180 243 // since sendmail historically offers no means to specify secrets on cmdline. 181 244 // 1) server can require no authentication -> … … 194 257 // opt_from = xasprintf("%s@%s", G.user, domain); 195 258 //} 196 //if (ENABLE_FEATURE_CLEAN_UP)197 // free(domain);198 259 smtp_checkp("MAIL FROM:<%s>", opt_from, 250); 199 260 … … 215 276 printf("."); 216 277 // dump read line 217 printf("%s\r\n",s);278 send_r_n(s); 218 279 free(s); 219 280 continue; … … 222 283 // analyze headers 223 284 // To: or Cc: headers add recipients 224 if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { 225 rcptto(sane_address(s+3)); 226 goto addheader; 227 // Bcc: header adds blind copy (hidden) recipient 228 } else if (0 == strncasecmp("Bcc:", s, 4)) { 229 rcptto(sane_address(s+4)); 230 free(s); 231 // N.B. Bcc: vanishes from headers! 232 233 // other headers go verbatim 234 235 // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. 236 // Continuation is denoted by prefixing additional lines with whitespace(s). 237 // Thanks (stefan.seyfried at googlemail.com) for pointing this out. 238 } else if (strchr(s, ':') || (list && skip_whitespace(s) != s)) { 285 if (opts & OPT_t) { 286 if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) { 287 rcptto(sane_address(s+3)); 288 goto addheader; 289 } 290 // Bcc: header adds blind copy (hidden) recipient 291 if (0 == strncasecmp("Bcc:", s, 4)) { 292 rcptto(sane_address(s+4)); 293 free(s); 294 continue; // N.B. Bcc: vanishes from headers! 295 } 296 } 297 if (strchr(s, ':') || (list && isspace(s[0]))) { 298 // other headers go verbatim 299 // 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). 301 // Thanks (stefan.seyfried at googlemail.com) for pointing this out. 239 302 addheader: 240 303 // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks … … 242 305 goto bail; 243 306 llist_add_to_end(&list, s); 244 // a line without ":" (an empty line too, by definition) doesn't look like a valid header245 // so stop "analyze headers" mode246 307 } else { 308 // a line without ":" (an empty line too, by definition) doesn't look like a valid header 309 // so stop "analyze headers" mode 247 310 reenter: 248 311 // put recipients specified on cmdline … … 262 325 // dump the headers 263 326 while (list) { 264 printf("%s\r\n",(char *) llist_pop(&list));327 send_r_n((char *) llist_pop(&list)); 265 328 } 266 329 // stop analyzing headers … … 269 332 // just dump empty line and break the loop 270 333 if (!s) { 271 puts("\r");334 send_r_n(""); 272 335 break; 273 336 }
Note:
See TracChangeset
for help on using the changeset viewer.