xref: /plan9/sys/src/cmd/tlssrv.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mp.h>
5 #include <libsec.h>
6 
7 enum{ BufSize = 8192 };
8 
9 char *remotesys, *logfile;
10 int debug, p[2];
11 
12 void
13 death(void *, char *)
14 {
15 	int pid;
16 
17 	close(0);
18 	close(1);
19 	close(p[1]);
20 	pid = getpid();
21 	postnote(PNGROUP, pid, "die");
22 	postnote(PNGROUP, pid, "die");
23 	postnote(PNGROUP, pid, "die");
24 	_exits(0);
25 }
26 
27 static void
28 dump(int fd, uchar *buf, int n, char *label)
29 {
30 	Biobuf bout;
31 	int i;
32 
33 	Binit(&bout, fd, OWRITE);
34 	Bprint(&bout, "%s<%d>: ", label, n);
35 	if(n > 64)
36 		n = 64;
37 	for(i = 0; i < n; i++)
38 		Bprint(&bout, "%2.2x ", buf[i]);
39 	Bprint(&bout, "\n");
40 	Bterm(&bout);
41 }
42 
43 static void
44 xfer(int from, int to, int cfd, char *label)
45 {
46 	uchar buf[BufSize];
47 	int n;
48 
49 	if(fork() == 0)
50 		return;
51 
52 	close(cfd);
53 	for(;;){
54 		n = read(from, buf, sizeof(buf));
55 		if(n <= 0){
56 			fprint(2, "%s EOF\n", label);
57 			close(to);
58 			close(from);
59 			death(nil, nil);
60 		}
61 		dump(2, buf, n, label);
62 		n = write(to, buf, n);
63 		if(n < 0){
64 			fprint(2, "%s write err\n", label);
65 			close(to);
66 			close(from);
67 			death(nil, nil);
68 		}
69 	}
70 }
71 
72 static int
73 dumper(int fd)
74 {
75 	int p[2];
76 
77 	if(pipe(p) < 0)
78 		sysfatal("can't make pipe: %r");
79 
80 	xfer(fd, p[0], p[1], "read");
81 	xfer(p[0], fd, p[1], "write");
82 	close(p[0]);
83 	return p[1];
84 }
85 
86 static int
87 reporter(char *fmt, ...)
88 {
89 	va_list ap;
90 	char buf[2000];
91 
92 	va_start(ap, fmt);
93 	if(logfile){
94 		vsnprint(buf, sizeof buf, fmt, ap);
95 		syslog(0, logfile, "%s tls reports %s", remotesys, buf);
96 	}else{
97 		fprint(2, "%s: %s tls reports ", argv0, remotesys);
98 		vfprint(2, fmt, ap);
99 		fprint(2, "\n");
100 	}
101 	va_end(ap);
102 	return 0;
103 }
104 
105 void
106 main(int argc, char *argv[])
107 {
108 	TLSconn *conn;
109 	uchar buf[BufSize];
110 	char *cert;
111 	int n, fd, clearfd;
112 
113 	debug = 0;
114 	remotesys = nil;
115 	cert = nil;
116 	logfile = nil;
117 	ARGBEGIN{
118 	case 'D':
119 		debug++;
120 		break;
121 	case 'c':
122 		cert = ARGF();
123 		break;
124 	case 'l':
125 		logfile = ARGF();
126 		break;
127 	case 'r':
128 		remotesys = ARGF();
129 		break;
130 	default:
131 		fprint(2, "usage: tlssrv -c cert [-D] [-l logfile] [-r remotesys] [cmd args...]\n");
132 		fprint(2, "  after  auth/secretpem key.pem > /mnt/factotum/ctl\n");
133 		exits("usage");
134 	}ARGEND
135 
136 	if(cert == nil)
137 		sysfatal("no certificate specified");
138 	if(remotesys == nil)
139 		remotesys = "";
140 	conn = (TLSconn*)mallocz(sizeof *conn, 1);
141 	if(conn == nil)
142 		sysfatal("out of memory");
143 	conn->chain = readcertchain(cert);
144 	if (conn->chain == nil)
145 		sysfatal("can't read certificate");
146 	conn->cert = conn->chain->pem;
147 	conn->certlen = conn->chain->pemlen;
148 	conn->chain = conn->chain->next;
149 	if(debug)
150 		conn->trace = reporter;
151 
152 	clearfd = 0;
153 	fd = 1;
154 	if(debug > 1)
155 		fd = dumper(fd);
156 	fd = tlsServer(fd, conn);
157 	if(fd < 0){
158 		reporter("failed: %r");
159 		exits(0);
160 	}
161 	reporter("open\n");
162 
163 	if(argc > 0){
164 		if(pipe(p) < 0)
165 			exits("pipe");
166 		switch(fork()){
167 		case 0:
168 			close(fd);
169 			dup(p[0], 0);
170 			dup(p[0], 1);
171 			close(p[1]);
172 			close(p[0]);
173 			exec(argv[0], argv);
174 			reporter("can't exec %s: %r", argv[0]);
175 			_exits("exec");
176 		case -1:
177 			exits("fork");
178 		default:
179 			close(p[0]);
180 			clearfd = p[1];
181 			break;
182 		}
183 	}
184 
185 	rfork(RFNOTEG);
186 	notify(death);
187 	switch(rfork(RFPROC)){
188 	case -1:
189 		sysfatal("can't fork");
190 	case 0:
191 		for(;;){
192 			n = read(clearfd, buf, BufSize);
193 			if(n <= 0)
194 				break;
195 			if(write(fd, buf, n) != n)
196 				break;
197 		}
198 		break;
199 	default:
200 		for(;;){
201 			n = read(fd, buf, BufSize);
202 			if(n <= 0)
203 				break;
204 			if(write(clearfd, buf, n) != n)
205 				break;
206 		}
207 		break;
208 	}
209 	death(nil, nil);
210 }
211