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