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