de4ad03a6579fbefb9157ca69caf0eb24e2e4e8b
[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   silc_server_stop(silcd);
249 }
250
251 /* Dump server statistics into a file into /tmp directory */
252
253 SILC_TASK_CALLBACK(dump_stats)
254 {
255   FILE *fdd;
256   int fild;
257   char filename[256];
258
259   memset(filename, 0, sizeof(filename));
260   snprintf(filename, sizeof(filename) - 1, "/tmp/silcd.%d.stats-XXXXXX", getpid());
261   fild = mkstemp(filename);
262   if (fild == -1)
263     return;
264
265   fdd = fdopen(fild, "w");
266   if (fdd == NULL) {
267     close(fild);
268     unlink(filename);
269     return;
270   }
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   /* Dump internal flags */
313   fprintf(fdd, "\nDumping internal flags\n");
314   fprintf(fdd, "  server_type            : %d\n", silcd->server_type);
315   fprintf(fdd, "  standalone             : %d\n", silcd->standalone);
316   fprintf(fdd, "  listenning             : %d\n", silcd->listenning);
317   fprintf(fdd, "  background             : %d\n", silcd->background);
318   fprintf(fdd, "  backup_router          : %d\n", silcd->backup_router);
319   fprintf(fdd, "  backup_primary         : %d\n", silcd->backup_primary);
320   fprintf(fdd, "  backup_noswitch        : %d\n", silcd->backup_noswitch);
321   fprintf(fdd, "  backup_closed          : %d\n", silcd->backup_closed);
322   fprintf(fdd, "  wait_backup            : %d\n", silcd->wait_backup);
323   if (silcd->router)
324     fprintf(fdd, "  primary router         : %s\n",
325       silcd->router->server_name ? silcd->router->server_name : "");
326
327   /* Dump connections */
328   {
329     SilcPacketStream s;
330     SilcDList conns = silc_packet_engine_get_streams(silcd->packet_engine);
331
332     fprintf(fdd, "\nDumping connections\n");
333     silc_dlist_start(conns);
334     while ((s = silc_dlist_get(conns))) {
335       const char *hostname, *ip;
336       SilcUInt16 port;
337       SilcSocket sock;
338       SilcIDListData idata = silc_packet_get_context(s);
339       if (!silc_socket_stream_get_info(silc_packet_stream_get_stream(s),
340                                        &sock, &hostname, &ip, &port))
341         continue;
342       fprintf(fdd, "  %d: host %s ip %s port %d type %d idata %p\n",
343               sock, hostname ? hostname : "N/A",
344               ip ? ip : "N/A", port, idata ? idata->conn_type : 0, idata);
345     }
346     silc_dlist_uninit(conns);
347   }
348
349   /* Dump lists */
350   {
351     SilcList list;
352     SilcIDCacheEntry id_cache = NULL;
353     SilcServerEntry server_entry;
354     SilcClientEntry client_entry;
355     SilcChannelEntry channel_entry;
356     int c;
357
358     fprintf(fdd, "\nDumping databases\n");
359
360     if (silc_idcache_get_all(silcd->local_list->servers, &list)) {
361       c = 1;
362       fprintf(fdd, "\nServers in local-list:\n");
363       silc_list_start(list);
364       while ((id_cache = silc_list_get(list))) {
365           server_entry = (SilcServerEntry)id_cache->context;
366           fprintf(fdd, "  %d: name %s id %s status 0x%x idata %p\n", c,
367                   server_entry->server_name ? server_entry->server_name :
368                   "N/A", server_entry->id ?
369                   silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
370                   server_entry->data.status, server_entry);
371           c++;
372       }
373     }
374     if (silc_idcache_get_all(silcd->global_list->servers, &list)) {
375         fprintf(fdd, "\nServers in global-list:\n");
376         c = 1;
377         silc_list_start(list);
378         while ((id_cache = silc_list_get(list))) {
379           server_entry = (SilcServerEntry)id_cache->context;
380           fprintf(fdd, "  %d: name %s id %s status 0x%x idata %p\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, server_entry);
385           c++;
386         }
387     }
388     if (silc_idcache_get_all(silcd->local_list->clients, &list)) {
389         fprintf(fdd, "\nClients in local-list:\n");
390         c = 1;
391         silc_list_start(list);
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 idata %p\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", client_entry);
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         silc_list_start(list);
409         while ((id_cache = silc_list_get(list))) {
410           client_entry = (SilcClientEntry)id_cache->context;
411           server_entry = client_entry->router;
412           fprintf(fdd, "  %d: name %s id %s status 0x%x from %s idata %p\n", c,
413                   client_entry->nickname ? client_entry->nickname :
414                   (unsigned char *)"N/A", client_entry->id ?
415                   silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
416                   client_entry->data.status, server_entry ?
417                   server_entry->server_name ? server_entry->server_name :
418                   "N/A" : "local", client_entry);
419           c++;
420         }
421     }
422     if (silc_idcache_get_all(silcd->local_list->channels, &list)) {
423         fprintf(fdd, "\nChannels in local-list:\n");
424         c = 1;
425         silc_list_start(list);
426         while ((id_cache = silc_list_get(list))) {
427           channel_entry = (SilcChannelEntry)id_cache->context;
428           fprintf(fdd, "  %d: name %s id %s\n", c,
429                   channel_entry->channel_name ? channel_entry->channel_name :
430                   "N/A", channel_entry->id ?
431                   silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
432           c++;
433         }
434     }
435     if (silc_idcache_get_all(silcd->global_list->channels, &list)) {
436         fprintf(fdd, "\nChannels in global-list:\n");
437         c = 1;
438         silc_list_start(list);
439         while ((id_cache = silc_list_get(list))) {
440           channel_entry = (SilcChannelEntry)id_cache->context;
441           fprintf(fdd, "  %d: name %s id %s\n", c,
442                   channel_entry->channel_name ? channel_entry->channel_name :
443                   "N/A", channel_entry->id ?
444                   silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
445           c++;
446         }
447     }
448   }
449
450   fflush(fdd);
451   fclose(fdd);
452 }
453
454 #ifdef SILC_DEBUG
455
456 typedef struct {
457   int level;
458   const char *string;
459 } DebugLevel;
460
461 static DebugLevel debug_levels[] = {
462   /* Very basic stuff from silcd/ */
463   { 3, "silcd\\.c,server\\.c" },
464
465   /* More stuff from silcd/ */
466   { 7, "silcd\\.c,server\\.c,command\\.c,server_backup\\.c,packet_send\\.c" },
467
468   /* All basic stuff from silcd/ */
469   { 10, "silc_server_*,*silc_id_create_*,*idlist*,*skr*" },
470
471   /* All from silcd/ */
472   { 15, "*silcd*,*serverid*,silc_server_*,*idlist*,*skr*" },
473
474   /* All from silcd/ and basic stuff from libs */
475   { 20, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,*silcske*,"
476     "*skr*" },
477
478   /* All from silcd/ and more stuff from libs */
479   { 25, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
480     "*silcpacket*,*ske*,*silcrng*,*skr*" },
481
482   /* All from silcd/ and even more stuff from libs */
483   { 30, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,*skr*"
484     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" },
485
486   /* All from silcd/ and even more stuff from libs + all from silccore */
487   { 35, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,*skr*"
488     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
489     "*silcid*,*argument*" },
490
491   /* All from silcd/, all from silccore, silccrypt and silcmath */
492   { 40, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,*skr*"
493     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
494     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*" },
495
496   /* All from silcd/, all from silccore, silccrypt and silcmath + stuff
497      from silcutil */
498   { 45, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,*skr*"
499     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
500     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
501     "*sockconn*" },
502
503   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
504      from silcutil */
505   { 50, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,*skr*"
506     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
507     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
508     "*sockconn*,*net*" },
509
510   /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
511      from silcutil */
512   { 55, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,*skr*"
513     "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
514     "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
515     "*sockconn*,*net*,*log*,*config*" },
516
517   /* All */
518   { 90, "*" },
519
520   { -1, NULL },
521 };
522
523 static void silc_get_debug_level(int level)
524 {
525   int i;
526
527   if (level < 0)
528     return;
529
530   for (i = 0; debug_levels[i].string; i++)
531     if (level <= debug_levels[i].level) {
532       silc_log_set_debug_string(debug_levels[i].string);
533       break;
534     }
535 }
536 #endif /* SILC_DEBUG */
537
538 /* This function should not be called directly but through the appropriate
539    wrapper macro defined in server.h */
540
541 void silc_server_stderr(SilcLogType type, char *message)
542 {
543   if (silcd->background) {
544     char *p, *n = message;
545
546     /* remove newlines if we are going to output it to a log file */
547     for (p = n; *p; p++) {
548       if (*p != '\n') {
549         if (p != n)
550           *n = *p;
551         n++;
552       }
553     }
554     *n = 0;
555
556     /* the message is freed inside the logging function */
557     silc_log_output(type, message);
558   }
559   else {
560     fprintf(stderr, "%s\n", message);
561     silc_free(message);
562   }
563 }
564
565 #ifdef SILC_DEBUG
566 #define NUM_DEBUGS 3000
567 static char debugs[NUM_DEBUGS][128];
568 static int cur_debug = 0;
569
570 SilcBool silc_server_debug_callback(char *file, char *function, int line,
571                                     char *message, void *context)
572 {
573   SilcTimeStruct curtime;
574
575   /* Save the message to ring buffer */
576   silc_time_value(0, &curtime);
577   silc_snprintf(debugs[cur_debug % NUM_DEBUGS], sizeof(debugs[0]),
578                 "%02d:%02d:%02d %s:%d: %s", curtime.hour,
579                 curtime.minute, curtime.second, function, line,
580                 message);
581   cur_debug++;
582
583   return FALSE;
584 }
585 #endif /* SILC_DEBUG */
586
587 int main(int argc, char **argv)
588 {
589   int ret, opt, option_index;
590   SilcBool foreground = FALSE;
591   SilcBool opt_create_keypair = FALSE;
592   char *silcd_config_file = NULL;
593   struct sigaction sa;
594
595 #ifdef SILC_DEBUG
596   silc_log_set_debug_callbacks(silc_server_debug_callback, NULL, NULL, NULL);
597 #endif /* SILC_DEBUG */
598
599   /* Parse command line arguments */
600   if (argc > 1) {
601 #ifdef HAVE_GETOPT_LONG
602     while ((opt = getopt_long(argc, argv, "f:p:d:D:xhFVC:",
603                               long_opts, &option_index)) != EOF) {
604 #else
605     while ((opt = getopt(argc, argv, "f:p:d:D:xhFVC:")) != EOF) {
606 #endif /* HAVE_GETOPT_LONG */
607       switch(opt) {
608         case 'h':
609           silc_usage();
610           break;
611         case 'V':
612           printf("SILCd Secure Internet Live Conferencing daemon, "
613                  "version %s (base: SILC Toolkit %s)\n",
614                  silc_dist_version, silc_version);
615           printf("(c) 1997 - 2007 Pekka Riikonen "
616                  "<priikone@silcnet.org>\n");
617           exit(0);
618           break;
619         case 'd':
620 #ifdef SILC_DEBUG
621           silc_log_debug(TRUE);
622           silc_log_quick(TRUE);
623           if (optarg)
624             silc_log_set_debug_string(optarg);
625           foreground = TRUE;        /* implied */
626 #else
627           fprintf(stderr,
628                   "Run-time debugging is not enabled. To enable it recompile\n"
629                   "the server with --enable-debug configuration option.\n");
630 #endif
631           break;
632         case 'D':
633 #ifdef SILC_DEBUG
634           silc_log_debug(TRUE);
635           silc_log_quick(TRUE);
636           if (optarg)
637             silc_get_debug_level(atoi(optarg));
638           foreground = TRUE;        /* implied */
639 #else
640           fprintf(stderr,
641                   "Run-time debugging is not enabled. To enable it recompile\n"
642                   "the server with --enable-debug configuration option.\n");
643 #endif
644           break;
645         case 'x':
646 #ifdef SILC_DEBUG
647           silc_log_debug(TRUE);
648           silc_log_debug_hexdump(TRUE);
649           silc_log_quick(TRUE);
650           foreground = TRUE; /* implied */
651 #else
652           fprintf(stderr,
653                   "Run-time debugging is not enabled. To enable it recompile\n"
654                   "the server with --enable-debug configuration option.\n");
655 #endif
656           break;
657         case 'f':
658           silcd_config_file = strdup(optarg);
659           break;
660         case 'F':
661           foreground = TRUE;
662           break;
663
664           /*
665            * Key management options
666            */
667         case 'C':
668           opt_create_keypair = TRUE;
669           if (optarg)
670             opt_keypath = strdup(optarg);
671           break;
672         case 10:
673           if (optarg)
674             opt_pkcs = strdup(optarg);
675           break;
676         case 11:
677           if (optarg)
678             opt_bits = atoi(optarg);
679           break;
680         case 12:
681           if (optarg)
682             opt_identifier = strdup(optarg);
683           break;
684
685         default:
686           silc_usage();
687           break;
688       }
689     }
690   }
691
692   if (opt_create_keypair == TRUE) {
693     /* Create new key pair and exit */
694     char pubfile[256], prvfile[256];
695
696     memset(pubfile, 0, sizeof(pubfile));
697     memset(prvfile, 0, sizeof(prvfile));
698     snprintf(pubfile, sizeof(pubfile) - 1, "%s/silcd.pub", opt_keypath);
699     snprintf(prvfile, sizeof(prvfile) - 1, "%s/silcd.prv", opt_keypath);
700
701     silc_cipher_register_default();
702     silc_pkcs_register_default();
703     silc_hash_register_default();
704     silc_hmac_register_default();
705     if (!silc_create_key_pair(opt_pkcs, opt_bits, pubfile, prvfile,
706                               opt_identifier, "", NULL, NULL, FALSE))
707       exit(1);
708     exit(0);
709   }
710
711   /* Default configuration file */
712   if (!silcd_config_file)
713     silcd_config_file = strdup(SILC_SERVER_CONFIG_FILE);
714
715   /* Create SILC Server object */
716   ret = silc_server_alloc(&silcd);
717   if (ret == FALSE)
718     goto fail;
719
720   /* Register default crypto stuff since we are going to need them
721      in the configuration file parsing phase */
722   silc_cipher_register_default();
723   silc_pkcs_register_default();
724   silc_hash_register_default();
725   silc_hmac_register_default();
726
727   /* Read configuration files */
728   silcd->config = silc_server_config_alloc(silcd_config_file, silcd);
729   if (silcd->config == NULL)
730     goto fail;
731   silcd->config_file = silcd_config_file;
732
733   /* Unregister the default crypto stuff so that configuration takes effect */
734   silc_cipher_unregister_all();
735   /* silc_pkcs_unregister_all();  MUST NOT do this anymore; SilcPublicKey
736      parsed from config file references pointers so we cannot unregister */
737   silc_hash_unregister_all();
738   silc_hmac_unregister_all();
739
740   /* Check for another silcd running */
741   silc_server_checkpid(silcd);
742
743   /* Initialize the server */
744   if (silc_server_init(silcd) == FALSE)
745     goto fail;
746
747   /* Ignore some signals */
748   sa.sa_handler = SIG_IGN;
749   sa.sa_flags = 0;
750   sigemptyset(&sa.sa_mask);
751 #if defined(SIGPIPE)
752   sigaction(SIGPIPE, &sa, NULL);      /* Ignore broken pipes */
753 #endif /* SIGPIPE*/
754 #if defined(SIGXFSZ)
755   sigaction(SIGXFSZ, &sa, NULL);      /* Ignore file limit exceeds */
756 #endif /* SIGXFSZ */
757 #if defined(SIGXCPU)
758   sigaction(SIGXCPU, &sa, NULL);      /* Ignore CPU time limit exceeds */
759 #endif /* SIGXCPU */
760
761   /* Handle specificly some other signals. */
762   silc_schedule_task_add_signal(silcd->schedule, SIGHUP, got_hup, NULL);
763   silc_schedule_task_add_signal(silcd->schedule, SIGTERM, stop_server, NULL);
764   silc_schedule_task_add_signal(silcd->schedule, SIGINT, stop_server, NULL);
765   silc_schedule_task_add_signal(silcd->schedule, SIGUSR1, dump_stats, NULL);
766
767   if (!foreground) {
768     /* Before running the server, fork to background. */
769     silc_server_daemonise(silcd);
770
771     /* If set, write pid to file */
772     if (silcd->config->server_info->pid_file) {
773       char buf[10], *pidfile = silcd->config->server_info->pid_file;
774       unlink(pidfile);
775       snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
776       silc_file_writefile(pidfile, buf, strlen(buf));
777     }
778
779   }
780   silc_server_drop_privs(silcd);
781
782   /* Run the server. When this returns the server has been stopped
783      and we will exit. */
784   silc_server_run(silcd);
785
786   /* Free server */
787   silc_server_config_destroy(silcd->config);
788   silc_server_free(silcd);
789
790   /* Flush the logging system */
791   silc_log_flush_all();
792
793   silc_free(silcd_config_file);
794   silc_free(opt_identifier);
795   silc_free(opt_keypath);
796   exit(0);
797
798  fail:
799   silc_free(silcd_config_file);
800   silc_free(opt_identifier);
801   silc_free(opt_keypath);
802   exit(1);
803 }