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  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  * 1. Redistributions of source code must retain the above copyright notice,
11  *    this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "sys.h"
30 
31 #include "log.h"
32 #include "defaults.h"
33 
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/ioctl.h>
37 #include <sys/uio.h>
38 #include <sys/stat.h>
39 #include <sys/file.h>
40 #include <sys/un.h>
41 #include <sys/time.h>
42 #include <net/if.h>
43 #include <netinet/in.h>
44 #include <netdb.h>
45 #include <fcntl.h>
46 #include <pwd.h>
47 #include <grp.h>
48 #include <fts.h>
49 #include <unistd.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <errno.h>
54 
55 #ifndef _SC_NPROCESSORS_ONLN
56 #include <sys/sysctl.h>
57 #endif /* !_SC_NPROCESSORS_ONLN */
58 
59 #if HAVE_DARWIN_LIBPROC
60 #include <libproc.h>
61 #endif
62 
63 #include <event2/util.h>
64 
65 /*
66  * Permanently drop from root privileges to an unprivileged user account.
67  * Sets the real, effective and stored user and group ID and the list of
68  * ancillary groups.  This is only safe if the effective user ID is 0.
69  * If username is unset and the effective uid != uid, drop privs to uid.
70  * This is to support setuid bit configurations.
71  * If groupname is set, it will be used instead of the user's default primary
72  * group.
73  * If jaildir is set, also chroot to jaildir after reading system files
74  * but before dropping privileges.
75  * Returns 0 on success, -1 on failure.
76  */
77 int
sys_privdrop(const char * username,const char * groupname,const char * jaildir)78 sys_privdrop(const char *username, const char *groupname, const char *jaildir)
79 {
80 	struct passwd *pw = NULL;
81 	struct group *gr = NULL;
82 	int ret = -1;
83 
84 	if (groupname) {
85 		errno = 0;
86 		if (!(gr = getgrnam(groupname))) {
87 			log_err_level_printf(LOG_CRIT, "Failed to getgrnam group '%s': %s\n",
88 			               groupname, strerror(errno));
89 			goto error;
90 		}
91 	}
92 
93 	if (username) {
94 		errno = 0;
95 		if (!(pw = getpwnam(username))) {
96 			log_err_level_printf(LOG_CRIT, "Failed to getpwnam user '%s': %s\n",
97 			               username, strerror(errno));
98 			goto error;
99 		}
100 
101 		if (gr != NULL) {
102 			pw->pw_gid = gr->gr_gid;
103 		}
104 
105 		if (initgroups(username, pw->pw_gid) == -1) {
106 			log_err_level_printf(LOG_CRIT, "Failed to initgroups user '%s': %s\n",
107 			               username, strerror(errno));
108 			goto error;
109 		}
110 	}
111 
112 	if (jaildir) {
113 		if (chroot(jaildir) == -1) {
114 			log_err_level_printf(LOG_CRIT, "Failed to chroot to '%s': %s\n",
115 			               jaildir, strerror(errno));
116 			goto error;
117 		}
118 		if (chdir("/") == -1) {
119 			log_err_level_printf(LOG_CRIT, "Failed to chdir to '/': %s\n",
120 			               strerror(errno));
121 			goto error;
122 		}
123 	}
124 
125 	if (username) {
126 		if (setgid(pw->pw_gid) == -1) {
127 			log_err_level_printf(LOG_CRIT, "Failed to setgid to %i: %s\n",
128 			               pw->pw_gid, strerror(errno));
129 			goto error;
130 		}
131 		if (setuid(pw->pw_uid) == -1) {
132 			log_err_level_printf(LOG_CRIT, "Failed to setuid to %i: %s\n",
133 			               pw->pw_uid, strerror(errno));
134 			goto error;
135 		}
136 	} else if (getuid() != geteuid()) {
137 		if (setuid(getuid()) == -1) {
138 			log_err_level_printf(LOG_CRIT, "Failed to setuid(getuid()): %s\n",
139 			               strerror(errno));
140 			goto error;
141 		}
142 	}
143 
144 	ret = 0;
145 error:
146 	if (pw) {
147 		endpwent();
148 	}
149 	if (gr) {
150 		endgrent();
151 	}
152 	return ret;
153 }
154 
155 /*
156  * If the user exists and on successful lookup, return 0 and if uid != NULL,
157  * write the uid of *username* to the value pointed to by uid.
158  * Return -1 on failure or if the user does not exist.
159  */
160 int
sys_uid(const char * username,uid_t * uid)161 sys_uid(const char *username, uid_t *uid)
162 {
163 	struct passwd *pw;
164 	int rv;
165 
166 	errno = 0;
167 	if (!(pw = getpwnam(username))) {
168 		if (errno != 0 && errno != ENOENT) {
169 			log_err_level_printf(LOG_CRIT, "Failed to load user '%s': %s (%i)\n",
170 			               username, strerror(errno), errno);
171 		}
172 		rv = -1;
173 	} else {
174 		if (uid)
175 			*uid = pw->pw_uid;
176 		rv = 0;
177 	}
178 	endpwent();
179 	return rv;
180 }
181 
182 /*
183  * Returns 1 if username can be loaded from user database, 0 otherwise.
184  */
185 int
sys_isuser(const char * username)186 sys_isuser(const char *username)
187 {
188 	return sys_uid(username, NULL) == 0;
189 }
190 
191 /*
192  * If the group exists and on successful lookup, return 0 and if gid != NULL,
193  * write the gid of *groupname* to the value pointed to by gid.
194  * Return -1 on failure or if the group does not exist.
195  */
196 int
sys_gid(const char * groupname,gid_t * gid)197 sys_gid(const char *groupname, gid_t *gid)
198 {
199 	struct group *gr;
200 	int rv;
201 
202 	errno = 0;
203 	if (!(gr = getgrnam(groupname))) {
204 		if (errno != 0 && errno != ENOENT) {
205 			log_err_level_printf(LOG_CRIT, "Failed to load group '%s': %s (%i)\n",
206 			               groupname, strerror(errno), errno);
207 		}
208 		rv = -1;
209 	} else {
210 		if (gid)
211 			*gid = gr->gr_gid;
212 		rv = 0;
213 	}
214 	endgrent();
215 	return rv;
216 }
217 
218 /*
219  * Returns 1 if groupname can be loaded from group database, 0 otherwise.
220  */
221 int
sys_isgroup(const char * groupname)222 sys_isgroup(const char *groupname)
223 {
224 	return sys_gid(groupname, NULL) == 0;
225 }
226 
227 /*
228  * Returns 1 if username is equivalent to the current effective UID.
229  * Returns 0 otherwise.
230  */
231 int
sys_isgeteuid(const char * username)232 sys_isgeteuid(const char *username)
233 {
234 	uid_t uid;
235 
236 	if (sys_uid(username, &uid) == -1)
237 		return 0;
238 	if (uid == geteuid())
239 		return 1;
240 	return 0;
241 }
242 
243 /*
244  * Open and lock process ID file fn.
245  * Returns open file descriptor on success or -1 on errors.
246  */
247 int
sys_pidf_open(const char * fn)248 sys_pidf_open(const char *fn)
249 {
250 	int fd;
251 
252 	if ((fd = open(fn, O_RDWR|O_CREAT, DFLT_PIDFMODE)) == -1) {
253 		log_err_level_printf(LOG_CRIT, "Failed to open '%s': %s\n", fn,
254 		               strerror(errno));
255 		return -1;
256 	}
257 	if (flock(fd, LOCK_EX|LOCK_NB) == -1) {
258 		log_err_level_printf(LOG_CRIT, "Failed to lock '%s': %s\n", fn,
259 		               strerror(errno));
260 		close(fd);
261 		return -1;
262 	}
263 
264 	return fd;
265 }
266 
267 /*
268  * Write process ID to open process ID file descriptor fd.
269  * Returns 0 on success, -1 on errors.
270  */
271 int
sys_pidf_write(int fd)272 sys_pidf_write(int fd)
273 {
274 	char pidbuf[4*sizeof(pid_t)];
275 	int rv;
276 	ssize_t n;
277 
278 	rv = snprintf(pidbuf, sizeof(pidbuf), "%d\n", getpid());
279 	if (rv == -1 || rv >= (int)sizeof(pidbuf))
280 		return -1;
281 
282 	n = write(fd, pidbuf, strlen(pidbuf));
283 	if (n < (ssize_t)strlen(pidbuf))
284 		return -1;
285 
286 	rv = fsync(fd);
287 	if (rv == -1)
288 		return -1;
289 
290 	rv = fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
291 	if (rv == -1)
292 		return -1;
293 
294 	return 0;
295 }
296 
297 /*
298  * Close and remove open process ID file before quitting.
299  */
300 void
sys_pidf_close(int fd,const char * fn)301 sys_pidf_close(int fd, const char *fn)
302 {
303 	unlink(fn);
304 	close(fd);
305 }
306 
307 /*
308  * Determine address family of addr
309  */
310 int
sys_get_af(const char * addr)311 sys_get_af(const char *addr)
312 {
313 	if (strstr(addr, ":"))
314 		return AF_INET6;
315 	else if (!strpbrk(addr, "abcdefghijklmnopqrstu"
316 							"vwxyzABCDEFGHIJKLMNOP"
317 							"QRSTUVWXYZ-"))
318 		return AF_INET;
319 	else
320 		return AF_UNSPEC;
321 }
322 
323 /*
324  * Parse an ascii host/IP and port tuple into a sockaddr_storage.
325  * On success, returns address family and fills in addr, addrlen.
326  * Returns -1 on error.
327  */
328 int
sys_sockaddr_parse(struct sockaddr_storage * addr,socklen_t * addrlen,char * naddr,char * nport,int af,int flags)329 sys_sockaddr_parse(struct sockaddr_storage *addr, socklen_t *addrlen,
330                    char *naddr, char *nport, int af, int flags)
331 {
332 	struct evutil_addrinfo hints;
333 	struct evutil_addrinfo *ai;
334 	int rv;
335 
336 	memset(&hints, 0, sizeof(hints));
337 	hints.ai_family = af;
338 	hints.ai_socktype = SOCK_STREAM;
339 	hints.ai_protocol = IPPROTO_TCP;
340 	hints.ai_flags = EVUTIL_AI_ADDRCONFIG | flags;
341 	rv = evutil_getaddrinfo(naddr, nport, &hints, &ai);
342 	if (rv != 0) {
343 		log_err_level_printf(LOG_CRIT, "Cannot resolve address '%s' port '%s': %s\n",
344 		               naddr, nport, gai_strerror(rv));
345 		return -1;
346 	}
347 	memcpy(addr, ai->ai_addr, ai->ai_addrlen);
348 	*addrlen = ai->ai_addrlen;
349 	af = ai->ai_family;
350 	freeaddrinfo(ai);
351 	return af;
352 }
353 
354 /*
355  * Converts an IPv4/IPv6 sockaddr into printable string representations of the
356  * host and the service (port) part.  Writes allocated buffers to *host and
357  * *serv which must both be freed by the caller.  Neither *host nor *port are
358  * freed by this function before newly allocating.
359  * Returns 0 on success, -1 otherwise.  When -1 is returned, pointers in *host
360  * and *serv are invalid and must not be used nor freed by the caller.
361  */
362 int
sys_sockaddr_str(struct sockaddr * addr,socklen_t addrlen,char ** host,char ** serv)363 sys_sockaddr_str(struct sockaddr *addr, socklen_t addrlen,
364                  char **host, char **serv)
365 {
366 	char tmphost[INET6_ADDRSTRLEN];
367 	int rv;
368 	size_t hostsz;
369 
370 	*serv = malloc(6); /* max decimal digits of short plus terminator */
371 	if (!*serv) {
372 		log_err_level_printf(LOG_CRIT, "Cannot allocate memory\n");
373 		return -1;
374 	}
375 	rv = getnameinfo(addr, addrlen,
376 	                 tmphost, sizeof(tmphost),
377 	                 *serv, 6,
378 	                 NI_NUMERICHOST | NI_NUMERICSERV);
379 	if (rv != 0) {
380 		log_err_level_printf(LOG_CRIT, "Cannot get nameinfo for socket address: %s\n",
381 		               gai_strerror(rv));
382 		free(*serv);
383 		return -1;
384 	}
385 	hostsz = strlen(tmphost) + 1; /* including terminator */
386 	*host = malloc(hostsz);
387 	if (!*host) {
388 		log_err_level_printf(LOG_CRIT, "Cannot allocate memory\n");
389 		free(*serv);
390 		return -1;
391 	}
392 	memcpy(*host, tmphost, hostsz);
393 	return 0;
394 }
395 
396 /*
397  * Sanitizes a valid IPv4 or IPv6 address for use in a filename, i.e. removes
398  * characters that are invalid on NTFS and replaces them with more innocent
399  * characters.  The function assumes that the input is a valid IPv4 or IPv6
400  * address; it is not a generic filename sanitizer.
401  *
402  * Returns a copy of string s that must be freed by the caller.
403  *
404  * Invalid NTFS characters are < > : " / \ | ? * according to
405  * https://msdn.microsoft.com/en-gb/library/windows/desktop/aa365247.aspx
406  */
407 char *
sys_ip46str_sanitize(const char * s)408 sys_ip46str_sanitize(const char *s)
409 {
410 	char *copy, *p;
411 
412 	copy = strdup(s);
413 	if (!copy)
414 		return NULL;
415 	p = copy;
416 	while (*p) {
417 		switch (*p) {
418 		case ':':
419 		case '%':
420 			*p = '_';
421 			break;
422 		}
423 		p++;
424 	}
425 
426 	return copy;
427 }
428 
429 /*
430  * Returns 1 if path points to an existing directory node in the filesystem.
431  * Returns 0 if path is NULL, does not exist, or points to a file of some kind.
432  */
433 int
sys_isdir(const char * path)434 sys_isdir(const char *path)
435 {
436 	struct stat s;
437 
438 	if (stat(path, &s) == -1) {
439 		if (errno != ENOENT) {
440 			log_err_level_printf(LOG_CRIT, "Error stating file: %s (%i)\n",
441 			               strerror(errno), errno);
442 		}
443 		return 0;
444 	}
445 	if (s.st_mode & S_IFDIR)
446 		return 1;
447 	return 0;
448 }
449 
450 /*
451  * Create directory including parent directories with mode_t.
452  * Mode of existing parent directories is not changed.
453  * Returns 0 on success, -1 and sets errno on error.
454  */
455 int
sys_mkpath(const char * path,mode_t mode)456 sys_mkpath(const char *path, mode_t mode)
457 {
458 	char parent[strlen(path)+1];
459 	char *p;
460 
461 	memcpy(parent, path, sizeof(parent));
462 
463 	p = parent;
464 	do {
465 		/* skip leading '/' characters */
466 		while (*p == '/') p++;
467 		p = strchr(p, '/');
468 		if (p) {
469 			/* overwrite '/' to terminate the string at the next
470 			 * parent directory */
471 			*p = '\0';
472 		}
473 
474 		struct stat sbuf;
475 		if (stat(parent, &sbuf) == -1) {
476 			if (errno == ENOENT) {
477 				if (mkdir(parent, mode) != 0)
478 					return -1;
479 			} else {
480 				return -1;
481 			}
482 		} else if (!S_ISDIR(sbuf.st_mode)) {
483 			errno = ENOTDIR;
484 			return -1;
485 		}
486 
487 		if (p) {
488 			/* replace the overwritten slash */
489 			*p = '/';
490 			p++;
491 		}
492 	} while (p);
493 
494 	return 0;
495 }
496 
497 /*
498  * Return realpath(dirname(path)) + / + basename(path) in a newly allocated
499  * string.  Returns NULL on failure and sets errno to ENOENT if the directory
500  * part does not exist.
501  */
502 char *
sys_realdir(const char * path)503 sys_realdir(const char *path)
504 {
505 	char *sep, *udir, *rdir, *p;
506 	int rerrno, rv;
507 
508 	if (path[0] == '\0') {
509 		errno = EINVAL;
510 		return NULL;
511 	}
512 
513 	udir = strdup(path);
514 	if (!udir)
515 		return NULL;
516 
517 	sep = strrchr(udir, '/');
518 	if (!sep) {
519 		free(udir);
520 		rv = asprintf(&udir, "./%s", path);
521 		if (rv == -1)
522 			return NULL;
523 		sep = udir + 1;
524 	} else if (sep == udir) {
525 		return udir;
526 	}
527 	*sep = '\0';
528 	rdir = realpath(udir, NULL);
529 	if (!rdir) {
530 		rerrno = errno;
531 		free(udir);
532 		errno = rerrno;
533 		return NULL;
534 	}
535 	rv = asprintf(&p, "%s/%s", rdir, sep + 1);
536 	rerrno = errno;
537 	free(rdir);
538 	free(udir);
539 	errno = rerrno;
540 	if (rv == -1)
541 		return NULL;
542 	return p;
543 }
544 
545 /*
546  * Portably get the number of CPU cores online in the system.
547  */
548 uint32_t
sys_get_cpu_cores(void)549 sys_get_cpu_cores(void)
550 {
551 #ifdef _SC_NPROCESSORS_ONLN
552 	return sysconf(_SC_NPROCESSORS_ONLN);
553 #else /* !_SC_NPROCESSORS_ONLN */
554 	int mib[2];
555 	uint32_t n;
556 	size_t len = sizeof(n);
557 
558 	mib[0] = CTL_HW;
559 	mib[1] = HW_AVAILCPU;
560 	sysctl(mib, sizeof(mib)/sizeof(int), &n, &len, NULL, 0);
561 
562 	if (n < 1) {
563 		mib[1] = HW_NCPU;
564 		sysctl(mib, sizeof(mib)/sizeof(int), &n, &len, NULL, 0);
565 		if (n < 1) {
566 			n = 1;
567 		}
568 	}
569 	return n;
570 #endif /* !_SC_NPROCESSORS_ONLN */
571 }
572 
573 /*
574  * Send a message and optional file descriptor on a connected AF_UNIX
575  * SOCKET_DGRAM socket s.  Returns the return value of sendmsg().
576  * If fd is -1, no file descriptor is passed.
577  */
578 ssize_t
sys_sendmsgfd(int sock,void * buf,size_t bufsz,int fd)579 sys_sendmsgfd(int sock, void *buf, size_t bufsz, int fd)
580 {
581 	struct iovec iov;
582 	struct msghdr msg;
583 	struct cmsghdr *cmsg;
584 	char cmsgbuf[CMSG_SPACE(sizeof(int))];
585 	ssize_t n;
586 
587 	iov.iov_base = buf;
588 	iov.iov_len = bufsz;
589 
590 	msg.msg_name = NULL;
591 	msg.msg_namelen = 0;
592 	msg.msg_iov = &iov;
593 	msg.msg_iovlen = 1;
594 	msg.msg_flags = 0;
595 
596 	if (fd != -1) {
597 		msg.msg_control = cmsgbuf;
598 		msg.msg_controllen = sizeof(cmsgbuf);
599 		memset(cmsgbuf, 0, sizeof(cmsgbuf));
600 
601 		cmsg = CMSG_FIRSTHDR(&msg);
602 		if (!cmsg)
603 			return -1;
604 		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
605 		cmsg->cmsg_level = SOL_SOCKET;
606 		cmsg->cmsg_type = SCM_RIGHTS;
607 
608 		*((int *) CMSG_DATA(cmsg)) = fd;
609 	} else {
610 		msg.msg_control = NULL;
611 		msg.msg_controllen = 0;
612 	}
613 	do {
614 #ifdef MSG_NOSIGNAL
615 		n = sendmsg(sock, &msg, MSG_NOSIGNAL);
616 #else /* !MSG_NOSIGNAL */
617 		n = sendmsg(sock, &msg, 0);
618 #endif /* !MSG_NOSIGNAL */
619 	} while (n == -1 && errno == EINTR);
620 	return n;
621 }
622 
623 /*
624  * Receive a message and optional file descriptor on a connected AF_UNIX
625  * SOCKET_DGRAM socket s.  Returns the return value of recvmsg()/recv()
626  * and sets errno to EINVAL if the received message is malformed.
627  * If pfd is NULL, no file descriptor is received; if a file descriptor was
628  * part of the received message and pfd is NULL, then the kernel will close it.
629  */
630 ssize_t
sys_recvmsgfd(int sock,void * buf,size_t bufsz,int * pfd)631 sys_recvmsgfd(int sock, void *buf, size_t bufsz, int *pfd)
632 {
633 	ssize_t n;
634 
635 	if (pfd) {
636 		struct iovec iov;
637 		struct msghdr msg;
638 		struct cmsghdr *cmsg;
639 		unsigned char cmsgbuf[CMSG_SPACE(sizeof(int))];
640 
641 		iov.iov_base = buf;
642 		iov.iov_len = bufsz;
643 
644 		msg.msg_name = NULL;
645 		msg.msg_namelen = 0;
646 		msg.msg_iov = &iov;
647 		msg.msg_iovlen = 1;
648 		msg.msg_control = cmsgbuf;
649 		msg.msg_controllen = sizeof(cmsgbuf);
650 		do {
651 			n = recvmsg(sock, &msg, 0);
652 		} while (n == -1 && errno == EINTR);
653 		if (n <= 0)
654 			return n;
655 		cmsg = CMSG_FIRSTHDR(&msg);
656 		if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
657 			if (cmsg->cmsg_level != SOL_SOCKET) {
658 				errno = EINVAL;
659 				return -1;
660 			}
661 			if (cmsg->cmsg_type != SCM_RIGHTS) {
662 				errno = EINVAL;
663 				return -1;
664 			}
665 			*pfd = *((int *) CMSG_DATA(cmsg));
666 		} else {
667 			*pfd = -1;
668 		}
669 	} else {
670 		do {
671 			n = recv(sock, buf, bufsz, 0);
672 		} while (n == -1 && errno == EINTR);
673 	}
674 	return n;
675 }
676 
677 /* vim: set noet ft=c: */
678