]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - unix/uxagentc.c
Update version number for 0.66 release.
[PuTTY.git] / unix / uxagentc.c
1 /*
2  * SSH agent client code.
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <assert.h>
8 #include <unistd.h>
9 #include <sys/socket.h>
10 #include <sys/un.h>
11 #include <fcntl.h>
12
13 #include "putty.h"
14 #include "misc.h"
15 #include "tree234.h"
16 #include "puttymem.h"
17
18 int agent_exists(void)
19 {
20     const char *p = getenv("SSH_AUTH_SOCK");
21     if (p && *p)
22         return TRUE;
23     return FALSE;
24 }
25
26 static tree234 *agent_connections;
27 struct agent_connection {
28     int fd;
29     char *retbuf;
30     char sizebuf[4];
31     int retsize, retlen;
32     void (*callback)(void *, void *, int);
33     void *callback_ctx;
34 };
35 static int agent_conncmp(void *av, void *bv)
36 {
37     struct agent_connection *a = (struct agent_connection *) av;
38     struct agent_connection *b = (struct agent_connection *) bv;
39     if (a->fd < b->fd)
40         return -1;
41     if (a->fd > b->fd)
42         return +1;
43     return 0;
44 }
45 static int agent_connfind(void *av, void *bv)
46 {
47     int afd = *(int *) av;
48     struct agent_connection *b = (struct agent_connection *) bv;
49     if (afd < b->fd)
50         return -1;
51     if (afd > b->fd)
52         return +1;
53     return 0;
54 }
55
56 static int agent_select_result(int fd, int event)
57 {
58     int ret;
59     struct agent_connection *conn;
60
61     assert(event == 1);                /* not selecting for anything but R */
62
63     conn = find234(agent_connections, &fd, agent_connfind);
64     if (!conn) {
65         uxsel_del(fd);
66         return 1;
67     }
68
69     ret = read(fd, conn->retbuf+conn->retlen, conn->retsize-conn->retlen);
70     if (ret <= 0) {
71         if (conn->retbuf != conn->sizebuf) sfree(conn->retbuf);
72         conn->retbuf = NULL;
73         conn->retlen = 0;
74         goto done;
75     }
76     conn->retlen += ret;
77     if (conn->retsize == 4 && conn->retlen == 4) {
78         conn->retsize = toint(GET_32BIT(conn->retbuf) + 4);
79         if (conn->retsize <= 0) {
80             conn->retbuf = NULL;
81             conn->retlen = 0;
82             goto done;
83         }
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
106 int agent_query(void *in, int inlen, void **out, int *outlen,
107                 void (*callback)(void *, void *, int), void *callback_ctx)
108 {
109     char *name;
110     int sock;
111     struct sockaddr_un addr;
112     int done;
113     struct agent_connection *conn;
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
125     cloexec(sock);
126
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
143     if (!agent_connections)
144         agent_connections = newtree234(agent_conncmp);
145
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);
154
155     uxsel_set(sock, 1, agent_select_result);
156     return 0;
157
158     failure:
159     *out = NULL;
160     *outlen = 0;
161     return 1;
162 }