1 /*
2 * aprsc
3 *
4 * (c) Heikki Hannikainen, OH7LZB <hessu@hes.iki.fi>
5 *
6 * This program is licensed under the BSD license, which can be found
7 * in the file LICENSE.
8 *
9 */
10
11 #define HELPS "Usage: aprsc [-t <chrootdir>] [-u <setuid user>] [-c <cfgfile>] [-f (fork)]\n" \
12 " [-n <logname>] [-e <loglevel>] [-o <logdest>] [-r <logdir>] [-p <pidfile>]\n" \
13 " [-y (try config)] [-h (help)]\n"
14
15 #include <pthread.h>
16 #include <semaphore.h>
17
18 #include <string.h>
19 #include <errno.h>
20 #include <stdarg.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <signal.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <pwd.h>
28 #include <time.h>
29 #include <sys/time.h>
30 #ifdef __linux__ /* Very Linux-specific code.. */
31 #include <sys/syscall.h>
32 #endif
33 #include <sys/resource.h>
34 #include <locale.h>
35 #include <ctype.h>
36
37 #include "hmalloc.h"
38 #include "hlog.h"
39 #include "config.h"
40 #include "ssl.h"
41 #include "accept.h"
42 #include "uplink.h"
43 #include "worker.h"
44 #include "status.h"
45 #include "http.h"
46 #include "version.h"
47
48 #include "dupecheck.h"
49 #include "filter.h"
50 #include "historydb.h"
51 #include "client_heard.h"
52 #include "keyhash.h"
53
54 #ifdef USE_POSIX_CAP
55 #include <sys/capability.h>
56 #include <sys/prctl.h>
57 #endif
58
59 struct itimerval itv; // Linux profiling timer does not pass over to pthreads..
60
61 int shutting_down; // are we shutting down now?
62 int reopen_logs; // should we reopen log files now?
63 int reconfiguring; // should we reconfigure now?
64 int fileno_limit = -1;
65 int dbdump_at_exit;
66 int quit_after_config;
67 int liveupgrade_startup;
68 int liveupgrade_fired;
69 int want_dbdump;
70
71 /* random instance ID, alphanumeric low-case */
72 #define INSTANCE_ID_LEN 8
73 char instance_id[INSTANCE_ID_LEN+1];
74
75 pthread_attr_t pthr_attrs;
76
77 /*
78 * Parse arguments
79 */
80
parse_cmdline(int argc,char * argv[])81 void parse_cmdline(int argc, char *argv[])
82 {
83 int s, i;
84 int failed = 0;
85
86 while ((s = getopt(argc, argv, "c:ft:u:n:r:d:DyZe:o:p:?h")) != -1) {
87 switch (s) {
88 case 'c':
89 if (cfgfile && cfgfile != def_cfgfile)
90 hfree(cfgfile);
91 cfgfile = hstrdup(optarg);
92 break;
93 case 'f':
94 fork_a_daemon = 1;
95 break;
96 case 't':
97 if (chrootdir)
98 hfree(chrootdir);
99 chrootdir = hstrdup(optarg);
100 break;
101 case 'u':
102 if (setuid_s)
103 hfree(setuid_s);
104 setuid_s = hstrdup(optarg);
105 break;
106 case 'n':
107 if (logname && logname != def_logname)
108 hfree(logname);
109 logname = hstrdup(optarg);
110 break;
111 case 'r':
112 if (log_dir)
113 hfree(log_dir);
114 log_dir = hstrdup(optarg);
115 break;
116 case 'd':
117 if (!strcasecmp(optarg, "requests")) {
118 //dump_requests = 1;
119 } else if (!strcasecmp(optarg, "splay")) {
120 dump_splay = 1;
121 } else {
122 fprintf(stderr, "Unknown -d parameter: %s\n", optarg);
123 failed = 1;
124 }
125 break;
126 case 'D':
127 dbdump_at_exit = 1;
128 break;
129 case 'y':
130 quit_after_config = 1;
131 break;
132 case 'Z': /* Can be removed in 2.2 or so, switched to an env var */
133 liveupgrade_startup = 1;
134 break;
135 case 'e':
136 i = pick_loglevel(optarg, log_levelnames);
137 if (i > -1)
138 log_level = i;
139 else {
140 fprintf(stderr, "Log level unknown: \"%s\"\n", optarg);
141 failed = 1;
142 }
143 break;
144 case 'o':
145 i = pick_loglevel(optarg, log_destnames);
146 if (i > -1)
147 if (i == 0)
148 log_dest = 0;
149 else
150 log_dest = 1 << (i-1);
151 else {
152 fprintf(stderr, "Log destination unknown: \"%s\"\n", optarg);
153 failed = 1;
154 }
155 break;
156 case 'p':
157 if (pidfile)
158 hfree(pidfile);
159 pidfile= hstrdup(optarg);
160 break;
161 case '?':
162 case 'h':
163 fprintf(stderr, "%s\nBuilt at %s by %s\nBuilt with:%s\n",
164 verstr, verstr_build_time, verstr_build_user, verstr_features);
165 failed = 1;
166 }
167 }
168
169 /* when doing a live upgrade, we're already with the right user */
170 if (liveupgrade_startup && setuid_s) {
171 hfree(setuid_s);
172 setuid_s = NULL;
173 }
174
175 if (!log_dir)
176 log_dir = hstrdup("logs");
177
178 if (failed) {
179 fputs(HELPS, stderr);
180 exit(failed);
181 }
182
183 if (quit_after_config) {
184 fork_a_daemon = 0;
185 }
186 }
187
188 /*
189 * signal handler
190 */
191
sighandler(int signum)192 int sighandler(int signum)
193 {
194 switch (signum) {
195
196 case SIGINT:
197 case SIGTERM:
198 case SIGQUIT:
199 hlog(LOG_NOTICE, "Shutting down on signal %d", signum);
200 shutting_down = 1;
201 return 0;
202
203 case SIGHUP:
204 hlog(LOG_INFO, "SIGHUP received: reopening logs");
205 reopen_logs = 1;
206 break;
207
208 case SIGUSR1:
209 hlog(LOG_INFO, "SIGUSR1 received: reconfiguring");
210 reconfiguring = 1;
211 break;
212
213 case SIGUSR2:
214 hlog(LOG_INFO, "SIGUSR2 received: performing live upgrade");
215 liveupgrade_fired = 1;
216 shutting_down = 1;
217 break;
218
219 default:
220 hlog(LOG_WARNING, "* SIG %d ignored", signum);
221 break;
222 }
223
224 signal(signum, (void *)sighandler); /* restore handler */
225 return 0;
226
227 }
228
229 /*
230 * A very Linux specific thing, as there the pthreads are a special variation
231 * of fork(), and per POSIX the profiling timers are not kept over fork()...
232 */
pthreads_profiling_reset(const char * name)233 void pthreads_profiling_reset(const char *name)
234 {
235 #ifdef __linux__ /* Very Linux-specific code.. */
236 int tid;
237 if (itv.it_interval.tv_usec || itv.it_interval.tv_sec) {
238 setitimer(ITIMER_PROF, &itv, NULL);
239 }
240
241 tid = syscall(SYS_gettid);
242 hlog(LOG_DEBUG, "Thread %s: Linux ThreadId: %d", name, tid);
243 #endif
244 }
245
246 #define PATHLEN 500
dbdump_historydb(void)247 static int dbdump_historydb(void)
248 {
249 FILE *fp;
250 char path[PATHLEN+1];
251 int ret = 0;
252
253 snprintf(path, PATHLEN, "%s/historydb.json", rundir);
254 fp = fopen(path,"w");
255 if (!fp) {
256 hlog(LOG_ERR, "dbdump historydb failed to open %s for writing: %s", path, strerror(errno));
257 return -1;
258 }
259
260 if (historydb_dump(fp)) {
261 ret = -1;
262 }
263
264 if (fclose(fp)) {
265 hlog(LOG_ERR, "dbdump historydb failed to close %s after writing: %s", path, strerror(errno));
266 return -1;
267 }
268
269 return ret;
270 }
271
dbdump_all(void)272 static void dbdump_all(void)
273 {
274 FILE *fp;
275 char path[PATHLEN+1];
276
277 /*
278 * As a general rule, dumping of databases is not a Good Idea in
279 * operational system. Development time debugging on other hand..
280 */
281
282 dbdump_historydb();
283
284 snprintf(path, PATHLEN, "%s/filter.wx.dump", rundir);
285 fp = fopen(path,"w");
286 if (fp) {
287 filter_wx_dump(fp);
288 fclose(fp);
289 }
290 snprintf(path, PATHLEN, "%s/filter.entry.dump", rundir);
291 fp = fopen(path,"w");
292 if (fp) {
293 filter_entrycall_dump(fp);
294 fclose(fp);
295 }
296 snprintf(path, PATHLEN, "%s/pbuf.dump", rundir);
297 fp = fopen(path,"w");
298 if (fp) {
299 pbuf_dump(fp);
300 fclose(fp);
301 }
302 snprintf(path, PATHLEN, "%s/pbuf.dupe.dump", rundir);
303 fp = fopen(path,"w");
304 if (fp) {
305 pbuf_dupe_dump(fp);
306 fclose(fp);
307 }
308 }
309
dbload_all(void)310 static void dbload_all(void)
311 {
312 FILE *fp;
313 char path[PATHLEN+1];
314 char path_renamed[PATHLEN+1];
315
316 snprintf(path, PATHLEN, "%s/historydb.json", rundir);
317 fp = fopen(path,"r");
318 if (fp) {
319 hlog(LOG_INFO, "Live upgrade: Loading historydb from %s ...", path);
320 snprintf(path_renamed, PATHLEN, "%s/historydb.json.old", rundir);
321 if (rename(path, path_renamed) < 0) {
322 hlog(LOG_ERR, "Failed to rename historydb dump file %s to %s: %s",
323 path, path_renamed, strerror(errno));
324 unlink(path);
325 }
326
327 historydb_load(fp);
328 fclose(fp);
329 }
330 }
331
332 /*
333 * switch uid
334 */
335 struct passwd pwbuf;
336 char *pw_buf_s;
337
338 /* Look up the target UID/GID from passwd/group */
find_uid(const char * uid_s)339 static void find_uid(const char *uid_s)
340 {
341 struct passwd *pwbufp;
342 int buflen;
343
344 buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
345 if (buflen < 10)
346 buflen = 1024;
347
348 pw_buf_s = hmalloc(buflen);
349
350 #ifdef sun
351 pwbufp = getpwnam_r(uid_s, &pwbuf, pw_buf_s, buflen);
352 #else
353 int e = getpwnam_r(uid_s, &pwbuf, pw_buf_s, buflen, &pwbufp);
354
355 if (e) {
356 fprintf(stderr, "aprsc: getpwnam(%s) failed, can not set UID: %s\n", uid_s, strerror(e));
357 exit(1);
358 }
359 #endif
360
361 if (pwbufp == NULL) {
362 fprintf(stderr, "aprsc: getpwnam(%s) failed, can not set UID: user not found\n", uid_s);
363 exit(1);
364 }
365 }
366
367 /* set effective UID, for startup time */
set_euid(void)368 static void set_euid(void)
369 {
370 if (setegid(pwbuf.pw_gid)) {
371 fprintf(stderr, "aprsc: Failed to set effective GID %d: %s\n", pwbuf.pw_gid, strerror(errno));
372 exit(1);
373 }
374
375 if (seteuid(pwbuf.pw_uid)) {
376 fprintf(stderr, "aprsc: Failed to set effective UID %d: %s\n", pwbuf.pw_uid, strerror(errno));
377 exit(1);
378 }
379 }
380
381 /* switch back to uid 0 for post-config setup as root */
set_euid_0(void)382 static void set_euid_0(void)
383 {
384 if (seteuid(0)) {
385 fprintf(stderr, "aprsc: Failed to set effective UID back to 0: %s\n", strerror(errno));
386 exit(1);
387 }
388 }
389
check_caps(char * when)390 static void check_caps(char *when)
391 {
392 #ifdef USE_POSIX_CAP
393 cap_t caps = cap_get_proc();
394
395 if (caps == NULL) {
396 hlog(LOG_ERR, "check_caps: Failed to get current POSIX capabilities: %s", strerror(errno));
397 return;
398 }
399
400 char *s = cap_to_text(caps, NULL);
401
402 if (s) {
403 hlog(LOG_DEBUG, "aprsc: capabilities %s: %s", when, s);
404 }
405
406 cap_free(caps);
407 #endif
408 }
409
set_initial_capabilities(void)410 static int set_initial_capabilities(void)
411 {
412 #ifdef USE_POSIX_CAP
413 int ret = -1;
414
415 cap_t caps = cap_init();
416
417 /* list of capabilities needed at startup - less than what root has */
418 #define NCAPS 5
419 cap_value_t cap_list[NCAPS];
420 cap_list[0] = CAP_NET_BIND_SERVICE;
421 cap_list[1] = CAP_SETUID;
422 cap_list[2] = CAP_SETGID;
423 cap_list[3] = CAP_SYS_RESOURCE;
424 cap_list[4] = CAP_SYS_CHROOT;
425
426 if (cap_set_flag(caps, CAP_PERMITTED, NCAPS, cap_list, CAP_SET) == -1) {
427 fprintf(stderr, "aprsc: Failed to set initial POSIX capability flags: %s\n", strerror(errno));
428 goto end_caps;
429 }
430
431 if (cap_set_flag(caps, CAP_EFFECTIVE, NCAPS, cap_list, CAP_SET) == -1) {
432 fprintf(stderr, "aprsc: Failed to set initial POSIX capability flags: %s\n", strerror(errno));
433 goto end_caps;
434 }
435
436 //fprintf(stderr, "aprsc: going to set: %s\n", cap_to_text(caps, NULL));
437
438 if (cap_set_proc(caps) == -1) {
439 fprintf(stderr, "aprsc: Failed to apply initial POSIX capabilities: %s\n", strerror(errno));
440 goto end_caps;
441 }
442
443 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
444 fprintf(stderr, "aprsc: Failed to set PR_SET_KEEPCAPS: %s\n", strerror(errno));
445 goto end_caps;
446 }
447
448 //fprintf(stderr, "aprsc: Successfully enabled initial POSIX capabilities\n");
449 ret = 0;
450
451 end_caps:
452 if (caps) {
453 if (cap_free(caps) == -1)
454 fprintf(stderr, "aprsc: Failed to free capabilities: %s\n", strerror(errno));
455 caps = NULL;
456 }
457
458 return ret;
459 #else
460 return 0;
461 #endif
462 }
463
set_final_capabilities(void)464 static int set_final_capabilities(void)
465 {
466 #ifdef USE_POSIX_CAP
467 int ret = -1;
468 cap_t caps = cap_init();
469
470 #define NCAPS_FINAL 1
471 if (listen_low_ports) {
472 cap_value_t cap_list[NCAPS_FINAL];
473 cap_list[0] = CAP_NET_BIND_SERVICE;
474
475 if (cap_set_flag(caps, CAP_PERMITTED, NCAPS_FINAL, cap_list, CAP_SET) == -1) {
476 hlog(LOG_ERR, "aprsc: Failed to set final permitted POSIX capability flags: %s", strerror(errno));
477 goto end_caps;
478 }
479
480 if (cap_set_flag(caps, CAP_EFFECTIVE, NCAPS_FINAL, cap_list, CAP_SET) == -1) {
481 hlog(LOG_ERR, "aprsc: Failed to set final effective POSIX capability flags: %s", strerror(errno));
482 goto end_caps;
483 }
484
485 /* when we exec() myself in live upgrade, these capabilities are also
486 * needed by the new process. INHERITABLE FTW!
487 */
488 if (cap_set_flag(caps, CAP_INHERITABLE, NCAPS_FINAL, cap_list, CAP_SET) == -1) {
489 hlog(LOG_ERR, "aprsc: Failed to set final inheritable POSIX capability flags: %s", strerror(errno));
490 goto end_caps;
491 }
492
493 //fprintf(stderr, "aprsc: going to set: %s\n", cap_to_text(caps, NULL));
494 ret = 1;
495 } else {
496 ret = 0;
497 }
498
499 if (cap_set_proc(caps) == -1) {
500 hlog(LOG_ERR, "aprsc: Failed to apply final POSIX capabilities: %s", strerror(errno));
501 ret = -1;
502 goto end_caps;
503 }
504
505 //fprintf(stderr, "aprsc: Successfully enabled final POSIX capabilities\n");
506
507 end_caps:
508 if (caps) {
509 if (cap_free(caps) == -1)
510 hlog(LOG_ERR, "aprsc: Failed to free capabilities: %s", strerror(errno));
511 caps = NULL;
512 }
513
514 return ret;
515 #else
516 return -1;
517 #endif
518 }
519
520 /* set real UID to non-root, cannot be reversed */
set_uid(void)521 static void set_uid(void)
522 {
523 //check_caps("before set_uid");
524
525 if (setgid(pwbuf.pw_gid)) {
526 fprintf(stderr, "aprsc: Failed to set GID %d: %s\n", pwbuf.pw_gid, strerror(errno));
527 exit(1);
528 }
529
530 if (setuid(pwbuf.pw_uid)) {
531 fprintf(stderr, "aprsc: Failed to set UID %d: %s\n", pwbuf.pw_uid, strerror(errno));
532 exit(1);
533 }
534
535 }
536
537 /*
538 * Check that we're not running as root. Bail out if we are
539 */
540
check_uid(void)541 static void check_uid(void)
542 {
543 if (getuid() == 0 || geteuid() == 0) {
544 fprintf(stderr,
545 "aprsc: Security incident about to happen: running as root.\n"
546 "Use the -u <username> switch to run as unprivileged user 'aprsc', or start\n"
547 "it up as such an user.\n");
548 exit(1);
549 }
550 }
551
552 /*
553 * Generate a pseudorandom instance ID by reading the pseudorandom
554 * source and converting the binary data to lower-case alphanumeric
555 */
556
generate_instance_id(void)557 static void generate_instance_id(void)
558 {
559 unsigned char s[INSTANCE_ID_LEN];
560 int fd, l;
561 char c;
562 unsigned seed;
563 struct timeval tv;
564
565 if ((fd = open("/dev/urandom", O_RDONLY)) == -1) {
566 hlog(LOG_ERR, "open(/dev/urandom) failed: %s", strerror(errno));
567 fd = -1;
568 }
569
570 /* seed the prng */
571 if (fd >= 0) {
572 l = read(fd, &seed, sizeof(seed));
573 if (l != sizeof(seed)) {
574 hlog(LOG_ERR, "read(/dev/urandom, %d) for seed failed: %s", sizeof(seed), strerror(errno));
575 close(fd);
576 fd = -1;
577 }
578 }
579
580 if (fd < 0) {
581 /* not very strong, but we're not doing cryptography here */
582 gettimeofday(&tv, NULL);
583 seed = tv.tv_sec + tv.tv_usec + getpid();
584 }
585
586 srandom(seed);
587
588 if (fd >= 0) {
589 /* generate instance id */
590 l = read(fd, s, INSTANCE_ID_LEN);
591 if (l != INSTANCE_ID_LEN) {
592 hlog(LOG_ERR, "read(/dev/urandom, %d) failed: %s", INSTANCE_ID_LEN, strerror(errno));
593 close(fd);
594 fd = -1;
595 }
596 }
597
598 if (fd < 0) {
599 /* urandom failed for us, use something inferior */
600 for (l = 0; l < INSTANCE_ID_LEN; l++) {
601 // coverity[dont_call] // squelch warning: not security sensitive use of random()
602 s[l] = random() % 256;
603 }
604 }
605
606 for (l = 0; l < INSTANCE_ID_LEN; l++) {
607 /* 256 is not divisible by 36, the distribution is slightly skewed,
608 * but that's not serious.
609 */
610 c = s[l] % (26 + 10); /* letters and numbers */
611 if (c < 10)
612 c += 48; /* number */
613 else
614 c = c - 10 + 97; /* letter */
615 instance_id[l] = c;
616 }
617 instance_id[INSTANCE_ID_LEN] = 0;
618
619 if (fd >= 0)
620 close(fd);
621 }
622
623 /*
624 * DNS lookup which phones home with version information.
625 *
626 * Tin foil hats off. Version information and instance statistics
627 * make developers happy.
628 */
629
version_report(const char * state)630 void version_report(const char *state)
631 {
632 #ifdef VERSION_REPORT_OVER_DNS
633 struct addrinfo hints;
634 struct addrinfo *ai;
635 char v[80];
636 char n[32];
637 char s[300];
638 int i, l;
639
640 /* don't send version reports during testing */
641 if (getenv("APRSC_NO_VERSION_REPORT"))
642 return;
643
644 /* normalize version string to fit in a DNS label */
645 strncpy(v, version_build, sizeof(v));
646 l = strlen(v);
647 for (i = 0; i < sizeof(v) && i < l; i++)
648 if (!isalnum(v[i]))
649 v[i] = '-';
650
651 if (serverid) {
652 /* we're configured, include serverid and normalize it */
653 strncpy(n, serverid, sizeof(n));
654 n[sizeof(n)-1] = 0;
655 l = strlen(n);
656 for (i = 0; i < sizeof(n) && i < l; i++)
657 if (!isalnum(n[i]))
658 n[i] = '-';
659 snprintf(s, 300, "%s.%s.%s.%s.aprsc.he.fi", n, v, instance_id, state);
660 } else {
661 snprintf(s, 300, "%s.%s.%s.aprsc.he.fi", v, instance_id, state);
662 }
663
664 /* reduce the amount of lookups in case of a failure, don't do
665 * separate AAAA + A lookups
666 */
667 memset(&hints, 0, sizeof(hints));
668 hints.ai_family = AF_INET;
669
670 ai = NULL;
671 i = getaddrinfo(s, NULL, &hints, &ai);
672 if (i != 0)
673 hlog(LOG_DEBUG, "DNS lookup of aprsc.he.fi failed: %s", gai_strerror(i));
674 if (ai)
675 freeaddrinfo(ai);
676 #endif
677 }
678
679 /*
680 * Execute a new myself to perform a live upgrade
681 */
682
liveupgrade_exec(int argc,char ** argv)683 static void liveupgrade_exec(int argc, char **argv)
684 {
685 char **nargv;
686 int i;
687 char *bin = argv[0];
688
689 i = strlen(argv[0]);
690 if (chrootdir && strncmp(argv[0], chrootdir, strlen(chrootdir)) == 0) {
691 bin = hmalloc(i+1);
692 strncpy(bin, argv[0] + strlen(chrootdir), i);
693 }
694
695 hlog(LOG_NOTICE, "Live upgrade: Executing the new me: %s", bin);
696
697 /* generate argument list for the new executable */
698 nargv = hmalloc(sizeof(char *) * (argc+1));
699
700 nargv[0] = bin;
701 for (i = 1; i < argc; i++)
702 nargv[i] = argv[i];
703
704 nargv[i++] = NULL;
705
706 /* new method of signalling live upgrade, less confusion */
707 #ifdef HAVE_SETENV
708 if (setenv("APRSC_LIVE_UPGRADE", "1", 1) != 0) {
709 hlog(LOG_CRIT, "Live upgrade: setenv(APRSC_LIVE_UPGRADE) failed: %s", strerror(errno));
710 goto err;
711 }
712 #else
713 #ifdef HAVE_PUTENV
714 if (putenv("APRSC_LIVE_UPGRADE=1") != 0) {
715 hlog(LOG_CRIT, "Live upgrade: putenv(APRSC_LIVE_UPGRADE) failed: %s", strerror(errno));
716 goto err;
717 }
718 #else
719 hlog(LOG_CRIT, "Live upgrade: no putenv/setenv available, live upgrade does not work");
720 goto err;
721 #endif
722 #endif
723
724 /* close pid file and free the lock on it */
725 closepid();
726
727 /* close log file so that we don't leak the file descriptor */
728 close_log(0);
729
730 /* execute new binary, should not return if all goes fine */
731 execv(bin, nargv);
732
733 hlog(LOG_CRIT, "liveupgrade: exec failed, I'm still here! %s", strerror(errno));
734
735 err:
736 /* free resources in case we'd decide to continue anyway */
737 if (bin != argv[0])
738 hfree(bin);
739 hfree(nargv);
740 }
741
742
743 /*
744 * Time-keeping thread
745 */
746
747 #ifdef USE_CLOCK_GETTIME
timeval_diff(struct timespec start,struct timespec end)748 static double timeval_diff(struct timespec start, struct timespec end)
749 {
750 double diff;
751
752 diff = (end.tv_sec - start.tv_sec)
753 + ((end.tv_nsec - start.tv_nsec) / 1000000000.0);
754
755 return diff;
756 }
757 #else
timeval_diff(struct timeval start,struct timeval end)758 static double timeval_diff(struct timeval start, struct timeval end)
759 {
760 double diff;
761
762 diff = (end.tv_sec - start.tv_sec)
763 + ((end.tv_usec - start.tv_usec) / 1000000.0);
764
765 return diff;
766 }
767 #endif
768
time_set_tick_and_now(void)769 void time_set_tick_and_now(void)
770 {
771 #ifdef USE_CLOCK_GETTIME
772 struct timespec ts;
773 clock_gettime(CLOCK_MONOTONIC, &ts);
774 tick = ts.tv_sec;
775 clock_gettime(CLOCK_REALTIME, &ts);
776 now = ts.tv_sec;
777 #else
778 struct timeval tv;
779 gettimeofday(&tv, NULL);
780 tick = tv.tv_sec;
781 now = tv.tv_sec;
782 #endif
783 }
784
time_thread(void * asdf)785 void time_thread(void *asdf)
786 {
787 sigset_t sigs_to_block;
788 time_t previous_tick;
789 struct timespec sleep_req;
790 #ifdef USE_CLOCK_GETTIME
791 struct timespec sleep_start, sleep_end;
792 struct timespec ts;
793 hlog(LOG_INFO, "Time thread starting: using clock_gettime");
794 #else
795 struct timeval sleep_start, sleep_end;
796 hlog(LOG_INFO, "Time thread starting: using gettimeofday");
797 #endif
798
799 pthreads_profiling_reset("time");
800
801 sigemptyset(&sigs_to_block);
802 sigaddset(&sigs_to_block, SIGALRM);
803 sigaddset(&sigs_to_block, SIGINT);
804 sigaddset(&sigs_to_block, SIGTERM);
805 sigaddset(&sigs_to_block, SIGQUIT);
806 sigaddset(&sigs_to_block, SIGHUP);
807 sigaddset(&sigs_to_block, SIGURG);
808 sigaddset(&sigs_to_block, SIGPIPE);
809 sigaddset(&sigs_to_block, SIGUSR1);
810 sigaddset(&sigs_to_block, SIGUSR2);
811 pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL);
812
813 time_set_tick_and_now();
814 previous_tick = tick;
815
816 sleep_req.tv_sec = 0;
817 sleep_req.tv_nsec = 210 * 1000 * 1000; /* 210 ms */
818
819 while (!accept_shutting_down) {
820 #ifdef USE_CLOCK_GETTIME
821 clock_gettime(CLOCK_MONOTONIC, &sleep_start);
822 nanosleep(&sleep_req, NULL);
823 clock_gettime(CLOCK_MONOTONIC, &sleep_end);
824 tick = sleep_end.tv_sec;
825 clock_gettime(CLOCK_REALTIME, &ts);
826 now = ts.tv_sec;
827 #else
828 gettimeofday(&sleep_start, NULL);
829 nanosleep(&sleep_req, NULL);
830 gettimeofday(&sleep_end, NULL);
831 tick = sleep_end.tv_sec;
832 now = tick;
833 #endif
834
835 double slept = timeval_diff(sleep_start, sleep_end);
836 if (slept > 0.90)
837 hlog(LOG_WARNING, "time keeping: sleep of %d ms took %.6f s!", sleep_req.tv_nsec / 1000 / 1000, slept);
838
839 /* catch some oddities with time keeping */
840 if (tick != previous_tick) {
841 if (previous_tick > tick) {
842 hlog(LOG_WARNING, "time keeping: Time jumped backward by %d seconds!", previous_tick - tick);
843 } else if (previous_tick < tick-1) {
844 hlog(LOG_WARNING, "time keeping: Time jumped forward by %d seconds!", tick - previous_tick);
845 }
846
847 previous_tick = tick;
848 }
849
850 }
851
852 }
853
init_reopen_stdio(void)854 static void init_reopen_stdio(void)
855 {
856 /* close stdin and stdout, and any other FDs that might be left open */
857 /* closing stderr masks error logs between this point and opening the logs... suboptimal. */
858 {
859 int i;
860 close(0);
861 close(1);
862 for (i = 3; i < 100; i++)
863 close(i);
864 }
865
866 /* all of this fails in chroot, so do it before */
867 if (open("/dev/null", O_RDWR) == -1) /* stdin */
868 hlog(LOG_ERR, "open(/dev/null) failed for stdin: %s", strerror(errno));
869 if (dup(0) == -1) /* stdout */
870 hlog(LOG_ERR, "dup(0) failed for stdout: %s", strerror(errno));
871 }
872
873 /*
874 * Main
875 */
876
main(int argc,char ** argv)877 int main(int argc, char **argv)
878 {
879 pthread_t accept_th;
880 pthread_t http_th;
881 pthread_t time_th;
882 int e;
883 struct rlimit rlim;
884 time_t cleanup_tick = 0;
885 time_t version_tick = 0;
886 int have_low_ports = 0;
887
888 if (getuid() == 0)
889 set_initial_capabilities();
890
891 time_set_tick_and_now();
892 cleanup_tick = tick;
893 // coverity[dont_call] // squelch warning: not security sensitive use of random()
894 version_tick = tick + random() % 60; /* some load distribution */
895 startup_tick = tick;
896 startup_time = now;
897 setlinebuf(stderr);
898
899 /* set locale to C so that isalnum(), isupper() etc don't do anything
900 * unexpected if the environment is unexpected.
901 */
902 if (!setlocale(LC_COLLATE, "C")) {
903 hlog(LOG_CRIT, "Failed to set locale C for LC_COLLATE.");
904 exit(1);
905 }
906 if (!setlocale(LC_CTYPE, "C")) {
907 hlog(LOG_CRIT, "Failed to set locale C for LC_CTYPE.");
908 exit(1);
909 }
910 if (!setlocale(LC_MESSAGES, "C")) {
911 hlog(LOG_CRIT, "Failed to set locale C for LC_MESSAGES.");
912 exit(1);
913 }
914 if (!setlocale(LC_NUMERIC, "C")) {
915 hlog(LOG_CRIT, "Failed to set locale C for LC_NUMERIC.");
916 exit(1);
917 }
918
919 /* Adjust process global fileno limit to match the maximum available
920 * at this time
921 */
922 e = getrlimit(RLIMIT_NOFILE, &rlim);
923 if (e < 0) {
924 hlog(LOG_ERR, "Failed to get initial file number resource limit: %s", strerror(errno));
925 } else {
926 rlim.rlim_cur = rlim.rlim_max;
927 e = setrlimit(RLIMIT_NOFILE, &rlim);
928 if (e < 0) {
929 hlog(LOG_ERR, "Failed to set file number resource limit: %s", strerror(errno));
930 }
931 e = getrlimit(RLIMIT_NOFILE, &rlim);
932 if (e < 0) {
933 hlog(LOG_ERR, "Failed to verify modified file number resource limit: %s", strerror(errno));
934 }
935 fileno_limit = rlim.rlim_cur;
936 }
937
938 getitimer(ITIMER_PROF, &itv);
939
940 /* check if we're doing a live upgrade - need to know this in the
941 * command line parser already
942 */
943 if (getenv("APRSC_LIVE_UPGRADE"))
944 liveupgrade_startup = 1;
945
946 /* command line */
947 parse_cmdline(argc, argv);
948
949 /* if setuid is needed, find the user UID */
950 if (setuid_s)
951 find_uid(setuid_s);
952
953 /* fork a daemon */
954 if (fork_a_daemon) {
955 hlog(LOG_INFO, "Forking...");
956 int i = fork();
957 if (i < 0) {
958 hlog(LOG_CRIT, "Fork to background failed: %s", strerror(errno));
959 fprintf(stderr, "Fork to background failed: %s\n", strerror(errno));
960 exit(1);
961 } else if (i == 0) {
962 /* child */
963 hlog(LOG_INFO, "Child started...");
964 if (setsid() == -1) {
965 fprintf(stderr, "setsid() failed: %s\n", strerror(errno));
966 //exit(1);
967 }
968 } else {
969 /* parent, quitting */
970 hlog(LOG_DEBUG, "Forked daemon process %d, parent quitting", i);
971 exit(0);
972 }
973 }
974
975 /* close stdin and stdout, and any other FDs that might be left open */
976 if (!liveupgrade_startup)
977 init_reopen_stdio();
978
979 /* prepare for a possible chroot, force loading of
980 * resolver libraries at this point, so that we don't
981 * need a copy of the shared libs within the chroot dir
982 */
983 generate_instance_id();
984 version_report("startup");
985
986 /* do a chroot if required */
987 if (chrootdir && !liveupgrade_startup) {
988 if ((!setuid_s) || pwbuf.pw_uid == 0) {
989 fprintf(stderr, "aprsc: chroot requested but not setuid to non-root user - insecure\n"
990 "configuration detected. Using -u <username> and start as root required.\n");
991 exit(1);
992 }
993 if (chdir(chrootdir) != 0) {
994 fprintf(stderr, "aprsc: chdir(%s) failed before chroot: %s\n", chrootdir, strerror(errno));
995 exit(1);
996 }
997 if (chroot(chrootdir)) {
998 fprintf(stderr, "aprsc: chroot(%s) failed: %s\n", chrootdir, strerror(errno));
999 exit(1);
1000 }
1001 if (chdir("/") != 0) { /* maybe redundant after the first chdir() */
1002 fprintf(stderr, "aprsc: chdir(/) failed after chroot: %s\n", strerror(errno));
1003 exit(1);
1004 }
1005 }
1006
1007 /* set effective UID to non-root before opening files */
1008 if (setuid_s && !liveupgrade_startup)
1009 set_euid();
1010
1011 /* open syslog, write an initial log message and read configuration */
1012 open_log(logname, 0);
1013 if (!quit_after_config)
1014 hlog(LOG_NOTICE, "Starting up version %s, instance id %s %s...",
1015 version_build, instance_id, (liveupgrade_startup) ? "- LIVE UPGRADE " : "");
1016
1017 int orig_log_dest = log_dest;
1018 log_dest |= L_STDERR;
1019
1020 if (read_config()) {
1021 hlog(LOG_CRIT, "Initial configuration failed.");
1022 exit(1);
1023 }
1024
1025 if (quit_after_config)
1026 exit(0);
1027
1028 /* adjust file limits as requested, not after every reconfigure
1029 * but only at startup - we won't have root privileges available
1030 * later.
1031 */
1032 if (setuid_s)
1033 set_euid_0();
1034
1035 if (new_fileno_limit > 0 && new_fileno_limit != fileno_limit && !liveupgrade_startup) {
1036 /* Adjust process global fileno limit */
1037 struct rlimit rlim;
1038 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
1039 hlog(LOG_WARNING, "Configuration: getrlimit(RLIMIT_NOFILE) failed: %s", strerror(errno));
1040 rlim.rlim_cur = rlim.rlim_max = new_fileno_limit;
1041 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
1042 hlog(LOG_WARNING, "Configuration: setrlimit(RLIMIT_NOFILE) failed: %s", strerror(errno));
1043 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
1044 fileno_limit = rlim.rlim_cur;
1045 if (fileno_limit < new_fileno_limit)
1046 hlog(LOG_WARNING, "Configuration could not raise FileLimit%s, it is now %d", (getuid() != 0) ? " (not running as root)" : "", fileno_limit);
1047 }
1048 }
1049
1050 /* if setuid is needed, do so */
1051 if (setuid_s) {
1052 set_uid();
1053 //check_caps("after set_uid");
1054 if (set_final_capabilities() >= 0)
1055 have_low_ports = 1;
1056 check_caps("after set_final_capabilities");
1057 }
1058
1059 /* check that we're not root - it would be insecure and really not required */
1060 check_uid();
1061
1062 /* if we're not logging on stderr, we close the stderr FD after we have read configuration
1063 * and opened the log file or syslog - initial config errors should go to stderr.
1064 */
1065 if (!(log_dest & L_STDERR)) {
1066 close(2);
1067 if (dup(0) == -1) /* stderr */
1068 hlog(LOG_ERR, "dup(0) failed for stderr: %s", strerror(errno));
1069 }
1070
1071 /* Write pid file, now that we have our final pid... might fail, which is critical.
1072 * writepid locks the pid file and leaves the file descriptor open, so that
1073 * reopening and re-locking the file will fail, protecting us from multiple
1074 * processes running accidentally.
1075 */
1076 if (!writepid(pidfile))
1077 exit(1);
1078
1079 log_dest = orig_log_dest;
1080
1081 /* log these only to the final log, after stderr is closed, so that
1082 * a normal, successful startup does not print out informative stuff
1083 * on the console
1084 */
1085 if (have_low_ports)
1086 hlog(LOG_INFO, "POSIX capabilities available: can bind low ports");
1087
1088 hlog(LOG_INFO, "After configuration FileLimit is %d, MaxClients is %d, xpoll using %s",
1089 fileno_limit, maxclients, xpoll_implementation);
1090
1091 /* validate maxclients vs fileno_limit, now when it's determined */
1092 if (fileno_limit < maxclients + 50) {
1093 hlog(LOG_ERR, "FileLimit is smaller than MaxClients + 50: Server may run out of file descriptors and break badly");
1094 }
1095
1096 /* catch signals */
1097 signal(SIGINT, (void *)sighandler);
1098 signal(SIGTERM, (void *)sighandler);
1099 signal(SIGQUIT, (void *)sighandler);
1100 signal(SIGHUP, (void *)sighandler);
1101 signal(SIGUSR1, (void *)sighandler);
1102 signal(SIGUSR2, (void *)sighandler);
1103 signal(SIGPIPE, SIG_IGN);
1104 signal(SIGURG, SIG_IGN);
1105
1106 /* Early inits in single-thread mode */
1107 keyhash_init();
1108 filter_init();
1109 pbuf_init();
1110 dupecheck_init();
1111 historydb_init();
1112 client_heard_init();
1113 client_init();
1114 xpoll_init();
1115 status_init();
1116 ssl_init();
1117
1118 /* if live upgrading, load status file and database dumps */
1119 if (liveupgrade_startup) {
1120 dbload_all();
1121 /* historydb must be loaded before applying filters, so do dbload_all first */
1122 status_read_liveupgrade();
1123 }
1124
1125 pthread_attr_init(&pthr_attrs);
1126 /* 128 kB stack is enough for each thread,
1127 default of 10 MB is way too much...*/
1128 pthread_attr_setstacksize(&pthr_attrs, 128*1024);
1129
1130 /* start the time thread, which will update the current time */
1131 if (pthread_create(&time_th, &pthr_attrs, (void *)time_thread, NULL))
1132 perror("pthread_create failed for time_thread");
1133
1134 /* start the accept thread, which will start server threads */
1135 if (pthread_create(&accept_th, &pthr_attrs, (void *)accept_thread, NULL))
1136 perror("pthread_create failed for accept_thread");
1137
1138 /* start the HTTP thread, which runs libevent's HTTP server */
1139 if (pthread_create(&http_th, &pthr_attrs, (void *)http_thread, NULL))
1140 perror("pthread_create failed for http_thread");
1141
1142 /* act as statistics and housekeeping thread from now on */
1143 while (!shutting_down) {
1144 if (poll(NULL, 0, 300) == -1 && errno != EINTR)
1145 hlog(LOG_WARNING, "main: poll sleep failed: %s", strerror(errno));
1146
1147 if (want_dbdump) {
1148 dbdump_all();
1149 want_dbdump = 0;
1150 }
1151
1152 if (reopen_logs) {
1153 reopen_logs = 0;
1154 close_log(1);
1155 }
1156
1157
1158 if (reconfiguring) {
1159 reconfiguring = 0;
1160 if (read_config()) {
1161 hlog(LOG_ERR, "New configuration was not successfully read.");
1162 } else {
1163 hlog(LOG_INFO, "New configuration read successfully. Applying....");
1164 accept_reconfiguring = 1;
1165 http_reconfiguring = 1;
1166 }
1167 }
1168
1169 if (cleanup_tick < tick || cleanup_tick > tick + 80) {
1170 cleanup_tick = tick + 60;
1171
1172 status_dump_file();
1173 historydb_cleanup();
1174 filter_wx_cleanup();
1175 filter_entrycall_cleanup();
1176 }
1177
1178 if (version_tick < tick || version_tick > tick + 86500) {
1179 version_tick = tick + 86400;
1180 version_report("run");
1181 }
1182 }
1183
1184 if (liveupgrade_fired)
1185 hlog(LOG_INFO, "Shutdown for LIVE UPGRADE!");
1186
1187 hlog(LOG_INFO, "Signalling threads to shut down...");
1188 accept_shutting_down = (liveupgrade_fired) ? 2 : 1;
1189
1190 if ((e = pthread_join(http_th, NULL)))
1191 hlog(LOG_ERR, "Could not pthread_join http_th: %s", strerror(e));
1192 else
1193 hlog(LOG_INFO, "HTTP thread has terminated.");
1194
1195 if ((e = pthread_join(accept_th, NULL)))
1196 hlog(LOG_ERR, "Could not pthread_join accept_th: %s", strerror(e));
1197 else
1198 hlog(LOG_INFO, "Accept thread has terminated.");
1199
1200 if ((e = pthread_join(time_th, NULL)))
1201 hlog(LOG_ERR, "Could not pthread_join time_th: %s", strerror(e));
1202
1203 if (dbdump_at_exit) {
1204 dbdump_all();
1205 }
1206
1207 if (liveupgrade_fired) {
1208 hlog(LOG_INFO, "Live upgrade: Dumping state to files...");
1209 if (dbdump_historydb() || status_dump_liveupgrade()) {
1210 hlog(LOG_ERR, "Live upgrade: Dumps failed - cannot continue!");
1211 return 1;
1212 }
1213 hlog(LOG_INFO, "Live upgrade: Dumps completed.");
1214 liveupgrade_exec(argc, argv);
1215 }
1216
1217 free_config();
1218 dupecheck_atend();
1219 historydb_atend();
1220 filter_wx_atend();
1221 filter_entrycall_atend();
1222 status_atend();
1223 ssl_atend();
1224
1225 hlog(LOG_NOTICE, "Shut down.");
1226 close_log(0);
1227
1228 return 0;
1229 }
1230
1231