1 /*
2 * BIRD Internet Routing Daemon -- Unix Entry Point
3 *
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 #undef LOCAL_DEBUG
10
11 #ifndef _GNU_SOURCE
12 #define _GNU_SOURCE
13 #endif
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <signal.h>
20 #include <pwd.h>
21 #include <grp.h>
22 #include <sys/stat.h>
23 #include <libgen.h>
24
25 #include "nest/bird.h"
26 #include "lib/lists.h"
27 #include "lib/resource.h"
28 #include "lib/socket.h"
29 #include "lib/event.h"
30 #include "lib/string.h"
31 #include "nest/route.h"
32 #include "nest/protocol.h"
33 #include "nest/iface.h"
34 #include "nest/cli.h"
35 #include "nest/locks.h"
36 #include "conf/conf.h"
37 #include "filter/filter.h"
38
39 #include "unix.h"
40 #include "krt.h"
41
42 /*
43 * Debugging
44 */
45
46 #ifdef DEBUGGING
47 static int debug_flag = 1;
48 #else
49 static int debug_flag = 0;
50 #endif
51
52 void
async_dump(void)53 async_dump(void)
54 {
55 debug("INTERNAL STATE DUMP\n\n");
56
57 rdump(&root_pool);
58 sk_dump_all();
59 tm_dump_all();
60 if_dump_all();
61 neigh_dump_all();
62 rta_dump_all();
63 rt_dump_all();
64 protos_dump_all();
65
66 debug("\n");
67 }
68
69 /*
70 * Dropping privileges
71 */
72
73 #ifdef CONFIG_RESTRICTED_PRIVILEGES
74 #include "lib/syspriv.h"
75 #else
76
77 static inline void
drop_uid(uid_t uid UNUSED)78 drop_uid(uid_t uid UNUSED)
79 {
80 die("Cannot change user on this platform");
81 }
82
83 #endif
84
85 static inline void
drop_gid(gid_t gid)86 drop_gid(gid_t gid)
87 {
88 if (setgid(gid) < 0)
89 die("setgid: %m");
90
91 if (setgroups(0, NULL) < 0)
92 die("setgroups: %m");
93 }
94
95 /*
96 * Reading the Configuration
97 */
98
99 #ifdef PATH_IPROUTE_DIR
100
101 static inline void
add_num_const(char * name,int val)102 add_num_const(char *name, int val)
103 {
104 struct symbol *s = cf_get_symbol(name);
105 s->class = SYM_CONSTANT | T_INT;
106 s->def = cfg_allocz(sizeof(struct f_val));
107 SYM_TYPE(s) = T_INT;
108 SYM_VAL(s).i = val;
109 }
110
111 /* the code of read_iproute_table() is based on
112 rtnl_tab_initialize() from iproute2 package */
113 static void
read_iproute_table(char * file,char * prefix,int max)114 read_iproute_table(char *file, char *prefix, int max)
115 {
116 char buf[512], namebuf[512];
117 char *name;
118 int val;
119 FILE *fp;
120
121 strcpy(namebuf, prefix);
122 name = namebuf + strlen(prefix);
123
124 fp = fopen(file, "r");
125 if (!fp)
126 return;
127
128 while (fgets(buf, sizeof(buf), fp))
129 {
130 char *p = buf;
131
132 while (*p == ' ' || *p == '\t')
133 p++;
134
135 if (*p == '#' || *p == '\n' || *p == 0)
136 continue;
137
138 if (sscanf(p, "0x%x %s\n", &val, name) != 2 &&
139 sscanf(p, "0x%x %s #", &val, name) != 2 &&
140 sscanf(p, "%d %s\n", &val, name) != 2 &&
141 sscanf(p, "%d %s #", &val, name) != 2)
142 continue;
143
144 if (val < 0 || val > max)
145 continue;
146
147 for(p = name; *p; p++)
148 if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_'))
149 *p = '_';
150
151 add_num_const(namebuf, val);
152 }
153
154 fclose(fp);
155 }
156
157 #endif // PATH_IPROUTE_DIR
158
159
160 static char *config_name = PATH_CONFIG_FILE;
161
162 static int
cf_read(byte * dest,uint len,int fd)163 cf_read(byte *dest, uint len, int fd)
164 {
165 int l = read(fd, dest, len);
166 if (l < 0)
167 cf_error("Read error");
168 return l;
169 }
170
171 void
sysdep_preconfig(struct config * c)172 sysdep_preconfig(struct config *c)
173 {
174 init_list(&c->logfiles);
175
176 c->latency_limit = UNIX_DEFAULT_LATENCY_LIMIT;
177 c->watchdog_warning = UNIX_DEFAULT_WATCHDOG_WARNING;
178
179 #ifdef PATH_IPROUTE_DIR
180 read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256);
181 read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256);
182 read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256);
183 read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256);
184 #endif
185 }
186
187 int
sysdep_commit(struct config * new,struct config * old UNUSED)188 sysdep_commit(struct config *new, struct config *old UNUSED)
189 {
190 log_switch(debug_flag, &new->logfiles, new->syslog_name);
191 return 0;
192 }
193
194 static int
unix_read_config(struct config ** cp,char * name)195 unix_read_config(struct config **cp, char *name)
196 {
197 struct config *conf = config_alloc(name);
198 int ret;
199
200 *cp = conf;
201 conf->file_fd = open(name, O_RDONLY);
202 if (conf->file_fd < 0)
203 return 0;
204 cf_read_hook = cf_read;
205 ret = config_parse(conf);
206 close(conf->file_fd);
207 return ret;
208 }
209
210 static struct config *
read_config(void)211 read_config(void)
212 {
213 struct config *conf;
214
215 if (!unix_read_config(&conf, config_name))
216 {
217 if (conf->err_msg)
218 die("%s:%d:%d %s", conf->err_file_name, conf->err_lino, conf->err_chno, conf->err_msg);
219 else
220 die("Unable to open configuration file %s: %m", config_name);
221 }
222
223 return conf;
224 }
225
226 void
async_config(void)227 async_config(void)
228 {
229 struct config *conf;
230
231 log(L_INFO "Reconfiguration requested by SIGHUP");
232 if (!unix_read_config(&conf, config_name))
233 {
234 if (conf->err_msg)
235 log(L_ERR "%s:%d:%d %s", conf->err_file_name, conf->err_lino, conf->err_chno, conf->err_msg);
236 else
237 log(L_ERR "Unable to open configuration file %s: %m", config_name);
238 config_free(conf);
239 }
240 else
241 config_commit(conf, RECONFIG_HARD, 0);
242 }
243
244 static struct config *
cmd_read_config(char * name)245 cmd_read_config(char *name)
246 {
247 struct config *conf;
248
249 if (!name)
250 name = config_name;
251
252 cli_msg(-2, "Reading configuration from %s", name);
253 if (!unix_read_config(&conf, name))
254 {
255 if (conf->err_msg)
256 cli_msg(8002, "%s:%d:%d %s", conf->err_file_name, conf->err_lino, conf->err_chno, conf->err_msg);
257 else
258 cli_msg(8002, "%s: %m", name);
259 config_free(conf);
260 conf = NULL;
261 }
262
263 return conf;
264 }
265
266 void
cmd_check_config(char * name)267 cmd_check_config(char *name)
268 {
269 struct config *conf = cmd_read_config(name);
270 if (!conf)
271 return;
272
273 cli_msg(20, "Configuration OK");
274 config_free(conf);
275 }
276
277 static void
cmd_reconfig_msg(int r)278 cmd_reconfig_msg(int r)
279 {
280 switch (r)
281 {
282 case CONF_DONE: cli_msg( 3, "Reconfigured"); break;
283 case CONF_PROGRESS: cli_msg( 4, "Reconfiguration in progress"); break;
284 case CONF_QUEUED: cli_msg( 5, "Reconfiguration already in progress, queueing new config"); break;
285 case CONF_UNQUEUED: cli_msg(17, "Reconfiguration already in progress, removing queued config"); break;
286 case CONF_CONFIRM: cli_msg(18, "Reconfiguration confirmed"); break;
287 case CONF_SHUTDOWN: cli_msg( 6, "Reconfiguration ignored, shutting down"); break;
288 case CONF_NOTHING: cli_msg(19, "Nothing to do"); break;
289 default: break;
290 }
291 }
292
293 /* Hack for scheduled undo notification */
294 cli *cmd_reconfig_stored_cli;
295
296 void
cmd_reconfig_undo_notify(void)297 cmd_reconfig_undo_notify(void)
298 {
299 if (cmd_reconfig_stored_cli)
300 {
301 cli *c = cmd_reconfig_stored_cli;
302 cli_printf(c, CLI_ASYNC_CODE, "Config timeout expired, starting undo");
303 cli_write_trigger(c);
304 }
305 }
306
307 void
cmd_reconfig(char * name,int type,int timeout)308 cmd_reconfig(char *name, int type, int timeout)
309 {
310 if (cli_access_restricted())
311 return;
312
313 struct config *conf = cmd_read_config(name);
314 if (!conf)
315 return;
316
317 int r = config_commit(conf, type, timeout);
318
319 if ((r >= 0) && (timeout > 0))
320 {
321 cmd_reconfig_stored_cli = this_cli;
322 cli_msg(-22, "Undo scheduled in %d s", timeout);
323 }
324
325 cmd_reconfig_msg(r);
326 }
327
328 void
cmd_reconfig_confirm(void)329 cmd_reconfig_confirm(void)
330 {
331 if (cli_access_restricted())
332 return;
333
334 int r = config_confirm();
335 cmd_reconfig_msg(r);
336 }
337
338 void
cmd_reconfig_undo(void)339 cmd_reconfig_undo(void)
340 {
341 if (cli_access_restricted())
342 return;
343
344 cli_msg(-21, "Undo requested");
345
346 int r = config_undo();
347 cmd_reconfig_msg(r);
348 }
349
350 /*
351 * Command-Line Interface
352 */
353
354 static sock *cli_sk;
355 static char *path_control_socket = PATH_CONTROL_SOCKET;
356
357
358 static void
cli_write(cli * c)359 cli_write(cli *c)
360 {
361 sock *s = c->priv;
362
363 while (c->tx_pos)
364 {
365 struct cli_out *o = c->tx_pos;
366
367 int len = o->wpos - o->outpos;
368 s->tbuf = o->outpos;
369 o->outpos = o->wpos;
370
371 if (sk_send(s, len) <= 0)
372 return;
373
374 c->tx_pos = o->next;
375 }
376
377 /* Everything is written */
378 s->tbuf = NULL;
379 cli_written(c);
380 }
381
382 void
cli_write_trigger(cli * c)383 cli_write_trigger(cli *c)
384 {
385 sock *s = c->priv;
386
387 if (s->tbuf == NULL)
388 cli_write(c);
389 }
390
391 static void
cli_tx(sock * s)392 cli_tx(sock *s)
393 {
394 cli_write(s->data);
395 }
396
397 int
cli_get_command(cli * c)398 cli_get_command(cli *c)
399 {
400 sock *s = c->priv;
401 byte *t = c->rx_aux ? : s->rbuf;
402 byte *tend = s->rpos;
403 byte *d = c->rx_pos;
404 byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
405
406 while (t < tend)
407 {
408 if (*t == '\r')
409 t++;
410 else if (*t == '\n')
411 {
412 t++;
413 c->rx_pos = c->rx_buf;
414 c->rx_aux = t;
415 *d = 0;
416 return (d < dend) ? 1 : -1;
417 }
418 else if (d < dend)
419 *d++ = *t++;
420 }
421 c->rx_aux = s->rpos = s->rbuf;
422 c->rx_pos = d;
423 return 0;
424 }
425
426 static int
cli_rx(sock * s,uint size UNUSED)427 cli_rx(sock *s, uint size UNUSED)
428 {
429 cli_kick(s->data);
430 return 0;
431 }
432
433 static void
cli_err(sock * s,int err)434 cli_err(sock *s, int err)
435 {
436 if (config->cli_debug)
437 {
438 if (err)
439 log(L_INFO "CLI connection dropped: %s", strerror(err));
440 else
441 log(L_INFO "CLI connection closed");
442 }
443 cli_free(s->data);
444 }
445
446 static int
cli_connect(sock * s,uint size UNUSED)447 cli_connect(sock *s, uint size UNUSED)
448 {
449 cli *c;
450
451 if (config->cli_debug)
452 log(L_INFO "CLI connect");
453 s->rx_hook = cli_rx;
454 s->tx_hook = cli_tx;
455 s->err_hook = cli_err;
456 s->data = c = cli_new(s);
457 s->pool = c->pool; /* We need to have all the socket buffers allocated in the cli pool */
458 s->fast_rx = 1;
459 c->rx_pos = c->rx_buf;
460 c->rx_aux = NULL;
461 rmove(s, c->pool);
462 return 1;
463 }
464
465 static void
cli_init_unix(uid_t use_uid,gid_t use_gid)466 cli_init_unix(uid_t use_uid, gid_t use_gid)
467 {
468 sock *s;
469
470 cli_init();
471 s = cli_sk = sk_new(cli_pool);
472 s->type = SK_UNIX_PASSIVE;
473 s->rx_hook = cli_connect;
474 s->rbsize = 1024;
475 s->fast_rx = 1;
476
477 /* Return value intentionally ignored */
478 unlink(path_control_socket);
479
480 if (sk_open_unix(s, path_control_socket) < 0)
481 die("Cannot create control socket %s: %m", path_control_socket);
482
483 if (use_uid || use_gid)
484 if (chown(path_control_socket, use_uid, use_gid) < 0)
485 die("chown: %m");
486
487 if (chmod(path_control_socket, 0660) < 0)
488 die("chmod: %m");
489 }
490
491 /*
492 * PID file
493 */
494
495 static char *pid_file;
496 static int pid_fd;
497
498 static inline void
open_pid_file(void)499 open_pid_file(void)
500 {
501 if (!pid_file)
502 return;
503
504 pid_fd = open(pid_file, O_WRONLY|O_CREAT, 0664);
505 if (pid_fd < 0)
506 die("Cannot create PID file %s: %m", pid_file);
507 }
508
509 static inline void
write_pid_file(void)510 write_pid_file(void)
511 {
512 int pl, rv;
513 char ps[24];
514
515 if (!pid_file)
516 return;
517
518 /* We don't use PID file for uniqueness, so no need for locking */
519
520 pl = bsnprintf(ps, sizeof(ps), "%ld\n", (long) getpid());
521 if (pl < 0)
522 bug("PID buffer too small");
523
524 rv = ftruncate(pid_fd, 0);
525 if (rv < 0)
526 die("fruncate: %m");
527
528 rv = write(pid_fd, ps, pl);
529 if(rv < 0)
530 die("write: %m");
531
532 close(pid_fd);
533 }
534
535 static inline void
unlink_pid_file(void)536 unlink_pid_file(void)
537 {
538 if (pid_file)
539 unlink(pid_file);
540 }
541
542
543 /*
544 * Shutdown
545 */
546
547 void
cmd_shutdown(void)548 cmd_shutdown(void)
549 {
550 if (cli_access_restricted())
551 return;
552
553 cli_msg(7, "Shutdown requested");
554 order_shutdown();
555 }
556
557 void
async_shutdown(void)558 async_shutdown(void)
559 {
560 DBG("Shutting down...\n");
561 order_shutdown();
562 }
563
564 void
sysdep_shutdown_done(void)565 sysdep_shutdown_done(void)
566 {
567 unlink_pid_file();
568 unlink(path_control_socket);
569 log_msg(L_FATAL "Shutdown completed");
570 exit(0);
571 }
572
573 /*
574 * Signals
575 */
576
577 static void
handle_sighup(int sig UNUSED)578 handle_sighup(int sig UNUSED)
579 {
580 DBG("Caught SIGHUP...\n");
581 async_config_flag = 1;
582 }
583
584 static void
handle_sigusr(int sig UNUSED)585 handle_sigusr(int sig UNUSED)
586 {
587 DBG("Caught SIGUSR...\n");
588 async_dump_flag = 1;
589 }
590
591 static void
handle_sigterm(int sig UNUSED)592 handle_sigterm(int sig UNUSED)
593 {
594 DBG("Caught SIGTERM...\n");
595 async_shutdown_flag = 1;
596 }
597
598 void watchdog_sigalrm(int sig UNUSED);
599
600 static void
signal_init(void)601 signal_init(void)
602 {
603 struct sigaction sa;
604
605 bzero(&sa, sizeof(sa));
606 sa.sa_handler = handle_sigusr;
607 sa.sa_flags = SA_RESTART;
608 sigaction(SIGUSR1, &sa, NULL);
609 sa.sa_handler = handle_sighup;
610 sa.sa_flags = SA_RESTART;
611 sigaction(SIGHUP, &sa, NULL);
612 sa.sa_handler = handle_sigterm;
613 sa.sa_flags = SA_RESTART;
614 sigaction(SIGTERM, &sa, NULL);
615 sa.sa_handler = watchdog_sigalrm;
616 sa.sa_flags = 0;
617 sigaction(SIGALRM, &sa, NULL);
618 signal(SIGPIPE, SIG_IGN);
619 }
620
621 /*
622 * Parsing of command-line arguments
623 */
624
625 static char *opt_list = "c:dD:ps:P:u:g:flRh";
626 static int parse_and_exit;
627 char *bird_name;
628 static char *use_user;
629 static char *use_group;
630 static int run_in_foreground = 0;
631
632 static void
display_usage(void)633 display_usage(void)
634 {
635 fprintf(stderr, "Usage: %s [--version] [--help] [-c <config-file>] [OPTIONS]\n", bird_name);
636 }
637
638 static void
display_help(void)639 display_help(void)
640 {
641 display_usage();
642
643 fprintf(stderr,
644 "\n"
645 "Options: \n"
646 " -c <config-file> Use given configuration file instead\n"
647 " of prefix/etc/bird.conf\n"
648 " -d Enable debug messages and run bird in foreground\n"
649 " -D <debug-file> Log debug messages to given file instead of stderr\n"
650 " -f Run bird in foreground\n"
651 " -g <group> Use given group ID\n"
652 " -h, --help Display this information\n"
653 " -l Look for a configuration file and a communication socket\n"
654 " file in the current working directory\n"
655 " -p Test configuration file and exit without start\n"
656 " -P <pid-file> Create a PID file with given filename\n"
657 " -R Apply graceful restart recovery after start\n"
658 " -s <control-socket> Use given filename for a control socket\n"
659 " -u <user> Drop privileges and use given user ID\n"
660 " --version Display version of BIRD\n");
661
662 exit(0);
663 }
664
665 static void
display_version(void)666 display_version(void)
667 {
668 fprintf(stderr, "BIRD version " BIRD_VERSION "\n");
669 exit(0);
670 }
671
672 static inline char *
get_bird_name(char * s,char * def)673 get_bird_name(char *s, char *def)
674 {
675 char *t;
676 if (!s)
677 return def;
678 t = strrchr(s, '/');
679 if (!t)
680 return s;
681 if (!t[1])
682 return def;
683 return t+1;
684 }
685
686 static inline uid_t
get_uid(const char * s)687 get_uid(const char *s)
688 {
689 struct passwd *pw;
690 char *endptr;
691 long int rv;
692
693 if (!s)
694 return 0;
695
696 errno = 0;
697 rv = strtol(s, &endptr, 10);
698
699 if (!errno && !*endptr)
700 return rv;
701
702 pw = getpwnam(s);
703 if (!pw)
704 die("Cannot find user '%s'", s);
705
706 return pw->pw_uid;
707 }
708
709 static inline gid_t
get_gid(const char * s)710 get_gid(const char *s)
711 {
712 struct group *gr;
713 char *endptr;
714 long int rv;
715
716 if (!s)
717 return 0;
718
719 errno = 0;
720 rv = strtol(s, &endptr, 10);
721
722 if (!errno && !*endptr)
723 return rv;
724
725 gr = getgrnam(s);
726 if (!gr)
727 die("Cannot find group '%s'", s);
728
729 return gr->gr_gid;
730 }
731
732 static void
parse_args(int argc,char ** argv)733 parse_args(int argc, char **argv)
734 {
735 int config_changed = 0;
736 int socket_changed = 0;
737 int c;
738
739 bird_name = get_bird_name(argv[0], "bird");
740 if (argc == 2)
741 {
742 if (!strcmp(argv[1], "--version"))
743 display_version();
744 if (!strcmp(argv[1], "--help"))
745 display_help();
746 }
747 while ((c = getopt(argc, argv, opt_list)) >= 0)
748 switch (c)
749 {
750 case 'c':
751 config_name = optarg;
752 config_changed = 1;
753 break;
754 case 'd':
755 debug_flag |= 1;
756 break;
757 case 'D':
758 log_init_debug(optarg);
759 debug_flag |= 2;
760 break;
761 case 'p':
762 parse_and_exit = 1;
763 break;
764 case 's':
765 path_control_socket = optarg;
766 socket_changed = 1;
767 break;
768 case 'P':
769 pid_file = optarg;
770 break;
771 case 'u':
772 use_user = optarg;
773 break;
774 case 'g':
775 use_group = optarg;
776 break;
777 case 'f':
778 run_in_foreground = 1;
779 break;
780 case 'l':
781 if (!config_changed)
782 config_name = xbasename(config_name);
783 if (!socket_changed)
784 path_control_socket = xbasename(path_control_socket);
785 break;
786 case 'R':
787 graceful_restart_recovery();
788 break;
789 case 'h':
790 display_help();
791 break;
792 default:
793 fputc('\n', stderr);
794 display_usage();
795 exit(1);
796 }
797 if (optind < argc)
798 {
799 display_usage();
800 exit(1);
801 }
802 }
803
804 /*
805 * Hic Est main()
806 */
807
808 int
main(int argc,char ** argv)809 main(int argc, char **argv)
810 {
811 #ifdef HAVE_LIBDMALLOC
812 if (!getenv("DMALLOC_OPTIONS"))
813 dmalloc_debug(0x2f03d00);
814 #endif
815
816 parse_args(argc, argv);
817 if (debug_flag == 1)
818 log_init_debug("");
819 log_switch(debug_flag, NULL, NULL);
820
821 resource_init();
822 olock_init();
823 io_init();
824 rt_init();
825 if_init();
826 roa_init();
827 config_init();
828
829 uid_t use_uid = get_uid(use_user);
830 gid_t use_gid = get_gid(use_group);
831
832 if (!parse_and_exit)
833 {
834 test_old_bird(path_control_socket);
835 cli_init_unix(use_uid, use_gid);
836 }
837
838 if (use_gid)
839 drop_gid(use_gid);
840
841 if (use_uid)
842 drop_uid(use_uid);
843
844 if (!parse_and_exit)
845 open_pid_file();
846
847 protos_build();
848 proto_build(&proto_unix_kernel);
849 proto_build(&proto_unix_iface);
850
851 struct config *conf = read_config();
852
853 if (parse_and_exit)
854 exit(0);
855
856 if (!(debug_flag||run_in_foreground))
857 {
858 pid_t pid = fork();
859 if (pid < 0)
860 die("fork: %m");
861 if (pid)
862 return 0;
863 setsid();
864 close(0);
865 if (open("/dev/null", O_RDWR) < 0)
866 die("Cannot open /dev/null: %m");
867 dup2(0, 1);
868 dup2(0, 2);
869 }
870
871 main_thread_init();
872
873 write_pid_file();
874
875 signal_init();
876
877 config_commit(conf, RECONFIG_HARD, 0);
878
879 graceful_restart_init();
880
881 #ifdef LOCAL_DEBUG
882 async_dump_flag = 1;
883 #endif
884
885 log(L_INFO "Started");
886 DBG("Entering I/O loop.\n");
887
888 io_loop();
889 bug("I/O loop died");
890 }
891