]> andersk Git - openssh.git/blame - authfd.c
bad checkin mode
[openssh.git] / authfd.c
CommitLineData
8efc0c15 1/*
6ae2364d 2 *
5260325f 3 * authfd.c
6ae2364d 4 *
5260325f 5 * Author: Tatu Ylonen <ylo@cs.hut.fi>
6ae2364d 6 *
5260325f 7 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 * All rights reserved
6ae2364d 9 *
5260325f 10 * Created: Wed Mar 29 01:30:28 1995 ylo
6ae2364d 11 *
5260325f 12 * Functions for connecting the local authentication agent.
6ae2364d 13 *
5260325f 14 */
8efc0c15 15
16#include "includes.h"
17RCSID("$Id$");
18
19#include "ssh.h"
20#include "rsa.h"
21#include "authfd.h"
22#include "buffer.h"
23#include "bufaux.h"
24#include "xmalloc.h"
25#include "getput.h"
26
27#include <openssl/rsa.h>
28
29/* Returns the number of the authentication fd, or -1 if there is none. */
30
31int
32ssh_get_authentication_socket()
33{
5260325f 34 const char *authsocket;
35 int sock;
36 struct sockaddr_un sunaddr;
37
38 authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
39 if (!authsocket)
40 return -1;
41
42 sunaddr.sun_family = AF_UNIX;
43 strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
44
45 sock = socket(AF_UNIX, SOCK_STREAM, 0);
46 if (sock < 0)
47 return -1;
48
49 /* close on exec */
50 if (fcntl(sock, F_SETFD, 1) == -1) {
51 close(sock);
52 return -1;
53 }
54 if (connect(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
55 close(sock);
56 return -1;
57 }
58 return sock;
8efc0c15 59}
60
aa3378df 61/*
62 * Closes the agent socket if it should be closed (depends on how it was
63 * obtained). The argument must have been returned by
64 * ssh_get_authentication_socket().
65 */
8efc0c15 66
6ae2364d 67void
5260325f 68ssh_close_authentication_socket(int sock)
8efc0c15 69{
5260325f 70 if (getenv(SSH_AUTHSOCKET_ENV_NAME))
71 close(sock);
8efc0c15 72}
73
aa3378df 74/*
75 * Opens and connects a private socket for communication with the
76 * authentication agent. Returns the file descriptor (which must be
77 * shut down and closed by the caller when no longer needed).
78 * Returns NULL if an error occurred and the connection could not be
79 * opened.
80 */
8efc0c15 81
5260325f 82AuthenticationConnection *
83ssh_get_authentication_connection()
8efc0c15 84{
5260325f 85 AuthenticationConnection *auth;
86 int sock;
87
88 sock = ssh_get_authentication_socket();
89
aa3378df 90 /*
91 * Fail if we couldn't obtain a connection. This happens if we
92 * exited due to a timeout.
93 */
5260325f 94 if (sock < 0)
95 return NULL;
96
5260325f 97 auth = xmalloc(sizeof(*auth));
98 auth->fd = sock;
99 buffer_init(&auth->packet);
100 buffer_init(&auth->identities);
101 auth->howmany = 0;
102
103 return auth;
8efc0c15 104}
105
aa3378df 106/*
107 * Closes the connection to the authentication agent and frees any associated
108 * memory.
109 */
8efc0c15 110
6ae2364d 111void
5260325f 112ssh_close_authentication_connection(AuthenticationConnection *ac)
8efc0c15 113{
5260325f 114 buffer_free(&ac->packet);
115 buffer_free(&ac->identities);
116 close(ac->fd);
117 xfree(ac);
8efc0c15 118}
119
aa3378df 120/*
121 * Returns the first authentication identity held by the agent.
122 * Returns true if an identity is available, 0 otherwise.
123 * The caller must initialize the integers before the call, and free the
124 * comment after a successful call (before calling ssh_get_next_identity).
125 */
8efc0c15 126
127int
128ssh_get_first_identity(AuthenticationConnection *auth,
4d195447 129 BIGNUM *e, BIGNUM *n, char **comment)
8efc0c15 130{
5260325f 131 unsigned char msg[8192];
132 int len, l;
133
aa3378df 134 /*
135 * Send a message to the agent requesting for a list of the
136 * identities it can represent.
137 */
5260325f 138 msg[0] = 0;
139 msg[1] = 0;
140 msg[2] = 0;
141 msg[3] = 1;
142 msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
a408af76 143 if (atomicio(write, auth->fd, msg, 5) != 5) {
5260325f 144 error("write auth->fd: %.100s", strerror(errno));
145 return 0;
146 }
147 /* Read the length of the response. XXX implement timeouts here. */
148 len = 4;
149 while (len > 0) {
150 l = read(auth->fd, msg + 4 - len, len);
151 if (l <= 0) {
152 error("read auth->fd: %.100s", strerror(errno));
153 return 0;
154 }
155 len -= l;
156 }
157
aa3378df 158 /*
159 * Extract the length, and check it for sanity. (We cannot trust
160 * authentication agents).
161 */
5260325f 162 len = GET_32BIT(msg);
163 if (len < 1 || len > 256 * 1024)
164 fatal("Authentication reply message too long: %d\n", len);
165
166 /* Read the packet itself. */
167 buffer_clear(&auth->identities);
168 while (len > 0) {
169 l = len;
170 if (l > sizeof(msg))
171 l = sizeof(msg);
172 l = read(auth->fd, msg, l);
173 if (l <= 0)
174 fatal("Incomplete authentication reply.");
175 buffer_append(&auth->identities, (char *) msg, l);
176 len -= l;
8efc0c15 177 }
5260325f 178
179 /* Get message type, and verify that we got a proper answer. */
180 buffer_get(&auth->identities, (char *) msg, 1);
181 if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
182 fatal("Bad authentication reply message type: %d", msg[0]);
183
184 /* Get the number of entries in the response and check it for sanity. */
185 auth->howmany = buffer_get_int(&auth->identities);
186 if (auth->howmany > 1024)
187 fatal("Too many identities in authentication reply: %d\n", auth->howmany);
188
189 /* Return the first entry (if any). */
190 return ssh_get_next_identity(auth, e, n, comment);
8efc0c15 191}
192
aa3378df 193/*
194 * Returns the next authentication identity for the agent. Other functions
195 * can be called between this and ssh_get_first_identity or two calls of this
196 * function. This returns 0 if there are no more identities. The caller
197 * must free comment after a successful return.
198 */
8efc0c15 199
200int
201ssh_get_next_identity(AuthenticationConnection *auth,
4d195447 202 BIGNUM *e, BIGNUM *n, char **comment)
8efc0c15 203{
5260325f 204 unsigned int bits;
4d195447 205
5260325f 206 /* Return failure if no more entries. */
207 if (auth->howmany <= 0)
208 return 0;
8efc0c15 209
aa3378df 210 /*
211 * Get the next entry from the packet. These will abort with a fatal
212 * error if the packet is too short or contains corrupt data.
213 */
5260325f 214 bits = buffer_get_int(&auth->identities);
215 buffer_get_bignum(&auth->identities, e);
216 buffer_get_bignum(&auth->identities, n);
217 *comment = buffer_get_string(&auth->identities, NULL);
8efc0c15 218
5260325f 219 if (bits != BN_num_bits(n))
0b242b12 220 log("Warning: identity keysize mismatch: actual %d, announced %u",
221 BN_num_bits(n), bits);
4d195447 222
5260325f 223 /* Decrement the number of remaining entries. */
224 auth->howmany--;
8efc0c15 225
5260325f 226 return 1;
8efc0c15 227}
228
aa3378df 229/*
230 * Generates a random challenge, sends it to the agent, and waits for
231 * response from the agent. Returns true (non-zero) if the agent gave the
232 * correct answer, zero otherwise. Response type selects the style of
233 * response desired, with 0 corresponding to protocol version 1.0 (no longer
234 * supported) and 1 corresponding to protocol version 1.1.
235 */
8efc0c15 236
237int
238ssh_decrypt_challenge(AuthenticationConnection *auth,
5260325f 239 BIGNUM* e, BIGNUM *n, BIGNUM *challenge,
8efc0c15 240 unsigned char session_id[16],
241 unsigned int response_type,
242 unsigned char response[16])
243{
5260325f 244 Buffer buffer;
245 unsigned char buf[8192];
246 int len, l, i;
247
248 /* Response type 0 is no longer supported. */
249 if (response_type == 0)
250 fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
251
252 /* Format a message to the agent. */
253 buf[0] = SSH_AGENTC_RSA_CHALLENGE;
254 buffer_init(&buffer);
255 buffer_append(&buffer, (char *) buf, 1);
256 buffer_put_int(&buffer, BN_num_bits(n));
257 buffer_put_bignum(&buffer, e);
258 buffer_put_bignum(&buffer, n);
259 buffer_put_bignum(&buffer, challenge);
260 buffer_append(&buffer, (char *) session_id, 16);
261 buffer_put_int(&buffer, response_type);
262
263 /* Get the length of the message, and format it in the buffer. */
264 len = buffer_len(&buffer);
265 PUT_32BIT(buf, len);
266
267 /* Send the length and then the packet to the agent. */
a408af76 268 if (atomicio(write, auth->fd, buf, 4) != 4 ||
269 atomicio(write, auth->fd, buffer_ptr(&buffer),
270 buffer_len(&buffer)) != buffer_len(&buffer)) {
5260325f 271 error("Error writing to authentication socket.");
272error_cleanup:
273 buffer_free(&buffer);
274 return 0;
275 }
aa3378df 276 /*
277 * Wait for response from the agent. First read the length of the
278 * response packet.
279 */
5260325f 280 len = 4;
281 while (len > 0) {
282 l = read(auth->fd, buf + 4 - len, len);
283 if (l <= 0) {
284 error("Error reading response length from authentication socket.");
285 goto error_cleanup;
286 }
287 len -= l;
288 }
289
290 /* Extract the length, and check it for sanity. */
291 len = GET_32BIT(buf);
292 if (len > 256 * 1024)
293 fatal("Authentication response too long: %d", len);
294
295 /* Read the rest of the response in tothe buffer. */
296 buffer_clear(&buffer);
297 while (len > 0) {
298 l = len;
299 if (l > sizeof(buf))
300 l = sizeof(buf);
301 l = read(auth->fd, buf, l);
302 if (l <= 0) {
303 error("Error reading response from authentication socket.");
304 goto error_cleanup;
305 }
306 buffer_append(&buffer, (char *) buf, l);
307 len -= l;
8efc0c15 308 }
5260325f 309
310 /* Get the type of the packet. */
311 buffer_get(&buffer, (char *) buf, 1);
312
313 /* Check for agent failure message. */
314 if (buf[0] == SSH_AGENT_FAILURE) {
315 log("Agent admitted failure to authenticate using the key.");
316 goto error_cleanup;
8efc0c15 317 }
5260325f 318 /* Now it must be an authentication response packet. */
319 if (buf[0] != SSH_AGENT_RSA_RESPONSE)
320 fatal("Bad authentication response: %d", buf[0]);
321
aa3378df 322 /*
323 * Get the response from the packet. This will abort with a fatal
324 * error if the packet is corrupt.
325 */
5260325f 326 for (i = 0; i < 16; i++)
327 response[i] = buffer_get_char(&buffer);
328
329 /* The buffer containing the packet is no longer needed. */
330 buffer_free(&buffer);
331
332 /* Correct answer. */
333 return 1;
334}
8efc0c15 335
aa3378df 336/*
337 * Adds an identity to the authentication server. This call is not meant to
338 * be used by normal applications.
339 */
8efc0c15 340
6ae2364d 341int
5260325f 342ssh_add_identity(AuthenticationConnection *auth,
343 RSA * key, const char *comment)
8efc0c15 344{
5260325f 345 Buffer buffer;
346 unsigned char buf[8192];
347 int len, l, type;
348
349 /* Format a message to the agent. */
350 buffer_init(&buffer);
351 buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
352 buffer_put_int(&buffer, BN_num_bits(key->n));
353 buffer_put_bignum(&buffer, key->n);
354 buffer_put_bignum(&buffer, key->e);
355 buffer_put_bignum(&buffer, key->d);
356 /* To keep within the protocol: p < q for ssh. in SSL p > q */
357 buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
358 buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
359 buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
360 buffer_put_string(&buffer, comment, strlen(comment));
361
362 /* Get the length of the message, and format it in the buffer. */
363 len = buffer_len(&buffer);
364 PUT_32BIT(buf, len);
365
366 /* Send the length and then the packet to the agent. */
a408af76 367 if (atomicio(write, auth->fd, buf, 4) != 4 ||
368 atomicio(write, auth->fd, buffer_ptr(&buffer),
369 buffer_len(&buffer)) != buffer_len(&buffer)) {
5260325f 370 error("Error writing to authentication socket.");
371error_cleanup:
372 buffer_free(&buffer);
373 return 0;
374 }
375 /* Wait for response from the agent. First read the length of the
376 response packet. */
377 len = 4;
378 while (len > 0) {
379 l = read(auth->fd, buf + 4 - len, len);
380 if (l <= 0) {
381 error("Error reading response length from authentication socket.");
382 goto error_cleanup;
383 }
384 len -= l;
385 }
386
387 /* Extract the length, and check it for sanity. */
388 len = GET_32BIT(buf);
389 if (len > 256 * 1024)
390 fatal("Add identity response too long: %d", len);
391
392 /* Read the rest of the response in tothe buffer. */
393 buffer_clear(&buffer);
394 while (len > 0) {
395 l = len;
396 if (l > sizeof(buf))
397 l = sizeof(buf);
398 l = read(auth->fd, buf, l);
399 if (l <= 0) {
400 error("Error reading response from authentication socket.");
401 goto error_cleanup;
402 }
403 buffer_append(&buffer, (char *) buf, l);
404 len -= l;
8efc0c15 405 }
5260325f 406
407 /* Get the type of the packet. */
408 type = buffer_get_char(&buffer);
409 switch (type) {
410 case SSH_AGENT_FAILURE:
411 buffer_free(&buffer);
412 return 0;
413 case SSH_AGENT_SUCCESS:
414 buffer_free(&buffer);
415 return 1;
416 default:
417 fatal("Bad response to add identity from authentication agent: %d",
418 type);
8efc0c15 419 }
5260325f 420 /* NOTREACHED */
421 return 0;
422}
423
aa3378df 424/*
425 * Removes an identity from the authentication server. This call is not
426 * meant to be used by normal applications.
427 */
8efc0c15 428
6ae2364d 429int
5260325f 430ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
8efc0c15 431{
5260325f 432 Buffer buffer;
433 unsigned char buf[8192];
434 int len, l, type;
435
436 /* Format a message to the agent. */
437 buffer_init(&buffer);
438 buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
439 buffer_put_int(&buffer, BN_num_bits(key->n));
440 buffer_put_bignum(&buffer, key->e);
441 buffer_put_bignum(&buffer, key->n);
442
443 /* Get the length of the message, and format it in the buffer. */
444 len = buffer_len(&buffer);
445 PUT_32BIT(buf, len);
446
447 /* Send the length and then the packet to the agent. */
a408af76 448 if (atomicio(write, auth->fd, buf, 4) != 4 ||
449 atomicio(write, auth->fd, buffer_ptr(&buffer),
450 buffer_len(&buffer)) != buffer_len(&buffer)) {
5260325f 451 error("Error writing to authentication socket.");
452error_cleanup:
453 buffer_free(&buffer);
454 return 0;
455 }
aa3378df 456 /*
457 * Wait for response from the agent. First read the length of the
458 * response packet.
459 */
5260325f 460 len = 4;
461 while (len > 0) {
462 l = read(auth->fd, buf + 4 - len, len);
463 if (l <= 0) {
464 error("Error reading response length from authentication socket.");
465 goto error_cleanup;
466 }
467 len -= l;
468 }
469
470 /* Extract the length, and check it for sanity. */
471 len = GET_32BIT(buf);
472 if (len > 256 * 1024)
473 fatal("Remove identity response too long: %d", len);
474
475 /* Read the rest of the response in tothe buffer. */
476 buffer_clear(&buffer);
477 while (len > 0) {
478 l = len;
479 if (l > sizeof(buf))
480 l = sizeof(buf);
481 l = read(auth->fd, buf, l);
482 if (l <= 0) {
483 error("Error reading response from authentication socket.");
484 goto error_cleanup;
485 }
486 buffer_append(&buffer, (char *) buf, l);
487 len -= l;
8efc0c15 488 }
5260325f 489
490 /* Get the type of the packet. */
491 type = buffer_get_char(&buffer);
492 switch (type) {
493 case SSH_AGENT_FAILURE:
494 buffer_free(&buffer);
495 return 0;
496 case SSH_AGENT_SUCCESS:
497 buffer_free(&buffer);
498 return 1;
499 default:
500 fatal("Bad response to remove identity from authentication agent: %d",
501 type);
8efc0c15 502 }
5260325f 503 /* NOTREACHED */
504 return 0;
505}
506
aa3378df 507/*
508 * Removes all identities from the agent. This call is not meant to be used
509 * by normal applications.
510 */
8efc0c15 511
6ae2364d 512int
5260325f 513ssh_remove_all_identities(AuthenticationConnection *auth)
8efc0c15 514{
5260325f 515 Buffer buffer;
516 unsigned char buf[8192];
517 int len, l, type;
518
519 /* Get the length of the message, and format it in the buffer. */
520 PUT_32BIT(buf, 1);
521 buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
522
523 /* Send the length and then the packet to the agent. */
a408af76 524 if (atomicio(write, auth->fd, buf, 5) != 5) {
5260325f 525 error("Error writing to authentication socket.");
526 return 0;
527 }
aa3378df 528 /*
529 * Wait for response from the agent. First read the length of the
530 * response packet.
531 */
5260325f 532 len = 4;
533 while (len > 0) {
534 l = read(auth->fd, buf + 4 - len, len);
535 if (l <= 0) {
536 error("Error reading response length from authentication socket.");
537 return 0;
538 }
539 len -= l;
540 }
541
542 /* Extract the length, and check it for sanity. */
543 len = GET_32BIT(buf);
544 if (len > 256 * 1024)
545 fatal("Remove identity response too long: %d", len);
546
547 /* Read the rest of the response into the buffer. */
548 buffer_init(&buffer);
549 while (len > 0) {
550 l = len;
551 if (l > sizeof(buf))
552 l = sizeof(buf);
553 l = read(auth->fd, buf, l);
554 if (l <= 0) {
555 error("Error reading response from authentication socket.");
556 buffer_free(&buffer);
557 return 0;
558 }
559 buffer_append(&buffer, (char *) buf, l);
560 len -= l;
8efc0c15 561 }
5260325f 562
563 /* Get the type of the packet. */
564 type = buffer_get_char(&buffer);
565 switch (type) {
566 case SSH_AGENT_FAILURE:
567 buffer_free(&buffer);
568 return 0;
569 case SSH_AGENT_SUCCESS:
570 buffer_free(&buffer);
571 return 1;
572 default:
573 fatal("Bad response to remove identity from authentication agent: %d",
574 type);
8efc0c15 575 }
5260325f 576 /* NOTREACHED */
577 return 0;
578}
This page took 0.145823 seconds and 5 git commands to generate.