mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-12 03:00:26 +09:00
ssh-agent: implement the clientside for agent forwarding auth.
This can only be used to authenticate the client, not to allow the connected server to transfer agent requests Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
committed by
Andreas Schneider
parent
9bdb546852
commit
e76442b650
@@ -71,6 +71,7 @@ struct ssh_agent_struct {
|
|||||||
struct ssh_socket_struct *sock;
|
struct ssh_socket_struct *sock;
|
||||||
ssh_buffer ident;
|
ssh_buffer ident;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
|
ssh_channel channel;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
|||||||
@@ -521,6 +521,7 @@ LIBSSH_API int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len);
|
|||||||
LIBSSH_API int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
LIBSSH_API int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
|
||||||
fd_set *readfds, struct timeval *timeout);
|
fd_set *readfds, struct timeval *timeout);
|
||||||
LIBSSH_API int ssh_service_request(ssh_session session, const char *service);
|
LIBSSH_API int ssh_service_request(ssh_session session, const char *service);
|
||||||
|
LIBSSH_API int ssh_set_agent_channel(ssh_session session, ssh_channel channel);
|
||||||
LIBSSH_API void ssh_set_blocking(ssh_session session, int blocking);
|
LIBSSH_API void ssh_set_blocking(ssh_session session, int blocking);
|
||||||
LIBSSH_API void ssh_set_fd_except(ssh_session session);
|
LIBSSH_API void ssh_set_fd_except(ssh_session session);
|
||||||
LIBSSH_API void ssh_set_fd_toread(ssh_session session);
|
LIBSSH_API void ssh_set_fd_toread(ssh_session session);
|
||||||
|
|||||||
61
src/agent.c
61
src/agent.c
@@ -83,13 +83,17 @@ static void agent_put_u32(void *vp, uint32_t v) {
|
|||||||
p[3] = (uint8_t)v & 0xff;
|
p[3] = (uint8_t)v & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t atomicio(ssh_socket s, void *buf, size_t n, int do_read) {
|
static size_t atomicio(struct ssh_agent_struct *agent, void *buf, size_t n, int do_read) {
|
||||||
char *b = buf;
|
char *b = buf;
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
ssize_t res;
|
ssize_t res;
|
||||||
ssh_pollfd_t pfd;
|
ssh_pollfd_t pfd;
|
||||||
socket_t fd = ssh_socket_get_fd_in(s);
|
ssh_channel channel = agent->channel;
|
||||||
|
socket_t fd;
|
||||||
|
|
||||||
|
/* Using a socket ? */
|
||||||
|
if (channel == NULL) {
|
||||||
|
fd = ssh_socket_get_fd_in(agent->sock);
|
||||||
pfd.fd = fd;
|
pfd.fd = fd;
|
||||||
pfd.events = do_read ? POLLIN : POLLOUT;
|
pfd.events = do_read ? POLLIN : POLLOUT;
|
||||||
|
|
||||||
@@ -121,8 +125,22 @@ static size_t atomicio(ssh_socket s, void *buf, size_t n, int do_read) {
|
|||||||
pos += (size_t) res;
|
pos += (size_t) res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pos;
|
return pos;
|
||||||
|
} else {
|
||||||
|
/* using an SSH channel */
|
||||||
|
while (n > pos){
|
||||||
|
if (do_read)
|
||||||
|
res = ssh_channel_read(channel,b + pos, n-pos, 0);
|
||||||
|
else
|
||||||
|
res = ssh_channel_write(channel, b+pos, n-pos);
|
||||||
|
if (res == SSH_AGAIN)
|
||||||
|
continue;
|
||||||
|
if (res == SSH_ERROR)
|
||||||
|
return 0;
|
||||||
|
pos += (size_t)res;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssh_agent agent_new(struct ssh_session_struct *session) {
|
ssh_agent agent_new(struct ssh_session_struct *session) {
|
||||||
@@ -140,10 +158,34 @@ ssh_agent agent_new(struct ssh_session_struct *session) {
|
|||||||
SAFE_FREE(agent);
|
SAFE_FREE(agent);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
agent->channel = NULL;
|
||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void agent_set_channel(struct ssh_agent_struct *agent, ssh_channel channel){
|
||||||
|
agent->channel = channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief sets the SSH agent channel.
|
||||||
|
* The SSH agent channel will be used to authenticate this client using
|
||||||
|
* an agent through a channel, from another session. The most likely use
|
||||||
|
* is to implement SSH Agent forwarding into a SSH proxy.
|
||||||
|
* @param[in] channel a SSH channel from another session.
|
||||||
|
* @returns SSH_OK in case of success
|
||||||
|
* SSH_ERROR in case of an error
|
||||||
|
*/
|
||||||
|
int ssh_set_agent_channel(ssh_session session, ssh_channel channel){
|
||||||
|
if (!session)
|
||||||
|
return SSH_ERROR;
|
||||||
|
if (!session->agent){
|
||||||
|
ssh_set_error(session, SSH_REQUEST_DENIED, "Session has no active agent");
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
agent_set_channel(session->agent, channel);
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void agent_close(struct ssh_agent_struct *agent) {
|
void agent_close(struct ssh_agent_struct *agent) {
|
||||||
if (agent == NULL) {
|
if (agent == NULL) {
|
||||||
return;
|
return;
|
||||||
@@ -174,6 +216,9 @@ static int agent_connect(ssh_session session) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session->agent->channel != NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
auth_sock = getenv("SSH_AUTH_SOCK");
|
auth_sock = getenv("SSH_AUTH_SOCK");
|
||||||
|
|
||||||
if (auth_sock && *auth_sock) {
|
if (auth_sock && *auth_sock) {
|
||||||
@@ -216,8 +261,8 @@ static int agent_talk(struct ssh_session_struct *session,
|
|||||||
agent_put_u32(payload, len);
|
agent_put_u32(payload, len);
|
||||||
|
|
||||||
/* send length and then the request packet */
|
/* send length and then the request packet */
|
||||||
if (atomicio(session->agent->sock, payload, 4, 0) == 4) {
|
if (atomicio(session->agent, payload, 4, 0) == 4) {
|
||||||
if (atomicio(session->agent->sock, buffer_get_rest(request), len, 0)
|
if (atomicio(session->agent, buffer_get_rest(request), len, 0)
|
||||||
!= len) {
|
!= len) {
|
||||||
SSH_LOG(session, SSH_LOG_WARN, "atomicio sending request failed: %s",
|
SSH_LOG(session, SSH_LOG_WARN, "atomicio sending request failed: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
@@ -231,7 +276,7 @@ static int agent_talk(struct ssh_session_struct *session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* wait for response, read the length of the response packet */
|
/* wait for response, read the length of the response packet */
|
||||||
if (atomicio(session->agent->sock, payload, 4, 1) != 4) {
|
if (atomicio(session->agent, payload, 4, 1) != 4) {
|
||||||
SSH_LOG(session, SSH_LOG_WARN, "atomicio read response length failed: %s",
|
SSH_LOG(session, SSH_LOG_WARN, "atomicio read response length failed: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
@@ -250,7 +295,7 @@ static int agent_talk(struct ssh_session_struct *session,
|
|||||||
if (n > sizeof(payload)) {
|
if (n > sizeof(payload)) {
|
||||||
n = sizeof(payload);
|
n = sizeof(payload);
|
||||||
}
|
}
|
||||||
if (atomicio(session->agent->sock, payload, n, 1) != n) {
|
if (atomicio(session->agent, payload, n, 1) != n) {
|
||||||
SSH_LOG(session, SSH_LOG_WARN,
|
SSH_LOG(session, SSH_LOG_WARN,
|
||||||
"Error reading response from authentication socket.");
|
"Error reading response from authentication socket.");
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
Reference in New Issue
Block a user