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