[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.10.2.4 and 1.10.2.5

version 1.10.2.4, 2001/03/12 15:44:17 version 1.10.2.5, 2001/03/21 18:53:16
Line 51 
Line 51 
 #include "log.h"  #include "log.h"
 #include "readconf.h"  #include "readconf.h"
 #include "readpass.h"  #include "readpass.h"
   #include "match.h"
   
 void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);  void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);
 void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);  void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *);
Line 171 
Line 172 
         debug("Sending SSH2_MSG_KEXDH_INIT.");          debug("Sending SSH2_MSG_KEXDH_INIT.");
         /* generate and send 'e', client DH public key */          /* generate and send 'e', client DH public key */
         dh = dh_new_group1();          dh = dh_new_group1();
         dh_gen_key(dh);          dh_gen_key(dh, kex->we_need * 8);
         packet_start(SSH2_MSG_KEXDH_INIT);          packet_start(SSH2_MSG_KEXDH_INIT);
         packet_put_bignum2(dh->pub_key);          packet_put_bignum2(dh->pub_key);
         packet_send();          packet_send();
Line 316 
Line 317 
         u_char *kbuf;          u_char *kbuf;
         u_char *hash;          u_char *hash;
   
         nbits = dh_estimate(kex->enc[MODE_OUT].cipher->key_len * 8);          nbits = dh_estimate(kex->we_need * 8);
   
         debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST.");          debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST.");
         packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);          packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
Line 342 
Line 343 
         packet_get_bignum2(g, &dlen);          packet_get_bignum2(g, &dlen);
         dh = dh_new_group(g, p);          dh = dh_new_group(g, p);
   
         dh_gen_key(dh);          dh_gen_key(dh, kex->we_need * 8);
   
 #ifdef DEBUG_KEXDH  #ifdef DEBUG_KEXDH
         fprintf(stderr, "\np= ");          fprintf(stderr, "\np= ");
Line 467 
Line 468 
         AuthenticationConnection *agent;          AuthenticationConnection *agent;
         Authmethod *method;          Authmethod *method;
         int success;          int success;
           char *authlist;
           Key *last_key;
           sign_cb_fn *last_key_sign;
           int last_key_hint;
 };  };
 struct Authmethod {  struct Authmethod {
         char    *name;          /* string to compare against server's list */          char    *name;          /* string to compare against server's list */
Line 480 
Line 485 
 void    input_userauth_banner(int type, int plen, void *ctxt);  void    input_userauth_banner(int type, int plen, void *ctxt);
 void    input_userauth_error(int type, int plen, void *ctxt);  void    input_userauth_error(int type, int plen, void *ctxt);
 void    input_userauth_info_req(int type, int plen, void *ctxt);  void    input_userauth_info_req(int type, int plen, void *ctxt);
   void    input_userauth_pk_ok(int type, int plen, void *ctxt);
   
 int     userauth_none(Authctxt *authctxt);  int     userauth_none(Authctxt *authctxt);
 int     userauth_pubkey(Authctxt *authctxt);  int     userauth_pubkey(Authctxt *authctxt);
 int     userauth_passwd(Authctxt *authctxt);  int     userauth_passwd(Authctxt *authctxt);
 int     userauth_kbdint(Authctxt *authctxt);  int     userauth_kbdint(Authctxt *authctxt);
   
 void    authmethod_clear(void);  void    userauth(Authctxt *authctxt, char *authlist);
   
   int
   sign_and_send_pubkey(Authctxt *authctxt, Key *k,
       sign_cb_fn *sign_callback);
   void    clear_auth_state(Authctxt *authctxt);
   
 Authmethod *authmethod_get(char *authlist);  Authmethod *authmethod_get(char *authlist);
 Authmethod *authmethod_lookup(const char *name);  Authmethod *authmethod_lookup(const char *name);
   char *authmethods_get(void);
   
 Authmethod authmethods[] = {  Authmethod authmethods[] = {
         {"publickey",          {"publickey",
Line 539 
Line 552 
         packet_done();          packet_done();
         debug("got SSH2_MSG_SERVICE_ACCEPT");          debug("got SSH2_MSG_SERVICE_ACCEPT");
   
           if (options.preferred_authentications == NULL)
                   options.preferred_authentications = authmethods_get();
   
         /* setup authentication context */          /* setup authentication context */
         authctxt.agent = ssh_get_authentication_connection();          authctxt.agent = ssh_get_authentication_connection();
         authctxt.server_user = server_user;          authctxt.server_user = server_user;
Line 546 
Line 562 
         authctxt.service = "ssh-connection";            /* service name */          authctxt.service = "ssh-connection";            /* service name */
         authctxt.success = 0;          authctxt.success = 0;
         authctxt.method = authmethod_lookup("none");          authctxt.method = authmethod_lookup("none");
           authctxt.authlist = NULL;
         if (authctxt.method == NULL)          if (authctxt.method == NULL)
                 fatal("ssh_userauth2: internal error: cannot send userauth none request");                  fatal("ssh_userauth2: internal error: cannot send userauth none request");
         authmethod_clear();  
   
         /* initial userauth request */          /* initial userauth request */
         userauth_none(&authctxt);          userauth_none(&authctxt);
Line 565 
Line 581 
         debug("ssh-userauth2 successful: method %s", authctxt.method->name);          debug("ssh-userauth2 successful: method %s", authctxt.method->name);
 }  }
 void  void
   userauth(Authctxt *authctxt, char *authlist)
   {
           if (authlist == NULL) {
                   authlist = authctxt->authlist;
           } else {
                   if (authctxt->authlist)
                           xfree(authctxt->authlist);
                   authctxt->authlist = authlist;
           }
           for (;;) {
                   Authmethod *method = authmethod_get(authlist);
                   if (method == NULL)
                           fatal("Permission denied (%s).", authlist);
                   authctxt->method = method;
                   if (method->userauth(authctxt) != 0) {
                           debug2("we sent a %s packet, wait for reply", method->name);
                           break;
                   } else {
                           debug2("we did not send a packet, disable method");
                           method->enabled = NULL;
                   }
           }
   }
   void
 input_userauth_error(int type, int plen, void *ctxt)  input_userauth_error(int type, int plen, void *ctxt)
 {  {
         fatal("input_userauth_error: bad message during authentication: "          fatal("input_userauth_error: bad message during authentication: "
Line 587 
Line 627 
         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)
                   xfree(authctxt->authlist);
           clear_auth_state(authctxt);
         authctxt->success = 1;                  /* break out */          authctxt->success = 1;                  /* break out */
 }  }
 void  void
 input_userauth_failure(int type, int plen, void *ctxt)  input_userauth_failure(int type, int plen, void *ctxt)
 {  {
         Authmethod *method = NULL;  
         Authctxt *authctxt = ctxt;          Authctxt *authctxt = ctxt;
         char *authlist = NULL;          char *authlist = NULL;
         int partial;          int partial;
Line 608 
Line 650 
                 log("Authenticated with partial success.");                  log("Authenticated with partial success.");
         debug("authentications that can continue: %s", authlist);          debug("authentications that can continue: %s", authlist);
   
         for (;;) {          clear_auth_state(authctxt);
                 method = authmethod_get(authlist);          userauth(authctxt, authlist);
                 if (method == NULL)  }
                         fatal("Permission denied (%s).", authlist);  void
                 authctxt->method = method;  input_userauth_pk_ok(int type, int plen, void *ctxt)
                 if (method->userauth(authctxt) != 0) {  {
                         debug2("we sent a %s packet, wait for reply", method->name);          Authctxt *authctxt = ctxt;
           Key *key = NULL;
           Buffer b;
           int alen, blen, pktype, sent = 0;
           char *pkalg, *pkblob, *fp;
   
           if (authctxt == NULL)
                   fatal("input_userauth_pk_ok: no authentication context");
           if (datafellows & SSH_BUG_PKOK) {
                   /* this is similar to SSH_BUG_PKAUTH */
                   debug2("input_userauth_pk_ok: SSH_BUG_PKOK");
                   pkblob = packet_get_string(&blen);
                   buffer_init(&b);
                   buffer_append(&b, pkblob, blen);
                   pkalg = buffer_get_string(&b, &alen);
                   buffer_free(&b);
           } else {
                   pkalg = packet_get_string(&alen);
                   pkblob = packet_get_string(&blen);
           }
           packet_done();
   
           debug("input_userauth_pk_ok: pkalg %s blen %d lastkey %p hint %d",
               pkalg, blen, authctxt->last_key, authctxt->last_key_hint);
   
           do {
                   if (authctxt->last_key == NULL ||
                       authctxt->last_key_sign == NULL) {
                           debug("no last key or no sign cb");
                         break;                          break;
                 } else {  
                         debug2("we did not send a packet, disable method");  
                         method->enabled = NULL;  
                 }                  }
         }                  if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
         xfree(authlist);                          debug("unknown pkalg %s", pkalg);
                           break;
                   }
                   if ((key = key_from_blob(pkblob, blen)) == NULL) {
                           debug("no key from blob. pkalg %s", pkalg);
                           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)
                   key_free(key);
           xfree(pkalg);
           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*/
           if (sent == 0)
                   userauth(authctxt, NULL);
   
 }  }
   
 int  int
Line 633 
Line 730 
         packet_put_cstring(authctxt->service);          packet_put_cstring(authctxt->service);
         packet_put_cstring(authctxt->method->name);          packet_put_cstring(authctxt->method->name);
         packet_send();          packet_send();
         packet_write_wait();  
         return 1;          return 1;
 }  }
   
Line 658 
Line 754 
         packet_put_cstring(authctxt->service);          packet_put_cstring(authctxt->service);
         packet_put_cstring(authctxt->method->name);          packet_put_cstring(authctxt->method->name);
         packet_put_char(0);          packet_put_char(0);
         ssh_put_password(password);          packet_put_cstring(password);
         memset(password, 0, strlen(password));          memset(password, 0, strlen(password));
         xfree(password);          xfree(password);
           packet_inject_ignore(64);
         packet_send();          packet_send();
         packet_write_wait();  
         return 1;          return 1;
 }  }
   
   void
   clear_auth_state(Authctxt *authctxt)
   {
           /* XXX clear authentication state */
           if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {
                   debug3("clear_auth_state: key_free %p", authctxt->last_key);
                   key_free(authctxt->last_key);
           }
           authctxt->last_key = NULL;
           authctxt->last_key_hint = -2;
           authctxt->last_key_sign = NULL;
   }
   
 int  int
 sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)  sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback)
 {  {
Line 677 
Line 786 
         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(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");
Line 707 
Line 817 
         buffer_put_string(&b, blob, bloblen);          buffer_put_string(&b, blob, bloblen);
   
         /* generate signature */          /* generate signature */
         ret = (*sign_callback)(authctxt, k, &signature, &slen, buffer_ptr(&b), buffer_len(&b));          ret = (*sign_callback)(authctxt, k, &signature, &slen,
               buffer_ptr(&b), buffer_len(&b));
         if (ret == -1) {          if (ret == -1) {
                 xfree(blob);                  xfree(blob);
                 buffer_free(&b);                  buffer_free(&b);
Line 719 
Line 830 
         if (datafellows & SSH_BUG_PKSERVICE) {          if (datafellows & SSH_BUG_PKSERVICE) {
                 buffer_clear(&b);                  buffer_clear(&b);
                 buffer_append(&b, session_id2, session_id2_len);                  buffer_append(&b, session_id2, session_id2_len);
                   skip = session_id2_len;
                 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);                  buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
                 buffer_put_cstring(&b, authctxt->server_user);                  buffer_put_cstring(&b, authctxt->server_user);
                 buffer_put_cstring(&b, authctxt->service);                  buffer_put_cstring(&b, authctxt->service);
Line 729 
Line 841 
                 buffer_put_string(&b, blob, bloblen);                  buffer_put_string(&b, blob, bloblen);
         }          }
         xfree(blob);          xfree(blob);
   
         /* append signature */          /* append signature */
         buffer_put_string(&b, signature, slen);          buffer_put_string(&b, signature, slen);
         xfree(signature);          xfree(signature);
Line 742 
Line 855 
         packet_start(SSH2_MSG_USERAUTH_REQUEST);          packet_start(SSH2_MSG_USERAUTH_REQUEST);
         packet_put_raw(buffer_ptr(&b), buffer_len(&b));          packet_put_raw(buffer_ptr(&b), buffer_len(&b));
         buffer_free(&b);          buffer_free(&b);
   
         /* send */  
         packet_send();          packet_send();
         packet_write_wait();  
   
         return 1;          return 1;
 }  }
   
 /* sign callback */  int
 int key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,  send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback,
     u_char *data, int datalen)      int hint)
 {  {
         return key_sign(key, sigp, lenp, data, datalen);          u_char *blob;
           int bloblen, have_sig = 0;
   
           debug3("send_pubkey_test");
   
           if (key_to_blob(k, &blob, &bloblen) == 0) {
                   /* we cannot handle this key */
                   debug3("send_pubkey_test: cannot handle key");
                   return 0;
           }
           /* 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);
   
           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_char(have_sig);
           if (!(datafellows & SSH_BUG_PKAUTH))
                   packet_put_cstring(key_ssh_name(k));
           packet_put_string(blob, bloblen);
           xfree(blob);
           packet_send();
           return 1;
 }  }
   
 int  Key *
 userauth_pubkey_identity(Authctxt *authctxt, char *filename)  load_identity_file(char *filename)
 {  {
         Key *k;          Key *private;
         int i, ret, try_next, success = 0;          char prompt[300], *passphrase;
           int success = 0, quit, i;
         struct stat st;          struct stat st;
         char *passphrase;  
         char prompt[300];  
   
         if (stat(filename, &st) != 0) {          if (stat(filename, &st) < 0) {
                 debug("key does not exist: %s", filename);                  debug3("no such identity: %s", filename);
                 return 0;                  return NULL;
         }          }
         debug("try pubkey: %s", filename);          private = key_new(KEY_UNSPEC);
           if (!load_private_key(filename, "", private, NULL)) {
         k = key_new(KEY_UNSPEC);  
         if (!load_private_key(filename, "", k, NULL)) {  
                 if (options.batch_mode) {                  if (options.batch_mode) {
                         key_free(k);                          key_free(private);
                         return 0;                          return NULL;
                 }                  }
                 snprintf(prompt, sizeof prompt,                  snprintf(prompt, sizeof prompt,
                      "Enter passphrase for key '%.100s': ", filename);                       "Enter passphrase for key '%.100s': ", filename);
                 for (i = 0; i < options.number_of_password_prompts; i++) {                  for (i = 0; i < options.number_of_password_prompts; i++) {
                         passphrase = read_passphrase(prompt, 0);                          passphrase = read_passphrase(prompt, 0);
                         if (strcmp(passphrase, "") != 0) {                          if (strcmp(passphrase, "") != 0) {
                                 success = load_private_key(filename, passphrase, k, NULL);                                  success = load_private_key(filename,
                                 try_next = 0;                                      passphrase, private, NULL);
                                   quit = 0;
                         } else {                          } else {
                                 debug2("no passphrase given, try next key");                                  debug2("no passphrase given, try next key");
                                 try_next = 1;                                  quit = 1;
                         }                          }
                         memset(passphrase, 0, strlen(passphrase));                          memset(passphrase, 0, strlen(passphrase));
                         xfree(passphrase);                          xfree(passphrase);
                         if (success || try_next)                          if (success || quit)
                                 break;                                  break;
                         debug2("bad passphrase given, try again...");                          debug2("bad passphrase given, try again...");
                 }                  }
                 if (!success) {                  if (!success) {
                         key_free(k);                          key_free(private);
                         return 0;                          return NULL;
                 }                  }
         }          }
         ret = sign_and_send_pubkey(authctxt, k, key_sign_cb);          return private;
         key_free(k);  }
   
   int
   identity_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
       u_char *data, int datalen)
   {
           Key *private;
           int idx, ret;
   
           idx = authctxt->last_key_hint;
           if (idx < 0)
                   return -1;
           private = load_identity_file(options.identity_files[idx]);
           if (private == NULL)
                   return -1;
           ret = key_sign(private, sigp, lenp, data, datalen);
           key_free(private);
         return ret;          return ret;
 }  }
   
 /* sign callback */  
 int agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,  int agent_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
     u_char *data, int datalen)      u_char *data, int datalen)
 {  {
         return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);          return ssh_agent_sign(authctxt->agent, key, sigp, lenp, data, datalen);
 }  }
   
   int key_sign_cb(Authctxt *authctxt, Key *key, u_char **sigp, int *lenp,
       u_char *data, int datalen)
   {
           return key_sign(key, sigp, lenp, data, datalen);
   }
   
 int  int
 userauth_pubkey_agent(Authctxt *authctxt)  userauth_pubkey_agent(Authctxt *authctxt)
 {  {
Line 829 
Line 984 
         if (k == NULL) {          if (k == NULL) {
                 debug2("userauth_pubkey_agent: no more keys");                  debug2("userauth_pubkey_agent: no more keys");
         } else {          } else {
                 debug("userauth_pubkey_agent: trying agent key %s", comment);                  debug("userauth_pubkey_agent: testing agent key %s", comment);
                 xfree(comment);                  xfree(comment);
                 ret = sign_and_send_pubkey(authctxt, k, agent_sign_cb);                  ret = send_pubkey_test(authctxt, k, agent_sign_cb, -1);
                 key_free(k);                  if (ret == 0)
                           key_free(k);
         }          }
         if (ret == 0)          if (ret == 0)
                 debug2("userauth_pubkey_agent: no message sent");                  debug2("userauth_pubkey_agent: no message sent");
Line 844 
Line 1000 
 {  {
         static int idx = 0;          static int idx = 0;
         int sent = 0;          int sent = 0;
           Key *key;
           char *filename;
   
         if (authctxt->agent != NULL) {          if (authctxt->agent != NULL) {
                 do {                  do {
Line 851 
Line 1009 
                 } while(!sent && authctxt->agent->howmany > 0);                  } while(!sent && authctxt->agent->howmany > 0);
         }          }
         while (!sent && idx < options.num_identity_files) {          while (!sent && idx < options.num_identity_files) {
                 if (options.identity_files_type[idx] != KEY_RSA1)                  key = options.identity_keys[idx];
                         sent = userauth_pubkey_identity(authctxt,                  filename = options.identity_files[idx];
                             options.identity_files[idx]);                  if (key == NULL) {
                           debug("try privkey: %s", filename);
                           key = load_identity_file(filename);
                           if (key != NULL) {
                                   sent = sign_and_send_pubkey(authctxt, key,
                                       key_sign_cb);
                                   key_free(key);
                           }
                   } else if (key->type != KEY_RSA1) {
                           debug("try pubkey: %s", filename);
                           sent = send_pubkey_test(authctxt, key,
                               identity_sign_cb, idx);
                   }
                 idx++;                  idx++;
         }          }
         return sent;          return sent;
Line 879 
Line 1049 
         packet_put_cstring(options.kbd_interactive_devices ?          packet_put_cstring(options.kbd_interactive_devices ?
             options.kbd_interactive_devices : "");              options.kbd_interactive_devices : "");
         packet_send();          packet_send();
         packet_write_wait();  
   
         dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);          dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req);
         return 1;          return 1;
Line 928 
Line 1097 
   
                 response = cli_prompt(prompt, echo);                  response = cli_prompt(prompt, echo);
   
                 ssh_put_password(response);                  packet_put_cstring(response);
                 memset(response, 0, strlen(response));                  memset(response, 0, strlen(response));
                 xfree(response);                  xfree(response);
                 xfree(prompt);                  xfree(prompt);
         }          }
         packet_done(); /* done with parsing incoming message. */          packet_done(); /* done with parsing incoming message. */
   
           packet_inject_ignore(64);
         packet_send();          packet_send();
         packet_write_wait();  
 }  }
   
 /* find auth method */  /* find auth method */
   
 #define DELIM   ","  
   
 static char *def_authlist = "publickey,password";  
 static char *authlist_current = NULL;    /* clean copy used for comparison */  
 static char *authname_current = NULL;    /* last used auth method */  
 static char *authlist_working = NULL;    /* copy that gets modified by strtok_r() */  
 static char *authlist_state = NULL;      /* state variable for strtok_r() */  
   
 /*  /*
  * Before starting to use a new authentication method list sent by the  
  * server, reset internal variables.  This should also be called when  
  * finished processing server list to free resources.  
  */  
 void  
 authmethod_clear(void)  
 {  
         if (authlist_current != NULL) {  
                 xfree(authlist_current);  
                 authlist_current = NULL;  
         }  
         if (authlist_working != NULL) {  
                 xfree(authlist_working);  
                 authlist_working = NULL;  
         }  
         if (authname_current != NULL) {  
                 xfree(authname_current);  
                 authname_current = NULL;  
         }  
         if (authlist_state != NULL)  
                 authlist_state = NULL;  
         return;  
 }  
   
 /*  
  * given auth method name, if configurable options permit this method fill   * given auth method name, if configurable options permit this method fill
  * in auth_ident field and return true, otherwise return false.   * in auth_ident field and return true, otherwise return false.
  */   */
Line 1004 
Line 1140 
         return NULL;          return NULL;
 }  }
   
   /* XXX internal state */
   static Authmethod *current = NULL;
   static char *supported = NULL;
   static char *preferred = NULL;
 /*  /*
  * Given the authentication method list sent by the server, return the   * Given the authentication method list sent by the server, return the
  * next method we should try.  If the server initially sends a nil list,   * next method we should try.  If the server initially sends a nil list,
  * use a built-in default list.  If the server sends a nil list after   * use a built-in default list.
  * previously sending a valid list, continue using the list originally  
  * sent.  
  */   */
   
 Authmethod *  Authmethod *
 authmethod_get(char *authlist)  authmethod_get(char *authlist)
 {  {
         char *name = NULL, *authname_old;  
         Authmethod *method = NULL;  
   
           char *name = NULL;
           int next;
   
         /* Use a suitable default if we're passed a nil list.  */          /* Use a suitable default if we're passed a nil list.  */
         if (authlist == NULL || strlen(authlist) == 0)          if (authlist == NULL || strlen(authlist) == 0)
                 authlist = def_authlist;                  authlist = options.preferred_authentications;
   
         if (authlist_current == NULL || strcmp(authlist, authlist_current) != 0) {          if (supported == NULL || strcmp(authlist, supported) != 0) {
                 /* start over if passed a different list */                  debug3("start over, passed a different list %s", authlist);
                 debug3("start over, passed a different list");                  if (supported != NULL)
                 authmethod_clear();                          xfree(supported);
                 authlist_current = xstrdup(authlist);                  supported = xstrdup(authlist);
                 authlist_working = xstrdup(authlist);                  preferred = options.preferred_authentications;
                 name = strtok_r(authlist_working, DELIM, &authlist_state);                  debug3("preferred %s", preferred);
         } else {                  current = NULL;
                 /*          } else if (current != NULL && authmethod_is_enabled(current))
                  * try to use previously used authentication method                  return current;
                  * or continue to use previously passed list  
                  */  
                 name = (authname_current != NULL) ?  
                     authname_current : strtok_r(NULL, DELIM, &authlist_state);  
         }  
   
         while (name != NULL) {          for (;;) {
                   if ((name = match_list(preferred, supported, &next)) == NULL) {
                           debug("no more auth methods to try");
                           current = NULL;
                           return NULL;
                   }
                   preferred += next;
                 debug3("authmethod_lookup %s", name);                  debug3("authmethod_lookup %s", name);
                 method = authmethod_lookup(name);                  debug3("remaining preferred: %s", preferred);
                 if (method != NULL && authmethod_is_enabled(method)) {                  if ((current = authmethod_lookup(name)) != NULL &&
                       authmethod_is_enabled(current)) {
                         debug3("authmethod_is_enabled %s", name);                          debug3("authmethod_is_enabled %s", name);
                         break;                          debug("next auth method to try is %s", name);
                           return current;
                 }                  }
                 name = strtok_r(NULL, DELIM, &authlist_state);  
                 method = NULL;  
         }          }
   }
   
         authname_old = authname_current;  
         if (method != NULL) {  
                 debug("next auth method to try is %s", name);  
                 authname_current = xstrdup(name);  
         } else {  
                 debug("no more auth methods to try");  
                 authname_current = NULL;  
         }  
   
         if (authname_old != NULL)  #define DELIM   ","
                 xfree(authname_old);  char *
   authmethods_get(void)
   {
           Authmethod *method = NULL;
           char buf[1024];
   
         return (method);          buf[0] = '\0';
           for (method = authmethods; method->name != NULL; method++) {
                   if (authmethod_is_enabled(method)) {
                           if (buf[0] != '\0')
                                   strlcat(buf, DELIM, sizeof buf);
                           strlcat(buf, method->name, sizeof buf);
                   }
           }
           return xstrdup(buf);
 }  }

Legend:
Removed from v.1.10.2.4  
changed lines
  Added in v.1.10.2.5