1 /*
2  *
3  *   Authors:
4  *    Pedro Roque		<roque@di.fc.ul.pt>
5  *    Lars Fenneberg		<lf@elemental.net>
6  *
7  *   This software is Copyright 1996-2000 by the above mentioned author(s),
8  *   All Rights Reserved.
9  *
10  *   The license which is distributed with this software in the file COPYRIGHT
11  *   applies to this software. If your distribution is missing this file, you
12  *   may request it from <reubenhwk@gmail.com>.
13  *
14  */
15 
16 #include "radvd.h"
17 #include "config.h"
18 #include "includes.h"
19 #include "pathnames.h"
20 
21 #ifdef HAVE_NETLINK
22 #include "netlink.h"
23 #endif
24 
25 #include <libgen.h>
26 #include <poll.h>
27 #include <sys/file.h>
28 
29 #ifdef HAVE_GETOPT_LONG
30 
31 /* clang-format off */
32 static char usage_str[] = {
33 "\n"
34 "  -C, --config=PATH       Set the config file.  Default is /etc/radvd.d.\n"
35 "  -c, --configtest        Parse the config file and exit.\n"
36 "  -d, --debug=NUM         Set the debug level.  Values can be 1, 2, 3, 4 or 5.\n"
37 "  -f, --facility=NUM      Set the logging facility.\n"
38 "  -h, --help              Show this help screen.\n"
39 "  -l, --logfile=PATH      Set the log file.\n"
40 "  -m, --logmethod=X       Set method to: syslog, stderr, stderr_syslog, logfile,\n"
41 "                          stderr_clean, or none.\n"
42 "  -n, --nodaemon          Prevent the daemonizing.\n"
43 "  -p, --pidfile=PATH      Set the pid file.\n"
44 "  -t, --chrootdir=PATH    Chroot to the specified path.\n"
45 "  -u, --username=USER     Switch to the specified user.\n"
46 "  -v, --version           Print the version and quit.\n"
47 };
48 
49 static struct option prog_opt[] = {
50 	{"chrootdir", 1, 0, 't'},
51 	{"config", 1, 0, 'C'},
52 	{"configtest", 0, 0, 'c'},
53 	{"debug", 1, 0, 'd'},
54 	{"facility", 1, 0, 'f'},
55 	{"help", 0, 0, 'h'},
56 	{"logfile", 1, 0, 'l'},
57 	{"logmethod", 1, 0, 'm'},
58 	{"nodaemon", 0, 0, 'n'},
59 	{"pidfile", 1, 0, 'p'},
60 	{"username", 1, 0, 'u'},
61 	{"version", 0, 0, 'v'},
62 	{NULL, 0, 0, 0}
63 };
64 
65 #else
66 
67 static char usage_str[] = {
68 "[-hvcn] [-d level] [-C config_path] [-m log_method] [-l log_file]\n"
69 "\t[-f facility] [-p pid_file] [-u username] [-t chrootdir]"
70 
71 };
72 /* clang-format on */
73 
74 #endif
75 
76 static volatile int sighup_received = 0;
77 static volatile int sigint_received = 0;
78 static volatile int sigterm_received = 0;
79 static volatile int sigusr1_received = 0;
80 
81 static int check_conffile_perm(const char *, const char *);
82 static int drop_root_privileges(const char *);
83 static int open_and_lock_pid_file(char const *daemon_pid_file_ident);
84 static int write_pid_file(char const *daemon_pid_file_ident, pid_t pid);
85 static pid_t daemonp(char const *daemon_pid_file_ident);
86 static pid_t do_daemonize(int log_method, char const *daemon_pid_file_ident);
87 static struct Interface *main_loop(int sock, struct Interface *ifaces, char const *conf_path);
88 static struct Interface *reload_config(int sock, struct Interface *ifaces, char const *conf_path);
89 static void check_pid_file(char const *daemon_pid_file_ident);
90 static void config_interface(struct Interface *iface);
91 static void kickoff_adverts(int sock, struct Interface *iface);
92 static void reset_prefix_lifetimes(struct Interface *ifaces);
93 static void reset_prefix_lifetimes_foo(struct Interface *iface, void *data);
94 static void setup_iface_foo(struct Interface *iface, void *data);
95 static void setup_ifaces(int sock, struct Interface *ifaces);
96 static void sighup_handler(int sig);
97 static void sigint_handler(int sig);
98 static void sigterm_handler(int sig);
99 static void sigusr1_handler(int sig);
100 static void stop_advert_foo(struct Interface *iface, void *data);
101 static void stop_adverts(int sock, struct Interface *ifaces);
102 static void timer_handler(int sock, struct Interface *iface);
103 static void usage(char const *pname);
104 static void version(void);
105 
106 /* daemonize and write pid file.  The pid of the daemon child process
107  * will be written to the pid file from the *parent* process.  This
108  * insures there is no race condition as described in redhat bug 664783. */
daemonp(char const * daemon_pid_file_ident)109 static pid_t daemonp(char const *daemon_pid_file_ident)
110 {
111 	int pipe_ends[2];
112 
113 	if (0 != pipe(pipe_ends)) {
114 		flog(LOG_ERR, "unable to create pipe: %s", strerror(errno));
115 		exit(-1);
116 	}
117 
118 	pid_t pid = fork();
119 
120 	if (-1 == pid) {
121 		flog(LOG_ERR, "unable to fork in daemonp");
122 		exit(-1);
123 	} else if (0 == pid) {
124 		/* Child process, detached.. */
125 		pid = getpid();
126 		close(pipe_ends[0]);
127 		if (0 != write_pid_file(daemon_pid_file_ident, pid)) {
128 			flog(LOG_ERR, "failure writing pid file");
129 			exit(-1);
130 		}
131 		if (sizeof(pid) != write(pipe_ends[1], &pid, sizeof(pid))) {
132 			flog(LOG_ERR, "failure piping pid to parent process");
133 		}
134 
135 		umask(0);
136 		if (-1 == setsid()) {
137 			flog(LOG_ERR, "unable to become a session leader: %s", strerror(errno));
138 			exit(-1);
139 		}
140 
141 		if (chdir("/") == -1) {
142 			perror("chdir");
143 			exit(1);
144 		}
145 		close(STDIN_FILENO);
146 		close(STDOUT_FILENO);
147 		close(STDERR_FILENO);
148 		if (open("/dev/null", O_RDONLY) == -1) {
149 			flog(LOG_ERR, "unable to redirect stdin to /dev/null");
150 			exit(-1);
151 		}
152 		if (open("/dev/null", O_WRONLY) == -1) {
153 			flog(LOG_ERR, "unable to redirect stdout to /dev/null");
154 			exit(-1);
155 		}
156 		if (open("/dev/null", O_RDWR) == -1) {
157 			flog(LOG_ERR, "unable to redirect stderr to /dev/null");
158 			exit(-1);
159 		}
160 	} else {
161 		/* Parent.  Make sure the pid file is written before exiting. */
162 		close(pipe_ends[1]);
163 		pid_t msg = -1;
164 		ssize_t rc = read(pipe_ends[0], &msg, sizeof(msg));
165 		if (rc != sizeof(msg)) {
166 			flog(LOG_ERR, "child failed to signal pid file written: %s", strerror(errno));
167 			exit(-1);
168 		} else if (msg != pid) {
169 			flog(LOG_ERR, "child wrote wrong pid to pid file: %d", msg);
170 			exit(-1);
171 		} else {
172 			dlog(LOG_DEBUG, 5, "child signaled pid file written: %d", msg);
173 		}
174 		close(pipe_ends[0]);
175 
176 		return pid;
177 	}
178 	return 0;
179 }
180 
main(int argc,char * argv[])181 int main(int argc, char *argv[])
182 {
183 	int c;
184 	int log_method = L_UNSPEC;
185 	char *logfile = PATH_RADVD_LOG;
186 	int facility = LOG_FACILITY;
187 	char *username = NULL;
188 	char *chrootdir = NULL;
189 	int configtest = 0;
190 	int daemonize = 1;
191 
192 	char const *pname = ((pname = strrchr(argv[0], '/')) != NULL) ? pname + 1 : argv[0];
193 
194 	srand((unsigned int)time(NULL));
195 
196 	char const *conf_path = PATH_RADVD_CONF;
197 	char const *daemon_pid_file_ident = PATH_RADVD_PID;
198 
199 /* parse args */
200 #define OPTIONS_STR "d:C:l:m:p:t:u:vhcn"
201 #ifdef HAVE_GETOPT_LONG
202 	int opt_idx;
203 	while ((c = getopt_long(argc, argv, OPTIONS_STR, prog_opt, &opt_idx)) > 0)
204 #else
205 	while ((c = getopt(argc, argv, OPTIONS_STR)) > 0)
206 #endif
207 	{
208 		switch (c) {
209 		case 'C':
210 			conf_path = optarg;
211 			break;
212 		case 'd':
213 			set_debuglevel(atoi(optarg));
214 			break;
215 		case 'f':
216 			facility = atoi(optarg);
217 			break;
218 		case 'l':
219 			logfile = optarg;
220 			break;
221 		case 'p':
222 			daemon_pid_file_ident = optarg;
223 			break;
224 		case 'm':
225 			if (!strcmp(optarg, "syslog")) {
226 				log_method = L_SYSLOG;
227 			} else if (!strcmp(optarg, "stderr_syslog")) {
228 				log_method = L_STDERR_SYSLOG;
229 			} else if (!strcmp(optarg, "stderr")) {
230 				log_method = L_STDERR;
231 			} else if (!strcmp(optarg, "stderr_clean")) {
232 				log_method = L_STDERR_CLEAN;
233 			} else if (!strcmp(optarg, "logfile")) {
234 				log_method = L_LOGFILE;
235 			} else if (!strcmp(optarg, "none")) {
236 				log_method = L_NONE;
237 			} else {
238 				fprintf(stderr, "%s: unknown log method: %s\n", pname, optarg);
239 				exit(1);
240 			}
241 			break;
242 		case 't':
243 			chrootdir = strdup(optarg);
244 			break;
245 		case 'u':
246 			username = strdup(optarg);
247 			break;
248 		case 'v':
249 			version();
250 			break;
251 		case 'c':
252 			configtest = 1;
253 			break;
254 		case 'n':
255 			daemonize = 0;
256 			break;
257 		case 'h':
258 			usage(pname);
259 #ifdef HAVE_GETOPT_LONG
260 		case ':':
261 			fprintf(stderr, "%s: option %s: parameter expected\n", pname, prog_opt[opt_idx].name);
262 			exit(1);
263 #endif
264 		case '?':
265 			exit(1);
266 		}
267 	}
268 
269 	/* TODO: Seems like this chroot'ing should happen *after* daemonizing for
270 	 * the sake of the PID file. */
271 	if (chrootdir) {
272 		if (!username) {
273 			fprintf(stderr, "Chroot as root is not safe, exiting\n");
274 			exit(1);
275 		}
276 
277 		if (chroot(chrootdir) == -1) {
278 			perror("chroot");
279 			exit(1);
280 		}
281 
282 		if (chdir("/") == -1) {
283 			perror("chdir");
284 			exit(1);
285 		}
286 		/* username will be switched later */
287 	}
288 
289 	if (configtest) {
290 		set_debuglevel(1);
291 		switch (log_method) {
292 		case L_STDERR:
293 		case L_STDERR_CLEAN:
294 			break;
295 		case L_STDERR_SYSLOG:
296 		case L_NONE:
297 		case L_UNSPEC:
298 		case L_SYSLOG:
299 		case L_LOGFILE:
300 		default:
301 			log_method = L_STDERR;
302 			break;
303 		}
304 	}
305 	if (log_method == L_UNSPEC)
306 		log_method = daemonize ? L_STDERR_SYSLOG : L_STDERR;
307 	if (log_open(log_method, pname, logfile, facility) < 0) {
308 		perror("log_open");
309 		exit(1);
310 	}
311 
312 	if (!configtest) {
313 		flog(LOG_INFO, "version %s started", VERSION);
314 	}
315 
316 	/* check that 'other' cannot write the file
317 	 * for non-root, also that self/own group can't either
318 	 */
319 	if (check_conffile_perm(username, conf_path) != 0) {
320 		if (get_debuglevel() == 0) {
321 			flog(LOG_ERR, "exiting, permissions on conf_file invalid");
322 			exit(1);
323 		} else
324 			flog(LOG_WARNING, "Insecure file permissions, but continuing anyway");
325 	}
326 
327 	/* parse config file */
328 	struct Interface *ifaces = NULL;
329 	if ((ifaces = readin_config(conf_path)) == 0) {
330 		flog(LOG_ERR, "exiting, failed to read config file");
331 		exit(1);
332 	}
333 
334 	if (configtest) {
335 		free_ifaces(ifaces);
336 		exit(0);
337 	}
338 
339 	/* get a raw socket for sending and receiving ICMPv6 messages */
340 	int sock = open_icmpv6_socket();
341 	if (sock < 0) {
342 		perror("open_icmpv6_socket");
343 		exit(1);
344 	}
345 
346 	/* if we know how to do it, check whether forwarding is enabled */
347 	if (check_ip6_forwarding()) {
348 		flog(LOG_WARNING, "IPv6 forwarding seems to be disabled, but continuing anyway");
349 	}
350 
351 	int const pidfd = open_and_lock_pid_file(daemon_pid_file_ident);
352 
353 	/*
354 	 * okay, config file is read in, socket and stuff is setup, so
355 	 * lets fork now...
356 	 */
357 	if (daemonize) {
358 		pid_t pid = do_daemonize(log_method, daemon_pid_file_ident);
359 		if (pid != 0 && pid != -1) {
360 			/* We want to see clean output from valgrind, so free username, chrootdir,
361 			 * and ifaces in the child process. */
362 			if (ifaces)
363 				free_ifaces(ifaces);
364 
365 			if (username)
366 				free(username);
367 
368 			if (chrootdir)
369 				free(chrootdir);
370 
371 			exit(0);
372 		}
373 	} else {
374 		if (0 != write_pid_file(daemon_pid_file_ident, getpid())) {
375 			flog(LOG_ERR, "failure writing pid file detected");
376 			exit(-1);
377 		}
378 	}
379 
380 	check_pid_file(daemon_pid_file_ident);
381 
382 #ifdef __linux__
383 	/* for privsep */ {
384 		dlog(LOG_DEBUG, 3, "initializing privsep");
385 
386 		int pipefds[2];
387 
388 		if (pipe(pipefds) != 0) {
389 			flog(LOG_ERR, "Couldn't create privsep pipe.");
390 			return -1;
391 		}
392 
393 		pid_t pid = fork();
394 
395 		if (pid == -1) {
396 			flog(LOG_ERR, "Couldn't fork for privsep.");
397 			return -1;
398 		}
399 
400 		if (pid == 0) {
401 			/* We want to see clean output from valgrind, so free username, chrootdir,
402 			 * and ifaces in the child process. */
403 			if (ifaces)
404 				free_ifaces(ifaces);
405 
406 			if (username)
407 				free(username);
408 
409 			if (chrootdir)
410 				free(chrootdir);
411 
412 			close(pipefds[1]);
413 
414 			privsep_init(pipefds[0]);
415 			_exit(0);
416 		}
417 
418 		dlog(LOG_DEBUG, 3, "radvd privsep PID is %d", pid);
419 
420 		/* Continue execution (will drop privileges soon) */
421 		close(pipefds[0]);
422 		privsep_set_write_fd(pipefds[1]);
423 	}
424 #endif
425 
426 	if (username) {
427 		if (drop_root_privileges(username) < 0) {
428 			perror("drop_root_privileges");
429 			flog(LOG_ERR, "unable to drop root privileges");
430 			exit(1);
431 		}
432 		dlog(LOG_DEBUG, 3, "running as user: %s", username);
433 	}
434 
435 	setup_ifaces(sock, ifaces);
436 	ifaces = main_loop(sock, ifaces, conf_path);
437 	stop_adverts(sock, ifaces);
438 
439 	flog(LOG_INFO, "removing %s", daemon_pid_file_ident);
440 	unlink(daemon_pid_file_ident);
441 	close(pidfd);
442 
443 	if (ifaces)
444 		free_ifaces(ifaces);
445 
446 	if (chrootdir)
447 		free(chrootdir);
448 
449 	if (username)
450 		free(username);
451 
452 	flog(LOG_INFO, "returning from radvd main");
453 	log_close();
454 
455 	return 0;
456 }
457 
main_loop(int sock,struct Interface * ifaces,char const * conf_path)458 static struct Interface *main_loop(int sock, struct Interface *ifaces, char const *conf_path)
459 {
460 	struct pollfd fds[2];
461 	sigset_t sigmask;
462 	sigset_t sigempty;
463 	struct sigaction sa;
464 
465 	sigemptyset(&sigempty);
466 
467 	sigemptyset(&sigmask);
468 	sigaddset(&sigmask, SIGHUP);
469 	sigaddset(&sigmask, SIGTERM);
470 	sigaddset(&sigmask, SIGINT);
471 	sigaddset(&sigmask, SIGUSR1);
472 	sigprocmask(SIG_BLOCK, &sigmask, NULL);
473 
474 	sa.sa_handler = sighup_handler;
475 	sigemptyset(&sa.sa_mask);
476 	sa.sa_flags = 0;
477 	sigaction(SIGHUP, &sa, 0);
478 
479 	sa.sa_handler = sigterm_handler;
480 	sigemptyset(&sa.sa_mask);
481 	sa.sa_flags = 0;
482 	sigaction(SIGTERM, &sa, 0);
483 
484 	sa.sa_handler = sigint_handler;
485 	sigemptyset(&sa.sa_mask);
486 	sa.sa_flags = 0;
487 	sigaction(SIGINT, &sa, 0);
488 
489 	sa.sa_handler = sigusr1_handler;
490 	sigemptyset(&sa.sa_mask);
491 	sa.sa_flags = 0;
492 	sigaction(SIGUSR1, &sa, 0);
493 
494 	memset(fds, 0, sizeof(fds));
495 
496 	fds[0].fd = sock;
497 	fds[0].events = POLLIN;
498 
499 #if HAVE_NETLINK
500 	fds[1].fd = netlink_socket();
501 	fds[1].events = POLLIN;
502 #else
503 	fds[1].fd = -1;
504 #endif
505 
506 	for (;;) {
507 		struct timespec *tsp = 0;
508 
509 		struct Interface *next_iface_to_expire = find_iface_by_time(ifaces);
510 		if (next_iface_to_expire) {
511 			static struct timespec ts;
512 			int timeout = next_time_msec(next_iface_to_expire);
513 			ts.tv_sec = timeout / 1000;
514 			ts.tv_nsec = (timeout - 1000 * ts.tv_sec) * 1000000;
515 			tsp = &ts;
516 			dlog(LOG_DEBUG, 1, "polling for %g second(s), next iface is %s", timeout / 1000.0,
517 			     next_iface_to_expire->props.name);
518 		} else {
519 			dlog(LOG_DEBUG, 1, "no iface is next. Polling indefinitely");
520 		}
521 #ifdef HAVE_PPOLL
522 		int rc = ppoll(fds, sizeof(fds) / sizeof(fds[0]), tsp, &sigempty);
523 #else
524 		int rc = poll(fds, sizeof(fds) / sizeof(fds[0]), 1000 * tsp->tv_sec);
525 #endif
526 
527 		if (rc > 0) {
528 #ifdef HAVE_NETLINK
529 			if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) {
530 				flog(LOG_WARNING, "socket error on fds[1].fd");
531 			} else if (fds[1].revents & POLLIN) {
532 				process_netlink_msg(fds[1].fd, ifaces);
533 			}
534 #endif
535 
536 			if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
537 				flog(LOG_WARNING, "socket error on fds[0].fd");
538 			} else if (fds[0].revents & POLLIN) {
539 				int len, hoplimit;
540 				struct sockaddr_in6 rcv_addr;
541 				struct in6_pktinfo *pkt_info = NULL;
542 				unsigned char msg[MSG_SIZE_RECV];
543 				unsigned char chdr[CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))];
544 
545 				len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit, chdr);
546 				if (len > 0 && pkt_info) {
547 					process(sock, ifaces, msg, len, &rcv_addr, pkt_info, hoplimit);
548 				} else if (!pkt_info) {
549 					dlog(LOG_INFO, 4, "recv_rs_ra returned null pkt_info");
550 				} else if (len <= 0) {
551 					dlog(LOG_INFO, 4, "recv_rs_ra returned len <= 0: %d", len);
552 				}
553 			}
554 		} else if (rc == 0) {
555 			if (next_iface_to_expire)
556 				timer_handler(sock, next_iface_to_expire);
557 		} else if (rc == -1) {
558 			dlog(LOG_INFO, 3, "poll returned early: %s", strerror(errno));
559 		}
560 
561 		if (sigint_received) {
562 			flog(LOG_WARNING, "exiting, %d sigint(s) received", sigint_received);
563 			break;
564 		}
565 
566 		if (sigterm_received) {
567 			flog(LOG_WARNING, "exiting, %d sigterm(s) received", sigterm_received);
568 			break;
569 		}
570 
571 		if (sighup_received) {
572 			dlog(LOG_INFO, 3, "sig hup received");
573 			ifaces = reload_config(sock, ifaces, conf_path);
574 			sighup_received = 0;
575 		}
576 
577 		if (sigusr1_received) {
578 			dlog(LOG_INFO, 3, "sig usr1 received");
579 			reset_prefix_lifetimes(ifaces);
580 			sigusr1_received = 0;
581 		}
582 	}
583 
584 	return ifaces;
585 }
586 
do_daemonize(int log_method,char const * daemon_pid_file_ident)587 static pid_t do_daemonize(int log_method, char const *daemon_pid_file_ident)
588 {
589 	pid_t pid = -1;
590 
591 	pid = daemonp(daemon_pid_file_ident);
592 
593 	if (-1 == pid) {
594 		flog(LOG_ERR, "unable to daemonize: %s", strerror(errno));
595 		exit(-1);
596 	}
597 	return pid;
598 }
599 
open_pid_file(char const * daemon_pid_file_ident)600 static int open_pid_file(char const *daemon_pid_file_ident)
601 {
602 	int pidfd = open(daemon_pid_file_ident, O_SYNC | O_CREAT | O_RDWR, 0644);
603 	if (-1 == pidfd) {
604 		flog(LOG_ERR, "unable to open pid file, %s: %s", daemon_pid_file_ident, strerror(errno));
605 		exit(-1);
606 	} else {
607 		dlog(LOG_DEBUG, 5, "opened pid file %s", daemon_pid_file_ident);
608 	}
609 	return pidfd;
610 }
611 
open_and_lock_pid_file(char const * daemon_pid_file_ident)612 static int open_and_lock_pid_file(char const *daemon_pid_file_ident)
613 {
614 	dlog(LOG_DEBUG, 3, "radvd startup PID is %d", getpid());
615 
616 	int pidfd = open_pid_file(daemon_pid_file_ident);
617 
618 	int lock = flock(pidfd, LOCK_EX | LOCK_NB);
619 	if (0 != lock) {
620 		flog(LOG_ERR, "unable to lock pid file, %s: %s", daemon_pid_file_ident, strerror(errno));
621 		exit(-1);
622 	} else {
623 		dlog(LOG_DEBUG, 4, "locked pid file %s", daemon_pid_file_ident);
624 	}
625 
626 	return pidfd;
627 }
628 
write_pid_file(char const * daemon_pid_file_ident,pid_t pid)629 static int write_pid_file(char const *daemon_pid_file_ident, pid_t pid)
630 {
631 	int pidfd = open_pid_file(daemon_pid_file_ident);
632 	char pid_str[20] = {""};
633 	sprintf(pid_str, "%d", pid);
634 	dlog(LOG_DEBUG, 3, "radvd PID is %s", pid_str);
635 	size_t len = strlen(pid_str);
636 	int rc = write(pidfd, pid_str, len);
637 	if (rc != (int)len) {
638 		return -1;
639 	}
640 	char newline[] = {"\n"};
641 	len = strlen(newline);
642 	rc = write(pidfd, newline, len);
643 	if (rc != (int)len) {
644 		return -1;
645 	}
646 	rc = fsync(pidfd);
647 	if (rc != 0) {
648 		dlog(LOG_DEBUG, 4, "failed to fsync pid file: %s", daemon_pid_file_ident);
649 	}
650 	rc = close(pidfd);
651 	if (rc != 0) {
652 		dlog(LOG_DEBUG, 4, "failed to close pid file: %s", daemon_pid_file_ident);
653 	}
654 	char *dirstrcopy = strdup(daemon_pid_file_ident);
655 	char *dirstr = dirname(dirstrcopy);
656 	int dirfd = open(dirstr, O_RDONLY);
657 	rc = fsync(dirfd);
658 	if (rc != 0) {
659 		dlog(LOG_DEBUG, 4, "failed to fsync pid dir: %s", dirstr);
660 	}
661 	rc = close(dirfd);
662 	if (rc != 0) {
663 		dlog(LOG_DEBUG, 4, "failed to close pid dir: %s", dirstr);
664 	}
665 	free(dirstrcopy);
666 	dlog(LOG_DEBUG, 4, "wrote pid %d to pid file: %s", pid, daemon_pid_file_ident);
667 	return rc;
668 }
669 
check_pid_file(char const * daemon_pid_file_ident)670 static void check_pid_file(char const *daemon_pid_file_ident)
671 {
672 	FILE *pidfile = fopen(daemon_pid_file_ident, "r");
673 
674 	if (!pidfile) {
675 		flog(LOG_ERR, "unable to open pid file, %s: %s", daemon_pid_file_ident, strerror(errno));
676 		exit(-1);
677 	}
678 
679 	pid_t pid = -1;
680 
681 	int rc = fscanf(pidfile, "%d", &pid);
682 	fclose(pidfile);
683 
684 	if (rc != 1) {
685 		flog(LOG_ERR, "unable to read pid from pid file: %s", daemon_pid_file_ident);
686 		exit(-1);
687 	}
688 
689 	if (pid != getpid()) {
690 		flog(LOG_ERR, "pid in file, %s, doesn't match getpid(): %d != %d", daemon_pid_file_ident, pid, getpid());
691 		exit(-1);
692 	}
693 	dlog(LOG_DEBUG, 4, "validated pid file, %s: %d", daemon_pid_file_ident, pid);
694 }
695 
timer_handler(int sock,struct Interface * iface)696 static void timer_handler(int sock, struct Interface *iface)
697 {
698 	dlog(LOG_DEBUG, 1, "timer_handler called for %s", iface->props.name);
699 
700 	if (send_ra_forall(sock, iface, NULL) != 0) {
701 		dlog(LOG_DEBUG, 4, "send_ra_forall failed on interface %s", iface->props.name);
702 	}
703 
704 	double next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval);
705 
706 	reschedule_iface(iface, next);
707 }
708 
config_interface(struct Interface * iface)709 static void config_interface(struct Interface *iface)
710 {
711 	if (iface->AdvLinkMTU)
712 		set_interface_linkmtu(iface->props.name, iface->AdvLinkMTU);
713 	if (iface->ra_header_info.AdvCurHopLimit)
714 		set_interface_curhlim(iface->props.name, iface->ra_header_info.AdvCurHopLimit);
715 	if (iface->ra_header_info.AdvReachableTime)
716 		set_interface_reachtime(iface->props.name, iface->ra_header_info.AdvReachableTime);
717 	if (iface->ra_header_info.AdvRetransTimer)
718 		set_interface_retranstimer(iface->props.name, iface->ra_header_info.AdvRetransTimer);
719 }
720 
721 /*
722  *      send initial advertisement and set timers
723  */
kickoff_adverts(int sock,struct Interface * iface)724 static void kickoff_adverts(int sock, struct Interface *iface)
725 {
726 	clock_gettime(CLOCK_MONOTONIC, &iface->times.last_ra_time);
727 
728 	if (iface->UnicastOnly)
729 		return;
730 
731 	clock_gettime(CLOCK_MONOTONIC, &iface->times.last_multicast);
732 
733 	/* send an initial advertisement */
734 	if (send_ra_forall(sock, iface, NULL) != 0) {
735 		dlog(LOG_DEBUG, 4, "send_ra_forall failed on interface %s", iface->props.name);
736 	}
737 
738 	double next = min(MAX_INITIAL_RTR_ADVERT_INTERVAL, iface->MaxRtrAdvInterval);
739 	reschedule_iface(iface, next);
740 }
741 
stop_advert_foo(struct Interface * iface,void * data)742 static void stop_advert_foo(struct Interface *iface, void *data)
743 {
744 	if (!iface->UnicastOnly) {
745 		/* send a final advertisement with zero Router Lifetime */
746 		dlog(LOG_DEBUG, 4, "stopping all adverts on %s", iface->props.name);
747 		iface->state_info.cease_adv = 1;
748 		int sock = *(int *)data;
749 		send_ra_forall(sock, iface, NULL);
750 	}
751 }
752 
stop_adverts(int sock,struct Interface * ifaces)753 static void stop_adverts(int sock, struct Interface *ifaces)
754 {
755 	flog(LOG_INFO, "sending stop adverts");
756 	/*
757 	 *      send final RA (a SHOULD in RFC4861 section 6.2.5)
758 	 */
759 	for_each_iface(ifaces, stop_advert_foo, &sock);
760 }
761 
setup_iface_foo(struct Interface * iface,void * data)762 static void setup_iface_foo(struct Interface *iface, void *data)
763 {
764 	int sock = *(int *)data;
765 
766 	if (setup_iface(sock, iface) < 0) {
767 		if (iface->IgnoreIfMissing) {
768 			dlog(LOG_DEBUG, 4, "interface %s does not exist or is not set up properly, ignoring the interface",
769 			     iface->props.name);
770 			return;
771 		} else {
772 			flog(LOG_ERR, "interface %s does not exist or is not set up properly", iface->props.name);
773 			exit(1);
774 		}
775 	}
776 
777 	config_interface(iface);
778 	kickoff_adverts(sock, iface);
779 }
780 
setup_ifaces(int sock,struct Interface * ifaces)781 static void setup_ifaces(int sock, struct Interface *ifaces) { for_each_iface(ifaces, setup_iface_foo, &sock); }
782 
reload_config(int sock,struct Interface * ifaces,char const * conf_path)783 static struct Interface *reload_config(int sock, struct Interface *ifaces, char const *conf_path)
784 {
785 	free_ifaces(ifaces);
786 
787 	flog(LOG_INFO, "attempting to reread config file");
788 
789 	/* reread config file */
790 	ifaces = readin_config(conf_path);
791 	if (!ifaces) {
792 		flog(LOG_ERR, "exiting, failed to read config file");
793 		exit(1);
794 	}
795 	setup_ifaces(sock, ifaces);
796 
797 	flog(LOG_INFO, "resuming normal operation");
798 
799 	return ifaces;
800 }
801 
sighup_handler(int sig)802 static void sighup_handler(int sig) { sighup_received = 1; }
803 
sigterm_handler(int sig)804 static void sigterm_handler(int sig)
805 {
806 	++sigterm_received;
807 
808 	if (sigterm_received > 2) {
809 		abort();
810 	}
811 }
812 
sigint_handler(int sig)813 static void sigint_handler(int sig)
814 {
815 	++sigint_received;
816 
817 	if (sigint_received > 2) {
818 		abort();
819 	}
820 }
821 
sigusr1_handler(int sig)822 static void sigusr1_handler(int sig) { sigusr1_received = 1; }
823 
reset_prefix_lifetimes_foo(struct Interface * iface,void * data)824 static void reset_prefix_lifetimes_foo(struct Interface *iface, void *data)
825 {
826 	flog(LOG_INFO, "Resetting prefix lifetimes on %s", iface->props.name);
827 
828 	for (struct AdvPrefix *prefix = iface->AdvPrefixList; prefix; prefix = prefix->next) {
829 		if (prefix->DecrementLifetimesFlag) {
830 			char pfx_str[INET6_ADDRSTRLEN];
831 			addrtostr(&prefix->Prefix, pfx_str, sizeof(pfx_str));
832 			dlog(LOG_DEBUG, 4, "%s/%u%%%s plft reset from %u to %u secs", pfx_str, prefix->PrefixLen,
833 			     iface->props.name, prefix->curr_preferredlft, prefix->AdvPreferredLifetime);
834 			dlog(LOG_DEBUG, 4, "%s/%u%%%s vlft reset from %u to %u secs", pfx_str, prefix->PrefixLen,
835 			     iface->props.name, prefix->curr_validlft, prefix->AdvValidLifetime);
836 			prefix->curr_validlft = prefix->AdvValidLifetime;
837 			prefix->curr_preferredlft = prefix->AdvPreferredLifetime;
838 		}
839 	}
840 }
841 
reset_prefix_lifetimes(struct Interface * ifaces)842 static void reset_prefix_lifetimes(struct Interface *ifaces) { for_each_iface(ifaces, reset_prefix_lifetimes_foo, 0); }
843 
drop_root_privileges(const char * username)844 static int drop_root_privileges(const char *username)
845 {
846 	struct passwd *pw = getpwnam(username);
847 	if (pw) {
848 		if (initgroups(username, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) {
849 			flog(LOG_ERR, "Couldn't change to '%.32s' uid=%d gid=%d", username, pw->pw_uid, pw->pw_gid);
850 			return -1;
851 		}
852 	} else {
853 		flog(LOG_ERR, "Couldn't find user '%.32s'", username);
854 		return -1;
855 	}
856 	return 0;
857 }
858 
check_conffile_perm(const char * username,const char * conf_file)859 static int check_conffile_perm(const char *username, const char *conf_file)
860 {
861 	FILE *fp = fopen(conf_file, "r");
862 	if (fp == NULL) {
863 		flog(LOG_ERR, "can't open %s: %s", conf_file, strerror(errno));
864 		return -1;
865 	}
866 	fclose(fp);
867 
868 	if (!username)
869 		username = "root";
870 
871 	struct passwd *pw = getpwnam(username);
872 	if (!pw) {
873 		return -1;
874 	}
875 
876 	struct stat stbuf;
877 	if (0 != stat(conf_file, &stbuf)) {
878 		return -1;
879 	}
880 
881 	if (stbuf.st_mode & S_IWOTH) {
882 		flog(LOG_ERR, "Insecure file permissions (writable by others): %s", conf_file);
883 		return -1;
884 	}
885 
886 	/* for non-root: must not be writable by self/own group */
887 	if (strncmp(username, "root", 5) != 0 && ((stbuf.st_mode & S_IWGRP && pw->pw_gid == stbuf.st_gid) ||
888 						  (stbuf.st_mode & S_IWUSR && pw->pw_uid == stbuf.st_uid))) {
889 		flog(LOG_ERR, "Insecure file permissions (writable by self/group): %s", conf_file);
890 		return -1;
891 	}
892 
893 	return 0;
894 }
895 
version(void)896 static void version(void)
897 {
898 	fprintf(stderr, "Version: %s\n\n", VERSION);
899 	fprintf(stderr, "Compiled in settings:\n");
900 	fprintf(stderr, "  default config file		\"%s\"\n", PATH_RADVD_CONF);
901 	fprintf(stderr, "  default pidfile		\"%s\"\n", PATH_RADVD_PID);
902 	fprintf(stderr, "  default logfile		\"%s\"\n", PATH_RADVD_LOG);
903 	fprintf(stderr, "  default syslog facility	%d\n", LOG_FACILITY);
904 	fprintf(stderr, "Please send bug reports or suggestions to %s.\n", CONTACT_EMAIL);
905 
906 	exit(1);
907 }
908 
usage(char const * pname)909 static void usage(char const *pname)
910 {
911 	fprintf(stderr, "usage: %s %s\n", pname, usage_str);
912 	exit(1);
913 }
914