GUACAMOLE-527: Add host key and type settings.

This commit is contained in:
Nick Couchman 2018-04-05 07:36:37 -04:00 committed by Nick Couchman
parent 171bae1f5c
commit 0d82cd1e6c
4 changed files with 89 additions and 31 deletions

View File

@ -98,7 +98,8 @@ void guac_common_ssh_uninit();
* if the connection or authentication were not successful. * if the connection or authentication were not successful.
*/ */
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
const char* hostname, const char* port, guac_common_ssh_user* user, int keepalive); const char* hostname, const char* port, guac_common_ssh_user* user, int keepalive,
const char* host_key_type, const char* host_key);
/** /**
* Disconnects and destroys the given SSH session, freeing all associated * Disconnects and destroys the given SSH session, freeing all associated

View File

@ -415,7 +415,8 @@ static int guac_common_ssh_authenticate(guac_common_ssh_session* common_session)
} }
guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client, guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
const char* hostname, const char* port, guac_common_ssh_user* user, int keepalive) { const char* hostname, const char* port, guac_common_ssh_user* user, int keepalive,
const char* host_key_type, const char* host_key) {
int retval; int retval;
@ -511,44 +512,68 @@ guac_common_ssh_session* guac_common_ssh_create_session(guac_client* client,
} }
/* Check known_hosts */ /* Check known_hosts */
size_t len; /* Get known hosts file from user running guacd */
int type;
struct passwd *pw = getpwuid(getuid()); struct passwd *pw = getpwuid(getuid());
char *homedir = pw->pw_dir; char *homedir = pw->pw_dir;
char *known_hosts = strcat(homedir, "/.ssh/known_hosts"); char *known_hosts = strcat(homedir, "/.ssh/known_hosts");
LIBSSH2_KNOWNHOSTS *ssh_known_hosts = libssh2_knownhost_init(session); LIBSSH2_KNOWNHOSTS *ssh_known_hosts = libssh2_knownhost_init(session);
libssh2_knownhost_readfile(ssh_known_hosts, known_hosts, LIBSSH2_KNOWNHOST_FILE_OPENSSH); libssh2_knownhost_readfile(ssh_known_hosts, known_hosts, LIBSSH2_KNOWNHOST_FILE_OPENSSH);
const char *fingerprint = libssh2_session_hostkey(session, &len, &type);
if (fingerprint) { /* Add host key provided from settings */
struct libssh2_knownhost *host; if (strcmp(host_key, "") > 0) {
int check = libssh2_knownhost_checkp(ssh_known_hosts, hostname, atoi(port),
fingerprint, len,
LIBSSH2_KNOWNHOST_TYPE_PLAIN|
LIBSSH2_KNOWNHOST_KEYENC_RAW,
&host);
switch (check) { int kh_key_type = 0;
case LIBSSH2_KNOWNHOST_CHECK_MATCH: if (strcmp(host_key_type, "ssh-rsa") == 0)
guac_client_log(client, GUAC_LOG_DEBUG, kh_key_type = LIBSSH2_KNOWNHOST_KEY_SSHRSA;
"Host key match found."); else if(strcmp(host_key_type, "ssh-dss") == 0)
break; kh_key_type = LIBSSH2_KNOWNHOST_KEY_SSHDSS;
case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND: else if(strcmp(host_key_type, "rsa1") == 0)
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, kh_key_type = LIBSSH2_KNOWNHOST_KEY_RSA1;
"Host key not found in known hosts file."); else
break; guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
case LIBSSH2_KNOWNHOST_CHECK_MISMATCH: "Invalid SSH host key type %s", host_key_type);
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Host key does not match host entry.");
break;
case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
default:
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Host could not be checked against known hosts.");
}
if (libssh2_knownhost_addc(ssh_known_hosts, hostname, NULL, host_key, strlen(host_key),
NULL, 0, LIBSSH2_KNOWNHOST_TYPE_PLAIN|LIBSSH2_KNOWNHOST_KEYENC_BASE64|
kh_key_type, NULL))
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Failed to add host key to known hosts store for %s", hostname);
}
/* Get fingerprint of host we're connecting to */
size_t fp_len;
int fp_type;
const char *fingerprint = libssh2_session_hostkey(session, &fp_len, &fp_type);
if (!fingerprint || strcmp(fingerprint, "") == 0) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Could not retrieve fingerprint of SSH server %s", hostname);
}
struct libssh2_knownhost *host;
int kh_check = libssh2_knownhost_checkp(ssh_known_hosts, hostname, atoi(port),
fingerprint, fp_len,
LIBSSH2_KNOWNHOST_TYPE_PLAIN|
LIBSSH2_KNOWNHOST_KEYENC_RAW,
&host);
switch (kh_check) {
case LIBSSH2_KNOWNHOST_CHECK_MATCH:
guac_client_log(client, GUAC_LOG_DEBUG,
"Host key match found.");
break;
case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Host key not found in known hosts file.");
break;
case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Host key does not match host entry.");
break;
case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
default:
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Host could not be checked against known hosts.");
} }
/* Perform handshake */ /* Perform handshake */

View File

@ -31,6 +31,8 @@
/* Client plugin arguments */ /* Client plugin arguments */
const char* GUAC_SSH_CLIENT_ARGS[] = { const char* GUAC_SSH_CLIENT_ARGS[] = {
"hostname", "hostname",
"host_key_type",
"host_key",
"port", "port",
"username", "username",
"password", "password",
@ -68,6 +70,16 @@ enum SSH_ARGS_IDX {
*/ */
IDX_HOSTNAME, IDX_HOSTNAME,
/**
* The type of public SSH host key provided. Optional.
*/
IDX_HOST_KEY_TYPE,
/**
* The Base64-encoded public SSH host key. Optional.
*/
IDX_HOST_KEY,
/** /**
* The port to connect to. Optional. * The port to connect to. Optional.
*/ */
@ -247,6 +259,14 @@ guac_ssh_settings* guac_ssh_parse_args(guac_user* user,
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv, guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
IDX_HOSTNAME, ""); IDX_HOSTNAME, "");
settings->host_key_type =
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
IDX_HOST_KEY_TYPE, "ssh-rsa");
settings->host_key =
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
IDX_HOST_KEY, NULL);
settings->username = settings->username =
guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv, guac_user_parse_args_string(user, GUAC_SSH_CLIENT_ARGS, argv,
IDX_USERNAME, NULL); IDX_USERNAME, NULL);
@ -384,6 +404,8 @@ void guac_ssh_settings_free(guac_ssh_settings* settings) {
/* Free network connection information */ /* Free network connection information */
free(settings->hostname); free(settings->hostname);
free(settings->host_key_type);
free(settings->host_key);
free(settings->port); free(settings->port);
/* Free credentials */ /* Free credentials */

View File

@ -70,6 +70,16 @@ typedef struct guac_ssh_settings {
*/ */
char* hostname; char* hostname;
/**
* The type of public SSH host key.
*/
char* host_key_type;
/**
* The public SSH host key.
*/
char* host_key;
/** /**
* The port of the SSH server to connect to. * The port of the SSH server to connect to.
*/ */