[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.107 and 1.107.2.2

version 1.107, 2002/07/01 19:48:46 version 1.107.2.2, 2003/09/16 21:20:29
Line 48 
Line 48 
 #include "msg.h"  #include "msg.h"
 #include "pathnames.h"  #include "pathnames.h"
   
   #ifdef GSSAPI
   #include "ssh-gss.h"
   #endif
   
 /* import */  /* import */
 extern char *client_version_string;  extern char *client_version_string;
 extern char *server_version_string;  extern char *server_version_string;
Line 58 
Line 62 
  */   */
   
 u_char *session_id2 = NULL;  u_char *session_id2 = NULL;
 int session_id2_len = 0;  u_int session_id2_len = 0;
   
 char *xxx_host;  char *xxx_host;
 struct sockaddr *xxx_hostaddr;  struct sockaddr *xxx_hostaddr;
Line 82 
Line 86 
         xxx_hostaddr = hostaddr;          xxx_hostaddr = hostaddr;
   
         if (options.ciphers == (char *)-1) {          if (options.ciphers == (char *)-1) {
                 log("No valid ciphers for protocol version 2 given, using defaults.");                  logit("No valid ciphers for protocol version 2 given, using defaults.");
                 options.ciphers = NULL;                  options.ciphers = NULL;
         }          }
         if (options.ciphers != NULL) {          if (options.ciphers != NULL) {
Line 108 
Line 112 
                 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =                  myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
                     options.hostkeyalgorithms;                      options.hostkeyalgorithms;
   
           if (options.rekey_limit)
                   packet_set_rekey_limit(options.rekey_limit);
   
         /* start key exchange */          /* start key exchange */
         kex = kex_setup(myproposal);          kex = kex_setup(myproposal);
           kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
           kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
         kex->client_version_string=client_version_string;          kex->client_version_string=client_version_string;
         kex->server_version_string=server_version_string;          kex->server_version_string=server_version_string;
         kex->verify_host_key=&verify_host_key_callback;          kex->verify_host_key=&verify_host_key_callback;
Line 128 
Line 137 
         packet_send();          packet_send();
         packet_write_wait();          packet_write_wait();
 #endif  #endif
         debug("done: ssh_kex2.");  
 }  }
   
 /*  /*
Line 137 
Line 145 
   
 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 151 
Line 167 
         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;
         /* kbd-interactive */          /* kbd-interactive */
         int info_req_seen;          int info_req_seen;
           /* generic */
           void *methoddata;
 };  };
 struct Authmethod {  struct Authmethod {
         char    *name;          /* string to compare against server's list */          char    *name;          /* string to compare against server's list */
Line 180 
Line 196 
 int     userauth_passwd(Authctxt *);  int     userauth_passwd(Authctxt *);
 int     userauth_kbdint(Authctxt *);  int     userauth_kbdint(Authctxt *);
 int     userauth_hostbased(Authctxt *);  int     userauth_hostbased(Authctxt *);
   int     userauth_kerberos(Authctxt *);
   
   #ifdef GSSAPI
   int     userauth_gssapi(Authctxt *authctxt);
   void    input_gssapi_response(int type, u_int32_t, void *);
   void    input_gssapi_token(int type, u_int32_t, void *);
   void    input_gssapi_hash(int type, u_int32_t, void *);
   void    input_gssapi_error(int, u_int32_t, void *);
   void    input_gssapi_errtok(int, u_int32_t, void *);
   #endif
   
 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 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);
 static char *authmethods_get(void);  static char *authmethods_get(void);
   
 Authmethod authmethods[] = {  Authmethod authmethods[] = {
   #ifdef GSSAPI
           {"gssapi",
                   userauth_gssapi,
                   &options.gss_authentication,
                   NULL},
   #endif
         {"hostbased",          {"hostbased",
                 userauth_hostbased,                  userauth_hostbased,
                 &options.hostbased_authentication,                  &options.hostbased_authentication,
Line 224 
Line 258 
         if (options.challenge_response_authentication)          if (options.challenge_response_authentication)
                 options.kbd_interactive_authentication = 1;                  options.kbd_interactive_authentication = 1;
   
         debug("send SSH2_MSG_SERVICE_REQUEST");  
         packet_start(SSH2_MSG_SERVICE_REQUEST);          packet_start(SSH2_MSG_SERVICE_REQUEST);
         packet_put_cstring("ssh-userauth");          packet_put_cstring("ssh-userauth");
         packet_send();          packet_send();
           debug("SSH2_MSG_SERVICE_REQUEST sent");
         packet_write_wait();          packet_write_wait();
         type = packet_read();          type = packet_read();
         if (type != SSH2_MSG_SERVICE_ACCEPT) {          if (type != SSH2_MSG_SERVICE_ACCEPT)
                 fatal("denied SSH2_MSG_SERVICE_ACCEPT: %d", type);                  fatal("Server denied authentication request: %d", type);
         }  
         if (packet_remaining() > 0) {          if (packet_remaining() > 0) {
                 char *reply = packet_get_string(NULL);                  char *reply = packet_get_string(NULL);
                 debug("service_accept: %s", reply);                  debug2("service_accept: %s", reply);
                 xfree(reply);                  xfree(reply);
         } else {          } else {
                 debug("buggy server: service_accept w/o service");                  debug2("buggy server: service_accept w/o service");
         }          }
         packet_check_eom();          packet_check_eom();
         debug("got SSH2_MSG_SERVICE_ACCEPT");          debug("SSH2_MSG_SERVICE_ACCEPT received");
   
         if (options.preferred_authentications == NULL)          if (options.preferred_authentications == NULL)
                 options.preferred_authentications = authmethods_get();                  options.preferred_authentications = authmethods_get();
   
         /* 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 256 
Line 289 
         authctxt.success = 0;          authctxt.success = 0;
         authctxt.method = authmethod_lookup("none");          authctxt.method = authmethod_lookup("none");
         authctxt.authlist = NULL;          authctxt.authlist = NULL;
           authctxt.methoddata = NULL;
         authctxt.sensitive = sensitive;          authctxt.sensitive = sensitive;
         authctxt.info_req_seen = 0;          authctxt.info_req_seen = 0;
         if (authctxt.method == NULL)          if (authctxt.method == NULL)
Line 270 
Line 304 
         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);          dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL);
   
         debug("ssh-userauth2 successful: method %s", authctxt.method->name);          debug("Authentication succeeded (%s).", authctxt.method->name);
 }  }
   
 void  void
 userauth(Authctxt *authctxt, char *authlist)  userauth(Authctxt *authctxt, char *authlist)
 {  {
           if (authctxt->methoddata) {
                   xfree(authctxt->methoddata);
                   authctxt->methoddata = NULL;
           }
         if (authlist == NULL) {          if (authlist == NULL) {
                 authlist = authctxt->authlist;                  authlist = authctxt->authlist;
         } else {          } else {
Line 290 
Line 329 
                 if (method == NULL)                  if (method == NULL)
                         fatal("Permission denied (%s).", authlist);                          fatal("Permission denied (%s).", authlist);
                 authctxt->method = method;                  authctxt->method = method;
   
                   /* reset the per method handler */
                   dispatch_range(SSH2_MSG_USERAUTH_PER_METHOD_MIN,
                       SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL);
   
                   /* and try new method */
                 if (method->userauth(authctxt) != 0) {                  if (method->userauth(authctxt) != 0) {
                         debug2("we sent a %s packet, wait for reply", method->name);                          debug2("we sent a %s packet, wait for reply", method->name);
                         break;                          break;
Line 314 
Line 359 
         debug3("input_userauth_banner");          debug3("input_userauth_banner");
         msg = packet_get_string(NULL);          msg = packet_get_string(NULL);
         lang = packet_get_string(NULL);          lang = packet_get_string(NULL);
         fprintf(stderr, "%s", msg);          logit("%s", msg);
         xfree(msg);          xfree(msg);
         xfree(lang);          xfree(lang);
 }  }
Line 327 
Line 372 
                 fatal("input_userauth_success: no authentication context");                  fatal("input_userauth_success: no authentication context");
         if (authctxt->authlist)          if (authctxt->authlist)
                 xfree(authctxt->authlist);                  xfree(authctxt->authlist);
         clear_auth_state(authctxt);          if (authctxt->methoddata)
                   xfree(authctxt->methoddata);
         authctxt->success = 1;                  /* break out */          authctxt->success = 1;                  /* break out */
 }  }
   
Line 346 
Line 392 
         packet_check_eom();          packet_check_eom();
   
         if (partial != 0)          if (partial != 0)
                 log("Authenticated with partial success.");                  logit("Authenticated with partial success.");
         debug("authentications that can continue: %s", authlist);          debug("Authentications that can continue: %s", authlist);
   
         clear_auth_state(authctxt);  
         userauth(authctxt, authlist);          userauth(authctxt, authlist);
 }  }
 void  void
Line 357 
Line 402 
 {  {
         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 379 
Line 425 
         }          }
         packet_check_eom();          packet_check_eom();
   
         debug("input_userauth_pk_ok: 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);
         xfree(pkblob);          xfree(pkblob);
   
         /* unregister */  
         clear_auth_state(authctxt);  
         dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL);  
   
         /* 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);
   }
   
   #ifdef GSSAPI
   int
   userauth_gssapi(Authctxt *authctxt)
   {
           Gssctxt *gssctxt = NULL;
           static gss_OID_set supported = NULL;
           static int mech = 0;
           OM_uint32 min;
           int ok = 0;
   
           /* Try one GSSAPI method at a time, rather than sending them all at
            * once. */
   
           if (supported == NULL)
                   gss_indicate_mechs(&min, &supported);
   
           /* Check to see if the mechanism is usable before we offer it */
           while (mech<supported->count && !ok) {
                   if (gssctxt)
                           ssh_gssapi_delete_ctx(&gssctxt);
                   ssh_gssapi_build_ctx(&gssctxt);
                   ssh_gssapi_set_oid(gssctxt, &supported->elements[mech]);
   
                   /* My DER encoding requires length<128 */
                   if (supported->elements[mech].length < 128 &&
                       !GSS_ERROR(ssh_gssapi_import_name(gssctxt,
                       authctxt->host))) {
                           ok = 1; /* Mechanism works */
                   } else {
                           mech++;
                   }
           }
   
           if (!ok) return 0;
   
           authctxt->methoddata=(void *)gssctxt;
   
           packet_start(SSH2_MSG_USERAUTH_REQUEST);
           packet_put_cstring(authctxt->server_user);
           packet_put_cstring(authctxt->service);
           packet_put_cstring(authctxt->method->name);
   
           packet_put_int(1);
   
           /* Some servers encode the OID incorrectly (as we used to) */
           if (datafellows & SSH_BUG_GSSAPI_BER) {
                   packet_put_string(supported->elements[mech].elements,
                       supported->elements[mech].length);
           } else {
                   packet_put_int((supported->elements[mech].length)+2);
                   packet_put_char(SSH_GSS_OIDTYPE);
                   packet_put_char(supported->elements[mech].length);
                   packet_put_raw(supported->elements[mech].elements,
                       supported->elements[mech].length);
           }
   
           packet_send();
   
           dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response);
           dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
           dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error);
           dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
   
           mech++; /* Move along to next candidate */
   
           return 1;
 }  }
   
   void
   input_gssapi_response(int type, u_int32_t plen, void *ctxt)
   {
           Authctxt *authctxt = ctxt;
           Gssctxt *gssctxt;
           OM_uint32 status, ms;
           int oidlen;
           char *oidv;
           gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
   
           if (authctxt == NULL)
                   fatal("input_gssapi_response: no authentication context");
           gssctxt = authctxt->methoddata;
   
           /* Setup our OID */
           oidv = packet_get_string(&oidlen);
   
           if (datafellows & SSH_BUG_GSSAPI_BER) {
                   if (!ssh_gssapi_check_oid(gssctxt, oidv, oidlen))
                           fatal("Server returned different OID than expected");
           } else {
                   if(oidv[0] != SSH_GSS_OIDTYPE || oidv[1] != oidlen-2) {
                           debug("Badly encoded mechanism OID received");
                           userauth(authctxt, NULL);
                           xfree(oidv);
                           return;
                   }
                   if (!ssh_gssapi_check_oid(gssctxt, oidv+2, oidlen-2))
                           fatal("Server returned different OID than expected");
           }
   
           packet_check_eom();
   
           xfree(oidv);
   
           status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
               GSS_C_NO_BUFFER, &send_tok, NULL);
           if (GSS_ERROR(status)) {
                   if (send_tok.length > 0) {
                           packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
                           packet_put_string(send_tok.value, send_tok.length);
                           packet_send();
                           gss_release_buffer(&ms, &send_tok);
                   }
                   /* Start again with next method on list */
                   debug("Trying to start again");
                   userauth(authctxt, NULL);
                   return;
           }
   
           /* We must have data to send */
           packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
           packet_put_string(send_tok.value, send_tok.length);
           packet_send();
           gss_release_buffer(&ms, &send_tok);
   }
   
   void
   input_gssapi_token(int type, u_int32_t plen, void *ctxt)
   {
           Authctxt *authctxt = ctxt;
           Gssctxt *gssctxt;
           gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
           gss_buffer_desc recv_tok;
           OM_uint32 status, ms;
           u_int slen;
   
           if (authctxt == NULL)
                   fatal("input_gssapi_response: no authentication context");
           gssctxt = authctxt->methoddata;
   
           recv_tok.value = packet_get_string(&slen);
           recv_tok.length = slen; /* safe typecast */
   
           packet_check_eom();
   
           status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
               &recv_tok, &send_tok, NULL);
   
           xfree(recv_tok.value);
   
           if (GSS_ERROR(status)) {
                   if (send_tok.length > 0) {
                           packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
                           packet_put_string(send_tok.value, send_tok.length);
                           packet_send();
                           gss_release_buffer(&ms, &send_tok);
                   }
                   /* Start again with the next method in the list */
                   userauth(authctxt, NULL);
                   return;
           }
   
           if (send_tok.length > 0) {
                   packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
                   packet_put_string(send_tok.value, send_tok.length);
                   packet_send();
                   gss_release_buffer(&ms, &send_tok);
           }
   
           if (status == GSS_S_COMPLETE) {
                   /* If that succeeded, send a exchange complete message */
                   packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
                   packet_send();
           }
   }
   
   void
   input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
   {
           Authctxt *authctxt = ctxt;
           Gssctxt *gssctxt;
           gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
           gss_buffer_desc recv_tok;
           OM_uint32 status, ms;
           u_int len;
   
           if (authctxt == NULL)
                   fatal("input_gssapi_response: no authentication context");
           gssctxt = authctxt->methoddata;
   
           recv_tok.value = packet_get_string(&len);
           recv_tok.length = len;
   
           packet_check_eom();
   
           /* Stick it into GSSAPI and see what it says */
           status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
                                        &recv_tok, &send_tok, NULL);
   
           xfree(recv_tok.value);
           gss_release_buffer(&ms, &send_tok);
   
           /* Server will be returning a failed packet after this one */
   }
   
   void
   input_gssapi_error(int type, u_int32_t plen, void *ctxt)
   {
           OM_uint32 maj, min;
           char *msg;
           char *lang;
   
           maj=packet_get_int();
           min=packet_get_int();
           msg=packet_get_string(NULL);
           lang=packet_get_string(NULL);
   
           packet_check_eom();
   
           debug("Server GSSAPI Error:\n%s\n", msg);
           xfree(msg);
           xfree(lang);
   }
   #endif /* GSSAPI */
   
 int  int
 userauth_none(Authctxt *authctxt)  userauth_none(Authctxt *authctxt)
 {  {
Line 491 
Line 749 
         info = packet_get_string(NULL);          info = packet_get_string(NULL);
         lang = packet_get_string(NULL);          lang = packet_get_string(NULL);
         if (strlen(info) > 0)          if (strlen(info) > 0)
                 log("%s", info);                  logit("%s", info);
         xfree(info);          xfree(info);
         xfree(lang);          xfree(lang);
         packet_start(SSH2_MSG_USERAUTH_REQUEST);          packet_start(SSH2_MSG_USERAUTH_REQUEST);
Line 523 
Line 781 
                 if (strcmp(password, retype) != 0) {                  if (strcmp(password, retype) != 0) {
                         memset(password, 0, strlen(password));                          memset(password, 0, strlen(password));
                         xfree(password);                          xfree(password);
                         log("Mismatch; try again, EOF to quit.");                          logit("Mismatch; try again, EOF to quit.");
                         password = NULL;                          password = NULL;
                 }                  }
                 memset(retype, 0, strlen(retype));                  memset(retype, 0, strlen(retype));
Line 539 
Line 797 
             &input_userauth_passwd_changereq);              &input_userauth_passwd_changereq);
 }  }
   
 static void  static int
 clear_auth_state(Authctxt *authctxt)  identity_sign(Identity *id, u_char **sigp, u_int *lenp,
       u_char *data, u_int datalen)
 {  {
         /* XXX clear authentication state */          Key *prv;
         dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL);          int ret;
   
         if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {          /* the agent supports this key */
                 debug3("clear_auth_state: key_free %p", authctxt->last_key);          if (id->ac)
                 key_free(authctxt->last_key);                  return (ssh_agent_sign(id->ac, id->key, sigp, lenp,
         }                      data, datalen));
         authctxt->last_key = NULL;          /*
         authctxt->last_key_hint = -2;           * we have already loaded the private key or
         authctxt->last_key_sign = NULL;           * 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;
         u_int bloblen, slen;          u_int bloblen, slen;
         int skip = 0;          u_int skip = 0;
         int ret = -1;          int ret = -1;
         int have_sig = 1;          int have_sig = 1;
   
         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 591 
Line 859 
         } 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 616 
Line 884 
                 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 640 
Line 908 
 }  }
   
 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 665 
Line 929 
         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 710 
Line 974 
         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("userauth_pubkey_agent: testing 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("try privkey: %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("try pubkey: %s", filename);  
                         sent = send_pubkey_test(authctxt, key,  
                             identity_sign_cb, idx);  
                 }                  }
                 idx++;                  if (sent)
                           return (sent);
         }          }
         return sent;          return (0);
 }  }
   
 /*  /*
Line 862 
Line 1157 
         inst = packet_get_string(NULL);          inst = packet_get_string(NULL);
         lang = packet_get_string(NULL);          lang = packet_get_string(NULL);
         if (strlen(name) > 0)          if (strlen(name) > 0)
                 log("%s", name);                  logit("%s", name);
         if (strlen(inst) > 0)          if (strlen(inst) > 0)
                 log("%s", inst);                  logit("%s", inst);
         xfree(name);          xfree(name);
         xfree(inst);          xfree(inst);
         xfree(lang);          xfree(lang);
Line 906 
Line 1201 
         pid_t pid;          pid_t pid;
         int to[2], from[2], status, version = 2;          int to[2], from[2], status, version = 2;
   
         debug("ssh_keysign called");          debug2("ssh_keysign called");
   
         if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) {          if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) {
                 error("ssh_keysign: no installed: %s", strerror(errno));                  error("ssh_keysign: no installed: %s", strerror(errno));
Line 947 
Line 1242 
         buffer_init(&b);          buffer_init(&b);
         buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */          buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */
         buffer_put_string(&b, data, datalen);          buffer_put_string(&b, data, datalen);
         msg_send(to[1], version, &b);          ssh_msg_send(to[1], version, &b);
   
         if (msg_recv(from[0], &b) < 0) {          if (ssh_msg_recv(from[0], &b) < 0) {
                 error("ssh_keysign: no reply");                  error("ssh_keysign: no reply");
                 buffer_clear(&b);                  buffer_clear(&b);
                 return -1;                  return -1;
Line 995 
Line 1290 
                 }                  }
         }          }
         if (!found) {          if (!found) {
                 debug("userauth_hostbased: no more client hostkeys");                  debug("No more client hostkeys for hostbased authentication.");
                 return 0;                  return 0;
         }          }
         if (key_to_blob(private, &blob, &blen) == 0) {          if (key_to_blob(private, &blob, &blen) == 0) {
Line 1014 
Line 1309 
         strlcpy(chost, p, len);          strlcpy(chost, p, len);
         strlcat(chost, ".", len);          strlcat(chost, ".", len);
         debug2("userauth_hostbased: chost %s", chost);          debug2("userauth_hostbased: chost %s", chost);
           xfree(p);
   
         service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :          service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
             authctxt->service;              authctxt->service;
Line 1109 
Line 1405 
 static Authmethod *  static Authmethod *
 authmethod_get(char *authlist)  authmethod_get(char *authlist)
 {  {
   
         char *name = NULL;          char *name = NULL;
         u_int next;          u_int next;
   
Line 1130 
Line 1425 
   
         for (;;) {          for (;;) {
                 if ((name = match_list(preferred, supported, &next)) == NULL) {                  if ((name = match_list(preferred, supported, &next)) == NULL) {
                         debug("no more auth methods to try");                          debug("No more authentication methods to try.");
                         current = NULL;                          current = NULL;
                         return NULL;                          return NULL;
                 }                  }
Line 1140 
Line 1435 
                 if ((current = authmethod_lookup(name)) != NULL &&                  if ((current = authmethod_lookup(name)) != NULL &&
                     authmethod_is_enabled(current)) {                      authmethod_is_enabled(current)) {
                         debug3("authmethod_is_enabled %s", name);                          debug3("authmethod_is_enabled %s", name);
                         debug("next auth method to try is %s", name);                          debug("Next authentication method: %s", name);
                         return current;                          return current;
                 }                  }
         }          }

Legend:
Removed from v.1.107  
changed lines
  Added in v.1.107.2.2