[BACK]Return to ssh-agent.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/ssh-agent.c between version 1.72.2.5 and 1.73

version 1.72.2.5, 2002/10/11 14:53:07 version 1.73, 2001/11/17 19:14:34
Line 1 
Line 1 
   /*      $OpenBSD$       */
   
 /*  /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>   * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland   * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Line 34 
Line 36 
  */   */
   
 #include "includes.h"  #include "includes.h"
 #include <sys/queue.h>  
 RCSID("$OpenBSD$");  RCSID("$OpenBSD$");
   
 #include <openssl/evp.h>  #include <openssl/evp.h>
Line 45 
Line 46 
 #include "buffer.h"  #include "buffer.h"
 #include "bufaux.h"  #include "bufaux.h"
 #include "xmalloc.h"  #include "xmalloc.h"
   #include "packet.h"
 #include "getput.h"  #include "getput.h"
   #include "mpaux.h"
 #include "key.h"  #include "key.h"
 #include "authfd.h"  #include "authfd.h"
   #include "cipher.h"
   #include "kex.h"
 #include "compat.h"  #include "compat.h"
 #include "log.h"  #include "log.h"
   
 #ifdef SMARTCARD  #ifdef SMARTCARD
   #include <openssl/engine.h>
 #include "scard.h"  #include "scard.h"
 #endif  #endif
   
Line 66 
Line 72 
         sock_type type;          sock_type type;
         Buffer input;          Buffer input;
         Buffer output;          Buffer output;
         Buffer request;  
 } SocketEntry;  } SocketEntry;
   
 u_int sockets_alloc = 0;  u_int sockets_alloc = 0;
 SocketEntry *sockets = NULL;  SocketEntry *sockets = NULL;
   
 typedef struct identity {  typedef struct {
         TAILQ_ENTRY(identity) next;  
         Key *key;          Key *key;
         char *comment;          char *comment;
         u_int death;  
 } Identity;  } Identity;
   
 typedef struct {  typedef struct {
         int nentries;          int nentries;
         TAILQ_HEAD(idqueue, identity) idlist;          Identity *identities;
 } Idtab;  } Idtab;
   
 /* private key table, one per protocol version */  /* private key table, one per protocol version */
Line 96 
Line 99 
 char socket_name[1024];  char socket_name[1024];
 char socket_dir[1024];  char socket_dir[1024];
   
 /* locking */  
 int locked = 0;  
 char *lock_passwd = NULL;  
   
 extern char *__progname;  extern char *__progname;
   
 static void  static void
 close_socket(SocketEntry *e)  
 {  
         close(e->fd);  
         e->fd = -1;  
         e->type = AUTH_UNUSED;  
         buffer_free(&e->input);  
         buffer_free(&e->output);  
         buffer_free(&e->request);  
 }  
   
 static void  
 idtab_init(void)  idtab_init(void)
 {  {
         int i;          int i;
           for (i = 0; i <=2; i++){
         for (i = 0; i <=2; i++) {                  idtable[i].identities = NULL;
                 TAILQ_INIT(&idtable[i].idlist);  
                 idtable[i].nentries = 0;                  idtable[i].nentries = 0;
         }          }
 }  }
Line 133 
Line 120 
         return &idtable[version];          return &idtable[version];
 }  }
   
 static void  
 free_identity(Identity *id)  
 {  
         key_free(id->key);  
         xfree(id->comment);  
         xfree(id);  
 }  
   
 /* return matching private key for given public key */  /* return matching private key for given public key */
 static Identity *  static Key *
 lookup_identity(Key *key, int version)  lookup_private_key(Key *key, int *idx, int version)
 {  {
         Identity *id;          int i;
   
         Idtab *tab = idtab_lookup(version);          Idtab *tab = idtab_lookup(version);
         TAILQ_FOREACH(id, &tab->idlist, next) {          for (i = 0; i < tab->nentries; i++) {
                 if (key_equal(key, id->key))                  if (key_equal(key, tab->identities[i].key)) {
                         return (id);                          if (idx != NULL)
                                   *idx = i;
                           return tab->identities[i].key;
                   }
         }          }
         return (NULL);          return NULL;
 }  }
   
 /* send list of supported public keys to 'client' */  /* send list of supported public keys to 'client' */
Line 160 
Line 141 
 process_request_identities(SocketEntry *e, int version)  process_request_identities(SocketEntry *e, int version)
 {  {
         Idtab *tab = idtab_lookup(version);          Idtab *tab = idtab_lookup(version);
         Identity *id;  
         Buffer msg;          Buffer msg;
           int i;
   
         buffer_init(&msg);          buffer_init(&msg);
         buffer_put_char(&msg, (version == 1) ?          buffer_put_char(&msg, (version == 1) ?
             SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);              SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
         buffer_put_int(&msg, tab->nentries);          buffer_put_int(&msg, tab->nentries);
         TAILQ_FOREACH(id, &tab->idlist, next) {          for (i = 0; i < tab->nentries; i++) {
                   Identity *id = &tab->identities[i];
                 if (id->key->type == KEY_RSA1) {                  if (id->key->type == KEY_RSA1) {
                         buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));                          buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
                         buffer_put_bignum(&msg, id->key->rsa->e);                          buffer_put_bignum(&msg, id->key->rsa->e);
Line 190 
Line 172 
 static void  static void
 process_authentication_challenge1(SocketEntry *e)  process_authentication_challenge1(SocketEntry *e)
 {  {
         u_char buf[32], mdbuf[16], session_id[16];          Key *key, *private;
         u_int response_type;  
         BIGNUM *challenge;          BIGNUM *challenge;
         Identity *id;  
         int i, len;          int i, len;
         Buffer msg;          Buffer msg;
         MD5_CTX md;          MD5_CTX md;
         Key *key;          u_char buf[32], mdbuf[16], session_id[16];
           u_int response_type;
   
         buffer_init(&msg);          buffer_init(&msg);
         key = key_new(KEY_RSA1);          key = key_new(KEY_RSA1);
         if ((challenge = BN_new()) == NULL)          challenge = BN_new();
                 fatal("process_authentication_challenge1: BN_new failed");  
   
         (void) buffer_get_int(&e->request);                     /* ignored */          buffer_get_int(&e->input);                              /* ignored */
         buffer_get_bignum(&e->request, key->rsa->e);          buffer_get_bignum(&e->input, key->rsa->e);
         buffer_get_bignum(&e->request, key->rsa->n);          buffer_get_bignum(&e->input, key->rsa->n);
         buffer_get_bignum(&e->request, challenge);          buffer_get_bignum(&e->input, challenge);
   
         /* Only protocol 1.1 is supported */          /* Only protocol 1.1 is supported */
         if (buffer_len(&e->request) == 0)          if (buffer_len(&e->input) == 0)
                 goto failure;                  goto failure;
         buffer_get(&e->request, session_id, 16);          buffer_get(&e->input, (char *) session_id, 16);
         response_type = buffer_get_int(&e->request);          response_type = buffer_get_int(&e->input);
         if (response_type != 1)          if (response_type != 1)
                 goto failure;                  goto failure;
   
         id = lookup_identity(key, 1);          private = lookup_private_key(key, NULL, 1);
         if (id != NULL) {          if (private != NULL) {
                 Key *private = id->key;  
                 /* Decrypt the challenge using the private key. */                  /* Decrypt the challenge using the private key. */
                 if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0)                  if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0)
                         goto failure;                          goto failure;
Line 259 
Line 238 
 static void  static void
 process_sign_request2(SocketEntry *e)  process_sign_request2(SocketEntry *e)
 {  {
           extern int datafellows;
           Key *key, *private;
         u_char *blob, *data, *signature = NULL;          u_char *blob, *data, *signature = NULL;
         u_int blen, dlen, slen = 0;          u_int blen, dlen, slen = 0;
         extern int datafellows;          int flags;
         int ok = -1, flags;  
         Buffer msg;          Buffer msg;
         Key *key;          int ok = -1;
   
         datafellows = 0;          datafellows = 0;
   
         blob = buffer_get_string(&e->request, &blen);          blob = buffer_get_string(&e->input, &blen);
         data = buffer_get_string(&e->request, &dlen);          data = buffer_get_string(&e->input, &dlen);
   
         flags = buffer_get_int(&e->request);          flags = buffer_get_int(&e->input);
         if (flags & SSH_AGENT_OLD_SIGNATURE)          if (flags & SSH_AGENT_OLD_SIGNATURE)
                 datafellows = SSH_BUG_SIGBLOB;                  datafellows = SSH_BUG_SIGBLOB;
   
         key = key_from_blob(blob, blen);          key = key_from_blob(blob, blen);
         if (key != NULL) {          if (key != NULL) {
                 Identity *id = lookup_identity(key, 2);                  private = lookup_private_key(key, NULL, 2);
                 if (id != NULL)                  if (private != NULL)
                         ok = key_sign(id->key, &signature, &slen, data, dlen);                          ok = key_sign(private, &signature, &slen, data, dlen);
         }          }
         key_free(key);          key_free(key);
         buffer_init(&msg);          buffer_init(&msg);
Line 303 
Line 283 
 static void  static void
 process_remove_identity(SocketEntry *e, int version)  process_remove_identity(SocketEntry *e, int version)
 {  {
         u_int blen, bits;          Key *key = NULL, *private;
         int success = 0;  
         Key *key = NULL;  
         u_char *blob;          u_char *blob;
           u_int blen;
           u_int bits;
           int success = 0;
   
         switch (version) {          switch(version){
         case 1:          case 1:
                 key = key_new(KEY_RSA1);                  key = key_new(KEY_RSA1);
                 bits = buffer_get_int(&e->request);                  bits = buffer_get_int(&e->input);
                 buffer_get_bignum(&e->request, key->rsa->e);                  buffer_get_bignum(&e->input, key->rsa->e);
                 buffer_get_bignum(&e->request, key->rsa->n);                  buffer_get_bignum(&e->input, key->rsa->n);
   
                 if (bits != key_size(key))                  if (bits != key_size(key))
                         log("Warning: identity keysize mismatch: actual %u, announced %u",                          log("Warning: identity keysize mismatch: actual %d, announced %d",
                             key_size(key), bits);                              key_size(key), bits);
                 break;                  break;
         case 2:          case 2:
                 blob = buffer_get_string(&e->request, &blen);                  blob = buffer_get_string(&e->input, &blen);
                 key = key_from_blob(blob, blen);                  key = key_from_blob(blob, blen);
                 xfree(blob);                  xfree(blob);
                 break;                  break;
         }          }
         if (key != NULL) {          if (key != NULL) {
                 Identity *id = lookup_identity(key, version);                  int idx;
                 if (id != NULL) {                  private = lookup_private_key(key, &idx, version);
                   if (private != NULL) {
                         /*                          /*
                          * We have this key.  Free the old key.  Since we                           * We have this key.  Free the old key.  Since we
                          * don\'t want to leave empty slots in the middle of                           * don\'t want to leave empty slots in the middle of
Line 336 
Line 318 
                          * of the array.                           * of the array.
                          */                           */
                         Idtab *tab = idtab_lookup(version);                          Idtab *tab = idtab_lookup(version);
                           key_free(tab->identities[idx].key);
                           xfree(tab->identities[idx].comment);
                         if (tab->nentries < 1)                          if (tab->nentries < 1)
                                 fatal("process_remove_identity: "                                  fatal("process_remove_identity: "
                                     "internal error: tab->nentries %d",                                      "internal error: tab->nentries %d",
                                     tab->nentries);                                      tab->nentries);
                         TAILQ_REMOVE(&tab->idlist, id, next);                          if (idx != tab->nentries - 1) {
                         free_identity(id);                                  int i;
                                   for (i = idx; i < tab->nentries - 1; i++)
                                           tab->identities[i] = tab->identities[i+1];
                           }
                           tab->identities[tab->nentries - 1].key = NULL;
                           tab->identities[tab->nentries - 1].comment = NULL;
                         tab->nentries--;                          tab->nentries--;
                         success = 1;                          success = 1;
                 }                  }
Line 355 
Line 344 
 static void  static void
 process_remove_all_identities(SocketEntry *e, int version)  process_remove_all_identities(SocketEntry *e, int version)
 {  {
           u_int i;
         Idtab *tab = idtab_lookup(version);          Idtab *tab = idtab_lookup(version);
         Identity *id;  
   
         /* Loop over all identities and clear the keys. */          /* Loop over all identities and clear the keys. */
         for (id = TAILQ_FIRST(&tab->idlist); id;          for (i = 0; i < tab->nentries; i++) {
             id = TAILQ_FIRST(&tab->idlist)) {                  key_free(tab->identities[i].key);
                 TAILQ_REMOVE(&tab->idlist, id, next);                  xfree(tab->identities[i].comment);
                 free_identity(id);  
         }          }
   
         /* Mark that there are no identities. */          /* Mark that there are no identities. */
Line 371 
Line 359 
         /* Send success. */          /* Send success. */
         buffer_put_int(&e->output, 1);          buffer_put_int(&e->output, 1);
         buffer_put_char(&e->output, SSH_AGENT_SUCCESS);          buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
           return;
 }  }
   
 static void  static void
 reaper(void)  
 {  
         u_int now = time(NULL);  
         Identity *id, *nxt;  
         int version;  
         Idtab *tab;  
   
         for (version = 1; version < 3; version++) {  
                 tab = idtab_lookup(version);  
                 for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {  
                         nxt = TAILQ_NEXT(id, next);  
                         if (id->death != 0 && now >= id->death) {  
                                 TAILQ_REMOVE(&tab->idlist, id, next);  
                                 free_identity(id);  
                                 tab->nentries--;  
                         }  
                 }  
         }  
 }  
   
 static void  
 process_add_identity(SocketEntry *e, int version)  process_add_identity(SocketEntry *e, int version)
 {  {
         Idtab *tab = idtab_lookup(version);  
         int type, success = 0, death = 0;  
         char *type_name, *comment;  
         Key *k = NULL;          Key *k = NULL;
           char *type_name;
           char *comment;
           int type, success = 0;
           Idtab *tab = idtab_lookup(version);
   
         switch (version) {          switch (version) {
         case 1:          case 1:
                 k = key_new_private(KEY_RSA1);                  k = key_new_private(KEY_RSA1);
                 (void) buffer_get_int(&e->request);             /* ignored */                  buffer_get_int(&e->input);                      /* ignored */
                 buffer_get_bignum(&e->request, k->rsa->n);                  buffer_get_bignum(&e->input, k->rsa->n);
                 buffer_get_bignum(&e->request, k->rsa->e);                  buffer_get_bignum(&e->input, k->rsa->e);
                 buffer_get_bignum(&e->request, k->rsa->d);                  buffer_get_bignum(&e->input, k->rsa->d);
                 buffer_get_bignum(&e->request, k->rsa->iqmp);                  buffer_get_bignum(&e->input, k->rsa->iqmp);
   
                 /* SSH and SSL have p and q swapped */                  /* SSH and SSL have p and q swapped */
                 buffer_get_bignum(&e->request, k->rsa->q);      /* p */                  buffer_get_bignum(&e->input, k->rsa->q);        /* p */
                 buffer_get_bignum(&e->request, k->rsa->p);      /* q */                  buffer_get_bignum(&e->input, k->rsa->p);        /* q */
   
                 /* Generate additional parameters */                  /* Generate additional parameters */
                 rsa_generate_additional_parameters(k->rsa);                  rsa_generate_additional_parameters(k->rsa);
                 break;                  break;
         case 2:          case 2:
                 type_name = buffer_get_string(&e->request, NULL);                  type_name = buffer_get_string(&e->input, NULL);
                 type = key_type_from_name(type_name);                  type = key_type_from_name(type_name);
                 xfree(type_name);                  xfree(type_name);
                 switch (type) {                  switch(type) {
                 case KEY_DSA:                  case KEY_DSA:
                         k = key_new_private(type);                          k = key_new_private(type);
                         buffer_get_bignum2(&e->request, k->dsa->p);                          buffer_get_bignum2(&e->input, k->dsa->p);
                         buffer_get_bignum2(&e->request, k->dsa->q);                          buffer_get_bignum2(&e->input, k->dsa->q);
                         buffer_get_bignum2(&e->request, k->dsa->g);                          buffer_get_bignum2(&e->input, k->dsa->g);
                         buffer_get_bignum2(&e->request, k->dsa->pub_key);                          buffer_get_bignum2(&e->input, k->dsa->pub_key);
                         buffer_get_bignum2(&e->request, k->dsa->priv_key);                          buffer_get_bignum2(&e->input, k->dsa->priv_key);
                         break;                          break;
                 case KEY_RSA:                  case KEY_RSA:
                         k = key_new_private(type);                          k = key_new_private(type);
                         buffer_get_bignum2(&e->request, k->rsa->n);                          buffer_get_bignum2(&e->input, k->rsa->n);
                         buffer_get_bignum2(&e->request, k->rsa->e);                          buffer_get_bignum2(&e->input, k->rsa->e);
                         buffer_get_bignum2(&e->request, k->rsa->d);                          buffer_get_bignum2(&e->input, k->rsa->d);
                         buffer_get_bignum2(&e->request, k->rsa->iqmp);                          buffer_get_bignum2(&e->input, k->rsa->iqmp);
                         buffer_get_bignum2(&e->request, k->rsa->p);                          buffer_get_bignum2(&e->input, k->rsa->p);
                         buffer_get_bignum2(&e->request, k->rsa->q);                          buffer_get_bignum2(&e->input, k->rsa->q);
   
                         /* Generate additional parameters */                          /* Generate additional parameters */
                         rsa_generate_additional_parameters(k->rsa);                          rsa_generate_additional_parameters(k->rsa);
                         break;                          break;
                 default:                  default:
                         buffer_clear(&e->request);                          buffer_clear(&e->input);
                         goto send;                          goto send;
                 }                  }
                 break;                  break;
         }          }
         comment = buffer_get_string(&e->request, NULL);          comment = buffer_get_string(&e->input, NULL);
         if (k == NULL) {          if (k == NULL) {
                 xfree(comment);                  xfree(comment);
                 goto send;                  goto send;
         }          }
         success = 1;          success = 1;
         while (buffer_len(&e->request)) {          if (lookup_private_key(k, NULL, version) == NULL) {
                 switch (buffer_get_char(&e->request)) {                  if (tab->nentries == 0)
                 case SSH_AGENT_CONSTRAIN_LIFETIME:                          tab->identities = xmalloc(sizeof(Identity));
                         death = time(NULL) + buffer_get_int(&e->request);                  else
                         break;                          tab->identities = xrealloc(tab->identities,
                 default:                              (tab->nentries + 1) * sizeof(Identity));
                         break;                  tab->identities[tab->nentries].key = k;
                 }                  tab->identities[tab->nentries].comment = comment;
         }  
         if (lookup_identity(k, version) == NULL) {  
                 Identity *id = xmalloc(sizeof(Identity));  
                 id->key = k;  
                 id->comment = comment;  
                 id->death = death;  
                 TAILQ_INSERT_TAIL(&tab->idlist, id, next);  
                 /* Increment the number of identities. */                  /* Increment the number of identities. */
                 tab->nentries++;                  tab->nentries++;
         } else {          } else {
Line 482 
Line 444 
             success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);              success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
 }  }
   
 /* XXX todo: encrypt sensitive data with passphrase */  
 static void  
 process_lock_agent(SocketEntry *e, int lock)  
 {  
         int success = 0;  
         char *passwd;  
   
         passwd = buffer_get_string(&e->request, NULL);  
         if (locked && !lock && strcmp(passwd, lock_passwd) == 0) {  
                 locked = 0;  
                 memset(lock_passwd, 0, strlen(lock_passwd));  
                 xfree(lock_passwd);  
                 lock_passwd = NULL;  
                 success = 1;  
         } else if (!locked && lock) {  
                 locked = 1;  
                 lock_passwd = xstrdup(passwd);  
                 success = 1;  
         }  
         memset(passwd, 0, strlen(passwd));  
         xfree(passwd);  
   
         buffer_put_int(&e->output, 1);  
         buffer_put_char(&e->output,  
             success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);  
 }  
   
 static void  
 no_identities(SocketEntry *e, u_int type)  
 {  
         Buffer msg;  
   
         buffer_init(&msg);  
         buffer_put_char(&msg,  
             (type == SSH_AGENTC_REQUEST_RSA_IDENTITIES) ?  
             SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);  
         buffer_put_int(&msg, 0);  
         buffer_put_int(&e->output, buffer_len(&msg));  
         buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));  
         buffer_free(&msg);  
 }  
   
 #ifdef SMARTCARD  #ifdef SMARTCARD
 static void  static void
 process_add_smartcard_key (SocketEntry *e)  process_add_smartcard_key (SocketEntry *e)
 {  {
         char *sc_reader_id = NULL, *pin;  
         int i, version, success = 0;  
         Key **keys, *k;  
         Identity *id;  
         Idtab *tab;          Idtab *tab;
           Key *n = NULL, *k = NULL;
         sc_reader_id = buffer_get_string(&e->request, NULL);          char *sc_reader_id = NULL;
         pin = buffer_get_string(&e->request, NULL);          int success = 0;
         keys = sc_get_keys(sc_reader_id, pin);  
           sc_reader_id = buffer_get_string(&e->input, NULL);
           k = sc_get_key(sc_reader_id);
         xfree(sc_reader_id);          xfree(sc_reader_id);
         xfree(pin);  
   
         if (keys == NULL || keys[0] == NULL) {          if (k == NULL) {
                 error("sc_get_keys failed");                  error("sc_get_pubkey failed");
                 goto send;                  goto send;
         }          }
         for (i = 0; keys[i] != NULL; i++) {          success = 1;
                 k = keys[i];  
                 version = k->type == KEY_RSA1 ? 1 : 2;          tab = idtab_lookup(1);
                 tab = idtab_lookup(version);          k->type = KEY_RSA1;
                 if (lookup_identity(k, version) == NULL) {          if (lookup_private_key(k, NULL, 1) == NULL) {
                         id = xmalloc(sizeof(Identity));                  if (tab->nentries == 0)
                         id->key = k;                          tab->identities = xmalloc(sizeof(Identity));
                         id->comment = xstrdup("smartcard key");                  else
                         id->death = 0;                          tab->identities = xrealloc(tab->identities,
                         TAILQ_INSERT_TAIL(&tab->idlist, id, next);                              (tab->nentries + 1) * sizeof(Identity));
                         tab->nentries++;                  n = key_new(KEY_RSA1);
                         success = 1;                  BN_copy(n->rsa->n, k->rsa->n);
                 } else {                  BN_copy(n->rsa->e, k->rsa->e);
                         key_free(k);                  RSA_set_method(n->rsa, sc_get_engine());
                 }                  tab->identities[tab->nentries].key = n;
                 keys[i] = NULL;                  tab->identities[tab->nentries].comment =
                       xstrdup("rsa1 smartcard");
                   tab->nentries++;
         }          }
         xfree(keys);          k->type = KEY_RSA;
           tab = idtab_lookup(2);
           if (lookup_private_key(k, NULL, 2) == NULL) {
                   if (tab->nentries == 0)
                           tab->identities = xmalloc(sizeof(Identity));
                   else
                           tab->identities = xrealloc(tab->identities,
                               (tab->nentries + 1) * sizeof(Identity));
                   n = key_new(KEY_RSA);
                   BN_copy(n->rsa->n, k->rsa->n);
                   BN_copy(n->rsa->e, k->rsa->e);
                   RSA_set_method(n->rsa, sc_get_engine());
                   tab->identities[tab->nentries].key = n;
                   tab->identities[tab->nentries].comment =
                       xstrdup("rsa smartcard");
                   tab->nentries++;
           }
           key_free(k);
 send:  send:
         buffer_put_int(&e->output, 1);          buffer_put_int(&e->output, 1);
         buffer_put_char(&e->output,          buffer_put_char(&e->output,
Line 571 
Line 508 
 static void  static void
 process_remove_smartcard_key(SocketEntry *e)  process_remove_smartcard_key(SocketEntry *e)
 {  {
         char *sc_reader_id = NULL, *pin;          Key *k = NULL, *private;
         int i, version, success = 0;          int idx;
         Key **keys, *k = NULL;          int success = 0;
         Identity *id;          char *sc_reader_id = NULL;
         Idtab *tab;  
   
         sc_reader_id = buffer_get_string(&e->request, NULL);          sc_reader_id = buffer_get_string(&e->input, NULL);
         pin = buffer_get_string(&e->request, NULL);          k = sc_get_key(sc_reader_id);
         keys = sc_get_keys(sc_reader_id, pin);  
         xfree(sc_reader_id);          xfree(sc_reader_id);
         xfree(pin);  
   
         if (keys == NULL || keys[0] == NULL) {          if (k == NULL) {
                 error("sc_get_keys failed");                  error("sc_get_pubkey failed");
                 goto send;          } else {
         }                  k->type = KEY_RSA1;
         for (i = 0; keys[i] != NULL; i++) {                  private = lookup_private_key(k, &idx, 1);
                 k = keys[i];                  if (private != NULL) {
                 version = k->type == KEY_RSA1 ? 1 : 2;                          Idtab *tab = idtab_lookup(1);
                 if ((id = lookup_identity(k, version)) != NULL) {                          key_free(tab->identities[idx].key);
                         tab = idtab_lookup(version);                          xfree(tab->identities[idx].comment);
                         TAILQ_REMOVE(&tab->idlist, id, next);                          if (idx != tab->nentries)
                                   tab->identities[idx] = tab->identities[tab->nentries];
                         tab->nentries--;                          tab->nentries--;
                         free_identity(id);  
                         success = 1;                          success = 1;
                 }                  }
                   k->type = KEY_RSA;
                   private = lookup_private_key(k, &idx, 2);
                   if (private != NULL) {
                           Idtab *tab = idtab_lookup(2);
                           key_free(tab->identities[idx].key);
                           xfree(tab->identities[idx].comment);
                           if (idx != tab->nentries)
                                   tab->identities[idx] = tab->identities[tab->nentries];
                           tab->nentries--;
                           success = 1;
                   }
                 key_free(k);                  key_free(k);
                 keys[i] = NULL;  
         }          }
         xfree(keys);  
 send:  
         buffer_put_int(&e->output, 1);          buffer_put_int(&e->output, 1);
         buffer_put_char(&e->output,          buffer_put_char(&e->output,
             success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);              success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
Line 613 
Line 556 
 static void  static void
 process_message(SocketEntry *e)  process_message(SocketEntry *e)
 {  {
         u_int msg_len, type;          u_int msg_len;
           u_int type;
         u_char *cp;          u_char *cp;
   
         /* kill dead keys */  
         reaper();  
   
         if (buffer_len(&e->input) < 5)          if (buffer_len(&e->input) < 5)
                 return;         /* Incomplete message. */                  return;         /* Incomplete message. */
         cp = buffer_ptr(&e->input);          cp = (u_char *) buffer_ptr(&e->input);
         msg_len = GET_32BIT(cp);          msg_len = GET_32BIT(cp);
         if (msg_len > 256 * 1024) {          if (msg_len > 256 * 1024) {
                 close_socket(e);                  shutdown(e->fd, SHUT_RDWR);
                   close(e->fd);
                   e->type = AUTH_UNUSED;
                 return;                  return;
         }          }
         if (buffer_len(&e->input) < msg_len + 4)          if (buffer_len(&e->input) < msg_len + 4)
                 return;                  return;
   
         /* move the current input to e->request */  
         buffer_consume(&e->input, 4);          buffer_consume(&e->input, 4);
         buffer_clear(&e->request);          type = buffer_get_char(&e->input);
         buffer_append(&e->request, buffer_ptr(&e->input), msg_len);  
         buffer_consume(&e->input, msg_len);  
         type = buffer_get_char(&e->request);  
   
         /* check wheter agent is locked */  
         if (locked && type != SSH_AGENTC_UNLOCK) {  
                 buffer_clear(&e->request);  
                 switch (type) {  
                 case SSH_AGENTC_REQUEST_RSA_IDENTITIES:  
                 case SSH2_AGENTC_REQUEST_IDENTITIES:  
                         /* send empty lists */  
                         no_identities(e, type);  
                         break;  
                 default:  
                         /* send a fail message for all other request types */  
                         buffer_put_int(&e->output, 1);  
                         buffer_put_char(&e->output, SSH_AGENT_FAILURE);  
                 }  
                 return;  
         }  
   
         debug("type %d", type);          debug("type %d", type);
         switch (type) {          switch (type) {
         case SSH_AGENTC_LOCK:  
         case SSH_AGENTC_UNLOCK:  
                 process_lock_agent(e, type == SSH_AGENTC_LOCK);  
                 break;  
         /* ssh1 */          /* ssh1 */
         case SSH_AGENTC_RSA_CHALLENGE:          case SSH_AGENTC_RSA_CHALLENGE:
                 process_authentication_challenge1(e);                  process_authentication_challenge1(e);
Line 668 
Line 584 
                 process_request_identities(e, 1);                  process_request_identities(e, 1);
                 break;                  break;
         case SSH_AGENTC_ADD_RSA_IDENTITY:          case SSH_AGENTC_ADD_RSA_IDENTITY:
         case SSH_AGENTC_ADD_RSA_ID_CONSTRAINED:  
                 process_add_identity(e, 1);                  process_add_identity(e, 1);
                 break;                  break;
         case SSH_AGENTC_REMOVE_RSA_IDENTITY:          case SSH_AGENTC_REMOVE_RSA_IDENTITY:
Line 685 
Line 600 
                 process_request_identities(e, 2);                  process_request_identities(e, 2);
                 break;                  break;
         case SSH2_AGENTC_ADD_IDENTITY:          case SSH2_AGENTC_ADD_IDENTITY:
         case SSH2_AGENTC_ADD_ID_CONSTRAINED:  
                 process_add_identity(e, 2);                  process_add_identity(e, 2);
                 break;                  break;
         case SSH2_AGENTC_REMOVE_IDENTITY:          case SSH2_AGENTC_REMOVE_IDENTITY:
Line 697 
Line 611 
 #ifdef SMARTCARD  #ifdef SMARTCARD
         case SSH_AGENTC_ADD_SMARTCARD_KEY:          case SSH_AGENTC_ADD_SMARTCARD_KEY:
                 process_add_smartcard_key(e);                  process_add_smartcard_key(e);
                 break;                  break;
         case SSH_AGENTC_REMOVE_SMARTCARD_KEY:          case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
                 process_remove_smartcard_key(e);                  process_remove_smartcard_key(e);
                 break;                  break;
 #endif /* SMARTCARD */  #endif /* SMARTCARD */
         default:          default:
                 /* Unknown message.  Respond with failure. */                  /* Unknown message.  Respond with failure. */
                 error("Unknown message %d", type);                  error("Unknown message %d", type);
                 buffer_clear(&e->request);                  buffer_clear(&e->input);
                 buffer_put_int(&e->output, 1);                  buffer_put_int(&e->output, 1);
                 buffer_put_char(&e->output, SSH_AGENT_FAILURE);                  buffer_put_char(&e->output, SSH_AGENT_FAILURE);
                 break;                  break;
Line 716 
Line 630 
 new_socket(sock_type type, int fd)  new_socket(sock_type type, int fd)
 {  {
         u_int i, old_alloc;          u_int i, old_alloc;
   
         if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)          if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                 error("fcntl O_NONBLOCK: %s", strerror(errno));                  error("fcntl O_NONBLOCK: %s", strerror(errno));
   
Line 729 
Line 642 
                         sockets[i].type = type;                          sockets[i].type = type;
                         buffer_init(&sockets[i].input);                          buffer_init(&sockets[i].input);
                         buffer_init(&sockets[i].output);                          buffer_init(&sockets[i].output);
                         buffer_init(&sockets[i].request);  
                         return;                          return;
                 }                  }
         old_alloc = sockets_alloc;          old_alloc = sockets_alloc;
Line 744 
Line 656 
         sockets[old_alloc].fd = fd;          sockets[old_alloc].fd = fd;
         buffer_init(&sockets[old_alloc].input);          buffer_init(&sockets[old_alloc].input);
         buffer_init(&sockets[old_alloc].output);          buffer_init(&sockets[old_alloc].output);
         buffer_init(&sockets[old_alloc].request);  
 }  }
   
 static int  static int
Line 801 
Line 712 
 static void  static void
 after_select(fd_set *readset, fd_set *writeset)  after_select(fd_set *readset, fd_set *writeset)
 {  {
         struct sockaddr_un sunaddr;          u_int i;
           int len, sock;
         socklen_t slen;          socklen_t slen;
         char buf[1024];          char buf[1024];
         int len, sock;          struct sockaddr_un sunaddr;
         u_int i;  
         uid_t euid;  
         gid_t egid;  
   
         for (i = 0; i < sockets_alloc; i++)          for (i = 0; i < sockets_alloc; i++)
                 switch (sockets[i].type) {                  switch (sockets[i].type) {
Line 819 
Line 728 
                                 sock = accept(sockets[i].fd,                                  sock = accept(sockets[i].fd,
                                     (struct sockaddr *) &sunaddr, &slen);                                      (struct sockaddr *) &sunaddr, &slen);
                                 if (sock < 0) {                                  if (sock < 0) {
                                         error("accept from AUTH_SOCKET: %s",                                          perror("accept from AUTH_SOCKET");
                                             strerror(errno));  
                                         break;                                          break;
                                 }                                  }
                                 if (getpeereid(sock, &euid, &egid) < 0) {  
                                         error("getpeereid %d failed: %s",  
                                             sock, strerror(errno));  
                                         close(sock);  
                                         break;  
                                 }  
                                 if ((euid != 0) && (getuid() != euid)) {  
                                         error("uid mismatch: "  
                                             "peer euid %u != uid %u",  
                                             (u_int) euid, (u_int) getuid());  
                                         close(sock);  
                                         break;  
                                 }  
                                 new_socket(AUTH_CONNECTION, sock);                                  new_socket(AUTH_CONNECTION, sock);
                         }                          }
                         break;                          break;
Line 852 
Line 747 
                                         break;                                          break;
                                 } while (1);                                  } while (1);
                                 if (len <= 0) {                                  if (len <= 0) {
                                         close_socket(&sockets[i]);                                          shutdown(sockets[i].fd, SHUT_RDWR);
                                           close(sockets[i].fd);
                                           sockets[i].type = AUTH_UNUSED;
                                           buffer_free(&sockets[i].input);
                                           buffer_free(&sockets[i].output);
                                         break;                                          break;
                                 }                                  }
                                 buffer_consume(&sockets[i].output, len);                                  buffer_consume(&sockets[i].output, len);
Line 866 
Line 765 
                                         break;                                          break;
                                 } while (1);                                  } while (1);
                                 if (len <= 0) {                                  if (len <= 0) {
                                         close_socket(&sockets[i]);                                          shutdown(sockets[i].fd, SHUT_RDWR);
                                           close(sockets[i].fd);
                                           sockets[i].type = AUTH_UNUSED;
                                           buffer_free(&sockets[i].input);
                                           buffer_free(&sockets[i].output);
                                         break;                                          break;
                                 }                                  }
                                 buffer_append(&sockets[i].input, buf, len);                                  buffer_append(&sockets[i].input, buf, len);
Line 879 
Line 782 
 }  }
   
 static void  static void
 cleanup_socket(void *p)  cleanup_socket(void)
 {  {
         if (socket_name[0])          if (socket_name[0])
                 unlink(socket_name);                  unlink(socket_name);
Line 890 
Line 793 
 static void  static void
 cleanup_exit(int i)  cleanup_exit(int i)
 {  {
         cleanup_socket(NULL);          cleanup_socket();
         exit(i);          exit(i);
 }  }
   
 static void  static void
 cleanup_handler(int sig)  cleanup_handler(int sig)
 {  {
         cleanup_socket(NULL);          cleanup_socket();
         _exit(2);          _exit(2);
 }  }
   
Line 925 
Line 828 
         fprintf(stderr, "  -s          Generate Bourne shell commands on stdout.\n");          fprintf(stderr, "  -s          Generate Bourne shell commands on stdout.\n");
         fprintf(stderr, "  -k          Kill the current agent.\n");          fprintf(stderr, "  -k          Kill the current agent.\n");
         fprintf(stderr, "  -d          Debug mode.\n");          fprintf(stderr, "  -d          Debug mode.\n");
         fprintf(stderr, "  -a socket   Bind agent socket to given name.\n");  
         exit(1);          exit(1);
 }  }
   
Line 933 
Line 835 
 main(int ac, char **av)  main(int ac, char **av)
 {  {
         int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc;          int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc;
         char *shell, *format, *pidstr, *agentsocket = NULL;  
         fd_set *readsetp = NULL, *writesetp = NULL;  
         struct sockaddr_un sunaddr;          struct sockaddr_un sunaddr;
         struct rlimit rlim;          struct rlimit rlim;
         extern int optind;  
         extern char *optarg;  
         pid_t pid;          pid_t pid;
         char pidstrbuf[1 + 3 * sizeof pid];          char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
           extern int optind;
           fd_set *readsetp = NULL, *writesetp = NULL;
   
         /* drop */  
         setegid(getgid());  
         setgid(getgid());  
   
         SSLeay_add_all_algorithms();          SSLeay_add_all_algorithms();
   
         while ((ch = getopt(ac, av, "cdksa:")) != -1) {          while ((ch = getopt(ac, av, "cdks")) != -1) {
                 switch (ch) {                  switch (ch) {
                 case 'c':                  case 'c':
                         if (s_flag)                          if (s_flag)
Line 968 
Line 864 
                                 usage();                                  usage();
                         d_flag++;                          d_flag++;
                         break;                          break;
                 case 'a':  
                         agentsocket = optarg;  
                         break;  
                 default:                  default:
                         usage();                          usage();
                 }                  }
Line 981 
Line 874 
         if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))          if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))
                 usage();                  usage();
   
         if (ac == 0 && !c_flag && !s_flag) {          if (ac == 0 && !c_flag && !k_flag && !s_flag && !d_flag) {
                 shell = getenv("SHELL");                  shell = getenv("SHELL");
                 if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)                  if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
                         c_flag = 1;                          c_flag = 1;
Line 1006 
Line 899 
                 format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";                  format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
                 printf(format, SSH_AUTHSOCKET_ENV_NAME);                  printf(format, SSH_AUTHSOCKET_ENV_NAME);
                 printf(format, SSH_AGENTPID_ENV_NAME);                  printf(format, SSH_AGENTPID_ENV_NAME);
                 printf("echo Agent pid %ld killed;\n", (long)pid);                  printf("echo Agent pid %d killed;\n", pid);
                 exit(0);                  exit(0);
         }          }
         parent_pid = getpid();          parent_pid = getpid();
   
         if (agentsocket == NULL) {          /* Create private directory for agent socket */
                 /* Create private directory for agent socket */          strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
                 strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);          if (mkdtemp(socket_dir) == NULL) {
                 if (mkdtemp(socket_dir) == NULL) {                  perror("mkdtemp: private socket dir");
                         perror("mkdtemp: private socket dir");                  exit(1);
                         exit(1);  
                 }  
                 snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,  
                     (long)parent_pid);  
         } else {  
                 /* Try to use specified agent socket */  
                 socket_dir[0] = '\0';  
                 strlcpy(socket_name, agentsocket, sizeof socket_name);  
         }          }
           snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
               parent_pid);
   
         /*          /*
          * Create socket early so it will exist before command gets run from           * Create socket early so it will exist before command gets run from
Line 1042 
Line 929 
                 perror("bind");                  perror("bind");
                 cleanup_exit(1);                  cleanup_exit(1);
         }          }
         if (listen(sock, 128) < 0) {          if (listen(sock, 5) < 0) {
                 perror("listen");                  perror("listen");
                 cleanup_exit(1);                  cleanup_exit(1);
         }          }
Line 1056 
Line 943 
                 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";                  format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
                 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,                  printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
                     SSH_AUTHSOCKET_ENV_NAME);                      SSH_AUTHSOCKET_ENV_NAME);
                 printf("echo Agent pid %ld;\n", (long)parent_pid);                  printf("echo Agent pid %d;\n", parent_pid);
                 goto skip;                  goto skip;
         }          }
         pid = fork();          pid = fork();
         if (pid == -1) {          if (pid == -1) {
                 perror("fork");                  perror("fork");
                 cleanup_exit(1);                  exit(1);
         }          }
         if (pid != 0) {         /* Parent - execute the given command. */          if (pid != 0) {         /* Parent - execute the given command. */
                 close(sock);                  close(sock);
                 snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid);                  snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
                 if (ac == 0) {                  if (ac == 0) {
                         format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";                          format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
                         printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,                          printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
                             SSH_AUTHSOCKET_ENV_NAME);                              SSH_AUTHSOCKET_ENV_NAME);
                         printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,                          printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
                             SSH_AGENTPID_ENV_NAME);                              SSH_AGENTPID_ENV_NAME);
                         printf("echo Agent pid %ld;\n", (long)pid);                          printf("echo Agent pid %d;\n", pid);
                         exit(0);                          exit(0);
                 }                  }
                 if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||                  if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
Line 1085 
Line 972 
                 perror(av[0]);                  perror(av[0]);
                 exit(1);                  exit(1);
         }          }
         /* child */  
         log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);  
   
         if (setsid() == -1) {          if (setsid() == -1) {
                 error("setsid: %s", strerror(errno));                  perror("setsid");
                 cleanup_exit(1);                  cleanup_exit(1);
         }          }
   
Line 1101 
Line 986 
         /* deny core dumps, since memory contains unencrypted private keys */          /* deny core dumps, since memory contains unencrypted private keys */
         rlim.rlim_cur = rlim.rlim_max = 0;          rlim.rlim_cur = rlim.rlim_max = 0;
         if (setrlimit(RLIMIT_CORE, &rlim) < 0) {          if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
                 error("setrlimit RLIMIT_CORE: %s", strerror(errno));                  perror("setrlimit rlimit_core failed");
                 cleanup_exit(1);                  cleanup_exit(1);
         }          }
   
 skip:  skip:
         fatal_add_cleanup(cleanup_socket, NULL);          if (atexit(cleanup_socket) < 0) {
                   perror("atexit");
                   cleanup_exit(1);
           }
         new_socket(AUTH_SOCKET, sock);          new_socket(AUTH_SOCKET, sock);
         if (ac > 0) {          if (ac > 0) {
                 signal(SIGALRM, check_parent_exists);                  signal(SIGALRM, check_parent_exists);
Line 1125 
Line 1013 
                 if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) {                  if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) {
                         if (errno == EINTR)                          if (errno == EINTR)
                                 continue;                                  continue;
                         fatal("select: %s", strerror(errno));                          exit(1);
                 }                  }
                 after_select(readsetp, writesetp);                  after_select(readsetp, writesetp);
         }          }

Legend:
Removed from v.1.72.2.5  
changed lines
  Added in v.1.73