source: trunk/third/ssh/authfd.c @ 12646

Revision 12646, 24.5 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12645, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2
3authfd.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8                   All rights reserved
9
10Created: Wed Mar 29 01:30:28 1995 ylo
11
12Functions for connecting the local authentication agent.
13
14*/
15
16/*
17 * $Id: authfd.c,v 1.1.1.4 1999-03-08 17:43:16 danw Exp $
18 * $Log: not supported by cvs2svn $
19 * Revision 1.16  1998/05/23  20:20:49  kivinen
20 *      Changed () -> (void).
21 *
22 * Revision 1.15  1998/03/27  16:56:30  kivinen
23 *      Allow authentication socket to be symlink, if not suid. Fixed
24 *      authsocketdir freeing.
25 *
26 * Revision 1.14  1998/01/02 06:15:49  kivinen
27 *      Fixed agent socket opening routine.
28 *
29 * Revision 1.13  1997/04/17 04:00:46  kivinen
30 *      Removed extra namelen variable.
31 *
32 * Revision 1.12  1997/03/26 07:00:57  kivinen
33 *      Changed uid 0 to UID_ROOT.
34 *      Fixed memory leak.
35 *      Removed ssh_close_authentication function.
36 *
37 * Revision 1.11  1996/11/19 22:44:03  kivinen
38 *      Changed socket directory checks so that if the
39 *      original_real_uid is root do not check the file owner.
40 *
41 * Revision 1.10  1996/10/29 22:34:52  kivinen
42 *      log -> log_msg. Removed userfile.h.
43 *
44 * Revision 1.9  1996/10/24 14:05:44  ttsalo
45 *       Cleaning up old fd-auth trash
46 *
47 * Revision 1.8  1996/10/21 16:15:40  ttsalo
48 *       Fixed auth socket name handling
49 *
50 * Revision 1.7  1996/10/20 16:26:17  ttsalo
51 *      Modified the routines to use agent socket directly
52 *
53 * Revision 1.6  1996/10/03 18:46:13  ylo
54 *      Fixed a bug that caused "Received signal 14" errors.
55 *
56 * Revision 1.5  1996/09/27 13:56:35  ttsalo
57 *      Fixed a memory deallocation bug
58 *
59 * Revision 1.4  1996/09/11 17:54:22  kivinen
60 *      Added check for bind errors in
61 *      ssh_get_authentication_connection_fd.
62 *      Fixed bug in old alarm / timeout restoration.
63 *      Changed limit of messages from 256 kB to 30 kB.
64 *
65 * Revision 1.3  1996/09/08 17:21:04  ttsalo
66 *      A lot of changes in agent-socket handling
67 *
68 * Revision 1.2  1996/09/04 12:41:50  ttsalo
69 *      Minor fixes
70 *
71 * Revision 1.1.1.1  1996/02/18 21:38:11  ylo
72 *      Imported ssh-1.2.13.
73 *
74 * Revision 1.7  1995/09/21  17:08:11  ylo
75 *      Support AF_UNIX_SIZE.
76 *
77 * Revision 1.6  1995/09/09  21:26:38  ylo
78 * /m/shadows/u2/users/ylo/ssh/README
79 *
80 * Revision 1.5  1995/08/29  22:18:58  ylo
81 *      Added remove_all_identities.
82 *
83 * Revision 1.4  1995/08/21  23:21:04  ylo
84 *      Deleted ssh_authenticate().
85 *      Pass session key and response_type in agent request.
86 *
87 * Revision 1.3  1995/07/13  01:14:40  ylo
88 *      Removed the "Last modified" header.
89 *
90 * Revision 1.2  1995/07/13  01:11:31  ylo
91 *      Added cvs log.
92 *
93 * $Endlog$
94 */
95
96#include "includes.h"
97#include "ssh.h"
98#include "rsa.h"
99#include "authfd.h"
100#include "buffer.h"
101#include "bufaux.h"
102#include "xmalloc.h"
103#include "getput.h"
104
105/* Returns the authentication fd, or -1 if there is none.
106   Socket directory privileges are checked to prevent anyone
107   from connecting to other users' sockets with suid root ssh. */
108
109int ssh_get_authentication_fd(void)
110{
111  char *authsocket, *authsocketdir, *newauthsockdir, *last_dir;
112  char *origauthsocket;
113  int sock;
114  struct sockaddr_un sunaddr;
115  struct stat socket_st, dir_st, dot_st, dotdot_st, parent_st, link_st;
116  struct passwd *pw;
117  int i;
118
119  newauthsockdir = NULL;
120
121  origauthsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
122  if (!origauthsocket)
123    return -1;
124  else
125    authsocketdir = xstrdup(origauthsocket);
126
127  /* Point to the end of the name */
128  authsocket = authsocketdir + strlen(authsocketdir);
129
130  /* Cut the authsocketdir and make authsocket point to
131     the bare socket name */
132  while (authsocket != authsocketdir && *authsocket != '/')
133    authsocket--;
134
135  *authsocket = '\0';
136  authsocket++;
137
138  /* Find parent directory */
139  last_dir = strrchr(authsocketdir, '/');
140  if (last_dir == NULL || last_dir == authsocketdir)
141    {
142      error("Invalid %s `%.100s', it should contain at least one /.",
143            SSH_AUTHSOCKET_ENV_NAME, authsocketdir);
144      xfree(authsocketdir);
145      return -1;
146    }
147
148  /* Stat parent directory */
149  *last_dir = '\0';
150  if (stat(authsocketdir, &parent_st) != 0)
151    {
152      error("Parent directory stat failed `%.100s'", authsocketdir);
153      xfree(authsocketdir);
154      return -1;
155    }
156  *last_dir = '/';
157
158  pw = getpwuid(original_real_uid);
159 
160  /* Change to the socket directory so it's privileges can be
161     reliably checked */
162
163  /* Stat it */
164  if (lstat(authsocketdir, &dir_st) != 0)
165    {
166      error("Cannot stat authentication socket directory %.100s",
167            authsocketdir);
168      xfree(authsocketdir);
169      return -1;
170    }
171 
172  chdir(authsocketdir);
173
174  if (stat(".", &dot_st) != 0)
175    {
176      perror("stat . failed");
177      xfree(authsocketdir);
178      return -1;
179    }
180
181  /* Check that stat of real directory name and . matches. */
182  if (dot_st.st_dev != dir_st.st_dev || dot_st.st_ino != dir_st.st_ino)
183    {
184      error("Wrong directory after chdir");
185      return -1;
186    }
187 
188  if (original_real_uid != UID_ROOT && dot_st.st_uid != pw->pw_uid)
189    {
190      error("Invalid owner of authentication socket directory %.100s",
191            authsocketdir);
192      xfree(authsocketdir);
193      return -1;
194    }
195
196  if ((dot_st.st_mode & 077) != 0)
197    {
198      error("Invalid modes for authentication socket directory %.100s",
199            authsocketdir);
200      xfree(authsocketdir);
201      return -1;
202    }
203
204  if (lstat(authsocket, &socket_st) != 0)
205    {
206      error("Cannot find authentication socket %.100s/%.100s",
207            authsocketdir, authsocket);
208      xfree(authsocketdir);
209      return -1;
210    }
211  if (S_ISLNK(socket_st.st_mode))
212    {
213      if (original_real_uid != geteuid())
214        {
215          error("Authentication socket `%.100s' is symlink", origauthsocket);
216          xfree(authsocketdir);
217          return -1;
218        }
219    }
220
221  /* Check if we are suid process */
222  if (original_real_uid != geteuid())
223    {
224      /* Something wierd code here again. We need to make sure the socket is
225         not symlink to somebody elses socket. We cannot use stat/lstat because
226         user might change the inode after we have stat/lstat'ed it. We cannot
227         use fstat, because it doesn't work for sockets, so we need some magic
228         spell here.
229
230         Create temporary directory at same position where the real agent
231         directory is, allow only owner to modify it (==root). Change current
232         working directory to there and make sure we ended where we wanted
233         (stat "." and real path and check that they match, and check that
234         parent is what it is supposed to be (stat of .. and real parent
235         matches)). Then check that the parent directory ("..") is sticky so
236         nobody can mess with this directory. Now we are at safe place where
237         nobody else have any permissions. Now make hard link from the real
238         authentication socket to this directory. Hard link to symlink will
239         point to destination of that symlink, so if the agent socket was
240         symlink to somebody elses socket then the stat of our hardlink and
241         agent socket given by user differs and we give an error. Otherwise we
242         know that the hard link points to real socket that (at least used to
243         be) at the directory that was owned by user, so we can safely open the
244         hardlink socket (not the original it might be changed after we have
245         checked the permissions). */
246
247      newauthsockdir = xmalloc(strlen(authsocketdir) + 20);
248      sprintf(newauthsockdir, "%s-%d", authsocketdir, getpid());
249
250      /* Create directory */
251      if (mkdir(newauthsockdir, S_IRWXU) != 0)
252        {
253          error("Cannot make temporary authentication socket directory %.100s",
254                newauthsockdir);
255          xfree(authsocketdir);
256          xfree(newauthsockdir);
257          return -1;
258        }
259
260      /* Stat it */
261      if (lstat(newauthsockdir, &dir_st) != 0)
262        {
263          error("Cannot stat newly created temporary authentication socket directory %.100s",
264                newauthsockdir);
265          xfree(authsocketdir);
266          xfree(newauthsockdir);
267          return -1;
268        }
269
270      /* Move to there */
271      chdir(newauthsockdir);
272
273      /* Stat . */
274      if (stat(".", &dot_st) != 0)
275        {
276          error("Cannot stat . in newly created temporary authentication socket directory %.100s",
277                newauthsockdir);
278          xfree(authsocketdir);
279          xfree(newauthsockdir);
280          return -1;
281        }
282
283      /* Check that stat of real directory name and . matches. */
284      if (dot_st.st_dev != dir_st.st_dev || dot_st.st_ino != dir_st.st_ino)
285        {
286          error("Wrong directory after chdir");
287          return -1;
288        }
289
290      /* Stat .. (it should match the parent directory and it must be sticky)*/
291      if (stat("..", &dotdot_st) != 0)
292        {
293          error("Cannot stat .. in newly created temporary authentication socket directory %.100s",
294                newauthsockdir);
295          xfree(authsocketdir);
296          xfree(newauthsockdir);
297          return -1;
298        }
299      if ((dotdot_st.st_mode & 01000) == 0)
300        {
301          error("Agent parent directory is not sticky, mode is %o it should be 041777",
302                dotdot_st.st_mode);
303          xfree(authsocketdir);
304          xfree(newauthsockdir);
305          return -1; 
306        }
307      if (dotdot_st.st_dev != parent_st.st_dev ||
308          dotdot_st.st_ino != parent_st.st_ino)
309        {
310          error("Wrong parent directory after chdir to temp directory");
311          xfree(authsocketdir);
312          xfree(newauthsockdir);
313          return -1; 
314        }
315
316      /* Now we are at safe place, make hardlink to agent socket */
317      if (link(origauthsocket, authsocket) != 0)
318        {
319          error("Hard link to auth socket failed");
320          xfree(authsocketdir);
321          xfree(newauthsockdir);
322          return -1;
323        }
324     
325      /* Check that it match the original socket */
326      if (stat(authsocket, &link_st) != 0)
327        {
328          error("Stat to hard link of authentication socket failed");
329          xfree(authsocketdir);
330          xfree(newauthsockdir);
331          return -1;
332        }
333      if (link_st.st_dev != socket_st.st_dev ||
334          link_st.st_ino != socket_st.st_ino)
335        {
336          error("Hard link and orignal socket are not same");
337          xfree(authsocketdir);
338          xfree(newauthsockdir);
339          return -1;
340        }
341      /* Note! here we are still at the newly created directory, so the connect
342         will use the hard link of socket instead of real socket */
343    }
344
345  sunaddr.sun_family = AF_UNIX;
346  strncpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
347
348  sock = socket(AF_UNIX, SOCK_STREAM, 0);
349  if (sock < 0)
350    {
351      error("Socket failed");
352      if (newauthsockdir != NULL)
353        {
354          unlink(authsocket);
355          chdir("/");
356          rmdir(newauthsockdir);
357          xfree(newauthsockdir);
358        }
359      xfree(authsocketdir);
360      return -1;
361    }
362
363  if (connect(sock, (struct sockaddr *)&sunaddr,
364              AF_UNIX_SIZE(sunaddr)) < 0)
365    {
366      close(sock);
367      if (newauthsockdir != NULL)
368        {
369          unlink(authsocket);
370          chdir("/");
371          rmdir(newauthsockdir);
372          xfree(newauthsockdir);
373        }
374      xfree(authsocketdir);
375      return -1;
376    }
377  if (newauthsockdir != NULL)
378    {
379      unlink(authsocket);
380      chdir("/");
381      rmdir(newauthsockdir);
382      xfree(newauthsockdir);
383    }
384  xfree(authsocketdir);
385  fcntl(sock, F_SETFL, 0);  /* Set the socket to blocking mode */
386  return sock;
387}
388
389/* Opens a socket to the authentication server.  Returns the number of
390   that socket, or -1 if no connection could be made. */
391
392int ssh_get_authentication_connection_fd(void)
393{
394  int authfd;
395
396  /* Get the the socket number from the environment. */
397  authfd = ssh_get_authentication_fd();
398
399  if (authfd >= 0)
400    debug("Connection to authentication agent opened.");
401  else
402    debug("No agent.");
403 
404  return authfd;
405
406
407/* Opens and connects a private socket for communication with the
408   authentication agent.  Returns the file descriptor (which must be
409   shut down and closed by the caller when no longer needed).
410   Returns NULL if an error occurred and the connection could not be
411   opened. */
412
413AuthenticationConnection *
414ssh_get_authentication_connection(void)
415{
416  AuthenticationConnection *auth;
417  int sock;
418 
419  /* Get a connection to the authentication agent. */
420  sock = ssh_get_authentication_connection_fd();
421
422  /* Fail if we couldn't obtain a connection.  This happens if we exited
423     due to a timeout. */
424  if (sock < 0)
425    return NULL;
426
427  /* Allocate the connection structure and initialize it. */
428  auth = xmalloc(sizeof(*auth));
429  auth->fd = sock;
430  buffer_init(&auth->packet);
431  buffer_init(&auth->identities);
432  auth->num_identities = 0;
433
434  return auth;
435}
436
437/* Closes the connection to the authentication agent and frees any associated
438   memory. */
439
440void ssh_close_authentication_connection(AuthenticationConnection *ac)
441{
442  /* Close the connection. */
443  shutdown(ac->fd, 2);
444  close(ac->fd);
445
446  /* Free the buffers. */
447  buffer_free(&ac->packet);
448  buffer_free(&ac->identities);
449 
450  /* Free the connection data structure. */
451  xfree(ac);
452}
453
454/* Returns the first authentication identity held by the agent.
455   Returns true if an identity is available, 0 otherwise.
456   The caller must initialize the integers before the call, and free the
457   comment after a successful call (before calling ssh_get_next_identity). */
458
459int ssh_get_first_identity(AuthenticationConnection *auth,
460                           int *bitsp, MP_INT *e, MP_INT *n, char **comment)
461{
462  unsigned char msg[8192];
463  int len, l;
464
465  /* Send a message to the agent requesting for a list of the identities
466     it can represent. */
467  msg[0] = 0;
468  msg[1] = 0;
469  msg[2] = 0;
470  msg[3] = 1;
471  msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
472  if (write(auth->fd, msg, 5) != 5)
473    {
474      error("write auth->fd: %.100s", strerror(errno));
475      return 0;
476    }
477
478  /* Read the length of the response.  XXX implement timeouts here. */
479  len = 4;
480  while (len > 0)
481    {
482      l = read(auth->fd, msg + 4 - len, len);
483      if (l <= 0)
484        {
485          error("read auth->fd: %.100s", strerror(errno));
486          return 0;
487        }
488      len -= l;
489    }
490
491  /* Extract the length, and check it for sanity.  (We cannot trust
492     authentication agents). */
493  len = GET_32BIT(msg);
494  if (len < 1 || len > 30*1024)
495    fatal("Authentication reply message too long: %d\n", len);
496
497  /* Read the packet itself. */
498  buffer_clear(&auth->identities);
499  while (len > 0)
500    {
501      l = len;
502      if (l > sizeof(msg))
503        l = sizeof(msg);
504      l = read(auth->fd, msg, l);
505      if (l <= 0)
506        fatal("Incomplete authentication reply.");
507      buffer_append(&auth->identities, (char *)msg, l);
508      len -= l;
509    }
510 
511  /* Get message type, and verify that we got a proper answer. */
512  buffer_get(&auth->identities, (char *)msg, 1);
513  if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
514    fatal("Bad authentication reply message type: %d", msg[0]);
515 
516  /* Get the number of entries in the response and check it for sanity. */
517  auth->num_identities = buffer_get_int(&auth->identities);
518  if (auth->num_identities > 1024)
519    fatal("Too many identities in authentication reply: %d\n",
520          auth->num_identities);
521
522  /* Return the first entry (if any). */
523  return ssh_get_next_identity(auth, bitsp, e, n, comment);
524}
525
526/* Returns the next authentication identity for the agent.  Other functions
527   can be called between this and ssh_get_first_identity or two calls of this
528   function.  This returns 0 if there are no more identities.  The caller
529   must free comment after a successful return. */
530
531int ssh_get_next_identity(AuthenticationConnection *auth,
532                          int *bitsp, MP_INT *e, MP_INT *n, char **comment)
533{
534  /* Return failure if no more entries. */
535  if (auth->num_identities <= 0)
536    return 0;
537
538  /* Get the next entry from the packet.  These will abort with a fatal
539     error if the packet is too short or contains corrupt data. */
540  *bitsp = buffer_get_int(&auth->identities);
541  buffer_get_mp_int(&auth->identities, e);
542  buffer_get_mp_int(&auth->identities, n);
543  *comment = buffer_get_string(&auth->identities, NULL);
544
545  /* Decrement the number of remaining entries. */
546  auth->num_identities--;
547
548  return 1;
549}
550
551/* Generates a random challenge, sends it to the agent, and waits for response
552   from the agent.  Returns true (non-zero) if the agent gave the correct
553   answer, zero otherwise.  Response type selects the style of response
554   desired, with 0 corresponding to protocol version 1.0 (no longer supported)
555   and 1 corresponding to protocol version 1.1. */
556
557int ssh_decrypt_challenge(AuthenticationConnection *auth,
558                          int bits, MP_INT *e, MP_INT *n, MP_INT *challenge,
559                          unsigned char session_id[16],
560                          unsigned int response_type,
561                          unsigned char response[16])
562{
563  Buffer buffer;
564  unsigned char buf[8192];
565  int len, l, i;
566
567  /* Response type 0 is no longer supported. */
568  if (response_type == 0)
569    fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
570
571  /* Format a message to the agent. */
572  buf[0] = SSH_AGENTC_RSA_CHALLENGE;
573  buffer_init(&buffer);
574  buffer_append(&buffer, (char *)buf, 1);
575  buffer_put_int(&buffer, bits);
576  buffer_put_mp_int(&buffer, e);
577  buffer_put_mp_int(&buffer, n);
578  buffer_put_mp_int(&buffer, challenge);
579  buffer_append(&buffer, (char *)session_id, 16);
580  buffer_put_int(&buffer, response_type);
581
582  /* Get the length of the message, and format it in the buffer. */
583  len = buffer_len(&buffer);
584  PUT_32BIT(buf, len);
585
586  /* Send the length and then the packet to the agent. */
587  if (write(auth->fd, buf, 4) != 4 ||
588      write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
589        buffer_len(&buffer))
590    {
591      error("Error writing to authentication socket.");
592    error_cleanup:
593      buffer_free(&buffer);
594      return 0;
595    }
596
597  /* Wait for response from the agent.  First read the length of the
598     response packet. */
599  len = 4;
600  while (len > 0)
601    {
602      l = read(auth->fd, buf + 4 - len, len);
603      if (l <= 0)
604        {
605          error("Error reading response length from authentication socket.");
606          goto error_cleanup;
607        }
608      len -= l;
609    }
610
611  /* Extract the length, and check it for sanity. */
612  len = GET_32BIT(buf);
613  if (len > 30*1024)
614    fatal("Authentication response too long: %d", len);
615
616  /* Read the rest of the response in to the buffer. */
617  buffer_clear(&buffer);
618  while (len > 0)
619    {
620      l = len;
621      if (l > sizeof(buf))
622        l = sizeof(buf);
623      l = read(auth->fd, buf, l);
624      if (l <= 0)
625        {
626          error("Error reading response from authentication socket.");
627          goto error_cleanup;
628        }
629      buffer_append(&buffer, (char *)buf, l);
630      len -= l;
631    }
632
633  /* Get the type of the packet. */
634  buffer_get(&buffer, (char *)buf, 1);
635
636  /* Check for agent failure message. */
637  if (buf[0] == SSH_AGENT_FAILURE)
638    {
639      log_msg("Agent admitted failure to authenticate using the key.");
640      goto error_cleanup;
641    }
642     
643  /* Now it must be an authentication response packet. */
644  if (buf[0] != SSH_AGENT_RSA_RESPONSE)
645    fatal("Bad authentication response: %d", buf[0]);
646
647  /* Get the response from the packet.  This will abort with a fatal error
648     if the packet is corrupt. */
649  for (i = 0; i < 16; i++)
650    response[i] = buffer_get_char(&buffer);
651
652  /* The buffer containing the packet is no longer needed. */
653  buffer_free(&buffer);
654
655  /* Correct answer. */
656  return 1;
657
658
659/* Adds an identity to the authentication server.  This call is not meant to
660   be used by normal applications. */
661
662int ssh_add_identity(AuthenticationConnection *auth,
663                     RSAPrivateKey *key, const char *comment)
664{
665  Buffer buffer;
666  unsigned char buf[8192];
667  int len, l, type;
668
669  /* Format a message to the agent. */
670  buffer_init(&buffer);
671  buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
672  buffer_put_int(&buffer, key->bits);
673  buffer_put_mp_int(&buffer, &key->n);
674  buffer_put_mp_int(&buffer, &key->e);
675  buffer_put_mp_int(&buffer, &key->d);
676  buffer_put_mp_int(&buffer, &key->u);
677  buffer_put_mp_int(&buffer, &key->p);
678  buffer_put_mp_int(&buffer, &key->q);
679  buffer_put_string(&buffer, comment, strlen(comment));
680
681  /* Get the length of the message, and format it in the buffer. */
682  len = buffer_len(&buffer);
683  PUT_32BIT(buf, len);
684
685  /* Send the length and then the packet to the agent. */
686  if (write(auth->fd, buf, 4) != 4 ||
687      write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
688        buffer_len(&buffer))
689    {
690      error("Error writing to authentication socket.");
691    error_cleanup:
692      buffer_free(&buffer);
693      return 0;
694    }
695
696  /* Wait for response from the agent.  First read the length of the
697     response packet. */
698  len = 4;
699  while (len > 0)
700    {
701      l = read(auth->fd, buf + 4 - len, len);
702      if (l <= 0)
703        {
704          error("Error reading response length from authentication socket.");
705          goto error_cleanup;
706        }
707      len -= l;
708    }
709
710  /* Extract the length, and check it for sanity. */
711  len = GET_32BIT(buf);
712  if (len > 30*1024)
713    fatal("Add identity response too long: %d", len);
714
715  /* Read the rest of the response in tothe buffer. */
716  buffer_clear(&buffer);
717  while (len > 0)
718    {
719      l = len;
720      if (l > sizeof(buf))
721        l = sizeof(buf);
722      l = read(auth->fd, buf, l);
723      if (l <= 0)
724        {
725          error("Error reading response from authentication socket.");
726          goto error_cleanup;
727        }
728      buffer_append(&buffer, (char *)buf, l);
729      len -= l;
730    }
731
732  /* Get the type of the packet. */
733  type = buffer_get_char(&buffer);
734  switch (type)
735    {
736    case SSH_AGENT_FAILURE:
737      buffer_free(&buffer);
738      return 0;
739    case SSH_AGENT_SUCCESS:
740      buffer_free(&buffer);
741      return 1;
742    default:
743      fatal("Bad response to add identity from authentication agent: %d",
744            type);
745    }
746  /*NOTREACHED*/
747  return 0;
748
749
750/* Removes an identity from the authentication server.  This call is not meant
751   to be used by normal applications. */
752
753int ssh_remove_identity(AuthenticationConnection *auth, RSAPublicKey *key)
754{
755  Buffer buffer;
756  unsigned char buf[8192];
757  int len, l, type;
758
759  /* Format a message to the agent. */
760  buffer_init(&buffer);
761  buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
762  buffer_put_int(&buffer, key->bits);
763  buffer_put_mp_int(&buffer, &key->e);
764  buffer_put_mp_int(&buffer, &key->n);
765
766  /* Get the length of the message, and format it in the buffer. */
767  len = buffer_len(&buffer);
768  PUT_32BIT(buf, len);
769
770  /* Send the length and then the packet to the agent. */
771  if (write(auth->fd, buf, 4) != 4 ||
772      write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
773        buffer_len(&buffer))
774    {
775      error("Error writing to authentication socket.");
776    error_cleanup:
777      buffer_free(&buffer);
778      return 0;
779    }
780
781  /* Wait for response from the agent.  First read the length of the
782     response packet. */
783  len = 4;
784  while (len > 0)
785    {
786      l = read(auth->fd, buf + 4 - len, len);
787      if (l <= 0)
788        {
789          error("Error reading response length from authentication socket.");
790          goto error_cleanup;
791        }
792      len -= l;
793    }
794
795  /* Extract the length, and check it for sanity. */
796  len = GET_32BIT(buf);
797  if (len > 30*1024)
798    fatal("Remove identity response too long: %d", len);
799
800  /* Read the rest of the response in tothe buffer. */
801  buffer_clear(&buffer);
802  while (len > 0)
803    {
804      l = len;
805      if (l > sizeof(buf))
806        l = sizeof(buf);
807      l = read(auth->fd, buf, l);
808      if (l <= 0)
809        {
810          error("Error reading response from authentication socket.");
811          goto error_cleanup;
812        }
813      buffer_append(&buffer, (char *)buf, l);
814      len -= l;
815    }
816
817  /* Get the type of the packet. */
818  type = buffer_get_char(&buffer);
819  switch (type)
820    {
821    case SSH_AGENT_FAILURE:
822      buffer_free(&buffer);
823      return 0;
824    case SSH_AGENT_SUCCESS:
825      buffer_free(&buffer);
826      return 1;
827    default:
828      fatal("Bad response to remove identity from authentication agent: %d",
829            type);
830    }
831  /*NOTREACHED*/
832  return 0;
833
834
835/* Removes all identities from the agent.  This call is not meant
836   to be used by normal applications. */
837
838int ssh_remove_all_identities(AuthenticationConnection *auth)
839{
840  Buffer buffer;
841  unsigned char buf[8192];
842  int len, l, type;
843
844  /* Get the length of the message, and format it in the buffer. */
845  PUT_32BIT(buf, 1);
846  buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
847
848  /* Send the length and then the packet to the agent. */
849  if (write(auth->fd, buf, 5) != 5)
850    {
851      error("Error writing to authentication socket.");
852      return 0;
853    }
854
855  /* Wait for response from the agent.  First read the length of the
856     response packet. */
857  len = 4;
858  while (len > 0)
859    {
860      l = read(auth->fd, buf + 4 - len, len);
861      if (l <= 0)
862        {
863          error("Error reading response length from authentication socket.");
864          return 0;
865        }
866      len -= l;
867    }
868
869  /* Extract the length, and check it for sanity. */
870  len = GET_32BIT(buf);
871  if (len > 30*1024)
872    fatal("Remove identity response too long: %d", len);
873
874  /* Read the rest of the response into the buffer. */
875  buffer_init(&buffer);
876  while (len > 0)
877    {
878      l = len;
879      if (l > sizeof(buf))
880        l = sizeof(buf);
881      l = read(auth->fd, buf, l);
882      if (l <= 0)
883        {
884          error("Error reading response from authentication socket.");
885          buffer_free(&buffer);
886          return 0;
887        }
888      buffer_append(&buffer, (char *)buf, l);
889      len -= l;
890    }
891
892  /* Get the type of the packet. */
893  type = buffer_get_char(&buffer);
894  switch (type)
895    {
896    case SSH_AGENT_FAILURE:
897      buffer_free(&buffer);
898      return 0;
899    case SSH_AGENT_SUCCESS:
900      buffer_free(&buffer);
901      return 1;
902    default:
903      fatal("Bad response to remove identity from authentication agent: %d",
904            type);
905    }
906  /*NOTREACHED*/
907  return 0;
908
Note: See TracBrowser for help on using the repository browser.