5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
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.
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.
24 #include "net-nonblock.h"
25 #include "net-sendbuffer.h"
35 #include "servers-setup.h"
37 #include "silc-servers.h"
38 #include "silc-channels.h"
39 #include "silc-queries.h"
40 #include "window-item-def.h"
42 #include "fe-common/core/printtext.h"
44 /* Asks yes/no from user on the input line. Returns TRUE on "yes" and
47 int silc_client_ask_yes_no(SilcClient client, char *prompt)
50 SilcClientInternal app = (SilcClientInternal)client->application;
55 silc_screen_input_reset(app->screen);
58 wattroff(app->screen->input_win, A_INVIS);
59 silc_screen_input_print_prompt(app->screen, prompt);
62 memset(answer, 0, sizeof(answer));
64 wgetnstr(app->screen->input_win, answer, sizeof(answer));
65 if (!strncasecmp(answer, "yes", strlen(answer)) ||
66 !strncasecmp(answer, "y", strlen(answer))) {
68 } else if (!strncasecmp(answer, "no", strlen(answer)) ||
69 !strncasecmp(answer, "n", strlen(answer))) {
72 silc_say(client, app->conn, "Type yes or no");
77 silc_screen_input_reset(app->screen);
84 /* Lists supported (builtin) ciphers */
86 void silc_client_list_ciphers()
88 char *ciphers = silc_cipher_get_supported();
89 fprintf(stdout, "%s\n", ciphers);
93 /* Lists supported (builtin) hash functions */
95 void silc_client_list_hash_funcs()
97 char *hash = silc_hash_get_supported();
98 fprintf(stdout, "%s\n", hash);
102 /* Lists supported PKCS algorithms */
104 void silc_client_list_pkcs()
106 char *pkcs = silc_pkcs_get_supported();
107 fprintf(stdout, "%s\n", pkcs);
111 /* Displays input prompt on command line and takes input data from user */
113 char *silc_client_get_input(const char *prompt)
119 fd = open("/dev/tty", O_RDONLY);
121 fprintf(stderr, "silc: %s\n", strerror(errno));
125 memset(input, 0, sizeof(input));
127 printf("%s", prompt);
130 if ((read(fd, input, sizeof(input))) < 0) {
131 fprintf(stderr, "silc: %s\n", strerror(errno));
135 if (strlen(input) <= 1)
138 if (strchr(input, '\n'))
139 *strchr(input, '\n') = '\0';
140 return strdup(input);
145 /* Returns identifier string for public key generation. */
147 char *silc_client_create_identifier()
149 char *username = NULL, *realname = NULL;
150 char hostname[256], email[256];
153 realname = silc_get_real_name();
156 memset(hostname, 0, sizeof(hostname));
157 gethostname(hostname, sizeof(hostname));
159 /* Get username (mandatory) */
160 username = silc_get_username();
164 /* Create default email address, whether it is right or not */
165 snprintf(email, sizeof(email), "%s@%s", username, hostname);
167 return silc_pkcs_encode_identifier(username, hostname, realname, email,
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. */
174 int silc_client_create_key_pair(char *pkcs_name, int bits,
175 char *public_key, char *private_key,
177 SilcPublicKey *ret_pub_key,
178 SilcPrivateKey *ret_prv_key)
181 SilcPublicKey pub_key;
182 SilcPrivateKey prv_key;
187 char *pkfile = NULL, *prvfile = NULL;
189 if (!pkcs_name || !public_key || !private_key)
191 New pair of keys will be created. Please, answer to following questions.\n\
197 silc_client_get_input("PKCS name (l to list names) [rsa]: ");
199 pkcs_name = strdup("rsa");
201 if (*pkcs_name == 'l' || *pkcs_name == 'L') {
202 silc_client_list_pkcs();
203 silc_free(pkcs_name);
208 if (!silc_pkcs_is_supported(pkcs_name)) {
209 fprintf(stderr, "Unknown PKCS `%s'", pkcs_name);
216 silc_client_get_input("Key length in bits [1024]: ");
224 char *def = silc_client_create_identifier();
226 memset(line, 0, sizeof(line));
228 snprintf(line, sizeof(line), "Identifier [%s]: ", def);
230 snprintf(line, sizeof(line),
231 "Identifier (eg. UN=jon, HN=jon.dummy.com, "
232 "RN=Jon Johnson, E=jon@dummy.com): ");
234 while (!identifier) {
235 identifier = silc_client_get_input(line);
236 if (!identifier && def)
237 identifier = strdup(def);
244 rng = silc_rng_alloc();
246 silc_rng_global_init(rng);
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);
254 pkfile = SILC_CLIENT_PUBLIC_KEY_NAME;
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);
265 prvfile = SILC_CLIENT_PRIVATE_KEY_NAME;
267 prvfile = private_key;
271 silc_pkcs_alloc(pkcs_name, &pkcs);
272 pkcs->pkcs->init(pkcs->context, bits, rng);
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,
278 silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
280 *ret_pub_key = pub_key;
282 memset(key, 0, sizeof(key_len));
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);
289 silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN);
291 *ret_prv_key = prv_key;
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");
298 memset(key, 0, sizeof(key_len));
302 silc_pkcs_free(pkcs);
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
314 int silc_client_check_silc_dir()
316 char filename[256], file_public_key[256], file_private_key[256];
317 char servfilename[256], clientfilename[256];
321 int firstime = FALSE;
322 time_t curtime, modtime;
324 SILC_LOG_DEBUG(("Checking ~./silc directory"));
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));
330 pw = getpwuid(getuid());
332 fprintf(stderr, "silc: %s\n", strerror(errno));
336 identifier = silc_client_create_identifier();
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",
342 snprintf(clientfilename, sizeof(clientfilename) - 1, "%s/.silc/clientkeys",
346 * Check ~/.silc directory
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);
357 /* Directory was created. First time running SILC */
360 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
365 fprintf(stderr, "%s\n", strerror(errno));
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",
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",
388 * Check ~./silc/serverkeys directory
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);
399 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
404 fprintf(stderr, "%s\n", strerror(errno));
410 * Check ~./silc/clientkeys directory
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);
421 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
426 fprintf(stderr, "%s\n", strerror(errno));
432 * Check Public and Private keys
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);
439 /* If running SILC first time */
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);
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,
456 file_private_key, identifier, NULL, NULL);
458 fprintf(stderr, "%s\n", strerror(errno));
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,
470 file_private_key, identifier, NULL, NULL);
472 fprintf(stderr, "%s\n", strerror(errno));
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");
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");
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) {
495 "Failed to change permissions for private key file!\n"
496 "Permissions for your private key file must be 0600.\n");
499 fprintf(stderr, "Done.\n\n");
502 /* See if the key has expired. */
503 modtime = st.st_mtime; /* last modified */
504 curtime = time(0) - modtime;
506 /* 86400 is seconds in a day. */
507 if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) {
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);
516 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
517 SILC_CLIENT_DEF_PKCS_LEN,
519 file_private_key, identifier, NULL, NULL);
523 silc_free(identifier);
528 /* Loads public and private key from files. */
530 int silc_client_load_keys(SilcClient client)
535 SILC_LOG_DEBUG(("Loading public and private keys"));
537 pw = getpwuid(getuid());
541 memset(filename, 0, sizeof(filename));
542 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s",
543 pw->pw_dir, SILC_CLIENT_PRIVATE_KEY_NAME);
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)
551 memset(filename, 0, sizeof(filename));
552 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s",
553 pw->pw_dir, SILC_CLIENT_PUBLIC_KEY_NAME);
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)
564 /* Dumps the public key on screen. Used from the command line option. */
566 int silc_client_show_key(char *keyfile)
568 SilcPublicKey public_key;
569 SilcPublicKeyIdentifier ident;
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);
584 ident = silc_pkcs_decode_identifier(public_key->identifier);
586 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
587 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
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);
594 printf("Public key file : %s\n", keyfile);
595 printf("Algorithm : %s\n", public_key->name);
597 printf("Key length (bits) : %d\n", key_len);
599 printf("Real name : %s\n", ident->realname);
601 printf("Username : %s\n", ident->username);
603 printf("Hostname : %s\n", ident->host);
605 printf("Email : %s\n", ident->email);
607 printf("Organization : %s\n", ident->org);
609 printf("Country : %s\n", ident->country);
610 printf("Fingerprint (SHA1) : %s\n", fingerprint);
614 silc_free(fingerprint);
616 silc_pkcs_public_key_free(public_key);
617 silc_pkcs_free_identifier(ident);