diff options
-rw-r--r-- | include/usage.h | 16 | ||||
-rw-r--r-- | networking/sendmail.c | 356 |
2 files changed, 215 insertions, 157 deletions
diff --git a/include/usage.h b/include/usage.h index 6b54a1266..e9770cea9 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -1026,17 +1026,19 @@ USE_FEATURE_BRCTL_FANCY("\n" \ | |||
1026 | " -v Give fdisk version" | 1026 | " -v Give fdisk version" |
1027 | 1027 | ||
1028 | #define fetchmail_trivial_usage \ | 1028 | #define fetchmail_trivial_usage \ |
1029 | "[-C dir] [-w timeout] [-U user] -P password [-X] [-t] [-z] server[:port]" | 1029 | "[-w timeout] [-U user] -P password [-X] [-t] [-z] server[:port] maildir [prog]" |
1030 | #define fetchmail_full_usage \ | 1030 | #define fetchmail_full_usage \ |
1031 | "Fetch content of remote mailbox to local Maildir." \ | 1031 | "Fetch content of remote mailbox to local Maildir." \ |
1032 | "\n\nOptions:\n" \ | 1032 | "\n\nOptions:\n" \ |
1033 | " -C dir Set Maildir location\n" \ | ||
1034 | " -w timeout Set timeout on network operations\n" \ | 1033 | " -w timeout Set timeout on network operations\n" \ |
1035 | " -U username Authenticate with specified username\n" \ | 1034 | " -U username Authenticate with specified username\n" \ |
1036 | " -P password Authenticate with specified password\n" \ | 1035 | " -P password Authenticate with specified password\n" \ |
1037 | " -X Use openssl connection helper for secured servers\n" \ | 1036 | " -X Use openssl connection helper for secured servers\n" \ |
1038 | " -t Get only headers\n" \ | 1037 | " -t Get only headers\n" \ |
1039 | " -z Delete messages on server" | 1038 | " -z Delete messages on server" \ |
1039 | USE_FEATURE_FETCHMAIL_FILTER("\n" \ | ||
1040 | " prog Run prog <message file> on message delivery" \ | ||
1041 | ) | ||
1040 | 1042 | ||
1041 | #define findfs_trivial_usage \ | 1043 | #define findfs_trivial_usage \ |
1042 | "LABEL=label or UUID=uuid" | 1044 | "LABEL=label or UUID=uuid" |
@@ -3258,18 +3260,16 @@ USE_FEATURE_RUN_PARTS_FANCY("\n -l Prints names of all matching files even when | |||
3258 | #define selinuxenabled_full_usage | 3260 | #define selinuxenabled_full_usage |
3259 | 3261 | ||
3260 | #define sendmail_trivial_usage \ | 3262 | #define sendmail_trivial_usage \ |
3261 | "[-C dir] [-w timeout] [-U user] [-P password] [-X]\n" \ | 3263 | "[-w timeout] [-U user] [-P password] [-X]\n" \ |
3262 | "-t to [-t to] -f from [-n] [-s subject] [-c charset] server[:port] [body] [attachment ...]" | 3264 | "-t to [-t to]... [-n] [-s subject] [-c charset] server[:port] from [body] [attachment ...]" |
3263 | #define sendmail_full_usage \ | 3265 | #define sendmail_full_usage \ |
3264 | "Send an email with optional attachments." \ | 3266 | "Send an email with optional attachments." \ |
3265 | "\n\nOptions:\n" \ | 3267 | "\n\nOptions:\n" \ |
3266 | " -C dir Change current directory to dir\n" \ | ||
3267 | " -w timeout Set timeout on network operations\n" \ | 3268 | " -w timeout Set timeout on network operations\n" \ |
3268 | " -U username Authenticate with specified username\n" \ | 3269 | " -U username Authenticate with specified username\n" \ |
3269 | " -P password Authenticate with specified password\n" \ | 3270 | " -P password Authenticate with specified password\n" \ |
3271 | " -t address Recipient(s). May be multiple\n" \ | ||
3270 | " -X Use openssl connection helper for secured servers\n" \ | 3272 | " -X Use openssl connection helper for secured servers\n" \ |
3271 | " -t to Recipient email. May be multiple\n" \ | ||
3272 | " -f from Sender address\n" \ | ||
3273 | " -n Request delivery notification to sender\n" \ | 3273 | " -n Request delivery notification to sender\n" \ |
3274 | " -s subject Subject\n" \ | 3274 | " -s subject Subject\n" \ |
3275 | " -c charset Assumed charset for body and subject [utf-8]" | 3275 | " -c charset Assumed charset for body and subject [utf-8]" |
diff --git a/networking/sendmail.c b/networking/sendmail.c index b2fbc5a7a..adc6c7626 100644 --- a/networking/sendmail.c +++ b/networking/sendmail.c | |||
@@ -27,9 +27,13 @@ static void uuencode(char *fname, const char *text) | |||
27 | if (NOT_LONE_DASH(fname)) | 27 | if (NOT_LONE_DASH(fname)) |
28 | fd = xopen(fname, O_RDONLY); | 28 | fd = xopen(fname, O_RDONLY); |
29 | src_buf = bb_common_bufsiz1; | 29 | src_buf = bb_common_bufsiz1; |
30 | } else { | 30 | // N.B. strlen(NULL) segfaults! |
31 | } else if (text) { | ||
32 | // though we do not call uuencode(NULL, NULL) explicitly | ||
33 | // still we do not want to break things suddenly | ||
31 | len = strlen(text); | 34 | len = strlen(text); |
32 | } | 35 | } else |
36 | return; | ||
33 | 37 | ||
34 | fflush(stdout); // sync stdio and unistd output | 38 | fflush(stdout); // sync stdio and unistd output |
35 | while (1) { | 39 | while (1) { |
@@ -59,7 +63,38 @@ static void uuencode(char *fname, const char *text) | |||
59 | close(fd); | 63 | close(fd); |
60 | } | 64 | } |
61 | 65 | ||
62 | static pid_t helper_pid; | 66 | static const char *const init_xargs[9] = { |
67 | "openssl", "s_client", "-quiet", "-connect", | ||
68 | NULL, "-tls1", "-starttls", "smtp" | ||
69 | }; | ||
70 | |||
71 | struct globals { | ||
72 | pid_t helper_pid; | ||
73 | unsigned timeout; | ||
74 | // arguments for SSL connection helper | ||
75 | const char *xargs[9]; | ||
76 | #if ENABLE_FEATURE_FETCHMAIL_FILTER | ||
77 | // arguments for postprocess helper | ||
78 | const char *fargs[3]; | ||
79 | #endif | ||
80 | }; | ||
81 | #define G (*ptr_to_globals) | ||
82 | #define helper_pid (G.helper_pid) | ||
83 | #define timeout (G.timeout ) | ||
84 | #define xargs (G.xargs ) | ||
85 | #define fargs (G.fargs ) | ||
86 | #define INIT_G() do { \ | ||
87 | PTR_TO_GLOBALS = xzalloc(sizeof(G)); \ | ||
88 | memcpy(xargs, init_xargs, sizeof(init_xargs)); \ | ||
89 | fargs[0] = "utf-8"; \ | ||
90 | } while (0) | ||
91 | |||
92 | #define opt_connect (xargs[4]) | ||
93 | #define opt_after_connect (xargs[5]) | ||
94 | #if ENABLE_FEATURE_FETCHMAIL_FILTER | ||
95 | #define opt_charset (fargs[0]) | ||
96 | #define opt_subject (fargs[1]) | ||
97 | #endif | ||
63 | 98 | ||
64 | static void kill_helper(void) | 99 | static void kill_helper(void) |
65 | { | 100 | { |
@@ -71,7 +106,7 @@ static void kill_helper(void) | |||
71 | // generic signal handler | 106 | // generic signal handler |
72 | static void signal_handler(int signo) | 107 | static void signal_handler(int signo) |
73 | { | 108 | { |
74 | int err; | 109 | #define err signo |
75 | 110 | ||
76 | if (SIGALRM == signo) { | 111 | if (SIGALRM == signo) { |
77 | kill_helper(); | 112 | kill_helper(); |
@@ -107,20 +142,19 @@ static void launch_helper(const char **argv) | |||
107 | close(pipes[i]); | 142 | close(pipes[i]); |
108 | if (!helper_pid) { | 143 | if (!helper_pid) { |
109 | // child - try to execute connection helper | 144 | // child - try to execute connection helper |
110 | BB_EXECVP(argv[0], (char **)argv); | 145 | // close(STDERR_FILENO); |
146 | BB_EXECVP(*argv, (char **)argv); | ||
111 | _exit(127); | 147 | _exit(127); |
112 | } | 148 | } |
113 | // parent - check whether child is alive | 149 | // parent - check whether child is alive |
114 | bb_signals_recursive(0 | 150 | bb_signals(0 |
115 | + (1 << SIGCHLD) | 151 | + (1 << SIGCHLD) |
116 | + (1 << SIGALRM) | 152 | + (1 << SIGALRM) |
117 | , signal_handler); | 153 | , signal_handler); |
118 | signal_handler(SIGCHLD); | 154 | signal_handler(SIGCHLD); |
119 | // child seems OK -> parent goes on | 155 | // child seems OK -> parent goes on |
120 | } | 156 | } |
121 | 157 | ||
122 | static unsigned timeout; | ||
123 | |||
124 | static char *command(const char *fmt, const char *param) | 158 | static char *command(const char *fmt, const char *param) |
125 | { | 159 | { |
126 | char *msg = (char *)fmt; | 160 | char *msg = (char *)fmt; |
@@ -145,7 +179,9 @@ static int smtp_checkp(const char *fmt, const char *param, int code) | |||
145 | // if code != -1 then checks whether the number equals the code | 179 | // if code != -1 then checks whether the number equals the code |
146 | // if not equal -> die saying msg | 180 | // if not equal -> die saying msg |
147 | #if ENABLE_FEATURE_SENDMAIL_EHLO | 181 | #if ENABLE_FEATURE_SENDMAIL_EHLO |
148 | while ((answer = xmalloc_getline(stdin)) && '-' == answer[3]) ; | 182 | while ((answer = xmalloc_getline(stdin)) != NULL) |
183 | if (strlen(answer) <= 3 || '-' != answer[3]) | ||
184 | break; | ||
149 | #else | 185 | #else |
150 | answer = xmalloc_getline(stdin); | 186 | answer = xmalloc_getline(stdin); |
151 | #endif | 187 | #endif |
@@ -169,15 +205,31 @@ static int smtp_check(const char *fmt, int code) | |||
169 | return smtp_checkp(fmt, NULL, code); | 205 | return smtp_checkp(fmt, NULL, code); |
170 | } | 206 | } |
171 | 207 | ||
208 | // strip argument of bad chars | ||
209 | static char *sane(char *str) | ||
210 | { | ||
211 | char *s = str; | ||
212 | char *p = s; | ||
213 | while (*s) { | ||
214 | if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) { | ||
215 | *p++ = *s; | ||
216 | } | ||
217 | s++; | ||
218 | } | ||
219 | *p = '\0'; | ||
220 | return str; | ||
221 | } | ||
222 | |||
223 | #if ENABLE_FETCHMAIL | ||
172 | static void pop3_checkr(const char *fmt, const char *param, char **ret) | 224 | static void pop3_checkr(const char *fmt, const char *param, char **ret) |
173 | { | 225 | { |
174 | char *msg = command(fmt, param); | 226 | char *msg = command(fmt, param); |
175 | char *answer = xmalloc_getline(stdin); | 227 | char *answer = xmalloc_getline(stdin); |
176 | if (answer && '+' == answer[0]) { | 228 | if (answer && '+' == *answer) { |
177 | alarm(0); | 229 | alarm(0); |
178 | if (ret) | 230 | if (ret) |
179 | *ret = answer; | 231 | *ret = answer+4; // skip "+OK " |
180 | else | 232 | else if (ENABLE_FEATURE_CLEAN_UP) |
181 | free(answer); | 233 | free(answer); |
182 | return; | 234 | return; |
183 | } | 235 | } |
@@ -190,28 +242,16 @@ static void pop3_check(const char *fmt, const char *param) | |||
190 | pop3_checkr(fmt, param, NULL); | 242 | pop3_checkr(fmt, param, NULL); |
191 | } | 243 | } |
192 | 244 | ||
193 | // strip argument of bad chars | 245 | static void pop3_message(const char *filename) |
194 | static char *sane(char *str) | ||
195 | { | ||
196 | char *s = str; | ||
197 | char *p = s; | ||
198 | while (*s) { | ||
199 | if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) { | ||
200 | *p++ = *s; | ||
201 | } | ||
202 | s++; | ||
203 | } | ||
204 | *p = '\0'; | ||
205 | return str; | ||
206 | } | ||
207 | |||
208 | static void pop3_message(int fd) | ||
209 | { | 246 | { |
247 | int fd; | ||
210 | char *answer; | 248 | char *answer; |
211 | // read stdin, copy to file fd | 249 | // create and open file filename |
250 | // read stdin, copy to created file | ||
251 | fd = xopen(filename, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL); | ||
212 | while ((answer = xmalloc_fgets_str(stdin, "\r\n"))) { | 252 | while ((answer = xmalloc_fgets_str(stdin, "\r\n"))) { |
213 | char *s = answer; | 253 | char *s = answer; |
214 | if ('.' == answer[0]) { | 254 | if ('.' == *answer) { |
215 | if ('.' == answer[1]) | 255 | if ('.' == answer[1]) |
216 | s++; | 256 | s++; |
217 | else if ('\r' == answer[1] && '\n' == answer[2] && '\0' == answer[3]) | 257 | else if ('\r' == answer[1] && '\n' == answer[2] && '\0' == answer[3]) |
@@ -222,64 +262,56 @@ static void pop3_message(int fd) | |||
222 | } | 262 | } |
223 | close(fd); | 263 | close(fd); |
224 | } | 264 | } |
225 | 265 | #endif | |
226 | static const char *args[] = { | ||
227 | "openssl", "s_client", "-quiet", "-connect", NULL, "-tls1", "-starttls", "smtp", NULL | ||
228 | }; | ||
229 | #define opt_connect args[4] | ||
230 | #define opt_after_connect args[5] | ||
231 | 266 | ||
232 | int sendgetmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 267 | int sendgetmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
233 | int sendgetmail_main(int argc, char **argv) | 268 | int sendgetmail_main(int argc, char **argv) |
234 | { | 269 | { |
235 | llist_t *recipients = NULL; | 270 | llist_t *opt_recipients = NULL; |
236 | char *from; | 271 | #if !ENABLE_FEATURE_FETCHMAIL_FILTER |
237 | const char *subject; | 272 | char *opt_subject; |
238 | char *charset = (char *)"utf-8"; | 273 | char *opt_charset = (char *)"utf-8"; |
274 | #endif | ||
239 | 275 | ||
240 | const char *opt_user; | 276 | const char *opt_user; |
241 | const char *opt_pass; | 277 | const char *opt_pass; |
242 | const char *opt_timeout; | ||
243 | const char *opt_chdir; | ||
244 | 278 | ||
245 | enum { | 279 | enum { |
246 | OPT_C = 1 << 0, // chdir | 280 | OPT_w = 1 << 0, // network timeout |
247 | OPT_w = 1 << 1, // network timeout | 281 | OPT_U = 1 << 1, // user |
248 | OPT_U = 1 << 2, // user | 282 | OPT_P = 1 << 2, // password |
249 | OPT_P = 1 << 3, // password | 283 | OPT_X = 1 << 3, // connect using openssl s_client helper |
250 | OPT_X = 1 << 4, // use openssl connection helper | ||
251 | 284 | ||
252 | OPTS_t = 1 << 5, // sendmail "to" | 285 | OPTS_n = 1 << 4, // sendmail: request notification |
253 | OPTF_t = 1 << 5, // fetchmail "TOP" | 286 | OPTF_t = 1 << 4, // fetchmail: use "TOP" not "RETR" |
254 | 287 | ||
255 | OPTS_f = 1 << 6, // sendmail "from" | 288 | OPTS_s = 1 << 5, // sendmail: subject |
256 | OPTF_z = 1 << 6, // fetchmail "delete" | 289 | OPTF_z = 1 << 5, // fetchmail: delete from server |
257 | 290 | ||
258 | OPTS_n = 1 << 7, // notification | 291 | OPTS_c = 1 << 6, // sendmail: assumed charset |
259 | OPTS_s = 1 << 8, // subject given | 292 | OPTS_t = 1 << 7, // sendmail: recipient(s) |
260 | OPTS_c = 1 << 9, // charset for subject and body | ||
261 | }; | 293 | }; |
262 | 294 | ||
263 | const char *options; | 295 | const char *options; |
264 | unsigned opts; | 296 | unsigned opts; |
265 | 297 | ||
266 | // SENDMAIL | 298 | INIT_G(); |
267 | if ('s' == applet_name[0]) { | 299 | |
268 | // save initial stdin | 300 | if (!ENABLE_FETCHMAIL || 's' == applet_name[0]) { |
301 | // SENDMAIL | ||
302 | // save initial stdin (body or attachements can be piped!) | ||
269 | xdup2(STDIN_FILENO, INITIAL_STDIN_FILENO); | 303 | xdup2(STDIN_FILENO, INITIAL_STDIN_FILENO); |
270 | // -f must be specified | 304 | opt_complementary = "-2:w+:t:t::"; // count(-t) > 0 |
271 | // -t may be multiple | 305 | options = "w:U:P:X" "ns:c:t:"; |
272 | opt_complementary = "-1:f:t::"; | ||
273 | options = "C:w:U:P:X" "t:f:ns:c:"; | ||
274 | // FETCHMAIL | ||
275 | } else { | 306 | } else { |
307 | // FETCHMAIL | ||
276 | opt_after_connect = NULL; | 308 | opt_after_connect = NULL; |
277 | opt_complementary = "=1:P"; | 309 | opt_complementary = "-2:w+:P"; |
278 | options = "C:w:U:P:X" "tz"; | 310 | options = "w:U:P:X" "tz"; |
279 | } | 311 | } |
280 | opts = getopt32(argv, options, | 312 | opts = getopt32(argv, options, |
281 | &opt_chdir, &opt_timeout, &opt_user, &opt_pass, | 313 | &timeout, &opt_user, &opt_pass, |
282 | &recipients, &from, &subject, &charset | 314 | &opt_subject, &opt_charset, &opt_recipients |
283 | ); | 315 | ); |
284 | 316 | ||
285 | //argc -= optind; | 317 | //argc -= optind; |
@@ -288,16 +320,9 @@ int sendgetmail_main(int argc, char **argv) | |||
288 | // first argument is remote server[:port] | 320 | // first argument is remote server[:port] |
289 | opt_connect = *argv++; | 321 | opt_connect = *argv++; |
290 | 322 | ||
291 | if (opts & OPT_w) | ||
292 | timeout = xatou(opt_timeout); | ||
293 | |||
294 | // chdir | ||
295 | if (opts & OPT_C) | ||
296 | xchdir(opt_chdir); | ||
297 | |||
298 | // connect to server | 323 | // connect to server |
299 | if (opts & OPT_X) { | 324 | if (opts & OPT_X) { |
300 | launch_helper(args); | 325 | launch_helper(xargs); |
301 | } else { | 326 | } else { |
302 | // no connection helper provided -> make plain connect | 327 | // no connection helper provided -> make plain connect |
303 | int fd = create_and_connect_stream_or_die(opt_connect, 0); | 328 | int fd = create_and_connect_stream_or_die(opt_connect, 0); |
@@ -305,24 +330,30 @@ int sendgetmail_main(int argc, char **argv) | |||
305 | xdup2(STDIN_FILENO, STDOUT_FILENO); | 330 | xdup2(STDIN_FILENO, STDOUT_FILENO); |
306 | } | 331 | } |
307 | 332 | ||
308 | // randomize | 333 | #if ENABLE_FETCHMAIL |
309 | srand(time(NULL)); | 334 | if (opt_after_connect) |
310 | 335 | #endif | |
311 | // SENDMAIL | 336 | { |
312 | if (recipients) { | 337 | // SENDMAIL |
338 | char *opt_from; | ||
313 | int code; | 339 | int code; |
314 | char *boundary; | 340 | char *boundary; |
341 | const char *fmt; | ||
342 | const char *p; | ||
343 | char *q; | ||
315 | 344 | ||
316 | // wait for initial OK on plain connect | 345 | // wait for initial OK on plain connect |
317 | if (!(opts & OPT_X)) | 346 | if (!(opts & OPT_X)) |
318 | smtp_check(NULL, 220); | 347 | smtp_check(NULL, 220); |
319 | 348 | ||
320 | sane(from); | 349 | // get specified sender |
350 | opt_from = sane(*argv++); | ||
351 | |||
321 | // introduce to server | 352 | // introduce to server |
322 | // should we respect modern (but useless here) EHLO? | 353 | // should we respect modern (but useless here) EHLO? |
323 | // or should they respect we wanna be tiny?! | 354 | // or should they respect we wanna be tiny?! |
324 | if (!ENABLE_FEATURE_SENDMAIL_EHLO || 250 != smtp_checkp("EHLO %s", from, -1)) { | 355 | if (!ENABLE_FEATURE_SENDMAIL_EHLO || 250 != smtp_checkp("EHLO %s", opt_from, -1)) { |
325 | smtp_checkp("HELO %s", from, 250); | 356 | smtp_checkp("HELO %s", opt_from, 250); |
326 | } | 357 | } |
327 | 358 | ||
328 | // set sender | 359 | // set sender |
@@ -330,13 +361,13 @@ int sendgetmail_main(int argc, char **argv) | |||
330 | // no authentication is possible | 361 | // no authentication is possible |
331 | code = (opts & OPT_P) ? -1 : 250; | 362 | code = (opts & OPT_P) ? -1 : 250; |
332 | // first try softly without authentication | 363 | // first try softly without authentication |
333 | while (250 != smtp_checkp("MAIL FROM:<%s>", from, code)) { | 364 | while (250 != smtp_checkp("MAIL FROM:<%s>", opt_from, code)) { |
334 | // MAIL FROM failed -> authentication needed | 365 | // MAIL FROM failed -> authentication needed |
335 | // do we have username? | 366 | // do we have username? |
336 | if (!(opts & OPT_U)) { | 367 | if (!(opts & OPT_U)) { |
337 | // no! fetch it from "from" option | 368 | // no! fetch it from "from" option |
338 | //opts |= OPT_U; | 369 | //opts |= OPT_U; |
339 | opt_user = xstrdup(from); | 370 | opt_user = xstrdup(opt_from); |
340 | *strchrnul(opt_user, '@') = '\0'; | 371 | *strchrnul(opt_user, '@') = '\0'; |
341 | } | 372 | } |
342 | // now it seems we have username | 373 | // now it seems we have username |
@@ -351,30 +382,35 @@ int sendgetmail_main(int argc, char **argv) | |||
351 | // but now die on failure | 382 | // but now die on failure |
352 | code = 250; | 383 | code = 250; |
353 | } | 384 | } |
385 | |||
354 | // set recipients | 386 | // set recipients |
355 | for (llist_t *to = recipients; to; to = to->link) { | 387 | for (llist_t *to = opt_recipients; to; to = to->link) { |
356 | smtp_checkp("RCPT TO:<%s>", sane(to->data), 250); | 388 | smtp_checkp("RCPT TO:<%s>", sane(to->data), 250); |
357 | } | 389 | } |
358 | 390 | ||
359 | // now put message | 391 | // now put message |
360 | smtp_check("DATA", 354); | 392 | smtp_check("DATA", 354); |
361 | // put address headers | 393 | // put address headers |
362 | printf("From: %s\r\n", from); | 394 | printf("From: %s\r\n", opt_from); |
363 | for (llist_t *to = recipients; to; to = to->link) { | 395 | for (llist_t *to = opt_recipients; to; to = to->link) { |
364 | printf("To: %s\r\n", to->data); | 396 | printf("To: %s\r\n", to->data); |
365 | } | 397 | } |
366 | // put encoded subject | 398 | // put encoded subject |
367 | if (opts & OPTS_c) | 399 | if (opts & OPTS_c) |
368 | sane(charset); | 400 | sane((char *)opt_charset); |
369 | if (opts & OPTS_s) { | 401 | if (opts & OPTS_s) { |
370 | printf("Subject: =?%s?B?", charset); | 402 | printf("Subject: =?%s?B?", opt_charset); |
371 | uuencode(NULL, subject); | 403 | uuencode(NULL, opt_subject); |
372 | printf("?=\r\n"); | 404 | printf("?=\r\n"); |
373 | } | 405 | } |
374 | // put notification | 406 | // put notification |
375 | if (opts & OPTS_n) | 407 | if (opts & OPTS_n) |
376 | printf("Disposition-Notification-To: %s\r\n", from); | 408 | printf("Disposition-Notification-To: %s\r\n", opt_from); |
377 | // put common headers and body start | 409 | // put common headers and body start |
410 | // randomize | ||
411 | #if ENABLE_FEATURE_SENDMAIL_BLOATY | ||
412 | srand(time(NULL)); | ||
413 | #endif | ||
378 | boundary = xasprintf("%d-%d-%d", rand(), rand(), rand()); | 414 | boundary = xasprintf("%d-%d-%d", rand(), rand(), rand()); |
379 | printf( | 415 | printf( |
380 | USE_FEATURE_SENDMAIL_BLOATY("X-Mailer: busybox " BB_VER " sendmail\r\n") | 416 | USE_FEATURE_SENDMAIL_BLOATY("X-Mailer: busybox " BB_VER " sendmail\r\n") |
@@ -386,16 +422,16 @@ int sendgetmail_main(int argc, char **argv) | |||
386 | , boundary | 422 | , boundary |
387 | ); | 423 | ); |
388 | // put body + attachment(s) | 424 | // put body + attachment(s) |
389 | { | 425 | |
390 | const char *fmt = | 426 | fmt = |
391 | "\r\n--%s\r\n" | 427 | "\r\n--%s\r\n" |
392 | "%stext/plain; charset=%s\r\n" | 428 | "%stext/plain; charset=%s\r\n" |
393 | "%s%s\r\n" | 429 | "%s%s\r\n" |
394 | "%s" | 430 | "%s" |
395 | ; | 431 | ; |
396 | const char *p = charset; | 432 | p = opt_charset; |
397 | char *q = (char *)""; | 433 | q = (char *)""; |
398 | while (argv[0]) { | 434 | while (*argv) { |
399 | printf( | 435 | printf( |
400 | fmt | 436 | fmt |
401 | , boundary | 437 | , boundary |
@@ -414,9 +450,9 @@ int sendgetmail_main(int argc, char **argv) | |||
414 | ; | 450 | ; |
415 | uuencode(*argv, NULL); | 451 | uuencode(*argv, NULL); |
416 | if (*(++argv)) | 452 | if (*(++argv)) |
417 | q = bb_get_last_path_component_strip(argv[0]); | 453 | q = bb_get_last_path_component_strip(*argv); |
418 | } | 454 | } |
419 | } | 455 | |
420 | // put terminator | 456 | // put terminator |
421 | printf("\r\n--%s--\r\n" "\r\n", boundary); | 457 | printf("\r\n--%s--\r\n" "\r\n", boundary); |
422 | if (ENABLE_FEATURE_CLEAN_UP) | 458 | if (ENABLE_FEATURE_CLEAN_UP) |
@@ -426,11 +462,25 @@ int sendgetmail_main(int argc, char **argv) | |||
426 | smtp_check(".", 250); | 462 | smtp_check(".", 250); |
427 | smtp_check("QUIT", 221); | 463 | smtp_check("QUIT", 221); |
428 | 464 | ||
429 | // FETCHMAIL | 465 | #if ENABLE_FETCHMAIL |
430 | } else { | 466 | } else { |
431 | // authenticate | 467 | // FETCHMAIL |
432 | char *buf; | 468 | char *buf; |
433 | unsigned nmsg; | 469 | unsigned nmsg; |
470 | char *hostname; | ||
471 | pid_t pid; | ||
472 | // cache fetch command | ||
473 | const char *retr = (opts & OPTF_t) ? "TOP %u 0" : "RETR %u"; | ||
474 | |||
475 | // goto maildir | ||
476 | xchdir(*argv++); | ||
477 | |||
478 | #if ENABLE_FEATURE_FETCHMAIL_FILTER | ||
479 | // cache postprocess program | ||
480 | *fargs = *argv; | ||
481 | #endif | ||
482 | |||
483 | // authenticate | ||
434 | if (!(opts & OPT_U)) { | 484 | if (!(opts & OPT_U)) { |
435 | //opts |= OPT_U; | 485 | //opts |= OPT_U; |
436 | opt_user = getenv("USER"); | 486 | opt_user = getenv("USER"); |
@@ -438,25 +488,29 @@ int sendgetmail_main(int argc, char **argv) | |||
438 | #if ENABLE_FEATURE_FETCHMAIL_APOP | 488 | #if ENABLE_FEATURE_FETCHMAIL_APOP |
439 | pop3_checkr(NULL, NULL, &buf); | 489 | pop3_checkr(NULL, NULL, &buf); |
440 | // server supports APOP? | 490 | // server supports APOP? |
441 | if ('<' == buf[4]) { | 491 | if ('<' == *buf) { |
442 | md5_ctx_t md5; | 492 | md5_ctx_t md5; |
443 | uint8_t hex[16*2 + 1]; | ||
444 | // yes. compose <stamp><password> | 493 | // yes. compose <stamp><password> |
445 | char *s = strchr(buf, '>'); | 494 | char *s = strchr(buf, '>'); |
446 | if (s) | 495 | if (s) |
447 | strcpy(s+1, opt_pass); | 496 | strcpy(s+1, opt_pass); |
448 | s = buf+4; | 497 | s = buf; |
449 | // get md5 sum of <stamp><password> | 498 | // get md5 sum of <stamp><password> |
450 | md5_begin(&md5); | 499 | md5_begin(&md5); |
451 | md5_hash(s, strlen(s), &md5); | 500 | md5_hash(s, strlen(s), &md5); |
452 | md5_end(s, &md5); | 501 | md5_end(s, &md5); |
453 | bin2hex(hex, s, 16); | 502 | // NOTE: md5 struct contains enough space |
503 | // so we reuse md5 space instead of xzalloc(16*2+1) | ||
504 | #define md5_hex ((uint8_t *)&md5) | ||
505 | // uint8_t *md5_hex = (uint8_t *)&md5; | ||
506 | *bin2hex(md5_hex, s, 16) = '\0'; | ||
454 | // APOP | 507 | // APOP |
455 | s = xasprintf("%s %s", opt_user, hex); | 508 | s = xasprintf("%s %s", opt_user, md5_hex); |
509 | #undef md5_hex | ||
456 | pop3_check("APOP %s", s); | 510 | pop3_check("APOP %s", s); |
457 | if (ENABLE_FEATURE_CLEAN_UP) { | 511 | if (ENABLE_FEATURE_CLEAN_UP) { |
458 | free(s); | 512 | free(s); |
459 | free(buf); | 513 | free(buf-4); // buf is "+OK " away from malloc'ed string |
460 | } | 514 | } |
461 | } else { | 515 | } else { |
462 | #else | 516 | #else |
@@ -472,60 +526,64 @@ int sendgetmail_main(int argc, char **argv) | |||
472 | // get statistics | 526 | // get statistics |
473 | pop3_checkr("STAT", NULL, &buf); | 527 | pop3_checkr("STAT", NULL, &buf); |
474 | 528 | ||
529 | // prepare message filename suffix | ||
530 | hostname = xzalloc(MAXHOSTNAMELEN+1); | ||
531 | gethostname(hostname, MAXHOSTNAMELEN); | ||
532 | pid = getpid(); | ||
533 | |||
475 | // get number of messages | 534 | // get number of messages |
476 | nmsg = atoi(buf+4); | 535 | // NOTE: we don't use xatou(buf) since buf is "nmsg nbytes" |
536 | // we only need nmsg and atoi is just exactly what we need | ||
537 | // if atoi fails to convert buf into number it returns 0 | ||
538 | // in this case the following loop simply will not be executed | ||
539 | nmsg = atoi(buf); | ||
477 | if (ENABLE_FEATURE_CLEAN_UP) | 540 | if (ENABLE_FEATURE_CLEAN_UP) |
478 | free(buf); | 541 | free(buf-4); // buf is "+OK " away from malloc'ed string |
479 | |||
480 | // lock maildir | ||
481 | ////USE_FEATURE_CLEAN_UP(close)(xopen(".lock", O_CREAT | O_WRONLY | O_TRUNC | O_EXCL)); | ||
482 | |||
483 | // make tempnam(dir, salt) respect dir argument | ||
484 | unsetenv("TMPDIR"); | ||
485 | |||
486 | // TODO: piping through external filter argv... if *argv | ||
487 | 542 | ||
488 | // cache fetch command | ||
489 | { | ||
490 | const char *retr = (opts & OPTF_t) ? "TOP %u 0" : "RETR %u"; | ||
491 | // loop through messages | 543 | // loop through messages |
492 | for (; nmsg; nmsg--) { | 544 | for (; nmsg; nmsg--) { |
493 | int fd; | 545 | char *filename = xasprintf("tmp/%llu.%u.%s", monotonic_us(), pid, hostname); |
494 | char tmp_name[sizeof("tmp/XXXXXX")]; | 546 | char *target; |
495 | char new_name[sizeof("new/XXXXXX")]; | 547 | #if ENABLE_FEATURE_FETCHMAIL_FILTER |
496 | 548 | int rc; | |
549 | #endif | ||
497 | // retrieve message in ./tmp | 550 | // retrieve message in ./tmp |
498 | strcpy(tmp_name, "tmp/XXXXXX"); | ||
499 | fd = mkstemp(tmp_name); | ||
500 | if (fd < 0) | ||
501 | bb_perror_msg_and_die("cannot create unique file"); | ||
502 | pop3_check(retr, (const char *)nmsg); | 551 | pop3_check(retr, (const char *)nmsg); |
503 | pop3_message(fd); // NB: closes fd | 552 | pop3_message(filename); |
504 | |||
505 | // move file to ./new atomically | ||
506 | strncpy(new_name, "new", 3); | ||
507 | strcpy(new_name + 3, tmp_name + 3); | ||
508 | if (rename(tmp_name, new_name) < 0) { | ||
509 | // rats! such file exists! try to make unique name | ||
510 | strcpy(new_name + 3, "tmp/XXXXXX" + 3); | ||
511 | fd = mkstemp(new_name); | ||
512 | if (fd < 0) | ||
513 | bb_perror_msg_and_die("cannot create unique file"); | ||
514 | close(fd); | ||
515 | xrename(tmp_name, new_name); | ||
516 | } | ||
517 | |||
518 | // delete message from server | 553 | // delete message from server |
519 | if (opts & OPTF_z) | 554 | if (opts & OPTF_z) |
520 | pop3_check("DELE %u", (const char*)nmsg); | 555 | pop3_check("DELE %u", (const char*)nmsg); |
556 | |||
557 | #if ENABLE_FEATURE_FETCHMAIL_FILTER | ||
558 | // run postprocessing program | ||
559 | if (*fargs) { | ||
560 | fargs[1] = filename; | ||
561 | rc = wait4pid(spawn((char **)fargs)); | ||
562 | if (99 == rc) | ||
563 | break; | ||
564 | if (1 == rc) | ||
565 | goto skip; | ||
566 | } | ||
567 | #endif | ||
568 | // atomically move message to ./new | ||
569 | target = xstrdup(filename); | ||
570 | strncpy(target, "new", 3); | ||
571 | // ... or just stop receiving on error | ||
572 | if (rename_or_warn(filename, target)) | ||
573 | break; | ||
574 | free(target); | ||
575 | #if ENABLE_FEATURE_FETCHMAIL_FILTER | ||
576 | skip: | ||
577 | #endif | ||
578 | free(filename); | ||
521 | } | 579 | } |
522 | } | 580 | |
581 | if (ENABLE_FEATURE_CLEAN_UP) | ||
582 | free(hostname); | ||
523 | 583 | ||
524 | // Bye | 584 | // Bye |
525 | pop3_check("QUIT", NULL); | 585 | pop3_check("QUIT", NULL); |
526 | 586 | #endif // ENABLE_FETCHMAIL | |
527 | // unlock maildir | ||
528 | ////unlink(".lock"); | ||
529 | } | 587 | } |
530 | 588 | ||
531 | return 0; | 589 | return 0; |