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

Diff for /src/usr.bin/ssh/auth.c between version 1.5 and 1.6

version 1.5, 2000/04/26 20:56:29 version 1.6, 2000/04/26 21:28:31
Line 7 
Line 7 
 #include "includes.h"  #include "includes.h"
 RCSID("$OpenBSD$");  RCSID("$OpenBSD$");
   
 #include <openssl/dsa.h>  
 #include <openssl/rsa.h>  
 #include <openssl/evp.h>  
   
 #include "xmalloc.h"  #include "xmalloc.h"
 #include "rsa.h"  #include "rsa.h"
 #include "ssh.h"  #include "ssh.h"
Line 23 
Line 19 
 #include "compat.h"  #include "compat.h"
 #include "channels.h"  #include "channels.h"
 #include "match.h"  #include "match.h"
   
 #include "bufaux.h"  #include "bufaux.h"
 #include "ssh2.h"  #include "ssh2.h"
 #include "auth.h"  #include "auth.h"
 #include "session.h"  #include "session.h"
 #include "dispatch.h"  #include "dispatch.h"
   
 #include "key.h"  
 #include "kex.h"  
 #include "dsa.h"  
 #include "uidswap.h"  
 #include "channels.h"  
   
 /* import */  /* import */
 extern ServerOptions options;  extern ServerOptions options;
Line 116 
Line 108 
         }          }
         /* We found no reason not to let this user try to log on... */          /* We found no reason not to let this user try to log on... */
         return 1;          return 1;
 }  
   
 /* import */  
 extern ServerOptions options;  
 extern char *forced_command;  
   
 /*  
  * convert ssh auth msg type into description  
  */  
 char *  
 get_authname(int type)  
 {  
         static char buf[1024];  
         switch (type) {  
         case SSH_CMSG_AUTH_PASSWORD:  
                 return "password";  
         case SSH_CMSG_AUTH_RSA:  
                 return "rsa";  
         case SSH_CMSG_AUTH_RHOSTS_RSA:  
                 return "rhosts-rsa";  
         case SSH_CMSG_AUTH_RHOSTS:  
                 return "rhosts";  
 #ifdef KRB4  
         case SSH_CMSG_AUTH_KERBEROS:  
                 return "kerberos";  
 #endif  
 #ifdef SKEY  
         case SSH_CMSG_AUTH_TIS_RESPONSE:  
                 return "s/key";  
 #endif  
         }  
         snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);  
         return buf;  
 }  
   
 #define AUTH_FAIL_MAX 6  
 #define AUTH_FAIL_LOG (AUTH_FAIL_MAX/2)  
 #define AUTH_FAIL_MSG "Too many authentication failures for %.100s"  
   
 /*  
  * The user does not exist or access is denied,  
  * but fake indication that authentication is needed.  
  */  
 void  
 do_fake_authloop1(char *user)  
 {  
         int attempt = 0;  
   
         log("Faking authloop for illegal user %.200s from %.200s port %d",  
             user,  
             get_remote_ipaddr(),  
             get_remote_port());  
   
         /* Indicate that authentication is needed. */  
         packet_start(SSH_SMSG_FAILURE);  
         packet_send();  
         packet_write_wait();  
   
         /*  
          * Keep reading packets, and always respond with a failure.  This is  
          * to avoid disclosing whether such a user really exists.  
          */  
         for (attempt = 1;; attempt++) {  
                 /* Read a packet.  This will not return if the client disconnects. */  
                 int plen;  
                 int type = packet_read(&plen);  
 #ifdef SKEY  
                 unsigned int dlen;  
                 char *password, *skeyinfo;  
                 password = NULL;  
                 /* Try to send a fake s/key challenge. */  
                 if (options.skey_authentication == 1 &&  
                     (skeyinfo = skey_fake_keyinfo(user)) != NULL) {  
                         if (type == SSH_CMSG_AUTH_TIS) {  
                                 packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);  
                                 packet_put_string(skeyinfo, strlen(skeyinfo));  
                                 packet_send();  
                                 packet_write_wait();  
                                 continue;  
                         } else if (type == SSH_CMSG_AUTH_PASSWORD &&  
                                    options.password_authentication &&  
                                    (password = packet_get_string(&dlen)) != NULL &&  
                                    dlen == 5 &&  
                                    strncasecmp(password, "s/key", 5) == 0 ) {  
                                 packet_send_debug(skeyinfo);  
                         }  
                 }  
                 if (password != NULL)  
                         xfree(password);  
 #endif  
                 if (attempt > AUTH_FAIL_MAX)  
                         packet_disconnect(AUTH_FAIL_MSG, user);  
   
                 /*  
                  * Send failure.  This should be indistinguishable from a  
                  * failed authentication.  
                  */  
                 packet_start(SSH_SMSG_FAILURE);  
                 packet_send();  
                 packet_write_wait();  
         }  
         /* NOTREACHED */  
         abort();  
 }  
   
 /*  
  * read packets and try to authenticate local user *pw.  
  * return if authentication is successfull  
  */  
 void  
 do_authloop(struct passwd * pw)  
 {  
         int attempt = 0;  
         unsigned int bits;  
         RSA *client_host_key;  
         BIGNUM *n;  
         char *client_user, *password;  
         char user[1024];  
         unsigned int dlen;  
         int plen, nlen, elen;  
         unsigned int ulen;  
         int type = 0;  
         void (*authlog) (const char *fmt,...) = verbose;  
   
         /* Indicate that authentication is needed. */  
         packet_start(SSH_SMSG_FAILURE);  
         packet_send();  
         packet_write_wait();  
   
         for (attempt = 1;; attempt++) {  
                 int authenticated = 0;  
                 strlcpy(user, "", sizeof user);  
   
                 /* Get a packet from the client. */  
                 type = packet_read(&plen);  
   
                 /* Process the packet. */  
                 switch (type) {  
 #ifdef AFS  
                 case SSH_CMSG_HAVE_KERBEROS_TGT:  
                         if (!options.kerberos_tgt_passing) {  
                                 /* packet_get_all(); */  
                                 verbose("Kerberos tgt passing disabled.");  
                                 break;  
                         } else {  
                                 /* Accept Kerberos tgt. */  
                                 char *tgt = packet_get_string(&dlen);  
                                 packet_integrity_check(plen, 4 + dlen, type);  
                                 if (!auth_kerberos_tgt(pw, tgt))  
                                         verbose("Kerberos tgt REFUSED for %s", pw->pw_name);  
                                 xfree(tgt);  
                         }  
                         continue;  
   
                 case SSH_CMSG_HAVE_AFS_TOKEN:  
                         if (!options.afs_token_passing || !k_hasafs()) {  
                                 /* packet_get_all(); */  
                                 verbose("AFS token passing disabled.");  
                                 break;  
                         } else {  
                                 /* Accept AFS token. */  
                                 char *token_string = packet_get_string(&dlen);  
                                 packet_integrity_check(plen, 4 + dlen, type);  
                                 if (!auth_afs_token(pw, token_string))  
                                         verbose("AFS token REFUSED for %s", pw->pw_name);  
                                 xfree(token_string);  
                         }  
                         continue;  
 #endif /* AFS */  
 #ifdef KRB4  
                 case SSH_CMSG_AUTH_KERBEROS:  
                         if (!options.kerberos_authentication) {  
                                 /* packet_get_all(); */  
                                 verbose("Kerberos authentication disabled.");  
                                 break;  
                         } else {  
                                 /* Try Kerberos v4 authentication. */  
                                 KTEXT_ST auth;  
                                 char *tkt_user = NULL;  
                                 char *kdata = packet_get_string((unsigned int *) &auth.length);  
                                 packet_integrity_check(plen, 4 + auth.length, type);  
   
                                 if (auth.length < MAX_KTXT_LEN)  
                                         memcpy(auth.dat, kdata, auth.length);  
                                 xfree(kdata);  
   
                                 authenticated = auth_krb4(pw->pw_name, &auth, &tkt_user);  
   
                                 if (authenticated) {  
                                         snprintf(user, sizeof user, " tktuser %s", tkt_user);  
                                         xfree(tkt_user);  
                                 }  
                         }  
                         break;  
 #endif /* KRB4 */  
   
                 case SSH_CMSG_AUTH_RHOSTS:  
                         if (!options.rhosts_authentication) {  
                                 verbose("Rhosts authentication disabled.");  
                                 break;  
                         }  
                         /*  
                          * Get client user name.  Note that we just have to  
                          * trust the client; this is one reason why rhosts  
                          * authentication is insecure. (Another is  
                          * IP-spoofing on a local network.)  
                          */  
                         client_user = packet_get_string(&ulen);  
                         packet_integrity_check(plen, 4 + ulen, type);  
   
                         /* Try to authenticate using /etc/hosts.equiv and  
                            .rhosts. */  
                         authenticated = auth_rhosts(pw, client_user);  
   
                         snprintf(user, sizeof user, " ruser %s", client_user);  
                         xfree(client_user);  
                         break;  
   
                 case SSH_CMSG_AUTH_RHOSTS_RSA:  
                         if (!options.rhosts_rsa_authentication) {  
                                 verbose("Rhosts with RSA authentication disabled.");  
                                 break;  
                         }  
                         /*  
                          * Get client user name.  Note that we just have to  
                          * trust the client; root on the client machine can  
                          * claim to be any user.  
                          */  
                         client_user = packet_get_string(&ulen);  
   
                         /* Get the client host key. */  
                         client_host_key = RSA_new();  
                         if (client_host_key == NULL)  
                                 fatal("RSA_new failed");  
                         client_host_key->e = BN_new();  
                         client_host_key->n = BN_new();  
                         if (client_host_key->e == NULL || client_host_key->n == NULL)  
                                 fatal("BN_new failed");  
                         bits = packet_get_int();  
                         packet_get_bignum(client_host_key->e, &elen);  
                         packet_get_bignum(client_host_key->n, &nlen);  
   
                         if (bits != BN_num_bits(client_host_key->n))  
                                 error("Warning: keysize mismatch for client_host_key: "  
                                       "actual %d, announced %d", BN_num_bits(client_host_key->n), bits);  
                         packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type);  
   
                         authenticated = auth_rhosts_rsa(pw, client_user, client_host_key);  
                         RSA_free(client_host_key);  
   
                         snprintf(user, sizeof user, " ruser %s", client_user);  
                         xfree(client_user);  
                         break;  
   
                 case SSH_CMSG_AUTH_RSA:  
                         if (!options.rsa_authentication) {  
                                 verbose("RSA authentication disabled.");  
                                 break;  
                         }  
                         /* RSA authentication requested. */  
                         n = BN_new();  
                         packet_get_bignum(n, &nlen);  
                         packet_integrity_check(plen, nlen, type);  
                         authenticated = auth_rsa(pw, n);  
                         BN_clear_free(n);  
                         break;  
   
                 case SSH_CMSG_AUTH_PASSWORD:  
                         if (!options.password_authentication) {  
                                 verbose("Password authentication disabled.");  
                                 break;  
                         }  
                         /*  
                          * Read user password.  It is in plain text, but was  
                          * transmitted over the encrypted channel so it is  
                          * not visible to an outside observer.  
                          */  
                         password = packet_get_string(&dlen);  
                         packet_integrity_check(plen, 4 + dlen, type);  
   
                         /* Try authentication with the password. */  
                         authenticated = auth_password(pw, password);  
   
                         memset(password, 0, strlen(password));  
                         xfree(password);  
                         break;  
   
 #ifdef SKEY  
                 case SSH_CMSG_AUTH_TIS:  
                         debug("rcvd SSH_CMSG_AUTH_TIS");  
                         if (options.skey_authentication == 1) {  
                                 char *skeyinfo = skey_keyinfo(pw->pw_name);  
                                 if (skeyinfo == NULL) {  
                                         debug("generating fake skeyinfo for %.100s.", pw->pw_name);  
                                         skeyinfo = skey_fake_keyinfo(pw->pw_name);  
                                 }  
                                 if (skeyinfo != NULL) {  
                                         /* we send our s/key- in tis-challenge messages */  
                                         debug("sending challenge '%s'", skeyinfo);  
                                         packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);  
                                         packet_put_string(skeyinfo, strlen(skeyinfo));  
                                         packet_send();  
                                         packet_write_wait();  
                                         continue;  
                                 }  
                         }  
                         break;  
                 case SSH_CMSG_AUTH_TIS_RESPONSE:  
                         debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");  
                         if (options.skey_authentication == 1) {  
                                 char *response = packet_get_string(&dlen);  
                                 debug("skey response == '%s'", response);  
                                 packet_integrity_check(plen, 4 + dlen, type);  
                                 authenticated = (skey_haskey(pw->pw_name) == 0 &&  
                                                  skey_passcheck(pw->pw_name, response) != -1);  
                                 xfree(response);  
                         }  
                         break;  
 #else  
                 case SSH_CMSG_AUTH_TIS:  
                         /* TIS Authentication is unsupported */  
                         log("TIS authentication unsupported.");  
                         break;  
 #endif  
   
                 default:  
                         /*  
                          * Any unknown messages will be ignored (and failure  
                          * returned) during authentication.  
                          */  
                         log("Unknown message during authentication: type %d", type);  
                         break;  
                 }  
   
                 /*  
                  * Check if the user is logging in as root and root logins  
                  * are disallowed.  
                  * Note that root login is allowed for forced commands.  
                  */  
                 if (authenticated && pw->pw_uid == 0 && !options.permit_root_login) {  
                         if (forced_command) {  
                                 log("Root login accepted for forced command.");  
                         } else {  
                                 authenticated = 0;  
                                 log("ROOT LOGIN REFUSED FROM %.200s",  
                                     get_canonical_hostname());  
                         }  
                 }  
   
                 /* Raise logging level */  
                 if (authenticated ||  
                     attempt == AUTH_FAIL_LOG ||  
                     type == SSH_CMSG_AUTH_PASSWORD)  
                         authlog = log;  
   
                 authlog("%s %s for %.200s from %.200s port %d%s",  
                         authenticated ? "Accepted" : "Failed",  
                         get_authname(type),  
                         pw->pw_uid == 0 ? "ROOT" : pw->pw_name,  
                         get_remote_ipaddr(),  
                         get_remote_port(),  
                         user);  
   
                 if (authenticated)  
                         return;  
   
                 if (attempt > AUTH_FAIL_MAX)  
                         packet_disconnect(AUTH_FAIL_MSG, pw->pw_name);  
   
                 /* Send a message indicating that the authentication attempt failed. */  
                 packet_start(SSH_SMSG_FAILURE);  
                 packet_send();  
                 packet_write_wait();  
         }  
 }  
   
 /*  
  * Performs authentication of an incoming connection.  Session key has already  
  * been exchanged and encryption is enabled.  
  */  
 void  
 do_authentication()  
 {  
         struct passwd *pw, pwcopy;  
         int plen;  
         unsigned int ulen;  
         char *user;  
   
         /* Get the name of the user that we wish to log in as. */  
         packet_read_expect(&plen, SSH_CMSG_USER);  
   
         /* Get the user name. */  
         user = packet_get_string(&ulen);  
         packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER);  
   
         setproctitle("%s", user);  
   
 #ifdef AFS  
         /* If machine has AFS, set process authentication group. */  
         if (k_hasafs()) {  
                 k_setpag();  
                 k_unlog();  
         }  
 #endif /* AFS */  
   
         /* Verify that the user is a valid user. */  
         pw = getpwnam(user);  
         if (!pw || !allowed_user(pw))  
                 do_fake_authloop1(user);  
         xfree(user);  
   
         /* Take a copy of the returned structure. */  
         memset(&pwcopy, 0, sizeof(pwcopy));  
         pwcopy.pw_name = xstrdup(pw->pw_name);  
         pwcopy.pw_passwd = xstrdup(pw->pw_passwd);  
         pwcopy.pw_uid = pw->pw_uid;  
         pwcopy.pw_gid = pw->pw_gid;  
         pwcopy.pw_dir = xstrdup(pw->pw_dir);  
         pwcopy.pw_shell = xstrdup(pw->pw_shell);  
         pw = &pwcopy;  
   
         /*  
          * If we are not running as root, the user must have the same uid as  
          * the server.  
          */  
         if (getuid() != 0 && pw->pw_uid != getuid())  
                 packet_disconnect("Cannot change user when server not running as root.");  
   
         debug("Attempting authentication for %.100s.", pw->pw_name);  
   
         /* If the user has no password, accept authentication immediately. */  
         if (options.password_authentication &&  
 #ifdef KRB4  
             (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&  
 #endif /* KRB4 */  
             auth_password(pw, "")) {  
                 /* Authentication with empty password succeeded. */  
                 log("Login for user %s from %.100s, accepted without authentication.",  
                     pw->pw_name, get_remote_ipaddr());  
         } else {  
                 /* Loop until the user has been authenticated or the  
                    connection is closed, do_authloop() returns only if  
                    authentication is successfull */  
                 do_authloop(pw);  
         }  
   
         /* The user has been authenticated and accepted. */  
         packet_start(SSH_SMSG_SUCCESS);  
         packet_send();  
         packet_write_wait();  
   
         /* Perform session preparation. */  
         do_authenticated(pw);  
 }  
   
 /* import */  
 extern ServerOptions options;  
 extern unsigned char *session_id2;  
 extern int session_id2_len;  
   
 /* protocol */  
   
 void    input_service_request(int type, int plen);  
 void    input_userauth_request(int type, int plen);  
 void    protocol_error(int type, int plen);  
   
 /* auth */  
 int     ssh2_auth_none(struct passwd *pw);  
 int     ssh2_auth_password(struct passwd *pw);  
 int     ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen);  
   
 /* helper */  
 struct passwd*   auth_set_user(char *u, char *s);  
 int     user_dsa_key_allowed(struct passwd *pw, Key *key);  
   
 typedef struct Authctxt Authctxt;  
 struct Authctxt {  
         char *user;  
         char *service;  
         struct passwd pw;  
         int valid;  
 };  
 static Authctxt *authctxt = NULL;  
 static int userauth_success = 0;  
   
 /* set and get current user */  
   
 struct passwd*  
 auth_get_user(void)  
 {  
         return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;  
 }  
   
 struct passwd*  
 auth_set_user(char *u, char *s)  
 {  
         struct passwd *pw, *copy;  
   
         if (authctxt == NULL) {  
                 authctxt = xmalloc(sizeof(*authctxt));  
                 authctxt->valid = 0;  
                 authctxt->user = xstrdup(u);  
                 authctxt->service = xstrdup(s);  
                 setproctitle("%s", u);  
                 pw = getpwnam(u);  
                 if (!pw || !allowed_user(pw)) {  
                         log("auth_set_user: bad user %s", u);  
                         return NULL;  
                 }  
                 copy = &authctxt->pw;  
                 memset(copy, 0, sizeof(*copy));  
                 copy->pw_name = xstrdup(pw->pw_name);  
                 copy->pw_passwd = xstrdup(pw->pw_passwd);  
                 copy->pw_uid = pw->pw_uid;  
                 copy->pw_gid = pw->pw_gid;  
                 copy->pw_dir = xstrdup(pw->pw_dir);  
                 copy->pw_shell = xstrdup(pw->pw_shell);  
                 authctxt->valid = 1;  
         } else {  
                 if (strcmp(u, authctxt->user) != 0 ||  
                     strcmp(s, authctxt->service) != 0) {  
                         log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",  
                             u, s, authctxt->user, authctxt->service);  
                         return NULL;  
                 }  
         }  
         return auth_get_user();  
 }  
   
 /*  
  * loop until userauth_success == TRUE  
  */  
   
 void  
 do_authentication2()  
 {  
         dispatch_init(&protocol_error);  
         dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);  
         dispatch_run(DISPATCH_BLOCK, &userauth_success);  
         do_authenticated2();  
 }  
   
 void  
 protocol_error(int type, int plen)  
 {  
         log("auth: protocol error: type %d plen %d", type, plen);  
         packet_start(SSH2_MSG_UNIMPLEMENTED);  
         packet_put_int(0);  
         packet_send();  
         packet_write_wait();  
 }  
   
 void  
 input_service_request(int type, int plen)  
 {  
         unsigned int len;  
         int accept = 0;  
         char *service = packet_get_string(&len);  
         packet_done();  
   
         if (strcmp(service, "ssh-userauth") == 0) {  
                 if (!userauth_success) {  
                         accept = 1;  
                         /* now we can handle user-auth requests */  
                         dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);  
                 }  
         }  
         /* XXX all other service requests are denied */  
   
         if (accept) {  
                 packet_start(SSH2_MSG_SERVICE_ACCEPT);  
                 packet_put_cstring(service);  
                 packet_send();  
                 packet_write_wait();  
         } else {  
                 debug("bad service request %s", service);  
                 packet_disconnect("bad service request %s", service);  
         }  
         xfree(service);  
 }  
   
 void  
 input_userauth_request(int type, int plen)  
 {  
         static int try = 0;  
         unsigned int len, rlen;  
         int authenticated = 0;  
         char *raw, *user, *service, *method;  
         struct passwd *pw;  
   
         if (++try == AUTH_FAIL_MAX)  
                 packet_disconnect("too many failed userauth_requests");  
   
         raw = packet_get_raw(&rlen);  
         if (plen != rlen)  
                 fatal("plen != rlen");  
         user = packet_get_string(&len);  
         service = packet_get_string(&len);  
         method = packet_get_string(&len);  
         debug("userauth-request for user %s service %s method %s", user, service, method);  
   
         /* XXX we only allow the ssh-connection service */  
         pw = auth_set_user(user, service);  
         if (pw && strcmp(service, "ssh-connection")==0) {  
                 if (strcmp(method, "none") == 0) {  
                         authenticated = ssh2_auth_none(pw);  
                 } else if (strcmp(method, "password") == 0) {  
                         authenticated = ssh2_auth_password(pw);  
                 } else if (strcmp(method, "publickey") == 0) {  
                         authenticated = ssh2_auth_pubkey(pw, raw, rlen);  
                 }  
         }  
         /* XXX check if other auth methods are needed */  
         if (authenticated == 1) {  
                 log("userauth success for %s method %s", user, method);  
                 /* turn off userauth */  
                 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);  
                 packet_start(SSH2_MSG_USERAUTH_SUCCESS);  
                 packet_send();  
                 packet_write_wait();  
                 /* now we can break out */  
                 userauth_success = 1;  
         } else if (authenticated == 0) {  
                 log("userauth failure for %s method %s", user, method);  
                 packet_start(SSH2_MSG_USERAUTH_FAILURE);  
                 packet_put_cstring("publickey,password");       /* XXX dynamic */  
                 packet_put_char(0);                             /* XXX partial success, unused */  
                 packet_send();  
                 packet_write_wait();  
         } else {  
                 log("userauth postponed for %s method %s", user, method);  
         }  
         xfree(service);  
         xfree(user);  
         xfree(method);  
 }  
   
 int  
 ssh2_auth_none(struct passwd *pw)  
 {  
         packet_done();  
         return auth_password(pw, "");  
 }  
 int  
 ssh2_auth_password(struct passwd *pw)  
 {  
         char *password;  
         int authenticated = 0;  
         int change;  
         unsigned int len;  
         change = packet_get_char();  
         if (change)  
                 log("password change not supported");  
         password = packet_get_string(&len);  
         packet_done();  
         if (auth_password(pw, password))  
                 authenticated = 1;  
         memset(password, 0, len);  
         xfree(password);  
         return authenticated;  
 }  
   
 int  
 ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen)  
 {  
         Buffer b;  
         Key *key;  
         char *pkalg, *pkblob, *sig;  
         unsigned int alen, blen, slen;  
         int have_sig;  
         int authenticated = 0;  
   
         have_sig = packet_get_char();  
         pkalg = packet_get_string(&alen);  
         if (strcmp(pkalg, KEX_DSS) != 0) {  
                 xfree(pkalg);  
                 log("bad pkalg %s", pkalg);     /*XXX*/  
                 return 0;  
         }  
         pkblob = packet_get_string(&blen);  
         key = dsa_key_from_blob(pkblob, blen);  
   
         if (have_sig && key != NULL) {  
                 sig = packet_get_string(&slen);  
                 packet_done();  
                 buffer_init(&b);  
                 buffer_append(&b, session_id2, session_id2_len);  
                 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);  
                 if (slen + 4 > rlen)  
                         fatal("bad rlen/slen");  
                 buffer_append(&b, raw, rlen - slen - 4);  
 #ifdef DEBUG_DSS  
                 buffer_dump(&b);  
 #endif  
                 /* test for correct signature */  
                 if (user_dsa_key_allowed(pw, key) &&  
                     dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)  
                         authenticated = 1;  
                 buffer_clear(&b);  
                 xfree(sig);  
         } else if (!have_sig && key != NULL) {  
                 packet_done();  
                 debug("test key...");  
                 /* test whether pkalg/pkblob are acceptable */  
                 /* XXX fake reply and always send PK_OK ? */  
                 if (user_dsa_key_allowed(pw, key)) {  
                         packet_start(SSH2_MSG_USERAUTH_PK_OK);  
                         packet_put_string(pkalg, alen);  
                         packet_put_string(pkblob, blen);  
                         packet_send();  
                         packet_write_wait();  
                         authenticated = -1;  
                 }  
         }  
         xfree(pkalg);  
         xfree(pkblob);  
         return authenticated;  
 }  
   
 /* return 1 if user allows given key */  
 int  
 user_dsa_key_allowed(struct passwd *pw, Key *key)  
 {  
         char line[8192], file[1024];  
         int found_key = 0;  
         unsigned int bits = -1;  
         FILE *f;  
         unsigned long linenum = 0;  
         struct stat st;  
         Key *found;  
   
         /* Temporarily use the user's uid. */  
         temporarily_use_uid(pw->pw_uid);  
   
         /* The authorized keys. */  
         snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,  
             SSH_USER_PERMITTED_KEYS2);  
   
         /* 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();  
                 packet_send_debug("Could not open %.900s for reading.", file);  
                 packet_send_debug("If your home is on an NFS volume, it may need to be world-readable.");  
                 return 0;  
         }  
         if (options.strict_modes) {  
                 int fail = 0;  
                 char buf[1024];  
                 /* Check open file in order to avoid open/stat races */  
                 if (fstat(fileno(f), &st) < 0 ||  
                     (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||  
                     (st.st_mode & 022) != 0) {  
                         snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "  
                             "bad ownership or modes for '%s'.", pw->pw_name, file);  
                         fail = 1;  
                 } else {  
                         /* Check path to SSH_USER_PERMITTED_KEYS */  
                         int i;  
                         static const char *check[] = {  
                                 "", SSH_USER_DIR, NULL  
                         };  
                         for (i = 0; check[i]; i++) {  
                                 snprintf(line, sizeof line, "%.500s/%.100s",  
                                     pw->pw_dir, check[i]);  
                                 if (stat(line, &st) < 0 ||  
                                     (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||  
                                     (st.st_mode & 022) != 0) {  
                                         snprintf(buf, sizeof buf,  
                                             "DSA authentication refused for %.100s: "  
                                             "bad ownership or modes for '%s'.",  
                                             pw->pw_name, line);  
                                         fail = 1;  
                                         break;  
                                 }  
                         }  
                 }  
                 if (fail) {  
                         log(buf);  
                         fclose(f);  
                         restore_uid();  
                         return 0;  
                 }  
         }  
         found_key = 0;  
         found = key_new(KEY_DSA);  
   
         while (fgets(line, sizeof(line), f)) {  
                 char *cp;  
                 linenum++;  
                 /* Skip leading whitespace, empty and comment lines. */  
                 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)  
                         ;  
                 if (!*cp || *cp == '\n' || *cp == '#')  
                         continue;  
                 bits = key_read(found, &cp);  
                 if (bits == 0)  
                         continue;  
                 if (key_equal(found, key)) {  
                         found_key = 1;  
                         debug("matching key found: file %s, line %ld",  
                             file, linenum);  
                         break;  
                 }  
         }  
         restore_uid();  
         fclose(f);  
         key_free(found);  
         return found_key;  
 }  }

Legend:
Removed from v.1.5  
changed lines
  Added in v.1.6