1 /*-
2 * SSLsplit - transparent SSL/TLS interception
3 * https://www.roe.ch/SSLsplit
4 *
5 * Copyright (c) 2009-2019, Daniel Roethlisberger <daniel@roe.ch>.
6 * Copyright (c) 2017-2021, Soner Tari <sonertari@gmail.com>.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 * 1. Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "privsep.h"
31
32 #include "sys.h"
33 #include "util.h"
34 #include "log.h"
35 #include "attrib.h"
36 #include "defaults.h"
37
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/select.h>
41 #include <sys/wait.h>
42 #include <netinet/in.h>
43 #include <signal.h>
44 #include <unistd.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <libgen.h>
50 #include <fcntl.h>
51
52
53 /*
54 * Privilege separation functionality.
55 *
56 * The server code has limitations on the internal functionality that can be
57 * used, namely only those that are initialized before forking.
58 */
59
60 /* maximal message sizes */
61 #define PRIVSEP_MAX_REQ_SIZE 512 /* arbitrary limit */
62 #define PRIVSEP_MAX_ANS_SIZE (1+sizeof(int))
63 /* command byte */
64 #define PRIVSEP_REQ_CLOSE 0 /* closing command socket */
65 #define PRIVSEP_REQ_OPENFILE 1 /* open content log file */
66 #define PRIVSEP_REQ_OPENFILE_P 2 /* open content log file w/mkpath */
67 #define PRIVSEP_REQ_OPENSOCK 3 /* open socket and pass fd */
68 #define PRIVSEP_REQ_CERTFILE 4 /* open cert file in certgendir */
69 #ifndef WITHOUT_USERAUTH
70 #define PRIVSEP_REQ_UPDATE_ATIME 5 /* update ip,user atime */
71 #endif /* !WITHOUT_USERAUTH */
72 /* response byte */
73 #define PRIVSEP_ANS_SUCCESS 0 /* success */
74 #define PRIVSEP_ANS_UNK_CMD 1 /* unknown command */
75 #define PRIVSEP_ANS_INVALID 2 /* invalid message */
76 #define PRIVSEP_ANS_DENIED 3 /* request denied */
77 #define PRIVSEP_ANS_SYS_ERR 4 /* system error; arg=errno */
78
79 /* Whether we short-circuit calls to privsep_client_* directly to
80 * privsep_server_* within the client process, bypassing the privilege
81 * separation mechanism; this is a performance optimization for use cases
82 * where the user chooses performance over security, especially with options
83 * that require privsep operations for each connection passing through.
84 * In the current implementation, for consistency, we still fork normally, but
85 * will not actually send any privsep requests to the parent process. */
86 static int privsep_fastpath;
87
88 /* communication with signal handler */
89 static volatile sig_atomic_t received_sighup;
90 static volatile sig_atomic_t received_sigint;
91 static volatile sig_atomic_t received_sigquit;
92 static volatile sig_atomic_t received_sigterm;
93 static volatile sig_atomic_t received_sigchld;
94 static volatile sig_atomic_t received_sigusr1;
95 /* write end of pipe used for unblocking select */
96 static volatile sig_atomic_t selfpipe_wrfd;
97
98 static void
privsep_server_signal_handler(int sig)99 privsep_server_signal_handler(int sig)
100 {
101 int saved_errno;
102
103 saved_errno = errno;
104
105 #ifdef DEBUG_PRIVSEP_SERVER
106 log_dbg_printf("privsep_server_signal_handler\n");
107 #endif /* DEBUG_PRIVSEP_SERVER */
108
109 switch (sig) {
110 case SIGHUP:
111 received_sighup = 1;
112 break;
113 case SIGINT:
114 received_sigint = 1;
115 break;
116 case SIGQUIT:
117 received_sigquit = 1;
118 break;
119 case SIGTERM:
120 received_sigterm = 1;
121 break;
122 case SIGCHLD:
123 received_sigchld = 1;
124 break;
125 case SIGUSR1:
126 received_sigusr1 = 1;
127 break;
128 }
129 if (selfpipe_wrfd != -1) {
130 ssize_t n;
131
132 #ifdef DEBUG_PRIVSEP_SERVER
133 log_dbg_printf("writing to selfpipe_wrfd %i\n", selfpipe_wrfd);
134 #endif /* DEBUG_PRIVSEP_SERVER */
135 do {
136 n = write(selfpipe_wrfd, "!", 1);
137 } while (n == -1 && errno == EINTR);
138 if (n == -1) {
139 log_err_level_printf(LOG_CRIT, "Failed to write from signal handler: "
140 "%s (%i)\n", strerror(errno), errno);
141 /* ignore error */
142 }
143 #ifdef DEBUG_PRIVSEP_SERVER
144 } else {
145 log_dbg_printf("selfpipe_wrfd is %i - not writing\n", selfpipe_wrfd);
146 #endif /* DEBUG_PRIVSEP_SERVER */
147 }
148 errno = saved_errno;
149 }
150
151 static int WUNRES
privsep_server_openfile_verify(global_t * global,const char * fn,UNUSED int mkpath)152 privsep_server_openfile_verify(global_t *global, const char *fn, UNUSED int mkpath)
153 {
154 /* Prefix must match one of the active log files that use privsep. */
155 do {
156 if (global->contentlog) {
157 if (strstr(fn, global->contentlog_isspec
158 ? global->contentlog_basedir
159 : global->contentlog) == fn)
160 break;
161 }
162 if (global->pcaplog) {
163 if (strstr(fn, global->pcaplog_isspec
164 ? global->pcaplog_basedir
165 : global->pcaplog) == fn)
166 break;
167 }
168 if (global->connectlog) {
169 if (strstr(fn, global->connectlog) == fn)
170 break;
171 }
172 if (global->masterkeylog) {
173 if (strstr(fn, global->masterkeylog) == fn)
174 break;
175 }
176 return -1;
177 } while (0);
178
179 /* Path must not contain dot-dot to prevent escaping the prefix. */
180 if (strstr(fn, "/../"))
181 return -1;
182
183 return 0;
184 }
185
186 static int WUNRES
privsep_server_openfile(const char * fn,int mkpath)187 privsep_server_openfile(const char *fn, int mkpath)
188 {
189 int fd, tmp;
190
191 if (mkpath) {
192 char *filedir, *fn2;
193
194 fn2 = strdup(fn);
195 if (!fn2) {
196 tmp = errno;
197 log_err_level_printf(LOG_CRIT, "Could not duplicate filname: %s (%i)\n",
198 strerror(errno), errno);
199 errno = tmp;
200 return -1;
201 }
202 filedir = dirname(fn2);
203 if (!filedir) {
204 tmp = errno;
205 log_err_level_printf(LOG_CRIT, "Could not get dirname: %s (%i)\n",
206 strerror(errno), errno);
207 free(fn2);
208 errno = tmp;
209 return -1;
210 }
211 if (sys_mkpath(filedir, DFLT_DIRMODE) == -1) {
212 tmp = errno;
213 log_err_level_printf(LOG_CRIT, "Could not create directory '%s': %s (%i)\n",
214 filedir, strerror(errno), errno);
215 free(fn2);
216 errno = tmp;
217 return -1;
218 }
219 free(fn2);
220 }
221
222 fd = open(fn, O_RDWR|O_CREAT, DFLT_FILEMODE);
223 if (fd == -1) {
224 tmp = errno;
225 log_err_level_printf(LOG_CRIT, "Failed to open '%s': %s (%i)\n",
226 fn, strerror(errno), errno);
227 errno = tmp;
228 return -1;
229 }
230 if (lseek(fd, 0, SEEK_END) == -1) {
231 tmp = errno;
232 log_err_level_printf(LOG_CRIT, "Failed to seek on '%s': %s (%i)\n",
233 fn, strerror(errno), errno);
234 errno = tmp;
235 return -1;
236 }
237 return fd;
238 }
239
240 static int WUNRES
privsep_server_opensock_verify(global_t * global,void * arg)241 privsep_server_opensock_verify(global_t *global, void *arg)
242 {
243 /* This check is safe, because modifications of the spec in the child
244 * process do not affect the copy of the spec here in the parent. */
245 for (proxyspec_t *spec = global->spec; spec; spec = spec->next) {
246 if (spec == arg)
247 return 0;
248 }
249 return 1;
250 }
251
252 static int WUNRES
privsep_server_opensock(const proxyspec_t * spec)253 privsep_server_opensock(const proxyspec_t *spec)
254 {
255 evutil_socket_t fd;
256 int on = 1;
257 int rv;
258
259 fd = socket(spec->listen_addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
260 if (fd == -1) {
261 log_err_level_printf(LOG_CRIT, "Error from socket(): %s (%i)\n",
262 strerror(errno), errno);
263 evutil_closesocket(fd);
264 return -1;
265 }
266
267 rv = evutil_make_socket_nonblocking(fd);
268 if (rv == -1) {
269 log_err_level_printf(LOG_CRIT, "Error making socket nonblocking: %s (%i)\n",
270 strerror(errno), errno);
271 evutil_closesocket(fd);
272 return -1;
273 }
274
275 rv = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on));
276 if (rv == -1) {
277 log_err_level_printf(LOG_CRIT, "Error from setsockopt(SO_KEEPALIVE): %s (%i)\n",
278 strerror(errno), errno);
279 evutil_closesocket(fd);
280 return -1;
281 }
282
283 rv = evutil_make_listen_socket_reuseable(fd);
284 if (rv == -1) {
285 log_err_level_printf(LOG_CRIT, "Error from setsockopt(SO_REUSABLE): %s\n",
286 strerror(errno));
287 evutil_closesocket(fd);
288 return -1;
289 }
290
291 if (spec->natsocket && (spec->natsocket(fd) == -1)) {
292 log_err_level_printf(LOG_CRIT, "Error from spec->natsocket()\n");
293 evutil_closesocket(fd);
294 return -1;
295 }
296
297 rv = bind(fd, (struct sockaddr *)&spec->listen_addr,
298 spec->listen_addrlen);
299 if (rv == -1) {
300 log_err_level_printf(LOG_CRIT, "Error from bind(): %s\n", strerror(errno));
301 evutil_closesocket(fd);
302 return -1;
303 }
304
305 return fd;
306 }
307
308 static int WUNRES
privsep_server_certfile_verify(global_t * global,const char * fn)309 privsep_server_certfile_verify(global_t *global, const char *fn)
310 {
311 if (!global->certgendir)
312 return -1;
313 if (strstr(fn, global->certgendir) != fn || strstr(fn, "/../"))
314 return -1;
315 return 0;
316 }
317
318 static int WUNRES
privsep_server_certfile(const char * fn)319 privsep_server_certfile(const char *fn)
320 {
321 int fd;
322
323 fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, DFLT_FILEMODE);
324 if (fd == -1 && errno != EEXIST) {
325 log_err_level_printf(LOG_CRIT, "Failed to open '%s': %s (%i)\n",
326 fn, strerror(errno), errno);
327 return -1;
328 }
329 return fd;
330 }
331
332 #ifndef WITHOUT_USERAUTH
333 static int WUNRES
privsep_server_update_atime(global_t * global,const userdbkeys_t * keys)334 privsep_server_update_atime(global_t *global, const userdbkeys_t *keys)
335 {
336 time_t atime = time(NULL);
337 // @todo Do we really need to reset the stmt, as we always reset while returning?
338 sqlite3_reset(global->update_user_atime);
339 sqlite3_bind_int(global->update_user_atime, 1, atime);
340 sqlite3_bind_text(global->update_user_atime, 2, keys->ip, -1, NULL);
341 sqlite3_bind_text(global->update_user_atime, 3, keys->user, -1, NULL);
342 sqlite3_bind_text(global->update_user_atime, 4, keys->ether, -1, NULL);
343
344 int rc = sqlite3_step(global->update_user_atime);
345
346 // Do not retry in case we cannot acquire db file or database: SQLITE_BUSY or SQLITE_LOCKED respectively
347 // No need to waste resources, atime update is not so critical
348 if (rc == SQLITE_DONE) {
349 log_dbg_printf("privsep_server_update_atime: Updated atime of user %s=%lld\n", keys->user, (long long)atime);
350 } else {
351 log_err_printf("Error updating user atime: %s\n", sqlite3_errmsg(global->userdb));
352 }
353 sqlite3_reset(global->update_user_atime);
354 return 0;
355 }
356 #endif /* !WITHOUT_USERAUTH */
357
358 /*
359 * Handle a single request on a readable server socket.
360 * Returns 0 on success, 1 on EOF and -1 on error.
361 */
362 static int WUNRES
privsep_server_handle_req(global_t * global,int srvsock)363 privsep_server_handle_req(global_t *global, int srvsock)
364 {
365 char req[PRIVSEP_MAX_REQ_SIZE];
366 char ans[PRIVSEP_MAX_ANS_SIZE];
367 ssize_t n;
368 int mkpath = 0;
369
370 if ((n = sys_recvmsgfd(srvsock, req, sizeof(req),
371 NULL)) == -1) {
372 if (errno == EPIPE || errno == ECONNRESET) {
373 /* unfriendly EOF, leave server */
374 return 1;
375 }
376 log_err_level_printf(LOG_CRIT, "Failed to receive msg: %s (%i)\n",
377 strerror(errno), errno);
378 return -1;
379 }
380 if (n == 0) {
381 /* EOF, leave server; will not happen for SOCK_DGRAM sockets */
382 return 1;
383 }
384 log_dbg_printf("Received privsep req type %02x sz %zd on srvsock %i\n",
385 req[0], n, srvsock);
386 switch (req[0]) {
387 case PRIVSEP_REQ_CLOSE: {
388 /* client indicates EOF through close message */
389 return 1;
390 }
391 case PRIVSEP_REQ_OPENFILE_P:
392 mkpath = 1;
393 /* fall through */
394 case PRIVSEP_REQ_OPENFILE: {
395 char *fn;
396 int fd;
397
398 if (n < 2) {
399 ans[0] = PRIVSEP_ANS_INVALID;
400 if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
401 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
402 ")\n", strerror(errno), errno);
403 return -1;
404 }
405 }
406 if (!(fn = malloc(n))) {
407 ans[0] = PRIVSEP_ANS_SYS_ERR;
408 *((int*)&ans[1]) = errno;
409 if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
410 -1) == -1) {
411 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
412 ")\n", strerror(errno), errno);
413 return -1;
414 }
415 return 0;
416 }
417 memcpy(fn, req + 1, n - 1);
418 fn[n - 1] = '\0';
419 if (privsep_server_openfile_verify(global, fn, mkpath) == -1) {
420 free(fn);
421 ans[0] = PRIVSEP_ANS_DENIED;
422 if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
423 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
424 ")\n", strerror(errno), errno);
425 return -1;
426 }
427 return 0;
428 }
429 if ((fd = privsep_server_openfile(fn, mkpath)) == -1) {
430 free(fn);
431 ans[0] = PRIVSEP_ANS_SYS_ERR;
432 *((int*)&ans[1]) = errno;
433 if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
434 -1) == -1) {
435 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
436 ")\n", strerror(errno), errno);
437 return -1;
438 }
439 return 0;
440 } else {
441 free(fn);
442 ans[0] = PRIVSEP_ANS_SUCCESS;
443 if (sys_sendmsgfd(srvsock, ans, 1, fd) == -1) {
444 close(fd);
445 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
446 ")\n", strerror(errno), errno);
447 return -1;
448 }
449 close(fd);
450 return 0;
451 }
452 /* not reached */
453 break;
454 }
455 case PRIVSEP_REQ_OPENSOCK: {
456 proxyspec_t *arg;
457 int s;
458
459 if (n != sizeof(char) + sizeof(arg)) {
460 ans[0] = PRIVSEP_ANS_INVALID;
461 if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
462 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
463 ")\n", strerror(errno), errno);
464 return -1;
465 }
466 return 0;
467 }
468 arg = *(proxyspec_t**)(&req[1]);
469 if (privsep_server_opensock_verify(global, arg) == -1) {
470 ans[0] = PRIVSEP_ANS_DENIED;
471 if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
472 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
473 ")\n", strerror(errno), errno);
474 return -1;
475 }
476 return 0;
477 }
478 if ((s = privsep_server_opensock(arg)) == -1) {
479 ans[0] = PRIVSEP_ANS_SYS_ERR;
480 *((int*)&ans[1]) = errno;
481 if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
482 -1) == -1) {
483 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
484 ")\n", strerror(errno), errno);
485 return -1;
486 }
487 return 0;
488 } else {
489 ans[0] = PRIVSEP_ANS_SUCCESS;
490 if (sys_sendmsgfd(srvsock, ans, 1, s) == -1) {
491 evutil_closesocket(s);
492 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
493 ")\n", strerror(errno), errno);
494 return -1;
495 }
496 evutil_closesocket(s);
497 return 0;
498 }
499 /* not reached */
500 break;
501 }
502 #ifndef WITHOUT_USERAUTH
503 case PRIVSEP_REQ_UPDATE_ATIME: {
504 userdbkeys_t arg;
505
506 if (n != sizeof(char) + sizeof(userdbkeys_t)) {
507 ans[0] = PRIVSEP_ANS_INVALID;
508 if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
509 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
510 ")\n", strerror(errno), errno);
511 return -1;
512 }
513 return 0;
514 }
515 arg = *(userdbkeys_t*)(&req[1]);
516 if (privsep_server_update_atime(global, &arg) == -1) {
517 ans[0] = PRIVSEP_ANS_SYS_ERR;
518 *((int*)&ans[1]) = errno;
519 if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
520 -1) == -1) {
521 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
522 ")\n", strerror(errno), errno);
523 return -1;
524 }
525 return 0;
526 } else {
527 ans[0] = PRIVSEP_ANS_SUCCESS;
528 // @attention Pass -1 as the 4th param, otherwise passing 0 opens an stdin (fd 0), causing fd leak
529 if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
530 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
531 ")\n", strerror(errno), errno);
532 return -1;
533 }
534 return 0;
535 }
536 /* not reached */
537 break;
538 }
539 #endif /* !WITHOUT_USERAUTH */
540 case PRIVSEP_REQ_CERTFILE: {
541 char *fn;
542 int fd;
543
544 if (n < 2) {
545 ans[0] = PRIVSEP_ANS_INVALID;
546 if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
547 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
548 ")\n", strerror(errno), errno);
549 return -1;
550 }
551 }
552 if (!(fn = malloc(n))) {
553 ans[0] = PRIVSEP_ANS_SYS_ERR;
554 *((int*)&ans[1]) = errno;
555 if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
556 -1) == -1) {
557 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
558 ")\n", strerror(errno), errno);
559 return -1;
560 }
561 return 0;
562 }
563 memcpy(fn, req + 1, n - 1);
564 fn[n - 1] = '\0';
565 if (privsep_server_certfile_verify(global, fn) == -1) {
566 free(fn);
567 ans[0] = PRIVSEP_ANS_DENIED;
568 if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
569 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
570 ")\n", strerror(errno), errno);
571 return -1;
572 }
573 return 0;
574 }
575 if ((fd = privsep_server_certfile(fn)) == -1) {
576 free(fn);
577 ans[0] = PRIVSEP_ANS_SYS_ERR;
578 *((int*)&ans[1]) = errno;
579 if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
580 -1) == -1) {
581 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
582 ")\n", strerror(errno), errno);
583 return -1;
584 }
585 return 0;
586 } else {
587 free(fn);
588 ans[0] = PRIVSEP_ANS_SUCCESS;
589 if (sys_sendmsgfd(srvsock, ans, 1, fd) == -1) {
590 close(fd);
591 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
592 ")\n", strerror(errno), errno);
593 return -1;
594 }
595 close(fd);
596 return 0;
597 }
598 /* not reached */
599 break;
600 }
601 default:
602 ans[0] = PRIVSEP_ANS_UNK_CMD;
603 if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
604 log_err_level_printf(LOG_CRIT, "Sending message failed: %s (%i"
605 ")\n", strerror(errno), errno);
606 return -1;
607 }
608 }
609 return 0;
610 }
611
612 /*
613 * Privilege separation server (main privileged monitor loop)
614 *
615 * sigpipe is the self-pipe trick pipe used for communicating signals to
616 * the main event loop and break out of select() without race conditions.
617 * srvsock[] is a dynamic array of connected privsep server sockets to serve.
618 * Caller is responsible for freeing memory after returning, if necessary.
619 * childpid is the pid of the child process to forward signals to.
620 *
621 * Returns 0 on a successful clean exit and -1 on errors.
622 */
623 static int
privsep_server(global_t * global,int sigpipe,int srvsock[],size_t nsrvsock,pid_t childpid)624 privsep_server(global_t *global, int sigpipe, int srvsock[], size_t nsrvsock,
625 pid_t childpid)
626 {
627 int srveof[nsrvsock];
628 size_t i = 0;
629
630 for (i = 0; i < nsrvsock; i++) {
631 srveof[i] = 0;
632 }
633
634 for (;;) {
635 fd_set readfds;
636 int maxfd, rv;
637
638 #ifdef DEBUG_PRIVSEP_SERVER
639 log_dbg_printf("privsep_server select()\n");
640 #endif /* DEBUG_PRIVSEP_SERVER */
641 do {
642 FD_ZERO(&readfds);
643 FD_SET(sigpipe, &readfds);
644 maxfd = sigpipe;
645 for (i = 0; i < nsrvsock; i++) {
646 if (!srveof[i]) {
647 FD_SET(srvsock[i], &readfds);
648 maxfd = util_max(maxfd, srvsock[i]);
649 }
650 }
651 rv = select(maxfd + 1, &readfds, NULL, NULL, NULL);
652 #ifdef DEBUG_PRIVSEP_SERVER
653 log_dbg_printf("privsep_server woke up (1)\n");
654 #endif /* DEBUG_PRIVSEP_SERVER */
655 } while (rv == -1 && errno == EINTR);
656 if (rv == -1) {
657 log_err_level_printf(LOG_CRIT, "select() failed: %s (%i)\n",
658 strerror(errno), errno);
659 return -1;
660 }
661 #ifdef DEBUG_PRIVSEP_SERVER
662 log_dbg_printf("privsep_server woke up (2)\n");
663 #endif /* DEBUG_PRIVSEP_SERVER */
664
665 if (FD_ISSET(sigpipe, &readfds)) {
666 char buf[16];
667 ssize_t n;
668 /* first drain the signal pipe, then deal with
669 * all the individual signal flags */
670 n = read(sigpipe, buf, sizeof(buf));
671 if (n == -1) {
672 log_err_level_printf(LOG_CRIT, "read(sigpipe) failed:"
673 " %s (%i)\n",
674 strerror(errno), errno);
675 return -1;
676 }
677 if (received_sigquit) {
678 if (kill(childpid, SIGQUIT) == -1) {
679 log_err_level_printf(LOG_CRIT, "kill(%i,SIGQUIT) "
680 "failed: %s (%i)\n",
681 childpid,
682 strerror(errno), errno);
683 }
684 received_sigquit = 0;
685 }
686 if (received_sigterm) {
687 if (kill(childpid, SIGTERM) == -1) {
688 log_err_level_printf(LOG_CRIT, "kill(%i,SIGTERM) "
689 "failed: %s (%i)\n",
690 childpid,
691 strerror(errno), errno);
692 }
693 received_sigterm = 0;
694 }
695 if (received_sighup) {
696 if (kill(childpid, SIGHUP) == -1) {
697 log_err_level_printf(LOG_CRIT, "kill(%i,SIGHUP) "
698 "failed: %s (%i)\n",
699 childpid,
700 strerror(errno), errno);
701 }
702 received_sighup = 0;
703 }
704 if (received_sigusr1) {
705 if (kill(childpid, SIGUSR1) == -1) {
706 log_err_level_printf(LOG_CRIT, "kill(%i,SIGUSR1) "
707 "failed: %s (%i)\n",
708 childpid,
709 strerror(errno), errno);
710 }
711 received_sigusr1 = 0;
712 }
713 if (received_sigint) {
714 /* if we don't detach from the TTY, the
715 * child process receives SIGINT directly */
716 if (global->detach) {
717 if (kill(childpid, SIGINT) == -1) {
718 log_err_level_printf(LOG_CRIT, "kill(%i,SIGINT"
719 ") failed: "
720 "%s (%i)\n",
721 childpid,
722 strerror(errno),
723 errno);
724 }
725 }
726 received_sigint = 0;
727 }
728 if (received_sigchld) {
729 /* break the loop; because we are using
730 * SOCKET_DGRAM we don't get EOF conditions
731 * on the disconnected socket ends here
732 * unless we attempt to write or read, so
733 * we depend on SIGCHLD to notify us of
734 * our child erroring out or crashing */
735 break;
736 }
737 }
738
739 for (i = 0; i < nsrvsock; i++) {
740 if (FD_ISSET(srvsock[i], &readfds)) {
741 int rv = privsep_server_handle_req(global,
742 srvsock[i]);
743 if (rv == -1) {
744 log_err_level_printf(LOG_CRIT, "Failed to handle "
745 "privsep req "
746 "on srvsock %i\n",
747 srvsock[i]);
748 return -1;
749 }
750 if (rv == 1) {
751 #ifdef DEBUG_PRIVSEP_SERVER
752 log_dbg_printf("srveof[%zu]=1\n", i);
753 #endif /* DEBUG_PRIVSEP_SERVER */
754 srveof[i] = 1;
755 }
756 }
757 }
758
759 /*
760 * We cannot exit as long as we need the signal handling,
761 * which is as long as the child process is running.
762 * The only way out of here is receiving SIGCHLD.
763 */
764 }
765
766 return 0;
767 }
768
769 int
privsep_client_openfile(int clisock,const char * fn,int mkpath)770 privsep_client_openfile(int clisock, const char *fn, int mkpath)
771 {
772 char ans[PRIVSEP_MAX_ANS_SIZE];
773 char req[1 + strlen(fn)];
774 int fd = -1;
775 ssize_t n;
776
777 if (privsep_fastpath)
778 return privsep_server_openfile(fn, mkpath);
779
780 req[0] = mkpath ? PRIVSEP_REQ_OPENFILE_P : PRIVSEP_REQ_OPENFILE;
781 memcpy(req + 1, fn, sizeof(req) - 1);
782
783 if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
784 return -1;
785 }
786
787 if ((n = sys_recvmsgfd(clisock, ans, sizeof(ans), &fd)) == -1) {
788 return -1;
789 }
790
791 if (n < 1) {
792 errno = EINVAL;
793 return -1;
794 }
795
796 switch (ans[0]) {
797 case PRIVSEP_ANS_SUCCESS:
798 break;
799 case PRIVSEP_ANS_DENIED:
800 errno = EACCES;
801 return -1;
802 case PRIVSEP_ANS_SYS_ERR:
803 if (n < (ssize_t)(1 + sizeof(int))) {
804 errno = EINVAL;
805 return -1;
806 }
807 errno = *((int*)&ans[1]);
808 return -1;
809 case PRIVSEP_ANS_UNK_CMD:
810 case PRIVSEP_ANS_INVALID:
811 default:
812 errno = EINVAL;
813 return -1;
814 }
815
816 return fd;
817 }
818
819 int
privsep_client_opensock(int clisock,const proxyspec_t * spec)820 privsep_client_opensock(int clisock, const proxyspec_t *spec)
821 {
822 char ans[PRIVSEP_MAX_ANS_SIZE];
823 char req[1 + sizeof(spec)];
824 int fd = -1;
825 ssize_t n;
826
827 if (privsep_fastpath)
828 return privsep_server_opensock(spec);
829
830 req[0] = PRIVSEP_REQ_OPENSOCK;
831 *((const proxyspec_t **)&req[1]) = spec;
832
833 if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
834 return -1;
835 }
836
837 if ((n = sys_recvmsgfd(clisock, ans, sizeof(ans), &fd)) == -1) {
838 return -1;
839 }
840
841 if (n < 1) {
842 errno = EINVAL;
843 return -1;
844 }
845
846 switch (ans[0]) {
847 case PRIVSEP_ANS_SUCCESS:
848 break;
849 case PRIVSEP_ANS_DENIED:
850 errno = EACCES;
851 return -1;
852 case PRIVSEP_ANS_SYS_ERR:
853 if (n < (ssize_t)(1 + sizeof(int))) {
854 errno = EINVAL;
855 return -1;
856 }
857 errno = *((int*)&ans[1]);
858 return -1;
859 case PRIVSEP_ANS_UNK_CMD:
860 case PRIVSEP_ANS_INVALID:
861 default:
862 errno = EINVAL;
863 return -1;
864 }
865
866 return fd;
867 }
868
869 int
privsep_client_certfile(int clisock,const char * fn)870 privsep_client_certfile(int clisock, const char *fn)
871 {
872 char ans[PRIVSEP_MAX_ANS_SIZE];
873 char req[1 + strlen(fn)];
874 int fd = -1;
875 ssize_t n;
876
877 if (privsep_fastpath)
878 return privsep_server_certfile(fn);
879
880 req[0] = PRIVSEP_REQ_CERTFILE;
881 memcpy(req + 1, fn, sizeof(req) - 1);
882
883 if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
884 return -1;
885 }
886
887 if ((n = sys_recvmsgfd(clisock, ans, sizeof(ans), &fd)) == -1) {
888 return -1;
889 }
890
891 if (n < 1) {
892 errno = EINVAL;
893 return -1;
894 }
895
896 switch (ans[0]) {
897 case PRIVSEP_ANS_SUCCESS:
898 break;
899 case PRIVSEP_ANS_DENIED:
900 errno = EACCES;
901 return -1;
902 case PRIVSEP_ANS_SYS_ERR:
903 if (n < (ssize_t)(1 + sizeof(int))) {
904 errno = EINVAL;
905 return -1;
906 }
907 errno = *((int*)&ans[1]);
908 return -1;
909 case PRIVSEP_ANS_UNK_CMD:
910 case PRIVSEP_ANS_INVALID:
911 default:
912 errno = EINVAL;
913 return -1;
914 }
915
916 return fd;
917 }
918
919 int
privsep_client_close(int clisock)920 privsep_client_close(int clisock)
921 {
922 char req[1];
923
924 req[0] = PRIVSEP_REQ_CLOSE;
925
926 if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
927 close(clisock);
928 return -1;
929 }
930
931 close(clisock);
932 return 0;
933 }
934
935 #ifndef WITHOUT_USERAUTH
936 int
privsep_client_update_atime(int clisock,const userdbkeys_t * keys)937 privsep_client_update_atime(int clisock, const userdbkeys_t *keys)
938 {
939 char ans[PRIVSEP_MAX_ANS_SIZE];
940 char req[1 + sizeof(userdbkeys_t)];
941 ssize_t n;
942
943 req[0] = PRIVSEP_REQ_UPDATE_ATIME;
944 // @attention Do not typecast, but memcpy
945 //*((const userdbkeys_t **)&req[1]) = keys;
946 memcpy(req + 1, keys, sizeof(req) - 1);
947
948 if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
949 return -1;
950 }
951
952 // @attention Pass NULL as the 4th param, otherwise other privsep calls cannot get the fds they request
953 if ((n = sys_recvmsgfd(clisock, ans, sizeof(ans), NULL)) == -1) {
954 return -1;
955 }
956
957 if (n < 1) {
958 errno = EINVAL;
959 return -1;
960 }
961
962 switch (ans[0]) {
963 case PRIVSEP_ANS_SUCCESS:
964 break;
965 case PRIVSEP_ANS_DENIED:
966 errno = EACCES;
967 return -1;
968 case PRIVSEP_ANS_SYS_ERR:
969 if (n < (ssize_t)(1 + sizeof(int))) {
970 errno = EINVAL;
971 return -1;
972 }
973 errno = *((int*)&ans[1]);
974 return -1;
975 case PRIVSEP_ANS_UNK_CMD:
976 case PRIVSEP_ANS_INVALID:
977 default:
978 errno = EINVAL;
979 return -1;
980 }
981 // Does not return an fd
982 return 0;
983 }
984 #endif /* !WITHOUT_USERAUTH */
985
986 /*
987 * Fork and set up privilege separated monitor process.
988 * Returns -1 on error before forking, 1 as parent, or 0 as child.
989 * The array of clisock's will get filled with nclisock privsep client
990 * sockets only for the child; on error and in the parent process it
991 * will not be touched.
992 */
993 int
privsep_fork(global_t * global,int clisock[],size_t nclisock,int * parent_rv)994 privsep_fork(global_t *global, int clisock[], size_t nclisock, int *parent_rv)
995 {
996 int selfpipev[2]; /* self-pipe trick: signal handler -> select */
997 int chldpipev[2]; /* el cheapo interprocess sync early after fork */
998 int sockcliv[nclisock][2];
999 pid_t pid;
1000
1001 if (!global->dropuser) {
1002 log_dbg_printf("Privsep fastpath enabled\n");
1003 privsep_fastpath = 1;
1004 } else {
1005 log_dbg_printf("Privsep fastpath disabled\n");
1006 privsep_fastpath = 0;
1007 }
1008
1009 received_sigquit = 0;
1010 received_sighup = 0;
1011 received_sigint = 0;
1012 received_sigchld = 0;
1013 received_sigusr1 = 0;
1014
1015 if (pipe(selfpipev) == -1) {
1016 log_err_level_printf(LOG_CRIT, "Failed to create self-pipe: %s (%i)\n",
1017 strerror(errno), errno);
1018 return -1;
1019 }
1020 log_dbg_printf("Created self-pipe [r=%i,w=%i]\n",
1021 selfpipev[0], selfpipev[1]);
1022
1023 if (pipe(chldpipev) == -1) {
1024 log_err_level_printf(LOG_CRIT, "Failed to create chld-pipe: %s (%i)\n",
1025 strerror(errno), errno);
1026 return -1;
1027 }
1028 log_dbg_printf("Created chld-pipe [r=%i,w=%i]\n",
1029 chldpipev[0], chldpipev[1]);
1030
1031 for (size_t i = 0; i < nclisock; i++) {
1032 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockcliv[i]) == -1) {
1033 log_err_level_printf(LOG_CRIT, "Failed to create socket pair %zu: "
1034 "%s (%i)\n", i, strerror(errno), errno);
1035 return -1;
1036 }
1037 log_dbg_printf("Created socketpair %zu [p=%i,c=%i]\n",
1038 i, sockcliv[i][0], sockcliv[i][1]);
1039 }
1040
1041 log_dbg_printf("Privsep parent pid %i\n", getpid());
1042 pid = fork();
1043 if (pid == -1) {
1044 log_err_level_printf(LOG_CRIT, "Failed to fork: %s (%i)\n",
1045 strerror(errno), errno);
1046 close(selfpipev[0]);
1047 close(selfpipev[1]);
1048 close(chldpipev[0]);
1049 close(chldpipev[1]);
1050 for (size_t i = 0; i < nclisock; i++) {
1051 close(sockcliv[i][0]);
1052 close(sockcliv[i][1]);
1053 }
1054 return -1;
1055 } else if (pid == 0) {
1056 /* child */
1057 close(selfpipev[0]);
1058 close(selfpipev[1]);
1059 for (size_t i = 0; i < nclisock; i++)
1060 close(sockcliv[i][0]);
1061 /* wait until parent has installed signal handlers,
1062 * intentionally ignoring errors */
1063 char buf[1];
1064 ssize_t n;
1065 close(chldpipev[1]);
1066 do {
1067 n = read(chldpipev[0], buf, sizeof(buf));
1068 } while (n == -1 && errno == EINTR);
1069 close(chldpipev[0]);
1070 log_dbg_printf("Privsep child pid %i\n", getpid());
1071 /* return the privsep client sockets */
1072 for (size_t i = 0; i < nclisock; i++)
1073 clisock[i] = sockcliv[i][1];
1074 return 0;
1075 }
1076 /* parent */
1077 for (size_t i = 0; i < nclisock; i++)
1078 close(sockcliv[i][1]);
1079 selfpipe_wrfd = selfpipev[1];
1080
1081 /* close file descriptors opened by preinit's only needed in client;
1082 * we still call the preinit's before forking in order to provide
1083 * better user feedback and less privsep complexity */
1084 nat_preinit_undo();
1085 log_preinit_undo();
1086
1087 /* If the child exits before the parent installs the signal handler
1088 * here, we have a race condition; this is solved by the client
1089 * blocking on the reading end of a pipe (chldpipev[0]). */
1090 if (signal(SIGHUP, privsep_server_signal_handler) == SIG_ERR) {
1091 log_err_level_printf(LOG_CRIT, "Failed to install SIGHUP handler: %s (%i)\n",
1092 strerror(errno), errno);
1093 return -1;
1094 }
1095 if (signal(SIGINT, privsep_server_signal_handler) == SIG_ERR) {
1096 log_err_level_printf(LOG_CRIT, "Failed to install SIGINT handler: %s (%i)\n",
1097 strerror(errno), errno);
1098 return -1;
1099 }
1100 if (signal(SIGTERM, privsep_server_signal_handler) == SIG_ERR) {
1101 log_err_level_printf(LOG_CRIT, "Failed to install SIGTERM handler: %s (%i)\n",
1102 strerror(errno), errno);
1103 return -1;
1104 }
1105 if (signal(SIGQUIT, privsep_server_signal_handler) == SIG_ERR) {
1106 log_err_level_printf(LOG_CRIT, "Failed to install SIGQUIT handler: %s (%i)\n",
1107 strerror(errno), errno);
1108 return -1;
1109 }
1110 if (signal(SIGUSR1, privsep_server_signal_handler) == SIG_ERR) {
1111 log_err_level_printf(LOG_CRIT, "Failed to install SIGUSR1 handler: %s (%i)\n",
1112 strerror(errno), errno);
1113 return -1;
1114 }
1115 if (signal(SIGCHLD, privsep_server_signal_handler) == SIG_ERR) {
1116 log_err_level_printf(LOG_CRIT, "Failed to install SIGCHLD handler: %s (%i)\n",
1117 strerror(errno), errno);
1118 return -1;
1119 }
1120
1121 /* unblock the child */
1122 close(chldpipev[0]);
1123 close(chldpipev[1]);
1124
1125 int socksrv[nclisock];
1126 for (size_t i = 0; i < nclisock; i++)
1127 socksrv[i] = sockcliv[i][0];
1128 if (privsep_server(global, selfpipev[0], socksrv, nclisock, pid) == -1) {
1129 log_err_level_printf(LOG_CRIT, "Privsep server failed: %s (%i)\n",
1130 strerror(errno), errno);
1131 /* fall through */
1132 }
1133 #ifdef DEBUG_PRIVSEP_SERVER
1134 log_dbg_printf("privsep_server exited\n");
1135 #endif /* DEBUG_PRIVSEP_SERVER */
1136
1137 for (size_t i = 0; i < nclisock; i++)
1138 close(sockcliv[i][0]);
1139 selfpipe_wrfd = -1; /* tell signal handler not to write anymore */
1140 close(selfpipev[0]);
1141 close(selfpipev[1]);
1142
1143 int status;
1144 pid_t wpid;
1145 wpid = wait(&status);
1146 if (wpid != pid) {
1147 /* should never happen, warn if it does anyway */
1148 log_err_printf("Child pid %lld != expected %lld from wait(2)\n",
1149 (long long)wpid, (long long)pid);
1150 }
1151 if (WIFEXITED(status)) {
1152 if (WEXITSTATUS(status) != 0) {
1153 log_err_level_printf(LOG_CRIT, "Child pid %lld exited with status %d\n",
1154 (long long)wpid, WEXITSTATUS(status));
1155 } else {
1156 log_dbg_printf("Child pid %lld exited with status %d\n",
1157 (long long)wpid, WEXITSTATUS(status));
1158 }
1159 *parent_rv = WEXITSTATUS(status);
1160 } else if (WIFSIGNALED(status)) {
1161 log_err_level_printf(LOG_CRIT, "Child pid %lld killed by signal %d\n",
1162 (long long)wpid, WTERMSIG(status));
1163 *parent_rv = 128 + WTERMSIG(status);
1164 } else {
1165 /* can only happen with WUNTRACED option or active tracing */
1166 log_err_level_printf(LOG_CRIT, "Child pid %lld neither exited nor killed\n",
1167 (long long)wpid);
1168 }
1169
1170 return 1;
1171 }
1172
1173 /* vim: set noet ft=c: */
1174
1175
1176
1177