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