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

Diff for /src/usr.bin/ssh/sshconnect2.c between version 1.116 and 1.117

version 1.116, 2003/04/08 20:21:29 version 1.117, 2003/05/12 16:55:37
Line 141 
Line 141 
   
 typedef struct Authctxt Authctxt;  typedef struct Authctxt Authctxt;
 typedef struct Authmethod Authmethod;  typedef struct Authmethod Authmethod;
   typedef struct identity Identity;
   typedef struct idlist Idlist;
   
 typedef int sign_cb_fn(  struct identity {
     Authctxt *authctxt, Key *key,          TAILQ_ENTRY(identity) next;
     u_char **sigp, u_int *lenp, u_char *data, u_int datalen);          AuthenticationConnection *ac;   /* set if agent supports key */
           Key     *key;                   /* public/private key */
           char    *filename;              /* comment for agent-only keys */
           int     tried;
           int     isprivate;              /* key points to the private key */
   };
   TAILQ_HEAD(idlist, identity);
   
 struct Authctxt {  struct Authctxt {
         const char *server_user;          const char *server_user;
Line 155 
Line 163 
         int success;          int success;
         char *authlist;          char *authlist;
         /* pubkey */          /* pubkey */
         Key *last_key;          Idlist keys;
         sign_cb_fn *last_key_sign;  
         int last_key_hint;  
         AuthenticationConnection *agent;          AuthenticationConnection *agent;
         /* hostbased */          /* hostbased */
         Sensitive *sensitive;          Sensitive *sensitive;
Line 187 
Line 193 
   
 void    userauth(Authctxt *, char *);  void    userauth(Authctxt *, char *);
   
 static int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *);  static int sign_and_send_pubkey(Authctxt *, Identity *);
 static void clear_auth_state(Authctxt *);  static void clear_auth_state(Authctxt *);
   static void pubkey_prepare(Authctxt *);
   static void pubkey_cleanup(Authctxt *);
   static Key *load_identity_file(char *);
   
 static Authmethod *authmethod_get(char *authlist);  static Authmethod *authmethod_get(char *authlist);
 static Authmethod *authmethod_lookup(const char *name);  static Authmethod *authmethod_lookup(const char *name);
Line 251 
Line 260 
   
         /* setup authentication context */          /* setup authentication context */
         memset(&authctxt, 0, sizeof(authctxt));          memset(&authctxt, 0, sizeof(authctxt));
         authctxt.agent = ssh_get_authentication_connection();          pubkey_prepare(&authctxt);
         authctxt.server_user = server_user;          authctxt.server_user = server_user;
         authctxt.local_user = local_user;          authctxt.local_user = local_user;
         authctxt.host = host;          authctxt.host = host;
Line 273 
Line 282 
         dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);          dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner);
         dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt);     /* loop until success */          dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt);     /* loop until success */
   
         if (authctxt.agent != NULL)          pubkey_cleanup(&authctxt);
                 ssh_close_authentication_connection(authctxt.agent);  
   
         debug("Authentication succeeded (%s).", authctxt.method->name);          debug("Authentication succeeded (%s).", authctxt.method->name);
 }  }
 void  void
Line 360 
Line 367 
 {  {
         Authctxt *authctxt = ctxt;          Authctxt *authctxt = ctxt;
         Key *key = NULL;          Key *key = NULL;
           Identity *id = NULL;
         Buffer b;          Buffer b;
         int pktype, sent = 0;          int pktype, sent = 0;
         u_int alen, blen;          u_int alen, blen;
Line 382 
Line 390 
         }          }
         packet_check_eom();          packet_check_eom();
   
         debug("Server accepts key: pkalg %s blen %u lastkey %p hint %d",          debug("Server accepts key: pkalg %s blen %u", pkalg, blen);
             pkalg, blen, authctxt->last_key, authctxt->last_key_hint);  
   
         do {          if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
                 if (authctxt->last_key == NULL ||                  debug("unknown pkalg %s", pkalg);
                     authctxt->last_key_sign == NULL) {                  goto done;
                         debug("no last key or no sign cb");          }
           if ((key = key_from_blob(pkblob, blen)) == NULL) {
                   debug("no key from blob. pkalg %s", pkalg);
                   goto done;
           }
           if (key->type != pktype) {
                   error("input_userauth_pk_ok: type mismatch "
                       "for decoded key (received %d, expected %d)",
                       key->type, pktype);
                   goto done;
           }
           fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
           debug2("input_userauth_pk_ok: fp %s", fp);
           xfree(fp);
   
           TAILQ_FOREACH(id, &authctxt->keys, next) {
                   if (key_equal(key, id->key)) {
                           sent = sign_and_send_pubkey(authctxt, id);
                         break;                          break;
                 }                  }
                 if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {          }
                         debug("unknown pkalg %s", pkalg);  done:
                         break;  
                 }  
                 if ((key = key_from_blob(pkblob, blen)) == NULL) {  
                         debug("no key from blob. pkalg %s", pkalg);  
                         break;  
                 }  
                 if (key->type != pktype) {  
                         error("input_userauth_pk_ok: type mismatch "  
                             "for decoded key (received %d, expected %d)",  
                             key->type, pktype);  
                         break;  
                 }  
                 fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);  
                 debug2("input_userauth_pk_ok: fp %s", fp);  
                 xfree(fp);  
                 if (!key_equal(key, authctxt->last_key)) {  
                         debug("key != last_key");  
                         break;  
                 }  
                 sent = sign_and_send_pubkey(authctxt, key,  
                    authctxt->last_key_sign);  
         } while (0);  
   
         if (key != NULL)          if (key != NULL)
                 key_free(key);                  key_free(key);
         xfree(pkalg);          xfree(pkalg);
Line 428 
Line 429 
         /* try another method if we did not send a packet */          /* try another method if we did not send a packet */
         if (sent == 0)          if (sent == 0)
                 userauth(authctxt, NULL);                  userauth(authctxt, NULL);
   
 }  }
   
 int  int
Line 547 
Line 547 
 {  {
         /* XXX clear authentication state */          /* XXX clear authentication state */
         dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL);          dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL);
   }
   
         if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {  static int
                 debug3("clear_auth_state: key_free %p", authctxt->last_key);  identity_sign(Identity *id, u_char **sigp, u_int *lenp,
                 key_free(authctxt->last_key);      u_char *data, u_int datalen)
         }  {
         authctxt->last_key = NULL;          Key *prv;
         authctxt->last_key_hint = -2;          int ret;
         authctxt->last_key_sign = NULL;  
           /* the agent supports this key */
           if (id->ac)
                   return (ssh_agent_sign(id->ac, id->key, sigp, lenp,
                       data, datalen));
           /*
            * we have already loaded the private key or
            * the private key is stored in external hardware
            */
           if (id->isprivate || (id->key->flags & KEY_FLAG_EXT))
                   return (key_sign(id->key, sigp, lenp, data, datalen));
           /* load the private key from the file */
           if ((prv = load_identity_file(id->filename)) == NULL)
                   return (-1);
           ret = key_sign(prv, sigp, lenp, data, datalen);
           key_free(prv);
           return (ret);
 }  }
   
 static int  static int
 sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)  sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
 {  {
         Buffer b;          Buffer b;
         u_char *blob, *signature;          u_char *blob, *signature;
Line 569 
Line 586 
   
         debug3("sign_and_send_pubkey");          debug3("sign_and_send_pubkey");
   
         if (key_to_blob(k, &blob, &bloblen) == 0) {          if (key_to_blob(id->key, &blob, &bloblen) == 0) {
                 /* we cannot handle this key */                  /* we cannot handle this key */
                 debug3("sign_and_send_pubkey: cannot handle key");                  debug3("sign_and_send_pubkey: cannot handle key");
                 return 0;                  return 0;
Line 594 
Line 611 
         } else {          } else {
                 buffer_put_cstring(&b, authctxt->method->name);                  buffer_put_cstring(&b, authctxt->method->name);
                 buffer_put_char(&b, have_sig);                  buffer_put_char(&b, have_sig);
                 buffer_put_cstring(&b, key_ssh_name(k));                  buffer_put_cstring(&b, key_ssh_name(id->key));
         }          }
         buffer_put_string(&b, blob, bloblen);          buffer_put_string(&b, blob, bloblen);
   
         /* generate signature */          /* generate signature */
         ret = (*sign_callback)(authctxt, k, &signature, &slen,          ret = identity_sign(id, &signature, &slen,
             buffer_ptr(&b), buffer_len(&b));              buffer_ptr(&b), buffer_len(&b));
         if (ret == -1) {          if (ret == -1) {
                 xfree(blob);                  xfree(blob);
Line 619 
Line 636 
                 buffer_put_cstring(&b, authctxt->method->name);                  buffer_put_cstring(&b, authctxt->method->name);
                 buffer_put_char(&b, have_sig);                  buffer_put_char(&b, have_sig);
                 if (!(datafellows & SSH_BUG_PKAUTH))                  if (!(datafellows & SSH_BUG_PKAUTH))
                         buffer_put_cstring(&b, key_ssh_name(k));                          buffer_put_cstring(&b, key_ssh_name(id->key));
                 buffer_put_string(&b, blob, bloblen);                  buffer_put_string(&b, blob, bloblen);
         }          }
         xfree(blob);          xfree(blob);
Line 643 
Line 660 
 }  }
   
 static int  static int
 send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,  send_pubkey_test(Authctxt *authctxt, Identity *id)
     int hint)  
 {  {
         u_char *blob;          u_char *blob;
         u_int bloblen, have_sig = 0;          u_int bloblen, have_sig = 0;
   
         debug3("send_pubkey_test");          debug3("send_pubkey_test");
   
         if (key_to_blob(k, &blob, &bloblen) == 0) {          if (key_to_blob(id->key, &blob, &bloblen) == 0) {
                 /* we cannot handle this key */                  /* we cannot handle this key */
                 debug3("send_pubkey_test: cannot handle key");                  debug3("send_pubkey_test: cannot handle key");
                 return 0;                  return 0;
         }          }
         /* register callback for USERAUTH_PK_OK message */          /* register callback for USERAUTH_PK_OK message */
         authctxt->last_key_sign = sign_callback;  
         authctxt->last_key_hint = hint;  
         authctxt->last_key = k;  
         dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);          dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok);
   
         packet_start(SSH2_MSG_USERAUTH_REQUEST);          packet_start(SSH2_MSG_USERAUTH_REQUEST);
Line 668 
Line 681 
         packet_put_cstring(authctxt->method->name);          packet_put_cstring(authctxt->method->name);
         packet_put_char(have_sig);          packet_put_char(have_sig);
         if (!(datafellows & SSH_BUG_PKAUTH))          if (!(datafellows & SSH_BUG_PKAUTH))
                 packet_put_cstring(key_ssh_name(k));                  packet_put_cstring(key_ssh_name(id->key));
         packet_put_string(blob, bloblen);          packet_put_string(blob, bloblen);
         xfree(blob);          xfree(blob);
         packet_send();          packet_send();
Line 713 
Line 726 
         return private;          return private;
 }  }
   
 static int  /*
 identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,   * try keys in the following order:
     u_char *data, u_int datalen)   *      1. agent keys that are found in the config file
    *      2. other agent keys
    *      3. keys that are only listed in the config file
    */
   static void
   pubkey_prepare(Authctxt *authctxt)
 {  {
         Key *private;          Identity *id;
         int idx, ret;          Idlist agent, files, *preferred;
           Key *key;
           AuthenticationConnection *ac;
           char *comment;
           int i, found;
   
         idx = authctxt->last_key_hint;          TAILQ_INIT(&agent);     /* keys from the agent */
         if (idx < 0)          TAILQ_INIT(&files);     /* keys from the config file */
                 return -1;          preferred = &authctxt->keys;
           TAILQ_INIT(preferred);  /* preferred order of keys */
   
         /* private key is stored in external hardware */          /* list of keys stored in the filesystem */
         if (options.identity_keys[idx]->flags & KEY_FLAG_EXT)          for (i = 0; i < options.num_identity_files; i++) {
                 return key_sign(options.identity_keys[idx], sigp, lenp, data, datalen);                  key = options.identity_keys[i];
                   if (key && key->type == KEY_RSA1)
         private = load_identity_file(options.identity_files[idx]);                          continue;
         if (private == NULL)                  options.identity_keys[i] = NULL;
                 return -1;                  id = xmalloc(sizeof(*id));
         ret = key_sign(private, sigp, lenp, data, datalen);                  memset(id, 0, sizeof(*id));
         key_free(private);                  id->key = key;
         return ret;                  id->filename = xstrdup(options.identity_files[i]);
                   TAILQ_INSERT_TAIL(&files, id, next);
           }
           /* list of keys supported by the agent */
           if ((ac = ssh_get_authentication_connection())) {
                   for (key = ssh_get_first_identity(ac, &comment, 2);
                       key != NULL;
                       key = ssh_get_next_identity(ac, &comment, 2)) {
                           found = 0;
                           TAILQ_FOREACH(id, &files, next) {
                                   /* agent keys from the config file are preferred */
                                   if (key_equal(key, id->key)) {
                                           key_free(key);
                                           xfree(comment);
                                           TAILQ_REMOVE(&files, id, next);
                                           TAILQ_INSERT_TAIL(preferred, id, next);
                                           id->ac = ac;
                                           found = 1;
                                           break;
                                   }
                           }
                           if (!found) {
                                   id = xmalloc(sizeof(*id));
                                   memset(id, 0, sizeof(*id));
                                   id->key = key;
                                   id->filename = comment;
                                   id->ac = ac;
                                   TAILQ_INSERT_TAIL(&agent, id, next);
                           }
                   }
                   /* append remaining agent keys */
                   for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) {
                           TAILQ_REMOVE(&agent, id, next);
                           TAILQ_INSERT_TAIL(preferred, id, next);
                   }
                   authctxt->agent = ac;
           }
           /* append remaining keys from the config file */
           for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) {
                   TAILQ_REMOVE(&files, id, next);
                   TAILQ_INSERT_TAIL(preferred, id, next);
           }
           TAILQ_FOREACH(id, preferred, next) {
                   debug2("key: %s (%p)", id->filename, id->key);
           }
 }  }
   
 static int  static void
 agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,  pubkey_cleanup(Authctxt *authctxt)
     u_char *data, u_int datalen)  
 {  {
         return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);          Identity *id;
 }  
   
 static int          if (authctxt->agent != NULL)
 key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,                  ssh_close_authentication_connection(authctxt->agent);
     u_char *data, u_int datalen)          for (id = TAILQ_FIRST(&authctxt->keys); id;
 {              id = TAILQ_FIRST(&authctxt->keys)) {
         return key_sign(key, sigp, lenp, data, datalen);                  TAILQ_REMOVE(&authctxt->keys, id, next);
 }                  if (id->key)
                           key_free(id->key);
 static int                  if (id->filename)
 userauth_pubkey_agent(Authctxt *authctxt)                          xfree(id->filename);
 {                  xfree(id);
         static int called = 0;  
         int ret = 0;  
         char *comment;  
         Key *k;  
   
         if (called == 0) {  
                 if (ssh_get_num_identities(authctxt->agent, 2) == 0)  
                         debug2("userauth_pubkey_agent: no keys at all");  
                 called = 1;  
         }          }
         k = ssh_get_next_identity(authctxt->agent, &comment, 2);  
         if (k == NULL) {  
                 debug2("userauth_pubkey_agent: no more keys");  
         } else {  
                 debug("Offering agent key: %s", comment);  
                 xfree(comment);  
                 ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1);  
                 if (ret == 0)  
                         key_free(k);  
         }  
         if (ret == 0)  
                 debug2("userauth_pubkey_agent: no message sent");  
         return ret;  
 }  }
   
 int  int
 userauth_pubkey(Authctxt *authctxt)  userauth_pubkey(Authctxt *authctxt)
 {  {
         static int idx = 0;          Identity *id;
         int sent = 0;          int sent = 0;
         Key *key;  
         char *filename;  
   
         if (authctxt->agent != NULL) {          while ((id = TAILQ_FIRST(&authctxt->keys))) {
                 do {                  if (id->tried++)
                         sent = userauth_pubkey_agent(authctxt);                          return (0);
                 } while (!sent && authctxt->agent->howmany > 0);                  TAILQ_REMOVE(&authctxt->keys, id, next);
         }                  TAILQ_INSERT_TAIL(&authctxt->keys, id, next);
         while (!sent && idx < options.num_identity_files) {                  /*
                 key = options.identity_keys[idx];                   * send a test message if we have the public key. for
                 filename = options.identity_files[idx];                   * encrypted keys we cannot do this and have to load the
                 if (key == NULL) {                   * private key instead
                         debug("Trying private key: %s", filename);                   */
                         key = load_identity_file(filename);                  if (id->key && id->key->type != KEY_RSA1) {
                         if (key != NULL) {                          debug("Offering public key: %s", id->filename);
                                 sent = sign_and_send_pubkey(authctxt, key,                          sent = send_pubkey_test(authctxt, id);
                                     key_sign_cb);                  } else if (id->key == NULL) {
                                 key_free(key);                          debug("Trying private key: %s", id->filename);
                           id->key = load_identity_file(id->filename);
                           if (id->key != NULL) {
                                   id->isprivate = 1;
                                   sent = sign_and_send_pubkey(authctxt, id);
                                   key_free(id->key);
                                   id->key = NULL;
                         }                          }
                 } else if (key->type != KEY_RSA1) {  
                         debug("Offering public key: %s", filename);  
                         sent = send_pubkey_test(authctxt, key,  
                             identity_sign_cb, idx);  
                 }                  }
                 idx++;                  if (sent)
                           return (sent);
         }          }
         return sent;          return (0);
 }  }
   
 /*  /*

Legend:
Removed from v.1.116  
changed lines
  Added in v.1.117