6b19cc6f18e2a857e4592398e66562b886299a20
[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 #if 0
355     /* Check the permissions of the dir */
356     if ((st.st_mode & 0777) != 0755) {
357       if ((chmod(filename, 0755)) == -1) {
358         fprintf(stderr, "Permissions for `%s' directory must be 0755\n", 
359                 filename);
360         return FALSE;
361       }
362     }
363 #endif
364   }
365
366   /*
367    * Check ~./silc/serverkeys directory
368    */
369   if ((stat(servfilename, &st)) == -1) {
370     /* If dir doesn't exist */
371     if (errno == ENOENT) {
372       if (pw->pw_uid == geteuid()) {
373         if ((mkdir(servfilename, 0755)) == -1) {
374           fprintf(stderr, "Couldn't create `%s' directory\n", servfilename);
375           return FALSE;
376         }
377       } else {
378         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
379                 servfilename);
380         return FALSE;
381       }
382     } else {
383       fprintf(stderr, "%s\n", strerror(errno));
384       return FALSE;
385     }
386   }
387   
388   /*
389    * Check ~./silc/clientkeys directory
390    */
391   if ((stat(clientfilename, &st)) == -1) {
392     /* If dir doesn't exist */
393     if (errno == ENOENT) {
394       if (pw->pw_uid == geteuid()) {
395         if ((mkdir(clientfilename, 0755)) == -1) {
396           fprintf(stderr, "Couldn't create `%s' directory\n", clientfilename);
397           return FALSE;
398         }
399       } else {
400         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
401                 clientfilename);
402         return FALSE;
403       }
404     } else {
405       fprintf(stderr, "%s\n", strerror(errno));
406       return FALSE;
407     }
408   }
409   
410   /*
411    * Check Public and Private keys
412    */
413   snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s", 
414            filename, SILC_CLIENT_PUBLIC_KEY_NAME);
415   snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s", 
416            filename, SILC_CLIENT_PRIVATE_KEY_NAME);
417   
418   /* If running SILC first time */
419   if (firstime) {
420     fprintf(stdout, "Running SILC for the first time\n");
421     silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
422                                 SILC_CLIENT_DEF_PKCS_LEN,
423                                 file_public_key, file_private_key, 
424                                 identifier, NULL, NULL);
425     return TRUE;
426   }
427   
428   if ((stat(file_public_key, &st)) == -1) {
429     /* If file doesn't exist */
430     if (errno == ENOENT) {
431       fprintf(stdout, "Your public key doesn't exist\n");
432       silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
433                                   SILC_CLIENT_DEF_PKCS_LEN,
434                                   file_public_key, 
435                                   file_private_key, identifier, NULL, NULL);
436     } else {
437       fprintf(stderr, "%s\n", strerror(errno));
438       return FALSE;
439     }
440   }
441
442   if ((stat(file_private_key, &st)) == -1) {
443     /* If file doesn't exist */
444     if (errno == ENOENT) {
445       fprintf(stdout, "Your private key doesn't exist\n");
446       silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
447                                   SILC_CLIENT_DEF_PKCS_LEN,
448                                   file_public_key, 
449                                   file_private_key, identifier, NULL, NULL);
450     } else {
451       fprintf(stderr, "%s\n", strerror(errno));
452       return FALSE;
453     }
454   }
455     
456   /* Check the owner of the public key */
457   if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
458     fprintf(stderr, "You don't seem to own your public key!?\n");
459     return FALSE;
460   }
461   
462   /* Check the owner of the private key */
463   if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
464     fprintf(stderr, "You don't seem to own your private key!?\n");
465     return FALSE;
466   }
467     
468   /* Check the permissions for the private key */
469   if ((st.st_mode & 0777) != 0600) {
470     fprintf(stderr, "Wrong permissions in your private key file `%s'!\n"
471             "Trying to change them ... ", file_private_key);
472     if ((chmod(file_private_key, 0600)) == -1) {
473       fprintf(stderr,
474               "Failed to change permissions for private key file!\n" 
475               "Permissions for your private key file must be 0600.\n");
476       return FALSE;
477     }
478     fprintf(stderr, "Done.\n\n");
479   }
480
481   /* See if the key has expired. */
482   modtime = st.st_mtime;        /* last modified */
483   curtime = time(0) - modtime;
484     
485   /* 86400 is seconds in a day. */
486   if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) {
487     fprintf(stdout, 
488             "--------------------------------------------------\n"
489             "Your private key has expired and needs to be\n" 
490             "recreated.  This will be done automatically now.\n"
491             "Your new key will expire in %d days from today.\n"
492             "--------------------------------------------------\n",
493             SILC_CLIENT_KEY_EXPIRES);
494
495     silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
496                                 SILC_CLIENT_DEF_PKCS_LEN,
497                                 file_public_key, 
498                                 file_private_key, identifier, NULL, NULL);
499   }
500   
501   if (identifier)
502     silc_free(identifier);
503
504   return TRUE;
505 }
506
507 /* Loads public and private key from files. */
508
509 int silc_client_load_keys(SilcClient client)
510 {
511   char filename[256];
512   struct passwd *pw;
513
514   SILC_LOG_DEBUG(("Loading public and private keys"));
515
516   pw = getpwuid(getuid());
517   if (!pw)
518     return FALSE;
519
520   memset(filename, 0, sizeof(filename));
521   snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s", 
522            pw->pw_dir, SILC_CLIENT_PRIVATE_KEY_NAME);
523
524   if (silc_pkcs_load_private_key(filename, &client->private_key,
525                                  SILC_PKCS_FILE_BIN) == FALSE)
526     if (silc_pkcs_load_private_key(filename, &client->private_key,
527                                    SILC_PKCS_FILE_PEM) == FALSE)
528       return FALSE;
529
530   memset(filename, 0, sizeof(filename));
531   snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s", 
532            pw->pw_dir, SILC_CLIENT_PUBLIC_KEY_NAME);
533
534   if (silc_pkcs_load_public_key(filename, &client->public_key,
535                                 SILC_PKCS_FILE_PEM) == FALSE)
536     if (silc_pkcs_load_public_key(filename, &client->public_key,
537                                   SILC_PKCS_FILE_BIN) == FALSE)
538       return FALSE;
539
540   silc_pkcs_alloc(client->public_key->name, &client->pkcs);
541   silc_pkcs_public_key_set(client->pkcs, client->public_key);
542   silc_pkcs_private_key_set(client->pkcs, client->private_key);
543
544   return TRUE;
545 }
546
547 /* Dumps the public key on screen. Used from the command line option. */
548
549 int silc_client_show_key(char *keyfile)
550 {
551   SilcPublicKey public_key;
552   SilcPublicKeyIdentifier ident;
553   char *fingerprint;
554   unsigned char *pk;
555   uint32 pk_len;
556   SilcPKCS pkcs;
557   int key_len = 0;
558
559   if (silc_pkcs_load_public_key(keyfile, &public_key,
560                                 SILC_PKCS_FILE_PEM) == FALSE)
561     if (silc_pkcs_load_public_key(keyfile, &public_key,
562                                   SILC_PKCS_FILE_BIN) == FALSE) {
563       fprintf(stderr, "Could not load public key file `%s'\n", keyfile);
564       return FALSE;
565     }
566
567   ident = silc_pkcs_decode_identifier(public_key->identifier);
568
569   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
570   fingerprint = silc_hash_fingerprint(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
595   fflush(stdout);
596
597   silc_free(fingerprint);
598   silc_free(pk);
599   silc_pkcs_public_key_free(public_key);
600   silc_pkcs_free_identifier(ident);
601
602   return TRUE;
603 }