mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-03-24 20:40:09 +09:00
Compare commits
10 Commits
1b3c061aae
...
76b14eaed7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76b14eaed7 | ||
|
|
8e8f091aba | ||
|
|
d75a54e206 | ||
|
|
efb7a7c4e0 | ||
|
|
7342e73d10 | ||
|
|
832f92e35f | ||
|
|
ea3464532e | ||
|
|
7e235f8748 | ||
|
|
052c8217b7 | ||
|
|
26b9ba5f8c |
@@ -171,21 +171,15 @@ The following RFC documents described SSH-2 protocol as an Internet standard.
|
||||
The Secure Shell (SSH) Session Channel Break Extension
|
||||
- <a href="https://tools.ietf.org/html/rfc4344" target="_blank">RFC 4344</a>,
|
||||
The Secure Shell (SSH) Transport Layer Encryption Modes
|
||||
- <a href="https://tools.ietf.org/html/rfc4345" target="_blank">RFC 4345</a>,
|
||||
Improved Arcfour Modes for the Secure Shell (SSH) Transport Layer Protocol
|
||||
|
||||
It was later modified and expanded by the following RFCs.
|
||||
|
||||
- <a href="https://tools.ietf.org/html/rfc4419" target="_blank">RFC 4419</a>,
|
||||
Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer
|
||||
Protocol
|
||||
- <a href="https://tools.ietf.org/html/rfc4432" target="_blank">RFC 4432</a>,
|
||||
RSA Key Exchange for the Secure Shell (SSH) Transport Layer Protocol
|
||||
(not implemented in libssh)
|
||||
- <a href="https://tools.ietf.org/html/rfc4462" target="_blank">RFC 4462</a>,
|
||||
Generic Security Service Application Program Interface (GSS-API)
|
||||
Authentication and Key Exchange for the Secure Shell (SSH) Protocol
|
||||
(only the authentication implemented in libssh)
|
||||
- <a href="https://tools.ietf.org/html/rfc4716" target="_blank">RFC 4716</a>,
|
||||
The Secure Shell (SSH) Public Key File Format
|
||||
(not implemented in libssh)
|
||||
@@ -204,7 +198,6 @@ It was later modified and expanded by the following RFCs.
|
||||
(not implemented in libssh)
|
||||
- <a href="https://tools.ietf.org/html/rfc8160" target="_blank">RFC 8160</a>,
|
||||
IUTF8 Terminal Mode in Secure Shell (SSH)
|
||||
(not handled in libssh)
|
||||
- <a href="https://tools.ietf.org/html/rfc8270" target="_blank">RFC 8270</a>,
|
||||
Increase the Secure Shell Minimum Recommended Diffie-Hellman Modulus Size to 2048 Bits
|
||||
- <a href="https://tools.ietf.org/html/rfc8308" target="_blank">RFC 8308</a>,
|
||||
@@ -223,6 +216,14 @@ There are also drafts that are being currently developed and followed.
|
||||
|
||||
- <a href="https://tools.ietf.org/html/draft-miller-ssh-agent-03" target="_blank">draft-miller-ssh-agent-08</a>
|
||||
SSH Agent Protocol
|
||||
- <a href="https://tools.ietf.org/html/draft-ietf-sshm-mlkem-hybrid-kex-09" target="_blank">draft-ietf-sshm-mlkem-hybrid-kex-09</a>
|
||||
PQ/T Hybrid Key Exchange with ML-KEM in SSH
|
||||
- <a href="https://tools.ietf.org/html/draft-ietf-sshm-ntruprime-ssh-06" target="_blank">draft-ietf-sshm-ntruprime-ssh-06</a>
|
||||
Secure Shell (SSH) Key Exchange Method Using Hybrid Streamlined NTRU Prime sntrup761 and X25519 with SHA-512: sntrup761x25519-sha512
|
||||
- <a href="https://tools.ietf.org/html/draft-ietf-sshm-chacha20-poly1305-02" target="_blank">draft-ietf-sshm-chacha20-poly1305-02</a>
|
||||
Secure Shell (SSH) authenticated encryption cipher: chacha20-poly1305
|
||||
- <a href="https://tools.ietf.org/html/draft-ietf-sshm-strict-kex-01" target="_blank">draft-ietf-sshm-strict-kex-01</a>
|
||||
SSH Strict KEX extension
|
||||
|
||||
Interesting cryptography documents:
|
||||
|
||||
@@ -247,8 +248,6 @@ them like the statvfs calls in SFTP or the ssh-agent.
|
||||
OpenSSH's deviations and extensions</a>
|
||||
- <a href="https://api.libssh.org/rfc/PROTOCOL.certkeys" target="_blank">
|
||||
OpenSSH's pubkey certificate authentication</a>
|
||||
- <a href="https://api.libssh.org/rfc/PROTOCOL.chacha20poly1305" target="_blank">
|
||||
chacha20-poly1305@openssh.com authenticated encryption mode</a>
|
||||
- <a href="https://api.libssh.org/rfc/PROTOCOL.key" target="_blank">
|
||||
OpenSSH private key format (openssh-key-v1)</a>
|
||||
|
||||
|
||||
@@ -1396,6 +1396,11 @@ int ssh_userauth_publickey_auto(ssh_session session,
|
||||
if (session == NULL) {
|
||||
return SSH_AUTH_ERROR;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_INFO,
|
||||
"Starting authentication as a user %s",
|
||||
username ? username : session->opts.username);
|
||||
|
||||
if (! (session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH)) {
|
||||
session->auth.supported_methods &= ~SSH_AUTH_METHOD_PUBLICKEY;
|
||||
return SSH_AUTH_DENIED;
|
||||
|
||||
@@ -542,16 +542,8 @@ static int ssh_connector_channel_data_cb(ssh_session session,
|
||||
window_len = MIN(window, len);
|
||||
|
||||
/* Route the data to the right exception channel */
|
||||
if (is_stderr && (connector->out_flags & SSH_CONNECTOR_STDERR)) {
|
||||
w = ssh_channel_write_stderr(connector->out_channel,
|
||||
data,
|
||||
window_len);
|
||||
} else if (!is_stderr &&
|
||||
(connector->out_flags & SSH_CONNECTOR_STDOUT)) {
|
||||
w = ssh_channel_write(connector->out_channel,
|
||||
data,
|
||||
window_len);
|
||||
} else if (connector->out_flags & SSH_CONNECTOR_STDOUT) {
|
||||
if (connector->out_flags & SSH_CONNECTOR_STDOUT &&
|
||||
!(is_stderr && (connector->out_flags & SSH_CONNECTOR_STDERR))) {
|
||||
w = ssh_channel_write(connector->out_channel,
|
||||
data,
|
||||
window_len);
|
||||
|
||||
12
src/misc.c
12
src/misc.c
@@ -814,7 +814,17 @@ static struct ssh_iterator *ssh_iterator_new(const void *data)
|
||||
return iterator;
|
||||
}
|
||||
|
||||
int ssh_list_append(struct ssh_list *list,const void *data)
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief Appends an element to the end of the list.
|
||||
*
|
||||
* @param[in] list The list to append the element
|
||||
* @param[in] data The element to append
|
||||
*
|
||||
* @return `SSH_OK` on success, `SSH_ERROR` on error
|
||||
*/
|
||||
int ssh_list_append(struct ssh_list *list, const void *data)
|
||||
{
|
||||
struct ssh_iterator *iterator = NULL;
|
||||
|
||||
|
||||
@@ -549,17 +549,14 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp,
|
||||
if (rc != SSH_OK){
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"Flags: %.8" PRIx32 "\n", attr->flags);
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Flags: %.8" PRIx32, attr->flags);
|
||||
|
||||
if (attr->flags & SSH_FILEXFER_ATTR_SIZE) {
|
||||
rc = ssh_buffer_unpack(buf, "q", &attr->size);
|
||||
if(rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"Size: %" PRIu64 "\n",
|
||||
(uint64_t) attr->size);
|
||||
SSH_LOG(SSH_LOG_DEBUG, "Size: %" PRIu64, (uint64_t)attr->size);
|
||||
}
|
||||
|
||||
if (attr->flags & SSH_FILEXFER_ATTR_UIDGID) {
|
||||
|
||||
218
src/socket.c
218
src/socket.c
@@ -97,6 +97,10 @@ struct ssh_socket_struct {
|
||||
struct jump_thread_data_struct {
|
||||
ssh_session session;
|
||||
socket_t fd;
|
||||
char *next_hostname;
|
||||
uint16_t next_port;
|
||||
struct ssh_jump_info_struct *next_jump;
|
||||
struct ssh_jump_callbacks_struct *next_cb;
|
||||
};
|
||||
|
||||
int proxy_disconnect = 0;
|
||||
@@ -1249,6 +1253,22 @@ verify_knownhost(ssh_session session)
|
||||
return SSH_OK;
|
||||
}
|
||||
|
||||
static void free_jump_thread_data(struct jump_thread_data_struct *data)
|
||||
{
|
||||
if (data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ssh_free(data->session);
|
||||
SAFE_FREE(data->next_hostname);
|
||||
if (data->next_jump != NULL) {
|
||||
SAFE_FREE(data->next_jump->hostname);
|
||||
SAFE_FREE(data->next_jump->username);
|
||||
}
|
||||
SAFE_FREE(data->next_jump);
|
||||
SAFE_FREE(data);
|
||||
}
|
||||
|
||||
static void *
|
||||
jump_thread_func(void *arg)
|
||||
{
|
||||
@@ -1260,72 +1280,30 @@ jump_thread_func(void *arg)
|
||||
int rc;
|
||||
ssh_event event = NULL;
|
||||
ssh_connector connector_in = NULL, connector_out = NULL;
|
||||
ssh_session session = NULL;
|
||||
int next_port;
|
||||
uint16_t next_port;
|
||||
char *next_hostname = NULL;
|
||||
|
||||
jump_thread_data = (struct jump_thread_data_struct *)arg;
|
||||
session = jump_thread_data->session;
|
||||
jump_session = jump_thread_data->session;
|
||||
|
||||
next_port = session->opts.port;
|
||||
next_hostname = strdup(session->opts.host);
|
||||
/* First thing we need to do is to set the right level as its kept in
|
||||
* thread local variable, therefore reset to 0 after spawning new thread.
|
||||
*/
|
||||
ssh_set_log_level(jump_session->common.log_verbosity);
|
||||
|
||||
jump_session = ssh_new();
|
||||
if (jump_session == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
cb = jump_thread_data->next_cb;
|
||||
jis = jump_thread_data->next_jump;
|
||||
|
||||
jump_session->proxy_root = false;
|
||||
/* Reset the global variable if it was previously 1 */
|
||||
if (session->proxy_root) {
|
||||
proxy_disconnect = 0;
|
||||
}
|
||||
|
||||
for (jis = ssh_list_pop_head(struct ssh_jump_info_struct *,
|
||||
session->opts.proxy_jumps);
|
||||
jis != NULL;
|
||||
jis = ssh_list_pop_head(struct ssh_jump_info_struct *,
|
||||
session->opts.proxy_jumps)) {
|
||||
rc = ssh_list_append(jump_session->opts.proxy_jumps, jis);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
for (jis =
|
||||
ssh_list_pop_head(struct ssh_jump_info_struct *,
|
||||
session->opts.proxy_jumps_user_cb);
|
||||
jis != NULL;
|
||||
jis = ssh_list_pop_head(struct ssh_jump_info_struct *,
|
||||
session->opts.proxy_jumps_user_cb)) {
|
||||
rc = ssh_list_append(jump_session->opts.proxy_jumps_user_cb, jis);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_oom(session);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
ssh_options_set(jump_session,
|
||||
SSH_OPTIONS_LOG_VERBOSITY,
|
||||
&session->common.log_verbosity);
|
||||
|
||||
/* Pop the information about the current jump */
|
||||
jis = ssh_list_pop_head(struct ssh_jump_info_struct *,
|
||||
jump_session->opts.proxy_jumps);
|
||||
if (jis == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Inconsistent list of proxy jumps received");
|
||||
goto exit;
|
||||
}
|
||||
/* This is the calling thread target where we will eventually initialize
|
||||
* forwarding */
|
||||
next_port = jump_thread_data->next_port;
|
||||
next_hostname = jump_thread_data->next_hostname;
|
||||
|
||||
ssh_options_set(jump_session, SSH_OPTIONS_HOST, jis->hostname);
|
||||
ssh_options_set(jump_session, SSH_OPTIONS_USER, jis->username);
|
||||
ssh_options_set(jump_session, SSH_OPTIONS_PORT, &jis->port);
|
||||
|
||||
/* Pop the callbacks for the current jump */
|
||||
cb = ssh_list_pop_head(struct ssh_jump_callbacks_struct *,
|
||||
jump_session->opts.proxy_jumps_user_cb);
|
||||
|
||||
if (cb != NULL) {
|
||||
if (cb != NULL && cb->before_connection != NULL) {
|
||||
rc = cb->before_connection(jump_session, cb->userdata);
|
||||
if (rc != SSH_OK) {
|
||||
SSH_LOG(SSH_LOG_WARN, "%s", ssh_get_error(jump_session));
|
||||
@@ -1333,6 +1311,13 @@ jump_thread_func(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET,
|
||||
"Proxy connecting to host %s port %d user %s, callbacks=%p",
|
||||
jis->hostname,
|
||||
jis->port,
|
||||
jis->username,
|
||||
(void *)cb);
|
||||
|
||||
/* If there are more jumps then this will make a new thread and call the
|
||||
* current function again, until there are no jumps. When there are no jumps
|
||||
* it connects normally. */
|
||||
@@ -1423,36 +1408,42 @@ exit:
|
||||
ssh_event_remove_connector(event, connector_out);
|
||||
ssh_connector_free(connector_out);
|
||||
}
|
||||
SAFE_FREE(next_hostname);
|
||||
if (jis != NULL) {
|
||||
SAFE_FREE(jis->hostname);
|
||||
SAFE_FREE(jis->username);
|
||||
}
|
||||
SAFE_FREE(jis);
|
||||
|
||||
ssh_disconnect(jump_session);
|
||||
ssh_event_free(event);
|
||||
ssh_free(jump_session);
|
||||
|
||||
shutdown(jump_thread_data->fd, SHUT_RDWR);
|
||||
close(jump_thread_data->fd);
|
||||
SAFE_FREE(jump_thread_data);
|
||||
|
||||
free_jump_thread_data(jump_thread_data);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
int
|
||||
ssh_socket_connect_proxyjump(ssh_socket s)
|
||||
{
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
ssh_poll_handle h = NULL;
|
||||
int rc;
|
||||
pthread_t jump_thread;
|
||||
struct ssh_jump_info_struct *jis = NULL;
|
||||
struct ssh_jump_callbacks_struct *cb = NULL;
|
||||
struct jump_thread_data_struct *jump_thread_data = NULL;
|
||||
socket_t pair[2];
|
||||
ssh_session jump_session = NULL, session = NULL;
|
||||
struct ssh_list *empty_list = NULL;
|
||||
socket_t pair[2] = {SSH_INVALID_SOCKET, SSH_INVALID_SOCKET};
|
||||
|
||||
session = s->session;
|
||||
|
||||
SSH_LOG(SSH_LOG_INFO,
|
||||
"Connecting to host %s port %d user %s through ProxyJump",
|
||||
session->opts.host,
|
||||
session->opts.port,
|
||||
session->opts.username);
|
||||
|
||||
if (s->state != SSH_SOCKET_NONE) {
|
||||
ssh_set_error(
|
||||
s->session,
|
||||
session,
|
||||
SSH_FATAL,
|
||||
"ssh_socket_connect_proxyjump called on socket not unconnected");
|
||||
return SSH_ERROR;
|
||||
@@ -1460,50 +1451,100 @@ ssh_socket_connect_proxyjump(ssh_socket s)
|
||||
|
||||
jump_thread_data = calloc(1, sizeof(struct jump_thread_data_struct));
|
||||
if (jump_thread_data == NULL) {
|
||||
ssh_set_error_oom(s->session);
|
||||
ssh_set_error_oom(session);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = socketpair(PF_UNIX, SOCK_STREAM, 0, pair);
|
||||
if (rc == -1) {
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
|
||||
ssh_set_error(s->session,
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Creating socket pair failed: %s",
|
||||
ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
SAFE_FREE(jump_thread_data);
|
||||
return SSH_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
jump_thread_data->session = s->session;
|
||||
jump_session = ssh_new();
|
||||
if (jump_session == NULL) {
|
||||
ssh_set_error_oom(session);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
jump_session->proxy_root = false;
|
||||
/* Reset the global variable if it was previously 1 */
|
||||
if (session->proxy_root) {
|
||||
proxy_disconnect = 0;
|
||||
}
|
||||
|
||||
/* Pop first jump that will be used by the following thread */
|
||||
jis = ssh_list_pop_head(struct ssh_jump_info_struct *,
|
||||
session->opts.proxy_jumps);
|
||||
if (jis == NULL) {
|
||||
SSH_LOG(SSH_LOG_WARN, "Inconsistent list of proxy jumps received");
|
||||
ssh_free(jump_session);
|
||||
goto fail;
|
||||
}
|
||||
jump_thread_data->next_jump = jis;
|
||||
/* Move remaining to the jump session without reallocation.
|
||||
* The list in the new jump_session is just allocated so empty */
|
||||
empty_list = jump_session->opts.proxy_jumps;
|
||||
jump_session->opts.proxy_jumps = session->opts.proxy_jumps;
|
||||
session->opts.proxy_jumps = empty_list;
|
||||
|
||||
/* Pop the callbacks for the first jump */
|
||||
cb = ssh_list_pop_head(struct ssh_jump_callbacks_struct *,
|
||||
session->opts.proxy_jumps_user_cb);
|
||||
/* empty is ok */
|
||||
jump_thread_data->next_cb = cb;
|
||||
/* Move remaining to the jump session without reallocation.
|
||||
* The list in the new jump_session is just allocated so empty */
|
||||
empty_list = jump_session->opts.proxy_jumps_user_cb;
|
||||
jump_session->opts.proxy_jumps_user_cb = session->opts.proxy_jumps_user_cb;
|
||||
session->opts.proxy_jumps_user_cb = empty_list;
|
||||
|
||||
ssh_options_set(jump_session,
|
||||
SSH_OPTIONS_LOG_VERBOSITY,
|
||||
&session->common.log_verbosity);
|
||||
|
||||
jump_thread_data->next_port = session->opts.port;
|
||||
jump_thread_data->next_hostname = strdup(session->opts.host);
|
||||
|
||||
jump_thread_data->fd = pair[0];
|
||||
pair[0] = SSH_INVALID_SOCKET;
|
||||
jump_thread_data->session = jump_session;
|
||||
/* transferred to the jump_thread_data */
|
||||
jump_session = NULL;
|
||||
|
||||
SSH_LOG(SSH_LOG_INFO,
|
||||
"Starting proxy thread to host %s port %d user %s, callbacks=%p",
|
||||
jump_thread_data->next_jump->hostname,
|
||||
jump_thread_data->next_jump->port,
|
||||
jump_thread_data->next_jump->username,
|
||||
(void *)jump_thread_data->next_cb);
|
||||
|
||||
rc = pthread_create(&jump_thread, NULL, jump_thread_func, jump_thread_data);
|
||||
if (rc != 0) {
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
|
||||
ssh_set_error(s->session,
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Creating new thread failed: %s",
|
||||
ssh_strerror(rc, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
SAFE_FREE(jump_thread_data);
|
||||
return SSH_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
/* ownership passed to the thread */
|
||||
jump_thread_data = NULL;
|
||||
|
||||
rc = pthread_detach(jump_thread);
|
||||
if (rc != 0) {
|
||||
char err_msg[SSH_ERRNO_MSG_MAX] = {0};
|
||||
|
||||
ssh_set_error(s->session,
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Failed to detach thread: %s",
|
||||
ssh_strerror(rc, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
SAFE_FREE(jump_thread_data);
|
||||
return SSH_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
SSH_LOG(SSH_LOG_DEBUG,
|
||||
"ProxyJump connection pipe: [%d,%d]",
|
||||
"ProxyJump connection thread %lu started pipe: [%d,%d]",
|
||||
(unsigned long)jump_thread,
|
||||
pair[0],
|
||||
pair[1]);
|
||||
|
||||
@@ -1511,6 +1552,7 @@ ssh_socket_connect_proxyjump(ssh_socket s)
|
||||
if (rc != SSH_OK) {
|
||||
return rc;
|
||||
}
|
||||
pair[1] = SSH_INVALID_SOCKET;
|
||||
|
||||
s->fd_is_socket = 1;
|
||||
h = ssh_socket_get_poll_handle(s);
|
||||
@@ -1525,6 +1567,16 @@ ssh_socket_connect_proxyjump(ssh_socket s)
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
|
||||
fail:
|
||||
if (pair[0] != SSH_INVALID_SOCKET) {
|
||||
close(pair[0]);
|
||||
}
|
||||
if (pair[1] != SSH_INVALID_SOCKET) {
|
||||
close(pair[1]);
|
||||
}
|
||||
free_jump_thread_data(jump_thread_data);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
#endif /* HAVE_PTHREAD */
|
||||
|
||||
@@ -394,6 +394,7 @@ if (CLIENT_TESTING OR SERVER_TESTING)
|
||||
# Allow to auth with bob's public keys on alice and doe account
|
||||
configure_file(keys/id_rsa.pub ${CMAKE_CURRENT_BINARY_DIR}/home/alice/.ssh/authorized_keys @ONLY)
|
||||
configure_file(keys/id_rsa.pub ${CMAKE_CURRENT_BINARY_DIR}/home/doe/.ssh/authorized_keys @ONLY)
|
||||
configure_file(keys/id_ecdsa.pub ${CMAKE_CURRENT_BINARY_DIR}/home/frank/.ssh/authorized_keys @ONLY)
|
||||
|
||||
# append ECDSA public key
|
||||
file(READ keys/id_ecdsa.pub CONTENTS)
|
||||
|
||||
@@ -121,6 +121,50 @@ static int authenticate(ssh_session jump_session, void *user)
|
||||
return ssh_userauth_publickey_auto(jump_session, NULL, NULL);
|
||||
}
|
||||
|
||||
static int authenticate_doe(ssh_session jump_session, void *user)
|
||||
{
|
||||
ssh_key pkey = NULL;
|
||||
char bob_ssh_key[1024];
|
||||
struct passwd *pwd = NULL;
|
||||
int rc;
|
||||
|
||||
(void)user;
|
||||
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
|
||||
snprintf(bob_ssh_key, sizeof(bob_ssh_key), "%s/.ssh/id_rsa", pwd->pw_dir);
|
||||
|
||||
rc = ssh_pki_import_privkey_file(bob_ssh_key, NULL, NULL, NULL, &pkey);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
rc = ssh_userauth_publickey(jump_session, NULL, pkey);
|
||||
ssh_key_free(pkey);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int authenticate_frank(ssh_session jump_session, void *user)
|
||||
{
|
||||
ssh_key pkey = NULL;
|
||||
char bob_ssh_key[1024];
|
||||
struct passwd *pwd = NULL;
|
||||
int rc;
|
||||
|
||||
(void)user;
|
||||
|
||||
pwd = getpwnam("bob");
|
||||
assert_non_null(pwd);
|
||||
|
||||
snprintf(bob_ssh_key, sizeof(bob_ssh_key), "%s/.ssh/id_ecdsa", pwd->pw_dir);
|
||||
|
||||
rc = ssh_pki_import_privkey_file(bob_ssh_key, NULL, NULL, NULL, &pkey);
|
||||
assert_int_equal(rc, SSH_OK);
|
||||
|
||||
rc = ssh_userauth_publickey(jump_session, NULL, pkey);
|
||||
ssh_key_free(pkey);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void torture_proxyjump_multiple_jump(void **state)
|
||||
{
|
||||
struct torture_state *s = *state;
|
||||
@@ -129,11 +173,10 @@ static void torture_proxyjump_multiple_jump(void **state)
|
||||
const char *address = torture_server_address(AF_INET);
|
||||
int rc;
|
||||
socket_t fd;
|
||||
|
||||
struct ssh_jump_callbacks_struct c = {
|
||||
.before_connection = before_connection,
|
||||
.verify_knownhost = verify_knownhost,
|
||||
.authenticate = authenticate
|
||||
.authenticate = authenticate,
|
||||
};
|
||||
|
||||
rc = snprintf(proxyjump_buf,
|
||||
@@ -177,14 +220,14 @@ static void torture_proxyjump_multiple_sshd_jump(void **state)
|
||||
struct ssh_jump_callbacks_struct c = {
|
||||
.before_connection = before_connection,
|
||||
.verify_knownhost = verify_knownhost,
|
||||
.authenticate = authenticate,
|
||||
.authenticate = authenticate_doe,
|
||||
};
|
||||
|
||||
torture_setup_sshd_servers(state, false);
|
||||
|
||||
rc = snprintf(proxyjump_buf,
|
||||
sizeof(proxyjump_buf),
|
||||
"alice@%s:22,alice@%s:22",
|
||||
"doe@%s:22,doe@%s:22",
|
||||
address,
|
||||
address1);
|
||||
if (rc < 0 || rc >= (int)sizeof(proxyjump_buf)) {
|
||||
@@ -222,17 +265,22 @@ static void torture_proxyjump_multiple_sshd_users_jump(void **state)
|
||||
int rc;
|
||||
socket_t fd;
|
||||
|
||||
struct ssh_jump_callbacks_struct c = {
|
||||
struct ssh_jump_callbacks_struct c1 = {
|
||||
.before_connection = before_connection,
|
||||
.verify_knownhost = verify_knownhost,
|
||||
.authenticate = authenticate,
|
||||
.authenticate = authenticate_doe,
|
||||
};
|
||||
struct ssh_jump_callbacks_struct c2 = {
|
||||
.before_connection = before_connection,
|
||||
.verify_knownhost = verify_knownhost,
|
||||
.authenticate = authenticate_frank,
|
||||
};
|
||||
|
||||
torture_setup_sshd_servers(state, false);
|
||||
|
||||
rc = snprintf(proxyjump_buf,
|
||||
sizeof(proxyjump_buf),
|
||||
"doe@%s:22,alice@%s:22",
|
||||
"doe@%s:22,frank@%s:22",
|
||||
address,
|
||||
address1);
|
||||
if (rc < 0 || rc >= (int)sizeof(proxyjump_buf)) {
|
||||
@@ -240,9 +288,9 @@ static void torture_proxyjump_multiple_sshd_users_jump(void **state)
|
||||
}
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYJUMP, proxyjump_buf);
|
||||
assert_ssh_return_code(session, rc);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND, &c);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND, &c1);
|
||||
assert_ssh_return_code(session, rc);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND, &c);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_PROXYJUMP_CB_LIST_APPEND, &c2);
|
||||
assert_ssh_return_code(session, rc);
|
||||
|
||||
rc = ssh_connect(session);
|
||||
|
||||
@@ -2,6 +2,7 @@ bob:x:5000:9000:bob gecos:@HOMEDIR@/bob:/bin/sh
|
||||
alice:x:5001:9000:alice gecos:@HOMEDIR@/alice:/bin/sh
|
||||
charlie:x:5002:9000:charlie gecos:@HOMEDIR@/charlie:/bin/sh
|
||||
doe:x:5003:9000:doe gecos:@HOMEDIR@/doe:/bin/sh
|
||||
frank:x:5003:9000:doe gecos:@HOMEDIR@/frank:/bin/sh
|
||||
sshd:x:65530:65531:sshd:@HOMEDIR@:/sbin/nologin
|
||||
nobody:x:65533:65534:nobody gecos:@HOMEDIR@:/bin/false
|
||||
root:x:65534:65532:root gecos:@HOMEDIR@:/bin/false
|
||||
|
||||
@@ -833,7 +833,7 @@ torture_setup_create_sshd_config(void **state, bool pam, bool second_sshd)
|
||||
"TrustedUserCAKeys %s\n"
|
||||
"\n"
|
||||
"LogLevel DEBUG3\n"
|
||||
"Subsystem sftp %s -l DEBUG2\n"
|
||||
"Subsystem sftp %s -l DEBUG3 -e\n"
|
||||
"\n"
|
||||
"PasswordAuthentication yes\n"
|
||||
"PubkeyAuthentication yes\n"
|
||||
@@ -873,7 +873,7 @@ torture_setup_create_sshd_config(void **state, bool pam, bool second_sshd)
|
||||
"TrustedUserCAKeys %s\n" /* Trusted CA */
|
||||
"\n"
|
||||
"LogLevel DEBUG3\n"
|
||||
"Subsystem sftp %s -l DEBUG2\n" /* SFTP server */
|
||||
"Subsystem sftp %s -l DEBUG3 -e\n" /* SFTP server */
|
||||
"\n"
|
||||
"PasswordAuthentication yes\n"
|
||||
"PubkeyAuthentication yes\n"
|
||||
|
||||
@@ -159,6 +159,8 @@ extern LIBSSH_THREAD int ssh_log_level;
|
||||
"\tProxyJump jumpbox:2222\n" \
|
||||
"Host two-step\n" \
|
||||
"\tProxyJump u1@first:222,u2@second:33\n" \
|
||||
"Host three-step\n" \
|
||||
"\tProxyJump u1@first:222,u2@second:33,u3@third:444\n" \
|
||||
"Host none\n" \
|
||||
"\tProxyJump none\n" \
|
||||
"Host only-command\n" \
|
||||
@@ -1172,6 +1174,23 @@ static void torture_config_proxyjump(void **state,
|
||||
"u1",
|
||||
"222");
|
||||
|
||||
/* Three step jump */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "three-step");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
helper_proxy_jump_check(session->opts.proxy_jumps->root,
|
||||
"third",
|
||||
"u3",
|
||||
"444");
|
||||
helper_proxy_jump_check(session->opts.proxy_jumps->root->next,
|
||||
"second",
|
||||
"u2",
|
||||
"33");
|
||||
helper_proxy_jump_check(session->opts.proxy_jumps->root->next->next,
|
||||
"first",
|
||||
"u1",
|
||||
"222");
|
||||
|
||||
/* none */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "none");
|
||||
@@ -1237,6 +1256,13 @@ static void torture_config_proxyjump(void **state,
|
||||
assert_string_equal(session->opts.ProxyCommand,
|
||||
"ssh -l u1 -p 222 -J u2@second:33 -W '[%h]:%p' first");
|
||||
|
||||
/* Three step jump */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "three-step");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.ProxyCommand,
|
||||
"ssh -l u1 -p 222 -J u2@second:33,u3@third:444 -W '[%h]:%p' first");
|
||||
|
||||
/* none */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "none");
|
||||
|
||||
Reference in New Issue
Block a user