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