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_rng_global_init(rng);
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));
494 silc_pkcs_free(pkcs);
499 /* This checks stats for various SILC files and directories. First it
500 checks if ~/.silc directory exist and is owned by the correct user. If
501 it doesn't exist, it will create the directory. After that it checks if
502 user's Public and Private key files exists and that they aren't expired.
503 If they doesn't exist or they are expired, they will be (re)created
506 int silc_client_check_silc_dir()
508 char filename[256], file_public_key[256], file_private_key[256];
509 char servfilename[256], clientfilename[256];
513 int firstime = FALSE;
514 time_t curtime, modtime;
516 SILC_LOG_DEBUG(("Checking ~./silc directory"));
518 memset(filename, 0, sizeof(filename));
519 memset(file_public_key, 0, sizeof(file_public_key));
520 memset(file_private_key, 0, sizeof(file_private_key));
522 pw = getpwuid(getuid());
524 fprintf(stderr, "silc: %s\n", strerror(errno));
528 identifier = silc_client_create_identifier();
530 /* We'll take home path from /etc/passwd file to be sure. */
531 snprintf(filename, sizeof(filename) - 1, "%s/.silc/", pw->pw_dir);
532 snprintf(servfilename, sizeof(servfilename) - 1, "%s/.silc/serverkeys",
534 snprintf(clientfilename, sizeof(clientfilename) - 1, "%s/.silc/clientkeys",
538 * Check ~/.silc directory
540 if ((stat(filename, &st)) == -1) {
541 /* If dir doesn't exist */
542 if (errno == ENOENT) {
543 if (pw->pw_uid == geteuid()) {
544 if ((mkdir(filename, 0755)) == -1) {
545 fprintf(stderr, "Couldn't create `%s' directory\n", filename);
549 /* Directory was created. First time running SILC */
552 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
557 fprintf(stderr, "%s\n", strerror(errno));
562 /* Check the owner of the dir */
563 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
564 fprintf(stderr, "You don't seem to own `%s' directory\n",
569 /* Check the permissions of the dir */
570 if ((st.st_mode & 0777) != 0755) {
571 if ((chmod(filename, 0755)) == -1) {
572 fprintf(stderr, "Permissions for `%s' directory must be 0755\n",
580 * Check ~./silc/serverkeys directory
582 if ((stat(servfilename, &st)) == -1) {
583 /* If dir doesn't exist */
584 if (errno == ENOENT) {
585 if (pw->pw_uid == geteuid()) {
586 if ((mkdir(servfilename, 0755)) == -1) {
587 fprintf(stderr, "Couldn't create `%s' directory\n", servfilename);
591 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
596 fprintf(stderr, "%s\n", strerror(errno));
602 * Check ~./silc/clientkeys directory
604 if ((stat(clientfilename, &st)) == -1) {
605 /* If dir doesn't exist */
606 if (errno == ENOENT) {
607 if (pw->pw_uid == geteuid()) {
608 if ((mkdir(clientfilename, 0755)) == -1) {
609 fprintf(stderr, "Couldn't create `%s' directory\n", clientfilename);
613 fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
618 fprintf(stderr, "%s\n", strerror(errno));
624 * Check Public and Private keys
626 snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s",
627 filename, SILC_CLIENT_PUBLIC_KEY_NAME);
628 snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s",
629 filename, SILC_CLIENT_PRIVATE_KEY_NAME);
631 /* If running SILC first time */
633 fprintf(stdout, "Running SILC for the first time\n");
634 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
635 SILC_CLIENT_DEF_PKCS_LEN,
636 file_public_key, file_private_key,
637 identifier, NULL, NULL);
641 if ((stat(file_public_key, &st)) == -1) {
642 /* If file doesn't exist */
643 if (errno == ENOENT) {
644 fprintf(stdout, "Your public key doesn't exist\n");
645 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
646 SILC_CLIENT_DEF_PKCS_LEN,
648 file_private_key, identifier, NULL, NULL);
650 fprintf(stderr, "%s\n", strerror(errno));
655 if ((stat(file_private_key, &st)) == -1) {
656 /* If file doesn't exist */
657 if (errno == ENOENT) {
658 fprintf(stdout, "Your private key doesn't exist\n");
659 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
660 SILC_CLIENT_DEF_PKCS_LEN,
662 file_private_key, identifier, NULL, NULL);
664 fprintf(stderr, "%s\n", strerror(errno));
669 /* Check the owner of the public key */
670 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
671 fprintf(stderr, "You don't seem to own your public key!?\n");
675 /* Check the owner of the private key */
676 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
677 fprintf(stderr, "You don't seem to own your private key!?\n");
681 /* Check the permissions for the private key */
682 if ((st.st_mode & 0777) != 0600) {
683 fprintf(stderr, "Wrong permissions in your private key file `%s'!\n"
684 "Trying to change them ... ", file_private_key);
685 if ((chmod(file_private_key, 0600)) == -1) {
687 "Failed to change permissions for private key file!\n"
688 "Permissions for your private key file must be 0600.\n");
691 fprintf(stderr, "Done.\n\n");
694 /* See if the key has expired. */
695 modtime = st.st_mtime; /* last modified */
696 curtime = time(0) - modtime;
698 /* 86400 is seconds in a day. */
699 if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) {
701 "--------------------------------------------------\n"
702 "Your private key has expired and needs to be\n"
703 "recreated. This will be done automatically now.\n"
704 "Your new key will expire in %d days from today.\n"
705 "--------------------------------------------------\n",
706 SILC_CLIENT_KEY_EXPIRES);
708 silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS,
709 SILC_CLIENT_DEF_PKCS_LEN,
711 file_private_key, identifier, NULL, NULL);
715 silc_free(identifier);
720 /* Loads public and private key from files. */
722 int silc_client_load_keys(SilcClient client)
727 SILC_LOG_DEBUG(("Loading public and private keys"));
729 pw = getpwuid(getuid());
733 memset(filename, 0, sizeof(filename));
734 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s",
735 pw->pw_dir, SILC_CLIENT_PRIVATE_KEY_NAME);
737 if (silc_pkcs_load_private_key(filename, &client->private_key,
738 SILC_PKCS_FILE_BIN) == FALSE)
739 if (silc_pkcs_load_private_key(filename, &client->private_key,
740 SILC_PKCS_FILE_PEM) == FALSE)
743 memset(filename, 0, sizeof(filename));
744 snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s",
745 pw->pw_dir, SILC_CLIENT_PUBLIC_KEY_NAME);
747 if (silc_pkcs_load_public_key(filename, &client->public_key,
748 SILC_PKCS_FILE_PEM) == FALSE)
749 if (silc_pkcs_load_public_key(filename, &client->public_key,
750 SILC_PKCS_FILE_BIN) == FALSE)