OSDN Git Service

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