updates.
[silc.git] / apps / irssi / src / silc / core / clientutil.c
1 /*
2
3   client.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 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 /* $Id$ */
20
21 #include "module.h"
22
23 #include "net-nonblock.h"
24 #include "net-sendbuffer.h"
25 #include "signals.h"
26 #include "servers.h"
27 #include "commands.h"
28 #include "levels.h"
29 #include "modules.h"
30 #include "rawlog.h"
31 #include "misc.h"
32 #include "settings.h"
33
34 #include "channels-setup.h"
35
36 #include "silc-servers.h"
37 #include "silc-channels.h"
38 #include "silc-queries.h"
39 #include "silc-nicklist.h"
40 #include "window-item-def.h"
41
42 #include "fe-common/core/printtext.h"
43 #include "fe-common/core/keyboard.h"
44
45 #include "core.h"
46
47 /* Lists supported ciphers */
48
49 void silc_client_list_ciphers()
50 {
51   char *ciphers = silc_cipher_get_supported();
52   fprintf(stdout, "%s\n", ciphers);
53   silc_free(ciphers);
54 }
55
56 /* Lists supported hash functions */
57
58 void silc_client_list_hash_funcs()
59 {
60   char *hash = silc_hash_get_supported();
61   fprintf(stdout, "%s\n", hash);
62   silc_free(hash);
63 }
64
65 /* Lists supported hash functions */
66
67 void silc_client_list_hmacs()
68 {
69   char *hash = silc_hmac_get_supported();
70   fprintf(stdout, "%s\n", hash);
71   silc_free(hash);
72 }
73
74 /* Lists supported PKCS algorithms */
75
76 void silc_client_list_pkcs()
77 {
78   char *pkcs = silc_pkcs_get_supported();
79   fprintf(stdout, "%s\n", pkcs);
80   silc_free(pkcs);
81 }
82
83 /* Returns identifier string for public key generation. */
84
85 char *silc_client_create_identifier()
86 {
87   char *username = NULL, *realname = NULL;
88   char *hostname, email[256];
89   char *ident;
90   
91   /* Get realname */
92   realname = silc_get_real_name();
93
94   /* Get hostname */
95   hostname = silc_net_localhost();
96   if (!hostname)
97     return NULL;
98
99   /* Get username (mandatory) */
100   username = silc_get_username();
101   if (!username)
102     return NULL;
103
104   /* Create default email address, whether it is right or not */
105   snprintf(email, sizeof(email), "%s@%s", username, hostname);
106
107   ident = silc_pkcs_encode_identifier(username, hostname, realname, email,
108                                       NULL, NULL);
109   if (realname)
110     silc_free(realname);
111   silc_free(hostname);
112   silc_free(username);
113
114   return ident;
115 }
116
117 /* Creates new public key and private key pair. This is used only
118    when user wants to create new key pair from command line. */
119
120 int silc_client_create_key_pair(char *pkcs_name, int bits,
121                                 char *public_key, char *private_key,
122                                 char *identifier, 
123                                 SilcPublicKey *ret_pub_key,
124                                 SilcPrivateKey *ret_prv_key)
125 {
126   SilcPKCS pkcs;
127   SilcPublicKey pub_key;
128   SilcPrivateKey prv_key;
129   SilcRng rng;
130   unsigned char *key;
131   SilcUInt32 key_len;
132   char line[256];
133   char *pkfile = NULL, *prvfile = NULL;
134
135   if (!pkcs_name || !public_key || !private_key)
136     printf("\
137 New pair of keys will be created.  Please, answer to following questions.\n\
138 ");
139
140   if (!pkcs_name) {
141   again_name:
142     pkcs_name = silc_get_input("PKCS name (l to list names) [rsa]: ", FALSE);
143     if (!pkcs_name)
144       pkcs_name = strdup("rsa");
145
146     if (*pkcs_name == 'l' || *pkcs_name == 'L') {
147       silc_client_list_pkcs();
148       silc_free(pkcs_name);
149       goto again_name;
150     }
151   }
152
153   if (!silc_pkcs_is_supported(pkcs_name)) {
154     fprintf(stderr, "Unknown PKCS `%s'", pkcs_name);
155     return FALSE;
156   }
157
158   if (!bits) {
159     char *length = NULL;
160     length = silc_get_input("Key length in bits [1024]: ", FALSE);
161     if (!length)
162       bits = 1024;
163     else
164       bits = atoi(length);
165   }
166
167   if (!identifier) {
168     char *def = silc_client_create_identifier();
169
170     memset(line, 0, sizeof(line));
171     if (def)
172       snprintf(line, sizeof(line), "Identifier [%s]: ", def);
173     else
174       snprintf(line, sizeof(line),
175                "Identifier (eg. UN=jon, HN=jon.dummy.com, "
176                "RN=Jon Johnson, E=jon@dummy.com): ");
177
178     while (!identifier) {
179       identifier = silc_get_input(line, FALSE);
180       if (!identifier && def)
181         identifier = strdup(def);
182     }
183
184     if (def)
185       silc_free(def);
186   }
187
188   rng = silc_rng_alloc();
189   silc_rng_init(rng);
190   silc_rng_global_init(rng);
191
192   if (!public_key) {
193     memset(line, 0, sizeof(line));
194     snprintf(line, sizeof(line), "Public key filename [%s] ", 
195              SILC_CLIENT_PUBLIC_KEY_NAME);
196     pkfile = silc_get_input(line, FALSE);
197     if (!pkfile)
198       pkfile = SILC_CLIENT_PUBLIC_KEY_NAME;
199   } else {
200     pkfile = public_key;
201   }
202
203   if (!private_key) {
204     memset(line, 0, sizeof(line));
205     snprintf(line, sizeof(line), "Public key filename [%s] ", 
206              SILC_CLIENT_PRIVATE_KEY_NAME);
207     prvfile = silc_get_input(line, FALSE);
208     if (!prvfile)
209       prvfile = SILC_CLIENT_PRIVATE_KEY_NAME;
210   } else {
211     prvfile = private_key;
212   }
213
214   /* Generate keys */
215   silc_pkcs_alloc(pkcs_name, &pkcs);
216   silc_pkcs_generate_key(pkcs, bits, rng);
217
218   /* Save public key into file */
219   key = silc_pkcs_get_public_key(pkcs, &key_len);
220   pub_key = silc_pkcs_public_key_alloc(pkcs->pkcs->name, identifier,
221                                        key, key_len);
222   silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
223   if (ret_pub_key)
224     *ret_pub_key = pub_key;
225
226   memset(key, 0, sizeof(key_len));
227   silc_free(key);
228
229   /* Save private key into file */
230   key = silc_pkcs_get_private_key(pkcs, &key_len);
231   prv_key = silc_pkcs_private_key_alloc(pkcs->pkcs->name, key, key_len);
232
233   silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN);
234   if (ret_prv_key)
235     *ret_prv_key = prv_key;
236
237   printf("Public key has been saved into `%s'.\n", pkfile);
238   printf("Private key has been saved into `%s'.\n", prvfile);
239   printf("Press <Enter> to continue...\n");
240   getchar();
241
242   memset(key, 0, sizeof(key_len));
243   silc_free(key);
244
245   silc_rng_free(rng);
246   silc_pkcs_free(pkcs);
247
248   return TRUE;
249 }
250
251 /* This checks stats for various SILC files and directories. First it 
252    checks if ~/.silc directory exist and is owned by the correct user. If 
253    it doesn't exist, it will create the directory. After that it checks if
254    user's Public and Private key files exists and that they aren't expired.
255    If they doesn't exist or they are expired, they will be (re)created
256    after return. */
257
258 int silc_client_check_silc_dir()
259 {
260   char filename[256], file_public_key[256], file_private_key[256];
261   char servfilename[256], clientfilename[256];
262   char *identifier;
263   struct stat st;
264   struct passwd *pw;
265   int firstime = FALSE;
266   time_t curtime, modtime;
267
268   SILC_LOG_DEBUG(("Checking ~./silc directory"));
269
270   memset(filename, 0, sizeof(filename));
271   memset(file_public_key, 0, sizeof(file_public_key));
272   memset(file_private_key, 0, sizeof(file_private_key));
273
274   identifier = silc_client_create_identifier();
275
276   pw = getpwuid(getuid());
277   if (!pw) {
278     fprintf(stderr, "silc: %s\n", strerror(errno));
279     if (identifier)
280       silc_free(identifier);
281     return FALSE;
282   }
283
284   /* We'll take home path from /etc/passwd file to be sure. */
285   snprintf(filename, sizeof(filename) - 1, "%s/", get_irssi_dir());
286   snprintf(servfilename, sizeof(servfilename) - 1, "%s/serverkeys", 
287            get_irssi_dir());
288   snprintf(clientfilename, sizeof(clientfilename) - 1, "%s/clientkeys", 
289            get_irssi_dir());
290
291   /*
292    * Check ~/.silc directory
293    */
294   if ((stat(filename, &st)) == -1) {
295     /* If dir doesn't exist */
296     if (errno == ENOENT) {
297       if (pw->pw_uid == geteuid()) {
298         if ((mkdir(filename, 0755)) == -1) {
299           fprintf(stderr, "Couldn't create `%s' directory\n", filename);
300           return FALSE;
301         }
302
303         /* Directory was created. First time running SILC */
304         firstime = TRUE;
305       } else {
306         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
307                 filename);
308         return FALSE;
309       }
310     } else {
311       fprintf(stderr, "%s\n", strerror(errno));
312       return FALSE;
313     }
314   } else {
315     
316     /* Check the owner of the dir */
317     if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
318       fprintf(stderr, "You don't seem to own `%s' directory\n",
319               filename);
320       return FALSE;
321     }
322     
323 #if 0
324     /* Check the permissions of the dir */
325     if ((st.st_mode & 0777) != 0755) {
326       if ((chmod(filename, 0755)) == -1) {
327         fprintf(stderr, "Permissions for `%s' directory must be 0755\n", 
328                 filename);
329         return FALSE;
330       }
331     }
332 #endif
333   }
334
335   /*
336    * Check ~./silc/serverkeys directory
337    */
338   if ((stat(servfilename, &st)) == -1) {
339     /* If dir doesn't exist */
340     if (errno == ENOENT) {
341       if (pw->pw_uid == geteuid()) {
342         if ((mkdir(servfilename, 0755)) == -1) {
343           fprintf(stderr, "Couldn't create `%s' directory\n", servfilename);
344           return FALSE;
345         }
346       } else {
347         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
348                 servfilename);
349         return FALSE;
350       }
351     } else {
352       fprintf(stderr, "%s\n", strerror(errno));
353       return FALSE;
354     }
355   }
356   
357   /*
358    * Check ~./silc/clientkeys directory
359    */
360   if ((stat(clientfilename, &st)) == -1) {
361     /* If dir doesn't exist */
362     if (errno == ENOENT) {
363       if (pw->pw_uid == geteuid()) {
364         if ((mkdir(clientfilename, 0755)) == -1) {
365           fprintf(stderr, "Couldn't create `%s' directory\n", clientfilename);
366           return FALSE;
367         }
368       } else {
369         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
370                 clientfilename);
371         return FALSE;
372       }
373     } else {
374       fprintf(stderr, "%s\n", strerror(errno));
375       return FALSE;
376     }
377   }
378   
379   /*
380    * Check Public and Private keys
381    */
382   snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s", 
383            filename, SILC_CLIENT_PUBLIC_KEY_NAME);
384   snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s", 
385            filename, SILC_CLIENT_PRIVATE_KEY_NAME);
386   
387   /* If running SILC first time */
388   if (firstime) {
389     fprintf(stdout, "Running SILC for the first time\n");
390     silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
391                                 SILC_CLIENT_DEF_PKCS_LEN,
392                                 file_public_key, file_private_key, 
393                                 identifier, NULL, NULL);
394     return TRUE;
395   }
396   
397   if ((stat(file_public_key, &st)) == -1) {
398     /* If file doesn't exist */
399     if (errno == ENOENT) {
400       fprintf(stdout, "Your public key doesn't exist\n");
401       silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
402                                   SILC_CLIENT_DEF_PKCS_LEN,
403                                   file_public_key, 
404                                   file_private_key, identifier, NULL, NULL);
405     } else {
406       fprintf(stderr, "%s\n", strerror(errno));
407       return FALSE;
408     }
409   }
410
411   if ((stat(file_private_key, &st)) == -1) {
412     /* If file doesn't exist */
413     if (errno == ENOENT) {
414       fprintf(stdout, "Your private key doesn't exist\n");
415       silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
416                                   SILC_CLIENT_DEF_PKCS_LEN,
417                                   file_public_key, 
418                                   file_private_key, identifier, NULL, NULL);
419     } else {
420       fprintf(stderr, "%s\n", strerror(errno));
421       return FALSE;
422     }
423   }
424     
425   /* Check the owner of the public key */
426   if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
427     fprintf(stderr, "You don't seem to own your public key!?\n");
428     return FALSE;
429   }
430   
431   /* Check the owner of the private key */
432   if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
433     fprintf(stderr, "You don't seem to own your private key!?\n");
434     return FALSE;
435   }
436     
437   /* Check the permissions for the private key */
438   if ((st.st_mode & 0777) != 0600) {
439     fprintf(stderr, "Wrong permissions in your private key file `%s'!\n"
440             "Trying to change them ... ", file_private_key);
441     if ((chmod(file_private_key, 0600)) == -1) {
442       fprintf(stderr,
443               "Failed to change permissions for private key file!\n" 
444               "Permissions for your private key file must be 0600.\n");
445       return FALSE;
446     }
447     fprintf(stderr, "Done.\n\n");
448   }
449
450   /* See if the key has expired. */
451   modtime = st.st_mtime;        /* last modified */
452   curtime = time(0) - modtime;
453     
454   /* 86400 is seconds in a day. */
455   if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) {
456     fprintf(stdout, 
457             "--------------------------------------------------\n"
458             "Your private key has expired and needs to be\n" 
459             "recreated.  This will be done automatically now.\n"
460             "Your new key will expire in %d days from today.\n"
461             "--------------------------------------------------\n",
462             SILC_CLIENT_KEY_EXPIRES);
463
464     silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
465                                 SILC_CLIENT_DEF_PKCS_LEN,
466                                 file_public_key, 
467                                 file_private_key, identifier, NULL, NULL);
468   }
469   
470   if (identifier)
471     silc_free(identifier);
472
473   return TRUE;
474 }
475
476 /* Loads public and private key from files. */
477
478 int silc_client_load_keys(SilcClient client)
479 {
480   char filename[256];
481   struct passwd *pw;
482
483   SILC_LOG_DEBUG(("Loading public and private keys"));
484
485   pw = getpwuid(getuid());
486   if (!pw)
487     return FALSE;
488
489   memset(filename, 0, sizeof(filename));
490   snprintf(filename, sizeof(filename) - 1, "%s/%s", 
491            get_irssi_dir(), SILC_CLIENT_PRIVATE_KEY_NAME);
492
493   if (silc_pkcs_load_private_key(filename, &client->private_key,
494                                  SILC_PKCS_FILE_BIN) == FALSE)
495     if (silc_pkcs_load_private_key(filename, &client->private_key,
496                                    SILC_PKCS_FILE_PEM) == FALSE)
497       return FALSE;
498
499   memset(filename, 0, sizeof(filename));
500   snprintf(filename, sizeof(filename) - 1, "%s/%s", 
501            get_irssi_dir(), SILC_CLIENT_PUBLIC_KEY_NAME);
502
503   if (silc_pkcs_load_public_key(filename, &client->public_key,
504                                 SILC_PKCS_FILE_PEM) == FALSE)
505     if (silc_pkcs_load_public_key(filename, &client->public_key,
506                                   SILC_PKCS_FILE_BIN) == FALSE)
507       return FALSE;
508
509   silc_pkcs_alloc(client->public_key->name, &client->pkcs);
510   silc_pkcs_public_key_set(client->pkcs, client->public_key);
511   silc_pkcs_private_key_set(client->pkcs, client->private_key);
512
513   return TRUE;
514 }
515
516 /* Dumps the public key on screen. Used from the command line option. */
517
518 int silc_client_show_key(char *keyfile)
519 {
520   SilcPublicKey public_key;
521   SilcPublicKeyIdentifier ident;
522   char *fingerprint, *babbleprint;
523   unsigned char *pk;
524   SilcUInt32 pk_len;
525   SilcPKCS pkcs;
526   int key_len = 0;
527
528   if (silc_pkcs_load_public_key(keyfile, &public_key,
529                                 SILC_PKCS_FILE_PEM) == FALSE)
530     if (silc_pkcs_load_public_key(keyfile, &public_key,
531                                   SILC_PKCS_FILE_BIN) == FALSE) {
532       fprintf(stderr, "Could not load public key file `%s'\n", keyfile);
533       return FALSE;
534     }
535
536   ident = silc_pkcs_decode_identifier(public_key->identifier);
537
538   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
539   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
540   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
541
542   if (silc_pkcs_alloc(public_key->name, &pkcs)) {
543     key_len = silc_pkcs_public_key_set(pkcs, public_key);
544     silc_pkcs_free(pkcs);
545   }
546
547   printf("Public key file    : %s\n", keyfile);
548   printf("Algorithm          : %s\n", public_key->name);
549   if (key_len)
550     printf("Key length (bits)  : %d\n", key_len);
551   if (ident->realname)
552     printf("Real name          : %s\n", ident->realname);
553   if (ident->username)
554     printf("Username           : %s\n", ident->username);
555   if (ident->host)
556     printf("Hostname           : %s\n", ident->host);
557   if (ident->email)
558     printf("Email              : %s\n", ident->email);
559   if (ident->org)
560     printf("Organization       : %s\n", ident->org);
561   if (ident->country)
562     printf("Country            : %s\n", ident->country);
563   printf("Fingerprint (SHA1) : %s\n", fingerprint); 
564   printf("Babbleprint (SHA1) : %s\n", babbleprint); 
565
566   fflush(stdout);
567
568   silc_free(fingerprint);
569   silc_free(babbleprint);
570   silc_free(pk);
571   silc_pkcs_public_key_free(public_key);
572   silc_pkcs_free_identifier(ident);
573
574   return TRUE;
575 }