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

Diff for /src/usr.bin/ssh/auth2.c between version 1.89.2.5 and 1.90

version 1.89.2.5, 2003/04/03 22:35:16 version 1.90, 2002/05/12 23:53:45
Line 25 
Line 25 
 #include "includes.h"  #include "includes.h"
 RCSID("$OpenBSD$");  RCSID("$OpenBSD$");
   
   #include <openssl/evp.h>
   
 #include "ssh2.h"  #include "ssh2.h"
 #include "xmalloc.h"  #include "xmalloc.h"
   #include "rsa.h"
   #include "sshpty.h"
 #include "packet.h"  #include "packet.h"
   #include "buffer.h"
 #include "log.h"  #include "log.h"
 #include "servconf.h"  #include "servconf.h"
 #include "compat.h"  #include "compat.h"
   #include "channels.h"
   #include "bufaux.h"
 #include "auth.h"  #include "auth.h"
   #include "session.h"
 #include "dispatch.h"  #include "dispatch.h"
   #include "key.h"
   #include "cipher.h"
   #include "kex.h"
 #include "pathnames.h"  #include "pathnames.h"
   #include "uidswap.h"
   #include "auth-options.h"
   #include "hostfile.h"
   #include "canohost.h"
   #include "match.h"
 #include "monitor_wrap.h"  #include "monitor_wrap.h"
   
 /* import */  /* import */
Line 42 
Line 58 
 extern int session_id2_len;  extern int session_id2_len;
   
 Authctxt *x_authctxt = NULL;  Authctxt *x_authctxt = NULL;
   static int one = 1;
   
 /* methods */  typedef struct Authmethod Authmethod;
   struct Authmethod {
 extern Authmethod method_none;          char    *name;
 extern Authmethod method_pubkey;          int     (*userauth)(Authctxt *authctxt);
 extern Authmethod method_passwd;          int     *enabled;
 extern Authmethod method_kbdint;  
 extern Authmethod method_hostbased;  
   
 Authmethod *authmethods[] = {  
         &method_none,  
         &method_pubkey,  
         &method_passwd,  
         &method_kbdint,  
         &method_hostbased,  
         NULL  
 };  };
   
 /* protocol */  /* protocol */
Line 71 
Line 78 
 int user_key_allowed(struct passwd *, Key *);  int user_key_allowed(struct passwd *, Key *);
 int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);  int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
   
   /* auth */
   static void userauth_banner(void);
   static int userauth_none(Authctxt *);
   static int userauth_passwd(Authctxt *);
   static int userauth_pubkey(Authctxt *);
   static int userauth_hostbased(Authctxt *);
   static int userauth_kbdint(Authctxt *);
   
   Authmethod authmethods[] = {
           {"none",
                   userauth_none,
                   &one},
           {"publickey",
                   userauth_pubkey,
                   &options.pubkey_authentication},
           {"password",
                   userauth_passwd,
                   &options.password_authentication},
           {"keyboard-interactive",
                   userauth_kbdint,
                   &options.kbd_interactive_authentication},
           {"hostbased",
                   userauth_hostbased,
                   &options.hostbased_authentication},
           {NULL, NULL, NULL}
   };
   
 /*  /*
  * loop until authctxt->success == TRUE   * loop until authctxt->success == TRUE
  */   */
Line 98 
Line 132 
 {  {
         Authctxt *authctxt = ctxt;          Authctxt *authctxt = ctxt;
         u_int len;          u_int len;
         int acceptit = 0;          int accept = 0;
         char *service = packet_get_string(&len);          char *service = packet_get_string(&len);
         packet_check_eom();          packet_check_eom();
   
Line 107 
Line 141 
   
         if (strcmp(service, "ssh-userauth") == 0) {          if (strcmp(service, "ssh-userauth") == 0) {
                 if (!authctxt->success) {                  if (!authctxt->success) {
                         acceptit = 1;                          accept = 1;
                         /* now we can handle user-auth requests */                          /* now we can handle user-auth requests */
                         dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);                          dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
                 }                  }
         }          }
         /* XXX all other service requests are denied */          /* XXX all other service requests are denied */
   
         if (acceptit) {          if (accept) {
                 packet_start(SSH2_MSG_SERVICE_ACCEPT);                  packet_start(SSH2_MSG_SERVICE_ACCEPT);
                 packet_put_cstring(service);                  packet_put_cstring(service);
                 packet_send();                  packet_send();
Line 227 
Line 261 
         }          }
 }  }
   
   char *
   auth2_read_banner(void)
   {
           struct stat st;
           char *banner = NULL;
           off_t len, n;
           int fd;
   
           if ((fd = open(options.banner, O_RDONLY)) == -1)
                   return (NULL);
           if (fstat(fd, &st) == -1) {
                   close(fd);
                   return (NULL);
           }
           len = st.st_size;
           banner = xmalloc(len + 1);
           n = atomicio(read, fd, banner, len);
           close(fd);
   
           if (n != len) {
                   free(banner);
                   return (NULL);
           }
           banner[n] = '\0';
   
           return (banner);
   }
   
   static void
   userauth_banner(void)
   {
           char *banner = NULL;
   
           if (options.banner == NULL || (datafellows & SSH_BUG_BANNER))
                   return;
   
           if ((banner = PRIVSEP(auth2_read_banner())) == NULL)
                   goto done;
   
           packet_start(SSH2_MSG_USERAUTH_BANNER);
           packet_put_cstring(banner);
           packet_put_cstring("");         /* language, unused */
           packet_send();
           debug("userauth_banner: sent");
   done:
           if (banner)
                   xfree(banner);
           return;
   }
   
   static int
   userauth_none(Authctxt *authctxt)
   {
           /* disable method "none", only allowed one time */
           Authmethod *m = authmethod_lookup("none");
           if (m != NULL)
                   m->enabled = NULL;
           packet_check_eom();
           userauth_banner();
           return (authctxt->valid ? PRIVSEP(auth_password(authctxt, "")) : 0);
   }
   
   static int
   userauth_passwd(Authctxt *authctxt)
   {
           char *password;
           int authenticated = 0;
           int change;
           u_int len;
           change = packet_get_char();
           if (change)
                   log("password change not supported");
           password = packet_get_string(&len);
           packet_check_eom();
           if (authctxt->valid &&
               PRIVSEP(auth_password(authctxt, password)) == 1)
                   authenticated = 1;
           memset(password, 0, len);
           xfree(password);
           return authenticated;
   }
   
   static int
   userauth_kbdint(Authctxt *authctxt)
   {
           int authenticated = 0;
           char *lang, *devs;
   
           lang = packet_get_string(NULL);
           devs = packet_get_string(NULL);
           packet_check_eom();
   
           debug("keyboard-interactive devs %s", devs);
   
           if (options.challenge_response_authentication)
                   authenticated = auth2_challenge(authctxt, devs);
   
           xfree(devs);
           xfree(lang);
           return authenticated;
   }
   
   static int
   userauth_pubkey(Authctxt *authctxt)
   {
           Buffer b;
           Key *key = NULL;
           char *pkalg;
           u_char *pkblob, *sig;
           u_int alen, blen, slen;
           int have_sig, pktype;
           int authenticated = 0;
   
           if (!authctxt->valid) {
                   debug2("userauth_pubkey: disabled because of invalid user");
                   return 0;
           }
           have_sig = packet_get_char();
           if (datafellows & SSH_BUG_PKAUTH) {
                   debug2("userauth_pubkey: SSH_BUG_PKAUTH");
                   /* no explicit pkalg given */
                   pkblob = packet_get_string(&blen);
                   buffer_init(&b);
                   buffer_append(&b, pkblob, blen);
                   /* so we have to extract the pkalg from the pkblob */
                   pkalg = buffer_get_string(&b, &alen);
                   buffer_free(&b);
           } else {
                   pkalg = packet_get_string(&alen);
                   pkblob = packet_get_string(&blen);
           }
           pktype = key_type_from_name(pkalg);
           if (pktype == KEY_UNSPEC) {
                   /* this is perfectly legal */
                   log("userauth_pubkey: unsupported public key algorithm: %s",
                       pkalg);
                   goto done;
           }
           key = key_from_blob(pkblob, blen);
           if (key == NULL) {
                   error("userauth_pubkey: cannot decode key: %s", pkalg);
                   goto done;
           }
           if (key->type != pktype) {
                   error("userauth_pubkey: type mismatch for decoded key "
                       "(received %d, expected %d)", key->type, pktype);
                   goto done;
           }
           if (have_sig) {
                   sig = packet_get_string(&slen);
                   packet_check_eom();
                   buffer_init(&b);
                   if (datafellows & SSH_OLD_SESSIONID) {
                           buffer_append(&b, session_id2, session_id2_len);
                   } else {
                           buffer_put_string(&b, session_id2, session_id2_len);
                   }
                   /* reconstruct packet */
                   buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
                   buffer_put_cstring(&b, authctxt->user);
                   buffer_put_cstring(&b,
                       datafellows & SSH_BUG_PKSERVICE ?
                       "ssh-userauth" :
                       authctxt->service);
                   if (datafellows & SSH_BUG_PKAUTH) {
                           buffer_put_char(&b, have_sig);
                   } else {
                           buffer_put_cstring(&b, "publickey");
                           buffer_put_char(&b, have_sig);
                           buffer_put_cstring(&b, pkalg);
                   }
                   buffer_put_string(&b, pkblob, blen);
   #ifdef DEBUG_PK
                   buffer_dump(&b);
   #endif
                   /* test for correct signature */
                   authenticated = 0;
                   if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
                       PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
                                   buffer_len(&b))) == 1)
                           authenticated = 1;
                   buffer_clear(&b);
                   xfree(sig);
           } else {
                   debug("test whether pkalg/pkblob are acceptable");
                   packet_check_eom();
   
                   /* XXX fake reply and always send PK_OK ? */
                   /*
                    * XXX this allows testing whether a user is allowed
                    * to login: if you happen to have a valid pubkey this
                    * message is sent. the message is NEVER sent at all
                    * if a user is not allowed to login. is this an
                    * issue? -markus
                    */
                   if (PRIVSEP(user_key_allowed(authctxt->pw, key))) {
                           packet_start(SSH2_MSG_USERAUTH_PK_OK);
                           packet_put_string(pkalg, alen);
                           packet_put_string(pkblob, blen);
                           packet_send();
                           packet_write_wait();
                           authctxt->postponed = 1;
                   }
           }
           if (authenticated != 1)
                   auth_clear_options();
   done:
           debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
           if (key != NULL)
                   key_free(key);
           xfree(pkalg);
           xfree(pkblob);
           return authenticated;
   }
   
   static int
   userauth_hostbased(Authctxt *authctxt)
   {
           Buffer b;
           Key *key = NULL;
           char *pkalg, *cuser, *chost, *service;
           u_char *pkblob, *sig;
           u_int alen, blen, slen;
           int pktype;
           int authenticated = 0;
   
           if (!authctxt->valid) {
                   debug2("userauth_hostbased: disabled because of invalid user");
                   return 0;
           }
           pkalg = packet_get_string(&alen);
           pkblob = packet_get_string(&blen);
           chost = packet_get_string(NULL);
           cuser = packet_get_string(NULL);
           sig = packet_get_string(&slen);
   
           debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
               cuser, chost, pkalg, slen);
   #ifdef DEBUG_PK
           debug("signature:");
           buffer_init(&b);
           buffer_append(&b, sig, slen);
           buffer_dump(&b);
           buffer_free(&b);
   #endif
           pktype = key_type_from_name(pkalg);
           if (pktype == KEY_UNSPEC) {
                   /* this is perfectly legal */
                   log("userauth_hostbased: unsupported "
                       "public key algorithm: %s", pkalg);
                   goto done;
           }
           key = key_from_blob(pkblob, blen);
           if (key == NULL) {
                   error("userauth_hostbased: cannot decode key: %s", pkalg);
                   goto done;
           }
           if (key->type != pktype) {
                   error("userauth_hostbased: type mismatch for decoded key "
                       "(received %d, expected %d)", key->type, pktype);
                   goto done;
           }
           service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
               authctxt->service;
           buffer_init(&b);
           buffer_put_string(&b, session_id2, session_id2_len);
           /* reconstruct packet */
           buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
           buffer_put_cstring(&b, authctxt->user);
           buffer_put_cstring(&b, service);
           buffer_put_cstring(&b, "hostbased");
           buffer_put_string(&b, pkalg, alen);
           buffer_put_string(&b, pkblob, blen);
           buffer_put_cstring(&b, chost);
           buffer_put_cstring(&b, cuser);
   #ifdef DEBUG_PK
           buffer_dump(&b);
   #endif
           /* test for allowed key and correct signature */
           authenticated = 0;
           if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
               PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
                           buffer_len(&b))) == 1)
                   authenticated = 1;
   
           buffer_clear(&b);
   done:
           debug2("userauth_hostbased: authenticated %d", authenticated);
           if (key != NULL)
                   key_free(key);
           xfree(pkalg);
           xfree(pkblob);
           xfree(cuser);
           xfree(chost);
           xfree(sig);
           return authenticated;
   }
   
 /* get current user */  /* get current user */
   
 struct passwd*  struct passwd*
Line 240 
Line 572 
 static char *  static char *
 authmethods_get(void)  authmethods_get(void)
 {  {
           Authmethod *method = NULL;
         Buffer b;          Buffer b;
         char *list;          char *list;
         int i;  
   
         buffer_init(&b);          buffer_init(&b);
         for (i = 0; authmethods[i] != NULL; i++) {          for (method = authmethods; method->name != NULL; method++) {
                 if (strcmp(authmethods[i]->name, "none") == 0)                  if (strcmp(method->name, "none") == 0)
                         continue;                          continue;
                 if (authmethods[i]->enabled != NULL &&                  if (method->enabled != NULL && *(method->enabled) != 0) {
                     *(authmethods[i]->enabled) != 0) {  
                         if (buffer_len(&b) > 0)                          if (buffer_len(&b) > 0)
                                 buffer_append(&b, ",", 1);                                  buffer_append(&b, ",", 1);
                         buffer_append(&b, authmethods[i]->name,                          buffer_append(&b, method->name, strlen(method->name));
                             strlen(authmethods[i]->name));  
                 }                  }
         }          }
         buffer_append(&b, "\0", 1);          buffer_append(&b, "\0", 1);
Line 265 
Line 595 
 static Authmethod *  static Authmethod *
 authmethod_lookup(const char *name)  authmethod_lookup(const char *name)
 {  {
         int i;          Authmethod *method = NULL;
   
         if (name != NULL)          if (name != NULL)
                 for (i = 0; authmethods[i] != NULL; i++)                  for (method = authmethods; method->name != NULL; method++)
                         if (authmethods[i]->enabled != NULL &&                          if (method->enabled != NULL &&
                             *(authmethods[i]->enabled) != 0 &&                              *(method->enabled) != 0 &&
                             strcmp(name, authmethods[i]->name) == 0)                              strcmp(name, method->name) == 0)
                                 return authmethods[i];                                  return method;
         debug2("Unrecognized authentication method name: %s",          debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
             name ? name : "NULL");  
         return NULL;          return NULL;
   }
   
   /* return 1 if user allows given key */
   static int
   user_key_allowed2(struct passwd *pw, Key *key, char *file)
   {
           char line[8192];
           int found_key = 0;
           FILE *f;
           u_long linenum = 0;
           struct stat st;
           Key *found;
           char *fp;
   
           if (pw == NULL)
                   return 0;
   
           /* Temporarily use the user's uid. */
           temporarily_use_uid(pw);
   
           debug("trying public key file %s", file);
   
           /* Fail quietly if file does not exist */
           if (stat(file, &st) < 0) {
                   /* Restore the privileged uid. */
                   restore_uid();
                   return 0;
           }
           /* Open the file containing the authorized keys. */
           f = fopen(file, "r");
           if (!f) {
                   /* Restore the privileged uid. */
                   restore_uid();
                   return 0;
           }
           if (options.strict_modes &&
               secure_filename(f, file, pw, line, sizeof(line)) != 0) {
                   fclose(f);
                   log("Authentication refused: %s", line);
                   restore_uid();
                   return 0;
           }
   
           found_key = 0;
           found = key_new(key->type);
   
           while (fgets(line, sizeof(line), f)) {
                   char *cp, *options = NULL;
                   linenum++;
                   /* Skip leading whitespace, empty and comment lines. */
                   for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
                           ;
                   if (!*cp || *cp == '\n' || *cp == '#')
                           continue;
   
                   if (key_read(found, &cp) != 1) {
                           /* no key?  check if there are options for this key */
                           int quoted = 0;
                           debug2("user_key_allowed: check options: '%s'", cp);
                           options = cp;
                           for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
                                   if (*cp == '\\' && cp[1] == '"')
                                           cp++;   /* Skip both */
                                   else if (*cp == '"')
                                           quoted = !quoted;
                           }
                           /* Skip remaining whitespace. */
                           for (; *cp == ' ' || *cp == '\t'; cp++)
                                   ;
                           if (key_read(found, &cp) != 1) {
                                   debug2("user_key_allowed: advance: '%s'", cp);
                                   /* still no key?  advance to next line*/
                                   continue;
                           }
                   }
                   if (key_equal(found, key) &&
                       auth_parse_options(pw, options, file, linenum) == 1) {
                           found_key = 1;
                           debug("matching key found: file %s, line %lu",
                               file, linenum);
                           fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
                           verbose("Found matching %s key: %s",
                               key_type(found), fp);
                           xfree(fp);
                           break;
                   }
           }
           restore_uid();
           fclose(f);
           key_free(found);
           if (!found_key)
                   debug2("key not found");
           return found_key;
   }
   
   /* check whether given key is in .ssh/authorized_keys* */
   int
   user_key_allowed(struct passwd *pw, Key *key)
   {
           int success;
           char *file;
   
           file = authorized_keys_file(pw);
           success = user_key_allowed2(pw, key, file);
           xfree(file);
           if (success)
                   return success;
   
           /* try suffix "2" for backward compat, too */
           file = authorized_keys_file2(pw);
           success = user_key_allowed2(pw, key, file);
           xfree(file);
           return success;
   }
   
   /* return 1 if given hostkey is allowed */
   int
   hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
       Key *key)
   {
           const char *resolvedname, *ipaddr, *lookup;
           HostStatus host_status;
           int len;
   
           resolvedname = get_canonical_hostname(options.verify_reverse_mapping);
           ipaddr = get_remote_ipaddr();
   
           debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
               chost, resolvedname, ipaddr);
   
           if (options.hostbased_uses_name_from_packet_only) {
                   if (auth_rhosts2(pw, cuser, chost, chost) == 0)
                           return 0;
                   lookup = chost;
           } else {
                   if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
                           debug2("stripping trailing dot from chost %s", chost);
                           chost[len - 1] = '\0';
                   }
                   if (strcasecmp(resolvedname, chost) != 0)
                           log("userauth_hostbased mismatch: "
                               "client sends %s, but we resolve %s to %s",
                               chost, ipaddr, resolvedname);
                   if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0)
                           return 0;
                   lookup = resolvedname;
           }
           debug2("userauth_hostbased: access allowed by auth_rhosts2");
   
           host_status = check_key_in_hostfiles(pw, key, lookup,
               _PATH_SSH_SYSTEM_HOSTFILE,
               options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
   
           /* backward compat if no key has been found. */
           if (host_status == HOST_NEW)
                   host_status = check_key_in_hostfiles(pw, key, lookup,
                       _PATH_SSH_SYSTEM_HOSTFILE2,
                       options.ignore_user_known_hosts ? NULL :
                       _PATH_SSH_USER_HOSTFILE2);
   
           return (host_status == HOST_OK);
 }  }

Legend:
Removed from v.1.89.2.5  
changed lines
  Added in v.1.90