diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/core/Makefile.am | 4 | ||||
-rw-r--r-- | src/core/wee-command.c | 2 | ||||
-rw-r--r-- | src/core/wee-secure-buffer.c | 229 | ||||
-rw-r--r-- | src/core/wee-secure-buffer.h | 32 | ||||
-rw-r--r-- | src/core/wee-secure-config.c | 628 | ||||
-rw-r--r-- | src/core/wee-secure-config.h | 38 | ||||
-rw-r--r-- | src/core/wee-secure.c | 834 | ||||
-rw-r--r-- | src/core/wee-secure.h | 36 | ||||
-rw-r--r-- | src/core/wee-upgrade.c | 2 | ||||
-rw-r--r-- | src/core/weechat.c | 11 | ||||
-rw-r--r-- | src/gui/gui-buffer.c | 2 |
12 files changed, 991 insertions, 829 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8574dcf78..788aa24d2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -39,6 +39,8 @@ set(LIB_CORE_SRC wee-network.c wee-network.h wee-proxy.c wee-proxy.h wee-secure.c wee-secure.h + wee-secure-buffer.c wee-secure-buffer.h + wee-secure-config.c wee-secure-config.h wee-string.c wee-string.h wee-upgrade.c wee-upgrade.h wee-upgrade-file.c wee-upgrade-file.h diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 009f0c2cb..ba6250c16 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -59,6 +59,10 @@ lib_weechat_core_a_SOURCES = weechat.c \ wee-proxy.h \ wee-secure.c \ wee-secure.h \ + wee-secure-buffer.c \ + wee-secure-buffer.h \ + wee-secure-config.c \ + wee-secure-config.h \ wee-string.c \ wee-string.h \ wee-upgrade.c \ diff --git a/src/core/wee-command.c b/src/core/wee-command.c index 934f3006a..2b680d723 100644 --- a/src/core/wee-command.c +++ b/src/core/wee-command.c @@ -54,6 +54,8 @@ #include "wee-log.h" #include "wee-proxy.h" #include "wee-secure.h" +#include "wee-secure-buffer.h" +#include "wee-secure-config.h" #include "wee-string.h" #include "wee-upgrade.h" #include "wee-utf8.h" diff --git a/src/core/wee-secure-buffer.c b/src/core/wee-secure-buffer.c new file mode 100644 index 000000000..5a0d96342 --- /dev/null +++ b/src/core/wee-secure-buffer.c @@ -0,0 +1,229 @@ +/* + * wee-secure-buffer.c - secured data buffer + * + * Copyright (C) 2013-2018 Sébastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "weechat.h" +#include "wee-config-file.h" +#include "wee-hashtable.h" +#include "wee-secure.h" +#include "wee-secure-buffer.h" +#include "wee-secure-config.h" +#include "wee-string.h" +#include "../gui/gui-buffer.h" +#include "../gui/gui-chat.h" +#include "../gui/gui-color.h" +#include "../gui/gui-window.h" +#include "../plugins/plugin.h" + +struct t_gui_buffer *secure_buffer = NULL; +int secure_buffer_display_values = 0; + + +/* + * Displays a secured data. + */ + +void +secure_buffer_display_data (void *data, + struct t_hashtable *hashtable, + const void *key, const void *value) +{ + int *line; + + /* make C compiler happy */ + (void) value; + + line = (int *)data; + + if (secure_buffer_display_values && (hashtable == secure_hashtable_data)) + { + gui_chat_printf_y (secure_buffer, (*line)++, + " %s%s = %s\"%s%s%s\"", + key, + GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), + GUI_COLOR(GUI_COLOR_CHAT), + GUI_COLOR(GUI_COLOR_CHAT_VALUE), + value, + GUI_COLOR(GUI_COLOR_CHAT)); + } + else + { + gui_chat_printf_y (secure_buffer, (*line)++, + " %s", key); + } +} + +/* + * Displays content of secured data buffer. + */ + +void +secure_buffer_display () +{ + int line, count, count_encrypted; + + if (!secure_buffer) + return; + + gui_buffer_clear (secure_buffer); + + /* set title buffer */ + gui_buffer_set_title (secure_buffer, + _("WeeChat secured data (sec.conf) | " + "Keys: [alt-v] Toggle values")); + + line = 0; + + gui_chat_printf_y (secure_buffer, line++, + "Hash algo: %s Cipher: %s Salt: %s", + secure_hash_algo_string[CONFIG_INTEGER(secure_config_crypt_hash_algo)], + secure_cipher_string[CONFIG_INTEGER(secure_config_crypt_cipher)], + (CONFIG_BOOLEAN(secure_config_crypt_salt)) ? _("on") : _("off")); + + /* display passphrase */ + line++; + gui_chat_printf_y (secure_buffer, line++, + (secure_passphrase) ? + _("Passphrase is set") : _("Passphrase is not set")); + + /* display secured data */ + count = secure_hashtable_data->items_count; + count_encrypted = secure_hashtable_data_encrypted->items_count; + if (count > 0) + { + line++; + gui_chat_printf_y (secure_buffer, line++, _("Secured data:")); + line++; + hashtable_map (secure_hashtable_data, + &secure_buffer_display_data, &line); + } + /* display secured data not decrypted */ + if (count_encrypted > 0) + { + line++; + gui_chat_printf_y (secure_buffer, line++, + _("Secured data STILL ENCRYPTED: (use /secure decrypt, " + "see /help secure)")); + line++; + hashtable_map (secure_hashtable_data_encrypted, + &secure_buffer_display_data, &line); + } + if ((count == 0) && (count_encrypted == 0)) + { + line++; + gui_chat_printf_y (secure_buffer, line++, _("No secured data set")); + } +} + +/* + * Input callback for secured data buffer. + */ + +int +secure_buffer_input_cb (const void *pointer, void *data, + struct t_gui_buffer *buffer, + const char *input_data) +{ + /* make C compiler happy */ + (void) pointer; + (void) data; + + if (string_strcasecmp (input_data, "q") == 0) + { + gui_buffer_close (buffer); + } + + return WEECHAT_RC_OK; +} + +/* + * Close callback for secured data buffer. + */ + +int +secure_buffer_close_cb (const void *pointer, void *data, + struct t_gui_buffer *buffer) +{ + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) buffer; + + secure_buffer = NULL; + + return WEECHAT_RC_OK; +} + +/* + * Assigns secured data buffer to pointer if it is not yet set. + */ + +void +secure_buffer_assign () +{ + if (!secure_buffer) + { + secure_buffer = gui_buffer_search_by_name (NULL, SECURE_BUFFER_NAME); + if (secure_buffer) + { + secure_buffer->input_callback = &secure_buffer_input_cb; + secure_buffer->close_callback = &secure_buffer_close_cb; + } + } +} + +/* + * Opens a buffer to display secured data. + */ + +void +secure_buffer_open () +{ + if (!secure_buffer) + { + secure_buffer = gui_buffer_new (NULL, SECURE_BUFFER_NAME, + &secure_buffer_input_cb, NULL, NULL, + &secure_buffer_close_cb, NULL, NULL); + if (secure_buffer) + { + if (!secure_buffer->short_name) + secure_buffer->short_name = strdup (SECURE_BUFFER_NAME); + gui_buffer_set (secure_buffer, "type", "free"); + gui_buffer_set (secure_buffer, "localvar_set_no_log", "1"); + gui_buffer_set (secure_buffer, "key_bind_meta-v", "/secure toggle_values"); + } + secure_buffer_display_values = 0; + } + + if (!secure_buffer) + return; + + gui_window_switch_to_buffer (gui_current_window, secure_buffer, 1); + + secure_buffer_display (); +} diff --git a/src/core/wee-secure-buffer.h b/src/core/wee-secure-buffer.h new file mode 100644 index 000000000..d086ec440 --- /dev/null +++ b/src/core/wee-secure-buffer.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013-2018 Sébastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef WEECHAT_SECURE_BUFFER_H +#define WEECHAT_SECURE_BUFFER_H + +#define SECURE_BUFFER_NAME "secured_data" + +extern struct t_gui_buffer *secure_buffer; +extern int secure_buffer_display_values; + +extern void secure_buffer_display (); +extern void secure_buffer_assign (); +extern void secure_buffer_open (); + +#endif /* WEECHAT_SECURE_BUFFER_H */ diff --git a/src/core/wee-secure-config.c b/src/core/wee-secure-config.c new file mode 100644 index 000000000..6d0d93fb8 --- /dev/null +++ b/src/core/wee-secure-config.c @@ -0,0 +1,628 @@ +/* + * wee-secure-config.c - secured data configuration options (file sec.conf) + * + * Copyright (C) 2013-2018 Sébastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "weechat.h" +#include "wee-config-file.h" +#include "wee-hashtable.h" +#include "wee-secure.h" +#include "wee-secure-config.h" +#include "wee-string.h" +#include "../gui/gui-chat.h" +#include "../gui/gui-main.h" +#include "../gui/gui-window.h" +#include "../plugins/plugin.h" + +struct t_config_file *secure_config_file = NULL; + +struct t_config_option *secure_config_crypt_cipher = NULL; +struct t_config_option *secure_config_crypt_hash_algo = NULL; +struct t_config_option *secure_config_crypt_passphrase_file = NULL; +struct t_config_option *secure_config_crypt_salt = NULL; + + +/* + * Gets passphrase from user and puts it in variable "secure_passphrase". + */ + +void +secure_config_get_passphrase_from_user (const char *error) +{ + const char *prompt[5]; + char passphrase[1024]; + + prompt[0] = _("Please enter your passphrase to decrypt the data secured " + "by WeeChat:"); + prompt[1] = _("(enter just one space to skip the passphrase, but this " + "will DISABLE all secured data!)"); + prompt[2] = _("(press ctrl-C to exit WeeChat now)"); + prompt[3] = error; + prompt[4] = NULL; + + while (1) + { + gui_main_get_password (prompt, passphrase, sizeof (passphrase)); + if (secure_passphrase) + { + free (secure_passphrase); + secure_passphrase = NULL; + } + if (passphrase[0]) + { + /* the special value " " (one space) disables passphrase */ + if (strcmp (passphrase, " ") == 0) + { + gui_chat_printf (NULL, + _("To recover your secured data, you can " + "use /secure decrypt (see /help secure)")); + } + else if (strcmp (passphrase, "\x03") == 0) + { + /* ctrl-C pressed, just exit now */ + exit (1); + } + else + secure_passphrase = strdup (passphrase); + return; + } + } +} + +/* + * Gets passphrase from a file. + * + * Returns passphrase read in file (only the first line with max length of + * 1024 chars), or NULL if error. + * + * Note: result must be freed after use. + */ + +char * +secure_config_get_passphrase_from_file (const char *filename) +{ + FILE *file; + char *passphrase, *filename2, buffer[1024+1], *pos; + size_t num_read; + + passphrase = NULL; + + filename2 = string_expand_home (filename); + if (!filename2) + return NULL; + + file = fopen (filename2, "r"); + if (file) + { + num_read = fread (buffer, 1, sizeof (buffer) - 1, file); + if (num_read > 0) + { + buffer[num_read] = '\0'; + pos = strchr (buffer, '\r'); + if (pos) + pos[0] = '\0'; + pos = strchr (buffer, '\n'); + if (pos) + pos[0] = '\0'; + if (buffer[0]) + passphrase = strdup (buffer); + } + fclose (file); + } + + free (filename2); + + return passphrase; +} + +/* + * Checks option "sec.crypt.passphrase_file". + */ + +int +secure_config_check_crypt_passphrase_file (const void *pointer, void *data, + struct t_config_option *option, + const char *value) +{ + char *passphrase; + + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) option; + + /* empty value is OK in option (no file used for passphrase) */ + if (!value || !value[0]) + return 1; + + passphrase = secure_config_get_passphrase_from_file (value); + if (passphrase) + free (passphrase); + else + { + gui_chat_printf (NULL, + _("%sWarning: unable to read passphrase from file " + "\"%s\""), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], + value); + } + + return 1; +} + +/* + * Reloads secured data configuration file. + * + * Returns: + * WEECHAT_CONFIG_READ_OK: OK + * WEECHAT_CONFIG_READ_MEMORY_ERROR: not enough memory + * WEECHAT_CONFIG_READ_FILE_NOT_FOUND: file not found + */ + +int +secure_config_reload_cb (const void *pointer, void *data, + struct t_config_file *config_file) +{ + /* make C compiler happy */ + (void) pointer; + (void) data; + + if (secure_hashtable_data_encrypted->items_count > 0) + { + gui_chat_printf (NULL, + _("%sError: not possible to reload file sec.conf " + "because there is still encrypted data (use /secure " + "decrypt, see /help secure)"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]); + return WEECHAT_CONFIG_READ_FILE_NOT_FOUND; + } + + secure_data_encrypted = 0; + + /* remove all secured data */ + hashtable_remove_all (secure_hashtable_data); + + return config_file_reload (config_file); +} + +/* + * Reads a data option in secured data configuration file. + */ + +int +secure_config_data_read_cb (const void *pointer, void *data, + struct t_config_file *config_file, + struct t_config_section *section, + const char *option_name, const char *value) +{ + char *buffer, *decrypted, str_error[1024]; + int length_buffer, length_decrypted, rc; + + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) config_file; + (void) section; + + if (!option_name || !value || !value[0]) + { + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + } + + /* special line indicating if a passphrase must be used to decrypt data */ + if (strcmp (option_name, SECURE_DATA_PASSPHRASE_FLAG) == 0) + { + secure_data_encrypted = config_file_string_to_boolean (value); + if (secure_data_encrypted && !secure_passphrase && !gui_init_ok) + { + /* if a passphrase file is set, use it */ + if (CONFIG_STRING(secure_config_crypt_passphrase_file)[0]) + secure_passphrase = secure_config_get_passphrase_from_file ( + CONFIG_STRING(secure_config_crypt_passphrase_file)); + + /* ask passphrase to the user (if no file, or file not found) */ + if (!secure_passphrase) + secure_config_get_passphrase_from_user (""); + } + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + } + + if (!secure_data_encrypted) + { + /* clear data: just store value in hashtable */ + hashtable_set (secure_hashtable_data, option_name, value); + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + } + + /* check that passphrase is set */ + if (!secure_passphrase) + { + gui_chat_printf (NULL, + _("%sPassphrase is not set, unable to decrypt data \"%s\""), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], + option_name); + hashtable_set (secure_hashtable_data_encrypted, option_name, value); + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + } + + /* decrypt data */ + buffer = malloc (strlen (value) + 1); + if (!buffer) + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + + length_buffer = string_decode_base16 (value, buffer); + while (1) + { + decrypted = NULL; + length_decrypted = 0; + rc = secure_decrypt_data ( + buffer, + length_buffer, + secure_hash_algo[CONFIG_INTEGER(secure_config_crypt_hash_algo)], + secure_cipher[CONFIG_INTEGER(secure_config_crypt_cipher)], + secure_passphrase, + &decrypted, + &length_decrypted); + if (rc == 0) + { + if (decrypted) + { + hashtable_set (secure_hashtable_data, option_name, + decrypted); + free (decrypted); + break; + } + } + else + { + if (decrypted) + free (decrypted); + if (gui_init_ok) + { + gui_chat_printf (NULL, + _("%sWrong passphrase, unable to decrypt data " + "\"%s\""), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], + option_name); + break; + } + snprintf (str_error, sizeof (str_error), + _("*** Wrong passphrase (decrypt error: %s) ***"), + secure_decrypt_error[(rc * -1) - 1]); + secure_config_get_passphrase_from_user (str_error); + if (!secure_passphrase) + { + gui_chat_printf (NULL, + _("%sPassphrase is not set, unable to decrypt " + "data \"%s\""), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], + option_name); + hashtable_set (secure_hashtable_data_encrypted, option_name, + value); + break; + } + } + } + free (buffer); + + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; +} + +/* + * Encrypts data and writes it in secured data configuration file. + */ + +void +secure_config_data_write_map_cb (void *data, + struct t_hashtable *hashtable, + const void *key, const void *value) +{ + struct t_config_file *config_file; + char *buffer, *buffer_base16; + int length_buffer, rc; + + /* make C compiler happy */ + (void) hashtable; + + config_file = (struct t_config_file *)data; + + buffer = NULL; + length_buffer = 0; + + if (secure_passphrase) + { + /* encrypt password using passphrase */ + rc = secure_encrypt_data ( + value, strlen (value) + 1, + secure_hash_algo[CONFIG_INTEGER(secure_config_crypt_hash_algo)], + secure_cipher[CONFIG_INTEGER(secure_config_crypt_cipher)], + secure_passphrase, + &buffer, + &length_buffer); + if (rc == 0) + { + if (buffer) + { + buffer_base16 = malloc ((length_buffer * 2) + 1); + if (buffer_base16) + { + string_encode_base16 (buffer, length_buffer, buffer_base16); + config_file_write_line (config_file, key, + "\"%s\"", buffer_base16); + free (buffer_base16); + } + free (buffer); + } + } + else + { + gui_chat_printf (NULL, + _("%sError encrypting data \"%s\" (%d)"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], + key, rc); + } + } + else + { + /* store password as plain text */ + config_file_write_line (config_file, key, "\"%s\"", value); + } +} + +/* + * Writes already encrypted data in secured data configuration file. + */ + +void +secure_config_data_write_map_encrypted_cb (void *data, + struct t_hashtable *hashtable, + const void *key, const void *value) +{ + struct t_config_file *config_file; + + /* make C compiler happy */ + (void) hashtable; + + config_file = (struct t_config_file *)data; + + /* store data as-is (it is already encrypted) */ + config_file_write_line (config_file, key, "\"%s\"", value); +} + +/* + * Writes section "data" in secured data configuration file. + */ + +int +secure_config_data_write_cb (const void *pointer, void *data, + struct t_config_file *config_file, + const char *section_name) +{ + /* make C compiler happy */ + (void) pointer; + (void) data; + + /* write name of section */ + if (!config_file_write_line (config_file, section_name, NULL)) + return WEECHAT_CONFIG_WRITE_ERROR; + + if (secure_hashtable_data->items_count > 0) + { + /* + * write a special line indicating if a passphrase must be used to + * decrypt data (if not, then data is stored as plain text) + */ + if (!config_file_write_line (config_file, + SECURE_DATA_PASSPHRASE_FLAG, + (secure_passphrase) ? "on" : "off")) + { + return WEECHAT_CONFIG_WRITE_ERROR; + } + /* encrypt and write secured data */ + hashtable_map (secure_hashtable_data, + &secure_config_data_write_map_cb, config_file); + } + else if (secure_hashtable_data_encrypted->items_count > 0) + { + /* + * if there is encrypted data, that means passphrase was not set and + * we were unable to decrypt => just save the encrypted content + * as-is (so that content of sec.conf is not lost) + */ + if (!config_file_write_line (config_file, + SECURE_DATA_PASSPHRASE_FLAG, "on")) + { + return WEECHAT_CONFIG_WRITE_ERROR; + } + hashtable_map (secure_hashtable_data_encrypted, + &secure_config_data_write_map_encrypted_cb, config_file); + } + + return WEECHAT_CONFIG_WRITE_OK; +} + +/* + * Creates options in secured data configuration. + * + * Returns: + * 1: OK + * 0: error + */ + +int +secure_config_init_options () +{ + struct t_config_section *ptr_section; + + secure_config_file = config_file_new (NULL, SECURE_CONFIG_NAME, + &secure_config_reload_cb, NULL, NULL); + if (!secure_config_file) + return 0; + + /* crypt */ + ptr_section = config_file_new_section (secure_config_file, "crypt", + 0, 0, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL); + if (!ptr_section) + { + config_file_free (secure_config_file); + secure_config_file = NULL; + return 0; + } + + secure_config_crypt_cipher = config_file_new_option ( + secure_config_file, ptr_section, + "cipher", "integer", + N_("cipher used to crypt data (the number after algorithm is the size " + "of the key in bits)"), + "aes128|aes192|aes256", 0, 0, "aes256", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + secure_config_crypt_hash_algo = config_file_new_option ( + secure_config_file, ptr_section, + "hash_algo", "integer", + N_("hash algorithm used to check the decrypted data"), + "sha224|sha256|sha384|sha512", 0, 0, "sha256", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + secure_config_crypt_passphrase_file = config_file_new_option ( + secure_config_file, ptr_section, + "passphrase_file", "string", + N_("path to a file containing the passphrase to encrypt/decrypt secured " + "data; this option is used only when reading file sec.conf; only " + "first line of file is used; this file is used only if the " + "environment variable \"WEECHAT_PASSPHRASE\" is not set (the " + "environment variable has higher priority); security note: it is " + "recommended to keep this file readable only by you and store it " + "outside WeeChat home (for example in your home); example: " + "\"~/.weechat-passphrase\""), + NULL, 0, 0, "", NULL, 0, + &secure_config_check_crypt_passphrase_file, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL); + secure_config_crypt_salt = config_file_new_option ( + secure_config_file, ptr_section, + "salt", "boolean", + N_("use salt when generating key used in encryption (recommended for " + "maximum security); when enabled, the content of crypted data in " + "file sec.conf will be different on each write of the file; if you " + "put the file sec.conf in a version control system, then you " + "can turn off this option to have always same content in file"), + NULL, 0, 0, "on", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + + /* data */ + ptr_section = config_file_new_section ( + secure_config_file, "data", + 0, 0, + &secure_config_data_read_cb, NULL, NULL, + &secure_config_data_write_cb, NULL, NULL, + &secure_config_data_write_cb, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL); + if (!ptr_section) + { + config_file_free (secure_config_file); + secure_config_file = NULL; + return 0; + } + + return 1; +} + +/* + * Reads secured data configuration file. + * + * Returns: + * WEECHAT_CONFIG_READ_OK: OK + * WEECHAT_CONFIG_READ_MEMORY_ERROR: not enough memory + * WEECHAT_CONFIG_READ_FILE_NOT_FOUND: file not found + */ + +int +secure_config_read () +{ + int rc; + + secure_data_encrypted = 0; + + rc = config_file_read (secure_config_file); + + return rc; +} + +/* + * Writes secured data configuration file. + * + * Returns: + * WEECHAT_CONFIG_WRITE_OK: OK + * WEECHAT_CONFIG_WRITE_ERROR: error + * WEECHAT_CONFIG_WRITE_MEMORY_ERROR: not enough memory + */ + +int +secure_config_write () +{ + return config_file_write (secure_config_file); +} + +/* + * Initializes secured data configuration. + * + * Returns: + * 1: OK + * 0: error + */ + +int +secure_config_init () +{ + int rc; + + rc = secure_config_init_options (); + + if (!rc) + { + gui_chat_printf (NULL, + _("FATAL: error initializing configuration options")); + } + + return rc; +} + +/* + * Frees secured data file and variables. + */ + +void +secure_config_free () +{ + config_file_free (secure_config_file); + secure_config_file = NULL; +} diff --git a/src/core/wee-secure-config.h b/src/core/wee-secure-config.h new file mode 100644 index 000000000..b24350a4b --- /dev/null +++ b/src/core/wee-secure-config.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2013-2018 Sébastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef WEECHAT_SECURE_CONFIG_H +#define WEECHAT_SECURE_CONFIG_H + +#define SECURE_CONFIG_NAME "sec" + +extern struct t_config_file *secure_config_file; +extern struct t_config_section *secure_config_section_pwd; + +extern struct t_config_option *secure_config_crypt_cipher; +extern struct t_config_option *secure_config_crypt_hash_algo; +extern struct t_config_option *secure_config_crypt_passphrase_file; +extern struct t_config_option *secure_config_crypt_salt; + +extern int secure_config_read (); +extern int secure_config_write (); +extern int secure_config_init (); +extern void secure_config_free (); + +#endif /* WEECHAT_SECURE_CONFIG_H */ diff --git a/src/core/wee-secure.c b/src/core/wee-secure.c index b30f0dd66..c4382d3f9 100644 --- a/src/core/wee-secure.c +++ b/src/core/wee-secure.c @@ -1,5 +1,5 @@ /* - * wee-secure.c - secured data configuration options (file sec.conf) + * wee-secure.c - secured data * * Copyright (C) 2013-2018 Sébastien Helleu <flashcode@flashtux.org> * @@ -31,23 +31,10 @@ #include "wee-config-file.h" #include "wee-hashtable.h" #include "wee-secure.h" +#include "wee-secure-config.h" #include "wee-string.h" -#include "../gui/gui-buffer.h" -#include "../gui/gui-chat.h" -#include "../gui/gui-color.h" -#include "../gui/gui-main.h" -#include "../gui/gui-window.h" #include "../plugins/plugin.h" -#define SALT_SIZE 8 - -struct t_config_file *secure_config_file = NULL; - -struct t_config_option *secure_config_crypt_cipher = NULL; -struct t_config_option *secure_config_crypt_hash_algo = NULL; -struct t_config_option *secure_config_crypt_passphrase_file = NULL; -struct t_config_option *secure_config_crypt_salt = NULL; - /* the passphrase used to encrypt/decrypt data */ char *secure_passphrase = NULL; @@ -74,10 +61,6 @@ char *secure_decrypt_error[] = { "memory", "buffer", "key", "cipher", "setkey", /* used only when reading sec.conf: 1 if flag __passphrase__ is enabled */ int secure_data_encrypted = 0; -/* secured data buffer */ -struct t_gui_buffer *secure_buffer = NULL; -int secure_buffer_display_values = 0; - /* * Derives a key from salt + passphrase (using a hash). @@ -97,14 +80,14 @@ secure_derive_key (const char *salt, const char *passphrase, memset (key, 0, length_key); - length = SALT_SIZE + strlen (passphrase); + length = SECURE_SALT_SIZE + strlen (passphrase); buffer = malloc (length); if (!buffer) return 0; /* build a buffer with salt + passphrase */ - memcpy (buffer, salt, SALT_SIZE); - memcpy (buffer + SALT_SIZE, passphrase, strlen (passphrase)); + memcpy (buffer, salt, SECURE_SALT_SIZE); + memcpy (buffer + SECURE_SALT_SIZE, passphrase, strlen (passphrase)); /* compute hash of buffer */ if (gcry_md_open (&hd_md, GCRY_MD_SHA512, 0) != 0) @@ -175,7 +158,7 @@ secure_encrypt_data (const char *data, int length_data, int hd_md_opened, hd_cipher_opened; gcry_md_hd_t *hd_md; gcry_cipher_hd_t *hd_cipher; - char salt[SALT_SIZE]; + char salt[SECURE_SALT_SIZE]; unsigned char *ptr_hash, *key, *hash_and_data; rc = -1; @@ -203,14 +186,15 @@ secure_encrypt_data (const char *data, int length_data, if (!key) goto encend; if (CONFIG_BOOLEAN(secure_config_crypt_salt)) - gcry_randomize (salt, SALT_SIZE, GCRY_STRONG_RANDOM); + gcry_randomize (salt, SECURE_SALT_SIZE, GCRY_STRONG_RANDOM); else { length_salt = strlen (SECURE_SALT_DEFAULT); - if (length_salt < SALT_SIZE) - memset (salt, 0, SALT_SIZE); + if (length_salt < SECURE_SALT_SIZE) + memset (salt, 0, SECURE_SALT_SIZE); memcpy (salt, SECURE_SALT_DEFAULT, - (length_salt <= SALT_SIZE) ? length_salt : SALT_SIZE); + (length_salt <= SECURE_SALT_SIZE) ? + length_salt : SECURE_SALT_SIZE); } if (!secure_derive_key (salt, passphrase, key, length_key)) { @@ -262,12 +246,12 @@ secure_encrypt_data (const char *data, int length_data, } /* create buffer and copy salt + encrypted hash/data into this buffer*/ - *length_encrypted = SALT_SIZE + length_hash_data; + *length_encrypted = SECURE_SALT_SIZE + length_hash_data; *encrypted = malloc (*length_encrypted); if (!*encrypted) goto encend; - memcpy (*encrypted, salt, SALT_SIZE); - memcpy (*encrypted + SALT_SIZE, hash_and_data, length_hash_data); + memcpy (*encrypted, salt, SECURE_SALT_SIZE); + memcpy (*encrypted + SECURE_SALT_SIZE, hash_and_data, length_hash_data); rc = 0; @@ -336,7 +320,7 @@ secure_decrypt_data (const char *buffer, int length_buffer, /* check length of buffer */ length_hash = gcry_md_get_algo_dlen (hash_algo); - if (length_buffer <= SALT_SIZE + length_hash) + if (length_buffer <= SECURE_SALT_SIZE + length_hash) return -2; hd_md = NULL; @@ -368,7 +352,7 @@ secure_decrypt_data (const char *buffer, int length_buffer, } /* decrypt hash + data */ - decrypted_hash_data = malloc (length_buffer - SALT_SIZE); + decrypted_hash_data = malloc (length_buffer - SECURE_SALT_SIZE); if (!decrypted_hash_data) goto decend; if (gcry_cipher_open (hd_cipher, cipher, GCRY_CIPHER_MODE_CFB, 0) != 0) @@ -383,8 +367,10 @@ secure_decrypt_data (const char *buffer, int length_buffer, goto decend; } if (gcry_cipher_decrypt (*hd_cipher, - decrypted_hash_data, length_buffer - SALT_SIZE, - buffer + SALT_SIZE, length_buffer - SALT_SIZE) != 0) + decrypted_hash_data, + length_buffer - SECURE_SALT_SIZE, + buffer + SECURE_SALT_SIZE, + length_buffer - SECURE_SALT_SIZE) != 0) { rc = -6; goto decend; @@ -398,7 +384,7 @@ secure_decrypt_data (const char *buffer, int length_buffer, } hd_md_opened = 1; gcry_md_write (*hd_md, decrypted_hash_data + length_hash, - length_buffer - SALT_SIZE - length_hash); + length_buffer - SECURE_SALT_SIZE - length_hash); ptr_hash = gcry_md_read (*hd_md, hash_algo); if (!ptr_hash) { @@ -412,7 +398,7 @@ secure_decrypt_data (const char *buffer, int length_buffer, } /* return the decrypted data */ - *length_decrypted = length_buffer - SALT_SIZE - length_hash; + *length_decrypted = length_buffer - SECURE_SALT_SIZE - length_hash; *decrypted = malloc (*length_decrypted); if (!*decrypted) goto decend; @@ -480,13 +466,14 @@ secure_decrypt_data_not_decrypted (const char *passphrase) length_buffer = string_decode_base16 (value, buffer); decrypted = NULL; length_decrypted = 0; - rc = secure_decrypt_data (buffer, - length_buffer, - secure_hash_algo[CONFIG_INTEGER(secure_config_crypt_hash_algo)], - secure_cipher[CONFIG_INTEGER(secure_config_crypt_cipher)], - passphrase, - &decrypted, - &length_decrypted); + rc = secure_decrypt_data ( + buffer, + length_buffer, + secure_hash_algo[CONFIG_INTEGER(secure_config_crypt_hash_algo)], + secure_cipher[CONFIG_INTEGER(secure_config_crypt_cipher)], + passphrase, + &decrypted, + &length_decrypted); if ((rc == 0) && decrypted) { hashtable_set (secure_hashtable_data, keys[i], @@ -508,514 +495,7 @@ secure_decrypt_data_not_decrypted (const char *passphrase) } /* - * Gets passphrase from user and puts it in variable "secure_passphrase". - */ - -void -secure_get_passphrase_from_user (const char *error) -{ - const char *prompt[5]; - char passphrase[1024]; - - prompt[0] = _("Please enter your passphrase to decrypt the data secured " - "by WeeChat:"); - prompt[1] = _("(enter just one space to skip the passphrase, but this " - "will DISABLE all secured data!)"); - prompt[2] = _("(press ctrl-C to exit WeeChat now)"); - prompt[3] = error; - prompt[4] = NULL; - - while (1) - { - gui_main_get_password (prompt, passphrase, sizeof (passphrase)); - if (secure_passphrase) - { - free (secure_passphrase); - secure_passphrase = NULL; - } - if (passphrase[0]) - { - /* the special value " " (one space) disables passphrase */ - if (strcmp (passphrase, " ") == 0) - { - gui_chat_printf (NULL, - _("To recover your secured data, you can " - "use /secure decrypt (see /help secure)")); - } - else if (strcmp (passphrase, "\x03") == 0) - { - /* ctrl-C pressed, just exit now */ - exit (1); - } - else - secure_passphrase = strdup (passphrase); - return; - } - } -} - -/* - * Gets passphrase from a file. - * - * Returns passphrase read in file (only the first line with max length of - * 1024 chars), or NULL if error. - * - * Note: result must be freed after use. - */ - -char * -secure_get_passphrase_from_file (const char *filename) -{ - FILE *file; - char *passphrase, *filename2, buffer[1024+1], *pos; - size_t num_read; - - passphrase = NULL; - - filename2 = string_expand_home (filename); - if (!filename2) - return NULL; - - file = fopen (filename2, "r"); - if (file) - { - num_read = fread (buffer, 1, sizeof (buffer) - 1, file); - if (num_read > 0) - { - buffer[num_read] = '\0'; - pos = strchr (buffer, '\r'); - if (pos) - pos[0] = '\0'; - pos = strchr (buffer, '\n'); - if (pos) - pos[0] = '\0'; - if (buffer[0]) - passphrase = strdup (buffer); - } - fclose (file); - } - - free (filename2); - - return passphrase; -} - -/* - * Checks option "sec.crypt.passphrase_file". - */ - -int -secure_check_crypt_passphrase_file (const void *pointer, void *data, - struct t_config_option *option, - const char *value) -{ - char *passphrase; - - /* make C compiler happy */ - (void) pointer; - (void) data; - (void) option; - - /* empty value is OK in option (no file used for passphrase) */ - if (!value || !value[0]) - return 1; - - passphrase = secure_get_passphrase_from_file (value); - if (passphrase) - free (passphrase); - else - { - gui_chat_printf (NULL, - _("%sWarning: unable to read passphrase from file " - "\"%s\""), - gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], - value); - } - - return 1; -} - -/* - * Reloads secured data configuration file. - * - * Returns: - * WEECHAT_CONFIG_READ_OK: OK - * WEECHAT_CONFIG_READ_MEMORY_ERROR: not enough memory - * WEECHAT_CONFIG_READ_FILE_NOT_FOUND: file not found - */ - -int -secure_reload_cb (const void *pointer, void *data, - struct t_config_file *config_file) -{ - /* make C compiler happy */ - (void) pointer; - (void) data; - - if (secure_hashtable_data_encrypted->items_count > 0) - { - gui_chat_printf (NULL, - _("%sError: not possible to reload file sec.conf " - "because there is still encrypted data (use /secure " - "decrypt, see /help secure)"), - gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]); - return WEECHAT_CONFIG_READ_FILE_NOT_FOUND; - } - - secure_data_encrypted = 0; - - /* remove all secured data */ - hashtable_remove_all (secure_hashtable_data); - - return config_file_reload (config_file); -} - -/* - * Reads a data option in secured data configuration file. - */ - -int -secure_data_read_cb (const void *pointer, void *data, - struct t_config_file *config_file, - struct t_config_section *section, - const char *option_name, const char *value) -{ - char *buffer, *decrypted, str_error[1024]; - int length_buffer, length_decrypted, rc; - - /* make C compiler happy */ - (void) pointer; - (void) data; - (void) config_file; - (void) section; - - if (!option_name || !value || !value[0]) - { - return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; - } - - /* special line indicating if a passphrase must be used to decrypt data */ - if (strcmp (option_name, SECURE_DATA_PASSPHRASE_FLAG) == 0) - { - secure_data_encrypted = config_file_string_to_boolean (value); - if (secure_data_encrypted && !secure_passphrase && !gui_init_ok) - { - /* if a passphrase file is set, use it */ - if (CONFIG_STRING(secure_config_crypt_passphrase_file)[0]) - secure_passphrase = secure_get_passphrase_from_file (CONFIG_STRING(secure_config_crypt_passphrase_file)); - - /* ask passphrase to the user (if no file, or file not found) */ - if (!secure_passphrase) - secure_get_passphrase_from_user (""); - } - return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; - } - - if (!secure_data_encrypted) - { - /* clear data: just store value in hashtable */ - hashtable_set (secure_hashtable_data, option_name, value); - return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; - } - - /* check that passphrase is set */ - if (!secure_passphrase) - { - gui_chat_printf (NULL, - _("%sPassphrase is not set, unable to decrypt data \"%s\""), - gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], - option_name); - hashtable_set (secure_hashtable_data_encrypted, option_name, value); - return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; - } - - /* decrypt data */ - buffer = malloc (strlen (value) + 1); - if (!buffer) - return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; - - length_buffer = string_decode_base16 (value, buffer); - while (1) - { - decrypted = NULL; - length_decrypted = 0; - rc = secure_decrypt_data (buffer, - length_buffer, - secure_hash_algo[CONFIG_INTEGER(secure_config_crypt_hash_algo)], - secure_cipher[CONFIG_INTEGER(secure_config_crypt_cipher)], - secure_passphrase, - &decrypted, - &length_decrypted); - if (rc == 0) - { - if (decrypted) - { - hashtable_set (secure_hashtable_data, option_name, - decrypted); - free (decrypted); - break; - } - } - else - { - if (decrypted) - free (decrypted); - if (gui_init_ok) - { - gui_chat_printf (NULL, - _("%sWrong passphrase, unable to decrypt data " - "\"%s\""), - gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], - option_name); - break; - } - snprintf (str_error, sizeof (str_error), - _("*** Wrong passphrase (decrypt error: %s) ***"), - secure_decrypt_error[(rc * -1) - 1]); - secure_get_passphrase_from_user (str_error); - if (!secure_passphrase) - { - gui_chat_printf (NULL, - _("%sPassphrase is not set, unable to decrypt " - "data \"%s\""), - gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], - option_name); - hashtable_set (secure_hashtable_data_encrypted, option_name, - value); - break; - } - } - } - free (buffer); - - return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; -} - -/* - * Encrypts data and writes it in secured data configuration file. - */ - -void -secure_data_write_map_cb (void *data, - struct t_hashtable *hashtable, - const void *key, const void *value) -{ - struct t_config_file *config_file; - char *buffer, *buffer_base16; - int length_buffer, rc; - - /* make C compiler happy */ - (void) hashtable; - - config_file = (struct t_config_file *)data; - - buffer = NULL; - length_buffer = 0; - - if (secure_passphrase) - { - /* encrypt password using passphrase */ - rc = secure_encrypt_data (value, strlen (value) + 1, - secure_hash_algo[CONFIG_INTEGER(secure_config_crypt_hash_algo)], - secure_cipher[CONFIG_INTEGER(secure_config_crypt_cipher)], - secure_passphrase, - &buffer, - &length_buffer); - if (rc == 0) - { - if (buffer) - { - buffer_base16 = malloc ((length_buffer * 2) + 1); - if (buffer_base16) - { - string_encode_base16 (buffer, length_buffer, buffer_base16); - config_file_write_line (config_file, key, - "\"%s\"", buffer_base16); - free (buffer_base16); - } - free (buffer); - } - } - else - { - gui_chat_printf (NULL, - _("%sError encrypting data \"%s\" (%d)"), - gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], - key, rc); - } - } - else - { - /* store password as plain text */ - config_file_write_line (config_file, key, "\"%s\"", value); - } -} - -/* - * Writes already encrypted data in secured data configuration file. - */ - -void -secure_data_write_map_encrypted_cb (void *data, - struct t_hashtable *hashtable, - const void *key, const void *value) -{ - struct t_config_file *config_file; - - /* make C compiler happy */ - (void) hashtable; - - config_file = (struct t_config_file *)data; - - /* store data as-is (it is already encrypted) */ - config_file_write_line (config_file, key, "\"%s\"", value); -} - -/* - * Writes section "data" in secured data configuration file. - */ - -int -secure_data_write_cb (const void *pointer, void *data, - struct t_config_file *config_file, - const char *section_name) -{ - /* make C compiler happy */ - (void) pointer; - (void) data; - - /* write name of section */ - if (!config_file_write_line (config_file, section_name, NULL)) - return WEECHAT_CONFIG_WRITE_ERROR; - - if (secure_hashtable_data->items_count > 0) - { - /* - * write a special line indicating if a passphrase must be used to - * decrypt data (if not, then data is stored as plain text) - */ - if (!config_file_write_line (config_file, - SECURE_DATA_PASSPHRASE_FLAG, - (secure_passphrase) ? "on" : "off")) - { - return WEECHAT_CONFIG_WRITE_ERROR; - } - /* encrypt and write secured data */ - hashtable_map (secure_hashtable_data, - &secure_data_write_map_cb, config_file); - } - else if (secure_hashtable_data_encrypted->items_count > 0) - { - /* - * if there is encrypted data, that means passphrase was not set and - * we were unable to decrypt => just save the encrypted content - * as-is (so that content of sec.conf is not lost) - */ - if (!config_file_write_line (config_file, - SECURE_DATA_PASSPHRASE_FLAG, "on")) - { - return WEECHAT_CONFIG_WRITE_ERROR; - } - hashtable_map (secure_hashtable_data_encrypted, - &secure_data_write_map_encrypted_cb, config_file); - } - - return WEECHAT_CONFIG_WRITE_OK; -} - -/* - * Creates options in secured data configuration. - * - * Returns: - * 1: OK - * 0: error - */ - -int -secure_init_options () -{ - struct t_config_section *ptr_section; - - secure_config_file = config_file_new (NULL, SECURE_CONFIG_NAME, - &secure_reload_cb, NULL, NULL); - if (!secure_config_file) - return 0; - - /* crypt */ - ptr_section = config_file_new_section (secure_config_file, "crypt", - 0, 0, - NULL, NULL, NULL, - NULL, NULL, NULL, - NULL, NULL, NULL, - NULL, NULL, NULL, - NULL, NULL, NULL); - if (!ptr_section) - { - config_file_free (secure_config_file); - secure_config_file = NULL; - return 0; - } - - secure_config_crypt_cipher = config_file_new_option ( - secure_config_file, ptr_section, - "cipher", "integer", - N_("cipher used to crypt data (the number after algorithm is the size " - "of the key in bits)"), - "aes128|aes192|aes256", 0, 0, "aes256", NULL, 0, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - secure_config_crypt_hash_algo = config_file_new_option ( - secure_config_file, ptr_section, - "hash_algo", "integer", - N_("hash algorithm used to check the decrypted data"), - "sha224|sha256|sha384|sha512", 0, 0, "sha256", NULL, 0, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - secure_config_crypt_passphrase_file = config_file_new_option ( - secure_config_file, ptr_section, - "passphrase_file", "string", - N_("path to a file containing the passphrase to encrypt/decrypt secured " - "data; this option is used only when reading file sec.conf; only " - "first line of file is used; this file is used only if the " - "environment variable \"WEECHAT_PASSPHRASE\" is not set (the " - "environment variable has higher priority); security note: it is " - "recommended to keep this file readable only by you and store it " - "outside WeeChat home (for example in your home); example: " - "\"~/.weechat-passphrase\""), - NULL, 0, 0, "", NULL, 0, - &secure_check_crypt_passphrase_file, NULL, NULL, - NULL, NULL, NULL, - NULL, NULL, NULL); - secure_config_crypt_salt = config_file_new_option ( - secure_config_file, ptr_section, - "salt", "boolean", - N_("use salt when generating key used in encryption (recommended for " - "maximum security); when enabled, the content of crypted data in " - "file sec.conf will be different on each write of the file; if you " - "put the file sec.conf in a version control system, then you " - "can turn off this option to have always same content in file"), - NULL, 0, 0, "on", NULL, 0, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - - /* data */ - ptr_section = config_file_new_section ( - secure_config_file, "data", - 0, 0, - &secure_data_read_cb, NULL, NULL, - &secure_data_write_cb, NULL, NULL, - &secure_data_write_cb, NULL, NULL, - NULL, NULL, NULL, - NULL, NULL, NULL); - if (!ptr_section) - { - config_file_free (secure_config_file); - secure_config_file = NULL; - return 0; - } - - return 1; -} - -/* - * Initializes secured data configuration. + * Initializes secured data. * * Returns: * 1: OK @@ -1025,7 +505,6 @@ secure_init_options () int secure_init () { - int rc; char *ptr_phrase; /* try to read passphrase (if not set) from env var "WEECHAT_PASSPHRASE" */ @@ -1057,256 +536,7 @@ secure_init () return 0; } - rc = secure_init_options (); - - if (!rc) - { - gui_chat_printf (NULL, - _("FATAL: error initializing configuration options")); - } - - return rc; -} - -/* - * Reads secured data configuration file. - * - * Returns: - * WEECHAT_CONFIG_READ_OK: OK - * WEECHAT_CONFIG_READ_MEMORY_ERROR: not enough memory - * WEECHAT_CONFIG_READ_FILE_NOT_FOUND: file not found - */ - -int -secure_read () -{ - int rc; - - secure_data_encrypted = 0; - - rc = config_file_read (secure_config_file); - - return rc; -} - -/* - * Writes secured data configuration file. - * - * Returns: - * WEECHAT_CONFIG_WRITE_OK: OK - * WEECHAT_CONFIG_WRITE_ERROR: error - * WEECHAT_CONFIG_WRITE_MEMORY_ERROR: not enough memory - */ - -int -secure_write () -{ - return config_file_write (secure_config_file); -} - -/* - * Frees secured data file and variables. - */ - -void -secure_free () -{ - config_file_free (secure_config_file); - - if (secure_hashtable_data) - { - hashtable_free (secure_hashtable_data); - secure_hashtable_data = NULL; - } - if (secure_hashtable_data_encrypted) - { - hashtable_free (secure_hashtable_data_encrypted); - secure_hashtable_data_encrypted = NULL; - } -} - -/* - * Displays a secured data. - */ - -void -secure_buffer_display_data (void *data, - struct t_hashtable *hashtable, - const void *key, const void *value) -{ - int *line; - - /* make C compiler happy */ - (void) value; - - line = (int *)data; - - if (secure_buffer_display_values && (hashtable == secure_hashtable_data)) - { - gui_chat_printf_y (secure_buffer, (*line)++, - " %s%s = %s\"%s%s%s\"", - key, - GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), - GUI_COLOR(GUI_COLOR_CHAT), - GUI_COLOR(GUI_COLOR_CHAT_VALUE), - value, - GUI_COLOR(GUI_COLOR_CHAT)); - } - else - { - gui_chat_printf_y (secure_buffer, (*line)++, - " %s", key); - } -} - -/* - * Displays content of secured data buffer. - */ - -void -secure_buffer_display () -{ - int line, count, count_encrypted; - - if (!secure_buffer) - return; - - gui_buffer_clear (secure_buffer); - - /* set title buffer */ - gui_buffer_set_title (secure_buffer, - _("WeeChat secured data (sec.conf) | " - "Keys: [alt-v] Toggle values")); - - line = 0; - - gui_chat_printf_y (secure_buffer, line++, - "Hash algo: %s Cipher: %s Salt: %s", - secure_hash_algo_string[CONFIG_INTEGER(secure_config_crypt_hash_algo)], - secure_cipher_string[CONFIG_INTEGER(secure_config_crypt_cipher)], - (CONFIG_BOOLEAN(secure_config_crypt_salt)) ? _("on") : _("off")); - - /* display passphrase */ - line++; - gui_chat_printf_y (secure_buffer, line++, - (secure_passphrase) ? - _("Passphrase is set") : _("Passphrase is not set")); - - /* display secured data */ - count = secure_hashtable_data->items_count; - count_encrypted = secure_hashtable_data_encrypted->items_count; - if (count > 0) - { - line++; - gui_chat_printf_y (secure_buffer, line++, _("Secured data:")); - line++; - hashtable_map (secure_hashtable_data, - &secure_buffer_display_data, &line); - } - /* display secured data not decrypted */ - if (count_encrypted > 0) - { - line++; - gui_chat_printf_y (secure_buffer, line++, - _("Secured data STILL ENCRYPTED: (use /secure decrypt, " - "see /help secure)")); - line++; - hashtable_map (secure_hashtable_data_encrypted, - &secure_buffer_display_data, &line); - } - if ((count == 0) && (count_encrypted == 0)) - { - line++; - gui_chat_printf_y (secure_buffer, line++, _("No secured data set")); - } -} - -/* - * Input callback for secured data buffer. - */ - -int -secure_buffer_input_cb (const void *pointer, void *data, - struct t_gui_buffer *buffer, - const char *input_data) -{ - /* make C compiler happy */ - (void) pointer; - (void) data; - - if (string_strcasecmp (input_data, "q") == 0) - { - gui_buffer_close (buffer); - } - - return WEECHAT_RC_OK; -} - -/* - * Close callback for secured data buffer. - */ - -int -secure_buffer_close_cb (const void *pointer, void *data, - struct t_gui_buffer *buffer) -{ - /* make C compiler happy */ - (void) pointer; - (void) data; - (void) buffer; - - secure_buffer = NULL; - - return WEECHAT_RC_OK; -} - -/* - * Assigns secured data buffer to pointer if it is not yet set. - */ - -void -secure_buffer_assign () -{ - if (!secure_buffer) - { - secure_buffer = gui_buffer_search_by_name (NULL, SECURE_BUFFER_NAME); - if (secure_buffer) - { - secure_buffer->input_callback = &secure_buffer_input_cb; - secure_buffer->close_callback = &secure_buffer_close_cb; - } - } -} - -/* - * Opens a buffer to display secured data. - */ - -void -secure_buffer_open () -{ - if (!secure_buffer) - { - secure_buffer = gui_buffer_new (NULL, SECURE_BUFFER_NAME, - &secure_buffer_input_cb, NULL, NULL, - &secure_buffer_close_cb, NULL, NULL); - if (secure_buffer) - { - if (!secure_buffer->short_name) - secure_buffer->short_name = strdup (SECURE_BUFFER_NAME); - gui_buffer_set (secure_buffer, "type", "free"); - gui_buffer_set (secure_buffer, "localvar_set_no_log", "1"); - gui_buffer_set (secure_buffer, "key_bind_meta-v", "/secure toggle_values"); - } - secure_buffer_display_values = 0; - } - - if (!secure_buffer) - return; - - gui_window_switch_to_buffer (gui_current_window, secure_buffer, 1); - - secure_buffer_display (); + return 1; } /* diff --git a/src/core/wee-secure.h b/src/core/wee-secure.h index 9c01eb068..4a2e9dc9d 100644 --- a/src/core/wee-secure.h +++ b/src/core/wee-secure.h @@ -20,13 +20,10 @@ #ifndef WEECHAT_SECURE_H #define WEECHAT_SECURE_H -#define SECURE_CONFIG_NAME "sec" - #define SECURE_ENV_PASSPHRASE "WEECHAT_PASSPHRASE" #define SECURE_SALT_DEFAULT "WeeChat!" #define SECURE_DATA_PASSPHRASE_FLAG "__passphrase__" - -#define SECURE_BUFFER_NAME "secured_data" +#define SECURE_SALT_SIZE 8 enum t_secure_config_hash_algo { @@ -43,29 +40,26 @@ enum t_secure_config_cipher SECURE_CONFIG_CIPHER_AES256, }; -extern struct t_config_file *secure_config_file; -extern struct t_config_section *secure_config_section_pwd; - -extern struct t_config_option *secure_config_crypt_cipher; -extern struct t_config_option *secure_config_crypt_hash_algo; -extern struct t_config_option *secure_config_crypt_passphrase_file; -extern struct t_config_option *secure_config_crypt_salt; - extern char *secure_passphrase; extern struct t_hashtable *secure_hashtable_data; extern struct t_hashtable *secure_hashtable_data_encrypted; +extern char *secure_hash_algo_string[]; +extern int secure_hash_algo[]; +extern char *secure_cipher_string[]; +extern int secure_cipher[]; +extern int secure_data_encrypted; +extern char *secure_decrypt_error[]; -extern struct t_gui_buffer *secure_buffer; -extern int secure_buffer_display_values; - +extern int secure_encrypt_data (const char *data, int length_data, + int hash_algo, int cipher, + const char *passphrase, char **encrypted, + int *length_encrypted); +extern int secure_decrypt_data (const char *buffer, int length_buffer, + int hash_algo, int cipher, + const char *passphrase, char **decrypted, + int *length_decrypted); extern int secure_decrypt_data_not_decrypted (const char *passphrase); extern int secure_init (); -extern int secure_read (); -extern int secure_write (); -extern void secure_free (); -extern void secure_buffer_display (); -extern void secure_buffer_assign (); -extern void secure_buffer_open (); extern void secure_end (); #endif /* WEECHAT_SECURE_H */ diff --git a/src/core/wee-upgrade.c b/src/core/wee-upgrade.c index 30f131646..a78ba2873 100644 --- a/src/core/wee-upgrade.c +++ b/src/core/wee-upgrade.c @@ -32,7 +32,7 @@ #include "wee-upgrade.h" #include "wee-hook.h" #include "wee-infolist.h" -#include "wee-secure.h" +#include "wee-secure-buffer.h" #include "wee-string.h" #include "wee-util.h" #include "../gui/gui-buffer.h" diff --git a/src/core/weechat.c b/src/core/weechat.c index 35a08d98b..dee813023 100644 --- a/src/core/weechat.c +++ b/src/core/weechat.c @@ -65,6 +65,7 @@ #include "wee-network.h" #include "wee-proxy.h" #include "wee-secure.h" +#include "wee-secure-config.h" #include "wee-string.h" #include "wee-upgrade.h" #include "wee-utf8.h" @@ -702,7 +703,9 @@ weechat_init (int argc, char *argv[], void (*gui_init_cb)()) completion_init (); /* add core completion hooks */ gui_key_init (); /* init keys */ network_init_gcrypt (); /* init gcrypt */ - if (!secure_init ()) /* init secured data options (sec.*)*/ + if (!secure_init ()) /* init secured data */ + weechat_shutdown (EXIT_FAILURE, 0); + if (!secure_config_init ()) /* init secured data options (sec.*)*/ weechat_shutdown (EXIT_FAILURE, 0); if (!config_weechat_init ()) /* init WeeChat options (weechat.*) */ weechat_shutdown (EXIT_FAILURE, 0); @@ -710,7 +713,7 @@ weechat_init (int argc, char *argv[], void (*gui_init_cb)()) weechat_create_home_dir (); /* create WeeChat home directory */ log_init (); /* init log file */ plugin_api_init (); /* create some hooks (info,hdata,..)*/ - secure_read (); /* read secured data options */ + secure_config_read (); /* read secured data options */ config_weechat_read (); /* read WeeChat options */ network_init_gnutls (); /* init GnuTLS */ @@ -747,14 +750,14 @@ weechat_end (void (*gui_end_cb)(int clean_exit)) plugin_end (); /* end plugin interface(s) */ if (CONFIG_BOOLEAN(config_look_save_config_on_exit)) (void) config_weechat_write (); /* save WeeChat config file */ - (void) secure_write (); /* save secured data */ + (void) secure_config_write (); /* save secured data */ if (gui_end_cb) (*gui_end_cb) (1); /* shut down WeeChat GUI */ proxy_free_all (); /* free all proxies */ config_weechat_free (); /* free WeeChat options */ - secure_free (); /* free secured data options */ + secure_config_free (); /* free secured data options */ config_file_free_all (); /* free all configuration files */ gui_key_end (); /* remove all keys */ unhook_all (); /* remove all hooks */ diff --git a/src/gui/gui-buffer.c b/src/gui/gui-buffer.c index 19bfc03bd..f0749d995 100644 --- a/src/gui/gui-buffer.c +++ b/src/gui/gui-buffer.c @@ -42,7 +42,7 @@ #include "../core/wee-infolist.h" #include "../core/wee-list.h" #include "../core/wee-log.h" -#include "../core/wee-secure.h" +#include "../core/wee-secure-buffer.h" #include "../core/wee-string.h" #include "../core/wee-utf8.h" #include "../plugins/plugin.h" |