Removed HTTP server libary, it's available in SRT now
[silc.git] / apps / silcd / silcd.c
1 /*
2
3   silcd.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /*
20  * Created: Wed Mar 19 00:17:12 1997
21  *
22  * This is the main program for the SILC daemon. This parses command
23  * line arguments and creates the server object.
24  */
25 /* $Id$ */
26
27 #include "serverincludes.h"
28 #include "server_internal.h"
29 #include "silcversion.h"
30
31 /* For now, we'll have this one server context global for this module. */
32 static SilcServer silcd;
33
34 static void silc_usage(void);
35
36 #ifdef HAVE_GETOPT_LONG
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 #endif /* HAVE_GETOPT_LONG */
58
59 /* Command line option variables */
60 static char *opt_keypath = NULL;
61 static char *opt_pkcs = "rsa";
62 static char *opt_identifier = NULL;
63 static int opt_bits = 2048;
64
65 /* Prints out the usage of silc client */
66
67 static void silc_usage(void)
68 {
69   printf(""
70 "Usage: silcd [options]\n"
71 "\n"
72 "  Generic Options:\n"
73 "  -f  --config-file=FILE        Alternate configuration file\n"
74 "  -d  --debug=string            Enable debugging (Implies --foreground)\n"
75 "  -D  --debug-level=level       Enable debugging (Implies --foreground)\n"
76 "  -x  --hexdump                 Enable hexdumps (Implies --debug)\n"
77 "  -h  --help                    Display this message\n"
78 "  -F  --foreground              Dont fork\n"
79 "  -V  --version                 Display version\n"
80 "\n"
81 "  Key Management Options:\n"
82 "  -C, --create-key-pair=PATH    Create new public key pair\n"
83 "      --pkcs=PKCS               Set the PKCS of the public key pair\n"
84 "      --bits=VALUE              Set length of the public key pair\n"
85 "      --identifier=IDENTIFIER   Public key identifier\n"
86 "\n"
87 "      The public key identifier may be of the following format:\n"
88 "\n"
89 "      UN=<username>, HN=<hostname or IP>, RN=<real name>, E=<email>,\n"
90 "      O=<organization>, C=<country>\n"
91 "\n"
92 "      The UN and HN must be provided, the others are optional.  If the\n"
93 "      --identifier option is not used an identifier will be created for\n"
94 "      the public key automatically.\n"
95 "\n"
96 "      Example identifier: \"UN=foobar, HN=foo.bar.com, RN=Foo T. Bar, \n"
97 "                           E=foo@bar.com, C=FI\"\n"
98 "\n");
99   exit(0);
100 }
101
102 /* Die if a *valid* pid file exists already */
103
104 static void silc_server_checkpid(SilcServer silcd)
105 {
106   if (silcd->config->server_info->pid_file) {
107     int oldpid;
108     char *buf;
109     SilcUInt32 buf_len;
110
111     SILC_LOG_DEBUG(("Checking for another silcd running"));
112     buf = silc_file_readfile(silcd->config->server_info->pid_file, &buf_len);
113     if (!buf)
114       return;
115     oldpid = atoi(buf);
116     silc_free(buf);
117     if (oldpid <= 0)
118       return;
119     kill(oldpid, SIGCHLD); /* this signal does nothing, check if alive */
120     if (errno != ESRCH) {
121       fprintf(stderr, "\nI detected another daemon running with the "
122               "same pid file.\n");
123       fprintf(stderr, "Please change the config file, or erase the %s\n",
124         silcd->config->server_info->pid_file);
125       exit(1);
126     }
127   }
128 }
129
130 /* Drop root privileges. If some system call fails, die. */
131
132 static void silc_server_drop_privs(SilcServer server)
133 {
134   /* Are we executing silcd as root or a regular user? */
135   if (geteuid()) {
136     SILC_LOG_DEBUG(("Server started as user"));
137   }
138   else {
139     struct passwd *pw;
140     struct group *gr;
141     char *user, *group;
142
143     SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
144
145     /* Get the values given for user and group in configuration file */
146     user = server->config->server_info->user;
147     group = server->config->server_info->group;
148
149     if (!user || !group) {
150       fprintf(stderr, "Error:"
151        "\tSILC server must not be run as root.  For the security of your\n"
152        "\tsystem it is strongly suggested that you run SILC under dedicated\n"
153        "\tuser account.  Modify the ServerInfo configuration section to run\n"
154        "\tthe server as non-root user.\n");
155       exit(1);
156     }
157
158     /* Check whether the user/group does not begin with a number */
159     if (isdigit(user[0]) || isdigit(group[0])) {
160       SILC_LOG_DEBUG(("User and/or group starts with a number"));
161       fprintf(stderr, "Invalid user and/or group information\n");
162       fprintf(stderr, "Please assign them as names, not numbers\n");
163       exit(1);
164     }
165
166     if (!(pw = getpwnam(user))) {
167       fprintf(stderr, "Error: No such user %s found.\n", user);
168       exit(1);
169     }
170     if (!(gr = getgrnam(group))) {
171       fprintf(stderr, "Error: No such group %s found.\n", group);
172       exit(1);
173     }
174
175     /* Check whether user and/or group is set to root. If yes, exit
176        immediately. Otherwise, setgid and setuid server to user.group */
177     if ((gr->gr_gid == 0) || (pw->pw_uid == 0)) {
178       fprintf(stderr, "Error:"
179        "\tSILC server must not be run as root.  For the security of your\n"
180        "\tsystem it is strongly suggested that you run SILC under dedicated\n"
181        "\tuser account.  Modify the ServerInfo configuration section to run\n"
182        "\tthe server as non-root user.\n");
183       exit(1);
184     }
185
186     SILC_LOG_DEBUG(("Changing to group %s (gid=%u)", group, gr->gr_gid));
187     if (setgid(gr->gr_gid) != 0) {
188       fprintf(stderr, "Error: Failed setgid() to %s (gid=%u). Exiting.\n",
189               group, gr->gr_gid);
190       exit(1);
191     }
192 #if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS
193     SILC_LOG_DEBUG(("Removing supplementary groups"));
194     if (setgroups(0, NULL) != 0) {
195       fprintf(stderr, "Error: Failed setgroups() to NULL. Exiting.\n");
196       exit(1);
197     }
198     SILC_LOG_DEBUG(("Setting supplementary groups for user %s", user));
199     if (initgroups(user, gr->gr_gid) != 0) {
200       fprintf(stderr, "Error: Failed initgroups() for user %s (gid=%u). "
201               "Exiting.\n", user, gr->gr_gid);
202       exit(1);
203     }
204 #endif
205     SILC_LOG_DEBUG(("Changing to user %s (uid=%u)", user, pw->pw_uid));
206     if (setuid(pw->pw_uid) != 0) {
207       fprintf(stderr, "Error: Failed to setuid() to %s (gid=%u). Exiting.\n",
208               user, pw->pw_uid);
209       exit(1);
210     }
211   }
212 }
213
214 /* Fork server to background */
215
216 static void silc_server_daemonise(SilcServer server)
217 {
218   int i;
219
220   SILC_LOG_DEBUG(("Forking SILC server to background"));
221
222   if ((i = fork()) < 0) {
223     fprintf(stderr, "Error: fork() failed: %s\n", strerror(errno));
224     exit(1);
225   }
226
227   if (i) /* Kill the parent */
228     exit(0);
229
230   server->background = TRUE;
231   setsid();
232
233   /* XXX close stdin, stdout, stderr -- before this, check that all writes
234      to stderr are changed to SILC_SERVER_LOG_ERROR() */
235 }
236
237 SILC_TASK_CALLBACK(got_hup)
238 {
239   /* First, reset all log files (they might have been deleted) */
240   silc_log_reset_all();
241
242   /* Rehash the configuration file */
243   silc_server_rehash(silcd);
244 }
245
246 SILC_TASK_CALLBACK(stop_server)
247 {
248   /* Stop scheduler, the program will stop eventually after noticing
249      that the scheduler is down. */
250   silc_schedule_stop(silcd->schedule);
251 }
252
253 /* Dump server statistics into a file into /tmp directory */
254
255 SILC_TASK_CALLBACK(dump_stats)
256 {
257   FILE *fdd;
258   int fild;
259   char filename[256];
260
261   memset(filename, 0, sizeof(filename));
262   snprintf(filename, sizeof(filename) - 1, "/tmp/silcd.%d.stats-XXXXXX", getpid());
263   fild = mkstemp(filename);
264   if (fild == -1)
265     return;
266
267   fdd = fdopen(fild, "w");
268   if (fdd == NULL) {
269     close(fild);
270     unlink(filename);
271     return;
272   }
273
274 #define STAT_OUTPUT(fmt, stat) fprintf(fdd, fmt "\n", (int)stat);
275
276   fprintf(fdd, "SILC Server %s Statistics\n\n", silcd->server_name);
277   fprintf(fdd, "Local Stats:\n");
278   STAT_OUTPUT("  My clients              : %d", silcd->stat.my_clients);
279   STAT_OUTPUT("  My servers              : %d", silcd->stat.my_servers);
280   STAT_OUTPUT("  My routers              : %d", silcd->stat.my_routers);
281   STAT_OUTPUT("  My channels             : %d", silcd->stat.my_channels);
282   STAT_OUTPUT("  My joined users         : %d", silcd->stat.my_chanclients);
283   STAT_OUTPUT("  My aways                : %d", silcd->stat.my_aways);
284   STAT_OUTPUT("  My detached clients     : %d", silcd->stat.my_detached);
285   STAT_OUTPUT("  My server operators     : %d", silcd->stat.my_server_ops);
286   STAT_OUTPUT("  My router operators     : %d", silcd->stat.my_router_ops);
287   fprintf(fdd, "\nGlobal Stats:\n");
288   STAT_OUTPUT("  Cell clients            : %d", silcd->stat.cell_clients);
289   STAT_OUTPUT("  Cell servers            : %d", silcd->stat.cell_servers);
290   STAT_OUTPUT("  Cell channels           : %d", silcd->stat.cell_channels);
291   STAT_OUTPUT("  Cell joined users       : %d", silcd->stat.cell_chanclients);
292   STAT_OUTPUT("  All clients             : %d", silcd->stat.clients);
293   STAT_OUTPUT("  All servers             : %d", silcd->stat.servers);
294   STAT_OUTPUT("  All routers             : %d", silcd->stat.routers);
295   STAT_OUTPUT("  All channels            : %d", silcd->stat.channels);
296   STAT_OUTPUT("  All joined users        : %d", silcd->stat.chanclients);
297   STAT_OUTPUT("  All aways               : %d", silcd->stat.aways);
298   STAT_OUTPUT("  All detached clients    : %d", silcd->stat.detached);
299   STAT_OUTPUT("  All server operators    : %d", silcd->stat.server_ops);
300   STAT_OUTPUT("  All router operators    : %d", silcd->stat.router_ops);
301   fprintf(fdd, "\nGeneral Stats:\n");
302   STAT_OUTPUT("  Connection attempts     : %d", silcd->stat.conn_attempts);
303   STAT_OUTPUT("  Connection failures     : %d", silcd->stat.conn_failures);
304   STAT_OUTPUT("  Authentication attempts : %d", silcd->stat.auth_attempts);
305   STAT_OUTPUT("  Authentication failures : %d", silcd->stat.auth_failures);
306   STAT_OUTPUT("  Packets sent            : %d", silcd->stat.packets_sent);
307   STAT_OUTPUT("  Packets received        : %d", silcd->stat.packets_received);
308   STAT_OUTPUT("  Commands sent           : %d", silcd->stat.commands_sent);
309   STAT_OUTPUT("  Commands received       : %d", silcd->stat.commands_received);
310   STAT_OUTPUT("  Connections             : %d", silcd->stat.conn_num);
311
312 #undef STAT_OUTPUT
313
314 #ifdef SILC_DEBUG
315   /* Dump internal flags */
316   fprintf(fdd, "\nDumping internal flags\n");
317   fprintf(fdd, "  server_type            : %d\n", silcd->server_type);
318   fprintf(fdd, "  standalone             : %d\n", silcd->standalone);
319   fprintf(fdd, "  listenning             : %d\n", silcd->listenning);
320   fprintf(fdd, "  background             : %d\n", silcd->background);
321   fprintf(fdd, "  backup_router          : %d\n", silcd->backup_router);
322   fprintf(fdd, "  backup_primary         : %d\n", silcd->backup_primary);
323   fprintf(fdd, "  backup_noswitch        : %d\n", silcd->backup_noswitch);
324   fprintf(fdd, "  backup_closed          : %d\n", silcd->backup_closed);
325   fprintf(fdd, "  wait_backup            : %d\n", silcd->wait_backup);
326   if (silcd->router)
327     fprintf(fdd, "  primary router         : %s\n",
328       silcd->router->server_name ? silcd->router->server_name : "");
329
330   /* Dump connections */
331   {
332     SilcPacketStream s;
333     SilcDList conns = silc_packet_engine_get_streams(silcd->packet_engine);
334
335     fprintf(fdd, "\nDumping connections\n");
336     silc_dlist_start(conns);
337     while ((s = silc_dlist_get(conns))) {
338       const char *hostname, *ip;
339       SilcUInt16 port;
340       SilcSocket sock;
341       SilcIDListData idata = silc_packet_get_context(s);
342       if (!silc_socket_stream_get_info(silc_packet_stream_get_stream(s),
343                                        &sock, &hostname, &ip, &port))
344         continue;
345       fprintf(fdd, "  %d: host %s ip %s port %d type %d\n",
346               sock, hostname ? hostname : "N/A",
347               ip ? ip : "N/A", port, idata ? idata->conn_type : 0);
348     }
349     silc_dlist_uninit(conns);
350   }
351
352   /* Dump lists */
353   {
354     SilcList list;
355     SilcIDCacheEntry id_cache = NULL;
356     SilcServerEntry server_entry;
357     SilcClientEntry client_entry;
358     SilcChannelEntry channel_entry;
359     int c;
360
361     fprintf(fdd, "\nDumping databases\n");
362
363     if (silc_idcache_get_all(silcd->local_list->servers, &list)) {
364       c = 1;
365       fprintf(fdd, "\nServers in local-list:\n");
366       while ((id_cache = silc_list_get(list))) {
367           server_entry = (SilcServerEntry)id_cache->context;
368           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
369                   server_entry->server_name ? server_entry->server_name :
370                   "N/A", server_entry->id ?
371                   silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
372                   server_entry->data.status);
373           c++;
374       }
375     }
376     if (silc_idcache_get_all(silcd->global_list->servers, &list)) {
377         fprintf(fdd, "\nServers in global-list:\n");
378         c = 1;
379         while ((id_cache = silc_list_get(list))) {
380           server_entry = (SilcServerEntry)id_cache->context;
381           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
382                   server_entry->server_name ? server_entry->server_name :
383                   "N/A", server_entry->id ?
384                   silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
385                   server_entry->data.status);
386           c++;
387         }
388     }
389     if (silc_idcache_get_all(silcd->local_list->clients, &list)) {
390         fprintf(fdd, "\nClients in local-list:\n");
391         c = 1;
392         while ((id_cache = silc_list_get(list))) {
393           client_entry = (SilcClientEntry)id_cache->context;
394           server_entry = client_entry->router;
395           fprintf(fdd, "  %d: name %s id %s status 0x%x from %s\n", c,
396                   client_entry->nickname ? client_entry->nickname :
397                   (unsigned char *)"N/A", client_entry->id ?
398                   silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
399                   client_entry->data.status, server_entry ?
400                   server_entry->server_name ? server_entry->server_name :
401                   "N/A" : "local");
402           c++;
403         }
404     }
405     if (silc_idcache_get_all(silcd->global_list->clients, &list)) {
406         fprintf(fdd, "\nClients in global-list:\n");
407         c = 1;
408         while ((id_cache = silc_list_get(list))) {
409           client_entry = (SilcClientEntry)id_cache->context;
410           server_entry = client_entry->router;
411           fprintf(fdd, "  %d: name %s id %s status 0x%x from %s\n", c,
412                   client_entry->nickname ? client_entry->nickname :
413                   (unsigned char *)"N/A", client_entry->id ?
414                   silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
415                   client_entry->data.status, server_entry ?
416                   server_entry->server_name ? server_entry->server_name :
417                   "N/A" : "local");
418           c++;
419         }
420     }
421     if (silc_idcache_get_all(silcd->local_list->channels, &list)) {
422         fprintf(fdd, "\nChannels in local-list:\n");
423         c = 1;
424         while ((id_cache = silc_list_get(list))) {
425           channel_entry = (SilcChannelEntry)id_cache->context;
426           fprintf(fdd, "  %d: name %s id %s\n", c,
427                   channel_entry->channel_name ? channel_entry->channel_name :
428                   "N/A", channel_entry->id ?
429                   silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
430           c++;
431         }
432     }
433     if (silc_idcache_get_all(silcd->global_list->channels, &list)) {
434         fprintf(fdd, "\nChannels in global-list:\n");
435         c = 1;
436         while ((id_cache = silc_list_get(list))) {
437           channel_entry = (SilcChannelEntry)id_cache->context;
438           fprintf(fdd, "  %d: name %s id %s\n", c,
439                   channel_entry->channel_name ? channel_entry->channel_name :
440                   "N/A", channel_entry->id ?
441                   silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
442           c++;
443         }
444     }
445   }
446 #endif
447
448   fflush(fdd);
449   fclose(fdd);
450 }
451
452 #ifdef SILC_DEBUG
453
454 typedef struct {
455   int level;
456   const char *string;
457 } DebugLevel;
458
459 static DebugLevel debug_levels[] = {
460   /* Very basic stuff from silcd/ */
461   { 3, "silcd\\.c,server\\.c" },
462
463   /* More stuff from silcd/ */
464   { 7, "silcd\\.c,server\\.c,command\\.c,server_backup\\.c,packet_send\\.c" },
465
466   /* All basic stuff from silcd/ */
467   { 10, "silc_server_*" },
468
469   /* All from silcd/ */
470   { 15, "*silcd*,*serverid*,silc_server_*,*idlist*" },
471
472   /* All from silcd/ and basic stuff from libs */
473   { 20, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,*silcske*" },
474
475   /* All from silcd/ and more stuff from libs */
476   { 25, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
477     "*silcpacket*,*ske*,*silcrng*" },
478
479   /* All from silcd/ and even more stuff from libs */
480   { 30, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
481     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" },
482
483   /* All from silcd/ and even more stuff from libs + all from silccore */
484   { 35, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
485     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
486     "*silcid*,*argument*" },
487
488   /* All from silcd/, all from silccore, silccrypt and silcmath */
489   { 40, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
490     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
491     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*" },
492
493   /* All from silcd/, all from silccore, silccrypt and silcmath + stuff
494      from silcutil */
495   { 45, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
496     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
497     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
498     "*sockconn*" },
499
500   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
501      from silcutil */
502   { 50, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
503     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
504     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
505     "*sockconn*,*net*" },
506
507   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
508      from silcutil */
509   { 55, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
510     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
511     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
512     "*sockconn*,*net*,*log*,*config*" },
513
514   /* All */
515   { 90, "*" },
516
517   { -1, NULL },
518 };
519
520 static void silc_get_debug_level(int level)
521 {
522   int i;
523
524   if (level < 0)
525     return;
526
527   for (i = 0; debug_levels[i].string; i++)
528     if (level <= debug_levels[i].level) {
529       silc_log_set_debug_string(debug_levels[i].string);
530       break;
531     }
532 }
533 #endif /* SILC_DEBUG */
534
535 /* This function should not be called directly but through the appropriate
536    wrapper macro defined in server.h */
537
538 void silc_server_stderr(SilcLogType type, char *message)
539 {
540   if (silcd->background) {
541     char *p, *n = message;
542
543     /* remove newlines if we are going to output it to a log file */
544     for (p = n; *p; p++) {
545       if (*p != '\n') {
546         if (p != n)
547           *n = *p;
548         n++;
549       }
550     }
551     *n = 0;
552
553     /* the message is freed inside the logging function */
554     silc_log_output(type, message);
555   }
556   else {
557     fprintf(stderr, "%s\n", message);
558     silc_free(message);
559   }
560 }
561
562 int main(int argc, char **argv)
563 {
564   int ret, opt, option_index;
565   SilcBool foreground = FALSE;
566   SilcBool opt_create_keypair = FALSE;
567   char *silcd_config_file = NULL;
568   struct sigaction sa;
569
570   /* Parse command line arguments */
571   if (argc > 1) {
572 #ifdef HAVE_GETOPT_LONG
573     while ((opt = getopt_long(argc, argv, "f:p:d:D:xhFVC:",
574                               long_opts, &option_index)) != EOF) {
575 #else
576     while ((opt = getopt(argc, argv, "f:p:d:D:xhFVC:")) != EOF) {
577 #endif /* HAVE_GETOPT_LONG */
578       switch(opt) {
579         case 'h':
580           silc_usage();
581           break;
582         case 'V':
583           printf("SILCd Secure Internet Live Conferencing daemon, "
584                  "version %s (base: SILC Toolkit %s)\n",
585                  silc_dist_version, silc_version);
586           printf("(c) 1997 - 2007 Pekka Riikonen "
587                  "<priikone@silcnet.org>\n");
588           exit(0);
589           break;
590         case 'd':
591 #ifdef SILC_DEBUG
592           silc_log_debug(TRUE);
593           silc_log_quick(TRUE);
594           if (optarg)
595             silc_log_set_debug_string(optarg);
596           foreground = TRUE;        /* implied */
597 #else
598           fprintf(stderr,
599                   "Run-time debugging is not enabled. To enable it recompile\n"
600                   "the server with --enable-debug configuration option.\n");
601 #endif
602           break;
603         case 'D':
604 #ifdef SILC_DEBUG
605           silc_log_debug(TRUE);
606           silc_log_quick(TRUE);
607           if (optarg)
608             silc_get_debug_level(atoi(optarg));
609           foreground = TRUE;        /* implied */
610 #else
611           fprintf(stderr,
612                   "Run-time debugging is not enabled. To enable it recompile\n"
613                   "the server with --enable-debug configuration option.\n");
614 #endif
615           break;
616         case 'x':
617 #ifdef SILC_DEBUG
618           silc_log_debug(TRUE);
619           silc_log_debug_hexdump(TRUE);
620           silc_log_quick(TRUE);
621           foreground = TRUE; /* implied */
622 #else
623           fprintf(stderr,
624                   "Run-time debugging is not enabled. To enable it recompile\n"
625                   "the server with --enable-debug configuration option.\n");
626 #endif
627           break;
628         case 'f':
629           silcd_config_file = strdup(optarg);
630           break;
631         case 'F':
632           foreground = TRUE;
633           break;
634
635           /*
636            * Key management options
637            */
638         case 'C':
639           opt_create_keypair = TRUE;
640           if (optarg)
641             opt_keypath = strdup(optarg);
642           break;
643         case 10:
644           if (optarg)
645             opt_pkcs = strdup(optarg);
646           break;
647         case 11:
648           if (optarg)
649             opt_bits = atoi(optarg);
650           break;
651         case 12:
652           if (optarg)
653             opt_identifier = strdup(optarg);
654           break;
655
656         default:
657           silc_usage();
658           break;
659       }
660     }
661   }
662
663   if (opt_create_keypair == TRUE) {
664     /* Create new key pair and exit */
665     char pubfile[256], prvfile[256];
666
667     memset(pubfile, 0, sizeof(pubfile));
668     memset(prvfile, 0, sizeof(prvfile));
669     snprintf(pubfile, sizeof(pubfile) - 1, "%s/silcd.pub", opt_keypath);
670     snprintf(prvfile, sizeof(prvfile) - 1, "%s/silcd.prv", opt_keypath);
671
672     silc_cipher_register_default();
673     silc_pkcs_register_default();
674     silc_hash_register_default();
675     silc_hmac_register_default();
676     if (!silc_create_key_pair(opt_pkcs, opt_bits, pubfile, prvfile,
677                               opt_identifier, "", NULL, NULL, FALSE))
678       exit(1);
679     exit(0);
680   }
681
682   /* Default configuration file */
683   if (!silcd_config_file)
684     silcd_config_file = strdup(SILC_SERVER_CONFIG_FILE);
685
686   /* Create SILC Server object */
687   ret = silc_server_alloc(&silcd);
688   if (ret == FALSE)
689     goto fail;
690
691   /* Register default crypto stuff since we are going to need them
692      in the configuration file parsing phase */
693   silc_cipher_register_default();
694   silc_pkcs_register_default();
695   silc_hash_register_default();
696   silc_hmac_register_default();
697
698   /* Read configuration files */
699   silcd->config = silc_server_config_alloc(silcd_config_file, silcd);
700   if (silcd->config == NULL)
701     goto fail;
702   silcd->config_file = silcd_config_file;
703
704   /* Unregister the default crypto stuff so that configuration takes effect */
705   silc_cipher_unregister_all();
706   /* silc_pkcs_unregister_all();  MUST NOT do this anymore; SilcPublicKey
707      parsed from config file references pointers so we cannot unregister */
708   silc_hash_unregister_all();
709   silc_hmac_unregister_all();
710
711   /* Check for another silcd running */
712   silc_server_checkpid(silcd);
713
714   /* Initialize the server */
715   if (silc_server_init(silcd) == FALSE)
716     goto fail;
717
718   /* Ignore some signals */
719   sa.sa_handler = SIG_IGN;
720   sa.sa_flags = 0;
721   sigemptyset(&sa.sa_mask);
722 #if defined(SIGPIPE)
723   sigaction(SIGPIPE, &sa, NULL);      /* Ignore broken pipes */
724 #endif /* SIGPIPE*/
725 #if defined(SIGXFSZ)
726   sigaction(SIGXFSZ, &sa, NULL);      /* Ignore file limit exceeds */
727 #endif /* SIGXFSZ */
728 #if defined(SIGXCPU)
729   sigaction(SIGXCPU, &sa, NULL);      /* Ignore CPU time limit exceeds */
730 #endif /* SIGXCPU */
731
732   /* Handle specificly some other signals. */
733   silc_schedule_task_add_signal(silcd->schedule, SIGHUP, got_hup, NULL);
734   silc_schedule_task_add_signal(silcd->schedule, SIGTERM, stop_server, NULL);
735   silc_schedule_task_add_signal(silcd->schedule, SIGINT, stop_server, NULL);
736   silc_schedule_task_add_signal(silcd->schedule, SIGUSR1, dump_stats, NULL);
737
738   if (!foreground) {
739     /* Before running the server, fork to background. */
740     silc_server_daemonise(silcd);
741
742     /* If set, write pid to file */
743     if (silcd->config->server_info->pid_file) {
744       char buf[10], *pidfile = silcd->config->server_info->pid_file;
745       unlink(pidfile);
746       snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
747       silc_file_writefile(pidfile, buf, strlen(buf));
748     }
749
750     silc_server_drop_privs(silcd);
751   }
752
753   /* Run the server. When this returns the server has been stopped
754      and we will exit. */
755   silc_server_run(silcd);
756
757   /* Stop the server and free it. */
758   silc_server_stop(silcd);
759   silc_server_config_destroy(silcd->config);
760   silc_server_free(silcd);
761
762   /* Flush the logging system */
763   silc_log_flush_all();
764
765   silc_free(silcd_config_file);
766   silc_free(opt_identifier);
767   silc_free(opt_keypath);
768   exit(0);
769
770  fail:
771   silc_free(silcd_config_file);
772   silc_free(opt_identifier);
773   silc_free(opt_keypath);
774   exit(1);
775 }