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