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.
22 #include "clientincludes.h"
24 /* Routine used to print lines to window. This can split the
25 line neatly if a word would overlap the line. */
27 void silc_print_to_window(WINDOW *win, char *message)
31 str_len = strlen(message);
33 if (str_len > COLS - 1) {
34 /* Split overlapping words to next line */
35 /* XXX In principal this is wrong as this modifies the original
36 string as it replaces the last ' ' with '\n'. This could be done
37 with little more work so that it would not replace anything. */
41 while (len && message[len] != ' ')
54 wprintw(win, "%s", message);
58 /* Prints message to the screen. This is used to print the messages
59 user is typed and message that came on channels. */
61 void silc_print(SilcClient client, char *msg, ...)
65 SilcClientInternal app = client->application;
67 memset(message, 0, sizeof(message));
68 strncat(message, "\n ", 2);
71 vsprintf(message + 1, msg, vp);
74 /* Print the message */
75 silc_print_to_window(app->screen->output_win[0], message);
78 /* Returns user's mail path */
80 char *silc_get_mail_path()
82 char pathbuf[MAXPATHLEN];
86 #define _PATH_MAILDIR "/var/mail"
89 path = getenv("MAIL");
91 strncpy(pathbuf, path, strlen(path));
93 strcpy(pathbuf, _PATH_MAILDIR);
95 strcat(pathbuf, silc_get_username());
98 return strdup(pathbuf);
101 /* gets the number of the user's mails, if possible */
103 int silc_get_number_of_emails()
110 filename = silc_get_mail_path();
112 tl = fopen(filename, "r");
114 fprintf(stderr, "Couldn't open mail file (%s).\n", filename);
116 while((fscanf(tl, "%s", data)) != EOF) {
117 if(!strcmp(data, "From:"))
127 /* Returns time til next minute changes. Used to update the clock when
130 int silc_client_time_til_next_min()
136 min = localtime(&curtime);
138 return 60 - min->tm_sec;
141 /* Asks yes/no from user on the input line. Returns TRUE on "yes" and
144 int silc_client_ask_yes_no(SilcClient client, char *prompt)
146 SilcClientInternal app = (SilcClientInternal)client->application;
151 silc_screen_input_reset(app->screen);
154 wattroff(app->screen->input_win, A_INVIS);
155 silc_screen_input_print_prompt(app->screen, prompt);
158 memset(answer, 0, sizeof(answer));
160 wgetnstr(app->screen->input_win, answer, sizeof(answer));
161 if (!strncasecmp(answer, "yes", strlen(answer)) ||
162 !strncasecmp(answer, "y", strlen(answer))) {
164 } else if (!strncasecmp(answer, "no", strlen(answer)) ||
165 !strncasecmp(answer, "n", strlen(answer))) {
168 silc_say(client, app->conn, "Type yes or no");
173 silc_screen_input_reset(app->screen);
178 /* Lists supported (builtin) ciphers */
180 void silc_client_list_ciphers()
182 char *ciphers = silc_cipher_get_supported();
183 fprintf(stdout, "%s\n", ciphers);
187 /* Lists supported (builtin) hash functions */
189 void silc_client_list_hash_funcs()
191 char *hash = silc_hash_get_supported();
192 fprintf(stdout, "%s\n", hash);
196 /* Lists supported PKCS algorithms */
198 void silc_client_list_pkcs()
200 char *pkcs = silc_pkcs_get_supported();
201 fprintf(stdout, "%s\n", pkcs);
205 /* Displays input prompt on command line and takes input data from user */
207 char *silc_client_get_input(const char *prompt)
212 fd = open("/dev/tty", O_RDONLY);
214 fprintf(stderr, "silc: %s\n", strerror(errno));
218 memset(input, 0, sizeof(input));
220 printf("%s", prompt);
223 if ((read(fd, input, sizeof(input))) < 0) {
224 fprintf(stderr, "silc: %s\n", strerror(errno));
228 if (strlen(input) <= 1)
231 if (strchr(input, '\n'))
232 *strchr(input, '\n') = '\0';
234 return strdup(input);
237 /* Displays prompt on command line and takes passphrase with echo
240 char *silc_client_get_passphrase(const char *prompt)
247 struct termios to_old;
249 fd = open("/dev/tty", O_RDONLY);
251 fprintf(stderr, "silc: %s\n", strerror(errno));
255 signal(SIGINT, SIG_IGN);
257 /* Get terminal info */
262 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
263 tcsetattr(fd, TCSANOW, &to);
265 memset(input, 0, sizeof(input));
267 printf("%s", prompt);
270 if ((read(fd, input, sizeof(input))) < 0) {
271 fprintf(stderr, "silc: %s\n", strerror(errno));
275 if (strlen(input) <= 1) {
276 tcsetattr(fd, TCSANOW, &to_old);
280 if (strchr(input, '\n'))
281 *strchr(input, '\n') = '\0';
283 /* Restore old terminfo */
284 tcsetattr(fd, TCSANOW, &to_old);
285 signal(SIGINT, SIG_DFL);
287 ret = silc_calloc(strlen(input), sizeof(char));
288 memcpy(ret, input, strlen(input));
289 memset(input, 0, sizeof(input));
296 /* Returns identifier string for public key generation. */
298 char *silc_client_create_identifier()
300 char *username = NULL, *realname = NULL;
301 char hostname[256], email[256];
304 realname = silc_get_real_name();
307 memset(hostname, 0, sizeof(hostname));
308 gethostname(hostname, sizeof(hostname));
310 /* Get username (mandatory) */
311 username = silc_get_username();
315 /* Create default email address, whether it is right or not */
316 snprintf(email, sizeof(email), "%s@%s", username, hostname);
318 return silc_pkcs_encode_identifier(username, hostname, realname, email,
322 /* Creates new public key and private key pair. This is used only
323 when user wants to create new key pair from command line. */
325 int silc_client_create_key_pair(char *pkcs_name, int bits,
326 char *public_key, char *private_key,
328 SilcPublicKey *ret_pub_key,
329 SilcPrivateKey *ret_prv_key)
332 SilcPublicKey pub_key;
333 SilcPrivateKey prv_key;
338 char *pkfile = NULL, *prvfile = NULL;
340 if (!pkcs_name || !public_key || !private_key)
342 New pair of keys will be created. Please, answer to following questions.\n\
348 silc_client_get_input("PKCS name (l to list names) [rsa]: ");
350 pkcs_name = strdup("rsa");
352 if (*pkcs_name == 'l' || *pkcs_name == 'L') {
353 silc_client_list_pkcs();
354 silc_free(pkcs_name);
359 if (!silc_pkcs_is_supported(pkcs_name)) {
360 fprintf(stderr, "Unknown PKCS `%s'", pkcs_name);
367 silc_client_get_input("Key length in bits [1024]: ");
375 char *def = silc_client_create_identifier();
377 memset(line, 0, sizeof(line));
379 snprintf(line, sizeof(line), "Identifier [%s]: ", def);
381 snprintf(line, sizeof(line),
382 "Identifier (eg. UN=jon, HN=jon.dummy.com, "
383 "RN=Jon Johnson, E=jon@dummy.com): ");
385 while (!identifier) {
386 identifier = silc_client_get_input(line);
387 if (!identifier && def)
388 identifier = strdup(def);
395 rng = silc_rng_alloc();
397 silc_rng_global_init(rng);
400 memset(line, 0, sizeof(line));
401 snprintf(line, sizeof(line), "Public key filename [%s] ",
402 SILC_CLIENT_PUBLIC_KEY_NAME);
403 pkfile = silc_client_get_input(line);
405 pkfile = SILC_CLIENT_PUBLIC_KEY_NAME;
411 memset(line, 0, sizeof(line));
412 snprintf(line, sizeof(line), "Public key filename [%s] ",
413 SILC_CLIENT_PRIVATE_KEY_NAME);
414 prvfile = silc_client_get_input(line);
416 prvfile = SILC_CLIENT_PRIVATE_KEY_NAME;
418 prvfile = private_key;
422 silc_pkcs_alloc(pkcs_name, &pkcs);
423 pkcs->pkcs->init(pkcs->context, bits, rng);
425 /* Save public key into file */
426 key = silc_pkcs_get_public_key(pkcs, &key_len);
427 pub_key = silc_pkcs_public_key_alloc(pkcs->pkcs->name, identifier,
429 silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
431 *ret_pub_key = pub_key;
433 memset(key, 0, sizeof(key_len));
436 /* Save private key into file */
437 key = silc_pkcs_get_private_key(pkcs, &key_len);
438 prv_key = silc_pkcs_private_key_alloc(pkcs->pkcs->name, key, key_len);
440 silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN);
442 *ret_prv_key = prv_key;
444 printf("Public key has been saved into `%s'.\n", pkfile);
445 printf("Private key has been saved into `%s'.\n", prvfile);
446 printf("Press <Enter> to continue...\n");
449 memset(key, 0, sizeof(key_len));
453 silc_pkcs_free(pkcs);
458 /* This checks stats for various SILC files and directories. First it
459 checks if ~/.silc directory exist and is owned by the correct user. If
460 it doesn't exist, it will create the directory. After that it checks if
461 user's Public and Private key files exists and that they aren't expired.
462 If they doesn't exist or they are expired, they will be (re)created
465 int silc_client_check_silc_dir()
467 char filename[256], file_public_key[256], file_private_key[256];
468 char servfilename[256], clientfilename[256];
472 int firstime = FALSE;
473 time_t curtime, modtime;
475 SILC_LOG_DEBUG(("Checking ~./silc directory"));
477 memset(filename, 0, sizeof(filename));
478 memset(file_public_key, 0, sizeof(file_public_key));
479 memset(file_private_key, 0, sizeof(file_private_key));
481 pw = getpwuid(getuid());
483 fprintf(stderr, "silc: %s\n", strerror(errno));
487 identifier = silc_client_create_identifier();
489 /* We'll take home path from /etc/passwd file to be sure. */
490 snprintf(filename, sizeof(filename) - 1, "%s/.silc/", pw->pw_dir);
491 snprintf(servfilename, sizeof(servfilename) - 1, "%s/.silc/serverkeys",
493 snprintf(clientfilename, sizeof(clientfilename) - 1, "%s/.silc/clientkeys",
497 * Check ~/.silc directory
499 if ((stat(filename, &st)) == -1) {
500 /* If dir doesn't exist */
501 if (errno == ENOENT) {
502 if (pw->pw_uid == geteuid()) {
503 if ((mkdir(filename, 0755)) == -1) {
504 fprintf(stderr, "Couldn't create `%s' directory\n", filename);
508 /* Directory was created. First time running SILC */
511 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
516 fprintf(stderr, "%s\n", strerror(errno));
521 /* Check the owner of the dir */
522 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
523 fprintf(stderr, "You don't seem to own `%s' directory\n",
528 /* Check the permissions of the dir */
529 if ((st.st_mode & 0777) != 0755) {
530 if ((chmod(filename, 0755)) == -1) {
531 fprintf(stderr, "Permissions for `%s' directory must be 0755\n",
539 * Check ~./silc/serverkeys directory
541 if ((stat(servfilename, &st)) == -1) {
542 /* If dir doesn't exist */
543 if (errno == ENOENT) {
544 if (pw->pw_uid == geteuid()) {
545 if ((mkdir(servfilename, 0755)) == -1) {
546 fprintf(stderr, "Couldn't create `%s' directory\n", servfilename);
550 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
555 fprintf(stderr, "%s\n", strerror(errno));
561 * Check ~./silc/clientkeys directory
563 if ((stat(clientfilename, &st)) == -1) {
564 /* If dir doesn't exist */
565 if (errno == ENOENT) {
566 if (pw->pw_uid == geteuid()) {
567 if ((mkdir(clientfilename, 0755)) == -1) {
568 fprintf(stderr, "Couldn't create `%s' directory\n", clientfilename);
572 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
577 fprintf(stderr, "%s\n", strerror(errno));
583 * Check Public and Private keys
585 snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s",
586 filename, SILC_CLIENT_PUBLIC_KEY_NAME);
587 snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s",
588 filename, SILC_CLIENT_PRIVATE_KEY_NAME);
590 /* If running SILC first time */
592 fprintf(stdout, "Running SILC for the first time\n");
593 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
594 SILC_CLIENT_DEF_PKCS_LEN,
595 file_public_key, file_private_key,
596 identifier, NULL, NULL);
600 if ((stat(file_public_key, &st)) == -1) {
601 /* If file doesn't exist */
602 if (errno == ENOENT) {
603 fprintf(stdout, "Your public key doesn't exist\n");
604 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
605 SILC_CLIENT_DEF_PKCS_LEN,
607 file_private_key, identifier, NULL, NULL);
609 fprintf(stderr, "%s\n", strerror(errno));
614 if ((stat(file_private_key, &st)) == -1) {
615 /* If file doesn't exist */
616 if (errno == ENOENT) {
617 fprintf(stdout, "Your private key doesn't exist\n");
618 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
619 SILC_CLIENT_DEF_PKCS_LEN,
621 file_private_key, identifier, NULL, NULL);
623 fprintf(stderr, "%s\n", strerror(errno));
628 /* Check the owner of the public key */
629 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
630 fprintf(stderr, "You don't seem to own your public key!?\n");
634 /* Check the owner of the private key */
635 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
636 fprintf(stderr, "You don't seem to own your private key!?\n");
640 /* Check the permissions for the private key */
641 if ((st.st_mode & 0777) != 0600) {
642 fprintf(stderr, "Wrong permissions in your private key file `%s'!\n"
643 "Trying to change them ... ", file_private_key);
644 if ((chmod(file_private_key, 0600)) == -1) {
646 "Failed to change permissions for private key file!\n"
647 "Permissions for your private key file must be 0600.\n");
650 fprintf(stderr, "Done.\n\n");
653 /* See if the key has expired. */
654 modtime = st.st_mtime; /* last modified */
655 curtime = time(0) - modtime;
657 /* 86400 is seconds in a day. */
658 if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) {
660 "--------------------------------------------------\n"
661 "Your private key has expired and needs to be\n"
662 "recreated. This will be done automatically now.\n"
663 "Your new key will expire in %d days from today.\n"
664 "--------------------------------------------------\n",
665 SILC_CLIENT_KEY_EXPIRES);
667 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
668 SILC_CLIENT_DEF_PKCS_LEN,
670 file_private_key, identifier, NULL, NULL);
674 silc_free(identifier);
679 /* Loads public and private key from files. */
681 int silc_client_load_keys(SilcClient client)
686 SILC_LOG_DEBUG(("Loading public and private keys"));
688 pw = getpwuid(getuid());
692 memset(filename, 0, sizeof(filename));
693 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s",
694 pw->pw_dir, SILC_CLIENT_PRIVATE_KEY_NAME);
696 if (silc_pkcs_load_private_key(filename, &client->private_key,
697 SILC_PKCS_FILE_BIN) == FALSE)
698 if (silc_pkcs_load_private_key(filename, &client->private_key,
699 SILC_PKCS_FILE_PEM) == FALSE)
702 memset(filename, 0, sizeof(filename));
703 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s",
704 pw->pw_dir, SILC_CLIENT_PUBLIC_KEY_NAME);
706 if (silc_pkcs_load_public_key(filename, &client->public_key,
707 SILC_PKCS_FILE_PEM) == FALSE)
708 if (silc_pkcs_load_public_key(filename, &client->public_key,
709 SILC_PKCS_FILE_BIN) == FALSE)
715 /* Dumps the public key on screen. Used from the command line option. */
717 int silc_client_show_key(char *keyfile)
719 SilcPublicKey public_key;
720 SilcPublicKeyIdentifier ident;
727 if (silc_pkcs_load_public_key(keyfile, &public_key,
728 SILC_PKCS_FILE_PEM) == FALSE)
729 if (silc_pkcs_load_public_key(keyfile, &public_key,
730 SILC_PKCS_FILE_BIN) == FALSE) {
731 fprintf(stderr, "Could not load public key file `%s'\n", keyfile);
735 ident = silc_pkcs_decode_identifier(public_key->identifier);
737 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
738 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
740 if (silc_pkcs_alloc(public_key->name, &pkcs)) {
741 key_len = silc_pkcs_public_key_set(pkcs, public_key);
742 silc_pkcs_free(pkcs);
745 printf("Public key file : %s\n", keyfile);
746 printf("Algorithm : %s\n", public_key->name);
748 printf("Key length (bits) : %d\n", key_len);
750 printf("Real name : %s\n", ident->realname);
752 printf("Username : %s\n", ident->username);
754 printf("Hostname : %s\n", ident->host);
756 printf("Email : %s\n", ident->email);
758 printf("Organization : %s\n", ident->org);
760 printf("Country : %s\n", ident->country);
761 printf("Fingerprint (SHA1) : %s\n", fingerprint);
765 silc_free(fingerprint);
767 silc_pkcs_public_key_free(public_key);
768 silc_pkcs_free_identifier(ident);