1 #include <sys/types.h>
2 #include <unistd.h>
3 #include "matrixSsl.h"
4 #include "uidgid.h"
5 #include "prot.h"
6 #include "error.h"
7 #include "strerr.h"
8 #include "fd.h"
9 #include "pathexec.h"
10 #include "stralloc.h"
11 #include "byte.h"
12 #include "taia.h"
13 #include "iopause.h"
14 #include "ndelay.h"
15 #include "fmt.h"
16 #include "scan.h"
17 #include "sgetopt.h"
18 #include "env.h"
19 #include "sig.h"
20 #include "sslerror_str.h"
21 
22 #define USAGEROOT " -u user [-U user] [-/ root] [-C cert] [-K key] [-A ca] [-vc] prog"
23 #define USAGE " [-C cert] [-K key] [-A ca] [-cv] prog"
24 #define VERSION "$Id: 5b49a0244b79fd00a69b028b11d60dde84c7a8a5 $"
25 #define NAME "sslio["
26 #define FATAL "]: fatal: "
27 #define WARNING "]: warning: "
28 #define INFO "]: info: "
29 
30 const char *progname;
31 extern char id[FMT_ULONG];
32 extern char ul[FMT_ULONG];
33 extern int pid;
34 
35 static void finish(void);
die_nomem()36 static void die_nomem() {
37   strerr_die4x(111, NAME, id, FATAL, "out of memory.");
38 }
fatalm(char * m0)39 static void fatalm(char *m0) { strerr_die5sys(111, NAME, id, FATAL, m0, ": "); }
fatalmx(char * m0)40 static void fatalmx(char *m0) { strerr_die4x(111, NAME, id, FATAL, m0); }
fatal(char * m0)41 static void fatal(char *m0) {
42   strerr_warn5(NAME, id, FATAL, m0, ": ", &strerr_sys); finish();
43   _exit(111);
44 }
fatalx(char * m0)45 static void fatalx(char *m0) {
46   strerr_warn4(NAME, id, FATAL, m0, 0); finish();
47   _exit(111);
48 }
fatals(char * m0,int e)49 static void fatals(char *m0, int e) {
50   strerr_warn6(NAME, id, FATAL, m0, ": ", sslerror_str(e), 0); finish();
51   _exit(111);
52 }
warn(char * m0)53 static void warn(char *m0) {
54   strerr_warn5(NAME, id, WARNING, m0, ": ", &strerr_sys);
55 }
warnx(char * m0)56 static void warnx(char *m0) { strerr_warn4(NAME, id, WARNING, m0, 0); }
info(char * m0)57 static void info(char *m0) { strerr_warn4(NAME, id, INFO, m0, 0); }
infou(char * m0,unsigned long u)58 static void infou(char *m0, unsigned long u) {
59   ul[fmt_ulong(ul, u)] =0;
60   strerr_warn5(NAME, id, INFO, m0, ul, 0);
61 }
62 
63 extern char *cert;
64 extern char *key;
65 extern char *ssluser;
66 extern char *ca;
67 extern char *svuser;
68 extern char *root;
69 extern unsigned int client;
70 extern unsigned int verbose;
71 extern struct uidgid ugid, sslugid;
72 extern ssl_t *ssl;
73 extern sslKeys_t *keys;
74 
75 static unsigned long bufsizein =8192;
76 static unsigned long bufsizeou =12288;
77 
78 static int encpipe[2];
79 static int decpipe[2];
80 static int len;
81 static int rc;
82 static int handshake =1;
83 static int getdec =1;
84 static char *s;
85 static unsigned long handshake_timeout =300;
86 
87 static sslBuf_t encin, encou;
88 static stralloc encinbuf ={0};
89 static stralloc encoubuf ={0};
90 static sslBuf_t decin, decou;
91 static stralloc decinbuf ={0};
92 static stralloc decoubuf ={0};
93 
94 static int fdstdin =0;
95 static int fdstdou =1;
96 static unsigned long bytesin =0;
97 static unsigned long bytesou =0;
98 
99 static unsigned char error, alvl, adesc;
100 static char *bad_certificate;
101 
sig_term_handler(void)102 static void sig_term_handler(void) {
103   if (verbose) info("sigterm received, exit.");
104   finish();
105   _exit(0);
106 }
blowup(sslBuf_t * buf,stralloc * sa,unsigned int len)107 unsigned int blowup(sslBuf_t *buf, stralloc *sa, unsigned int len) {
108   sa->len =buf->end -buf->buf;
109   buf->size +=len;
110   if (! stralloc_ready(sa, buf->size)) return(0);
111   buf->end =sa->s +(buf->end -buf->buf);
112   buf->start =sa->s +(buf->start -buf->buf);
113   buf->buf =sa->s;
114   return(1);
115 }
finish(void)116 void finish(void) {
117   if (fdstdou != -1)
118     for (;;) {
119       decou.start =decou.end =decou.buf;
120       rc =matrixSslEncodeClosureAlert(ssl, &decou);
121       if (rc == SSL_FULL) {
122         if (! blowup(&decou, &decoubuf, bufsizeou)) die_nomem();
123         if (verbose > 1) infou("decode output buffer size: ", decou.size);
124         continue;
125       }
126       if (rc == SSL_ERROR)
127         if (verbose) warnx("unable to encode ssl close notify");
128       if (rc == 0) {
129         if (write(fdstdou, decou.start, decou.end -decou.start)
130             != (decou.end -decou.start)) {
131           if (verbose) warn("unable to send ssl close notify");
132           break;
133         }
134         if (verbose > 2) info("sending ssl close notify");
135         if (verbose > 2) infou("write bytes: ", decou.end -decou.start);
136         bytesou +=decou.end -decou.start;
137       }
138       break;
139     }
140   /* bummer */
141   matrixSslFreeKeys(keys);
142   matrixSslDeleteSession(ssl);
143   matrixSslClose();
144   if (fdstdou != -1) close(fdstdou);
145   if (encpipe[0] != -1) close(encpipe[0]);
146   if (fdstdin != -1) close(fdstdin);
147   if (decpipe[1] != -1) close(decpipe[1]);
148   if (verbose) { infou("bytes in: ", bytesin); infou("bytes ou: ", bytesou); }
149 }
validate(sslCertInfo_t * cert,void * arg)150 int validate(sslCertInfo_t *cert, void *arg) {
151   sslCertInfo_t *c =cert;
152 
153   if (bad_certificate) return 1;
154   while (c->next) c =c->next;
155   return(c->verified);
156 }
157 
encode(void)158 void encode(void) {
159   if ((len =read(encpipe[0], encinbuf.s, encin.size)) < 0)
160     fatal("unable to read from prog");
161   if (len == 0) {
162     if (verbose > 2) info("eof reading from proc");
163     finish();
164     _exit(0);
165   }
166   for (;;) {
167     rc =matrixSslEncode(ssl, encin.buf, len, &encou);
168     if (rc == SSL_ERROR) {
169       close(fdstdou); fdstdou =-1;
170       fatalx("unable to encode data");
171     }
172     if (rc == SSL_FULL) {
173       if (! blowup(&encou, &encoubuf, bufsizeou)) die_nomem();
174       if (verbose > 1) infou("encode output buffer size: ", encou.size);
175       continue;
176     }
177     if (write(fdstdou, encou.start, encou.end -encou.start)
178         != encou.end -encou.start) fatal("unable to write to network");
179     if (verbose > 2) infou("write bytes: ", encou.end -encou.start);
180     bytesou +=encou.end -encou.start;
181     encou.start =encou.end =encou.buf =encoubuf.s;
182     return;
183   }
184 }
decode(void)185 void decode(void) {
186   do {
187     if (getdec) {
188       len =decin.size -(decin.end -decin.buf);
189       if ((len =read(fdstdin, decin.end, len)) < 0)
190         fatal("unable to read from network");
191       if (len == 0) {
192         if (verbose > 2) info("eof reading from network");
193         close(fdstdin); close(decpipe[1]);
194         fdstdin =decpipe[1] =-1;
195         return;
196       }
197       if (verbose > 2) infou("read bytes: ", len);
198       bytesin +=len;
199       decin.end +=len;
200       getdec =0;
201     }
202     for (;;) {
203       rc =matrixSslDecode(ssl, &decin, &decou, &error, &alvl, &adesc);
204       if (rc == SSL_SUCCESS) break;
205       if (rc == SSL_ERROR) {
206         if (decou.end > decou.start)
207           if (write(fdstdou, decou.start, decou.end -decou.start)
208               != decou.end -decou.start) warn("unable to write to network");
209         close(fdstdou); fdstdou =-1;
210         fatals("ssl decode error", error);
211       }
212       if (rc == SSL_PROCESS_DATA) {
213         if (write(decpipe[1], decou.start, decou.end -decou.start)
214             != decou.end -decou.start) fatal("unable to write to prog");
215         decou.start =decou.end =decou.buf;
216         if (decin.start > decin.buf) { /* align */
217           byte_copy(decin.buf, decin.end -decin.start, decin.start);
218           decin.end -=decin.start -decin.buf;
219           decin.start =decin.buf;
220         }
221         break;
222       }
223       if (rc == SSL_SEND_RESPONSE) {
224         if (write(fdstdou, decou.start, decou.end -decou.start)
225             != (decou.end -decou.start))
226           fatal("unable to send ssl response");
227         bytesou +=decou.end -decou.start;
228         if (verbose > 2) info("sending ssl handshake response");
229         if (verbose > 2) infou("write bytes: ", decou.end -decou.start);
230         decou.start =decou.end =decou.buf;
231         break;
232       }
233       if (rc == SSL_ALERT) {
234         close(fdstdou); fdstdou =-1;
235         if (adesc != SSL_ALERT_CLOSE_NOTIFY)
236           fatals("ssl alert from peer", adesc);
237         if (verbose > 2) info("ssl close notify from peer");
238         finish();
239         _exit(0);
240       }
241       if (rc == SSL_PARTIAL) {
242         getdec =1;
243         if (decin.size -(decin.end -decin.buf) < bufsizein) {
244           if (! blowup(&decin, &decinbuf, bufsizein)) die_nomem();
245           if (verbose > 1) infou("decode input buffer size: ", decin.size);
246         }
247         break;
248       }
249       if (rc == SSL_FULL) {
250         if (! blowup(&decou, &decoubuf, bufsizeou)) die_nomem();
251         if (verbose > 1) infou("decode output buffer size: ", decou.size);
252         continue;
253       }
254     }
255     if (decin.start == decin.end) {
256       decin.start =decin.end =decin.buf;
257       getdec =1;
258     }
259   } while (getdec == 0);
260   if (handshake)
261     if (matrixSslHandshakeIsComplete(ssl)) {
262       handshake =0;
263       if (verbose > 2) info("ssl handshake complete");
264     }
265 }
266 
doio(void)267 void doio(void) {
268   iopause_fd x[2];
269   struct taia deadline;
270   struct taia now;
271   struct taia timeout;
272 
273   if (! stralloc_ready(&encinbuf, bufsizein)) die_nomem();
274   encin.buf =encin.start =encin.end =encinbuf.s; encin.size =bufsizein;
275   if (! stralloc_ready(&decinbuf, bufsizein)) die_nomem();
276   decin.buf =decin.start =decin.end =decinbuf.s; decin.size =bufsizein;
277   if (! stralloc_ready(&encoubuf, bufsizeou)) die_nomem();
278   encou.buf =encou.start =encou.end =encoubuf.s; encou.size =bufsizeou;
279   if (! stralloc_ready(&decoubuf, bufsizeou)) die_nomem();
280   decou.buf =decou.start =decou.end =decoubuf.s; decou.size =bufsizeou;
281 
282   if (client) {
283     rc =matrixSslEncodeClientHello(ssl, &decou, 0);
284     if (rc != 0) fatalx("unable to encode client hello");
285     if (write(fdstdou, decou.start, decou.end -decou.start)
286         != (decou.end -decou.start))
287       fatal("unable to send client hello");
288     if (verbose > 2) info("sending client hello");
289     if (verbose > 2) infou("write bytes: ", decou.end -decou.start);
290     bytesou +=decou.end -decou.start;
291     decou.start =decou.end =decou.buf;
292   }
293 
294   taia_now(&now);
295   taia_uint(&timeout, handshake_timeout);
296   taia_add(&timeout, &now, &timeout);
297 
298   for (;;) {
299     iopause_fd *xx =x;
300     int l =2;
301 
302     x[0].fd =encpipe[0];
303     x[0].events =IOPAUSE_READ;
304     x[0].revents =0;
305     x[1].fd =fdstdin;
306     x[1].events =IOPAUSE_READ;
307     x[1].revents =0;
308 
309     if ((x[0].fd == -1) || handshake) { --l; ++xx; }
310     if (x[1].fd == -1) --l;
311     if (! l) return;
312 
313     taia_now(&now);
314     if (handshake) {
315       if (taia_less(&timeout, &now)) {
316         if (verbose) info("ssl handshake timeout, exit.");
317         return;
318       }
319       deadline.sec =timeout.sec;
320       deadline.nano =timeout.nano;
321       deadline.atto =timeout.atto;
322     }
323     else {
324       taia_uint(&deadline, 30);
325       taia_add(&deadline, &now, &deadline);
326     }
327     iopause(xx, l, &deadline, &now);
328 
329     if (x[0].revents) encode();
330     if (x[1].revents) decode();
331   }
332 }
333 
ssl_io(unsigned int newsession,const char ** prog)334 int ssl_io(unsigned int newsession, const char **prog) {
335   if (client) { fdstdin =6; fdstdou =7; }
336   bad_certificate = env_get("SSLIO_BAD_CERTIFICATE");
337   if ((s =env_get("SSLIO_BUFIN"))) scan_ulong(s, &bufsizein);
338   if ((s =env_get("SSLIO_BUFOU"))) scan_ulong(s, &bufsizeou);
339   if (bufsizein < 64) bufsizein =64;
340   if (bufsizeou < 64) bufsizeou =64;
341   if ((s =env_get("SSLIO_HANDSHAKE_TIMEOUT")))
342     scan_ulong(s, &handshake_timeout);
343   if (handshake_timeout < 1) handshake_timeout =1;
344 
345   if (pipe(encpipe) == -1) fatalm("unable to create pipe for encoding");
346   if (pipe(decpipe) == -1) fatalm("unable to create pipe for decoding");
347   if ((pid =fork()) == -1) fatalm("unable to fork");
348   if (pid == 0) {
349     if (close(encpipe[1]) == -1)
350       fatalm("unable to close encoding pipe output");
351     if (close(decpipe[0]) == -1)
352       fatalm("unable to close decoding pipe input");
353     if (newsession) if (matrixSslOpen() < 0) fatalm("unable to initialize ssl");
354     if (root) {
355       if (chdir(root) == -1) fatalm("unable to change to new root directory");
356       if (chroot(".") == -1) fatalm("unable to chroot");
357     }
358     if (ssluser) {
359       /* drop permissions */
360       if (setgroups(sslugid.gids, sslugid.gid) == -1)
361         fatal("unable to set groups");
362       if (setgid(*sslugid.gid) == -1) fatal("unable to set gid");
363       if (prot_uid(sslugid.uid) == -1) fatalm("unable to set uid");
364     }
365     if (newsession) {
366       if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
367         if (client) fatalm("unable to read cert, key, or ca file");
368         fatalm("unable to read cert or key file");
369       }
370       if (matrixSslNewSession(&ssl, keys, 0, client?0:SSL_FLAGS_SERVER) < 0)
371         fatalmx("unable to create ssl session");
372     }
373     if (client)
374       if (ca || bad_certificate) matrixSslSetCertValidator(ssl, &validate, 0);
375 
376     sig_catch(sig_term, sig_term_handler);
377     sig_ignore(sig_pipe);
378     doio();
379     finish();
380     _exit(0);
381   }
382   if (close(encpipe[0]) == -1) fatalm("unable to close encoding pipe input");
383   if (close(decpipe[1]) == -1) fatalm("unable to close decoding pipe output");
384   if (fd_move(fdstdin, decpipe[0]) == -1)
385     fatalm("unable to setup filedescriptor for decoding");
386   if (fd_move(fdstdou, encpipe[1]) == -1)
387     fatalm("unable to setup filedescriptor for encoding");
388   sslCloseOsdep();
389   if (svuser) {
390     if (setgroups(ugid.gids, ugid.gid) == -1)
391       fatal("unable to set groups for prog");
392     if (setgid(*ugid.gid) == -1) fatal("unable to set gid for prog");
393     if (prot_uid(ugid.uid) == -1) fatalm("unable to set uid for prog");
394   }
395   pathexec(prog);
396   fatalm("unable to run prog");
397   return(111);
398 }
399