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