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