diff --git a/tokens/Makemodule.am b/tokens/Makemodule.am index 983a6db6..20989ecf 100644 --- a/tokens/Makemodule.am +++ b/tokens/Makemodule.am @@ -6,11 +6,13 @@ TOKENS_LDFLAGS = $(AM_LDFLAGS) -no-undefined \ if SSHPLUGIN_TOKEN libcryptsetup_token_ssh_la_LDFLAGS = $(TOKENS_LDFLAGS) -libcryptsetup_token_ssh_la_SOURCES = tokens/ssh/libcryptsetup-token-ssh.c +libcryptsetup_token_ssh_la_SOURCES = tokens/ssh/libcryptsetup-token-ssh.c \ + tokens/ssh/ssh-utils.c \ + tokens/ssh/ssh-utils.h libcryptsetup_token_ssh_la_LIBADD = -lssh libcryptsetup.la @JSON_C_LIBS@ lib_LTLIBRARIES += libcryptsetup-token-ssh.la -cryptsetup_ssh_SOURCES = tokens/ssh/cryptsetup-ssh.c +cryptsetup_ssh_SOURCES = tokens/ssh/cryptsetup-ssh.c tokens/ssh/ssh-utils.h cryptsetup_ssh_LDADD = libcryptsetup.la @JSON_C_LIBS@ sbin_PROGRAMS += cryptsetup-ssh diff --git a/tokens/ssh/cryptsetup-ssh.c b/tokens/ssh/cryptsetup-ssh.c index a782e46b..d860e23e 100644 --- a/tokens/ssh/cryptsetup-ssh.c +++ b/tokens/ssh/cryptsetup-ssh.c @@ -33,8 +33,6 @@ #define TOKEN_NAME "ssh" -#define PASSWORD_LENGTH 8192 - #define l_err(cd, x...) crypt_logf(cd, CRYPT_LOG_ERROR, x) #define l_dbg(cd, x...) crypt_logf(cd, CRYPT_LOG_DEBUG, x) diff --git a/tokens/ssh/libcryptsetup-token-ssh.c b/tokens/ssh/libcryptsetup-token-ssh.c index 0ee73543..6b55dc1e 100644 --- a/tokens/ssh/libcryptsetup-token-ssh.c +++ b/tokens/ssh/libcryptsetup-token-ssh.c @@ -29,13 +29,9 @@ #include #include #include -#include #include -#include -#include #include "libcryptsetup.h" - -#define PASSWORD_LENGTH 8192 +#include "ssh-utils.h" #define TOKEN_NAME "ssh" #define TOKEN_VERSION_MAJOR "1" @@ -78,148 +74,6 @@ static json_object *get_token_jobj(struct crypt_device *cd, int token) return json_tokener_parse(json_slot); } -static int sshplugin_download_password(struct crypt_device *cd, ssh_session ssh, - const char *path, char **password, size_t *password_len) -{ - char *pass = NULL; - size_t pass_len; - int r; - sftp_attributes sftp_attr = NULL; - sftp_session sftp = NULL; - sftp_file file = NULL; - - sftp = sftp_new(ssh); - if (!sftp) { - crypt_log(cd, CRYPT_LOG_ERROR, "Cannot create sftp session: "); - r = SSH_FX_FAILURE; - goto out; - } - - r = sftp_init(sftp); - if (r != SSH_OK) { - crypt_log(cd, CRYPT_LOG_ERROR, "Cannot init sftp session: "); - goto out; - } - - file = sftp_open(sftp, path, O_RDONLY, 0); - if (!file) { - crypt_log(cd, CRYPT_LOG_ERROR, "Cannot create sftp session: "); - r = SSH_FX_FAILURE; - goto out; - } - - sftp_attr = sftp_fstat(file); - if (!sftp_attr) { - crypt_log(cd, CRYPT_LOG_ERROR, "Cannot stat sftp file: "); - r = SSH_FX_FAILURE; - goto out; - } - - pass_len = sftp_attr->size > PASSWORD_LENGTH ? PASSWORD_LENGTH : sftp_attr->size; - pass = malloc(pass_len); - if (!pass) { - crypt_log(cd, CRYPT_LOG_ERROR, "Not enough memory.\n"); - r = SSH_FX_FAILURE; - goto out; - } - - r = sftp_read(file, pass, pass_len); - if (r < 0 || (size_t)r != pass_len) { - crypt_log(cd, CRYPT_LOG_ERROR, "Cannot read remote key: "); - r = SSH_FX_FAILURE; - goto out; - } - - *password = pass; - *password_len = pass_len; - - r = SSH_OK; -out: - if (r != SSH_OK) { - crypt_log(cd, CRYPT_LOG_ERROR, ssh_get_error(ssh)); - crypt_log(cd, CRYPT_LOG_ERROR, "\n"); - free(pass); - } - - if (sftp_attr) - sftp_attributes_free(sftp_attr); - - if (file) - sftp_close(file); - if (sftp) - sftp_free(sftp); - return r == SSH_OK ? 0 : -EINVAL; -} - -static ssh_session sshplugin_session_init(struct crypt_device *cd, - const char *host, const char *user) -{ - int r, port = 22; - ssh_session ssh = ssh_new(); - if (!ssh) - return NULL; - - ssh_options_set(ssh, SSH_OPTIONS_HOST, host); - ssh_options_set(ssh, SSH_OPTIONS_USER, user); - ssh_options_set(ssh, SSH_OPTIONS_PORT, &port); - - crypt_log(cd, CRYPT_LOG_NORMAL, "SSH token initiating ssh session.\n"); - - r = ssh_connect(ssh); - if (r != SSH_OK) { - crypt_log(cd, CRYPT_LOG_ERROR, "Connection failed: "); - goto out; - } - - r = ssh_session_is_known_server(ssh); - if (r != SSH_SERVER_KNOWN_OK) { - crypt_log(cd, CRYPT_LOG_ERROR, "Server not known: "); - r = SSH_AUTH_ERROR; - goto out; - } - - r = SSH_OK; - - /* initialise list of authentication methods. yes, according to official libssh docs... */ - ssh_userauth_none(ssh, NULL); -out: - if (r != SSH_OK) { - crypt_log(cd, CRYPT_LOG_ERROR, ssh_get_error(ssh)); - crypt_log(cd, CRYPT_LOG_ERROR, "\n"); - ssh_disconnect(ssh); - ssh_free(ssh); - ssh = NULL; - } - - return ssh; -} - -static int sshplugin_public_key_auth(struct crypt_device *cd, ssh_session ssh, const ssh_key pkey) -{ - int r; - - crypt_log(cd, CRYPT_LOG_DEBUG, "Trying public key authentication method.\n"); - - if (!(ssh_userauth_list(ssh, NULL) & SSH_AUTH_METHOD_PUBLICKEY)) { - crypt_log(cd, CRYPT_LOG_ERROR, "Public key auth method not allowed on host.\n"); - return SSH_AUTH_ERROR; - } - - r = ssh_userauth_try_publickey(ssh, NULL, pkey); - if (r == SSH_AUTH_SUCCESS) { - crypt_log(cd, CRYPT_LOG_DEBUG, "Public key method accepted.\n"); - r = ssh_userauth_publickey(ssh, NULL, pkey); - } - - if (r != SSH_AUTH_SUCCESS) { - crypt_log(cd, CRYPT_LOG_ERROR, "Public key authentication error: "); - crypt_log(cd, CRYPT_LOG_ERROR, ssh_get_error(ssh)); - crypt_log(cd, CRYPT_LOG_ERROR, "\n"); - } - - return r; -} - int cryptsetup_token_open_pin(struct crypt_device *cd, int token, const char *pin, size_t pin_size __attribute__((unused)), char **password, size_t *password_len, void *usrptr __attribute__((unused))) diff --git a/tokens/ssh/ssh-utils.c b/tokens/ssh/ssh-utils.c new file mode 100644 index 00000000..ba4824b7 --- /dev/null +++ b/tokens/ssh/ssh-utils.c @@ -0,0 +1,171 @@ +/* + * ssh plugin utilities + * + * Copyright (C) 2016-2021 Milan Broz + * Copyright (C) 2020-2021 Vojtech Trefny + * + * This program 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 2 + * of the License, or (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define KEYFILE_LENGTH_MAX 8192 + +int sshplugin_download_password(struct crypt_device *cd, ssh_session ssh, + const char *path, char **password, size_t *password_len) +{ + char *pass = NULL; + size_t pass_len; + int r; + sftp_attributes sftp_attr = NULL; + sftp_session sftp = NULL; + sftp_file file = NULL; + + sftp = sftp_new(ssh); + if (!sftp) { + crypt_log(cd, CRYPT_LOG_ERROR, "Cannot create sftp session: "); + r = SSH_FX_FAILURE; + goto out; + } + + r = sftp_init(sftp); + if (r != SSH_OK) { + crypt_log(cd, CRYPT_LOG_ERROR, "Cannot init sftp session: "); + goto out; + } + + file = sftp_open(sftp, path, O_RDONLY, 0); + if (!file) { + crypt_log(cd, CRYPT_LOG_ERROR, "Cannot create sftp session: "); + r = SSH_FX_FAILURE; + goto out; + } + + sftp_attr = sftp_fstat(file); + if (!sftp_attr) { + crypt_log(cd, CRYPT_LOG_ERROR, "Cannot stat sftp file: "); + r = SSH_FX_FAILURE; + goto out; + } + + pass_len = sftp_attr->size > KEYFILE_LENGTH_MAX ? KEYFILE_LENGTH_MAX : sftp_attr->size; + pass = malloc(pass_len); + if (!pass) { + crypt_log(cd, CRYPT_LOG_ERROR, "Not enough memory.\n"); + r = SSH_FX_FAILURE; + goto out; + } + + r = sftp_read(file, pass, pass_len); + if (r < 0 || (size_t)r != pass_len) { + crypt_log(cd, CRYPT_LOG_ERROR, "Cannot read remote key: "); + r = SSH_FX_FAILURE; + goto out; + } + + *password = pass; + *password_len = pass_len; + + r = SSH_OK; +out: + if (r != SSH_OK) { + crypt_log(cd, CRYPT_LOG_ERROR, ssh_get_error(ssh)); + crypt_log(cd, CRYPT_LOG_ERROR, "\n"); + free(pass); + } + + if (sftp_attr) + sftp_attributes_free(sftp_attr); + + if (file) + sftp_close(file); + if (sftp) + sftp_free(sftp); + return r == SSH_OK ? 0 : -EINVAL; +} + +ssh_session sshplugin_session_init(struct crypt_device *cd, const char *host, const char *user) +{ + int r, port = 22; + ssh_session ssh = ssh_new(); + if (!ssh) + return NULL; + + ssh_options_set(ssh, SSH_OPTIONS_HOST, host); + ssh_options_set(ssh, SSH_OPTIONS_USER, user); + ssh_options_set(ssh, SSH_OPTIONS_PORT, &port); + + crypt_log(cd, CRYPT_LOG_NORMAL, "SSH token initiating ssh session.\n"); + + r = ssh_connect(ssh); + if (r != SSH_OK) { + crypt_log(cd, CRYPT_LOG_ERROR, "Connection failed: "); + goto out; + } + + r = ssh_session_is_known_server(ssh); + if (r != SSH_SERVER_KNOWN_OK) { + crypt_log(cd, CRYPT_LOG_ERROR, "Server not known: "); + r = SSH_AUTH_ERROR; + goto out; + } + + r = SSH_OK; + + /* initialise list of authentication methods. yes, according to official libssh docs... */ + ssh_userauth_none(ssh, NULL); +out: + if (r != SSH_OK) { + crypt_log(cd, CRYPT_LOG_ERROR, ssh_get_error(ssh)); + crypt_log(cd, CRYPT_LOG_ERROR, "\n"); + ssh_disconnect(ssh); + ssh_free(ssh); + ssh = NULL; + } + + return ssh; +} + +int sshplugin_public_key_auth(struct crypt_device *cd, ssh_session ssh, const ssh_key pkey) +{ + int r; + + crypt_log(cd, CRYPT_LOG_DEBUG, "Trying public key authentication method.\n"); + + if (!(ssh_userauth_list(ssh, NULL) & SSH_AUTH_METHOD_PUBLICKEY)) { + crypt_log(cd, CRYPT_LOG_ERROR, "Public key auth method not allowed on host.\n"); + return SSH_AUTH_ERROR; + } + + r = ssh_userauth_try_publickey(ssh, NULL, pkey); + if (r == SSH_AUTH_SUCCESS) { + crypt_log(cd, CRYPT_LOG_DEBUG, "Public key method accepted.\n"); + r = ssh_userauth_publickey(ssh, NULL, pkey); + } + + if (r != SSH_AUTH_SUCCESS) { + crypt_log(cd, CRYPT_LOG_ERROR, "Public key authentication error: "); + crypt_log(cd, CRYPT_LOG_ERROR, ssh_get_error(ssh)); + crypt_log(cd, CRYPT_LOG_ERROR, "\n"); + } + + return r; +} diff --git a/tokens/ssh/ssh-utils.h b/tokens/ssh/ssh-utils.h new file mode 100644 index 00000000..0759e3d3 --- /dev/null +++ b/tokens/ssh/ssh-utils.h @@ -0,0 +1,29 @@ +/* + * ssh plugin utilities + * + * Copyright (C) 2016-2021 Milan Broz + * Copyright (C) 2020-2021 Vojtech Trefny + * + * This program 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 2 + * of the License, or (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +int sshplugin_download_password(struct crypt_device *cd, ssh_session ssh, + const char *path, char **password, size_t *password_len); +ssh_session sshplugin_session_init(struct crypt_device *cd, const char *host, const char *user); +int sshplugin_public_key_auth(struct crypt_device *cd, ssh_session ssh, const ssh_key pkey);