mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-04 12:20:42 +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;
|
||||
ssh_buffer ident;
|
||||
unsigned int count;
|
||||
ssh_channel channel;
|
||||
};
|
||||
|
||||
#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,
|
||||
fd_set *readfds, struct timeval *timeout);
|
||||
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_fd_except(ssh_session session);
|
||||
LIBSSH_API void ssh_set_fd_toread(ssh_session session);
|
||||
|
||||
101
src/agent.c
101
src/agent.c
@@ -83,23 +83,27 @@ static void agent_put_u32(void *vp, uint32_t v) {
|
||||
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;
|
||||
size_t pos = 0;
|
||||
ssize_t res;
|
||||
ssh_pollfd_t pfd;
|
||||
socket_t fd = ssh_socket_get_fd_in(s);
|
||||
ssh_channel channel = agent->channel;
|
||||
socket_t fd;
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = do_read ? POLLIN : POLLOUT;
|
||||
/* Using a socket ? */
|
||||
if (channel == NULL) {
|
||||
fd = ssh_socket_get_fd_in(agent->sock);
|
||||
pfd.fd = fd;
|
||||
pfd.events = do_read ? POLLIN : POLLOUT;
|
||||
|
||||
while (n > pos) {
|
||||
if (do_read) {
|
||||
res = read(fd, b + pos, n - pos);
|
||||
} else {
|
||||
res = write(fd, b + pos, n - pos);
|
||||
}
|
||||
switch (res) {
|
||||
while (n > pos) {
|
||||
if (do_read) {
|
||||
res = read(fd, b + pos, n - pos);
|
||||
} else {
|
||||
res = write(fd, b + pos, n - pos);
|
||||
}
|
||||
switch (res) {
|
||||
case -1:
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
@@ -107,22 +111,36 @@ static size_t atomicio(ssh_socket s, void *buf, size_t n, int do_read) {
|
||||
#ifdef EWOULDBLOCK
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
#else
|
||||
if (errno == EAGAIN) {
|
||||
if (errno == EAGAIN) {
|
||||
#endif
|
||||
(void) ssh_poll(&pfd, 1, -1);
|
||||
continue;
|
||||
(void) ssh_poll(&pfd, 1, -1);
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
case 0:
|
||||
/* read returns 0 on end-of-file */
|
||||
errno = do_read ? 0 : EPIPE;
|
||||
return pos;
|
||||
default:
|
||||
pos += (size_t) res;
|
||||
}
|
||||
return 0;
|
||||
case 0:
|
||||
/* read returns 0 on end-of-file */
|
||||
errno = do_read ? 0 : EPIPE;
|
||||
}
|
||||
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;
|
||||
default:
|
||||
pos += (size_t) res;
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
agent->channel = NULL;
|
||||
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) {
|
||||
if (agent == NULL) {
|
||||
return;
|
||||
@@ -174,6 +216,9 @@ static int agent_connect(ssh_session session) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session->agent->channel != NULL)
|
||||
return 0;
|
||||
|
||||
auth_sock = getenv("SSH_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);
|
||||
|
||||
/* send length and then the request packet */
|
||||
if (atomicio(session->agent->sock, payload, 4, 0) == 4) {
|
||||
if (atomicio(session->agent->sock, buffer_get_rest(request), len, 0)
|
||||
if (atomicio(session->agent, payload, 4, 0) == 4) {
|
||||
if (atomicio(session->agent, buffer_get_rest(request), len, 0)
|
||||
!= len) {
|
||||
SSH_LOG(session, SSH_LOG_WARN, "atomicio sending request failed: %s",
|
||||
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 */
|
||||
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",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
@@ -250,7 +295,7 @@ static int agent_talk(struct ssh_session_struct *session,
|
||||
if (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,
|
||||
"Error reading response from authentication socket.");
|
||||
return -1;
|
||||
|
||||
Reference in New Issue
Block a user