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 "channels-setup.h"
37 #include "silc-servers.h"
38 #include "silc-channels.h"
39 #include "silc-queries.h"
40 #include "silc-nicklist.h"
41 #include "window-item-def.h"
43 #include "fe-common/core/printtext.h"
44 #include "fe-common/core/keyboard.h"
46 /* Asks yes/no from user on the input line. Returns TRUE on "yes" and
49 void silc_client_ask_yes_no(char *prompt, SIGNAL_FUNC func)
51 keyboard_entry_redirect(func, prompt, 0, NULL);
54 /* Lists supported (builtin) ciphers */
56 void silc_client_list_ciphers()
58 char *ciphers = silc_cipher_get_supported();
59 fprintf(stdout, "%s\n", ciphers);
63 /* Lists supported (builtin) hash functions */
65 void silc_client_list_hash_funcs()
67 char *hash = silc_hash_get_supported();
68 fprintf(stdout, "%s\n", hash);
72 /* Lists supported PKCS algorithms */
74 void silc_client_list_pkcs()
76 char *pkcs = silc_pkcs_get_supported();
77 fprintf(stdout, "%s\n", pkcs);
81 /* Displays input prompt on command line and takes input data from user */
83 char *silc_client_get_input(const char *prompt)
88 fd = open("/dev/tty", O_RDONLY);
90 fprintf(stderr, "silc: %s\n", strerror(errno));
94 memset(input, 0, sizeof(input));
99 if ((read(fd, input, sizeof(input))) < 0) {
100 fprintf(stderr, "silc: %s\n", strerror(errno));
104 if (strlen(input) <= 1)
107 if (strchr(input, '\n'))
108 *strchr(input, '\n') = '\0';
110 return strdup(input);
113 /* Returns identifier string for public key generation. */
115 char *silc_client_create_identifier()
117 char *username = NULL, *realname = NULL;
118 char hostname[256], email[256];
121 realname = silc_get_real_name();
124 memset(hostname, 0, sizeof(hostname));
125 gethostname(hostname, sizeof(hostname));
127 /* Get username (mandatory) */
128 username = silc_get_username();
132 /* Create default email address, whether it is right or not */
133 snprintf(email, sizeof(email), "%s@%s", username, hostname);
135 return silc_pkcs_encode_identifier(username, hostname, realname, email,
139 /* Creates new public key and private key pair. This is used only
140 when user wants to create new key pair from command line. */
142 int silc_client_create_key_pair(char *pkcs_name, int bits,
143 char *public_key, char *private_key,
145 SilcPublicKey *ret_pub_key,
146 SilcPrivateKey *ret_prv_key)
149 SilcPublicKey pub_key;
150 SilcPrivateKey prv_key;
155 char *pkfile = NULL, *prvfile = NULL;
157 if (!pkcs_name || !public_key || !private_key)
159 New pair of keys will be created. Please, answer to following questions.\n\
165 silc_client_get_input("PKCS name (l to list names) [rsa]: ");
167 pkcs_name = strdup("rsa");
169 if (*pkcs_name == 'l' || *pkcs_name == 'L') {
170 silc_client_list_pkcs();
171 silc_free(pkcs_name);
176 if (!silc_pkcs_is_supported(pkcs_name)) {
177 fprintf(stderr, "Unknown PKCS `%s'", pkcs_name);
184 silc_client_get_input("Key length in bits [1024]: ");
192 char *def = silc_client_create_identifier();
194 memset(line, 0, sizeof(line));
196 snprintf(line, sizeof(line), "Identifier [%s]: ", def);
198 snprintf(line, sizeof(line),
199 "Identifier (eg. UN=jon, HN=jon.dummy.com, "
200 "RN=Jon Johnson, E=jon@dummy.com): ");
202 while (!identifier) {
203 identifier = silc_client_get_input(line);
204 if (!identifier && def)
205 identifier = strdup(def);
212 rng = silc_rng_alloc();
214 silc_rng_global_init(rng);
217 memset(line, 0, sizeof(line));
218 snprintf(line, sizeof(line), "Public key filename [%s] ",
219 SILC_CLIENT_PUBLIC_KEY_NAME);
220 pkfile = silc_client_get_input(line);
222 pkfile = SILC_CLIENT_PUBLIC_KEY_NAME;
228 memset(line, 0, sizeof(line));
229 snprintf(line, sizeof(line), "Public key filename [%s] ",
230 SILC_CLIENT_PRIVATE_KEY_NAME);
231 prvfile = silc_client_get_input(line);
233 prvfile = SILC_CLIENT_PRIVATE_KEY_NAME;
235 prvfile = private_key;
239 silc_pkcs_alloc(pkcs_name, &pkcs);
240 pkcs->pkcs->init(pkcs->context, bits, rng);
242 /* Save public key into file */
243 key = silc_pkcs_get_public_key(pkcs, &key_len);
244 pub_key = silc_pkcs_public_key_alloc(pkcs->pkcs->name, identifier,
246 silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
248 *ret_pub_key = pub_key;
250 memset(key, 0, sizeof(key_len));
253 /* Save private key into file */
254 key = silc_pkcs_get_private_key(pkcs, &key_len);
255 prv_key = silc_pkcs_private_key_alloc(pkcs->pkcs->name, key, key_len);
257 silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN);
259 *ret_prv_key = prv_key;
261 printf("Public key has been saved into `%s'.\n", pkfile);
262 printf("Private key has been saved into `%s'.\n", prvfile);
263 printf("Press <Enter> to continue...\n");
266 memset(key, 0, sizeof(key_len));
270 silc_pkcs_free(pkcs);
275 /* This checks stats for various SILC files and directories. First it
276 checks if ~/.silc directory exist and is owned by the correct user. If
277 it doesn't exist, it will create the directory. After that it checks if
278 user's Public and Private key files exists and that they aren't expired.
279 If they doesn't exist or they are expired, they will be (re)created
282 int silc_client_check_silc_dir()
284 char filename[256], file_public_key[256], file_private_key[256];
285 char servfilename[256], clientfilename[256];
289 int firstime = FALSE;
290 time_t curtime, modtime;
292 SILC_LOG_DEBUG(("Checking ~./silc directory"));
294 memset(filename, 0, sizeof(filename));
295 memset(file_public_key, 0, sizeof(file_public_key));
296 memset(file_private_key, 0, sizeof(file_private_key));
298 pw = getpwuid(getuid());
300 fprintf(stderr, "silc: %s\n", strerror(errno));
304 identifier = silc_client_create_identifier();
306 /* We'll take home path from /etc/passwd file to be sure. */
307 snprintf(filename, sizeof(filename) - 1, "%s/.silc/", pw->pw_dir);
308 snprintf(servfilename, sizeof(servfilename) - 1, "%s/.silc/serverkeys",
310 snprintf(clientfilename, sizeof(clientfilename) - 1, "%s/.silc/clientkeys",
314 * Check ~/.silc directory
316 if ((stat(filename, &st)) == -1) {
317 /* If dir doesn't exist */
318 if (errno == ENOENT) {
319 if (pw->pw_uid == geteuid()) {
320 if ((mkdir(filename, 0755)) == -1) {
321 fprintf(stderr, "Couldn't create `%s' directory\n", filename);
325 /* Directory was created. First time running SILC */
328 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
333 fprintf(stderr, "%s\n", strerror(errno));
338 /* Check the owner of the dir */
339 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
340 fprintf(stderr, "You don't seem to own `%s' directory\n",
345 /* Check the permissions of the dir */
346 if ((st.st_mode & 0777) != 0755) {
347 if ((chmod(filename, 0755)) == -1) {
348 fprintf(stderr, "Permissions for `%s' directory must be 0755\n",
356 * Check ~./silc/serverkeys directory
358 if ((stat(servfilename, &st)) == -1) {
359 /* If dir doesn't exist */
360 if (errno == ENOENT) {
361 if (pw->pw_uid == geteuid()) {
362 if ((mkdir(servfilename, 0755)) == -1) {
363 fprintf(stderr, "Couldn't create `%s' directory\n", servfilename);
367 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
372 fprintf(stderr, "%s\n", strerror(errno));
378 * Check ~./silc/clientkeys directory
380 if ((stat(clientfilename, &st)) == -1) {
381 /* If dir doesn't exist */
382 if (errno == ENOENT) {
383 if (pw->pw_uid == geteuid()) {
384 if ((mkdir(clientfilename, 0755)) == -1) {
385 fprintf(stderr, "Couldn't create `%s' directory\n", clientfilename);
389 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
394 fprintf(stderr, "%s\n", strerror(errno));
400 * Check Public and Private keys
402 snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s",
403 filename, SILC_CLIENT_PUBLIC_KEY_NAME);
404 snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s",
405 filename, SILC_CLIENT_PRIVATE_KEY_NAME);
407 /* If running SILC first time */
409 fprintf(stdout, "Running SILC for the first time\n");
410 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
411 SILC_CLIENT_DEF_PKCS_LEN,
412 file_public_key, file_private_key,
413 identifier, NULL, NULL);
417 if ((stat(file_public_key, &st)) == -1) {
418 /* If file doesn't exist */
419 if (errno == ENOENT) {
420 fprintf(stdout, "Your public key doesn't exist\n");
421 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
422 SILC_CLIENT_DEF_PKCS_LEN,
424 file_private_key, identifier, NULL, NULL);
426 fprintf(stderr, "%s\n", strerror(errno));
431 if ((stat(file_private_key, &st)) == -1) {
432 /* If file doesn't exist */
433 if (errno == ENOENT) {
434 fprintf(stdout, "Your private key doesn't exist\n");
435 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
436 SILC_CLIENT_DEF_PKCS_LEN,
438 file_private_key, identifier, NULL, NULL);
440 fprintf(stderr, "%s\n", strerror(errno));
445 /* Check the owner of the public key */
446 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
447 fprintf(stderr, "You don't seem to own your public key!?\n");
451 /* Check the owner of the private key */
452 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
453 fprintf(stderr, "You don't seem to own your private key!?\n");
457 /* Check the permissions for the private key */
458 if ((st.st_mode & 0777) != 0600) {
459 fprintf(stderr, "Wrong permissions in your private key file `%s'!\n"
460 "Trying to change them ... ", file_private_key);
461 if ((chmod(file_private_key, 0600)) == -1) {
463 "Failed to change permissions for private key file!\n"
464 "Permissions for your private key file must be 0600.\n");
467 fprintf(stderr, "Done.\n\n");
470 /* See if the key has expired. */
471 modtime = st.st_mtime; /* last modified */
472 curtime = time(0) - modtime;
474 /* 86400 is seconds in a day. */
475 if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) {
477 "--------------------------------------------------\n"
478 "Your private key has expired and needs to be\n"
479 "recreated. This will be done automatically now.\n"
480 "Your new key will expire in %d days from today.\n"
481 "--------------------------------------------------\n",
482 SILC_CLIENT_KEY_EXPIRES);
484 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
485 SILC_CLIENT_DEF_PKCS_LEN,
487 file_private_key, identifier, NULL, NULL);
491 silc_free(identifier);
496 /* Loads public and private key from files. */
498 int silc_client_load_keys(SilcClient client)
503 SILC_LOG_DEBUG(("Loading public and private keys"));
505 pw = getpwuid(getuid());
509 memset(filename, 0, sizeof(filename));
510 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s",
511 pw->pw_dir, SILC_CLIENT_PRIVATE_KEY_NAME);
513 if (silc_pkcs_load_private_key(filename, &client->private_key,
514 SILC_PKCS_FILE_BIN) == FALSE)
515 if (silc_pkcs_load_private_key(filename, &client->private_key,
516 SILC_PKCS_FILE_PEM) == FALSE)
519 memset(filename, 0, sizeof(filename));
520 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s",
521 pw->pw_dir, SILC_CLIENT_PUBLIC_KEY_NAME);
523 if (silc_pkcs_load_public_key(filename, &client->public_key,
524 SILC_PKCS_FILE_PEM) == FALSE)
525 if (silc_pkcs_load_public_key(filename, &client->public_key,
526 SILC_PKCS_FILE_BIN) == FALSE)
532 /* Dumps the public key on screen. Used from the command line option. */
534 int silc_client_show_key(char *keyfile)
536 SilcPublicKey public_key;
537 SilcPublicKeyIdentifier ident;
544 if (silc_pkcs_load_public_key(keyfile, &public_key,
545 SILC_PKCS_FILE_PEM) == FALSE)
546 if (silc_pkcs_load_public_key(keyfile, &public_key,
547 SILC_PKCS_FILE_BIN) == FALSE) {
548 fprintf(stderr, "Could not load public key file `%s'\n", keyfile);
552 ident = silc_pkcs_decode_identifier(public_key->identifier);
554 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
555 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
557 if (silc_pkcs_alloc(public_key->name, &pkcs)) {
558 key_len = silc_pkcs_public_key_set(pkcs, public_key);
559 silc_pkcs_free(pkcs);
562 printf("Public key file : %s\n", keyfile);
563 printf("Algorithm : %s\n", public_key->name);
565 printf("Key length (bits) : %d\n", key_len);
567 printf("Real name : %s\n", ident->realname);
569 printf("Username : %s\n", ident->username);
571 printf("Hostname : %s\n", ident->host);
573 printf("Email : %s\n", ident->email);
575 printf("Organization : %s\n", ident->org);
577 printf("Country : %s\n", ident->country);
578 printf("Fingerprint (SHA1) : %s\n", fingerprint);
582 silc_free(fingerprint);
584 silc_pkcs_public_key_free(public_key);
585 silc_pkcs_free_identifier(ident);