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