[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.4 and 1.5

version 1.4, 2000/04/14 10:30:29 version 1.5, 2000/04/26 20:56:29
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 19 
Line 23 
 #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 40 
Line 48 
  * If the user's shell is not executable, false will be returned.   * If the user's shell is not executable, false will be returned.
  * Otherwise true is returned.   * Otherwise true is returned.
  */   */
 static int  int
 allowed_user(struct passwd * pw)  allowed_user(struct passwd * pw)
 {  {
         struct stat st;          struct stat st;
Line 110 
Line 118 
         return 1;          return 1;
 }  }
   
   /* import */
   extern ServerOptions options;
   extern char *forced_command;
   
 /*  /*
  * convert ssh auth msg type into description   * convert ssh auth msg type into description
  */   */
Line 559 
Line 571 
         do_authenticated(pw);          do_authenticated(pw);
 }  }
   
   /* import */
   extern ServerOptions options;
   extern unsigned char *session_id2;
   extern int session_id2_len;
   
 void input_service_request(int type, int plen);  /* protocol */
 void input_userauth_request(int type, int plen);  
 void ssh2_pty_cleanup(void);  
   
   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;  typedef struct Authctxt Authctxt;
 struct Authctxt {  struct Authctxt {
         char *user;          char *user;
Line 574 
Line 601 
 static Authctxt *authctxt = NULL;  static Authctxt *authctxt = NULL;
 static int userauth_success = 0;  static int userauth_success = 0;
   
   /* set and get current user */
   
 struct passwd*  struct passwd*
 auth_get_user(void)  auth_get_user(void)
 {  {
         return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;          return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
 }  }
   
 struct passwd*  struct passwd*
 auth_set_user(char *u, char *s)  auth_set_user(char *u, char *s)
 {  {
Line 615 
Line 645 
         return auth_get_user();          return auth_get_user();
 }  }
   
 static void  /*
    * 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)  protocol_error(int type, int plen)
 {  {
         log("auth: protocol error: type %d plen %d", type, plen);          log("auth: protocol error: type %d plen %d", type, plen);
Line 624 
Line 667 
         packet_send();          packet_send();
         packet_write_wait();          packet_write_wait();
 }  }
   
 void  void
 input_service_request(int type, int plen)  input_service_request(int type, int plen)
 {  {
Line 652 
Line 696 
         }          }
         xfree(service);          xfree(service);
 }  }
   
 void  void
 input_userauth_request(int type, int plen)  input_userauth_request(int type, int plen)
 {  {
         static int try = 0;          static int try = 0;
         unsigned int len;          unsigned int len, rlen;
         int c, authenticated = 0;          int authenticated = 0;
         char *user, *service, *method;          char *raw, *user, *service, *method;
         struct passwd *pw;          struct passwd *pw;
   
         if (++try == AUTH_FAIL_MAX)          if (++try == AUTH_FAIL_MAX)
                 packet_disconnect("too many failed userauth_requests");                  packet_disconnect("too many failed userauth_requests");
   
           raw = packet_get_raw(&rlen);
           if (plen != rlen)
                   fatal("plen != rlen");
         user = packet_get_string(&len);          user = packet_get_string(&len);
         service = packet_get_string(&len);          service = packet_get_string(&len);
         method = packet_get_string(&len);          method = packet_get_string(&len);
Line 672 
Line 720 
         /* XXX we only allow the ssh-connection service */          /* XXX we only allow the ssh-connection service */
         pw = auth_set_user(user, service);          pw = auth_set_user(user, service);
         if (pw && strcmp(service, "ssh-connection")==0) {          if (pw && strcmp(service, "ssh-connection")==0) {
                 if (strcmp(method, "none") == 0 && try == 1) {                  if (strcmp(method, "none") == 0) {
                         packet_done();                          authenticated = ssh2_auth_none(pw);
                         authenticated = auth_password(pw, "");  
                 } else if (strcmp(method, "password") == 0) {                  } else if (strcmp(method, "password") == 0) {
                         char *password;                          authenticated = ssh2_auth_password(pw);
                         c = packet_get_char();  
                         if (c)  
                                 debug("password change not supported");  
                         password = packet_get_string(&len);  
                         packet_done();  
                         authenticated = auth_password(pw, password);  
                         memset(password, 0, len);  
                         xfree(password);  
                 } else if (strcmp(method, "publickey") == 0) {                  } else if (strcmp(method, "publickey") == 0) {
                         /* XXX TODO */                          authenticated = ssh2_auth_pubkey(pw, raw, rlen);
                         char *pkalg, *pkblob, *sig;  
                         int have_sig = packet_get_char();  
                         pkalg = packet_get_string(&len);  
                         pkblob = packet_get_string(&len);  
                         if (have_sig) {  
                                 sig = packet_get_string(&len);  
                                 /* test for correct signature */  
                                 packet_done();  
                                 xfree(sig);  
                         } else {  
                                 packet_done();  
                                 /* test whether pkalg/pkblob are acceptable */  
                         }  
                         xfree(pkalg);  
                         xfree(pkblob);  
                 }                  }
         }          }
         /* XXX check if other auth methods are needed */          /* XXX check if other auth methods are needed */
         if (authenticated) {          if (authenticated == 1) {
                   log("userauth success for %s method %s", user, method);
                 /* turn off userauth */                  /* turn off userauth */
                 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);                  dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
                 packet_start(SSH2_MSG_USERAUTH_SUCCESS);                  packet_start(SSH2_MSG_USERAUTH_SUCCESS);
                 packet_send();                  packet_send();
                 packet_write_wait();                  packet_write_wait();
                 log("userauth success for %s", user);  
                 /* now we can break out */                  /* now we can break out */
                 userauth_success = 1;                  userauth_success = 1;
         } else {          } else if (authenticated == 0) {
                   log("userauth failure for %s method %s", user, method);
                 packet_start(SSH2_MSG_USERAUTH_FAILURE);                  packet_start(SSH2_MSG_USERAUTH_FAILURE);
                 packet_put_cstring("password");                  packet_put_cstring("publickey,password");       /* XXX dynamic */
                 packet_put_char(0);             /* partial success */                  packet_put_char(0);                             /* XXX partial success, unused */
                 packet_send();                  packet_send();
                 packet_write_wait();                  packet_write_wait();
           } else {
                   log("userauth postponed for %s method %s", user, method);
         }          }
         xfree(service);          xfree(service);
         xfree(user);          xfree(user);
         xfree(method);          xfree(method);
 }  }
 void  
 do_authentication2()  int
   ssh2_auth_none(struct passwd *pw)
 {  {
         dispatch_init(&protocol_error);          packet_done();
         dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);          return auth_password(pw, "");
         dispatch_run(DISPATCH_BLOCK, &userauth_success);  }
         do_authenticated2();  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.4  
changed lines
  Added in v.1.5