Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / unix / main.c @ ab188fb7

History | View | Annotate | Download (11.8 KB)

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
#define _GNU_SOURCE 1
12

    
13
#include <stdio.h>
14
#include <stdlib.h>
15
#include <fcntl.h>
16
#include <unistd.h>
17
#include <signal.h>
18
#include <pwd.h>
19
#include <grp.h>
20
#include <sys/stat.h>
21
#include <libgen.h>
22

    
23
#include "nest/bird.h"
24
#include "lib/lists.h"
25
#include "lib/resource.h"
26
#include "lib/socket.h"
27
#include "lib/event.h"
28
#include "lib/string.h"
29
#include "nest/route.h"
30
#include "nest/protocol.h"
31
#include "nest/iface.h"
32
#include "nest/cli.h"
33
#include "nest/locks.h"
34
#include "conf/conf.h"
35
#include "filter/filter.h"
36

    
37
#include "unix.h"
38
#include "krt.h"
39

    
40
/*
41
 *        Debugging
42
 */
43

    
44
#ifdef DEBUGGING
45
static int debug_flag = 1;
46
#else
47
static int debug_flag = 0;
48
#endif
49

    
50
void
51
async_dump(void)
52
{
53
  debug("INTERNAL STATE DUMP\n\n");
54

    
55
  rdump(&root_pool);
56
  sk_dump_all();
57
  tm_dump_all();
58
  if_dump_all();
59
  neigh_dump_all();
60
  rta_dump_all();
61
  rt_dump_all();
62
  protos_dump_all();
63

    
64
  debug("\n");
65
}
66

    
67
/*
68
 *        Dropping privileges
69
 */
70

    
71
#ifdef CONFIG_RESTRICTED_PRIVILEGES
72
#include "lib/syspriv.h"
73
#else
74

    
75
static inline void
76
drop_uid(uid_t uid)
77
{
78
  die("Cannot change user on this platform");
79
}
80

    
81
#endif
82

    
83
static inline void
84
drop_gid(gid_t gid)
85
{
86
  if (setgid(gid) < 0)
87
    die("setgid: %m");
88
}
89

    
90
/*
91
 *        Reading the Configuration
92
 */
93

    
94
#ifdef PATH_IPROUTE_DIR
95

    
96
static inline void
97
add_num_const(char *name, int val)
98
{
99
  struct symbol *s = cf_find_symbol(name);
100
  s->class = SYM_NUMBER;
101
  s->def = NULL;
102
  s->aux = val;
103
}
104

    
105
/* the code of read_iproute_table() is based on
106
   rtnl_tab_initialize() from iproute2 package */
107
static void
108
read_iproute_table(char *file, char *prefix, int max)
109
{
110
  char buf[512], namebuf[512];
111
  char *name;
112
  int val;
113
  FILE *fp;
114

    
115
  strcpy(namebuf, prefix);
116
  name = namebuf + strlen(prefix);
117

    
118
  fp = fopen(file, "r");
119
  if (!fp)
120
    return;
121

    
122
  while (fgets(buf, sizeof(buf), fp))
123
  {
124
    char *p = buf;
125

    
126
    while (*p == ' ' || *p == '\t')
127
      p++;
128

    
129
    if (*p == '#' || *p == '\n' || *p == 0)
130
      continue;
131
   
132
    if (sscanf(p, "0x%x %s\n", &val, name) != 2 &&
133
        sscanf(p, "0x%x %s #", &val, name) != 2 &&
134
        sscanf(p, "%d %s\n", &val, name) != 2 &&
135
        sscanf(p, "%d %s #", &val, name) != 2)
136
      continue;
137

    
138
    if (val < 0 || val > max)
139
      continue;
140

    
141
    for(p = name; *p; p++)
142
      if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_'))
143
        *p = '_';
144

    
145
    add_num_const(namebuf, val);
146
  }
147

    
148
  fclose(fp);
149
}
150

    
151
#endif // PATH_IPROUTE_DIR
152

    
153

    
154
static char *config_name = PATH_CONFIG_FILE;
155

    
156
static int
157
cf_read(byte *dest, unsigned int len, int fd)
158
{
159
  int l = read(fd, dest, len);
160
  if (l < 0)
161
    cf_error("Read error");
162
  return l;
163
}
164

    
165
static int
166
cf_open(char *filename)
167
{
168
  char full_name[BIRD_FNAME_MAX];
169
  char *cur = filename;
170
  int ret;
171

    
172
  if (*filename != '/') {
173
    char dir[BIRD_FNAME_MAX];
174
    strncpy(dir, config_name, sizeof(dir));
175
    dir[sizeof(dir)-1] = 0;
176
    snprintf(full_name, sizeof(full_name), "%s/%s", dirname(dir), filename);
177
    full_name[sizeof(full_name)-1] = 0;
178
    cur = full_name;
179
  }
180

    
181
  if ((ret = open(cur, O_RDONLY)) == -1)
182
    cf_error("Unable to open included configuration file: %s", cur);
183

    
184
  return ret;
185
}
186

    
187

    
188
void
189
sysdep_preconfig(struct config *c)
190
{
191
  init_list(&c->logfiles);
192

    
193
#ifdef PATH_IPROUTE_DIR
194
  read_iproute_table(PATH_IPROUTE_DIR "/rt_protos", "ipp_", 256);
195
  read_iproute_table(PATH_IPROUTE_DIR "/rt_realms", "ipr_", 256);
196
  read_iproute_table(PATH_IPROUTE_DIR "/rt_scopes", "ips_", 256);
197
  read_iproute_table(PATH_IPROUTE_DIR "/rt_tables", "ipt_", 256);
198
#endif
199
}
200

    
201
int
202
sysdep_commit(struct config *new, struct config *old UNUSED)
203
{
204
  log_switch(debug_flag, &new->logfiles, new->syslog_name);
205
  return 0;
206
}
207

    
208
static int
209
unix_read_config(struct config **cp, char *name)
210
{
211
  struct config *conf = config_alloc(name);
212
  int ret;
213

    
214
  *cp = conf;
215
  conf->file_fd = open(name, O_RDONLY);
216
  if (conf->file_fd < 0)
217
    return 0;
218
  cf_read_hook = cf_read;
219
  cf_open_hook = cf_open;
220
  ret = config_parse(conf);
221
  close(conf->file_fd);
222
  return ret;
223
}
224

    
225
static void
226
read_config(void)
227
{
228
  struct config *conf;
229

    
230
  if (!unix_read_config(&conf, config_name))
231
    {
232
      if (conf->err_msg)
233
        die("%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
234
      else
235
        die("Unable to open configuration file %s: %m", config_name);
236
    }
237
  config_commit(conf, RECONFIG_HARD);
238
}
239

    
240
void
241
async_config(void)
242
{
243
  struct config *conf;
244

    
245
  log(L_INFO "Reconfiguration requested by SIGHUP");
246
  if (!unix_read_config(&conf, config_name))
247
    {
248
      if (conf->err_msg)
249
        log(L_ERR "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
250
      else
251
        log(L_ERR "Unable to open configuration file %s: %m", config_name);
252
      config_free(conf);
253
    }
254
  else
255
    config_commit(conf, RECONFIG_HARD);
256
}
257

    
258
void
259
cmd_reconfig(char *name, int type)
260
{
261
  struct config *conf;
262

    
263
  if (cli_access_restricted())
264
    return;
265

    
266
  if (!name)
267
    name = config_name;
268
  cli_msg(-2, "Reading configuration from %s", name);
269
  if (!unix_read_config(&conf, name))
270
    {
271
      if (conf->err_msg)
272
        cli_msg(8002, "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
273
      else
274
        cli_msg(8002, "%s: %m", name);
275
      config_free(conf);
276
    }
277
  else
278
    {
279
      switch (config_commit(conf, type))
280
        {
281
        case CONF_DONE:
282
          cli_msg(3, "Reconfigured.");
283
          break;
284
        case CONF_PROGRESS:
285
          cli_msg(4, "Reconfiguration in progress.");
286
          break;
287
        case CONF_SHUTDOWN:
288
          cli_msg(6, "Reconfiguration ignored, shutting down.");
289
          break;
290
        default:
291
          cli_msg(5, "Reconfiguration already in progress, queueing new config");
292
        }
293
    }
294
}
295

    
296
/*
297
 *        Command-Line Interface
298
 */
299

    
300
static sock *cli_sk;
301
static char *path_control_socket = PATH_CONTROL_SOCKET;
302

    
303

    
304
static void
305
cli_write(cli *c)
306
{
307
  sock *s = c->priv;
308

    
309
  while (c->tx_pos)
310
    {
311
      struct cli_out *o = c->tx_pos;
312

    
313
      int len = o->wpos - o->outpos;
314
      s->tbuf = o->outpos;
315
      o->outpos = o->wpos;
316

    
317
      if (sk_send(s, len) <= 0)
318
        return;
319

    
320
      c->tx_pos = o->next;
321
    }
322

    
323
  /* Everything is written */
324
  s->tbuf = NULL;
325
  cli_written(c);
326
}
327

    
328
void
329
cli_write_trigger(cli *c)
330
{
331
  sock *s = c->priv;
332

    
333
  if (s->tbuf == NULL)
334
    cli_write(c);
335
}
336

    
337
static void
338
cli_tx(sock *s)
339
{
340
  cli_write(s->data);
341
}
342

    
343
int
344
cli_get_command(cli *c)
345
{
346
  sock *s = c->priv;
347
  byte *t = c->rx_aux ? : s->rbuf;
348
  byte *tend = s->rpos;
349
  byte *d = c->rx_pos;
350
  byte *dend = c->rx_buf + CLI_RX_BUF_SIZE - 2;
351

    
352
  while (t < tend)
353
    {
354
      if (*t == '\r')
355
        t++;
356
      else if (*t == '\n')
357
        {
358
          t++;
359
          c->rx_pos = c->rx_buf;
360
          c->rx_aux = t;
361
          *d = 0;
362
          return (d < dend) ? 1 : -1;
363
        }
364
      else if (d < dend)
365
        *d++ = *t++;
366
    }
367
  c->rx_aux = s->rpos = s->rbuf;
368
  c->rx_pos = d;
369
  return 0;
370
}
371

    
372
static int
373
cli_rx(sock *s, int size UNUSED)
374
{
375
  cli_kick(s->data);
376
  return 0;
377
}
378

    
379
static void
380
cli_err(sock *s, int err)
381
{
382
  if (config->cli_debug)
383
    {
384
      if (err)
385
        log(L_INFO "CLI connection dropped: %s", strerror(err));
386
      else
387
        log(L_INFO "CLI connection closed");
388
    }
389
  cli_free(s->data);
390
}
391

    
392
static int
393
cli_connect(sock *s, int size UNUSED)
394
{
395
  cli *c;
396

    
397
  if (config->cli_debug)
398
    log(L_INFO "CLI connect");
399
  s->rx_hook = cli_rx;
400
  s->tx_hook = cli_tx;
401
  s->err_hook = cli_err;
402
  s->data = c = cli_new(s);
403
  s->pool = c->pool;                /* We need to have all the socket buffers allocated in the cli pool */
404
  c->rx_pos = c->rx_buf;
405
  c->rx_aux = NULL;
406
  rmove(s, c->pool);
407
  return 1;
408
}
409

    
410
static void
411
cli_init_unix(uid_t use_uid, gid_t use_gid)
412
{
413
  sock *s;
414

    
415
  cli_init();
416
  s = cli_sk = sk_new(cli_pool);
417
  s->type = SK_UNIX_PASSIVE;
418
  s->rx_hook = cli_connect;
419
  s->rbsize = 1024;
420
  sk_open_unix(s, path_control_socket);
421

    
422
  if (use_uid || use_gid)
423
    if (chown(path_control_socket, use_uid, use_gid) < 0)
424
      die("chown: %m");
425

    
426
  if (chmod(path_control_socket, 0660) < 0)
427
    die("chmod: %m");
428
}
429

    
430
/*
431
 *        Shutdown
432
 */
433

    
434
void
435
cmd_shutdown(void)
436
{
437
  if (cli_access_restricted())
438
    return;
439

    
440
  cli_msg(7, "Shutdown requested");
441
  order_shutdown();
442
}
443

    
444
void
445
async_shutdown(void)
446
{
447
  DBG("Shutting down...\n");
448
  order_shutdown();
449
}
450

    
451
void
452
sysdep_shutdown_done(void)
453
{
454
  unlink(path_control_socket);
455
  log_msg(L_FATAL "Shutdown completed");
456
  exit(0);
457
}
458

    
459
/*
460
 *        Signals
461
 */
462

    
463
static void
464
handle_sighup(int sig UNUSED)
465
{
466
  DBG("Caught SIGHUP...\n");
467
  async_config_flag = 1;
468
}
469

    
470
static void
471
handle_sigusr(int sig UNUSED)
472
{
473
  DBG("Caught SIGUSR...\n");
474
  async_dump_flag = 1;
475
}
476

    
477
static void
478
handle_sigterm(int sig UNUSED)
479
{
480
  DBG("Caught SIGTERM...\n");
481
  async_shutdown_flag = 1;
482
}
483

    
484
static void
485
signal_init(void)
486
{
487
  struct sigaction sa;
488

    
489
  bzero(&sa, sizeof(sa));
490
  sa.sa_handler = handle_sigusr;
491
  sa.sa_flags = SA_RESTART;
492
  sigaction(SIGUSR1, &sa, NULL);
493
  sa.sa_handler = handle_sighup;
494
  sa.sa_flags = SA_RESTART;
495
  sigaction(SIGHUP, &sa, NULL);
496
  sa.sa_handler = handle_sigterm;
497
  sa.sa_flags = SA_RESTART;
498
  sigaction(SIGTERM, &sa, NULL);
499
  signal(SIGPIPE, SIG_IGN);
500
}
501

    
502
/*
503
 *        Parsing of command-line arguments
504
 */
505

    
506
static char *opt_list = "c:dD:ps:u:g:";
507
static int parse_and_exit;
508
char *bird_name;
509
static char *use_user;
510
static char *use_group;
511

    
512
static void
513
usage(void)
514
{
515
  fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-u <user>] [-g <group>]\n", bird_name);
516
  exit(1);
517
}
518

    
519
static inline char *
520
get_bird_name(char *s, char *def)
521
{
522
  char *t;
523
  if (!s)
524
    return def;
525
  t = strrchr(s, '/');
526
  if (!t)
527
    return s;
528
  if (!t[1])
529
    return def;
530
  return t+1;
531
}
532

    
533
static inline uid_t
534
get_uid(const char *s)
535
{
536
  struct passwd *pw;
537
  char *endptr;
538
  long int rv;
539

    
540
  if (!s)
541
    return 0;
542

    
543
  errno = 0;
544
  rv = strtol(s, &endptr, 10);
545

    
546
  if (!errno && !*endptr)
547
    return rv;
548

    
549
  pw = getpwnam(s);
550
  if (!pw)
551
    die("Cannot find user '%s'", s);
552

    
553
  return pw->pw_uid;
554
}
555

    
556
static inline gid_t
557
get_gid(const char *s)
558
{
559
  struct group *gr;
560
  char *endptr;
561
  long int rv;
562

    
563
  if (!s)
564
    return 0;
565
  
566
  errno = 0;
567
  rv = strtol(s, &endptr, 10);
568

    
569
  if (!errno && !*endptr)
570
    return rv;
571

    
572
  gr = getgrnam(s);
573
  if (!gr)
574
    die("Cannot find group '%s'", s);
575

    
576
  return gr->gr_gid;
577
}
578

    
579
static void
580
parse_args(int argc, char **argv)
581
{
582
  int c;
583

    
584
  bird_name = get_bird_name(argv[0], "bird");
585
  if (argc == 2)
586
    {
587
      if (!strcmp(argv[1], "--version"))
588
        {
589
          fprintf(stderr, "BIRD version " BIRD_VERSION "\n");
590
          exit(0);
591
        }
592
      if (!strcmp(argv[1], "--help"))
593
        usage();
594
    }
595
  while ((c = getopt(argc, argv, opt_list)) >= 0)
596
    switch (c)
597
      {
598
      case 'c':
599
        config_name = optarg;
600
        break;
601
      case 'd':
602
        debug_flag |= 1;
603
        break;
604
      case 'D':
605
        log_init_debug(optarg);
606
        debug_flag |= 2;
607
        break;
608
      case 'p':
609
        parse_and_exit = 1;
610
        break;
611
      case 's':
612
        path_control_socket = optarg;
613
        break;
614
      case 'u':
615
        use_user = optarg;
616
        break;
617
      case 'g':
618
        use_group = optarg;
619
        break;
620
      default:
621
        usage();
622
      }
623
  if (optind < argc)
624
    usage();
625
}
626

    
627
/*
628
 *        Hic Est main()
629
 */
630

    
631
int
632
main(int argc, char **argv)
633
{
634
#ifdef HAVE_LIBDMALLOC
635
  if (!getenv("DMALLOC_OPTIONS"))
636
    dmalloc_debug(0x2f03d00);
637
#endif
638

    
639
  parse_args(argc, argv);
640
  if (debug_flag == 1)
641
    log_init_debug("");
642
  log_switch(debug_flag, NULL, NULL);
643

    
644
  resource_init();
645
  olock_init();
646
  io_init();
647
  rt_init();
648
  if_init();
649
  roa_init();
650

    
651
  uid_t use_uid = get_uid(use_user);
652
  gid_t use_gid = get_gid(use_group);
653

    
654
  if (!parse_and_exit)
655
  {
656
    test_old_bird(path_control_socket);
657
    cli_init_unix(use_uid, use_gid);
658
  }
659

    
660
  if (use_gid)
661
    drop_gid(use_gid);
662

    
663
  if (use_uid)
664
    drop_uid(use_uid);
665

    
666
  protos_build();
667
  proto_build(&proto_unix_kernel);
668
  proto_build(&proto_unix_iface);
669

    
670
  read_config();
671

    
672
  if (parse_and_exit)
673
    exit(0);
674

    
675
  if (!debug_flag)
676
    {
677
      pid_t pid = fork();
678
      if (pid < 0)
679
        die("fork: %m");
680
      if (pid)
681
        return 0;
682
      setsid();
683
      close(0);
684
      if (open("/dev/null", O_RDWR) < 0)
685
        die("Cannot open /dev/null: %m");
686
      dup2(0, 1);
687
      dup2(0, 2);
688
    }
689

    
690
  signal_init();
691

    
692
#ifdef LOCAL_DEBUG
693
  async_dump_flag = 1;
694
#endif
695

    
696
  log(L_INFO "Started");
697
  DBG("Entering I/O loop.\n");
698

    
699
  io_loop();
700
  bug("I/O loop died");
701
}