[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.220 and 1.221

version 1.220, 2017/04/30 23:18:44 version 1.221, 2017/04/30 23:29:10
Line 105 
Line 105 
         u_int confirm;          u_int confirm;
 } Identity;  } Identity;
   
 typedef struct {  struct idtable {
         int nentries;          int nentries;
         TAILQ_HEAD(idqueue, identity) idlist;          TAILQ_HEAD(idqueue, identity) idlist;
 } Idtab;  };
   
 /* private key table, one per protocol version */  /* private key table */
 Idtab idtable[3];  struct idtable *idtab;
   
 int max_fd = 0;  int max_fd = 0;
   
Line 158 
Line 158 
 static void  static void
 idtab_init(void)  idtab_init(void)
 {  {
         int i;          idtab = xcalloc(1, sizeof(*idtab));
           TAILQ_INIT(&idtab->idlist);
         for (i = 0; i <=2; i++) {          idtab->nentries = 0;
                 TAILQ_INIT(&idtable[i].idlist);  
                 idtable[i].nentries = 0;  
         }  
 }  }
   
 /* return private key table for requested protocol version */  
 static Idtab *  
 idtab_lookup(int version)  
 {  
         if (version < 1 || version > 2)  
                 fatal("internal error, bad protocol version %d", version);  
         return &idtable[version];  
 }  
   
 static void  static void
 free_identity(Identity *id)  free_identity(Identity *id)
 {  {
Line 186 
Line 174 
   
 /* return matching private key for given public key */  /* return matching private key for given public key */
 static Identity *  static Identity *
 lookup_identity(struct sshkey *key, int version)  lookup_identity(struct sshkey *key)
 {  {
         Identity *id;          Identity *id;
   
         Idtab *tab = idtab_lookup(version);          TAILQ_FOREACH(id, &idtab->idlist, next) {
         TAILQ_FOREACH(id, &tab->idlist, next) {  
                 if (sshkey_equal(key, id->key))                  if (sshkey_equal(key, id->key))
                         return (id);                          return (id);
         }          }
Line 228 
Line 215 
   
 /* send list of supported public keys to 'client' */  /* send list of supported public keys to 'client' */
 static void  static void
 process_request_identities(SocketEntry *e, int version)  process_request_identities(SocketEntry *e)
 {  {
         Idtab *tab = idtab_lookup(version);  
         Identity *id;          Identity *id;
         struct sshbuf *msg;          struct sshbuf *msg;
         int r;          int r;
         u_char *blob;  
         size_t blen;  
   
         if ((msg = sshbuf_new()) == NULL)          if ((msg = sshbuf_new()) == NULL)
                 fatal("%s: sshbuf_new failed", __func__);                  fatal("%s: sshbuf_new failed", __func__);
         if ((r = sshbuf_put_u8(msg, (version == 1) ?          if ((r = sshbuf_put_u8(msg, SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
             SSH_AGENT_RSA_IDENTITIES_ANSWER :              (r = sshbuf_put_u32(msg, idtab->nentries)) != 0)
             SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||  
             (r = sshbuf_put_u32(msg, tab->nentries)) != 0)  
                 fatal("%s: buffer error: %s", __func__, ssh_err(r));                  fatal("%s: buffer error: %s", __func__, ssh_err(r));
         TAILQ_FOREACH(id, &tab->idlist, next) {          TAILQ_FOREACH(id, &idtab->idlist, next) {
                 if ((r = sshkey_to_blob(id->key, &blob, &blen)) != 0) {                  if ((r = sshkey_puts(id->key, msg)) != 0 ||
                         error("%s: sshkey_to_blob: %s", __func__,                      (r = sshbuf_put_cstring(msg, id->comment)) != 0) {
                           error("%s: put key/comment: %s", __func__,
                             ssh_err(r));                              ssh_err(r));
                         continue;                          continue;
                 }                  }
                 if ((r = sshbuf_put_string(msg, blob, blen)) != 0)  
                         fatal("%s: buffer error: %s",  
                             __func__, ssh_err(r));  
                 free(blob);  
                 if ((r = sshbuf_put_cstring(msg, id->comment)) != 0)  
                         fatal("%s: buffer error: %s", __func__, ssh_err(r));  
         }          }
         if ((r = sshbuf_put_stringb(e->output, msg)) != 0)          if ((r = sshbuf_put_stringb(e->output, msg)) != 0)
                 fatal("%s: buffer error: %s", __func__, ssh_err(r));                  fatal("%s: buffer error: %s", __func__, ssh_err(r));
Line 279 
Line 256 
 static void  static void
 process_sign_request2(SocketEntry *e)  process_sign_request2(SocketEntry *e)
 {  {
         u_char *blob, *data, *signature = NULL;          const u_char *data;
         size_t blen, dlen, slen = 0;          u_char *signature = NULL;
           size_t dlen, slen = 0;
         u_int compat = 0, flags;          u_int compat = 0, flags;
         int r, ok = -1;          int r, ok = -1;
         struct sshbuf *msg;          struct sshbuf *msg;
         struct sshkey *key;          struct sshkey *key = NULL;
         struct identity *id;          struct identity *id;
   
         if ((msg = sshbuf_new()) == NULL)          if ((msg = sshbuf_new()) == NULL)
                 fatal("%s: sshbuf_new failed", __func__);                  fatal("%s: sshbuf_new failed", __func__);
         if ((r = sshbuf_get_string(e->request, &blob, &blen)) != 0 ||          if ((r = sshkey_froms(e->request, &key)) != 0 ||
             (r = sshbuf_get_string(e->request, &data, &dlen)) != 0 ||              (r = sshbuf_get_string_direct(e->request, &data, &dlen)) != 0 ||
             (r = sshbuf_get_u32(e->request, &flags)) != 0)              (r = sshbuf_get_u32(e->request, &flags)) != 0)
                 fatal("%s: buffer error: %s", __func__, ssh_err(r));                  fatal("%s: buffer error: %s", __func__, ssh_err(r));
         if (flags & SSH_AGENT_OLD_SIGNATURE)          if (flags & SSH_AGENT_OLD_SIGNATURE)
                 compat = SSH_BUG_SIGBLOB;                  compat = SSH_BUG_SIGBLOB;
         if ((r = sshkey_from_blob(blob, blen, &key)) != 0) {          if ((id = lookup_identity(key)) == NULL) {
                 error("%s: cannot parse key blob: %s", __func__, ssh_err(r));  
                 goto send;  
         }  
         if ((id = lookup_identity(key, 2)) == NULL) {  
                 verbose("%s: %s key not found", __func__, sshkey_type(key));                  verbose("%s: %s key not found", __func__, sshkey_type(key));
                 goto send;                  goto send;
         }          }
Line 327 
Line 301 
                 fatal("%s: buffer error: %s", __func__, ssh_err(r));                  fatal("%s: buffer error: %s", __func__, ssh_err(r));
   
         sshbuf_free(msg);          sshbuf_free(msg);
         free(data);  
         free(blob);  
         free(signature);          free(signature);
 }  }
   
 /* shared */  /* shared */
 static void  static void
 process_remove_identity(SocketEntry *e, int version)  process_remove_identity(SocketEntry *e)
 {  {
         size_t blen;  
         int r, success = 0;          int r, success = 0;
         struct sshkey *key = NULL;          struct sshkey *key = NULL;
         u_char *blob;          Identity *id;
   
         switch (version) {          if ((r = sshkey_froms(e->request, &key)) != 0) {
         case 2:                  error("%s: get key: %s", __func__, ssh_err(r));
                 if ((r = sshbuf_get_string(e->request, &blob, &blen)) != 0)                  goto done;
                         fatal("%s: buffer error: %s", __func__, ssh_err(r));  
                 if ((r = sshkey_from_blob(blob, blen, &key)) != 0)  
                         error("%s: sshkey_from_blob failed: %s",  
                             __func__, ssh_err(r));  
                 free(blob);  
                 break;  
         }          }
         if (key != NULL) {          if ((id = lookup_identity(key)) == NULL) {
                 Identity *id = lookup_identity(key, version);                  debug("%s: key not found", __func__);
                 if (id != NULL) {                  goto done;
                         /*  
                          * We have this key.  Free the old key.  Since we  
                          * don't want to leave empty slots in the middle of  
                          * the array, we actually free the key there and move  
                          * all the entries between the empty slot and the end  
                          * of the array.  
                          */  
                         Idtab *tab = idtab_lookup(version);  
                         if (tab->nentries < 1)  
                                 fatal("process_remove_identity: "  
                                     "internal error: tab->nentries %d",  
                                     tab->nentries);  
                         TAILQ_REMOVE(&tab->idlist, id, next);  
                         free_identity(id);  
                         tab->nentries--;  
                         success = 1;  
                 }  
                 sshkey_free(key);  
         }          }
           /* We have this key, free it. */
           if (idtab->nentries < 1)
                   fatal("%s: internal error: nentries %d",
                       __func__, idtab->nentries);
           TAILQ_REMOVE(&idtab->idlist, id, next);
           free_identity(id);
           idtab->nentries--;
           sshkey_free(key);
           success = 1;
    done:
         send_status(e, success);          send_status(e, success);
 }  }
   
 static void  static void
 process_remove_all_identities(SocketEntry *e, int version)  process_remove_all_identities(SocketEntry *e)
 {  {
         Idtab *tab = idtab_lookup(version);  
         Identity *id;          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 (id = TAILQ_FIRST(&idtab->idlist); id;
             id = TAILQ_FIRST(&tab->idlist)) {              id = TAILQ_FIRST(&idtab->idlist)) {
                 TAILQ_REMOVE(&tab->idlist, id, next);                  TAILQ_REMOVE(&idtab->idlist, id, next);
                 free_identity(id);                  free_identity(id);
         }          }
   
         /* Mark that there are no identities. */          /* Mark that there are no identities. */
         tab->nentries = 0;          idtab->nentries = 0;
   
         /* Send success. */          /* Send success. */
         send_status(e, 1);          send_status(e, 1);
Line 402 
Line 358 
 {  {
         time_t deadline = 0, now = monotime();          time_t deadline = 0, now = monotime();
         Identity *id, *nxt;          Identity *id, *nxt;
         int version;  
         Idtab *tab;  
   
         for (version = 1; version < 3; version++) {          for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
                 tab = idtab_lookup(version);                  nxt = TAILQ_NEXT(id, next);
                 for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {                  if (id->death == 0)
                         nxt = TAILQ_NEXT(id, next);                          continue;
                         if (id->death == 0)                  if (now >= id->death) {
                                 continue;                          debug("expiring key '%s'", id->comment);
                         if (now >= id->death) {                          TAILQ_REMOVE(&idtab->idlist, id, next);
                                 debug("expiring key '%s'", id->comment);                          free_identity(id);
                                 TAILQ_REMOVE(&tab->idlist, id, next);                          idtab->nentries--;
                                 free_identity(id);                  } else
                                 tab->nentries--;                          deadline = (deadline == 0) ? id->death :
                         } else                              MINIMUM(deadline, id->death);
                                 deadline = (deadline == 0) ? id->death :  
                                     MINIMUM(deadline, id->death);  
                 }  
         }          }
         if (deadline == 0 || deadline <= now)          if (deadline == 0 || deadline <= now)
                 return 0;                  return 0;
Line 427 
Line 378 
                 return (deadline - now);                  return (deadline - now);
 }  }
   
 /*  
  * XXX this and the corresponding serialisation function probably belongs  
  * in key.c  
  */  
   
 static void  static void
 process_add_identity(SocketEntry *e, int version)  process_add_identity(SocketEntry *e)
 {  {
         Idtab *tab = idtab_lookup(version);  
         Identity *id;          Identity *id;
         int success = 0, confirm = 0;          int success = 0, confirm = 0;
         u_int seconds;          u_int seconds;
Line 445 
Line 390 
         u_char ctype;          u_char ctype;
         int r = SSH_ERR_INTERNAL_ERROR;          int r = SSH_ERR_INTERNAL_ERROR;
   
         switch (version) {          if ((r = sshkey_private_deserialize(e->request, &k)) != 0 ||
         case 2:              k == NULL ||
                 r = sshkey_private_deserialize(e->request, &k);  
                 break;  
         }  
         if (r != 0 || k == NULL ||  
             (r = sshbuf_get_cstring(e->request, &comment, NULL)) != 0) {              (r = sshbuf_get_cstring(e->request, &comment, NULL)) != 0) {
                 error("%s: decode private key: %s", __func__, ssh_err(r));                  error("%s: decode private key: %s", __func__, ssh_err(r));
                 goto err;                  goto err;
Line 486 
Line 427 
         success = 1;          success = 1;
         if (lifetime && !death)          if (lifetime && !death)
                 death = monotime() + lifetime;                  death = monotime() + lifetime;
         if ((id = lookup_identity(k, version)) == NULL) {          if ((id = lookup_identity(k)) == NULL) {
                 id = xcalloc(1, sizeof(Identity));                  id = xcalloc(1, sizeof(Identity));
                 id->key = k;                  id->key = k;
                 TAILQ_INSERT_TAIL(&tab->idlist, id, next);                  TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
                 /* Increment the number of identities. */                  /* Increment the number of identities. */
                 tab->nentries++;                  idtab->nentries++;
         } else {          } else {
                 sshkey_free(k);                  sshkey_free(k);
                 free(id->comment);                  free(id->comment);
Line 552 
Line 493 
 }  }
   
 static void  static void
 no_identities(SocketEntry *e, u_int type)  no_identities(SocketEntry *e)
 {  {
         struct sshbuf *msg;          struct sshbuf *msg;
         int r;          int r;
   
         if ((msg = sshbuf_new()) == NULL)          if ((msg = sshbuf_new()) == NULL)
                 fatal("%s: sshbuf_new failed", __func__);                  fatal("%s: sshbuf_new failed", __func__);
         if ((r = sshbuf_put_u8(msg,          if ((r = sshbuf_put_u8(msg, SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||
             (type == SSH_AGENTC_REQUEST_RSA_IDENTITIES) ?  
             SSH_AGENT_RSA_IDENTITIES_ANSWER :  
             SSH2_AGENT_IDENTITIES_ANSWER)) != 0 ||  
             (r = sshbuf_put_u32(msg, 0)) != 0 ||              (r = sshbuf_put_u32(msg, 0)) != 0 ||
             (r = sshbuf_put_stringb(e->output, msg)) != 0)              (r = sshbuf_put_stringb(e->output, msg)) != 0)
                 fatal("%s: buffer error: %s", __func__, ssh_err(r));                  fatal("%s: buffer error: %s", __func__, ssh_err(r));
Line 574 
Line 512 
 process_add_smartcard_key(SocketEntry *e)  process_add_smartcard_key(SocketEntry *e)
 {  {
         char *provider = NULL, *pin, canonical_provider[PATH_MAX];          char *provider = NULL, *pin, canonical_provider[PATH_MAX];
         int r, i, version, count = 0, success = 0, confirm = 0;          int r, i, count = 0, success = 0, confirm = 0;
         u_int seconds;          u_int seconds;
         time_t death = 0;          time_t death = 0;
         u_char type;          u_char type;
         struct sshkey **keys = NULL, *k;          struct sshkey **keys = NULL, *k;
         Identity *id;          Identity *id;
         Idtab *tab;  
   
         if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||          if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
             (r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0)              (r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0)
Line 600 
Line 537 
                         confirm = 1;                          confirm = 1;
                         break;                          break;
                 default:                  default:
                         error("process_add_smartcard_key: "                          error("%s: Unknown constraint type %d", __func__, type);
                             "Unknown constraint type %d", type);  
                         goto send;                          goto send;
                 }                  }
         }          }
Line 622 
Line 558 
         count = pkcs11_add_provider(canonical_provider, pin, &keys);          count = pkcs11_add_provider(canonical_provider, pin, &keys);
         for (i = 0; i < count; i++) {          for (i = 0; i < count; i++) {
                 k = keys[i];                  k = keys[i];
                 version = 2;                  if (lookup_identity(k) == NULL) {
                 tab = idtab_lookup(version);  
                 if (lookup_identity(k, version) == NULL) {  
                         id = xcalloc(1, sizeof(Identity));                          id = xcalloc(1, sizeof(Identity));
                         id->key = k;                          id->key = k;
                         id->provider = xstrdup(canonical_provider);                          id->provider = xstrdup(canonical_provider);
                         id->comment = xstrdup(canonical_provider); /* XXX */                          id->comment = xstrdup(canonical_provider); /* XXX */
                         id->death = death;                          id->death = death;
                         id->confirm = confirm;                          id->confirm = confirm;
                         TAILQ_INSERT_TAIL(&tab->idlist, id, next);                          TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
                         tab->nentries++;                          idtab->nentries++;
                         success = 1;                          success = 1;
                 } else {                  } else {
                         sshkey_free(k);                          sshkey_free(k);
Line 650 
Line 584 
 process_remove_smartcard_key(SocketEntry *e)  process_remove_smartcard_key(SocketEntry *e)
 {  {
         char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];          char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
         int r, version, success = 0;          int r, success = 0;
         Identity *id, *nxt;          Identity *id, *nxt;
         Idtab *tab;  
   
         if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||          if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 ||
             (r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0)              (r = sshbuf_get_cstring(e->request, &pin, NULL)) != 0)
Line 666 
Line 599 
         }          }
   
         debug("%s: remove %.100s", __func__, canonical_provider);          debug("%s: remove %.100s", __func__, canonical_provider);
         for (version = 1; version < 3; version++) {          for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
                 tab = idtab_lookup(version);                  nxt = TAILQ_NEXT(id, next);
                 for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {                  /* Skip file--based keys */
                         nxt = TAILQ_NEXT(id, next);                  if (id->provider == NULL)
                         /* Skip file--based keys */                          continue;
                         if (id->provider == NULL)                  if (!strcmp(canonical_provider, id->provider)) {
                                 continue;                          TAILQ_REMOVE(&idtab->idlist, id, next);
                         if (!strcmp(canonical_provider, id->provider)) {                          free_identity(id);
                                 TAILQ_REMOVE(&tab->idlist, id, next);                          idtab->nentries--;
                                 free_identity(id);  
                                 tab->nentries--;  
                         }  
                 }                  }
         }          }
         if (pkcs11_del_provider(canonical_provider) == 0)          if (pkcs11_del_provider(canonical_provider) == 0)
                 success = 1;                  success = 1;
         else          else
                 error("process_remove_smartcard_key:"                  error("%s: pkcs11_del_provider failed", __func__);
                     " pkcs11_del_provider failed");  
 send:  send:
         free(provider);          free(provider);
         send_status(e, success);          send_status(e, success);
Line 722 
Line 651 
         if (locked && type != SSH_AGENTC_UNLOCK) {          if (locked && type != SSH_AGENTC_UNLOCK) {
                 sshbuf_reset(e->request);                  sshbuf_reset(e->request);
                 switch (type) {                  switch (type) {
                 case SSH_AGENTC_REQUEST_RSA_IDENTITIES:  
                 case SSH2_AGENTC_REQUEST_IDENTITIES:                  case SSH2_AGENTC_REQUEST_IDENTITIES:
                         /* send empty lists */                          /* send empty lists */
                         no_identities(e, type);                          no_identities(e);
                         break;                          break;
                 default:                  default:
                         /* send a fail message for all other request types */                          /* send a fail message for all other request types */
Line 741 
Line 669 
                 process_lock_agent(e, type == SSH_AGENTC_LOCK);                  process_lock_agent(e, type == SSH_AGENTC_LOCK);
                 break;                  break;
         case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:          case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
                 process_remove_all_identities(e, 1); /* safe for !WITH_SSH1 */                  process_remove_all_identities(e); /* safe for !WITH_SSH1 */
                 break;                  break;
         /* ssh2 */          /* ssh2 */
         case SSH2_AGENTC_SIGN_REQUEST:          case SSH2_AGENTC_SIGN_REQUEST:
                 process_sign_request2(e);                  process_sign_request2(e);
                 break;                  break;
         case SSH2_AGENTC_REQUEST_IDENTITIES:          case SSH2_AGENTC_REQUEST_IDENTITIES:
                 process_request_identities(e, 2);                  process_request_identities(e);
                 break;                  break;
         case SSH2_AGENTC_ADD_IDENTITY:          case SSH2_AGENTC_ADD_IDENTITY:
         case SSH2_AGENTC_ADD_ID_CONSTRAINED:          case SSH2_AGENTC_ADD_ID_CONSTRAINED:
                 process_add_identity(e, 2);                  process_add_identity(e);
                 break;                  break;
         case SSH2_AGENTC_REMOVE_IDENTITY:          case SSH2_AGENTC_REMOVE_IDENTITY:
                 process_remove_identity(e, 2);                  process_remove_identity(e);
                 break;                  break;
         case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:          case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
                 process_remove_all_identities(e, 2);                  process_remove_all_identities(e);
                 break;                  break;
 #ifdef ENABLE_PKCS11  #ifdef ENABLE_PKCS11
         case SSH_AGENTC_ADD_SMARTCARD_KEY:          case SSH_AGENTC_ADD_SMARTCARD_KEY:

Legend:
Removed from v.1.220  
changed lines
  Added in v.1.221