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 the username of the user. If the global variable LOGNAME
128 does not exists we will get the name from the password file. */
130 char *silc_get_username()
132 char *logname = NULL;
134 logname = strdup(getenv("LOGNAME"));
136 logname = getlogin();
140 pw = getpwuid(getuid());
142 fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
146 logname = strdup(pw->pw_name);
153 /* Returns the real name of ther user. */
155 char *silc_get_real_name()
157 char *realname = NULL;
160 pw = getpwuid(getuid());
162 fprintf(stderr, "silc_get_username: %s\n", strerror(errno));
166 if (strchr(pw->pw_gecos, ','))
167 *strchr(pw->pw_gecos, ',') = 0;
169 realname = strdup(pw->pw_gecos);
174 /* Returns time til next minute changes. Used to update the clock when
177 int silc_client_time_til_next_min()
183 min = localtime(&curtime);
185 return 60 - min->tm_sec;
188 /* Asks yes/no from user on the input line. Returns TRUE on "yes" and
191 int silc_client_ask_yes_no(SilcClient client, char *prompt)
193 SilcClientInternal app = (SilcClientInternal)client->application;
198 silc_screen_input_reset(app->screen);
201 wattroff(app->screen->input_win, A_INVIS);
202 silc_screen_input_print_prompt(app->screen, prompt);
205 memset(answer, 0, sizeof(answer));
207 wgetnstr(app->screen->input_win, answer, sizeof(answer));
208 if (!strncasecmp(answer, "yes", strlen(answer)) ||
209 !strncasecmp(answer, "y", strlen(answer))) {
211 } else if (!strncasecmp(answer, "no", strlen(answer)) ||
212 !strncasecmp(answer, "n", strlen(answer))) {
215 silc_say(client, app->conn, "Type yes or no");
220 silc_screen_input_reset(app->screen);
225 /* Lists supported (builtin) ciphers */
227 void silc_client_list_ciphers()
232 /* Lists supported (builtin) hash functions */
234 void silc_client_list_hash_funcs()
239 /* Lists supported PKCS algorithms */
241 void silc_client_list_pkcs()
246 /* Displays input prompt on command line and takes input data from user */
248 char *silc_client_get_input(const char *prompt)
253 fd = open("/dev/tty", O_RDONLY);
255 fprintf(stderr, "silc: %s\n", strerror(errno));
259 memset(input, 0, sizeof(input));
261 printf("%s", prompt);
264 if ((read(fd, input, sizeof(input))) < 0) {
265 fprintf(stderr, "silc: %s\n", strerror(errno));
269 if (strlen(input) <= 1)
272 if (strchr(input, '\n'))
273 *strchr(input, '\n') = '\0';
275 return strdup(input);
278 /* Displays prompt on command line and takes passphrase with echo
281 char *silc_client_get_passphrase(const char *prompt)
288 struct termios to_old;
290 fd = open("/dev/tty", O_RDONLY);
292 fprintf(stderr, "silc: %s\n", strerror(errno));
296 signal(SIGINT, SIG_IGN);
298 /* Get terminal info */
303 to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
304 tcsetattr(fd, TCSANOW, &to);
306 memset(input, 0, sizeof(input));
308 printf("%s", prompt);
311 if ((read(fd, input, sizeof(input))) < 0) {
312 fprintf(stderr, "silc: %s\n", strerror(errno));
316 if (strlen(input) <= 1) {
317 tcsetattr(fd, TCSANOW, &to_old);
321 if (strchr(input, '\n'))
322 *strchr(input, '\n') = '\0';
324 /* Restore old terminfo */
325 tcsetattr(fd, TCSANOW, &to_old);
326 signal(SIGINT, SIG_DFL);
328 ret = silc_calloc(strlen(input), sizeof(char));
329 memcpy(ret, input, strlen(input));
330 memset(input, 0, sizeof(input));
337 /* Returns identifier string for public key generation. */
339 char *silc_client_create_identifier()
341 char *username = NULL, *realname = NULL;
342 char hostname[256], email[256];
345 realname = silc_get_real_name();
348 memset(hostname, 0, sizeof(hostname));
349 gethostname(hostname, sizeof(hostname));
351 /* Get username (mandatory) */
352 username = silc_get_username();
356 /* Create default email address, whether it is right or not */
357 snprintf(email, sizeof(email), "%s@%s", username, hostname);
359 return silc_pkcs_encode_identifier(username, hostname, realname, email,
363 /* Creates new public key and private key pair. This is used only
364 when user wants to create new key pair from command line. */
366 int silc_client_create_key_pair(char *pkcs_name, int bits,
367 char *public_key, char *private_key,
369 SilcPublicKey *ret_pub_key,
370 SilcPrivateKey *ret_prv_key)
373 SilcPublicKey pub_key;
374 SilcPrivateKey prv_key;
377 unsigned int key_len;
379 char *pkfile = NULL, *prvfile = NULL;
381 if (!pkcs_name || !public_key || !private_key)
383 New pair of keys will be created. Please, answer to following questions.\n\
389 silc_client_get_input("PKCS name (l to list names) [rsa]: ");
391 pkcs_name = strdup("rsa");
393 if (*pkcs_name == 'l' || *pkcs_name == 'L') {
394 silc_client_list_pkcs();
395 silc_free(pkcs_name);
400 if (!silc_pkcs_is_supported(pkcs_name)) {
401 fprintf(stderr, "Unsupported PKCS `%s'", pkcs_name);
408 silc_client_get_input("Key length in bits [1024]: ");
416 char *def = silc_client_create_identifier();
418 memset(line, 0, sizeof(line));
420 snprintf(line, sizeof(line), "Identifier [%s]: ", def);
422 snprintf(line, sizeof(line),
423 "Identifier (eg. UN=jon, HN=jon.dummy.com, "
424 "RN=Jon Johnson, E=jon@dummy.com): ");
426 while (!identifier) {
427 identifier = silc_client_get_input(line);
428 if (!identifier && def)
429 identifier = strdup(def);
436 rng = silc_rng_alloc();
438 silc_math_primegen_init();
441 memset(line, 0, sizeof(line));
442 snprintf(line, sizeof(line), "Public key filename [%s] ",
443 SILC_CLIENT_PUBLIC_KEY_NAME);
444 pkfile = silc_client_get_input(line);
446 pkfile = SILC_CLIENT_PUBLIC_KEY_NAME;
452 memset(line, 0, sizeof(line));
453 snprintf(line, sizeof(line), "Public key filename [%s] ",
454 SILC_CLIENT_PRIVATE_KEY_NAME);
455 prvfile = silc_client_get_input(line);
457 prvfile = SILC_CLIENT_PRIVATE_KEY_NAME;
459 prvfile = private_key;
463 silc_pkcs_alloc(pkcs_name, &pkcs);
464 pkcs->pkcs->init(pkcs->context, bits, rng);
466 /* Save public key into file */
467 key = silc_pkcs_get_public_key(pkcs, &key_len);
468 pub_key = silc_pkcs_public_key_alloc(pkcs->pkcs->name, identifier,
470 silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
472 *ret_pub_key = pub_key;
474 memset(key, 0, sizeof(key_len));
477 /* Save private key into file */
478 key = silc_pkcs_get_private_key(pkcs, &key_len);
479 prv_key = silc_pkcs_private_key_alloc(pkcs->pkcs->name, key, key_len);
481 silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN);
483 *ret_prv_key = prv_key;
485 printf("Public key has been save into `%s'.\n", pkfile);
486 printf("Private key has been saved into `%s'.\n", prvfile);
487 printf("Press <Enter> to continue...\n");
490 memset(key, 0, sizeof(key_len));
493 silc_math_primegen_uninit();
495 silc_pkcs_free(pkcs);
500 /* This checks stats for various SILC files and directories. First it
501 checks if ~/.silc directory exist and is owned by the correct user. If
502 it doesn't exist, it will create the directory. After that it checks if
503 user's Public and Private key files exists and that they aren't expired.
504 If they doesn't exist or they are expired, they will be (re)created
507 int silc_client_check_silc_dir()
509 char filename[256], file_public_key[256], file_private_key[256];
510 char servfilename[256];
514 int firstime = FALSE;
515 time_t curtime, modtime;
517 SILC_LOG_DEBUG(("Checking ~./silc directory"));
519 memset(filename, 0, sizeof(filename));
520 memset(file_public_key, 0, sizeof(file_public_key));
521 memset(file_private_key, 0, sizeof(file_private_key));
523 pw = getpwuid(getuid());
525 fprintf(stderr, "silc: %s\n", strerror(errno));
529 identifier = silc_client_create_identifier();
531 /* We'll take home path from /etc/passwd file to be sure. */
532 snprintf(filename, sizeof(filename) - 1, "%s/.silc/", pw->pw_dir);
533 snprintf(servfilename, sizeof(servfilename) - 1, "%s/.silc/serverkeys",
537 * Check ~/.silc directory
539 if ((stat(filename, &st)) == -1) {
540 /* If dir doesn't exist */
541 if (errno == ENOENT) {
542 if (pw->pw_uid == geteuid()) {
543 if ((mkdir(filename, 0755)) == -1) {
544 fprintf(stderr, "Couldn't create `%s' directory\n", filename);
548 /* Directory was created. First time running SILC */
551 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
556 fprintf(stderr, "%s\n", strerror(errno));
561 /* Check the owner of the dir */
562 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
563 fprintf(stderr, "You don't seem to own `%s' directory\n",
568 /* Check the permissions of the dir */
569 if ((st.st_mode & 0777) != 0755) {
570 if ((chmod(filename, 0755)) == -1) {
571 fprintf(stderr, "Permissions for `%s' directory must be 0755\n",
579 * Check ~./silc/serverkeys directory
581 if ((stat(servfilename, &st)) == -1) {
582 /* If dir doesn't exist */
583 if (errno == ENOENT) {
584 if (pw->pw_uid == geteuid()) {
585 if ((mkdir(servfilename, 0755)) == -1) {
586 fprintf(stderr, "Couldn't create `%s' directory\n", servfilename);
590 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
595 fprintf(stderr, "%s\n", strerror(errno));
601 * Check Public and Private keys
603 snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s",
604 filename, SILC_CLIENT_PUBLIC_KEY_NAME);
605 snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s",
606 filename, SILC_CLIENT_PRIVATE_KEY_NAME);
608 /* If running SILC first time */
610 fprintf(stdout, "Running SILC for the first time\n");
611 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
612 SILC_CLIENT_DEF_PKCS_LEN,
613 file_public_key, file_private_key,
614 identifier, NULL, NULL);
618 if ((stat(file_public_key, &st)) == -1) {
619 /* If file doesn't exist */
620 if (errno == ENOENT) {
621 fprintf(stdout, "Your public key doesn't exist\n");
622 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
623 SILC_CLIENT_DEF_PKCS_LEN,
625 file_private_key, identifier, NULL, NULL);
627 fprintf(stderr, "%s\n", strerror(errno));
632 if ((stat(file_private_key, &st)) == -1) {
633 /* If file doesn't exist */
634 if (errno == ENOENT) {
635 fprintf(stdout, "Your private key doesn't exist\n");
636 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
637 SILC_CLIENT_DEF_PKCS_LEN,
639 file_private_key, identifier, NULL, NULL);
641 fprintf(stderr, "%s\n", strerror(errno));
646 /* Check the owner of the public key */
647 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
648 fprintf(stderr, "You don't seem to own your public key!?\n");
652 /* Check the owner of the private key */
653 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
654 fprintf(stderr, "You don't seem to own your private key!?\n");
658 /* Check the permissions for the private key */
659 if ((st.st_mode & 0777) != 0600) {
660 fprintf(stderr, "Wrong permissions in your private key file `%s'!\n"
661 "Trying to change them ... ", file_private_key);
662 if ((chmod(file_private_key, 0600)) == -1) {
664 "Failed to change permissions for private key file!\n"
665 "Permissions for your private key file must be 0600.\n");
668 fprintf(stderr, "Done.\n\n");
671 /* See if the key has expired. */
672 modtime = st.st_mtime; /* last modified */
673 curtime = time(0) - modtime;
675 /* 86400 is seconds in a day. */
676 if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) {
678 "--------------------------------------------------\n"
679 "Your private key has expired and needs to be\n"
680 "recreated. This will be done automatically now.\n"
681 "Your new key will expire in %d days from today.\n"
682 "--------------------------------------------------\n",
683 SILC_CLIENT_KEY_EXPIRES);
685 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
686 SILC_CLIENT_DEF_PKCS_LEN,
688 file_private_key, identifier, NULL, NULL);
692 silc_free(identifier);
697 /* Loads public and private key from files. */
699 int silc_client_load_keys(SilcClient client)
704 SILC_LOG_DEBUG(("Loading public and private keys"));
706 pw = getpwuid(getuid());
710 memset(filename, 0, sizeof(filename));
711 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s",
712 pw->pw_dir, SILC_CLIENT_PRIVATE_KEY_NAME);
714 if (silc_pkcs_load_private_key(filename, &client->private_key,
715 SILC_PKCS_FILE_BIN) == FALSE)
716 if (silc_pkcs_load_private_key(filename, &client->private_key,
717 SILC_PKCS_FILE_PEM) == 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,
725 SILC_PKCS_FILE_PEM) == FALSE)
726 if (silc_pkcs_load_public_key(filename, &client->public_key,
727 SILC_PKCS_FILE_BIN) == FALSE)