updates.
[silc.git] / apps / silcd / silcd.c
1 /*
2
3   silcd.c
4   
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2001 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 "version.h"
31
32 static void silc_usage();
33 static char *silc_server_create_identifier();
34 static int 
35 silc_server_create_key_pair(char *pkcs_name, int bits, char *path,
36                             char *identifier, 
37                             SilcPublicKey *ret_pub_key,
38                             SilcPrivateKey *ret_prv_key);
39
40 /* Long command line options */
41 static struct option long_opts[] = 
42 {
43   { "config-file", 1, NULL, 'f' },
44   { "debug", 1, NULL, 'd' },
45   { "help", 0, NULL, 'h' },
46   { "version", 0, NULL,'V' },
47
48   /* Key management options */
49   { "create-key-pair", 1, NULL, 'C' },
50   { "pkcs", 1, NULL, 10 },
51   { "bits", 1, NULL, 11 },
52   { "identifier", 1, NULL, 12 },
53
54   { NULL, 0, NULL, 0 }
55 };
56
57 /* Command line option variables */
58 static bool opt_create_keypair = FALSE;
59 static char *opt_keypath = NULL;
60 static char *opt_pkcs = "rsa";
61 static char *opt_identifier = NULL;
62 static int opt_bits = 1024;
63
64 /* Prints out the usage of silc client */
65
66 static void silc_usage()
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 (no daemon)\n\
74   -h  --help                    Display this message\n\
75   -V  --version                 Display version\n\
76 \n\
77   Key Management Options:\n\
78   -C, --create-key-pair=PATH    Create new public key pair\n\
79       --pkcs=PKCS               Set the PKCS of the public key pair\n\
80       --bits=VALUE              Set length of the public key pair\n\
81       --identifier=IDENTIFIER   Public key identifier\n\
82 \n\
83       The public key identifier may be of the following format:\n\
84 \n\
85       UN=<username>, HN=<hostname or IP>, RN=<real name>, E=<email>,\n\
86       O=<organization>, C=<country>\n\
87 \n\
88       The UN and HN must be provided, the others are optional.  If the\n\
89       --identifier option is not used an identifier will be created for\n\
90       the public key automatically.\n\
91 \n\
92       Example identifier: \"UN=foobar, HN=foo.bar.com, RN=Foo T. Bar, \n\
93                            E=foo@bar.com, C=FI\"\n\
94 \n");
95   exit(0);
96 }
97
98 int main(int argc, char **argv)
99 {
100   int ret;
101   int opt, option_index;
102   char *config_file = NULL;
103   SilcServer silcd;
104   struct sigaction sa;
105   char pid[10];
106
107   silc_debug = FALSE;
108
109   /* Parse command line arguments */
110   if (argc > 1) {
111     while ((opt = getopt_long(argc, argv, "cf:d:hVC:",
112                               long_opts, &option_index)) != EOF) {
113       switch(opt) 
114         {
115         case 'h':
116           silc_usage();
117           break;
118         case 'V':
119           printf("SILCd Secure Internet Live Conferencing daemon, "
120                  "version %s (base: SILC Toolkit %s)\n",
121                  silc_dist_version, silc_version);
122           printf("(c) 1997 - 2001 Pekka Riikonen "
123                  "<priikone@silcnet.org>\n");
124           exit(0);
125           break;
126         case 'd':
127           silc_debug = TRUE;
128           silc_debug_hexdump = TRUE;
129           silc_log_set_debug_string(optarg);
130           break;
131         case 'f':
132           config_file = strdup(optarg);
133           break;
134
135           /*
136            * Key management options
137            */
138         case 'C':
139           opt_create_keypair = TRUE;
140           if (optarg)
141             opt_keypath = strdup(optarg);
142           break;
143         case 10:
144           if (optarg)
145             opt_pkcs = strdup(optarg);
146           break;
147         case 11:
148           if (optarg)
149             opt_bits = atoi(optarg);
150           break;
151         case 12:
152           if (optarg)
153             opt_identifier = strdup(optarg);
154           break;
155
156         default:
157           silc_usage();
158           break;
159         }
160     }
161   }
162
163   if (opt_create_keypair == TRUE) {
164     /* Create new key pair and exit */
165     silc_cipher_register_default();
166     silc_pkcs_register_default();
167     silc_hash_register_default();
168     silc_hmac_register_default();
169     silc_server_create_key_pair(opt_pkcs, opt_bits, opt_keypath,
170                                 opt_identifier, NULL, NULL);
171     exit(0);
172   }
173
174   /* Default configuration file */
175   if (!config_file)
176     config_file = strdup(SILC_SERVER_CONFIG_FILE);
177
178   /* Create SILC Server object */
179   ret = silc_server_alloc(&silcd);
180   if (ret == FALSE)
181     goto fail;
182
183   /* Read configuration files */
184   silcd->config = silc_server_config_alloc(config_file);
185   if (silcd->config == NULL)
186     goto fail;
187
188   /* Initialize the server */
189   ret = silc_server_init(silcd);
190   if (ret == FALSE)
191     goto fail;
192
193   /* Ignore SIGPIPE */
194   sa.sa_handler = SIG_IGN;
195   sa.sa_flags = 0;
196   sigemptyset(&sa.sa_mask);
197   sigaction(SIGPIPE, &sa, NULL);
198
199   if (silc_debug == FALSE)
200     /* Before running the server, fork to background and set
201        both user and group no non-root */    
202     silc_server_daemonise(silcd);
203
204   /* Set /var/run/silcd.pid */
205   unlink(SILC_SERVER_PID_FILE);
206   memset(pid, 0, sizeof(pid));
207   snprintf(pid, sizeof(pid) - 1, "%d\n", getpid());
208   silc_file_writefile(SILC_SERVER_PID_FILE, pid, strlen(pid));
209   
210   /* Run the server. When this returns the server has been stopped
211      and we will exit. */
212   silc_server_run(silcd);
213   
214   /* Stop the server. This probably has been done already but it
215      doesn't hurt to do it here again. */
216   silc_server_stop(silcd);
217   silc_server_free(silcd);
218   
219   exit(0);
220  fail:
221   exit(1);
222 }
223
224 /* Returns identifier string for public key generation. */
225
226 static char *silc_server_create_identifier()
227 {
228   char *username = NULL, *realname = NULL;
229   char hostname[256], email[256];
230   
231   /* Get realname */
232   realname = silc_get_real_name();
233
234   /* Get hostname */
235   memset(hostname, 0, sizeof(hostname));
236   gethostname(hostname, sizeof(hostname));
237
238   /* Get username (mandatory) */
239   username = silc_get_username();
240   if (!username)
241     return NULL;
242
243   /* Create default email address, whether it is right or not */
244   snprintf(email, sizeof(email), "%s@%s", username, hostname);
245
246   return silc_pkcs_encode_identifier(username, hostname, realname, email,
247                                      NULL, NULL);
248 }
249
250 /* Creates new public key and private key pair. This is used only
251    when user wants to create new key pair from command line. */
252
253 static int 
254 silc_server_create_key_pair(char *pkcs_name, int bits, char *path,
255                             char *identifier, 
256                             SilcPublicKey *ret_pub_key,
257                             SilcPrivateKey *ret_prv_key)
258 {
259   SilcPKCS pkcs;
260   SilcPublicKey pub_key;
261   SilcPrivateKey prv_key;
262   SilcRng rng;
263   unsigned char *key;
264   uint32 key_len;
265   char pkfile[256], prvfile[256];
266
267   if (!pkcs_name || !path)
268     return FALSE;
269
270   if (!silc_pkcs_is_supported(pkcs_name)) {
271     fprintf(stderr, "Unsupported PKCS `%s'", pkcs_name);
272     return FALSE;
273   }
274
275   if (!bits)
276     bits = 1024;
277
278   if (!identifier)
279     identifier = silc_server_create_identifier();
280
281   rng = silc_rng_alloc();
282   silc_rng_init(rng);
283   silc_rng_global_init(rng);
284
285   snprintf(pkfile, sizeof(pkfile) - 1, "%s%s", path,
286            SILC_SERVER_PUBLIC_KEY_NAME);
287   snprintf(prvfile, sizeof(prvfile) - 1, "%s%s", path,
288            SILC_SERVER_PRIVATE_KEY_NAME);
289
290   /* Generate keys */
291   silc_pkcs_alloc(pkcs_name, &pkcs);
292   pkcs->pkcs->init(pkcs->context, bits, rng);
293
294   /* Save public key into file */
295   key = silc_pkcs_get_public_key(pkcs, &key_len);
296   pub_key = silc_pkcs_public_key_alloc(pkcs->pkcs->name, identifier,
297                                        key, key_len);
298   silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
299   if (ret_pub_key)
300     *ret_pub_key = pub_key;
301   else
302     silc_pkcs_public_key_free(pub_key);
303
304   memset(key, 0, sizeof(key_len));
305   silc_free(key);
306
307   /* Save private key into file */
308   key = silc_pkcs_get_private_key(pkcs, &key_len);
309   prv_key = silc_pkcs_private_key_alloc(pkcs->pkcs->name, key, key_len);
310   silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN);
311   if (ret_prv_key)
312     *ret_prv_key = prv_key;
313   else
314     silc_pkcs_private_key_free(prv_key);
315
316   printf("Public key has been saved into `%s'\n", pkfile);
317   printf("Private key has been saved into `%s'\n", prvfile);
318
319   memset(key, 0, sizeof(key_len));
320   silc_free(key);
321
322   silc_rng_free(rng);
323   silc_pkcs_free(pkcs);
324
325   return TRUE;
326 }