aboutsummaryrefslogtreecommitdiff
path: root/src/agent.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/agent.c')
-rw-r--r--src/agent.c105
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;