[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.91 and 1.92

version 1.91, 2002/05/13 02:37:39 version 1.92, 2002/05/25 18:51:07
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"
 #include "atomicio.h"  
   
 /* import */  /* import */
 extern ServerOptions options;  extern ServerOptions options;
Line 80 
Line 63 
 int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);  int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
   
 /* auth */  /* 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[] = {  Authmethod authmethods[] = {
         {"none",          {"none",
Line 262 
Line 239 
         }          }
 }  }
   
 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 605 
Line 284 
                                 return method;                                  return method;
         debug2("Unrecognized authentication method name: %s", name ? name : "NULL");          debug2("Unrecognized authentication method name: %s", 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.91  
changed lines
  Added in v.1.92