OSDN Git Service

Enhance all settings encryption.
[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     const char *p = getenv("SSH_AUTH_SOCK");\r
21     if (p && *p)\r
22         return TRUE;\r
23     return FALSE;\r
24 }\r
25 \r
26 static tree234 *agent_connections;\r
27 struct agent_connection {\r
28     int fd;\r
29     char *retbuf;\r
30     char sizebuf[4];\r
31     int retsize, retlen;\r
32     void (*callback)(void *, void *, int);\r
33     void *callback_ctx;\r
34 };\r
35 static int agent_conncmp(void *av, void *bv)\r
36 {\r
37     struct agent_connection *a = (struct agent_connection *) av;\r
38     struct agent_connection *b = (struct agent_connection *) bv;\r
39     if (a->fd < b->fd)\r
40         return -1;\r
41     if (a->fd > b->fd)\r
42         return +1;\r
43     return 0;\r
44 }\r
45 static int agent_connfind(void *av, void *bv)\r
46 {\r
47     int afd = *(int *) av;\r
48     struct agent_connection *b = (struct agent_connection *) bv;\r
49     if (afd < b->fd)\r
50         return -1;\r
51     if (afd > b->fd)\r
52         return +1;\r
53     return 0;\r
54 }\r
55 \r
56 static int agent_select_result(int fd, int event)\r
57 {\r
58     int ret;\r
59     struct agent_connection *conn;\r
60 \r
61     assert(event == 1);                /* not selecting for anything but R */\r
62 \r
63     conn = find234(agent_connections, &fd, agent_connfind);\r
64     if (!conn) {\r
65         uxsel_del(fd);\r
66         return 1;\r
67     }\r
68 \r
69     ret = read(fd, conn->retbuf+conn->retlen, conn->retsize-conn->retlen);\r
70     if (ret <= 0) {\r
71         if (conn->retbuf != conn->sizebuf) sfree(conn->retbuf);\r
72         conn->retbuf = NULL;\r
73         conn->retlen = 0;\r
74         goto done;\r
75     }\r
76     conn->retlen += ret;\r
77     if (conn->retsize == 4 && conn->retlen == 4) {\r
78         conn->retsize = toint(GET_32BIT(conn->retbuf) + 4);\r
79         if (conn->retsize <= 0) {\r
80             conn->retbuf = NULL;\r
81             conn->retlen = 0;\r
82             goto done;\r
83         }\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