diff options
Diffstat (limited to 'authfd.c')
-rw-r--r-- | authfd.c | 840 |
1 files changed, 441 insertions, 399 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: authfd.c,v 1.93 2014/04/29 18:01:49 markus Exp $ */ | 1 | /* $OpenBSD: authfd.c,v 1.94 2015/01/14 20:05:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -47,124 +47,121 @@ | |||
47 | #include <stdarg.h> | 47 | #include <stdarg.h> |
48 | #include <string.h> | 48 | #include <string.h> |
49 | #include <unistd.h> | 49 | #include <unistd.h> |
50 | #include <errno.h> | ||
50 | 51 | ||
51 | #include "xmalloc.h" | 52 | #include "xmalloc.h" |
52 | #include "ssh.h" | 53 | #include "ssh.h" |
53 | #include "rsa.h" | 54 | #include "rsa.h" |
54 | #include "buffer.h" | 55 | #include "sshbuf.h" |
55 | #include "key.h" | 56 | #include "sshkey.h" |
56 | #include "authfd.h" | 57 | #include "authfd.h" |
57 | #include "cipher.h" | 58 | #include "cipher.h" |
58 | #include "kex.h" | ||
59 | #include "compat.h" | 59 | #include "compat.h" |
60 | #include "log.h" | 60 | #include "log.h" |
61 | #include "atomicio.h" | 61 | #include "atomicio.h" |
62 | #include "misc.h" | 62 | #include "misc.h" |
63 | #include "ssherr.h" | ||
63 | 64 | ||
64 | static int agent_present = 0; | 65 | #define MAX_AGENT_IDENTITIES 2048 /* Max keys in agent reply */ |
65 | 66 | #define MAX_AGENT_REPLY_LEN (256 * 1024) /* Max bytes in agent reply */ | |
66 | /* helper */ | ||
67 | int decode_reply(int type); | ||
68 | 67 | ||
69 | /* macro to check for "agent failure" message */ | 68 | /* macro to check for "agent failure" message */ |
70 | #define agent_failed(x) \ | 69 | #define agent_failed(x) \ |
71 | ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \ | 70 | ((x == SSH_AGENT_FAILURE) || \ |
71 | (x == SSH_COM_AGENT2_FAILURE) || \ | ||
72 | (x == SSH2_AGENT_FAILURE)) | 72 | (x == SSH2_AGENT_FAILURE)) |
73 | 73 | ||
74 | int | 74 | /* Convert success/failure response from agent to a err.h status */ |
75 | ssh_agent_present(void) | 75 | static int |
76 | decode_reply(u_char type) | ||
76 | { | 77 | { |
77 | int authfd; | 78 | if (agent_failed(type)) |
78 | 79 | return SSH_ERR_AGENT_FAILURE; | |
79 | if (agent_present) | 80 | else if (type == SSH_AGENT_SUCCESS) |
80 | return 1; | ||
81 | if ((authfd = ssh_get_authentication_socket()) == -1) | ||
82 | return 0; | 81 | return 0; |
83 | else { | 82 | else |
84 | ssh_close_authentication_socket(authfd); | 83 | return SSH_ERR_INVALID_FORMAT; |
85 | return 1; | ||
86 | } | ||
87 | } | 84 | } |
88 | 85 | ||
89 | /* Returns the number of the authentication fd, or -1 if there is none. */ | 86 | /* Returns the number of the authentication fd, or -1 if there is none. */ |
90 | |||
91 | int | 87 | int |
92 | ssh_get_authentication_socket(void) | 88 | ssh_get_authentication_socket(int *fdp) |
93 | { | 89 | { |
94 | const char *authsocket; | 90 | const char *authsocket; |
95 | int sock; | 91 | int sock, oerrno; |
96 | struct sockaddr_un sunaddr; | 92 | struct sockaddr_un sunaddr; |
97 | 93 | ||
94 | if (fdp != NULL) | ||
95 | *fdp = -1; | ||
96 | |||
98 | authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); | 97 | authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); |
99 | if (!authsocket) | 98 | if (!authsocket) |
100 | return -1; | 99 | return SSH_ERR_AGENT_NOT_PRESENT; |
101 | 100 | ||
102 | memset(&sunaddr, 0, sizeof(sunaddr)); | 101 | memset(&sunaddr, 0, sizeof(sunaddr)); |
103 | sunaddr.sun_family = AF_UNIX; | 102 | sunaddr.sun_family = AF_UNIX; |
104 | strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); | 103 | strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); |
105 | 104 | ||
106 | sock = socket(AF_UNIX, SOCK_STREAM, 0); | 105 | if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) |
107 | if (sock < 0) | 106 | return SSH_ERR_SYSTEM_ERROR; |
108 | return -1; | ||
109 | 107 | ||
110 | /* close on exec */ | 108 | /* close on exec */ |
111 | if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { | 109 | if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 || |
110 | connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) { | ||
111 | oerrno = errno; | ||
112 | close(sock); | 112 | close(sock); |
113 | return -1; | 113 | errno = oerrno; |
114 | return SSH_ERR_SYSTEM_ERROR; | ||
114 | } | 115 | } |
115 | if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { | 116 | if (fdp != NULL) |
117 | *fdp = sock; | ||
118 | else | ||
116 | close(sock); | 119 | close(sock); |
117 | return -1; | 120 | return 0; |
118 | } | ||
119 | agent_present = 1; | ||
120 | return sock; | ||
121 | } | 121 | } |
122 | 122 | ||
123 | /* Communicate with agent: send request and read reply */ | ||
123 | static int | 124 | static int |
124 | ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply) | 125 | ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply) |
125 | { | 126 | { |
126 | u_int l, len; | 127 | int r; |
128 | size_t l, len; | ||
127 | char buf[1024]; | 129 | char buf[1024]; |
128 | 130 | ||
129 | /* Get the length of the message, and format it in the buffer. */ | 131 | /* Get the length of the message, and format it in the buffer. */ |
130 | len = buffer_len(request); | 132 | len = sshbuf_len(request); |
131 | put_u32(buf, len); | 133 | put_u32(buf, len); |
132 | 134 | ||
133 | /* Send the length and then the packet to the agent. */ | 135 | /* Send the length and then the packet to the agent. */ |
134 | if (atomicio(vwrite, auth->fd, buf, 4) != 4 || | 136 | if (atomicio(vwrite, sock, buf, 4) != 4 || |
135 | atomicio(vwrite, auth->fd, buffer_ptr(request), | 137 | atomicio(vwrite, sock, (u_char *)sshbuf_ptr(request), |
136 | buffer_len(request)) != buffer_len(request)) { | 138 | sshbuf_len(request)) != sshbuf_len(request)) |
137 | error("Error writing to authentication socket."); | 139 | return SSH_ERR_AGENT_COMMUNICATION; |
138 | return 0; | ||
139 | } | ||
140 | /* | 140 | /* |
141 | * Wait for response from the agent. First read the length of the | 141 | * Wait for response from the agent. First read the length of the |
142 | * response packet. | 142 | * response packet. |
143 | */ | 143 | */ |
144 | if (atomicio(read, auth->fd, buf, 4) != 4) { | 144 | if (atomicio(read, sock, buf, 4) != 4) |
145 | error("Error reading response length from authentication socket."); | 145 | return SSH_ERR_AGENT_COMMUNICATION; |
146 | return 0; | ||
147 | } | ||
148 | 146 | ||
149 | /* Extract the length, and check it for sanity. */ | 147 | /* Extract the length, and check it for sanity. */ |
150 | len = get_u32(buf); | 148 | len = get_u32(buf); |
151 | if (len > 256 * 1024) | 149 | if (len > MAX_AGENT_REPLY_LEN) |
152 | fatal("Authentication response too long: %u", len); | 150 | return SSH_ERR_INVALID_FORMAT; |
153 | 151 | ||
154 | /* Read the rest of the response in to the buffer. */ | 152 | /* Read the rest of the response in to the buffer. */ |
155 | buffer_clear(reply); | 153 | sshbuf_reset(reply); |
156 | while (len > 0) { | 154 | while (len > 0) { |
157 | l = len; | 155 | l = len; |
158 | if (l > sizeof(buf)) | 156 | if (l > sizeof(buf)) |
159 | l = sizeof(buf); | 157 | l = sizeof(buf); |
160 | if (atomicio(read, auth->fd, buf, l) != l) { | 158 | if (atomicio(read, sock, buf, l) != l) |
161 | error("Error reading response from authentication socket."); | 159 | return SSH_ERR_AGENT_COMMUNICATION; |
162 | return 0; | 160 | if ((r = sshbuf_put(reply, buf, l)) != 0) |
163 | } | 161 | return r; |
164 | buffer_append(reply, buf, l); | ||
165 | len -= l; | 162 | len -= l; |
166 | } | 163 | } |
167 | return 1; | 164 | return 0; |
168 | } | 165 | } |
169 | 166 | ||
170 | /* | 167 | /* |
@@ -172,7 +169,6 @@ ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply | |||
172 | * obtained). The argument must have been returned by | 169 | * obtained). The argument must have been returned by |
173 | * ssh_get_authentication_socket(). | 170 | * ssh_get_authentication_socket(). |
174 | */ | 171 | */ |
175 | |||
176 | void | 172 | void |
177 | ssh_close_authentication_socket(int sock) | 173 | ssh_close_authentication_socket(int sock) |
178 | { | 174 | { |
@@ -180,80 +176,103 @@ ssh_close_authentication_socket(int sock) | |||
180 | close(sock); | 176 | close(sock); |
181 | } | 177 | } |
182 | 178 | ||
183 | /* | 179 | /* Lock/unlock agent */ |
184 | * Opens and connects a private socket for communication with the | 180 | int |
185 | * authentication agent. Returns the file descriptor (which must be | 181 | ssh_lock_agent(int sock, int lock, const char *password) |
186 | * shut down and closed by the caller when no longer needed). | ||
187 | * Returns NULL if an error occurred and the connection could not be | ||
188 | * opened. | ||
189 | */ | ||
190 | |||
191 | AuthenticationConnection * | ||
192 | ssh_get_authentication_connection(void) | ||
193 | { | 182 | { |
194 | AuthenticationConnection *auth; | 183 | int r; |
195 | int sock; | 184 | u_char type = lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK; |
196 | 185 | struct sshbuf *msg; | |
197 | sock = ssh_get_authentication_socket(); | 186 | |
198 | 187 | if ((msg = sshbuf_new()) == NULL) | |
199 | /* | 188 | return SSH_ERR_ALLOC_FAIL; |
200 | * Fail if we couldn't obtain a connection. This happens if we | 189 | if ((r = sshbuf_put_u8(msg, type)) != 0 || |
201 | * exited due to a timeout. | 190 | (r = sshbuf_put_cstring(msg, password)) != 0) |
202 | */ | 191 | goto out; |
203 | if (sock < 0) | 192 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
204 | return NULL; | 193 | goto out; |
205 | 194 | if ((r = sshbuf_get_u8(msg, &type)) != 0) | |
206 | auth = xcalloc(1, sizeof(*auth)); | 195 | goto out; |
207 | auth->fd = sock; | 196 | r = decode_reply(type); |
208 | buffer_init(&auth->identities); | 197 | out: |
209 | auth->howmany = 0; | 198 | sshbuf_free(msg); |
210 | 199 | return r; | |
211 | return auth; | ||
212 | } | 200 | } |
213 | 201 | ||
214 | /* | 202 | #ifdef WITH_SSH1 |
215 | * Closes the connection to the authentication agent and frees any associated | 203 | static int |
216 | * memory. | 204 | deserialise_identity1(struct sshbuf *ids, struct sshkey **keyp, char **commentp) |
217 | */ | ||
218 | |||
219 | void | ||
220 | ssh_close_authentication_connection(AuthenticationConnection *auth) | ||
221 | { | 205 | { |
222 | buffer_free(&auth->identities); | 206 | struct sshkey *key; |
223 | close(auth->fd); | 207 | int r, keybits; |
224 | free(auth); | 208 | u_int32_t bits; |
209 | char *comment = NULL; | ||
210 | |||
211 | if ((key = sshkey_new(KEY_RSA1)) == NULL) | ||
212 | return SSH_ERR_ALLOC_FAIL; | ||
213 | if ((r = sshbuf_get_u32(ids, &bits)) != 0 || | ||
214 | (r = sshbuf_get_bignum1(ids, key->rsa->e)) != 0 || | ||
215 | (r = sshbuf_get_bignum1(ids, key->rsa->n)) != 0 || | ||
216 | (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0) | ||
217 | goto out; | ||
218 | keybits = BN_num_bits(key->rsa->n); | ||
219 | /* XXX previously we just warned here. I think we should be strict */ | ||
220 | if (keybits < 0 || bits != (u_int)keybits) { | ||
221 | r = SSH_ERR_KEY_BITS_MISMATCH; | ||
222 | goto out; | ||
223 | } | ||
224 | if (keyp != NULL) { | ||
225 | *keyp = key; | ||
226 | key = NULL; | ||
227 | } | ||
228 | if (commentp != NULL) { | ||
229 | *commentp = comment; | ||
230 | comment = NULL; | ||
231 | } | ||
232 | r = 0; | ||
233 | out: | ||
234 | sshkey_free(key); | ||
235 | free(comment); | ||
236 | return r; | ||
225 | } | 237 | } |
238 | #endif | ||
226 | 239 | ||
227 | /* Lock/unlock agent */ | 240 | static int |
228 | int | 241 | deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp) |
229 | ssh_lock_agent(AuthenticationConnection *auth, int lock, const char *password) | ||
230 | { | 242 | { |
231 | int type; | 243 | int r; |
232 | Buffer msg; | 244 | char *comment = NULL; |
233 | 245 | const u_char *blob; | |
234 | buffer_init(&msg); | 246 | size_t blen; |
235 | buffer_put_char(&msg, lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK); | 247 | |
236 | buffer_put_cstring(&msg, password); | 248 | if ((r = sshbuf_get_string_direct(ids, &blob, &blen)) != 0 || |
237 | 249 | (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0) | |
238 | if (ssh_request_reply(auth, &msg, &msg) == 0) { | 250 | goto out; |
239 | buffer_free(&msg); | 251 | if ((r = sshkey_from_blob(blob, blen, keyp)) != 0) |
240 | return 0; | 252 | goto out; |
253 | if (commentp != NULL) { | ||
254 | *commentp = comment; | ||
255 | comment = NULL; | ||
241 | } | 256 | } |
242 | type = buffer_get_char(&msg); | 257 | r = 0; |
243 | buffer_free(&msg); | 258 | out: |
244 | return decode_reply(type); | 259 | free(comment); |
260 | return r; | ||
245 | } | 261 | } |
246 | 262 | ||
247 | /* | 263 | /* |
248 | * Returns the first authentication identity held by the agent. | 264 | * Fetch list of identities held by the agent. |
249 | */ | 265 | */ |
250 | |||
251 | int | 266 | int |
252 | ssh_get_num_identities(AuthenticationConnection *auth, int version) | 267 | ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp) |
253 | { | 268 | { |
254 | int type, code1 = 0, code2 = 0; | 269 | u_char type, code1 = 0, code2 = 0; |
255 | Buffer request; | 270 | u_int32_t num, i; |
271 | struct sshbuf *msg; | ||
272 | struct ssh_identitylist *idl = NULL; | ||
273 | int r; | ||
256 | 274 | ||
275 | /* Determine request and expected response types */ | ||
257 | switch (version) { | 276 | switch (version) { |
258 | case 1: | 277 | case 1: |
259 | code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; | 278 | code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; |
@@ -264,238 +283,270 @@ ssh_get_num_identities(AuthenticationConnection *auth, int version) | |||
264 | code2 = SSH2_AGENT_IDENTITIES_ANSWER; | 283 | code2 = SSH2_AGENT_IDENTITIES_ANSWER; |
265 | break; | 284 | break; |
266 | default: | 285 | default: |
267 | return 0; | 286 | return SSH_ERR_INVALID_ARGUMENT; |
268 | } | 287 | } |
269 | 288 | ||
270 | /* | 289 | /* |
271 | * Send a message to the agent requesting for a list of the | 290 | * Send a message to the agent requesting for a list of the |
272 | * identities it can represent. | 291 | * identities it can represent. |
273 | */ | 292 | */ |
274 | buffer_init(&request); | 293 | if ((msg = sshbuf_new()) == NULL) |
275 | buffer_put_char(&request, code1); | 294 | return SSH_ERR_ALLOC_FAIL; |
295 | if ((r = sshbuf_put_u8(msg, code1)) != 0) | ||
296 | goto out; | ||
276 | 297 | ||
277 | buffer_clear(&auth->identities); | 298 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
278 | if (ssh_request_reply(auth, &request, &auth->identities) == 0) { | 299 | goto out; |
279 | buffer_free(&request); | ||
280 | return 0; | ||
281 | } | ||
282 | buffer_free(&request); | ||
283 | 300 | ||
284 | /* Get message type, and verify that we got a proper answer. */ | 301 | /* Get message type, and verify that we got a proper answer. */ |
285 | type = buffer_get_char(&auth->identities); | 302 | if ((r = sshbuf_get_u8(msg, &type)) != 0) |
303 | goto out; | ||
286 | if (agent_failed(type)) { | 304 | if (agent_failed(type)) { |
287 | return 0; | 305 | r = SSH_ERR_AGENT_FAILURE; |
306 | goto out; | ||
288 | } else if (type != code2) { | 307 | } else if (type != code2) { |
289 | fatal("Bad authentication reply message type: %d", type); | 308 | r = SSH_ERR_INVALID_FORMAT; |
309 | goto out; | ||
290 | } | 310 | } |
291 | 311 | ||
292 | /* Get the number of entries in the response and check it for sanity. */ | 312 | /* Get the number of entries in the response and check it for sanity. */ |
293 | auth->howmany = buffer_get_int(&auth->identities); | 313 | if ((r = sshbuf_get_u32(msg, &num)) != 0) |
294 | if ((u_int)auth->howmany > 1024) | 314 | goto out; |
295 | fatal("Too many identities in authentication reply: %d", | 315 | if (num > MAX_AGENT_IDENTITIES) { |
296 | auth->howmany); | 316 | r = SSH_ERR_INVALID_FORMAT; |
297 | 317 | goto out; | |
298 | return auth->howmany; | 318 | } |
299 | } | 319 | if (num == 0) { |
300 | 320 | r = SSH_ERR_AGENT_NO_IDENTITIES; | |
301 | Key * | 321 | goto out; |
302 | ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version) | 322 | } |
303 | { | ||
304 | /* get number of identities and return the first entry (if any). */ | ||
305 | if (ssh_get_num_identities(auth, version) > 0) | ||
306 | return ssh_get_next_identity(auth, comment, version); | ||
307 | return NULL; | ||
308 | } | ||
309 | 323 | ||
310 | Key * | 324 | /* Deserialise the response into a list of keys/comments */ |
311 | ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version) | 325 | if ((idl = calloc(1, sizeof(*idl))) == NULL || |
312 | { | 326 | (idl->keys = calloc(num, sizeof(*idl->keys))) == NULL || |
327 | (idl->comments = calloc(num, sizeof(*idl->comments))) == NULL) { | ||
328 | r = SSH_ERR_ALLOC_FAIL; | ||
329 | goto out; | ||
330 | } | ||
331 | for (i = 0; i < num;) { | ||
332 | switch (version) { | ||
333 | case 1: | ||
313 | #ifdef WITH_SSH1 | 334 | #ifdef WITH_SSH1 |
314 | int keybits; | 335 | if ((r = deserialise_identity1(msg, |
315 | u_int bits; | 336 | &(idl->keys[i]), &(idl->comments[i]))) != 0) |
337 | goto out; | ||
316 | #endif | 338 | #endif |
317 | u_char *blob; | 339 | break; |
318 | u_int blen; | 340 | case 2: |
319 | Key *key = NULL; | 341 | if ((r = deserialise_identity2(msg, |
320 | 342 | &(idl->keys[i]), &(idl->comments[i]))) != 0) { | |
321 | /* Return failure if no more entries. */ | 343 | if (r == SSH_ERR_KEY_TYPE_UNKNOWN) { |
322 | if (auth->howmany <= 0) | 344 | /* Gracefully skip unknown key types */ |
323 | return NULL; | 345 | num--; |
346 | continue; | ||
347 | } else | ||
348 | goto out; | ||
349 | } | ||
350 | break; | ||
351 | } | ||
352 | i++; | ||
353 | } | ||
354 | idl->nkeys = num; | ||
355 | *idlp = idl; | ||
356 | idl = NULL; | ||
357 | r = 0; | ||
358 | out: | ||
359 | sshbuf_free(msg); | ||
360 | if (idl != NULL) | ||
361 | ssh_free_identitylist(idl); | ||
362 | return r; | ||
363 | } | ||
324 | 364 | ||
325 | /* | 365 | void |
326 | * Get the next entry from the packet. These will abort with a fatal | 366 | ssh_free_identitylist(struct ssh_identitylist *idl) |
327 | * error if the packet is too short or contains corrupt data. | 367 | { |
328 | */ | 368 | size_t i; |
329 | switch (version) { | 369 | |
330 | #ifdef WITH_SSH1 | 370 | if (idl == NULL) |
331 | case 1: | 371 | return; |
332 | key = key_new(KEY_RSA1); | 372 | for (i = 0; i < idl->nkeys; i++) { |
333 | bits = buffer_get_int(&auth->identities); | 373 | if (idl->keys != NULL) |
334 | buffer_get_bignum(&auth->identities, key->rsa->e); | 374 | sshkey_free(idl->keys[i]); |
335 | buffer_get_bignum(&auth->identities, key->rsa->n); | 375 | if (idl->comments != NULL) |
336 | *comment = buffer_get_string(&auth->identities, NULL); | 376 | free(idl->comments[i]); |
337 | keybits = BN_num_bits(key->rsa->n); | ||
338 | if (keybits < 0 || bits != (u_int)keybits) | ||
339 | logit("Warning: identity keysize mismatch: actual %d, announced %u", | ||
340 | BN_num_bits(key->rsa->n), bits); | ||
341 | break; | ||
342 | #endif | ||
343 | case 2: | ||
344 | blob = buffer_get_string(&auth->identities, &blen); | ||
345 | *comment = buffer_get_string(&auth->identities, NULL); | ||
346 | key = key_from_blob(blob, blen); | ||
347 | free(blob); | ||
348 | break; | ||
349 | default: | ||
350 | return NULL; | ||
351 | } | 377 | } |
352 | /* Decrement the number of remaining entries. */ | 378 | free(idl); |
353 | auth->howmany--; | ||
354 | return key; | ||
355 | } | 379 | } |
356 | 380 | ||
357 | /* | 381 | /* |
358 | * Generates a random challenge, sends it to the agent, and waits for | 382 | * Sends a challenge (typically from a server via ssh(1)) to the agent, |
359 | * response from the agent. Returns true (non-zero) if the agent gave the | 383 | * and waits for a response from the agent. |
360 | * correct answer, zero otherwise. Response type selects the style of | 384 | * Returns true (non-zero) if the agent gave the correct answer, zero |
361 | * response desired, with 0 corresponding to protocol version 1.0 (no longer | 385 | * otherwise. |
362 | * supported) and 1 corresponding to protocol version 1.1. | ||
363 | */ | 386 | */ |
364 | 387 | ||
365 | #ifdef WITH_SSH1 | 388 | #ifdef WITH_SSH1 |
366 | int | 389 | int |
367 | ssh_decrypt_challenge(AuthenticationConnection *auth, | 390 | ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge, |
368 | Key* key, BIGNUM *challenge, | 391 | u_char session_id[16], u_char response[16]) |
369 | u_char session_id[16], | ||
370 | u_int response_type, | ||
371 | u_char response[16]) | ||
372 | { | 392 | { |
373 | Buffer buffer; | 393 | struct sshbuf *msg; |
374 | int success = 0; | 394 | int r; |
375 | int i; | 395 | u_char type; |
376 | int type; | ||
377 | 396 | ||
378 | if (key->type != KEY_RSA1) | 397 | if (key->type != KEY_RSA1) |
379 | return 0; | 398 | return SSH_ERR_INVALID_ARGUMENT; |
380 | if (response_type == 0) { | 399 | if ((msg = sshbuf_new()) == NULL) |
381 | logit("Compatibility with ssh protocol version 1.0 no longer supported."); | 400 | return SSH_ERR_ALLOC_FAIL; |
382 | return 0; | 401 | if ((r = sshbuf_put_u8(msg, SSH_AGENTC_RSA_CHALLENGE)) != 0 || |
383 | } | 402 | (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 || |
384 | buffer_init(&buffer); | 403 | (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 || |
385 | buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE); | 404 | (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0 || |
386 | buffer_put_int(&buffer, BN_num_bits(key->rsa->n)); | 405 | (r = sshbuf_put_bignum1(msg, challenge)) != 0 || |
387 | buffer_put_bignum(&buffer, key->rsa->e); | 406 | (r = sshbuf_put(msg, session_id, 16)) != 0 || |
388 | buffer_put_bignum(&buffer, key->rsa->n); | 407 | (r = sshbuf_put_u32(msg, 1)) != 0) /* Response type for proto 1.1 */ |
389 | buffer_put_bignum(&buffer, challenge); | 408 | goto out; |
390 | buffer_append(&buffer, session_id, 16); | 409 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
391 | buffer_put_int(&buffer, response_type); | 410 | goto out; |
392 | 411 | if ((r = sshbuf_get_u8(msg, &type)) != 0) | |
393 | if (ssh_request_reply(auth, &buffer, &buffer) == 0) { | 412 | goto out; |
394 | buffer_free(&buffer); | ||
395 | return 0; | ||
396 | } | ||
397 | type = buffer_get_char(&buffer); | ||
398 | |||
399 | if (agent_failed(type)) { | 413 | if (agent_failed(type)) { |
400 | logit("Agent admitted failure to authenticate using the key."); | 414 | r = SSH_ERR_AGENT_FAILURE; |
415 | goto out; | ||
401 | } else if (type != SSH_AGENT_RSA_RESPONSE) { | 416 | } else if (type != SSH_AGENT_RSA_RESPONSE) { |
402 | fatal("Bad authentication response: %d", type); | 417 | r = SSH_ERR_INVALID_FORMAT; |
403 | } else { | 418 | goto out; |
404 | success = 1; | ||
405 | /* | ||
406 | * Get the response from the packet. This will abort with a | ||
407 | * fatal error if the packet is corrupt. | ||
408 | */ | ||
409 | for (i = 0; i < 16; i++) | ||
410 | response[i] = (u_char)buffer_get_char(&buffer); | ||
411 | } | 419 | } |
412 | buffer_free(&buffer); | 420 | if ((r = sshbuf_get(msg, response, 16)) != 0) |
413 | return success; | 421 | goto out; |
422 | r = 0; | ||
423 | out: | ||
424 | sshbuf_free(msg); | ||
425 | return r; | ||
414 | } | 426 | } |
415 | #endif | 427 | #endif |
416 | 428 | ||
417 | /* ask agent to sign data, returns -1 on error, 0 on success */ | 429 | /* ask agent to sign data, returns err.h code on error, 0 on success */ |
418 | int | 430 | int |
419 | ssh_agent_sign(AuthenticationConnection *auth, | 431 | ssh_agent_sign(int sock, struct sshkey *key, |
420 | Key *key, | 432 | u_char **sigp, size_t *lenp, |
421 | u_char **sigp, u_int *lenp, | 433 | const u_char *data, size_t datalen, u_int compat) |
422 | u_char *data, u_int datalen) | ||
423 | { | 434 | { |
424 | extern int datafellows; | 435 | struct sshbuf *msg; |
425 | Buffer msg; | 436 | u_char *blob = NULL, type; |
426 | u_char *blob; | 437 | size_t blen = 0, len = 0; |
427 | u_int blen; | 438 | u_int flags = 0; |
428 | int type, flags = 0; | 439 | int r = SSH_ERR_INTERNAL_ERROR; |
429 | int ret = -1; | 440 | |
430 | 441 | if (sigp != NULL) | |
431 | if (key_to_blob(key, &blob, &blen) == 0) | 442 | *sigp = NULL; |
432 | return -1; | 443 | if (lenp != NULL) |
433 | 444 | *lenp = 0; | |
434 | if (datafellows & SSH_BUG_SIGBLOB) | 445 | |
435 | flags = SSH_AGENT_OLD_SIGNATURE; | 446 | if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) |
436 | 447 | return SSH_ERR_INVALID_ARGUMENT; | |
437 | buffer_init(&msg); | 448 | if (compat & SSH_BUG_SIGBLOB) |
438 | buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); | 449 | flags |= SSH_AGENT_OLD_SIGNATURE; |
439 | buffer_put_string(&msg, blob, blen); | 450 | if ((msg = sshbuf_new()) == NULL) |
440 | buffer_put_string(&msg, data, datalen); | 451 | return SSH_ERR_ALLOC_FAIL; |
441 | buffer_put_int(&msg, flags); | 452 | if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) |
442 | free(blob); | 453 | goto out; |
443 | 454 | if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || | |
444 | if (ssh_request_reply(auth, &msg, &msg) == 0) { | 455 | (r = sshbuf_put_string(msg, blob, blen)) != 0 || |
445 | buffer_free(&msg); | 456 | (r = sshbuf_put_string(msg, data, datalen)) != 0 || |
446 | return -1; | 457 | (r = sshbuf_put_u32(msg, flags)) != 0) |
447 | } | 458 | goto out; |
448 | type = buffer_get_char(&msg); | 459 | if ((r = ssh_request_reply(sock, msg, msg) != 0)) |
460 | goto out; | ||
461 | if ((r = sshbuf_get_u8(msg, &type)) != 0) | ||
462 | goto out; | ||
449 | if (agent_failed(type)) { | 463 | if (agent_failed(type)) { |
450 | logit("Agent admitted failure to sign using the key."); | 464 | r = SSH_ERR_AGENT_FAILURE; |
465 | goto out; | ||
451 | } else if (type != SSH2_AGENT_SIGN_RESPONSE) { | 466 | } else if (type != SSH2_AGENT_SIGN_RESPONSE) { |
452 | fatal("Bad authentication response: %d", type); | 467 | r = SSH_ERR_INVALID_FORMAT; |
453 | } else { | 468 | goto out; |
454 | ret = 0; | 469 | } |
455 | *sigp = buffer_get_string(&msg, lenp); | 470 | if ((r = sshbuf_get_string(msg, sigp, &len)) != 0) |
471 | goto out; | ||
472 | *lenp = len; | ||
473 | r = 0; | ||
474 | out: | ||
475 | if (blob != NULL) { | ||
476 | explicit_bzero(blob, blen); | ||
477 | free(blob); | ||
456 | } | 478 | } |
457 | buffer_free(&msg); | 479 | sshbuf_free(msg); |
458 | return ret; | 480 | return r; |
459 | } | 481 | } |
460 | 482 | ||
461 | /* Encode key for a message to the agent. */ | 483 | /* Encode key for a message to the agent. */ |
462 | 484 | ||
463 | #ifdef WITH_SSH1 | 485 | #ifdef WITH_SSH1 |
464 | static void | 486 | static int |
465 | ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment) | 487 | ssh_encode_identity_rsa1(struct sshbuf *b, RSA *key, const char *comment) |
466 | { | 488 | { |
467 | buffer_put_int(b, BN_num_bits(key->n)); | 489 | int r; |
468 | buffer_put_bignum(b, key->n); | 490 | |
469 | buffer_put_bignum(b, key->e); | ||
470 | buffer_put_bignum(b, key->d); | ||
471 | /* To keep within the protocol: p < q for ssh. in SSL p > q */ | 491 | /* To keep within the protocol: p < q for ssh. in SSL p > q */ |
472 | buffer_put_bignum(b, key->iqmp); /* ssh key->u */ | 492 | if ((r = sshbuf_put_u32(b, BN_num_bits(key->n))) != 0 || |
473 | buffer_put_bignum(b, key->q); /* ssh key->p, SSL key->q */ | 493 | (r = sshbuf_put_bignum1(b, key->n)) != 0 || |
474 | buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */ | 494 | (r = sshbuf_put_bignum1(b, key->e)) != 0 || |
475 | buffer_put_cstring(b, comment); | 495 | (r = sshbuf_put_bignum1(b, key->d)) != 0 || |
496 | (r = sshbuf_put_bignum1(b, key->iqmp)) != 0 || | ||
497 | (r = sshbuf_put_bignum1(b, key->q)) != 0 || | ||
498 | (r = sshbuf_put_bignum1(b, key->p)) != 0 || | ||
499 | (r = sshbuf_put_cstring(b, comment)) != 0) | ||
500 | return r; | ||
501 | return 0; | ||
476 | } | 502 | } |
477 | #endif | 503 | #endif |
478 | 504 | ||
479 | static void | 505 | static int |
480 | ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) | 506 | ssh_encode_identity_ssh2(struct sshbuf *b, struct sshkey *key, |
507 | const char *comment) | ||
508 | { | ||
509 | int r; | ||
510 | |||
511 | if ((r = sshkey_private_serialize(key, b)) != 0 || | ||
512 | (r = sshbuf_put_cstring(b, comment)) != 0) | ||
513 | return r; | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static int | ||
518 | encode_constraints(struct sshbuf *m, u_int life, u_int confirm) | ||
481 | { | 519 | { |
482 | key_private_serialize(key, b); | 520 | int r; |
483 | buffer_put_cstring(b, comment); | 521 | |
522 | if (life != 0) { | ||
523 | if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_LIFETIME)) != 0 || | ||
524 | (r = sshbuf_put_u32(m, life)) != 0) | ||
525 | goto out; | ||
526 | } | ||
527 | if (confirm != 0) { | ||
528 | if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0) | ||
529 | goto out; | ||
530 | } | ||
531 | r = 0; | ||
532 | out: | ||
533 | return r; | ||
484 | } | 534 | } |
485 | 535 | ||
486 | /* | 536 | /* |
487 | * Adds an identity to the authentication server. This call is not meant to | 537 | * Adds an identity to the authentication server. |
488 | * be used by normal applications. | 538 | * This call is intended only for use by ssh-add(1) and like applications. |
489 | */ | 539 | */ |
490 | |||
491 | int | 540 | int |
492 | ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, | 541 | ssh_add_identity_constrained(int sock, struct sshkey *key, const char *comment, |
493 | const char *comment, u_int life, u_int confirm) | 542 | u_int life, u_int confirm) |
494 | { | 543 | { |
495 | Buffer msg; | 544 | struct sshbuf *msg; |
496 | int type, constrained = (life || confirm); | 545 | int r, constrained = (life || confirm); |
546 | u_char type; | ||
497 | 547 | ||
498 | buffer_init(&msg); | 548 | if ((msg = sshbuf_new()) == NULL) |
549 | return SSH_ERR_ALLOC_FAIL; | ||
499 | 550 | ||
500 | switch (key->type) { | 551 | switch (key->type) { |
501 | #ifdef WITH_SSH1 | 552 | #ifdef WITH_SSH1 |
@@ -503,8 +554,9 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, | |||
503 | type = constrained ? | 554 | type = constrained ? |
504 | SSH_AGENTC_ADD_RSA_ID_CONSTRAINED : | 555 | SSH_AGENTC_ADD_RSA_ID_CONSTRAINED : |
505 | SSH_AGENTC_ADD_RSA_IDENTITY; | 556 | SSH_AGENTC_ADD_RSA_IDENTITY; |
506 | buffer_put_char(&msg, type); | 557 | if ((r = sshbuf_put_u8(msg, type)) != 0 || |
507 | ssh_encode_identity_rsa1(&msg, key->rsa, comment); | 558 | (r = ssh_encode_identity_rsa1(msg, key->rsa, comment)) != 0) |
559 | goto out; | ||
508 | break; | 560 | break; |
509 | #endif | 561 | #endif |
510 | #ifdef WITH_OPENSSL | 562 | #ifdef WITH_OPENSSL |
@@ -522,77 +574,88 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, | |||
522 | type = constrained ? | 574 | type = constrained ? |
523 | SSH2_AGENTC_ADD_ID_CONSTRAINED : | 575 | SSH2_AGENTC_ADD_ID_CONSTRAINED : |
524 | SSH2_AGENTC_ADD_IDENTITY; | 576 | SSH2_AGENTC_ADD_IDENTITY; |
525 | buffer_put_char(&msg, type); | 577 | if ((r = sshbuf_put_u8(msg, type)) != 0 || |
526 | ssh_encode_identity_ssh2(&msg, key, comment); | 578 | (r = ssh_encode_identity_ssh2(msg, key, comment)) != 0) |
579 | goto out; | ||
527 | break; | 580 | break; |
528 | default: | 581 | default: |
529 | buffer_free(&msg); | 582 | r = SSH_ERR_INVALID_ARGUMENT; |
530 | return 0; | 583 | goto out; |
531 | } | ||
532 | if (constrained) { | ||
533 | if (life != 0) { | ||
534 | buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME); | ||
535 | buffer_put_int(&msg, life); | ||
536 | } | ||
537 | if (confirm != 0) | ||
538 | buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM); | ||
539 | } | 584 | } |
540 | if (ssh_request_reply(auth, &msg, &msg) == 0) { | 585 | if (constrained && |
541 | buffer_free(&msg); | 586 | (r = encode_constraints(msg, life, confirm)) != 0) |
542 | return 0; | 587 | goto out; |
543 | } | 588 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
544 | type = buffer_get_char(&msg); | 589 | goto out; |
545 | buffer_free(&msg); | 590 | if ((r = sshbuf_get_u8(msg, &type)) != 0) |
546 | return decode_reply(type); | 591 | goto out; |
592 | r = decode_reply(type); | ||
593 | out: | ||
594 | sshbuf_free(msg); | ||
595 | return r; | ||
547 | } | 596 | } |
548 | 597 | ||
549 | /* | 598 | /* |
550 | * Removes an identity from the authentication server. This call is not | 599 | * Removes an identity from the authentication server. |
551 | * meant to be used by normal applications. | 600 | * This call is intended only for use by ssh-add(1) and like applications. |
552 | */ | 601 | */ |
553 | |||
554 | int | 602 | int |
555 | ssh_remove_identity(AuthenticationConnection *auth, Key *key) | 603 | ssh_remove_identity(int sock, struct sshkey *key) |
556 | { | 604 | { |
557 | Buffer msg; | 605 | struct sshbuf *msg; |
558 | int type; | 606 | int r; |
559 | u_char *blob; | 607 | u_char type, *blob = NULL; |
560 | u_int blen; | 608 | size_t blen; |
561 | 609 | ||
562 | buffer_init(&msg); | 610 | if ((msg = sshbuf_new()) == NULL) |
611 | return SSH_ERR_ALLOC_FAIL; | ||
563 | 612 | ||
564 | #ifdef WITH_SSH1 | 613 | #ifdef WITH_SSH1 |
565 | if (key->type == KEY_RSA1) { | 614 | if (key->type == KEY_RSA1) { |
566 | buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY); | 615 | if ((r = sshbuf_put_u8(msg, |
567 | buffer_put_int(&msg, BN_num_bits(key->rsa->n)); | 616 | SSH_AGENTC_REMOVE_RSA_IDENTITY)) != 0 || |
568 | buffer_put_bignum(&msg, key->rsa->e); | 617 | (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 || |
569 | buffer_put_bignum(&msg, key->rsa->n); | 618 | (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 || |
619 | (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0) | ||
620 | goto out; | ||
570 | } else | 621 | } else |
571 | #endif | 622 | #endif |
572 | if (key->type != KEY_UNSPEC) { | 623 | if (key->type != KEY_UNSPEC) { |
573 | key_to_blob(key, &blob, &blen); | 624 | if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) |
574 | buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); | 625 | goto out; |
575 | buffer_put_string(&msg, blob, blen); | 626 | if ((r = sshbuf_put_u8(msg, |
576 | free(blob); | 627 | SSH2_AGENTC_REMOVE_IDENTITY)) != 0 || |
628 | (r = sshbuf_put_string(msg, blob, blen)) != 0) | ||
629 | goto out; | ||
577 | } else { | 630 | } else { |
578 | buffer_free(&msg); | 631 | r = SSH_ERR_INVALID_ARGUMENT; |
579 | return 0; | 632 | goto out; |
580 | } | 633 | } |
581 | if (ssh_request_reply(auth, &msg, &msg) == 0) { | 634 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
582 | buffer_free(&msg); | 635 | goto out; |
583 | return 0; | 636 | if ((r = sshbuf_get_u8(msg, &type)) != 0) |
637 | goto out; | ||
638 | r = decode_reply(type); | ||
639 | out: | ||
640 | if (blob != NULL) { | ||
641 | explicit_bzero(blob, blen); | ||
642 | free(blob); | ||
584 | } | 643 | } |
585 | type = buffer_get_char(&msg); | 644 | sshbuf_free(msg); |
586 | buffer_free(&msg); | 645 | return r; |
587 | return decode_reply(type); | ||
588 | } | 646 | } |
589 | 647 | ||
648 | /* | ||
649 | * Add/remove an token-based identity from the authentication server. | ||
650 | * This call is intended only for use by ssh-add(1) and like applications. | ||
651 | */ | ||
590 | int | 652 | int |
591 | ssh_update_card(AuthenticationConnection *auth, int add, | 653 | ssh_update_card(int sock, int add, const char *reader_id, const char *pin, |
592 | const char *reader_id, const char *pin, u_int life, u_int confirm) | 654 | u_int life, u_int confirm) |
593 | { | 655 | { |
594 | Buffer msg; | 656 | struct sshbuf *msg; |
595 | int type, constrained = (life || confirm); | 657 | int r, constrained = (life || confirm); |
658 | u_char type; | ||
596 | 659 | ||
597 | if (add) { | 660 | if (add) { |
598 | type = constrained ? | 661 | type = constrained ? |
@@ -601,69 +664,48 @@ ssh_update_card(AuthenticationConnection *auth, int add, | |||
601 | } else | 664 | } else |
602 | type = SSH_AGENTC_REMOVE_SMARTCARD_KEY; | 665 | type = SSH_AGENTC_REMOVE_SMARTCARD_KEY; |
603 | 666 | ||
604 | buffer_init(&msg); | 667 | if ((msg = sshbuf_new()) == NULL) |
605 | buffer_put_char(&msg, type); | 668 | return SSH_ERR_ALLOC_FAIL; |
606 | buffer_put_cstring(&msg, reader_id); | 669 | if ((r = sshbuf_put_u8(msg, type)) != 0 || |
607 | buffer_put_cstring(&msg, pin); | 670 | (r = sshbuf_put_cstring(msg, reader_id)) != 0 || |
608 | 671 | (r = sshbuf_put_cstring(msg, pin)) != 0) | |
609 | if (constrained) { | 672 | goto out; |
610 | if (life != 0) { | 673 | if (constrained && |
611 | buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME); | 674 | (r = encode_constraints(msg, life, confirm)) != 0) |
612 | buffer_put_int(&msg, life); | 675 | goto out; |
613 | } | 676 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
614 | if (confirm != 0) | 677 | goto out; |
615 | buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM); | 678 | if ((r = sshbuf_get_u8(msg, &type)) != 0) |
616 | } | 679 | goto out; |
617 | 680 | r = decode_reply(type); | |
618 | if (ssh_request_reply(auth, &msg, &msg) == 0) { | 681 | out: |
619 | buffer_free(&msg); | 682 | sshbuf_free(msg); |
620 | return 0; | 683 | return r; |
621 | } | ||
622 | type = buffer_get_char(&msg); | ||
623 | buffer_free(&msg); | ||
624 | return decode_reply(type); | ||
625 | } | 684 | } |
626 | 685 | ||
627 | /* | 686 | /* |
628 | * Removes all identities from the agent. This call is not meant to be used | 687 | * Removes all identities from the agent. |
629 | * by normal applications. | 688 | * This call is intended only for use by ssh-add(1) and like applications. |
630 | */ | 689 | */ |
631 | |||
632 | int | ||
633 | ssh_remove_all_identities(AuthenticationConnection *auth, int version) | ||
634 | { | ||
635 | Buffer msg; | ||
636 | int type; | ||
637 | int code = (version==1) ? | ||
638 | SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES : | ||
639 | SSH2_AGENTC_REMOVE_ALL_IDENTITIES; | ||
640 | |||
641 | buffer_init(&msg); | ||
642 | buffer_put_char(&msg, code); | ||
643 | |||
644 | if (ssh_request_reply(auth, &msg, &msg) == 0) { | ||
645 | buffer_free(&msg); | ||
646 | return 0; | ||
647 | } | ||
648 | type = buffer_get_char(&msg); | ||
649 | buffer_free(&msg); | ||
650 | return decode_reply(type); | ||
651 | } | ||
652 | |||
653 | int | 690 | int |
654 | decode_reply(int type) | 691 | ssh_remove_all_identities(int sock, int version) |
655 | { | 692 | { |
656 | switch (type) { | 693 | struct sshbuf *msg; |
657 | case SSH_AGENT_FAILURE: | 694 | u_char type = (version == 1) ? |
658 | case SSH_COM_AGENT2_FAILURE: | 695 | SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES : |
659 | case SSH2_AGENT_FAILURE: | 696 | SSH2_AGENTC_REMOVE_ALL_IDENTITIES; |
660 | logit("SSH_AGENT_FAILURE"); | 697 | int r; |
661 | return 0; | 698 | |
662 | case SSH_AGENT_SUCCESS: | 699 | if ((msg = sshbuf_new()) == NULL) |
663 | return 1; | 700 | return SSH_ERR_ALLOC_FAIL; |
664 | default: | 701 | if ((r = sshbuf_put_u8(msg, type)) != 0) |
665 | fatal("Bad response from authentication agent: %d", type); | 702 | goto out; |
666 | } | 703 | if ((r = ssh_request_reply(sock, msg, msg)) != 0) |
667 | /* NOTREACHED */ | 704 | goto out; |
668 | return 0; | 705 | if ((r = sshbuf_get_u8(msg, &type)) != 0) |
706 | goto out; | ||
707 | r = decode_reply(type); | ||
708 | out: | ||
709 | sshbuf_free(msg); | ||
710 | return r; | ||
669 | } | 711 | } |