1 /*
2 ** Copyright 1998 - 2004 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 **
5 */
6
7 #include "courier.h"
8 #include "rw.h"
9 #include "rfc822.h"
10 #include "comsubmitclient.h"
11 #include "maxlongsize.h"
12 #include "numlib/numlib.h"
13 #include "sbindir.h"
14 #include <pwd.h>
15 #include <stdio.h>
16 #include <ctype.h>
17 #include <signal.h>
18 #if HAVE_SYSEXITS_H
19 #include <sysexits.h>
20 #else
21
22 #define EX_NOUSER 67
23 #define EX_TEMPFAIL 75
24 #define EX_NOPERM 77
25 #endif
26
27 #if HAVE_LOCALE_H
28 #include <locale.h>
29 #endif
30
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37
38 extern void esmtpd();
39
40 static const char rcsid[]="$Id: sendmail.c,v 1.14 2007/10/15 01:46:46 mrsam Exp $";
41
mypwd()42 static struct passwd *mypwd()
43 {
44 static struct passwd *pwd=0;
45 int first_pwd=1;
46
47 if (first_pwd)
48 {
49 first_pwd=0;
50 pwd=getpwuid(getuid());
51 }
52
53 return (pwd);
54 }
55
env(const char * envname)56 static const char *env(const char *envname)
57 {
58 const char *p=getenv(envname);
59
60 if (p && !*p) p=0;
61 return (p);
62 }
63
rewrite_env_sender(const char * from)64 static char *rewrite_env_sender(const char *from)
65 {
66 const char *host;
67
68 if (!from)
69 {
70 if ((from=env("MAILSUSER")) == 0 &&
71 (from=env("MAILUSER")) == 0 &&
72 (from=env("LOGNAME")) == 0 &&
73 (from=env("USER")) == 0)
74 {
75 struct passwd *pw=mypwd();
76
77 from=pw ? pw->pw_name:"nobody";
78 }
79
80 if ((host=env("MAILSHOST")) != 0 ||
81 (host=env("MAILHOST")) != 0)
82 {
83 char *p=courier_malloc(strlen(from)+strlen(host)+2);
84
85 return (strcat(strcat(strcpy(p, from), "@"), host));
86 }
87 }
88 return (strcpy(courier_malloc(strlen(from)+1), from));
89 }
90
91 static char *rewrite_from(const char *, const char *, const char *,
92 const char *);
93
tokenize_name(const char * name)94 static struct rfc822t *tokenize_name(const char *name)
95 {
96 struct rfc822t *p=rw_rewrite_tokenize(name);
97 struct rfc822token *t;
98
99 for (t=p->tokens; t; t=t->next)
100 if (t->token) break;
101 if (t == 0) return (p); /* Only atoms */
102 if (p->tokens == 0) return (p);
103
104 p->tokens->token='"';
105 p->tokens->next=0;
106 p->tokens->ptr=name;
107 p->tokens->len=strlen(name);
108 return (p);
109 }
110
get_gecos()111 static char *get_gecos()
112 {
113 struct passwd *pw=mypwd();
114 char *p, *q;
115
116 if (!pw || !pw->pw_gecos) return (0);
117
118 p=strcpy(courier_malloc(strlen(pw->pw_gecos)+1), pw->pw_gecos);
119
120 if ((q=strchr(p, ',')) != 0) *q=0;
121 return (p);
122 }
123
rewrite_headers(const char * From)124 static void rewrite_headers(const char *From)
125 {
126 int seen_from=0;
127 char headerbuf[5000];
128 int c, i;
129 const char *mailuser, *mailuser2, *mailhost;
130 char *p;
131 char *pfrom=From ? strcpy(courier_malloc(strlen(From)+1), From):0;
132
133 if ((mailuser=env("MAILUSER")) == 0 &&
134 (mailuser=env("LOGNAME")) == 0)
135 mailuser=env("USER");
136 mailuser2=env("MAILUSER");
137 mailhost=env("MAILHOST");
138
139 while (fgets(headerbuf, sizeof(headerbuf), stdin))
140 {
141 char *p=strchr(headerbuf, '\n');
142
143 if (p)
144 {
145 *p=0;
146 if (p == headerbuf || strcmp(headerbuf, "\r") == 0)
147 break;
148 }
149
150 #if HAVE_STRNCASECMP
151 if (strncasecmp(headerbuf, "from:", 5))
152 #else
153 if (strnicmp(headerbuf, "from:", 5))
154 #endif
155 {
156 fprintf(submit_to, "%s", headerbuf);
157 if (!p)
158 while ((c=getchar()) != EOF && c != '\n')
159 putc(c, submit_to);
160 putc('\n', submit_to);
161 continue;
162 }
163 if (!p)
164 while ((c=getchar()) != EOF && c != '\n')
165 ; /* I don't care */
166 if (seen_from) continue; /* Screwit */
167 seen_from=1;
168
169 i=strlen(headerbuf);
170 for (;;)
171 {
172 c=getchar();
173 if (c != EOF) ungetc(c, stdin);
174 if (c == EOF || c == '\r' || c == '\n') break;
175 if (!isspace((int)(unsigned char)c)) break;
176 while ((c=getchar()) != EOF && c != '\n')
177 {
178 if (i < sizeof(headerbuf)-1)
179 headerbuf[i++]=c;
180 }
181 headerbuf[i]=0;
182 }
183
184 p=rewrite_from(headerbuf+5, mailuser2, mailhost, pfrom);
185 fprintf(submit_to, "From: %s\n", p);
186 free(p);
187 }
188 if (!seen_from)
189 {
190 if (!mailuser)
191 {
192 struct passwd *pw=mypwd();
193
194 mailuser=pw ? pw->pw_name:"nobody";
195 }
196
197 if (!pfrom)
198 {
199 if ( !(From=env("MAILNAME")) && !(From=env("NAME")))
200 {
201 pfrom=get_gecos();
202 }
203 else pfrom=strcpy(courier_malloc(strlen(From)+1),
204 From);
205 }
206
207 p=rewrite_from(NULL, mailuser, mailhost, pfrom);
208 fprintf(submit_to, "From: %s\n", p);
209 free(p);
210 }
211 putc('\n', submit_to);
212 if (pfrom) free(pfrom);
213 }
214
rewrite_from(const char * oldfrom,const char * newuser,const char * newhost,const char * newname)215 static char *rewrite_from(const char *oldfrom, const char *newuser,
216 const char *newhost, const char *newname)
217 {
218 struct rfc822t *rfct;
219 struct rfc822a *rfca;
220 struct rfc822t *usert, *hostt, *namet;
221 struct rfc822token attoken, **tp;
222 char *p;
223 const char *q;
224 char *gecosname=0;
225
226 if (!oldfrom)
227 {
228 char *p=courier_malloc(
229 (newuser ? strlen(newuser):0)+
230 (newhost ? strlen(newhost):0)+4);
231 strcpy(p, "<");
232 if (newuser) strcat(p, newuser);
233 if (newuser && newhost)
234 strcat(strcat(p, "@"), newhost);
235 strcat(p, ">");
236 if (newname)
237 {
238 char *q, *r;
239
240 namet=tokenize_name(newname);
241 q=rfc822_gettok(namet->tokens);
242 rfc822t_free(namet);
243 r=courier_malloc(strlen(p)+strlen(q)+2);
244 strcat(strcat(strcpy(r, q), " "), p);
245 free(p);
246 p=r;
247 free(q);
248 }
249 return (p);
250 }
251
252 if ((rfct=rfc822t_alloc_new(oldfrom, NULL, NULL)) == 0 ||
253 (rfca=rfc822a_alloc(rfct)) == 0)
254 {
255 clog_msg_errno();
256 return(0);
257 }
258
259 if ((q=env("MAILNAME")) || (q=env("NAME")))
260 newname=q;
261
262 if (!newname && rfca->naddrs == 0)
263 newname=gecosname=get_gecos();
264
265 if ((rfca->naddrs == 0 || rfca->addrs[0].tokens == 0) && newuser == 0)
266 {
267 struct passwd *pw=mypwd();
268
269 if (pw) newuser=pw->pw_name;
270 }
271
272 namet=newname ? tokenize_name(newname):0;
273 usert=newuser ? rw_rewrite_tokenize(newuser):0;
274 hostt=newhost ? rw_rewrite_tokenize(newhost):0;
275
276 if (rfca->naddrs == 0 || rfca->addrs[0].tokens == 0)
277 {
278 struct rfc822addr a;
279 struct rfc822a fakea;
280
281 if (hostt)
282 {
283 struct rfc822token *t;
284
285 attoken.token='@';
286 attoken.next=hostt->tokens;
287 attoken.ptr=0;
288 attoken.len=0;
289
290 for (t=usert->tokens; t->next; t=t->next)
291 ;
292 t->next=&attoken;
293 }
294 fakea.naddrs=1;
295 fakea.addrs= &a;
296
297 if (!namet) namet=tokenize_name("");
298 if (!usert) usert=rw_rewrite_tokenize("");
299 a.name=namet->tokens;
300 a.tokens=usert->tokens;
301 p=rfc822_getaddrs(&fakea);
302 }
303 else
304 {
305 struct rfc822token *t, *u;
306
307 rfca->naddrs=1;
308 if (usert)
309 {
310 for (t=rfca->addrs[0].tokens; t; t=t->next)
311 if (t->token == '@') break;
312
313 for (u=usert->tokens; u->next; u=u->next)
314 ;
315 u->next=t;
316 rfca->addrs[0].tokens=usert->tokens;;
317 }
318
319 if (hostt && rfca->addrs[0].tokens)
320 {
321 for (tp= &rfca->addrs[0].tokens; *tp;
322 tp= &(*tp)->next)
323 if ( (*tp)->token == '@') break;
324 *tp=&attoken;
325 attoken.token='@';
326 attoken.next=hostt->tokens;
327 attoken.ptr=0;
328 attoken.len=0;
329 }
330 if (namet)
331 rfca->addrs[0].name=namet->tokens;
332
333 p=rfc822_getaddrs(rfca);
334 }
335
336 if (!p) clog_msg_errno();
337
338 if (usert) rfc822t_free(usert);
339 if (hostt) rfc822t_free(hostt);
340 if (namet) rfc822t_free(namet);
341 rfc822t_free(rfct);
342 rfc822a_free(rfca);
343 if (gecosname) free(gecosname);
344 return (p);
345 }
346
exit_submit(int errcode)347 static void exit_submit(int errcode)
348 {
349 if (errcode == -5)
350 exit(EX_NOUSER);
351
352 exit(EX_TEMPFAIL);
353 }
354
main(int argc,char ** argv)355 int main(int argc, char **argv)
356 {
357 const char *from=0;
358 const char *From=0;
359 const char *ret=0, *dsn=0, *security=0, *envid=0;
360 int argn, argp;
361 int errflag=0;
362 int c;
363 char *args[6];
364 char *envs[7];
365 int envp;
366 int tostdout=0;
367 char frombuf[NUMBUFSIZE+30];
368 int doverp=0;
369 int bcconly=0;
370 char ubuf[NUMBUFSIZE];
371 char *uucprmail=0;
372 char *s;
373 char ret_buf[2], security_buf[40];
374 int submit_errcode;
375
376 /*
377 ** Immediately drop uid, force GID to MAILGID
378 ** The reason we can't just setgid ourselves to MAILGID is because
379 ** that only sets the effective uid. We need to also set both
380 ** real and effective GIDs, otherwise maildrop filtering will fail,
381 ** because the real gid won't be trusted.
382 */
383 setgid(MAILGID);
384 setuid(getuid());
385 signal(SIGCHLD, SIG_DFL);
386 signal(SIGPIPE, SIG_IGN);
387 argn=1;
388
389 putenv("AUTHMODULES="); /* See module.local/local.c */
390
391 #if HAVE_SETLOCALE
392 setlocale(LC_ALL, "C");
393 #endif
394
395 /* Only uucp can run rmail (this better be installed setgid) */
396
397 if ((s=strrchr(argv[0], '/')) != 0) ++s;
398 else s=argv[0];
399 if (strcmp(s, "rmail") == 0)
400 {
401 struct passwd *p=mypwd();
402 char *uu_machine, *uu_user;
403
404 if (!p || strcmp(p->pw_name, "uucp"))
405 {
406 fprintf(stderr, "rmail: permission denied.\n");
407 exit(EX_NOPERM);
408 }
409
410 uu_machine=getenv("UU_MACHINE");
411 uu_user=getenv("UU_USER");
412
413 if (!uu_machine || !uu_user)
414 {
415 fprintf(stderr,
416 "rmail: UU_MACHINE!UU_USER required.\n");
417 exit(EX_NOPERM);
418 }
419 uucprmail=malloc(strlen(uu_machine)+strlen(uu_user)+2);
420 if (!uucprmail)
421 {
422 perror("malloc");
423 exit(EX_TEMPFAIL);
424 }
425 strcat(strcat(strcpy(uucprmail, uu_machine), "!"), uu_user);
426 }
427
428 while (argn < argc)
429 {
430 const char *arg;
431 int c;
432
433 if (argv[argn][0] != '-') break;
434
435 if (strcmp(argv[argn], "-") == 0)
436 {
437 ++argn;
438 break;
439 }
440
441 if (uucprmail && strncmp(argv[argn], "-f", 2)
442
443 /*
444 ** Ok, obviously no UUCP version will give me the following
445 ** options, must I can hope, can't I?
446 */
447 && strcmp(argv[argn], "-verp")
448 && strncmp(argv[argn], "-N", 2)
449 && strncmp(argv[argn], "-R", 2)
450 && strncmp(argv[argn], "-V", 2)
451
452 /* Ignore the ignorable */
453
454 && strncmp(argv[argn], "-o", 2)
455 && strncmp(argv[argn], "-t", 2)
456
457 )
458 {
459 fprintf(stderr, "rmail: invalid option %s\n",
460 argv[argn]);
461 exit(EX_NOPERM);
462 }
463
464 if (strcmp(argv[argn], "-verp") == 0)
465 {
466 doverp=1;
467 ++argn;
468 continue;
469 }
470
471 if (strcmp(argv[argn], "-bcc") == 0)
472 {
473 bcconly=1;
474 ++argn;
475 continue;
476 }
477
478 if (strcmp(argv[argn], "-bs") == 0)
479 {
480 esmtpd();
481 }
482 switch (c=argv[argn][1]) {
483 case 'o':
484 case 'f':
485 case 'F':
486 case 'R':
487 case 'N':
488 case 'S':
489 case 'V':
490 break;
491 case 'n':
492 tostdout=1;
493 ++argn;
494 continue;
495 default:
496 ++argn;
497 continue;
498 }
499 arg=argv[argn]+2;
500 if (!*arg && argn+1 < argc)
501 arg=argv[++argn];
502 ++argn;
503
504 if (c == 'f')
505 from=arg;
506 else if (c == 'F')
507 From=arg;
508 else if (c == 'N')
509 dsn=arg;
510 else if (c == 'S')
511 {
512 char *q;
513
514 if (strcasecmp(arg, "NONE") &&
515 strcasecmp(arg, "STARTTLS"))
516 {
517 fprintf(stderr, "sendmail: invalid option"
518 " -S %s\n",
519 arg);
520 exit(EX_NOPERM);
521 }
522 strcpy(security_buf, arg);
523
524 for (q=security_buf; *q; q++)
525 *q=toupper((int)(unsigned char)*q);
526
527 security=security_buf;
528 }
529 else if (c == 'R')
530 {
531 ret_buf[0]= toupper((int)(unsigned char)*arg);
532 ret_buf[1]= 0;
533 ret=ret_buf;
534 }
535 else if (c == 'V')
536 envid=arg;
537 }
538
539 sprintf(frombuf, "uid %s", libmail_str_uid_t(getuid(), ubuf));
540 argp=0;
541 args[argp++]="submit";
542 if (bcconly)
543 args[argp++]="-bcc";
544
545 if (uucprmail)
546 {
547 if (argn >= argc)
548 {
549 fprintf(stderr, "rmail: missing recipients\n");
550 exit(EX_NOPERM);
551 }
552
553 args[argp++]="uucp";
554 s=malloc(sizeof("unknown; uucp ()")+strlen(uucprmail));
555 if (!s)
556 {
557 perror("malloc");
558 exit(EX_TEMPFAIL);
559 }
560 strcat(strcat(strcpy(s, "unknown; uucp ("), uucprmail), ")");
561 args[argp++]=s;
562 }
563 else
564 {
565 args[argp++]="local";
566 args[argp++]="dns; localhost (localhost [127.0.0.1])";
567 args[argp++]=frombuf;
568 }
569 args[argp++]=0;
570 envp=0;
571
572 clog_open_stderr("sendmail");
573 if (ret || security || doverp)
574 {
575 envs[envp]=strcat(strcat(strcpy(courier_malloc(strlen(ret ?
576 ret:"")+strlen(security ? security:"") + 30),
577 "DSNRET="), (ret ? ret:"")),
578 (doverp ? "V":""));
579 if (security)
580 strcat(strcat(strcat(envs[envp], "S{"),
581 security), "}");
582
583 ++envp;
584 }
585
586 if (dsn)
587 {
588 envs[envp]=strcat(strcpy(courier_malloc(strlen(dsn)+11),
589 "DSNNOTIFY="), dsn);
590 ++envp;
591 }
592 if (envid)
593 {
594 envs[envp]=strcat(strcpy(courier_malloc(strlen(envid)+10),
595 "DSNENVID="), envid);
596 ++envp;
597 }
598 envs[envp++]="TCPREMOTEHOST=localhost";
599 envs[envp++]="TCPREMOTEIP=127.0.0.1";
600
601 if (!uucprmail)
602 envs[envp++]=strcat(strcpy(courier_malloc(strlen(frombuf)+
603 sizeof("TCPREMOTEINFO=")),
604 "TCPREMOTEINFO="), frombuf);
605 envs[envp]=0;
606
607 if (!tostdout && submit_fork(args, envs, submit_print_stdout))
608 {
609 fprintf(stderr, "sendmail: Service temporarily unavailable.\n");
610 exit(EX_TEMPFAIL);
611 }
612
613 if (tostdout)
614 submit_to=stdout;
615 else
616 {
617 if (uucprmail)
618 {
619 submit_write_message(from ? from:"");
620 }
621 else
622 {
623 char *p;
624
625 p=rewrite_env_sender(from);
626 submit_write_message(p);
627 free(p);
628 }
629 if ((submit_errcode=submit_readrcprinterr()) != 0)
630 {
631 exit_submit(submit_errcode);
632 }
633 }
634
635 while (!tostdout && argn < argc)
636 {
637 submit_write_message(argv[argn]);
638 if ((errflag=submit_readrcprinterr()) != 0)
639 {
640 fprintf(stderr, "%s: invalid address.\n", argv[argn]);
641 }
642 ++argn;
643 }
644 if (errflag) exit_submit(errflag);
645 if (!tostdout)
646 putc('\n', submit_to);
647
648 if (!uucprmail)
649 rewrite_headers(From);
650
651 while ((c=getchar()) != EOF)
652 {
653 putc(c, submit_to);
654 }
655 fflush(submit_to);
656 signal(SIGINT, SIG_IGN);
657 signal(SIGTERM, SIG_IGN);
658 signal(SIGHUP, SIG_IGN);
659
660 errflag=0;
661 if (ferror(submit_to) || (!tostdout && (
662 fclose(submit_to) ||
663 (errflag=submit_readrcprinterr()) || submit_wait()))
664 )
665 {
666 fprintf(stderr, "sendmail: Unable to submit message.\n");
667 if (errflag)
668 exit_submit(errflag);
669 exit(EX_TEMPFAIL);
670 }
671 exit(0);
672 }
673