diff options
Diffstat (limited to 'tokens/ssh/ssh-utils.c')
-rw-r--r-- | tokens/ssh/ssh-utils.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/tokens/ssh/ssh-utils.c b/tokens/ssh/ssh-utils.c new file mode 100644 index 0000000..564d858 --- /dev/null +++ b/tokens/ssh/ssh-utils.c @@ -0,0 +1,177 @@ +/* + * ssh plugin utilities + * + * Copyright (C) 2016-2023 Milan Broz + * Copyright (C) 2020-2023 Vojtech Trefny + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This file 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <libssh/libssh.h> +#include <libssh/sftp.h> +#include <fcntl.h> +#include <libcryptsetup.h> +#include "ssh-utils.h" +#include "../lib/nls.h" + +#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 open 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; + } + +#if HAVE_DECL_SSH_SESSION_IS_KNOWN_SERVER + r = ssh_session_is_known_server(ssh); +#else + r = ssh_is_server_known(ssh); +#endif + 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; +} |