diff options
Diffstat (limited to 'src/agent.c')
-rw-r--r-- | src/agent.c | 105 |
1 files changed, 75 insertions, 30 deletions
diff --git a/src/agent.c b/src/agent.c index b962a8e3..9c62ea42 100644 --- a/src/agent.c +++ b/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); - - 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) { + 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.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) { 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; |