Merged silc_1_0_branch to trunk.
[silc.git] / apps / silcd / silcd.c
1 /*
2
3   silcd.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2005 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 static void signal_handler(int sig)
238 {
239   /* Mark the signal to be caller after this signal is over. */
240   silc_schedule_signal_call(silcd->schedule, sig);
241 }
242
243 SILC_TASK_CALLBACK(got_hup)
244 {
245   /* First, reset all log files (they might have been deleted) */
246   silc_log_reset_all();
247
248   /* Rehash the configuration file */
249   silc_server_rehash(silcd);
250 }
251
252 SILC_TASK_CALLBACK(stop_server)
253 {
254   /* Stop scheduler, the program will stop eventually after noticing
255      that the scheduler is down. */
256   silc_schedule_stop(silcd->schedule);
257 }
258
259 /* Dump server statistics into a file into /tmp directory */
260
261 SILC_TASK_CALLBACK(dump_stats)
262 {
263   FILE *fdd;
264   char filename[256];
265
266   memset(filename, 0, sizeof(filename));
267   snprintf(filename, sizeof(filename) - 1, "/tmp/silcd.%d.stats", getpid());
268   fdd = fopen(filename, "w+");
269   if (!fdd)
270     return;
271
272 #define STAT_OUTPUT(fmt, stat) fprintf(fdd, fmt "\n", (int)stat);
273
274   fprintf(fdd, "SILC Server %s Statistics\n\n", silcd->server_name);
275   fprintf(fdd, "Local Stats:\n");
276   STAT_OUTPUT("  My clients              : %d", silcd->stat.my_clients);
277   STAT_OUTPUT("  My servers              : %d", silcd->stat.my_servers);
278   STAT_OUTPUT("  My routers              : %d", silcd->stat.my_routers);
279   STAT_OUTPUT("  My channels             : %d", silcd->stat.my_channels);
280   STAT_OUTPUT("  My joined users         : %d", silcd->stat.my_chanclients);
281   STAT_OUTPUT("  My aways                : %d", silcd->stat.my_aways);
282   STAT_OUTPUT("  My detached clients     : %d", silcd->stat.my_detached);
283   STAT_OUTPUT("  My server operators     : %d", silcd->stat.my_server_ops);
284   STAT_OUTPUT("  My router operators     : %d", silcd->stat.my_router_ops);
285   fprintf(fdd, "\nGlobal Stats:\n");
286   STAT_OUTPUT("  Cell clients            : %d", silcd->stat.cell_clients);
287   STAT_OUTPUT("  Cell servers            : %d", silcd->stat.cell_servers);
288   STAT_OUTPUT("  Cell channels           : %d", silcd->stat.cell_channels);
289   STAT_OUTPUT("  Cell joined users       : %d", silcd->stat.cell_chanclients);
290   STAT_OUTPUT("  All clients             : %d", silcd->stat.clients);
291   STAT_OUTPUT("  All servers             : %d", silcd->stat.servers);
292   STAT_OUTPUT("  All routers             : %d", silcd->stat.routers);
293   STAT_OUTPUT("  All channels            : %d", silcd->stat.channels);
294   STAT_OUTPUT("  All joined users        : %d", silcd->stat.chanclients);
295   STAT_OUTPUT("  All aways               : %d", silcd->stat.aways);
296   STAT_OUTPUT("  All detached clients    : %d", silcd->stat.detached);
297   STAT_OUTPUT("  All server operators    : %d", silcd->stat.server_ops);
298   STAT_OUTPUT("  All router operators    : %d", silcd->stat.router_ops);
299   fprintf(fdd, "\nGeneral Stats:\n");
300   STAT_OUTPUT("  Connection attempts     : %d", silcd->stat.conn_attempts);
301   STAT_OUTPUT("  Connection failures     : %d", silcd->stat.conn_failures);
302   STAT_OUTPUT("  Authentication attempts : %d", silcd->stat.auth_attempts);
303   STAT_OUTPUT("  Authentication failures : %d", silcd->stat.auth_failures);
304   STAT_OUTPUT("  Packets sent            : %d", silcd->stat.packets_sent);
305   STAT_OUTPUT("  Packets received        : %d", silcd->stat.packets_received);
306   STAT_OUTPUT("  Commands sent           : %d", silcd->stat.commands_sent);
307   STAT_OUTPUT("  Commands received       : %d", silcd->stat.commands_received);
308   STAT_OUTPUT("  Connections             : %d", silcd->stat.conn_num);
309
310 #undef STAT_OUTPUT
311
312 #ifdef SILC_DEBUG
313   /* Dump internal flags */
314   fprintf(fdd, "\nDumping internal flags\n");
315   fprintf(fdd, "  server_type            : %d\n", silcd->server_type);
316   fprintf(fdd, "  standalone             : %d\n", silcd->standalone);
317   fprintf(fdd, "  listenning             : %d\n", silcd->listenning);
318   fprintf(fdd, "  background             : %d\n", silcd->background);
319   fprintf(fdd, "  backup_router          : %d\n", silcd->backup_router);
320   fprintf(fdd, "  backup_primary         : %d\n", silcd->backup_primary);
321   fprintf(fdd, "  backup_noswitch        : %d\n", silcd->backup_noswitch);
322   fprintf(fdd, "  backup_closed          : %d\n", silcd->backup_closed);
323   fprintf(fdd, "  wait_backup            : %d\n", silcd->wait_backup);
324   if (silcd->router)
325     fprintf(fdd, "  primary router         : %s\n",
326       silcd->router->server_name ? silcd->router->server_name : "");
327
328   /* Dump socket connections */
329   {
330     int i;
331     SilcSocketConnection s;
332
333     fprintf(fdd, "\nDumping socket connections\n");
334     for (i = 0; i < silcd->config->param.connections_max; i++) {
335       s = silcd->sockets[i];
336       if (!s)
337         continue;
338       fprintf(fdd, "  %d: host %s ip %s port %d type %d flags 0x%x\n",
339               s->sock, s->hostname ? s->hostname : "N/A",
340               s->ip ? s->ip : "N/A", s->port, s->type,
341               (unsigned int)s->flags);
342     }
343   }
344
345   /* Dump lists */
346   {
347     SilcIDCacheList list = NULL;
348     SilcIDCacheEntry id_cache = NULL;
349     SilcServerEntry server_entry;
350     SilcClientEntry client_entry;
351     SilcChannelEntry channel_entry;
352     int c;
353
354     fprintf(fdd, "\nDumping databases\n");
355
356     if (silc_idcache_get_all(silcd->local_list->servers, &list)) {
357       if (silc_idcache_list_first(list, &id_cache)) {
358         fprintf(fdd, "\nServers in local-list:\n");
359         c = 1;
360         while (id_cache) {
361           server_entry = (SilcServerEntry)id_cache->context;
362           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
363                   server_entry->server_name ? server_entry->server_name :
364                   "N/A", server_entry->id ?
365                   silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
366                   server_entry->data.status);
367           if (!silc_idcache_list_next(list, &id_cache))
368             break;
369           c++;
370         }
371       }
372       silc_idcache_list_free(list);
373     }
374     if (silc_idcache_get_all(silcd->global_list->servers, &list)) {
375       if (silc_idcache_list_first(list, &id_cache)) {
376         fprintf(fdd, "\nServers in global-list:\n");
377         c = 1;
378         while (id_cache) {
379           server_entry = (SilcServerEntry)id_cache->context;
380           fprintf(fdd, "  %d: name %s id %s status 0x%x\n", c,
381                   server_entry->server_name ? server_entry->server_name :
382                   "N/A", server_entry->id ?
383                   silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
384                   server_entry->data.status);
385           if (!silc_idcache_list_next(list, &id_cache))
386             break;
387           c++;
388         }
389       }
390       silc_idcache_list_free(list);
391     }
392     if (silc_idcache_get_all(silcd->local_list->clients, &list)) {
393       if (silc_idcache_list_first(list, &id_cache)) {
394         fprintf(fdd, "\nClients in local-list:\n");
395         c = 1;
396         while (id_cache) {
397           client_entry = (SilcClientEntry)id_cache->context;
398           server_entry = client_entry->router;
399           fprintf(fdd, "  %d: name %s id %s status 0x%x from %s\n", c,
400                   client_entry->nickname ? client_entry->nickname :
401                   (unsigned char *)"N/A", client_entry->id ?
402                   silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
403                   client_entry->data.status, server_entry ?
404                   server_entry->server_name ? server_entry->server_name :
405                   "N/A" : "local");
406           if (!silc_idcache_list_next(list, &id_cache))
407             break;
408           c++;
409         }
410       }
411       silc_idcache_list_free(list);
412     }
413     if (silc_idcache_get_all(silcd->global_list->clients, &list)) {
414       if (silc_idcache_list_first(list, &id_cache)) {
415         fprintf(fdd, "\nClients in global-list:\n");
416         c = 1;
417         while (id_cache) {
418           client_entry = (SilcClientEntry)id_cache->context;
419           server_entry = client_entry->router;
420           fprintf(fdd, "  %d: name %s id %s status 0x%x from %s\n", c,
421                   client_entry->nickname ? client_entry->nickname :
422                   (unsigned char *)"N/A", client_entry->id ?
423                   silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
424                   client_entry->data.status, server_entry ?
425                   server_entry->server_name ? server_entry->server_name :
426                   "N/A" : "local");
427           if (!silc_idcache_list_next(list, &id_cache))
428             break;
429           c++;
430         }
431       }
432       silc_idcache_list_free(list);
433     }
434     if (silc_idcache_get_all(silcd->local_list->channels, &list)) {
435       if (silc_idcache_list_first(list, &id_cache)) {
436         fprintf(fdd, "\nChannels in local-list:\n");
437         c = 1;
438         while (id_cache) {
439           channel_entry = (SilcChannelEntry)id_cache->context;
440           fprintf(fdd, "  %d: name %s id %s\n", c,
441                   channel_entry->channel_name ? channel_entry->channel_name :
442                   "N/A", channel_entry->id ?
443                   silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
444           if (!silc_idcache_list_next(list, &id_cache))
445             break;
446           c++;
447         }
448       }
449       silc_idcache_list_free(list);
450     }
451     if (silc_idcache_get_all(silcd->global_list->channels, &list)) {
452       if (silc_idcache_list_first(list, &id_cache)) {
453         fprintf(fdd, "\nChannels in global-list:\n");
454         c = 1;
455         while (id_cache) {
456           channel_entry = (SilcChannelEntry)id_cache->context;
457           fprintf(fdd, "  %d: name %s id %s\n", c,
458                   channel_entry->channel_name ? channel_entry->channel_name :
459                   "N/A", channel_entry->id ?
460                   silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
461           if (!silc_idcache_list_next(list, &id_cache))
462             break;
463           c++;
464         }
465       }
466       silc_idcache_list_free(list);
467     }
468   }
469 #endif
470
471   fflush(fdd);
472   fclose(fdd);
473 }
474
475 #ifdef SILC_DEBUG
476
477 typedef struct {
478   int level;
479   const char *string;
480 } DebugLevel;
481
482 static DebugLevel debug_levels[] = {
483   /* Very basic stuff from silcd/ */
484   { 3, "silcd\\.c,server\\.c" },
485
486   /* More stuff from silcd/ */
487   { 7, "silcd\\.c,server\\.c,command\\.c,server_backup\\.c,packet_send\\.c" },
488
489   /* All basic stuff from silcd/ */
490   { 10, "silc_server_*" },
491
492   /* All from silcd/ */
493   { 15, "*silcd*,*serverid*,silc_server_*,*idlist*" },
494
495   /* All from silcd/ and basic stuff from libs */
496   { 20, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,*silcske*" },
497
498   /* All from silcd/ and more stuff from libs */
499   { 25, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
500     "*silcpacket*,*ske*,*silcrng*" },
501
502   /* All from silcd/ and even more stuff from libs */
503   { 30, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
504     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" },
505
506   /* All from silcd/ and even more stuff from libs + all from silccore */
507   { 35, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
508     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
509     "*silcid*,*argument*" },
510
511   /* All from silcd/, all from silccore, silccrypt and silcmath */
512   { 40, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
513     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
514     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*" },
515
516   /* All from silcd/, all from silccore, silccrypt and silcmath + stuff
517      from silcutil */
518   { 45, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
519     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
520     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
521     "*sockconn*" },
522
523   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
524      from silcutil */
525   { 50, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
526     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
527     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
528     "*sockconn*,*net*" },
529
530   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
531      from silcutil */
532   { 55, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcauth*,"
533     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
534     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
535     "*sockconn*,*net*,*log*,*config*" },
536
537   /* All */
538   { 90, "*" },
539
540   { -1, NULL },
541 };
542
543 static void silc_get_debug_level(int level)
544 {
545   int i;
546
547   if (level < 0)
548     return;
549
550   for (i = 0; debug_levels[i].string; i++)
551     if (level <= debug_levels[i].level) {
552       silc_log_set_debug_string(debug_levels[i].string);
553       break;
554     }
555 }
556 #endif /* SILC_DEBUG */
557
558 /* This function should not be called directly but through the appropriate
559    wrapper macro defined in server.h */
560
561 void silc_server_stderr(SilcLogType type, char *message)
562 {
563   if (silcd->background) {
564     char *p, *n = message;
565
566     /* remove newlines if we are going to output it to a log file */
567     for (p = n; *p; p++) {
568       if (*p != '\n') {
569         if (p != n)
570           *n = *p;
571         n++;
572       }
573     }
574     *n = 0;
575
576     /* the message is freed inside the logging function */
577     silc_log_output(type, message);
578   }
579   else {
580     fprintf(stderr, "%s\n", message);
581     silc_free(message);
582   }
583 }
584
585 int main(int argc, char **argv)
586 {
587   int ret, opt, option_index;
588   bool foreground = FALSE;
589   bool opt_create_keypair = FALSE;
590   char *silcd_config_file = NULL;
591   struct sigaction sa;
592
593   /* Parse command line arguments */
594   if (argc > 1) {
595 #ifdef HAVE_GETOPT_LONG
596     while ((opt = getopt_long(argc, argv, "f:p:d:D:xhFVC:",
597                               long_opts, &option_index)) != EOF) {
598 #else
599     while ((opt = getopt(argc, argv, "f:p:d:D:xhFVC:")) != EOF) {
600 #endif /* HAVE_GETOPT_LONG */
601       switch(opt) {
602         case 'h':
603           silc_usage();
604           break;
605         case 'V':
606           printf("SILCd Secure Internet Live Conferencing daemon, "
607                  "version %s (base: SILC Toolkit %s)\n",
608                  silc_dist_version, silc_version);
609           printf("(c) 1997 - 2005 Pekka Riikonen "
610                  "<priikone@silcnet.org>\n");
611           exit(0);
612           break;
613         case 'd':
614 #ifdef SILC_DEBUG
615           silc_log_debug(TRUE);
616           silc_log_quick(TRUE);
617           if (optarg)
618             silc_log_set_debug_string(optarg);
619           foreground = TRUE;        /* implied */
620 #else
621           fprintf(stderr,
622                   "Run-time debugging is not enabled. To enable it recompile\n"
623                   "the server with --enable-debug configuration option.\n");
624 #endif
625           break;
626         case 'D':
627 #ifdef SILC_DEBUG
628           silc_log_debug(TRUE);
629           silc_log_quick(TRUE);
630           if (optarg)
631             silc_get_debug_level(atoi(optarg));
632           foreground = TRUE;        /* implied */
633 #else
634           fprintf(stderr,
635                   "Run-time debugging is not enabled. To enable it recompile\n"
636                   "the server with --enable-debug configuration option.\n");
637 #endif
638           break;
639         case 'x':
640 #ifdef SILC_DEBUG
641           silc_log_debug(TRUE);
642           silc_log_debug_hexdump(TRUE);
643           silc_log_quick(TRUE);
644           foreground = TRUE; /* implied */
645 #else
646           fprintf(stderr,
647                   "Run-time debugging is not enabled. To enable it recompile\n"
648                   "the server with --enable-debug configuration option.\n");
649 #endif
650           break;
651         case 'f':
652           silcd_config_file = strdup(optarg);
653           break;
654         case 'F':
655           foreground = TRUE;
656           break;
657
658           /*
659            * Key management options
660            */
661         case 'C':
662           opt_create_keypair = TRUE;
663           if (optarg)
664             opt_keypath = strdup(optarg);
665           break;
666         case 10:
667           if (optarg)
668             opt_pkcs = strdup(optarg);
669           break;
670         case 11:
671           if (optarg)
672             opt_bits = atoi(optarg);
673           break;
674         case 12:
675           if (optarg)
676             opt_identifier = strdup(optarg);
677           break;
678
679         default:
680           silc_usage();
681           break;
682       }
683     }
684   }
685
686   if (opt_create_keypair == TRUE) {
687     /* Create new key pair and exit */
688     char pubfile[256], prvfile[256];
689
690     memset(pubfile, 0, sizeof(pubfile));
691     memset(prvfile, 0, sizeof(prvfile));
692     snprintf(pubfile, sizeof(pubfile) - 1, "%s/silcd.pub", opt_keypath);
693     snprintf(prvfile, sizeof(prvfile) - 1, "%s/silcd.prv", opt_keypath);
694
695     silc_cipher_register_default();
696     silc_pkcs_register_default();
697     silc_hash_register_default();
698     silc_hmac_register_default();
699     silc_create_key_pair(opt_pkcs, opt_bits, pubfile, prvfile,
700                          opt_identifier, "", NULL, NULL, NULL, FALSE);
701     exit(0);
702   }
703
704   /* Default configuration file */
705   if (!silcd_config_file)
706     silcd_config_file = strdup(SILC_SERVER_CONFIG_FILE);
707
708   /* Create SILC Server object */
709   ret = silc_server_alloc(&silcd);
710   if (ret == FALSE)
711     goto fail;
712
713   /* Register default crypto stuff since we are going to need them
714      in the configuration file parsing phase */
715   silc_cipher_register_default();
716   silc_pkcs_register_default();
717   silc_hash_register_default();
718   silc_hmac_register_default();
719
720   /* Read configuration files */
721   silcd->config = silc_server_config_alloc(silcd_config_file);
722   if (silcd->config == NULL)
723     goto fail;
724   silcd->config_file = silcd_config_file;
725
726   /* Unregister the default crypto stuff so that configuration takes effect */
727   silc_cipher_unregister_all();
728   silc_pkcs_unregister_all();
729   silc_hash_unregister_all();
730   silc_hmac_unregister_all();
731
732   /* Check for another silcd running */
733   silc_server_checkpid(silcd);
734
735   /* Initialize the server */
736   if (silc_server_init(silcd) == FALSE)
737     goto fail;
738
739   /* Ignore some signals */
740   sa.sa_handler = SIG_IGN;
741   sa.sa_flags = 0;
742   sigemptyset(&sa.sa_mask);
743 #if defined(SIGPIPE)
744   sigaction(SIGPIPE, &sa, NULL);      /* Ignore broken pipes */
745 #endif /* SIGPIPE*/
746 #if defined(SIGXFSZ)
747   sigaction(SIGXFSZ, &sa, NULL);      /* Ignore file limit exceeds */
748 #endif /* SIGXFSZ */
749 #if defined(SIGXCPU)
750   sigaction(SIGXCPU, &sa, NULL);      /* Ignore CPU time limit exceeds */
751 #endif /* SIGXCPU */
752
753   /* Handle specificly some other signals. */
754   sa.sa_handler = signal_handler;
755   sigaction(SIGHUP, &sa, NULL);
756   sigaction(SIGTERM, &sa, NULL);
757   sigaction(SIGINT, &sa, NULL);
758   sigaction(SIGUSR1, &sa, NULL);
759   silc_schedule_signal_register(silcd->schedule, SIGHUP, got_hup, NULL);
760   silc_schedule_signal_register(silcd->schedule, SIGTERM, stop_server, NULL);
761   silc_schedule_signal_register(silcd->schedule, SIGINT, stop_server, NULL);
762   silc_schedule_signal_register(silcd->schedule, SIGUSR1, dump_stats, NULL);
763
764   if (!foreground) {
765     /* Before running the server, fork to background. */
766     silc_server_daemonise(silcd);
767
768     /* If set, write pid to file */
769     if (silcd->config->server_info->pid_file) {
770       char buf[10], *pidfile = silcd->config->server_info->pid_file;
771       unlink(pidfile);
772       snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
773       silc_file_writefile(pidfile, buf, strlen(buf));
774     }
775
776     silc_server_drop_privs(silcd);
777   }
778
779   /* Run the server. When this returns the server has been stopped
780      and we will exit. */
781   silc_server_run(silcd);
782
783   /* Stop the server and free it. */
784   silc_server_stop(silcd);
785   silc_server_config_destroy(silcd->config);
786   silc_server_free(silcd);
787
788   /* Flush the logging system */
789   silc_log_flush_all();
790
791   silc_free(silcd_config_file);
792   silc_free(opt_identifier);
793   silc_free(opt_keypath);
794   exit(0);
795
796  fail:
797   silc_free(silcd_config_file);
798   silc_free(opt_identifier);
799   silc_free(opt_keypath);
800   exit(1);
801 }