1 /*
2 ** Copyright 2000-2008 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5 #include	"config.h"
6 #include	"argparse.h"
7 #include	"spipe.h"
8 
9 #include	"libcouriertls.h"
10 #include	"tlscache.h"
11 #include	"rfc1035/rfc1035.h"
12 #include	"soxwrap/soxwrap.h"
13 #ifdef  getc
14 #undef  getc
15 #endif
16 #include	<stdio.h>
17 #include	<string.h>
18 #include	<stdlib.h>
19 #include	<ctype.h>
20 #include	<netdb.h>
21 #if HAVE_DIRENT_H
22 #include <dirent.h>
23 #define NAMLEN(dirent) strlen((dirent)->d_name)
24 #else
25 #define dirent direct
26 #define NAMLEN(dirent) (dirent)->d_namlen
27 #if HAVE_SYS_NDIR_H
28 #include <sys/ndir.h>
29 #endif
30 #if HAVE_SYS_DIR_H
31 #include <sys/dir.h>
32 #endif
33 #if HAVE_NDIR_H
34 #include <ndir.h>
35 #endif
36 #endif
37 #if	HAVE_UNISTD_H
38 #include	<unistd.h>
39 #endif
40 #if	HAVE_FCNTL_H
41 #include	<fcntl.h>
42 #endif
43 #include	<errno.h>
44 #if	HAVE_SYS_TYPES_H
45 #include	<sys/types.h>
46 #endif
47 #if	HAVE_SYS_STAT_H
48 #include	<sys/stat.h>
49 #endif
50 #include	<sys/socket.h>
51 #include	<arpa/inet.h>
52 
53 #if TIME_WITH_SYS_TIME
54 #include        <sys/time.h>
55 #include        <time.h>
56 #else
57 #if HAVE_SYS_TIME_H
58 #include        <sys/time.h>
59 #else
60 #include        <time.h>
61 #endif
62 #endif
63 #include	<locale.h>
64 
65 static const char rcsid[]="$Id: starttls.c,v 1.44 2009/06/27 16:32:38 mrsam Exp $";
66 
67 /* Command-line options: */
68 const char *clienthost=0;
69 const char *clientport=0;
70 
71 const char *server=0;
72 const char *localfd=0;
73 const char *remotefd=0;
74 const char *statusfd=0;
75 const char *tcpd=0;
76 const char *peer_verify_domain=0;
77 const char *fdprotocol=0;
78 static FILE *errfp;
79 static FILE *statusfp;
80 
81 const char *printx509=0;
82 
ssl_errmsg(const char * errmsg,void * dummy)83 static void ssl_errmsg(const char *errmsg, void *dummy)
84 {
85 	fprintf(errfp, "%s\n", errmsg);
86 }
87 
nonsslerror(const char * pfix)88 static void nonsslerror(const char *pfix)
89 {
90 	fprintf(errfp, "%s: %s\n", pfix, strerror(errno));
91 }
92 
docopy(ssl_handle ssl,int sslfd,int stdinfd,int stdoutfd)93 void docopy(ssl_handle ssl, int sslfd, int stdinfd, int stdoutfd)
94 {
95 	struct tls_transfer_info transfer_info;
96 
97 	char from_ssl_buf[BUFSIZ], to_ssl_buf[BUFSIZ];
98 	char *fromptr;
99 	int rc;
100 
101 	fd_set	fdr, fdw;
102 	int	maxfd=sslfd;
103 
104 	if (fcntl(stdinfd, F_SETFL, O_NONBLOCK)
105 	    || fcntl(stdoutfd, F_SETFL, O_NONBLOCK)
106 	    )
107 	{
108 		nonsslerror("fcntl");
109 		return;
110 	}
111 
112 	if (maxfd < stdinfd)	maxfd=stdinfd;
113 	if (maxfd < stdoutfd)	maxfd=stdoutfd;
114 
115 	tls_transfer_init(&transfer_info);
116 
117 	transfer_info.readptr=fromptr=from_ssl_buf;
118 
119 	for (;;)
120 	{
121 		if (transfer_info.readptr == fromptr)
122 		{
123 			transfer_info.readptr=fromptr=from_ssl_buf;
124 			transfer_info.readleft=sizeof(from_ssl_buf);
125 		}
126 		else
127 			transfer_info.readleft=0;
128 
129 		FD_ZERO(&fdr);
130 		FD_ZERO(&fdw);
131 
132 		rc=tls_transfer(&transfer_info, ssl, sslfd, &fdr, &fdw);
133 
134 		if (rc == 0)
135 			continue;
136 		if (rc < 0)
137 			break;
138 
139 		if (!tls_inprogress(&transfer_info))
140 		{
141 			if (transfer_info.readptr > fromptr)
142 				FD_SET(stdoutfd, &fdw);
143 
144 			if (transfer_info.writeleft == 0)
145 				FD_SET(stdinfd, &fdr);
146 		}
147 
148 		if (select(maxfd+1, &fdr, &fdw, 0, 0) <= 0)
149 		{
150 			if (errno != EINTR)
151 			{
152 				nonsslerror("select");
153 				break;
154 			}
155 			continue;
156 		}
157 
158 		if (FD_ISSET(stdoutfd, &fdw) &&
159 		    transfer_info.readptr > fromptr)
160 		{
161 			rc=write(stdoutfd, fromptr,
162 				 transfer_info.readptr - fromptr);
163 
164 			if (rc <= 0)
165 				break;
166 
167 			fromptr += rc;
168 		}
169 
170 		if (FD_ISSET(stdinfd, &fdr) && transfer_info.writeleft == 0)
171 		{
172 			rc=read(stdinfd, to_ssl_buf, sizeof(to_ssl_buf));
173 			if (rc <= 0)
174 				break;
175 
176 			transfer_info.writeptr=to_ssl_buf;
177 			transfer_info.writeleft=rc;
178 		}
179 	}
180 
181 	tls_closing(&transfer_info);
182 
183 	for (;;)
184 	{
185 		FD_ZERO(&fdr);
186 		FD_ZERO(&fdw);
187 
188 		if (tls_transfer(&transfer_info, ssl, sslfd, &fdr, &fdw) < 0)
189 			break;
190 
191 		if (select(maxfd+1, &fdr, &fdw, 0, 0) <= 0)
192 		{
193 			if (errno != EINTR)
194 			{
195 				nonsslerror("select");
196 				break;
197 			}
198 			continue;
199 		}
200 	}
201 }
202 
203 struct dump_capture_subject {
204 	char line[1024];
205 	int line_size;
206 
207 	int set_subject;
208 	int seen_subject;
209 	int in_subject;
210 	FILE *fp;
211 };
212 
dump_to_fp(const char * p,int cnt,void * arg)213 static void dump_to_fp(const char *p, int cnt, void *arg)
214 {
215 	struct dump_capture_subject *dcs=(struct dump_capture_subject *)arg;
216 	char *n, *v;
217 	char namebuf[64];
218 
219 	if (cnt < 0)
220 		cnt=strlen(p);
221 
222 	if (dcs->fp && fwrite(p, cnt, 1, dcs->fp) != 1)
223 		; /* NOOP */
224 
225 	while (cnt)
226 	{
227 		if (*p != '\n')
228 		{
229 			if (dcs->line_size < sizeof(dcs->line)-1)
230 				dcs->line[dcs->line_size++]=*p;
231 
232 			++p;
233 			--cnt;
234 			continue;
235 		}
236 		dcs->line[dcs->line_size]=0;
237 		++p;
238 		--cnt;
239 		dcs->line_size=0;
240 
241 		if (strncmp(dcs->line, "Subject:", 8) == 0)
242 		{
243 			if (dcs->seen_subject)
244 				continue;
245 
246 			dcs->seen_subject=1;
247 			dcs->in_subject=1;
248 			continue;
249 		}
250 
251 		if (!dcs->in_subject)
252 			continue;
253 
254 		if (dcs->line[0] != ' ')
255 		{
256 			dcs->in_subject=0;
257 			continue;
258 		}
259 
260 		for (n=dcs->line; *n; n++)
261 			if (*n != ' ')
262 				break;
263 
264 		for (v=n; *v; v++)
265 		{
266 			*v=toupper(*v);
267 			if (*v == '=')
268 			{
269 				*v++=0;
270 				break;
271 			}
272 		}
273 
274 		namebuf[snprintf(namebuf, sizeof(namebuf)-1,
275 				 "TLS_SUBJECT_%s", n)]=0;
276 
277 		if (dcs->set_subject)
278 			setenv(namebuf, v, 1);
279 	}
280 }
281 
verify_connection(ssl_handle ssl,void * dummy)282 static int verify_connection(ssl_handle ssl, void *dummy)
283 {
284 	FILE	*printx509_fp=NULL;
285 	int	printx509_fd=0;
286 	char	*buf;
287 
288 	struct dump_capture_subject dcs;
289 
290 	memset(&dcs, 0, sizeof(dcs));
291 
292 	if (printx509)
293 	{
294 		printx509_fd=atoi(printx509);
295 
296 		printx509_fp=fdopen(printx509_fd, "w");
297                 if (!printx509_fp)
298                         nonsslerror("fdopen");
299 	}
300 
301 	dcs.fp=printx509_fp;
302 
303 	dcs.set_subject=0;
304 
305 	if (tls_certificate_verified(ssl))
306 		dcs.set_subject=1;
307 
308 	tls_dump_connection_info(ssl, server ? 1:0, dump_to_fp, &dcs);
309 
310 	if (printx509_fp)
311 	{
312 		fclose(printx509_fp);
313 	}
314 
315 	if (statusfp)
316 	{
317 		fclose(statusfp);
318 		statusfp=NULL;
319 		errfp=stderr;
320 	}
321 
322 	buf=tls_get_encryption_desc(ssl);
323 
324 	setenv("TLS_CONNECTED_PROTOCOL",
325 	       buf ? buf:"(unknown)", 1);
326 
327 	if (buf)
328 		free(buf);
329 	return 1;
330 }
331 
332 /* ----------------------------------------------------------------------- */
333 
startclient(int argn,int argc,char ** argv,int fd,int * stdin_fd,int * stdout_fd)334 static void startclient(int argn, int argc, char **argv, int fd,
335 	int *stdin_fd, int *stdout_fd)
336 {
337 pid_t	p;
338 int	streampipe[2];
339 
340 	if (localfd)
341 	{
342 		*stdin_fd= *stdout_fd= atoi(localfd);
343 		return;
344 	}
345 
346 	if (argn >= argc)	return;		/* Interactive */
347 
348 	if (libmail_streampipe(streampipe))
349 	{
350 		nonsslerror("libmail_streampipe");
351 		exit(1);
352 	}
353 	if ((p=fork()) == -1)
354 	{
355 		nonsslerror("fork");
356 		close(streampipe[0]);
357 		close(streampipe[1]);
358 		exit(1);
359 	}
360 	if (p == 0)
361 	{
362 	char **argvec;
363 	int n;
364 
365 		close(fd);	/* Child process doesn't need it */
366 		dup2(streampipe[1], 0);
367 		dup2(streampipe[1], 1);
368 		close(streampipe[0]);
369 		close(streampipe[1]);
370 
371 		argvec=malloc(sizeof(char *)*(argc-argn+1));
372 		if (!argvec)
373 		{
374 			nonsslerror("malloc");
375 			exit(1);
376 		}
377 		for (n=0; n<argc-argn; n++)
378 			argvec[n]=argv[argn+n];
379 		argvec[n]=0;
380 		execvp(argvec[0], argvec);
381 		nonsslerror(argvec[0]);
382 		exit(1);
383 	}
384 	close(streampipe[1]);
385 
386 	*stdin_fd= *stdout_fd= streampipe[0];
387 }
388 
connectremote(const char * host,const char * port)389 static int connectremote(const char *host, const char *port)
390 {
391 int	fd;
392 
393 RFC1035_ADDR addr;
394 int	af;
395 RFC1035_ADDR *addrs;
396 unsigned	naddrs, n;
397 
398 RFC1035_NETADDR addrbuf;
399 const struct sockaddr *saddr;
400 int     saddrlen;
401 int	port_num;
402 
403 	port_num=atoi(port);
404 	if (port_num <= 0)
405 	{
406 	struct servent *servent;
407 
408 		servent=getservbyname(port, "tcp");
409 
410 		if (!servent)
411 		{
412 			fprintf(errfp, "%s: invalid port.\n", port);
413 			return (-1);
414 		}
415 		port_num=servent->s_port;
416 	}
417 	else
418 		port_num=htons(port_num);
419 
420 	if (rfc1035_aton(host, &addr) == 0) /* An explicit IP addr */
421 	{
422 		if ((addrs=malloc(sizeof(addr))) == 0)
423 		{
424 			nonsslerror("malloc");
425 			return (-1);
426 		}
427 		memcpy(addrs, &addr, sizeof(addr));
428 		naddrs=1;
429 	}
430 	else
431 	{
432 		if (rfc1035_a(&rfc1035_default_resolver, host, &addrs,
433 			      &naddrs))
434 		{
435 			fprintf(errfp, "%s: not found.\n", host);
436 			return (-1);
437 		}
438 	}
439 
440         if ((fd=rfc1035_mksocket(SOCK_STREAM, 0, &af)) < 0)
441         {
442                 nonsslerror("socket");
443                 return (-1);
444         }
445 
446 	for (n=0; n<naddrs; n++)
447 	{
448 		if (rfc1035_mkaddress(af, &addrbuf, addrs+n, port_num,
449 			&saddr, &saddrlen))	continue;
450 
451 		if (sox_connect(fd, saddr, saddrlen) == 0)
452 			break;
453 	}
454 	free(addrs);
455 
456 	if (n >= naddrs)
457 	{
458 		close(fd);
459 		nonsslerror("connect");
460 		return (-1);
461 	}
462 
463 	return (fd);
464 }
465 
connect_completed(ssl_handle ssl,int fd)466 static int connect_completed(ssl_handle ssl, int fd)
467 {
468 	struct tls_transfer_info transfer_info;
469 	tls_transfer_init(&transfer_info);
470 
471 	while (tls_connecting(ssl))
472 	{
473 		fd_set	fdr, fdw;
474 
475 		FD_ZERO(&fdr);
476 		FD_ZERO(&fdw);
477 		if (tls_transfer(&transfer_info, ssl,
478 				 fd, &fdr, &fdw) < 0)
479 			return (0);
480 
481 		if (!tls_connecting(ssl))
482 			break;
483 
484 		if (select(fd+1, &fdr, &fdw, 0, 0) <= 0)
485 		{
486 			if (errno != EINTR)
487 			{
488 				nonsslerror("select");
489 				return (0);
490 			}
491 		}
492 	}
493 	return (1);
494 }
495 
dossl(int fd,int argn,int argc,char ** argv)496 static int dossl(int fd, int argn, int argc, char **argv)
497 {
498 	ssl_context ctx;
499 	ssl_handle ssl;
500 
501 	int	stdin_fd, stdout_fd;
502 	struct tls_info info= *tls_get_default_info();
503 
504 	info.peer_verify_domain=peer_verify_domain;
505 	info.tls_err_msg=ssl_errmsg;
506 	info.connect_callback= &verify_connection;
507 	info.app_data=NULL;
508 
509 	ctx=tls_create(server ? 1:0, &info);
510 	if (ctx == 0)	return (1);
511 
512 	ssl=tls_connect(ctx, fd);
513 
514 	if (!ssl)
515 	{
516 		close(fd);
517 		return (1);
518 	}
519 
520 	if (!connect_completed(ssl, fd))
521 	{
522 		tls_disconnect(ssl, fd);
523 		close(fd);
524 		tls_destroy(ctx);
525 		return 1;
526 	}
527 
528 	stdin_fd=0;
529 	stdout_fd=1;
530 
531 	startclient(argn, argc, argv, fd, &stdin_fd, &stdout_fd);
532 
533 	docopy(ssl, fd, stdin_fd, stdout_fd);
534 
535 	tls_disconnect(ssl, fd);
536 	close(fd);
537 	tls_destroy(ctx);
538 	return (0);
539 }
540 
541 struct protoreadbuf {
542 	char buffer[512];
543 	char *bufptr;
544 	int bufleft;
545 
546 	char line[256];
547 } ;
548 
549 #define PRB_INIT(p) ( (p)->bufptr=0, (p)->bufleft=0)
550 
protoread(int fd,struct protoreadbuf * prb)551 static char protoread(int fd, struct protoreadbuf *prb)
552 {
553 	fd_set fds;
554 	struct timeval tv;
555 
556 	FD_ZERO(&fds);
557 	FD_SET(fd, &fds);
558 
559 	tv.tv_sec=60;
560 	tv.tv_usec=0;
561 
562 	if (select(fd+1, &fds, NULL, NULL, &tv) <= 0)
563 	{
564 		nonsslerror("select");
565 		exit(1);
566 	}
567 
568 	if ( (prb->bufleft=read(fd, prb->buffer, sizeof(prb->buffer))) <= 0)
569 	{
570 		errno=ECONNRESET;
571 		nonsslerror("read");
572 		exit(1);
573 	}
574 
575 	prb->bufptr= prb->buffer;
576 
577 	--prb->bufleft;
578 	return (*prb->bufptr++);
579 }
580 
581 #define PRB_GETCH(fd,prb) ( (prb)->bufleft-- > 0 ? *(prb)->bufptr++:\
582 				protoread( (fd), (prb)))
583 
prb_getline(int fd,struct protoreadbuf * prb)584 static const char *prb_getline(int fd, struct protoreadbuf *prb)
585 {
586 	int i=0;
587 	char c;
588 
589 	while ((c=PRB_GETCH(fd, prb)) != '\n')
590 	{
591 		if ( i < sizeof (prb->line)-1)
592 			prb->line[i++]=c;
593 	}
594 	prb->line[i]=0;
595 	return (prb->line);
596 }
597 
prb_write(int fd,struct protoreadbuf * prb,const char * p)598 static void prb_write(int fd, struct protoreadbuf *prb, const char *p)
599 {
600 	printf("%s", p);
601 	while (*p)
602 	{
603 		int l=write(fd, p, strlen(p));
604 
605 		if (l <= 0)
606 		{
607 			nonsslerror("write");
608 			exit(1);
609 		}
610 		p += l;
611 	}
612 }
613 
goodimap(const char * p)614 static int goodimap(const char *p)
615 {
616 	if (*p == 'x' && p[1] && isspace((int)(unsigned char)p[1]))
617 		++p;
618 	else
619 	{
620 		if (*p != '*')
621 			return (0);
622 		++p;
623 	}
624 	while (*p && isspace((int)(unsigned char)*p))
625 		++p;
626 	if (strncasecmp(p, "BAD", 3) == 0)
627 	{
628 		exit(1);
629 	}
630 
631 	if (strncasecmp(p, "BYE", 3) == 0)
632 	{
633 		exit(1);
634 	}
635 
636 	if (strncasecmp(p, "NO", 2) == 0)
637 	{
638 		exit(1);
639 	}
640 
641 	return (strncasecmp(p, "OK", 2) == 0);
642 }
643 
imap_proto(int fd)644 static void imap_proto(int fd)
645 {
646 	struct protoreadbuf prb;
647 	const char *p;
648 
649 	PRB_INIT(&prb);
650 
651 	do
652 	{
653 		p=prb_getline(fd, &prb);
654 		printf("%s\n", p);
655 
656 	} while (!goodimap(p));
657 
658 	prb_write(fd, &prb, "x STARTTLS\r\n");
659 
660 	do
661 	{
662 		p=prb_getline(fd, &prb);
663 		printf("%s\n", p);
664 	} while (!goodimap(p));
665 }
666 
pop3_proto(int fd)667 static void pop3_proto(int fd)
668 {
669 	struct protoreadbuf prb;
670 	const char *p;
671 
672 	PRB_INIT(&prb);
673 
674 	p=prb_getline(fd, &prb);
675 	printf("%s\n", p);
676 
677 	prb_write(fd, &prb, "STLS\r\n");
678 
679 	p=prb_getline(fd, &prb);
680 	printf("%s\n", p);
681 }
682 
smtp_proto(int fd)683 static void smtp_proto(int fd)
684 {
685 	struct protoreadbuf prb;
686 	const char *p;
687 
688 	char hostname[1024];
689 
690 	PRB_INIT(&prb);
691 
692 	do
693 	{
694 		p=prb_getline(fd, &prb);
695 		printf("%s\n", p);
696 	} while ( ! ( isdigit((int)(unsigned char)p[0]) &&
697 		      isdigit((int)(unsigned char)p[1]) &&
698 		      isdigit((int)(unsigned char)p[2]) &&
699 		      (p[3] == 0 || isspace((int)(unsigned char)p[3]))));
700 	if (strchr("123", *p) == 0)
701 		exit(1);
702 
703 	hostname[sizeof(hostname)-1]=0;
704 	if (gethostname(hostname, sizeof(hostname)-1) < 0)
705 		strcpy(hostname, "localhost");
706 
707 	prb_write(fd, &prb, "EHLO ");
708 	prb_write(fd, &prb, hostname);
709 	prb_write(fd, &prb, "\r\n");
710 	do
711 	{
712 		p=prb_getline(fd, &prb);
713 		printf("%s\n", p);
714 	} while ( ! ( isdigit((int)(unsigned char)p[0]) &&
715 		      isdigit((int)(unsigned char)p[1]) &&
716 		      isdigit((int)(unsigned char)p[2]) &&
717 		      (p[3] == 0 || isspace((int)(unsigned char)p[3]))));
718 	if (strchr("123", *p) == 0)
719 		exit(1);
720 
721 	prb_write(fd, &prb, "STARTTLS\r\n");
722 
723 	do
724 	{
725 		p=prb_getline(fd, &prb);
726 		printf("%s\n", p);
727 	} while ( ! ( isdigit((int)(unsigned char)p[0]) &&
728 		      isdigit((int)(unsigned char)p[1]) &&
729 		      isdigit((int)(unsigned char)p[2]) &&
730 		      (p[3] == 0 || isspace((int)(unsigned char)p[3]))));
731 	if (strchr("123", *p) == 0)
732 		exit(1);
733 
734 }
735 
main(int argc,char ** argv)736 int main(int argc, char **argv)
737 {
738 int	argn;
739 int	fd;
740 static struct args arginfo[] = {
741 	{ "host", &clienthost },
742 	{ "localfd", &localfd},
743 	{ "port", &clientport },
744 	{ "printx509", &printx509},
745 	{ "remotefd", &remotefd},
746 	{ "server", &server},
747 	{ "tcpd", &tcpd},
748 	{ "verify", &peer_verify_domain},
749 	{ "statusfd", &statusfd},
750 	{ "protocol", &fdprotocol},
751 	{0}};
752 void (*protocol_func)(int)=0;
753 
754 	setlocale(LC_ALL, "");
755 	errfp=stderr;
756 
757 	argn=argparse(argc, argv, arginfo);
758 
759 	if (statusfd)
760 		statusfp=fdopen(atoi(statusfd), "w");
761 
762 	if (statusfp)
763 		errfp=statusfp;
764 
765 	if (fdprotocol)
766 	{
767 		if (strcmp(fdprotocol, "smtp") == 0)
768 			protocol_func= &smtp_proto;
769 		else if (strcmp(fdprotocol, "imap") == 0)
770 			protocol_func= &imap_proto;
771 		else if (strcmp(fdprotocol, "pop3") == 0)
772 			protocol_func= &pop3_proto;
773 		else
774 		{
775 			fprintf(stderr, "--protocol=%s - unknown protocol.\n",
776 				fdprotocol);
777 			exit(1);
778 		}
779 	}
780 
781 	if (tcpd)
782 	{
783 		dup2(2, 1);
784 		fd=0;
785 	}
786 	else if (remotefd)
787 		fd=atoi(remotefd);
788 	else if (clienthost && clientport)
789 		fd=connectremote(clienthost, clientport);
790 	else
791 	{
792 		fprintf(errfp, "%s: specify remote location.\n",
793 			argv[0]);
794 		return (1);
795 	}
796 
797 	if (fd < 0)	return (1);
798 	if (protocol_func)
799 		(*protocol_func)(fd);
800 
801 	return (dossl(fd, argn, argc, argv));
802 }
803