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