Fix display of VT100 vertically-offset horizontal line characters
[sgt/putty] / unix / uxagentc.c
CommitLineData
c5e438ec 1/*
2 * SSH agent client code.
3 */
4
5#include <stdio.h>
6#include <stdlib.h>
fbbb86aa 7#include <assert.h>
8#include <unistd.h>
9#include <sys/socket.h>
10#include <sys/un.h>
89e97516 11#include <fcntl.h>
c5e438ec 12
839f10db 13#include "putty.h"
c5e438ec 14#include "misc.h"
839f10db 15#include "tree234.h"
c5e438ec 16#include "puttymem.h"
17
c5e438ec 18int agent_exists(void)
19{
fbbb86aa 20 if (getenv("SSH_AUTH_SOCK") != NULL)
21 return TRUE;
22 return FALSE;
c5e438ec 23}
24
839f10db 25static tree234 *agent_connections;
26struct agent_connection {
27 int fd;
28 char *retbuf;
29 char sizebuf[4];
30 int retsize, retlen;
31 void (*callback)(void *, void *, int);
32 void *callback_ctx;
33};
34static int agent_conncmp(void *av, void *bv)
35{
36 struct agent_connection *a = (struct agent_connection *) av;
37 struct agent_connection *b = (struct agent_connection *) bv;
38 if (a->fd < b->fd)
39 return -1;
40 if (a->fd > b->fd)
41 return +1;
42 return 0;
43}
44static int agent_connfind(void *av, void *bv)
45{
46 int afd = *(int *) av;
47 struct agent_connection *b = (struct agent_connection *) bv;
48 if (afd < b->fd)
49 return -1;
50 if (afd > b->fd)
51 return +1;
52 return 0;
53}
54
55static int agent_select_result(int fd, int event)
56{
57 int ret;
58 struct agent_connection *conn;
59
60 assert(event == 1); /* not selecting for anything but R */
61
62 conn = find234(agent_connections, &fd, agent_connfind);
63 if (!conn) {
64 uxsel_del(fd);
65 return 1;
66 }
67
68 ret = read(fd, conn->retbuf+conn->retlen, conn->retsize-conn->retlen);
69 if (ret <= 0) {
70 if (conn->retbuf != conn->sizebuf) sfree(conn->retbuf);
71 conn->retbuf = NULL;
72 conn->retlen = 0;
73 goto done;
74 }
75 conn->retlen += ret;
76 if (conn->retsize == 4 && conn->retlen == 4) {
77 conn->retsize = GET_32BIT(conn->retbuf);
78 if (conn->retsize <= 0) {
79 conn->retbuf = NULL;
80 conn->retlen = 0;
81 goto done;
82 }
83 conn->retsize += 4;
84 assert(conn->retbuf == conn->sizebuf);
85 conn->retbuf = snewn(conn->retsize, char);
86 memcpy(conn->retbuf, conn->sizebuf, 4);
87 }
88
89 if (conn->retlen < conn->retsize)
90 return 0; /* more data to come */
91
92 done:
93 /*
94 * We have now completed the agent query. Do the callback, and
95 * clean up. (Of course we don't free retbuf, since ownership
96 * of that passes to the callback.)
97 */
98 conn->callback(conn->callback_ctx, conn->retbuf, conn->retlen);
99 uxsel_del(fd);
100 close(fd);
101 del234(agent_connections, conn);
102 sfree(conn);
103 return 0;
104}
105
106int agent_query(void *in, int inlen, void **out, int *outlen,
107 void (*callback)(void *, void *, int), void *callback_ctx)
c5e438ec 108{
fbbb86aa 109 char *name;
110 int sock;
111 struct sockaddr_un addr;
112 int done;
839f10db 113 struct agent_connection *conn;
fbbb86aa 114
115 name = getenv("SSH_AUTH_SOCK");
116 if (!name)
117 goto failure;
118
119 sock = socket(PF_UNIX, SOCK_STREAM, 0);
120 if (sock < 0) {
121 perror("socket(PF_UNIX)");
122 exit(1);
123 }
124
db9b7dce 125 cloexec(sock);
89e97516 126
fbbb86aa 127 addr.sun_family = AF_UNIX;
128 strncpy(addr.sun_path, name, sizeof(addr.sun_path));
129 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
130 close(sock);
131 goto failure;
132 }
133
134 for (done = 0; done < inlen ;) {
135 int ret = write(sock, (char *)in + done, inlen - done);
136 if (ret <= 0) {
137 close(sock);
138 goto failure;
139 }
140 done += ret;
141 }
142
839f10db 143 if (!agent_connections)
144 agent_connections = newtree234(agent_conncmp);
fbbb86aa 145
839f10db 146 conn = snew(struct agent_connection);
147 conn->fd = sock;
148 conn->retbuf = conn->sizebuf;
149 conn->retsize = 4;
150 conn->retlen = 0;
151 conn->callback = callback;
152 conn->callback_ctx = callback_ctx;
153 add234(agent_connections, conn);
fbbb86aa 154
839f10db 155 uxsel_set(sock, 1, agent_select_result);
156 return 0;
fbbb86aa 157
158 failure:
159 *out = NULL;
160 *outlen = 0;
839f10db 161 return 1;
c5e438ec 162}