comparison cli-agentfwd.c @ 500:d588e3ea557a agent-client

propagate from branch 'au.asn.ucc.matt.dropbear' (head 4fb35083f0f46ea667e7043e7d4314aecd3df46c) to branch 'au.asn.ucc.matt.dropbear.cli-agent' (head 833d0adef6cdbf43ea75283524c665e70b0ee1ee)
author Matt Johnston <matt@ucc.asn.au>
date Tue, 23 Sep 2008 16:05:04 +0000
parents ca7e76d981d9
children cf376c696dfc
comparison
equal deleted inserted replaced
499:f3ca5ebc319a 500:d588e3ea557a
1 /*
2 * Dropbear - a SSH2 server
3 *
4 * Copyright (c) 2005 Matt Johnston
5 * All rights reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE. */
24
25 /* The basic protocol use to communicate with the agent is defined in
26 * draft-ylonen-ssh-protocol-00.txt, with the ssh2 extensions defined through
27 * openssh's implementation. */
28
29 #include "includes.h"
30
31 #ifdef ENABLE_CLI_AGENTFWD
32
33 #include "agentfwd.h"
34 #include "session.h"
35 #include "ssh.h"
36 #include "dbutil.h"
37 #include "chansession.h"
38 #include "channel.h"
39 #include "packet.h"
40 #include "buffer.h"
41 #include "random.h"
42 #include "listener.h"
43 #include "runopts.h"
44 #include "atomicio.h"
45 #include "signkey.h"
46 #include "auth.h"
47
48 static int new_agent_chan(struct Channel * channel);
49
50 const struct ChanType chan_cli_agent = {
51 0, /* sepfds */
52 "[email protected]",
53 new_agent_chan,
54 NULL,
55 NULL,
56 NULL
57 };
58
59 static int connect_agent() {
60
61 int fd = -1;
62 char* agent_sock = NULL;
63
64 agent_sock = getenv("SSH_AUTH_SOCK");
65 if (agent_sock == NULL)
66 return -1;
67
68 fd = connect_unix(agent_sock);
69
70 return fd;
71 }
72
73 // handle a request for a connection to the locally running ssh-agent
74 // or forward.
75 static int new_agent_chan(struct Channel * channel) {
76
77 int fd = -1;
78
79 if (!cli_opts.agent_fwd)
80 return SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
81
82 fd = connect_agent();
83
84 setnonblocking(fd);
85
86 ses.maxfd = MAX(ses.maxfd, fd);
87
88 channel->infd = fd;
89 channel->outfd = fd;
90
91 // success
92 return 0;
93 }
94
95 /* Sends a request to the agent, returning a newly allocated buffer
96 * with the response */
97 /* Packet format (from draft-ylonen)
98 4 bytes Length, msb first. Does not include length itself.
99 1 byte Packet type. The value 255 is reserved for future extensions.
100 data Any data, depending on packet type. Encoding as in the ssh packet
101 protocol.
102
103 In this case, data is always empty
104 */
105 static buffer * agent_request(int fd, unsigned char type) {
106
107 buffer * payload = NULL;
108 buffer * inbuf = NULL;
109 size_t readlen = 0;
110 ssize_t ret;
111
112 payload = buf_new(4 + 1);
113
114 buf_putint(payload, 1);
115 buf_putbyte(payload, type);
116
117 ret = atomicio(write, fd, buf_getptr(payload, payload->len), payload->len);
118 if ((size_t)ret != payload->len) {
119 TRACE(("write failed for agent_request"))
120 goto out;
121 }
122
123 buf_free(payload);
124 payload = NULL;
125
126 /* Now we read the response */
127 inbuf = buf_new(4);
128 ret = atomicio(read, fd, buf_getwriteptr(inbuf, 4), 4);
129 if (ret != 4) {
130 TRACE(("read of length failed for agent_request"))
131 goto out;
132 }
133
134 readlen = buf_getint(inbuf);
135 if (readlen > MAX_AGENT_REPLY) {
136 TRACE(("agent reply is too big"));
137 goto out;
138 }
139
140 buf_resize(inbuf, readlen);
141 ret = atomicio(read, fd, buf_getwriteptr(inbuf, readlen), readlen);
142 if ((size_t)ret != readlen) {
143 TRACE(("read of data failed for agent_request"))
144 goto out;
145 }
146
147 out:
148 if (payload)
149 buf_free(payload);
150
151 return inbuf;
152 }
153
154 static SignKeyList * agent_get_key_list(int fd)
155 {
156 buffer * inbuf = NULL;
157 unsigned int num = 0;
158 unsigned char packet_type;
159 unsigned int i;
160 struct SignKeyList *retkey = NULL, *key = NULL;
161 int ret;
162
163 inbuf = agent_request(fd, SSH2_AGENTC_REQUEST_IDENTITIES);
164 if (!inbuf) {
165 goto out;
166 }
167
168 /* The reply has a format of:
169 * byte packet_type
170 * int num_keys
171 *
172 * string keyblob1
173 * string comment1
174 * ...
175 * string keyblob(n)
176 * string comment(n)
177 */
178 packet_type = buf_getbyte(inbuf);
179 if (packet_type != SSH2_AGENT_IDENTITIES_ANSWER) {
180 goto out;
181 }
182
183 num = buf_getint(inbuf);
184 for (i = 0; i < num; i++) {
185 sign_key * pubkey = NULL;
186 char key_type = DROPBEAR_SIGNKEY_ANY;
187 struct SignKeyList *nextkey = NULL;
188
189 nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList));
190 if (key)
191 key->next = nextkey;
192 else
193 retkey = nextkey;
194 key = nextkey;
195
196 pubkey = new_sign_key();
197 ret = buf_get_pub_key(inbuf, pubkey, &key_type);
198 if (ret != DROPBEAR_SUCCESS) {
199 /* This is slack, properly would cleanup vars etc */
200 dropbear_exit("Bad pubkey received from agent");
201 }
202
203 key->key = pubkey;
204 key->next = NULL;
205 key->type = key_type;
206 key->source = SIGNKEY_SOURCE_AGENT;
207
208 /* We'll ignore the comment */
209 buf_eatstring(inbuf);
210 }
211
212 out:
213 if (inbuf) {
214 buf_free(inbuf);
215 inbuf = NULL;
216 }
217
218 return retkey;
219 }
220
221 /* return DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
222 SignKeyList * load_agent_keys()
223 {
224
225 SignKeyList * ret_list;
226 int fd;
227 fd = connect_agent();
228 if (fd < 0) {
229 dropbear_log(LOG_INFO, "Failed to connect to agent");
230 return NULL;
231 }
232
233 ret_list = agent_get_key_list(fd);
234 close(fd);
235 }
236
237 // general procedure:
238 // - get the list of keys from the agent
239 // - foreach, send a dummy userauth_pubkey message to the server and see
240 // if it lets us in
241 // - if it does, sign and auth
242 // - if not, repeat.
243 //
244
245 #endif