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