1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* ssh plugin utilities
*
* Copyright (C) 2016-2024 Milan Broz
* Copyright (C) 2020-2024 Vojtech Trefny
*/
#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;
}
|