b0155df1edd9990043a43a63324a18cb3297812b
[silc.git] / apps / silcd / silcd.c
1 /*
2
3   silcd.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /*
21  * Created: Wed Mar 19 00:17:12 1997
22  *
23  * This is the main program for the SILC daemon. This parses command
24  * line arguments and creates the server object.
25  */
26 /* $Id$ */
27
28 #include "serverincludes.h"
29 #include "server_internal.h"
30 #include "silcversion.h"
31
32 /* For now, we'll have this one server context global for this module. */
33 static SilcServer silcd;
34
35 static void silc_usage(void);
36
37 /* Long command line options */
38 static struct option long_opts[] =
39 {
40   { "config-file", 1, NULL, 'f' },
41   { "passphrase", 1, NULL, 'p' },
42   { "debug", 2, NULL, 'd' },
43   { "debug-level", 1, NULL, 'D' },
44   { "hexdump", 0, NULL, 'x' },
45   { "help", 0, NULL, 'h' },
46   { "foreground", 0, NULL, 'F' },
47   { "version", 0, NULL,'V' },
48
49   /* Key management options */
50   { "create-key-pair", 1, NULL, 'C' },
51   { "pkcs", 1, NULL, 10 },
52   { "bits", 1, NULL, 11 },
53   { "identifier", 1, NULL, 12 },
54
55   { NULL, 0, NULL, 0 }
56 };
57
58 /* Command line option variables */
59 static char *opt_keypath = NULL;
60 static char *opt_pkcs = "rsa";
61 static char *opt_identifier = NULL;
62 static int opt_bits = 2048;
63
64 /* Prints out the usage of silc client */
65
66 static void silc_usage(void)
67 {
68   printf(""
69 "Usage: silcd [options]\n"
70 "\n"
71 "  Generic Options:\n"
72 "  -f  --config-file=FILE        Alternate configuration file\n"
73 "  -d  --debug=string            Enable debugging (Implies --foreground)\n"
74 "  -D  --debug-level=level       Enable debugging (Implies --foreground)\n"
75 "  -x  --hexdump                 Enable hexdumps (Implies --debug)\n"
76 "  -h  --help                    Display this message\n"
77 "  -F  --foreground              Dont fork\n"
78 "  -V  --version                 Display version\n"
79 "\n"
80 "  Key Management Options:\n"
81 "  -C, --create-key-pair=PATH    Create new public key pair\n"
82 "      --pkcs=PKCS               Set the PKCS of the public key pair\n"
83 "      --bits=VALUE              Set length of the public key pair\n"
84 "      --identifier=IDENTIFIER   Public key identifier\n"
85 "\n"
86 "      The public key identifier may be of the following format:\n"
87 "\n"
88 "      UN=<username>, HN=<hostname or IP>, RN=<real name>, E=<email>,\n"
89 "      O=<organization>, C=<country>\n"
90 "\n"
91 "      The UN and HN must be provided, the others are optional.  If the\n"
92 "      --identifier option is not used an identifier will be created for\n"
93 "      the public key automatically.\n"
94 "\n"
95 "      Example identifier: \"UN=foobar, HN=foo.bar.com, RN=Foo T. Bar, \n"
96 "                           E=foo@bar.com, C=FI\"\n"
97 "\n");
98   exit(0);
99 }
100
101 /* Die if a *valid* pid file exists already */
102
103 static void silc_server_checkpid(SilcServer silcd)
104 {
105   if (silcd->config->server_info->pid_file) {
106     int oldpid;
107     char *buf;
108     SilcUInt32 buf_len;
109
110     SILC_LOG_DEBUG(("Checking for another silcd running"));
111     buf = silc_file_readfile(silcd->config->server_info->pid_file, &buf_len);
112     if (!buf)
113       return;
114     oldpid = atoi(buf);
115     silc_free(buf);
116     if (oldpid <= 0)
117       return;
118     kill(oldpid, SIGCHLD); /* this signal does nothing, check if alive */
119     if (errno != ESRCH) {
120       fprintf(stderr, "\nI detected another daemon running with the "
121               "same pid file.\n");
122       fprintf(stderr, "Please change the config file, or erase the %s\n",
123         silcd->config->server_info->pid_file);
124       exit(1);
125     }
126   }
127 }
128
129 /* Drop root privileges. If some system call fails, die. */
130
131 static void silc_server_drop_privs(SilcServer server)
132 {
133   /* Are we executing silcd as root or a regular user? */
134   if (geteuid()) {
135     SILC_LOG_DEBUG(("Server started as user"));
136   }
137   else {
138     struct passwd *pw;
139     struct group *gr;
140     char *user, *group;
141
142     SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
143
144     /* Get the values given for user and group in configuration file */
145     user = server->config->server_info->user;
146     group = server->config->server_info->group;
147
148     if (!user || !group) {
149       fprintf(stderr, "Error:"
150        "\tSILC server must not be run as root.  For the security of your\n"
151        "\tsystem it is strongly suggested that you run SILC under dedicated\n"
152        "\tuser account.  Modify the ServerInfo configuration section to run\n"
153        "\tthe server as non-root user.\n");
154       exit(1);
155     }
156
157     /* Check whether the user/group does not begin with a number */
158     if (isdigit(user[0]) || isdigit(group[0])) {
159       SILC_LOG_DEBUG(("User and/or group starts with a number"));
160       fprintf(stderr, "Invalid user and/or group information\n");
161       fprintf(stderr, "Please assign them as names, not numbers\n");
162       exit(1);
163     }
164
165     if (!(pw = getpwnam(user))) {
166       fprintf(stderr, "Error: No such user %s found.\n", user);
167       exit(1);
168     }
169     if (!(gr = getgrnam(group))) {
170       fprintf(stderr, "Error: No such group %s found.\n", group);
171       exit(1);
172     }
173
174     /* Check whether user and/or group is set to root. If yes, exit
175        immediately. Otherwise, setgid and setuid server to user.group */
176     if ((gr->gr_gid == 0) || (pw->pw_uid == 0)) {
177       fprintf(stderr, "Error:"
178        "\tSILC server must not be run as root.  For the security of your\n"
179        "\tsystem it is strongly suggested that you run SILC under dedicated\n"
180        "\tuser account.  Modify the ServerInfo configuration section to run\n"
181        "\tthe server as non-root user.\n");
182       exit(1);
183     }
184
185     SILC_LOG_DEBUG(("Changing to group %s (gid=%u)", group, gr->gr_gid));
186     if (setgid(gr->gr_gid) != 0) {
187       fprintf(stderr, "Error: Failed setgid() to %s (gid=%u). Exiting.\n",
188               group, gr->gr_gid);
189       exit(1);
190     }
191 #if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS
192     SILC_LOG_DEBUG(("Removing supplementary groups"));
193     if (setgroups(0, NULL) != 0) {
194       fprintf(stderr, "Error: Failed setgroups() to NULL. Exiting.\n");
195       exit(1);
196     }
197     SILC_LOG_DEBUG(("Setting supplementary groups for user %s", user));
198     if (initgroups(user, gr->gr_gid) != 0) {
199       fprintf(stderr, "Error: Failed initgroups() for user %s (gid=%u). "
200               "Exiting.\n", user, gr->gr_gid);
201       exit(1);
202     }
203 #endif
204     SILC_LOG_DEBUG(("Changing to user %s (uid=%u)", user, pw->pw_uid));
205     if (setuid(pw->pw_uid) != 0) {
206       fprintf(stderr, "Error: Failed to setuid() to %s (gid=%u). Exiting.\n",
207               user, pw->pw_uid);
208       exit(1);
209     }
210   }
211 }
212
213 /* Fork server to background */
214
215 static void silc_server_daemonise(SilcServer server)
216 {
217   int i;
218
219   SILC_LOG_DEBUG(("Forking SILC server to background"));
220
221   if ((i = fork()) < 0) {
222     fprintf(stderr, "Error: fork() failed: %s\n", strerror(errno));
223     exit(1);
224   }
225
226   if (i) /* Kill the parent */
227     exit(0);
228
229   server->background = TRUE;
230   setsid();
231
232   /* XXX close stdin, stdout, stderr -- before this, check that all writes
233      to stderr are changed to SILC_SERVER_LOG_ERROR() */
234 }
235
236 static void signal_handler(int sig)
237 {
238   /* Mark the signal to be caller after this signal is over. */
239   silc_schedule_signal_call(silcd->schedule, sig);
240 }
241
242 SILC_TASK_CALLBACK(got_hup)
243 {
244   /* First, reset all log files (they might have been deleted) */
245   silc_log_reset_all();
246
247   /* Rehash the configuration file */
248   silc_server_rehash(silcd);
249 }
250
251 SILC_TASK_CALLBACK(stop_server)
252 {
253   /* Stop scheduler, the program will stop eventually after noticing
254      that the scheduler is down. */
255   silc_schedule_stop(silcd->schedule);
256 }
257
258 /* Dump server statistics into a file into /tmp directory */
259
260 SILC_TASK_CALLBACK(dump_stats)
261 {
262   FILE *fdd;
263   char filename[256];
264
265   memset(filename, 0, sizeof(filename));
266   snprintf(filename, sizeof(filename) - 1, "/tmp/silcd.%d.stats", getpid());
267   fdd = fopen(filename, "w+");
268   if (!fdd)
269     return;
270
271 #define STAT_OUTPUT(fmt, stat) fprintf(fdd, fmt "\n", (int)stat);
272
273   fprintf(fdd, "SILC Server %s Statistics\n\n", silcd->server_name);
274   fprintf(fdd, "Local Stats:\n");
275   STAT_OUTPUT("  My clients              : %d", silcd->stat.my_clients);
276   STAT_OUTPUT("  My servers              : %d", silcd->stat.my_servers);
277   STAT_OUTPUT("  My routers              : %d", silcd->stat.my_routers);
278   STAT_OUTPUT("  My channels             : %d", silcd->stat.my_channels);
279   STAT_OUTPUT("  My joined users         : %d", silcd->stat.my_chanclients);
280   STAT_OUTPUT("  My aways                : %d", silcd->stat.my_aways);
281   STAT_OUTPUT("  My detached clients     : %d", silcd->stat.my_detached);
282   STAT_OUTPUT("  My server operators     : %d", silcd->stat.my_server_ops);
283   STAT_OUTPUT("  My router operators     : %d", silcd->stat.my_router_ops);
284   fprintf(fdd, "\nGlobal Stats:\n");
285   STAT_OUTPUT("  Cell clients            : %d", silcd->stat.cell_clients);
286   STAT_OUTPUT("  Cell servers            : %d", silcd->stat.cell_servers);
287   STAT_OUTPUT("  Cell channels           : %d", silcd->stat.cell_channels);
288   STAT_OUTPUT("  Cell joined users       : %d", silcd->stat.cell_chanclients);
289   STAT_OUTPUT("  All clients             : %d", silcd->stat.clients);
290   STAT_OUTPUT("  All servers             : %d", silcd->stat.servers);
291   STAT_OUTPUT("  All routers             : %d", silcd->stat.routers);
292   STAT_OUTPUT("  All channels            : %d", silcd->stat.channels);
293   STAT_OUTPUT("  All joined users        : %d", silcd->stat.chanclients);
294   STAT_OUTPUT("  All aways               : %d", silcd->stat.aways);
295   STAT_OUTPUT("  All detached clients    : %d", silcd->stat.detached);
296   STAT_OUTPUT("  All server operators    : %d", silcd->stat.server_ops);
297   STAT_OUTPUT("  All router operators    : %d", silcd->stat.router_ops);
298   fprintf(fdd, "\nGeneral Stats:\n");
299   STAT_OUTPUT("  Connection attempts     : %d", silcd->stat.conn_attempts);
300   STAT_OUTPUT("  Connection failures     : %d", silcd->stat.conn_failures);
301   STAT_OUTPUT("  Authentication attempts : %d", silcd->stat.auth_attempts);
302   STAT_OUTPUT("  Authentication failures : %d", silcd->stat.auth_failures);
303   STAT_OUTPUT("  Packets sent            : %d", silcd->stat.packets_sent);
304   STAT_OUTPUT("  Packets received        : %d", silcd->stat.packets_received);
305
306 #undef STAT_OUTPUT
307
308   fflush(fdd);
309   fclose(fdd);
310 }
311
312 typedef struct {
313   int level;
314   const char *string;
315 } DebugLevel;
316
317 static DebugLevel debug_levels[] = {
318   /* Very basic stuff from silcd/ */
319   { 3, "silcd\\.c,server\\.c" },
320
321   /* More stuff from silcd/ */
322   { 7, "silcd\\.c,server\\.c,command\\.c,server_backup\\.c,packet_send\\.c" },
323
324   /* All basic stuff from silcd/ */
325   { 10, "silc_server_*" },
326
327   /* All from silcd/ */
328   { 15, "*silcd*,*serverid*,silc_server_*,*idlist*" },
329
330   /* All from silcd/ and basic stuff from libs */
331   { 20, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,*silcske*" },
332
333   /* All from silcd/ and more stuff from libs */
334   { 25, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
335     "*silcpacket*,*ske*,*silcrng*" },
336
337   /* All from silcd/ and even more stuff from libs */
338   { 30, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
339     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" },
340
341   /* All from silcd/ and even more stuff from libs + all from silccore */
342   { 35, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
343     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
344     "*silcid*,*argument*" },
345
346   /* All from silcd/, all from silccore, silccrypt and silcmath */
347   { 40, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
348     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
349     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*" },
350
351   /* All from silcd/, all from silccore, silccrypt and silcmath + stuff
352      from silcutil */
353   { 45, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
354     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
355     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
356     "*sockconn*" },
357
358   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
359      from silcutil */
360   { 50, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
361     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
362     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
363     "*sockconn*,*net*" },
364
365   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
366      from silcutil */
367   { 55, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
368     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
369     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
370     "*sockconn*,*net*,*log*,*config*" },
371
372   /* All */
373   { 90, "*" },
374
375   { -1, NULL },
376 };
377
378 static void silc_get_debug_level(int level)
379 {
380   int i;
381
382   if (level < 0)
383     return;
384
385   for (i = 0; debug_levels[i].string; i++)
386     if (level <= debug_levels[i].level) {
387       silc_log_set_debug_string(debug_levels[i].string);
388       break;
389     }
390 }
391
392 /* This function should not be called directly but thru the wrapper
393    macro SILC_SERVER_LOG_STDERR() */
394
395 void silc_server_stderr(char *message)
396 {
397   if (silcd->background) {
398     char *p, *n = message;
399
400     /* remove newlines if we are going to output it to a log file */
401     for (p = n; *p; p++) {
402       if (*p != '\n') {
403         if (p != n)
404           *n = *p;
405         n++;
406       }
407     }
408     *n = 0;
409
410     silc_log_output(SILC_LOG_ERROR, message);
411   }
412   else {
413     fprintf(stderr, "%s\n", message);
414     silc_free(message);
415   }
416 }
417
418 int main(int argc, char **argv)
419 {
420   int ret, opt, option_index;
421   bool foreground = FALSE;
422   bool opt_create_keypair = FALSE;
423   char *silcd_config_file = NULL;
424   struct sigaction sa;
425
426   /* Parse command line arguments */
427   if (argc > 1) {
428     while ((opt = getopt_long(argc, argv, "f:p:d:D:xhFVC:",
429                               long_opts, &option_index)) != EOF) {
430       switch(opt) {
431         case 'h':
432           silc_usage();
433           break;
434         case 'V':
435           printf("SILCd Secure Internet Live Conferencing daemon, "
436                  "version %s (base: SILC Toolkit %s)\n",
437                  silc_dist_version, silc_version);
438           printf("(c) 1997 - 2002 Pekka Riikonen "
439                  "<priikone@silcnet.org>\n");
440           exit(0);
441           break;
442         case 'd':
443 #ifdef SILC_DEBUG
444           silc_debug = TRUE;
445           if (optarg)
446             silc_log_set_debug_string(optarg);
447           foreground = TRUE;        /* implied */
448           silc_log_quick = TRUE;    /* implied */
449 #else
450           fprintf(stderr,
451                   "Run-time debugging is not enabled. To enable it recompile\n"
452                   "the server with --enable-debug configuration option.\n");
453 #endif
454           break;
455         case 'D':
456 #ifdef SILC_DEBUG
457           silc_debug = TRUE;
458           if (optarg)
459             silc_get_debug_level(atoi(optarg));
460           foreground = TRUE;        /* implied */
461           silc_log_quick = TRUE;    /* implied */
462 #else
463           fprintf(stderr,
464                   "Run-time debugging is not enabled. To enable it recompile\n"
465                   "the server with --enable-debug configuration option.\n");
466 #endif
467           break;
468         case 'x':
469 #ifdef SILC_DEBUG
470           silc_debug_hexdump = TRUE;
471           silc_debug = TRUE; /* implied */
472           foreground = TRUE; /* implied */
473           silc_log_quick = TRUE; /* implied */
474 #else
475           fprintf(stderr,
476                   "Run-time debugging is not enabled. To enable it recompile\n"
477                   "the server with --enable-debug configuration option.\n");
478 #endif
479           break;
480         case 'f':
481           silcd_config_file = strdup(optarg);
482           break;
483         case 'F':
484           foreground = TRUE;
485           break;
486
487           /*
488            * Key management options
489            */
490         case 'C':
491           opt_create_keypair = TRUE;
492           if (optarg)
493             opt_keypath = strdup(optarg);
494           break;
495         case 10:
496           if (optarg)
497             opt_pkcs = strdup(optarg);
498           break;
499         case 11:
500           if (optarg)
501             opt_bits = atoi(optarg);
502           break;
503         case 12:
504           if (optarg)
505             opt_identifier = strdup(optarg);
506           break;
507
508         default:
509           silc_usage();
510           break;
511       }
512     }
513   }
514
515   if (opt_create_keypair == TRUE) {
516     /* Create new key pair and exit */
517     char pubfile[256], prvfile[256];
518
519     memset(pubfile, 0, sizeof(pubfile));
520     memset(prvfile, 0, sizeof(prvfile));
521     snprintf(pubfile, sizeof(pubfile) - 1, "%s/silcd.pub", opt_keypath);
522     snprintf(prvfile, sizeof(prvfile) - 1, "%s/silcd.prv", opt_keypath);
523
524     silc_cipher_register_default();
525     silc_pkcs_register_default();
526     silc_hash_register_default();
527     silc_hmac_register_default();
528     silc_create_key_pair(opt_pkcs, opt_bits, pubfile, prvfile,
529                          opt_identifier, "", NULL, NULL, NULL, FALSE);
530     exit(0);
531   }
532
533   /* Default configuration file */
534   if (!silcd_config_file)
535     silcd_config_file = strdup(SILC_SERVER_CONFIG_FILE);
536
537   /* Create SILC Server object */
538   ret = silc_server_alloc(&silcd);
539   if (ret == FALSE)
540     goto fail;
541
542   /* Register default crypto stuff since we are going to need them 
543      in the configuration file parsing phase */
544   silc_cipher_register_default();
545   silc_pkcs_register_default();
546   silc_hash_register_default();
547   silc_hmac_register_default();
548
549   /* Read configuration files */
550   silcd->config = silc_server_config_alloc(silcd_config_file);
551   if (silcd->config == NULL)
552     goto fail;
553   silcd->config_file = silcd_config_file;
554
555   /* Unregister the default crypto stuff so that configuration takes effect */
556   silc_cipher_unregister_all();
557   silc_pkcs_unregister_all();
558   silc_hash_unregister_all();
559   silc_hmac_unregister_all();
560
561   /* Check for another silcd running */
562   silc_server_checkpid(silcd);
563
564   /* Initialize the server */
565   if (silc_server_init(silcd) == FALSE)
566     goto fail;
567
568   /* Ignore SIGPIPE */
569   sa.sa_handler = SIG_IGN;
570   sa.sa_flags = 0;
571   sigemptyset(&sa.sa_mask);
572   sigaction(SIGPIPE, &sa, NULL);
573   sa.sa_handler = signal_handler;
574   sigaction(SIGHUP, &sa, NULL);
575   sigaction(SIGTERM, &sa, NULL);
576   sigaction(SIGINT, &sa, NULL);
577   sigaction(SIGUSR1, &sa, NULL);
578   silc_schedule_signal_register(silcd->schedule, SIGHUP, got_hup, NULL);
579   silc_schedule_signal_register(silcd->schedule, SIGTERM, stop_server, NULL);
580   silc_schedule_signal_register(silcd->schedule, SIGINT, stop_server, NULL);
581   silc_schedule_signal_register(silcd->schedule, SIGUSR1, dump_stats, NULL);
582
583   if (!foreground) {
584     /* Before running the server, fork to background. */
585     silc_server_daemonise(silcd);
586
587     /* If set, write pid to file */
588     if (silcd->config->server_info->pid_file) {
589       char buf[10], *pidfile = silcd->config->server_info->pid_file;
590       unlink(pidfile);
591       snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
592       silc_file_writefile(pidfile, buf, strlen(buf));
593     }
594   }
595
596   /* Drop root if we are not in debug mode, so you don't need to bother about
597      file writing permissions and so on */
598   if (!silc_debug)
599     silc_server_drop_privs(silcd);
600
601   /* Run the server. When this returns the server has been stopped
602      and we will exit. */
603   silc_server_run(silcd);
604
605   /* Stop the server and free it. */
606   silc_server_stop(silcd);
607   silc_server_config_destroy(silcd->config);
608   silc_server_free(silcd);
609
610   /* Flush the logging system */
611   silc_log_flush_all();
612
613   silc_free(silcd_config_file);
614   silc_free(opt_identifier);
615   silc_free(opt_keypath);
616   exit(0);
617
618  fail:
619   silc_free(silcd_config_file);
620   silc_free(opt_identifier);
621   silc_free(opt_keypath);
622   exit(1);
623 }