[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.112.2.2 and 1.113

version 1.112.2.2, 2004/03/04 18:18:17 version 1.113, 2003/04/01 10:10:23
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 62 
Line 58 
  */   */
   
 u_char *session_id2 = NULL;  u_char *session_id2 = NULL;
 u_int session_id2_len = 0;  int session_id2_len = 0;
   
 char *xxx_host;  char *xxx_host;
 struct sockaddr *xxx_hostaddr;  struct sockaddr *xxx_hostaddr;
Line 86 
Line 82 
         xxx_hostaddr = hostaddr;          xxx_hostaddr = hostaddr;
   
         if (options.ciphers == (char *)-1) {          if (options.ciphers == (char *)-1) {
                 logit("No valid ciphers for protocol version 2 given, using defaults.");                  log("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 145 
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;  
   
 struct identity {  typedef int sign_cb_fn(
         TAILQ_ENTRY(identity) next;      Authctxt *authctxt, Key *key,
         AuthenticationConnection *ac;   /* set if agent supports key */      u_char **sigp, u_int *lenp, u_char *data, u_int datalen);
         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 167 
Line 155 
         int success;          int success;
         char *authlist;          char *authlist;
         /* pubkey */          /* pubkey */
         Idlist keys;          Key *last_key;
           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 196 
Line 184 
 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 *, Identity *);  static int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *);
 static void pubkey_prepare(Authctxt *);  static void clear_auth_state(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-with-mic",  
                 userauth_gssapi,  
                 &options.gss_authentication,  
                 NULL},  
 #endif  
         {"hostbased",          {"hostbased",
                 userauth_hostbased,                  userauth_hostbased,
                 &options.hostbased_authentication,                  &options.hostbased_authentication,
Line 281 
Line 251 
   
         /* setup authentication context */          /* setup authentication context */
         memset(&authctxt, 0, sizeof(authctxt));          memset(&authctxt, 0, sizeof(authctxt));
         pubkey_prepare(&authctxt);          authctxt.agent = ssh_get_authentication_connection();
         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 289 
Line 259 
         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 304 
Line 273 
         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 */
   
         pubkey_cleanup(&authctxt);          if (authctxt.agent != NULL)
         dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL);                  ssh_close_authentication_connection(authctxt.agent);
   
         debug("Authentication succeeded (%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 329 
Line 293 
                 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 356 
Line 314 
 input_userauth_banner(int type, u_int32_t seq, void *ctxt)  input_userauth_banner(int type, u_int32_t seq, void *ctxt)
 {  {
         char *msg, *lang;          char *msg, *lang;
   
         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);
         if (options.log_level > SYSLOG_LEVEL_QUIET)          fprintf(stderr, "%s", msg);
                 fprintf(stderr, "%s", msg);  
         xfree(msg);          xfree(msg);
         xfree(lang);          xfree(lang);
 }  }
Line 372 
Line 328 
         Authctxt *authctxt = ctxt;          Authctxt *authctxt = ctxt;
         if (authctxt == NULL)          if (authctxt == NULL)
                 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);
                 authctxt->authlist = NULL;          clear_auth_state(authctxt);
         }  
         if (authctxt->methoddata) {  
                 xfree(authctxt->methoddata);  
                 authctxt->methoddata = NULL;  
         }  
         authctxt->success = 1;                  /* break out */          authctxt->success = 1;                  /* break out */
 }  }
   
Line 398 
Line 349 
         packet_check_eom();          packet_check_eom();
   
         if (partial != 0)          if (partial != 0)
                 logit("Authenticated with partial success.");                  log("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 408 
Line 360 
 {  {
         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 431 
Line 382 
         }          }
         packet_check_eom();          packet_check_eom();
   
         debug("Server accepts key: pkalg %s blen %u", pkalg, blen);          debug("Server accepts key: pkalg %s blen %u lastkey %p hint %d",
               pkalg, blen, authctxt->last_key, authctxt->last_key_hint);
   
         if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {          do {
                 debug("unknown pkalg %s", pkalg);                  if (authctxt->last_key == NULL ||
                 goto done;                      authctxt->last_key_sign == NULL) {
         }                          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);  
   
         /*  
          * search keys in the reverse order, because last candidate has been  
          * moved to the end of the queue.  this also avoids confusion by  
          * duplicate keys  
          */  
         TAILQ_FOREACH_REVERSE(id, &authctxt->keys, next, idlist) {  
                 if (key_equal(key, id->key)) {  
                         sent = sign_and_send_pubkey(authctxt, id);  
                         break;                          break;
                 }                  }
         }                  if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
 done:                          debug("unknown pkalg %s", pkalg);
                           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 gss_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 (gss_supported == NULL)  
                 gss_indicate_mechs(&min, &gss_supported);  
   
         /* Check to see if the mechanism is usable before we offer it */  
         while (mech < gss_supported->count && !ok) {  
                 if (gssctxt)  
                         ssh_gssapi_delete_ctx(&gssctxt);  
                 ssh_gssapi_build_ctx(&gssctxt);  
                 ssh_gssapi_set_oid(gssctxt, &gss_supported->elements[mech]);  
   
                 /* My DER encoding requires length<128 */  
                 if (gss_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);  
   
         packet_put_int((gss_supported->elements[mech].length) + 2);  
         packet_put_char(SSH_GSS_OIDTYPE);  
         packet_put_char(gss_supported->elements[mech].length);  
         packet_put_raw(gss_supported->elements[mech].elements,  
             gss_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;  
 }  }
   
 static OM_uint32  
 process_gssapi_token(void *ctxt, gss_buffer_t recv_tok)  
 {  
         Authctxt *authctxt = ctxt;  
         Gssctxt *gssctxt = authctxt->methoddata;  
         gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;  
         gss_buffer_desc gssbuf, mic;  
         OM_uint32 status, ms, flags;  
         Buffer b;  
   
         status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,  
             recv_tok, &send_tok, &flags);  
   
         if (send_tok.length > 0) {  
                 if (GSS_ERROR(status))  
                         packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);  
                 else  
                         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) {  
                 /* send either complete or MIC, depending on mechanism */  
                 if (!(flags & GSS_C_INTEG_FLAG)) {  
                         packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);  
                         packet_send();  
                 } else {  
                         ssh_gssapi_buildmic(&b, authctxt->server_user,  
                             authctxt->service, "gssapi-with-mic");  
   
                         gssbuf.value = buffer_ptr(&b);  
                         gssbuf.length = buffer_len(&b);  
   
                         status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic);  
   
                         if (!GSS_ERROR(status)) {  
                                 packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC);  
                                 packet_put_string(mic.value, mic.length);  
   
                                 packet_send();  
                         }  
   
                         buffer_free(&b);  
                         gss_release_buffer(&ms, &mic);  
                 }  
         }  
   
         return status;  
 }  
   
 void  
 input_gssapi_response(int type, u_int32_t plen, void *ctxt)  
 {  
         Authctxt *authctxt = ctxt;  
         Gssctxt *gssctxt;  
         int oidlen;  
         char *oidv;  
   
         if (authctxt == NULL)  
                 fatal("input_gssapi_response: no authentication context");  
         gssctxt = authctxt->methoddata;  
   
         /* Setup our OID */  
         oidv = packet_get_string(&oidlen);  
   
         if (oidlen <= 2 ||  
             oidv[0] != SSH_GSS_OIDTYPE ||  
             oidv[1] != oidlen - 2) {  
                 xfree(oidv);  
                 debug("Badly encoded mechanism OID received");  
                 userauth(authctxt, NULL);  
                 return;  
         }  
   
         if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2))  
                 fatal("Server returned different OID than expected");  
   
         packet_check_eom();  
   
         xfree(oidv);  
   
         if (GSS_ERROR(process_gssapi_token(ctxt, GSS_C_NO_BUFFER))) {  
                 /* Start again with next method on list */  
                 debug("Trying to start again");  
                 userauth(authctxt, NULL);  
                 return;  
         }  
 }  
   
 void  
 input_gssapi_token(int type, u_int32_t plen, void *ctxt)  
 {  
         Authctxt *authctxt = ctxt;  
         gss_buffer_desc recv_tok;  
         OM_uint32 status;  
         u_int slen;  
   
         if (authctxt == NULL)  
                 fatal("input_gssapi_response: no authentication context");  
   
         recv_tok.value = packet_get_string(&slen);  
         recv_tok.length = slen; /* safe typecast */  
   
         packet_check_eom();  
   
         status = process_gssapi_token(ctxt, &recv_tok);  
   
         xfree(recv_tok.value);  
   
         if (GSS_ERROR(status)) {  
                 /* Start again with the next method in the list */  
                 userauth(authctxt, NULL);  
                 return;  
         }  
 }  
   
 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 766 
Line 494 
         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)
                 logit("%s", info);                  log("%s", info);
         xfree(info);          xfree(info);
         xfree(lang);          xfree(lang);
         packet_start(SSH2_MSG_USERAUTH_REQUEST);          packet_start(SSH2_MSG_USERAUTH_REQUEST);
Line 798 
Line 526 
                 if (strcmp(password, retype) != 0) {                  if (strcmp(password, retype) != 0) {
                         memset(password, 0, strlen(password));                          memset(password, 0, strlen(password));
                         xfree(password);                          xfree(password);
                         logit("Mismatch; try again, EOF to quit.");                          log("Mismatch; try again, EOF to quit.");
                         password = NULL;                          password = NULL;
                 }                  }
                 memset(retype, 0, strlen(retype));                  memset(retype, 0, strlen(retype));
Line 814 
Line 542 
             &input_userauth_passwd_changereq);              &input_userauth_passwd_changereq);
 }  }
   
 static int  static void
 identity_sign(Identity *id, u_char **sigp, u_int *lenp,  clear_auth_state(Authctxt *authctxt)
     u_char *data, u_int datalen)  
 {  {
         Key *prv;          /* XXX clear authentication state */
         int ret;          dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL);
   
         /* the agent supports this key */          if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {
         if (id->ac)                  debug3("clear_auth_state: key_free %p", authctxt->last_key);
                 return (ssh_agent_sign(id->ac, id->key, sigp, lenp,                  key_free(authctxt->last_key);
                     data, datalen));          }
         /*          authctxt->last_key = NULL;
          * we have already loaded the private key or          authctxt->last_key_hint = -2;
          * the private key is stored in external hardware          authctxt->last_key_sign = NULL;
          */  
         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, Identity *id)  sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
 {  {
         Buffer b;          Buffer b;
         u_char *blob, *signature;          u_char *blob, *signature;
         u_int bloblen, slen;          u_int bloblen, slen;
         u_int skip = 0;          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(id->key, &blob, &bloblen) == 0) {          if (key_to_blob(k, &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 876 
Line 594 
         } 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(id->key));                  buffer_put_cstring(&b, key_ssh_name(k));
         }          }
         buffer_put_string(&b, blob, bloblen);          buffer_put_string(&b, blob, bloblen);
   
         /* generate signature */          /* generate signature */
         ret = identity_sign(id, &signature, &slen,          ret = (*sign_callback)(authctxt, k, &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 901 
Line 619 
                 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(id->key));                          buffer_put_cstring(&b, key_ssh_name(k));
                 buffer_put_string(&b, blob, bloblen);                  buffer_put_string(&b, blob, bloblen);
         }          }
         xfree(blob);          xfree(blob);
Line 925 
Line 643 
 }  }
   
 static int  static int
 send_pubkey_test(Authctxt *authctxt, Identity *id)  send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
       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(id->key, &blob, &bloblen) == 0) {          if (key_to_blob(k, &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 946 
Line 668 
         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(id->key));                  packet_put_cstring(key_ssh_name(k));
         packet_put_string(blob, bloblen);          packet_put_string(blob, bloblen);
         xfree(blob);          xfree(blob);
         packet_send();          packet_send();
Line 991 
Line 713 
         return private;          return private;
 }  }
   
 /*  static int
  * try keys in the following order:  identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
  *      1. agent keys that are found in the config file      u_char *data, u_int datalen)
  *      2. other agent keys  
  *      3. keys that are only listed in the config file  
  */  
 static void  
 pubkey_prepare(Authctxt *authctxt)  
 {  {
         Identity *id;          Key *private;
         Idlist agent, files, *preferred;          int idx, ret;
         Key *key;  
         AuthenticationConnection *ac;  
         char *comment;  
         int i, found;  
   
         TAILQ_INIT(&agent);     /* keys from the agent */          idx = authctxt->last_key_hint;
         TAILQ_INIT(&files);     /* keys from the config file */          if (idx < 0)
         preferred = &authctxt->keys;                  return -1;
         TAILQ_INIT(preferred);  /* preferred order of keys */  
   
         /* list of keys stored in the filesystem */          /* private key is stored in external hardware */
         for (i = 0; i < options.num_identity_files; i++) {          if (options.identity_keys[idx]->flags & KEY_FLAG_EXT)
                 key = options.identity_keys[i];                  return key_sign(options.identity_keys[idx], sigp, lenp, data, datalen);
                 if (key && key->type == KEY_RSA1)  
                         continue;          private = load_identity_file(options.identity_files[idx]);
                 options.identity_keys[i] = NULL;          if (private == NULL)
                 id = xmalloc(sizeof(*id));                  return -1;
                 memset(id, 0, sizeof(*id));          ret = key_sign(private, sigp, lenp, data, datalen);
                 id->key = key;          key_free(private);
                 id->filename = xstrdup(options.identity_files[i]);          return ret;
                 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 void  static int
 pubkey_cleanup(Authctxt *authctxt)  agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
       u_char *data, u_int datalen)
 {  {
         Identity *id;          return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
   }
   
         if (authctxt->agent != NULL)  static int
                 ssh_close_authentication_connection(authctxt->agent);  key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, u_int *lenp,
         for (id = TAILQ_FIRST(&authctxt->keys); id;      u_char *data, u_int datalen)
             id = TAILQ_FIRST(&authctxt->keys)) {  {
                 TAILQ_REMOVE(&authctxt->keys, id, next);          return key_sign(key, sigp, lenp, data, datalen);
                 if (id->key)  }
                         key_free(id->key);  
                 if (id->filename)  static int
                         xfree(id->filename);  userauth_pubkey_agent(Authctxt *authctxt)
                 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)
 {  {
         Identity *id;          static int idx = 0;
         int sent = 0;          int sent = 0;
           Key *key;
           char *filename;
   
         while ((id = TAILQ_FIRST(&authctxt->keys))) {          if (authctxt->agent != NULL) {
                 if (id->tried++)                  do {
                         return (0);                          sent = userauth_pubkey_agent(authctxt);
                 /* move key to the end of the queue */                  } 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);
                 }                  }
                 if (sent)                  idx++;
                         return (sent);  
         }          }
         return (0);          return sent;
 }  }
   
 /*  /*
Line 1175 
Line 865 
         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)
                 logit("%s", name);                  log("%s", name);
         if (strlen(inst) > 0)          if (strlen(inst) > 0)
                 logit("%s", inst);                  log("%s", inst);
         xfree(name);          xfree(name);
         xfree(inst);          xfree(inst);
         xfree(lang);          xfree(lang);
Line 1260 
Line 950 
         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);
         if (ssh_msg_send(to[1], version, &b) == -1)          ssh_msg_send(to[1], version, &b);
                 fatal("ssh_keysign: couldn't send request");  
   
         if (ssh_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_free(&b);                  buffer_clear(&b);
                 return -1;                  return -1;
         }          }
         close(from[0]);          close(from[0]);
Line 1277 
Line 966 
   
         if (buffer_get_char(&b) != version) {          if (buffer_get_char(&b) != version) {
                 error("ssh_keysign: bad version");                  error("ssh_keysign: bad version");
                 buffer_free(&b);                  buffer_clear(&b);
                 return -1;                  return -1;
         }          }
         *sigp = buffer_get_string(&b, lenp);          *sigp = buffer_get_string(&b, lenp);
         buffer_free(&b);          buffer_clear(&b);
   
         return 0;          return 0;
 }  }

Legend:
Removed from v.1.112.2.2  
changed lines
  Added in v.1.113