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