2 * SSH agent client code.
9 #include <sys/socket.h>
18 int agent_exists(void)
20 const char *p = getenv("SSH_AUTH_SOCK");
26 static tree234 *agent_pending_queries;
27 struct agent_pending_query {
32 void (*callback)(void *, void *, int);
35 static int agent_conncmp(void *av, void *bv)
37 agent_pending_query *a = (agent_pending_query *) av;
38 agent_pending_query *b = (agent_pending_query *) bv;
45 static int agent_connfind(void *av, void *bv)
47 int afd = *(int *) av;
48 agent_pending_query *b = (agent_pending_query *) bv;
57 * Attempt to read from an agent socket fd. Returns 0 if the expected
58 * response is as yet incomplete; returns 1 if it's either complete
59 * (conn->retbuf non-NULL and filled with something useful) or has
60 * failed totally (conn->retbuf is NULL).
62 static int agent_try_read(agent_pending_query *conn)
66 ret = read(conn->fd, conn->retbuf+conn->retlen,
67 conn->retsize-conn->retlen);
69 if (conn->retbuf != conn->sizebuf) sfree(conn->retbuf);
75 if (conn->retsize == 4 && conn->retlen == 4) {
76 conn->retsize = toint(GET_32BIT(conn->retbuf) + 4);
77 if (conn->retsize <= 0) {
80 return -1; /* way too large */
82 assert(conn->retbuf == conn->sizebuf);
83 conn->retbuf = snewn(conn->retsize, char);
84 memcpy(conn->retbuf, conn->sizebuf, 4);
87 if (conn->retlen < conn->retsize)
88 return 0; /* more data to come */
93 void agent_cancel_query(agent_pending_query *conn)
97 del234(agent_pending_queries, conn);
101 static int agent_select_result(int fd, int event)
103 agent_pending_query *conn;
105 assert(event == 1); /* not selecting for anything but R */
107 conn = find234(agent_pending_queries, &fd, agent_connfind);
113 if (!agent_try_read(conn))
114 return 0; /* more data to come */
117 * We have now completed the agent query. Do the callback, and
118 * clean up. (Of course we don't free retbuf, since ownership
119 * of that passes to the callback.)
121 conn->callback(conn->callback_ctx, conn->retbuf, conn->retlen);
122 agent_cancel_query(conn);
126 agent_pending_query *agent_query(
127 void *in, int inlen, void **out, int *outlen,
128 void (*callback)(void *, void *, int), void *callback_ctx)
132 struct sockaddr_un addr;
134 agent_pending_query *conn;
136 name = getenv("SSH_AUTH_SOCK");
140 sock = socket(PF_UNIX, SOCK_STREAM, 0);
142 perror("socket(PF_UNIX)");
148 addr.sun_family = AF_UNIX;
149 strncpy(addr.sun_path, name, sizeof(addr.sun_path));
150 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
155 for (done = 0; done < inlen ;) {
156 int ret = write(sock, (char *)in + done, inlen - done);
164 conn = snew(agent_pending_query);
166 conn->retbuf = conn->sizebuf;
169 conn->callback = callback;
170 conn->callback_ctx = callback_ctx;
174 * Bodge to permit making deliberately synchronous agent
175 * requests. Used by Unix Pageant in command-line client mode,
176 * which is legit because it really is true that no other part
177 * of the program is trying to get anything useful done
178 * simultaneously. But this special case shouldn't be used in
179 * any more general program.
181 no_nonblock(conn->fd);
182 while (!agent_try_read(conn))
183 /* empty loop body */;
186 *outlen = conn->retlen;
192 * Otherwise do it properly: add conn to the tree of agent
193 * connections currently in flight, return 0 to indicate that the
194 * response hasn't been received yet, and call the callback when
195 * select_result comes back to us.
197 if (!agent_pending_queries)
198 agent_pending_queries = newtree234(agent_conncmp);
199 add234(agent_pending_queries, conn);
201 uxsel_set(sock, 1, agent_select_result);