xref: /plan9/sys/src/cmd/tlssrv.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
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 	}
100 	va_end(ap);
101 	return 0;
102 }
103 
104 void
105 main(int argc, char *argv[])
106 {
107 	TLSconn *conn;
108 	uchar buf[BufSize];
109 	char *cert;
110 	int n, fd, clearfd;
111 
112 	debug = 0;
113 	remotesys = nil;
114 	cert = nil;
115 	logfile = nil;
116 	ARGBEGIN{
117 	case 'D':
118 		debug++;
119 		break;
120 	case 'c':
121 		cert = ARGF();
122 		break;
123 	case 'l':
124 		logfile = ARGF();
125 		break;
126 	case 'r':
127 		remotesys = ARGF();
128 		break;
129 	default:
130 		fprint(2, "usage: tlssrv -c cert [-D] [-l logfile] [-r remotesys] [cmd args...]\n");
131 		fprint(2, "  after  auth/secretpem key.pem > /mnt/factotum/ctl\n");
132 		exits("usage");
133 	}ARGEND
134 
135 	if(cert == nil)
136 		sysfatal("no certificate specified");
137 	if(remotesys == nil)
138 		remotesys = "";
139 	conn = (TLSconn*)mallocz(sizeof *conn, 1);
140 	if(conn == nil)
141 		sysfatal("out of memory");
142 	conn->cert = readcert(cert, &conn->certlen);
143 	if(debug)
144 		conn->trace = reporter;
145 
146 	clearfd = 0;
147 	fd = 1;
148 	if(debug > 1)
149 		fd = dumper(fd);
150 	fd = tlsServer(fd, conn);
151 	if(fd < 0){
152 		reporter("failed: %r\n");
153 		exits(0);
154 	}
155 	reporter("open\n");
156 
157 	if(argc > 0){
158 		if(pipe(p) < 0)
159 			exits("pipe");
160 		switch(fork()){
161 		case 0:
162 			close(fd);
163 			dup(p[0], 0);
164 			dup(p[0], 1);
165 			close(p[1]);
166 			close(p[0]);
167 			exec(argv[0], argv);
168 			reporter("can't exec %s: %r\n", argv[0]);
169 			_exits("exec");
170 		case -1:
171 			exits("fork");
172 		default:
173 			close(p[0]);
174 			clearfd = p[1];
175 			break;
176 		}
177 	}
178 
179 	rfork(RFNOTEG);
180 	notify(death);
181 	switch(rfork(RFPROC)){
182 	case -1:
183 		sysfatal("can't fork");
184 	case 0:
185 		for(;;){
186 			n = read(clearfd, buf, BufSize);
187 			if(n <= 0)
188 				break;
189 			if(write(fd, buf, n) != n)
190 				break;
191 		}
192 		break;
193 	default:
194 		for(;;){
195 			n = read(fd, buf, BufSize);
196 			if(n <= 0)
197 				break;
198 			if(write(clearfd, buf, n) != n)
199 				break;
200 		}
201 		break;
202 	}
203 	death(nil, nil);
204 }
205