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.
23 * Revision 1.2 2000/07/05 06:11:00 priikone
24 * Added ~./silc directory checking, autoloading of keys and
25 * tweaked the key pair generation function.
27 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
28 * Imported from internal CVS/Added Log headers.
33 #include "clientincludes.h"
35 /* Internal routine used to print lines to window. This can split the
36 line neatly if a word would overlap the line. */
38 static void silc_print_to_window(WINDOW *win, char *message)
42 str_len = strlen(message);
44 if (str_len > COLS - 1) {
45 /* Split overlapping words to next line */
46 /* XXX In principal this is wrong as this modifies the original
47 string as it replaces the last ' ' with '\n'. This could be done
48 with little more work so that it would not replace anything. */
52 while (len && message[len] != ' ')
65 wprintw(win, "%s", message);
69 /* Prints a message with three star (*) sign before the actual message
70 on the current output window. This is used to print command outputs
71 and error messages. */
72 /* XXX Change to accept SilcClientWindow and use output window
73 from there (the pointer to the output window must be added to the
74 SilcClientWindow object. */
76 void silc_say(SilcClient client, char *msg, ...)
81 memset(message, 0, sizeof(message));
82 strncat(message, "\n*** ", 5);
85 vsprintf(message + 5, msg, vp);
88 /* Print the message */
89 silc_print_to_window(client->screen->output_win[0], message);
92 /* Prints message to the screen. This is used to print the messages
93 user is typed and message that came on channels. */
95 void silc_print(SilcClient client, char *msg, ...)
100 memset(message, 0, sizeof(message));
101 strncat(message, "\n ", 2);
104 vsprintf(message + 1, msg, vp);
107 /* Print the message */
108 silc_print_to_window(client->screen->output_win[0], message);
111 /* Returns user's mail path */
113 char *silc_get_mail_path()
115 char pathbuf[MAXPATHLEN];
118 if ((path = (char *)getenv("MAIL")) != 0) {
119 strncpy(pathbuf, path, strlen(path));
121 strcpy(pathbuf, _PATH_MAILDIR);
122 strcat(pathbuf, "/");
123 strcat(pathbuf, silc_get_username());
126 return strdup(pathbuf);
129 /* gets the number of the user's mails, if possible */
131 int silc_get_number_of_emails()
138 filename = silc_get_mail_path();
140 tl = fopen(filename, "r");
142 fprintf(stderr, "Couldn't open mail file (%s).\n", filename);
144 while((fscanf(tl, "%s", data)) != EOF) {
145 if(!strcmp(data, "Subject:"))
155 /* Returns the username of the user. If the global variable LOGNAME
156 does not exists we will get the name from the password file. */
158 char *silc_get_username()
160 char *logname = NULL;
162 logname = strdup(getenv("LOGNAME"));
164 logname = getlogin();
168 pw = getpwuid(getuid());
170 fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
174 logname = strdup(pw->pw_name);
181 /* Returns the real name of ther user. */
183 char *silc_get_real_name()
185 char *realname = NULL;
188 pw = getpwuid(getuid());
190 fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
194 if (strchr(pw->pw_gecos, ','))
195 *strchr(pw->pw_gecos, ',') = 0;
197 realname = strdup(pw->pw_gecos);
202 /* Returns time til next minute changes. Used to update the clock when
205 int silc_client_time_til_next_min()
211 min = localtime(&curtime);
213 return 60 - min->tm_sec;
216 /* Asks passphrase from user on the input line. */
218 char *silc_client_ask_passphrase(SilcClient client)
220 char pass1[256], pass2[256];
227 wattroff(client->screen->input_win, A_INVIS);
228 silc_screen_input_print_prompt(client->screen, "Passphrase: ");
229 wattron(client->screen->input_win, A_INVIS);
232 memset(pass1, 0, sizeof(pass1));
233 wgetnstr(client->screen->input_win, pass1, sizeof(pass1));
235 /* Print retype prompt */
236 wattroff(client->screen->input_win, A_INVIS);
237 silc_screen_input_print_prompt(client->screen, "Retype passphrase: ");
238 wattron(client->screen->input_win, A_INVIS);
241 memset(pass2, 0, sizeof(pass2));
242 wgetnstr(client->screen->input_win, pass2, sizeof(pass2));
244 if (!strncmp(pass1, pass2, strlen(pass2)))
250 ret = silc_calloc(strlen(pass1), sizeof(char));
251 memcpy(ret, pass1, strlen(pass1));
253 memset(pass1, 0, sizeof(pass1));
254 memset(pass2, 0, sizeof(pass2));
256 wattroff(client->screen->input_win, A_INVIS);
257 silc_screen_input_reset(client->screen);
262 /* Lists supported (builtin) ciphers */
264 void silc_client_list_ciphers()
269 /* Lists supported (builtin) hash functions */
271 void silc_client_list_hash_funcs()
276 /* Lists supported PKCS algorithms */
278 void silc_client_list_pkcs()
283 /* Displays input prompt on command line and takes input data from user */
285 char *silc_client_get_input(const char *prompt)
290 fd = open("/dev/tty", O_RDONLY);
292 fprintf(stderr, "silc: %s\n", strerror(errno));
296 memset(input, 0, sizeof(input));
298 printf("%s", prompt);
301 if ((read(fd, input, sizeof(input))) < 0) {
302 fprintf(stderr, "silc: %s\n", strerror(errno));
306 if (strlen(input) <= 1)
309 if (strchr(input, '\n'))
310 *strchr(input, '\n') = '\0';
312 return strdup(input);
315 /* Displays prompt on command line and takes passphrase with echo
318 char *silc_client_get_passphrase(const char *prompt)
325 struct termios to_old;
327 fd = open("/dev/tty", O_RDONLY);
329 fprintf(stderr, "silc: %s\n", strerror(errno));
333 signal(SIGINT, SIG_IGN);
335 /* Get terminal info */
340 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
341 tcsetattr(fd, TCSANOW, &to);
343 memset(input, 0, sizeof(input));
345 printf("%s", prompt);
348 if ((read(fd, input, sizeof(input))) < 0) {
349 fprintf(stderr, "silc: %s\n", strerror(errno));
353 if (strlen(input) <= 1) {
354 tcsetattr(fd, TCSANOW, &to_old);
358 if (strchr(input, '\n'))
359 *strchr(input, '\n') = '\0';
361 /* Restore old terminfo */
362 tcsetattr(fd, TCSANOW, &to_old);
363 signal(SIGINT, SIG_DFL);
365 ret = silc_calloc(strlen(input), sizeof(char));
366 memcpy(ret, input, strlen(input));
367 memset(input, 0, sizeof(input));
374 /* Returns identifier string for public key generation. */
376 char *silc_client_create_identifier()
378 char *username = NULL, *realname = NULL;
379 char hostname[256], email[256];
382 realname = silc_get_real_name();
385 memset(hostname, 0, sizeof(hostname));
386 gethostname(hostname, sizeof(hostname));
388 /* Get username (mandatory) */
389 username = silc_get_username();
393 /* Create default email address, whether it is right or not */
394 snprintf(email, sizeof(email), "%s@%s", username, hostname);
396 return silc_pkcs_encode_identifier(username, hostname, realname, email,
400 /* Creates new public key and private key pair. This is used only
401 when user wants to create new key pair from command line. */
403 int silc_client_create_key_pair(char *pkcs_name, int bits,
404 char *public_key, char *private_key,
406 SilcPublicKey *ret_pub_key,
407 SilcPrivateKey *ret_prv_key)
410 SilcPublicKey pub_key;
411 SilcPrivateKey prv_key;
414 unsigned int key_len;
415 char *pkfile = NULL, *prvfile = NULL;
417 if (!pkcs_name || !public_key || !private_key)
419 New pair of keys will be created. Please, answer to following questions.\n\
425 silc_client_get_input("PKCS name (l to list names) [rsa]: ");
427 pkcs_name = strdup("rsa");
429 if (*pkcs_name == 'l' || *pkcs_name == 'L') {
430 silc_client_list_pkcs();
431 silc_free(pkcs_name);
436 if (!silc_pkcs_is_supported(pkcs_name)) {
437 fprintf(stderr, "Unsupported PKCS `%s'", pkcs_name);
444 silc_client_get_input("Key length in bits [1024]: ");
452 char *def = silc_client_create_identifier();
455 snprintf(def, sizeof(def), "Public key identifier [%s]: ", def);
457 snprintf(def, sizeof(def),
458 "Public key identifier (eg. UN=priikone, HN=poseidon.pspt.fi, "
459 "RN=Pekka Riikonen, E=priikone@poseidon.pspt.fi): ");
462 identifier = silc_client_get_input(def);
470 rng = silc_rng_alloc();
472 silc_math_primegen_init();
476 pkfile = silc_client_get_input("Public key filename: ");
478 printf("Public key filename must be defined\n");
487 prvfile = silc_client_get_input("Private key filename: ");
489 printf("Private key filename must be defined\n");
493 prvfile = private_key;
497 silc_pkcs_alloc(pkcs_name, &pkcs);
498 pkcs->pkcs->init(pkcs->context, bits, rng);
500 /* Save public key into file */
501 key = silc_pkcs_get_public_key(pkcs, &key_len);
502 pub_key = silc_pkcs_public_key_alloc(pkcs->pkcs->name, identifier,
504 silc_pkcs_save_public_key(pkfile, pub_key);
506 *ret_pub_key = pub_key;
508 memset(key, 0, sizeof(key_len));
511 /* Save private key into file */
512 key = silc_pkcs_get_private_key(pkcs, &key_len);
513 prv_key = silc_pkcs_private_key_alloc(pkcs->pkcs->name, key, key_len);
515 silc_pkcs_save_private_key(prvfile, prv_key, NULL);
517 *ret_prv_key = prv_key;
519 memset(key, 0, sizeof(key_len));
522 silc_math_primegen_uninit();
524 silc_pkcs_free(pkcs);
529 /* This checks stats for various SILC files and directories. First it
530 checks if ~/.silc directory exist and is owned by the correct user. If
531 it doesn't exist, it will create the directory. After that it checks if
532 user's Public and Private key files exists and that they aren't expired.
533 If they doesn't exist or they are expired, they will be (re)created
536 int silc_client_check_silc_dir()
538 char filename[256], file_public_key[256], file_private_key[256];
542 int firstime = FALSE;
543 time_t curtime, modtime;
545 SILC_LOG_DEBUG(("Checking ~./silc directory"));
547 memset(filename, 0, sizeof(filename));
548 memset(file_public_key, 0, sizeof(file_public_key));
549 memset(file_private_key, 0, sizeof(file_private_key));
551 pw = getpwuid(getuid());
553 fprintf(stderr, "silc: %s\n", strerror(errno));
557 identifier = silc_client_create_identifier();
559 /* We'll take home path from /etc/passwd file to be sure. */
560 snprintf(filename, sizeof(filename) - 1, "%s/.silc/", pw->pw_dir);
563 * Check ~/.silc directory
565 if ((stat(filename, &st)) == -1) {
566 /* If dir doesn't exist */
567 if (errno == ENOENT) {
568 if (pw->pw_uid == geteuid()) {
569 if ((mkdir(filename, 0755)) == -1) {
570 fprintf(stderr, "Couldn't create `%s' directory\n", filename);
574 /* Directory was created. First time running SILC */
577 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
582 fprintf(stderr, "%s\n", strerror(errno));
587 /* Check the owner of the dir */
588 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
589 fprintf(stderr, "You don't seem to own `%s' directory\n",
594 /* Check the permissions of the dir */
595 if ((st.st_mode & 0777) != 0755) {
596 if ((chmod(filename, 0755)) == -1) {
597 fprintf(stderr, "Permissions for `%s' directory must be 0755\n",
604 * Check Public and Private keys
606 snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s",
607 filename, SILC_CLIENT_PUBLIC_KEY_NAME);
608 snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s",
609 filename, SILC_CLIENT_PRIVATE_KEY_NAME);
611 /* If running SILC first time */
613 fprintf(stdout, "Running SILC for the first time.\n");
614 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
615 SILC_CLIENT_DEF_PKCS_LEN,
616 file_public_key, file_private_key,
617 identifier, NULL, NULL);
621 if ((stat(file_public_key, &st)) == -1) {
622 /* If file doesn't exist */
623 if (errno == ENOENT) {
624 fprintf(stdout, "Your public key doesn't exist\n");
625 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
626 SILC_CLIENT_DEF_PKCS_LEN,
628 file_private_key, identifier, NULL, NULL);
630 fprintf(stderr, "%s\n", strerror(errno));
635 if ((stat(file_private_key, &st)) == -1) {
636 /* If file doesn't exist */
637 if (errno == ENOENT) {
638 fprintf(stdout, "Your private key doesn't exist\n");
639 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
640 SILC_CLIENT_DEF_PKCS_LEN,
642 file_private_key, identifier, NULL, NULL);
644 fprintf(stderr, "%s\n", strerror(errno));
649 /* Check the owner of the public key */
650 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
651 fprintf(stderr, "You don't seem to own your public key!?\n");
655 /* Check the owner of the private key */
656 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
657 fprintf(stderr, "You don't seem to own your private key!?\n");
661 /* Check the permissions for the private key */
662 if ((st.st_mode & 0777) != 0600) {
663 fprintf(stderr, "Wrong permissions in your private key file `%s'!\n"
664 "Trying to change them ... ", file_private_key);
665 if ((chmod(file_private_key, 0600)) == -1) {
667 "Failed to change permissions for private key file!\n"
668 "Permissions for your private key file must be 0600.\n");
671 fprintf(stderr, "Done.\n\n");
674 /* See if the key has expired. */
675 modtime = st.st_mtime; /* last modified */
676 curtime = time(0) - modtime;
678 /* 86400 is seconds in a day. */
679 if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) {
681 "--------------------------------------------------\n"
682 "Your private key has expired and needs to be\n"
683 "recreated. This will be done automatically now.\n"
684 "Your new key will expire in %d days from today.\n"
685 "--------------------------------------------------\n",
686 SILC_CLIENT_KEY_EXPIRES);
688 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
689 SILC_CLIENT_DEF_PKCS_LEN,
691 file_private_key, identifier, NULL, NULL);
695 silc_free(identifier);
700 /* Loads public and private key from files. */
702 int silc_client_load_keys(SilcClient client)
707 SILC_LOG_DEBUG(("Loading public and private keys"));
709 pw = getpwuid(getuid());
713 memset(filename, 0, sizeof(filename));
714 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s",
715 pw->pw_dir, SILC_CLIENT_PRIVATE_KEY_NAME);
717 if (silc_pkcs_load_private_key(filename, &client->private_key) == FALSE)
720 memset(filename, 0, sizeof(filename));
721 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s",
722 pw->pw_dir, SILC_CLIENT_PUBLIC_KEY_NAME);
724 if (silc_pkcs_load_public_key(filename, &client->public_key) == FALSE)