Integer type name change.
[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   SilcUInt32 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   identifier = silc_client_create_identifier();
307
308   pw = getpwuid(getuid());
309   if (!pw) {
310     fprintf(stderr, "silc: %s\n", strerror(errno));
311     if (identifier)
312       silc_free(identifier);
313     return FALSE;
314   }
315
316   /* We'll take home path from /etc/passwd file to be sure. */
317   snprintf(filename, sizeof(filename) - 1, "%s/.silc/", pw->pw_dir);
318   snprintf(servfilename, sizeof(servfilename) - 1, "%s/.silc/serverkeys", 
319            pw->pw_dir);
320   snprintf(clientfilename, sizeof(clientfilename) - 1, "%s/.silc/clientkeys", 
321            pw->pw_dir);
322
323   /*
324    * Check ~/.silc directory
325    */
326   if ((stat(filename, &st)) == -1) {
327     /* If dir doesn't exist */
328     if (errno == ENOENT) {
329       if (pw->pw_uid == geteuid()) {
330         if ((mkdir(filename, 0755)) == -1) {
331           fprintf(stderr, "Couldn't create `%s' directory\n", filename);
332           return FALSE;
333         }
334
335         /* Directory was created. First time running SILC */
336         firstime = TRUE;
337       } else {
338         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
339                 filename);
340         return FALSE;
341       }
342     } else {
343       fprintf(stderr, "%s\n", strerror(errno));
344       return FALSE;
345     }
346   } else {
347     
348     /* Check the owner of the dir */
349     if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
350       fprintf(stderr, "You don't seem to own `%s' directory\n",
351               filename);
352       return FALSE;
353     }
354     
355 #if 0
356     /* Check the permissions of the dir */
357     if ((st.st_mode & 0777) != 0755) {
358       if ((chmod(filename, 0755)) == -1) {
359         fprintf(stderr, "Permissions for `%s' directory must be 0755\n", 
360                 filename);
361         return FALSE;
362       }
363     }
364 #endif
365   }
366
367   /*
368    * Check ~./silc/serverkeys directory
369    */
370   if ((stat(servfilename, &st)) == -1) {
371     /* If dir doesn't exist */
372     if (errno == ENOENT) {
373       if (pw->pw_uid == geteuid()) {
374         if ((mkdir(servfilename, 0755)) == -1) {
375           fprintf(stderr, "Couldn't create `%s' directory\n", servfilename);
376           return FALSE;
377         }
378       } else {
379         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
380                 servfilename);
381         return FALSE;
382       }
383     } else {
384       fprintf(stderr, "%s\n", strerror(errno));
385       return FALSE;
386     }
387   }
388   
389   /*
390    * Check ~./silc/clientkeys directory
391    */
392   if ((stat(clientfilename, &st)) == -1) {
393     /* If dir doesn't exist */
394     if (errno == ENOENT) {
395       if (pw->pw_uid == geteuid()) {
396         if ((mkdir(clientfilename, 0755)) == -1) {
397           fprintf(stderr, "Couldn't create `%s' directory\n", clientfilename);
398           return FALSE;
399         }
400       } else {
401         fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
402                 clientfilename);
403         return FALSE;
404       }
405     } else {
406       fprintf(stderr, "%s\n", strerror(errno));
407       return FALSE;
408     }
409   }
410   
411   /*
412    * Check Public and Private keys
413    */
414   snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s", 
415            filename, SILC_CLIENT_PUBLIC_KEY_NAME);
416   snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s", 
417            filename, SILC_CLIENT_PRIVATE_KEY_NAME);
418   
419   /* If running SILC first time */
420   if (firstime) {
421     fprintf(stdout, "Running SILC for the first time\n");
422     silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
423                                 SILC_CLIENT_DEF_PKCS_LEN,
424                                 file_public_key, file_private_key, 
425                                 identifier, NULL, NULL);
426     return TRUE;
427   }
428   
429   if ((stat(file_public_key, &st)) == -1) {
430     /* If file doesn't exist */
431     if (errno == ENOENT) {
432       fprintf(stdout, "Your public key doesn't exist\n");
433       silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
434                                   SILC_CLIENT_DEF_PKCS_LEN,
435                                   file_public_key, 
436                                   file_private_key, identifier, NULL, NULL);
437     } else {
438       fprintf(stderr, "%s\n", strerror(errno));
439       return FALSE;
440     }
441   }
442
443   if ((stat(file_private_key, &st)) == -1) {
444     /* If file doesn't exist */
445     if (errno == ENOENT) {
446       fprintf(stdout, "Your private key doesn't exist\n");
447       silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
448                                   SILC_CLIENT_DEF_PKCS_LEN,
449                                   file_public_key, 
450                                   file_private_key, identifier, NULL, NULL);
451     } else {
452       fprintf(stderr, "%s\n", strerror(errno));
453       return FALSE;
454     }
455   }
456     
457   /* Check the owner of the public key */
458   if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
459     fprintf(stderr, "You don't seem to own your public key!?\n");
460     return FALSE;
461   }
462   
463   /* Check the owner of the private key */
464   if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
465     fprintf(stderr, "You don't seem to own your private key!?\n");
466     return FALSE;
467   }
468     
469   /* Check the permissions for the private key */
470   if ((st.st_mode & 0777) != 0600) {
471     fprintf(stderr, "Wrong permissions in your private key file `%s'!\n"
472             "Trying to change them ... ", file_private_key);
473     if ((chmod(file_private_key, 0600)) == -1) {
474       fprintf(stderr,
475               "Failed to change permissions for private key file!\n" 
476               "Permissions for your private key file must be 0600.\n");
477       return FALSE;
478     }
479     fprintf(stderr, "Done.\n\n");
480   }
481
482   /* See if the key has expired. */
483   modtime = st.st_mtime;        /* last modified */
484   curtime = time(0) - modtime;
485     
486   /* 86400 is seconds in a day. */
487   if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) {
488     fprintf(stdout, 
489             "--------------------------------------------------\n"
490             "Your private key has expired and needs to be\n" 
491             "recreated.  This will be done automatically now.\n"
492             "Your new key will expire in %d days from today.\n"
493             "--------------------------------------------------\n",
494             SILC_CLIENT_KEY_EXPIRES);
495
496     silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
497                                 SILC_CLIENT_DEF_PKCS_LEN,
498                                 file_public_key, 
499                                 file_private_key, identifier, NULL, NULL);
500   }
501   
502   if (identifier)
503     silc_free(identifier);
504
505   return TRUE;
506 }
507
508 /* Loads public and private key from files. */
509
510 int silc_client_load_keys(SilcClient client)
511 {
512   char filename[256];
513   struct passwd *pw;
514
515   SILC_LOG_DEBUG(("Loading public and private keys"));
516
517   pw = getpwuid(getuid());
518   if (!pw)
519     return FALSE;
520
521   memset(filename, 0, sizeof(filename));
522   snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s", 
523            pw->pw_dir, SILC_CLIENT_PRIVATE_KEY_NAME);
524
525   if (silc_pkcs_load_private_key(filename, &client->private_key,
526                                  SILC_PKCS_FILE_BIN) == FALSE)
527     if (silc_pkcs_load_private_key(filename, &client->private_key,
528                                    SILC_PKCS_FILE_PEM) == FALSE)
529       return FALSE;
530
531   memset(filename, 0, sizeof(filename));
532   snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s", 
533            pw->pw_dir, SILC_CLIENT_PUBLIC_KEY_NAME);
534
535   if (silc_pkcs_load_public_key(filename, &client->public_key,
536                                 SILC_PKCS_FILE_PEM) == FALSE)
537     if (silc_pkcs_load_public_key(filename, &client->public_key,
538                                   SILC_PKCS_FILE_BIN) == FALSE)
539       return FALSE;
540
541   silc_pkcs_alloc(client->public_key->name, &client->pkcs);
542   silc_pkcs_public_key_set(client->pkcs, client->public_key);
543   silc_pkcs_private_key_set(client->pkcs, client->private_key);
544
545   return TRUE;
546 }
547
548 /* Dumps the public key on screen. Used from the command line option. */
549
550 int silc_client_show_key(char *keyfile)
551 {
552   SilcPublicKey public_key;
553   SilcPublicKeyIdentifier ident;
554   char *fingerprint, *babbleprint;
555   unsigned char *pk;
556   SilcUInt32 pk_len;
557   SilcPKCS pkcs;
558   int key_len = 0;
559
560   if (silc_pkcs_load_public_key(keyfile, &public_key,
561                                 SILC_PKCS_FILE_PEM) == FALSE)
562     if (silc_pkcs_load_public_key(keyfile, &public_key,
563                                   SILC_PKCS_FILE_BIN) == FALSE) {
564       fprintf(stderr, "Could not load public key file `%s'\n", keyfile);
565       return FALSE;
566     }
567
568   ident = silc_pkcs_decode_identifier(public_key->identifier);
569
570   pk = silc_pkcs_public_key_encode(public_key, &pk_len);
571   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
572   babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
573
574   if (silc_pkcs_alloc(public_key->name, &pkcs)) {
575     key_len = silc_pkcs_public_key_set(pkcs, public_key);
576     silc_pkcs_free(pkcs);
577   }
578
579   printf("Public key file    : %s\n", keyfile);
580   printf("Algorithm          : %s\n", public_key->name);
581   if (key_len)
582     printf("Key length (bits)  : %d\n", key_len);
583   if (ident->realname)
584     printf("Real name          : %s\n", ident->realname);
585   if (ident->username)
586     printf("Username           : %s\n", ident->username);
587   if (ident->host)
588     printf("Hostname           : %s\n", ident->host);
589   if (ident->email)
590     printf("Email              : %s\n", ident->email);
591   if (ident->org)
592     printf("Organization       : %s\n", ident->org);
593   if (ident->country)
594     printf("Country            : %s\n", ident->country);
595   printf("Fingerprint (SHA1) : %s\n", fingerprint); 
596   printf("Babbleprint (SHA1) : %s\n", babbleprint); 
597
598   fflush(stdout);
599
600   silc_free(fingerprint);
601   silc_free(babbleprint);
602   silc_free(pk);
603   silc_pkcs_public_key_free(public_key);
604   silc_pkcs_free_identifier(ident);
605
606   return TRUE;
607 }