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