]> andersk Git - openssh.git/blobdiff - auth2.c
- markus@cvs.openbsd.org 2002/01/13 17:57:37
[openssh.git] / auth2.c
diff --git a/auth2.c b/auth2.c
index d3c05a7ae058784d12496957045417c3271eaf93..431f955fcc1eb92239bc1de536f977b69b158f2d 100644 (file)
--- a/auth2.c
+++ b/auth2.c
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $");
+RCSID("$OpenBSD: auth2.c,v 1.82 2002/01/13 17:57:37 markus Exp $");
 
-#ifdef HAVE_OSF_SIA
-# include <sia.h>
-# include <siad.h>
-#endif
-
-#include <openssl/dsa.h>
-#include <openssl/rsa.h>
 #include <openssl/evp.h>
 
+#include "ssh2.h"
 #include "xmalloc.h"
 #include "rsa.h"
-#include "ssh.h"
-#include "pty.h"
+#include "sshpty.h"
 #include "packet.h"
 #include "buffer.h"
+#include "log.h"
 #include "servconf.h"
 #include "compat.h"
 #include "channels.h"
 #include "bufaux.h"
-#include "ssh2.h"
 #include "auth.h"
 #include "session.h"
 #include "dispatch.h"
-#include "auth.h"
 #include "key.h"
+#include "cipher.h"
 #include "kex.h"
-
-#include "dsa.h"
+#include "pathnames.h"
 #include "uidswap.h"
 #include "auth-options.h"
+#include "misc.h"
+#include "hostfile.h"
+#include "canohost.h"
+#include "match.h"
 
 /* import */
 extern ServerOptions options;
-extern unsigned char *session_id2;
+extern u_char *session_id2;
 extern int session_id2_len;
 
-#ifdef WITH_AIXAUTHENTICATE
-extern char *aixloginmsg;
-#endif
-#ifdef HAVE_OSF_SIA
-extern int saved_argc;
-extern char **saved_argv;
-#endif
-
 static Authctxt        *x_authctxt = NULL;
 static int one = 1;
 
@@ -81,22 +69,22 @@ struct Authmethod {
 
 /* protocol */
 
-void   input_service_request(int type, int plen, void *ctxt);
-void   input_userauth_request(int type, int plen, void *ctxt);
-void   protocol_error(int type, int plen, void *ctxt);
-
+static void input_service_request(int, u_int32_t, void *);
+static void input_userauth_request(int, u_int32_t, void *);
 
 /* helper */
-Authmethod     *authmethod_lookup(const char *name);
-struct passwd  *pwcopy(struct passwd *pw);
-int    user_dsa_key_allowed(struct passwd *pw, Key *key);
-char   *authmethods_get(void);
+static Authmethod *authmethod_lookup(const char *);
+static char *authmethods_get(void);
+static int user_key_allowed(struct passwd *, Key *);
+static int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
 
 /* auth */
-int    userauth_none(Authctxt *authctxt);
-int    userauth_passwd(Authctxt *authctxt);
-int    userauth_pubkey(Authctxt *authctxt);
-int    userauth_kbdint(Authctxt *authctxt);
+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",
@@ -104,13 +92,16 @@ Authmethod authmethods[] = {
                &one},
        {"publickey",
                userauth_pubkey,
-               &options.dsa_authentication},
-       {"keyboard-interactive",
-               userauth_kbdint,
-               &options.kbd_interactive_authentication},
+               &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}
 };
 
@@ -119,43 +110,32 @@ Authmethod authmethods[] = {
  */
 
 void
-do_authentication2()
+do_authentication2(void)
 {
-       Authctxt *authctxt = xmalloc(sizeof(*authctxt));
-       memset(authctxt, 'a', sizeof(*authctxt));
-       authctxt->valid = 0;
-       authctxt->attempt = 0;
-       authctxt->success = 0;
+       Authctxt *authctxt = authctxt_new();
+
        x_authctxt = authctxt;          /*XXX*/
 
-#ifdef KRB4
-       /* turn off kerberos, not supported by SSH2 */
-       options.kerberos_authentication = 0;
-#endif
-       dispatch_init(&protocol_error);
+       /* challenge-response is implemented via keyboard interactive */
+       if (options.challenge_response_authentication)
+               options.kbd_interactive_authentication = 1;
+       if (options.pam_authentication_via_kbd_int)
+               options.kbd_interactive_authentication = 1;
+
+       dispatch_init(&dispatch_protocol_error);
        dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
        dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
-       do_authenticated2();
+       do_authenticated(authctxt);
 }
 
-void
-protocol_error(int type, int plen, void *ctxt)
-{
-       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, void *ctxt)
+static void
+input_service_request(int type, u_int32_t seq, void *ctxt)
 {
        Authctxt *authctxt = ctxt;
-       unsigned int len;
+       u_int len;
        int accept = 0;
        char *service = packet_get_string(&len);
-       packet_done();
+       packet_check_eom();
 
        if (authctxt == NULL)
                fatal("input_service_request: no authctxt");
@@ -181,206 +161,203 @@ input_service_request(int type, int plen, void *ctxt)
        xfree(service);
 }
 
-void
-input_userauth_request(int type, int plen, void *ctxt)
+static void
+input_userauth_request(int type, u_int32_t seq, void *ctxt)
 {
        Authctxt *authctxt = ctxt;
        Authmethod *m = NULL;
-       char *user, *service, *method;
+       char *user, *service, *method, *style = NULL;
        int authenticated = 0;
 
        if (authctxt == NULL)
                fatal("input_userauth_request: no authctxt");
-       if (authctxt->attempt++ >= AUTH_FAIL_MAX) {
-#ifdef WITH_AIXAUTHENTICATE 
-               loginfailed(authctxt->pw->pw_name, get_canonical_hostname(), "ssh");
-#endif /* WITH_AIXAUTHENTICATE */
-               packet_disconnect("too many failed userauth_requests");
-       }
 
        user = packet_get_string(NULL);
        service = packet_get_string(NULL);
        method = packet_get_string(NULL);
        debug("userauth-request for user %s service %s method %s", user, service, method);
-       debug("attempt #%d", authctxt->attempt);
+       debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
 
-       if (authctxt->attempt == 1) { 
+       if ((style = strchr(user, ':')) != NULL)
+               *style++ = 0;
+
+       if (authctxt->attempt++ == 0) {
                /* setup auth context */
                struct passwd *pw = NULL;
-               setproctitle("%s", user);
                pw = getpwnam(user);
                if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) {
                        authctxt->pw = pwcopy(pw);
                        authctxt->valid = 1;
                        debug2("input_userauth_request: setting up authctxt for %s", user);
 #ifdef USE_PAM
-                       start_pam(pw);
+                       start_pam(pw->pw_name);
 #endif
                } else {
                        log("input_userauth_request: illegal user %s", user);
+#ifdef USE_PAM
+                       start_pam("NOUSER");
+#endif
                }
+               setproctitle("%s", pw ? user : "unknown");
                authctxt->user = xstrdup(user);
                authctxt->service = xstrdup(service);
-       } else if (authctxt->valid) {
-               if (strcmp(user, authctxt->user) != 0 ||
-                   strcmp(service, authctxt->service) != 0) {
-                       log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)",
-                           user, service, authctxt->user, authctxt->service);
-                       authctxt->valid = 0;
-               }
+               authctxt->style = style ? xstrdup(style) : NULL;
+       } else if (strcmp(user, authctxt->user) != 0 ||
+           strcmp(service, authctxt->service) != 0) {
+               packet_disconnect("Change of username or service not allowed: "
+                   "(%s,%s) -> (%s,%s)",
+                   authctxt->user, authctxt->service, user, service);
        }
+       /* reset state */
+       auth2_challenge_stop(authctxt);
+       authctxt->postponed = 0;
 
+       /* try to authenticate user */
        m = authmethod_lookup(method);
        if (m != NULL) {
                debug2("input_userauth_request: try method %s", method);
                authenticated = m->userauth(authctxt);
-       } else {
-               debug2("input_userauth_request: unsupported method %s", method);
-       }
-       if (!authctxt->valid && authenticated == 1) {
-               log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method);
-               authenticated = 0;
-       }
-
-       /* Special handling for root */
-       if (authenticated == 1 &&
-           authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) {
-               authenticated = 0;
-               log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname());
        }
-
-#ifdef USE_PAM
-       if (authenticated && !do_pam_account(authctxt->pw->pw_name, NULL))
-               authenticated = 0;
-#endif /* USE_PAM */
-
-       /* Log before sending the reply */
-       userauth_log(authctxt, authenticated, method);
-       userauth_reply(authctxt, authenticated);
+       userauth_finish(authctxt, authenticated, method);
 
        xfree(service);
        xfree(user);
        xfree(method);
 }
 
-
 void
-userauth_log(Authctxt *authctxt, int authenticated, char *method)
+userauth_finish(Authctxt *authctxt, int authenticated, char *method)
 {
-       void (*authlog) (const char *fmt,...) = verbose;
-       char *user = NULL, *authmsg = NULL;
+       char *methods;
 
-       /* Raise logging level */
-       if (authenticated == 1 ||
-           !authctxt->valid ||
-           authctxt->attempt >= AUTH_FAIL_LOG ||
-           strcmp(method, "password") == 0)
-               authlog = log;
+       if (!authctxt->valid && authenticated)
+               fatal("INTERNAL ERROR: authenticated invalid user %s",
+                   authctxt->user);
 
-       if (authenticated == 1) {
-               authmsg = "Accepted";
-       } else if (authenticated == 0) {
-               authmsg = "Failed";
-       } else {
-               authmsg = "Postponed";
-       }
+       /* Special handling for root */
+       if (authenticated && authctxt->pw->pw_uid == 0 &&
+           !auth_root_allowed(method))
+               authenticated = 0;
 
-       if (authctxt->valid) {
-               user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user;
-       } else {
-               user = "NOUSER";
-       }
+#ifdef USE_PAM
+       if (authenticated && authctxt->user && !do_pam_account(authctxt->user,
+           NULL))
+               authenticated = 0;
+#endif /* USE_PAM */
 
-       authlog("%s %s for %.200s from %.200s port %d ssh2",
-           authmsg,
-           method,
-           user,
-           get_remote_ipaddr(),
-           get_remote_port());
-}
+       /* Log before sending the reply */
+       auth_log(authctxt, authenticated, method, " ssh2");
+
+       if (authctxt->postponed)
+               return;
 
-void   
-userauth_reply(Authctxt *authctxt, int authenticated)
-{
        /* XXX todo: check if multiple auth methods are needed */
        if (authenticated == 1) {
-#ifdef WITH_AIXAUTHENTICATE
-               /* We don't have a pty yet, so just label the line as "ssh" */
-               if (loginsuccess(authctxt->pw->pw_name, get_canonical_hostname(), 
-                       "ssh", &aixloginmsg) < 0)
-                       aixloginmsg = NULL;
-#endif /* WITH_AIXAUTHENTICATE */
                /* turn off userauth */
-               dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
+               dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
                packet_start(SSH2_MSG_USERAUTH_SUCCESS);
                packet_send();
                packet_write_wait();
                /* now we can break out */
                authctxt->success = 1;
-       } else if (authenticated == 0) {
-               char *methods = authmethods_get();
+       } else {
+               if (authctxt->failures++ > AUTH_FAIL_MAX) {
+#ifdef WITH_AIXAUTHENTICATE
+                       loginfailed(authctxt->user,
+                           get_canonical_hostname(options.reverse_mapping_check),
+                           "ssh");
+#endif /* WITH_AIXAUTHENTICATE */
+                       packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
+               }
+               methods = authmethods_get();
                packet_start(SSH2_MSG_USERAUTH_FAILURE);
                packet_put_cstring(methods);
                packet_put_char(0);     /* XXX partial success, unused */
                packet_send();
                packet_write_wait();
                xfree(methods);
-       } else {
-               /* do nothing, we did already send a reply */
        }
 }
 
-int
+static void
+userauth_banner(void)
+{
+       struct stat st;
+       char *banner = NULL;
+       off_t len, n;
+       int fd;
+
+       if (options.banner == NULL || (datafellows & SSH_BUG_BANNER))
+               return;
+       if ((fd = open(options.banner, O_RDONLY)) < 0)
+               return;
+       if (fstat(fd, &st) < 0)
+               goto done;
+       len = st.st_size;
+       banner = xmalloc(len + 1);
+       if ((n = read(fd, banner, len)) < 0)
+               goto done;
+       banner[n] = '\0';
+       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);
+       close(fd);
+       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_done();
+       packet_check_eom();
+       userauth_banner();
 
        if (authctxt->valid == 0)
                return(0);
-               
+
 #ifdef HAVE_CYGWIN
-       if (check_nt_auth(1, authctxt->pw->pw_uid) == 0)
+       if (check_nt_auth(1, authctxt->pw) == 0)
                return(0);
 #endif
 #ifdef USE_PAM
        return auth_pam_password(authctxt->pw, "");
 #elif defined(HAVE_OSF_SIA)
-       return (sia_validate_user(NULL, saved_argc, saved_argv, 
-               get_canonical_hostname(), authctxt->pw->pw_name, NULL, 
-               0, NULL, "") == SIASUCCESS);
+       return 0;
 #else /* !HAVE_OSF_SIA && !USE_PAM */
-       return auth_password(authctxt->pw, "");
+       return auth_password(authctxt, "");
 #endif /* USE_PAM */
 }
 
-int
+static int
 userauth_passwd(Authctxt *authctxt)
 {
        char *password;
        int authenticated = 0;
        int change;
-       unsigned int len;
+       u_int len;
        change = packet_get_char();
        if (change)
                log("password change not supported");
        password = packet_get_string(&len);
-       packet_done();
+       packet_check_eom();
        if (authctxt->valid &&
 #ifdef HAVE_CYGWIN
-               check_nt_auth(1, authctxt->pw->pw_uid) &&
+           check_nt_auth(1, authctxt->pw) &&
 #endif
 #ifdef USE_PAM
            auth_pam_password(authctxt->pw, password) == 1)
 #elif defined(HAVE_OSF_SIA)
-           sia_validate_user(NULL, saved_argc, saved_argv, 
-                       get_canonical_hostname(), authctxt->pw->pw_name, NULL, 0, 
-                       NULL, password) == SIASUCCESS)
+           auth_sia_password(authctxt->user, password) == 1)
 #else /* !USE_PAM && !HAVE_OSF_SIA */
-           auth_password(authctxt->pw, password) == 1)
+           auth_password(authctxt, password) == 1)
 #endif /* USE_PAM */
                authenticated = 1;
        memset(password, 0, len);
@@ -388,40 +365,42 @@ userauth_passwd(Authctxt *authctxt)
        return authenticated;
 }
 
-int
+static int
 userauth_kbdint(Authctxt *authctxt)
 {
        int authenticated = 0;
-       char *lang = NULL;
-       char *devs = NULL;
+       char *lang, *devs;
 
        lang = packet_get_string(NULL);
        devs = packet_get_string(NULL);
-       packet_done();
+       packet_check_eom();
+
+       debug("keyboard-interactive devs %s", devs);
 
-       debug("keyboard-interactive language %s devs %s", lang, devs);
-#ifdef SKEY
-       /* XXX hardcoded, we should look at devs */
-       if (options.skey_authentication != 0)
-               authenticated = auth2_skey(authctxt);
+       if (options.challenge_response_authentication)
+               authenticated = auth2_challenge(authctxt, devs);
+
+#ifdef USE_PAM
+       if (authenticated == 0 && options.pam_authentication_via_kbd_int)
+               authenticated = auth2_pam(authctxt);
 #endif
-       xfree(lang);
        xfree(devs);
+       xfree(lang);
 #ifdef HAVE_CYGWIN
-       if (check_nt_auth(0, authctxt->pw->pw_uid) == 0)
+       if (check_nt_auth(0, authctxt->pw) == 0)
                return(0);
 #endif
        return authenticated;
 }
 
-int
+static int
 userauth_pubkey(Authctxt *authctxt)
 {
        Buffer b;
        Key *key;
        char *pkalg, *pkblob, *sig;
-       unsigned int alen, blen, slen;
-       int have_sig;
+       u_int alen, blen, slen;
+       int have_sig, pktype;
        int authenticated = 0;
 
        if (!authctxt->valid) {
@@ -429,18 +408,32 @@ userauth_pubkey(Authctxt *authctxt)
                return 0;
        }
        have_sig = packet_get_char();
-       pkalg = packet_get_string(&alen);
-       if (strcmp(pkalg, KEX_DSS) != 0) {
-               log("bad pkalg %s", pkalg);     /*XXX*/
+       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);
                xfree(pkalg);
+               xfree(pkblob);
                return 0;
        }
-       pkblob = packet_get_string(&blen);
-       key = dsa_key_from_blob(pkblob, blen);
+       key = key_from_blob(pkblob, blen);
        if (key != NULL) {
                if (have_sig) {
                        sig = packet_get_string(&slen);
-                       packet_done();
+                       packet_check_eom();
                        buffer_init(&b);
                        if (datafellows & SSH_OLD_SESSIONID) {
                                buffer_append(&b, session_id2, session_id2_len);
@@ -451,25 +444,29 @@ userauth_pubkey(Authctxt *authctxt)
                        buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
                        buffer_put_cstring(&b, authctxt->user);
                        buffer_put_cstring(&b,
-                           datafellows & SSH_BUG_PUBKEYAUTH ?
+                           datafellows & SSH_BUG_PKSERVICE ?
                            "ssh-userauth" :
                            authctxt->service);
-                       buffer_put_cstring(&b, "publickey");
-                       buffer_put_char(&b, have_sig);
-                       buffer_put_cstring(&b, KEX_DSS);
+                       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_DSS
+#ifdef DEBUG_PK
                        buffer_dump(&b);
 #endif
                        /* test for correct signature */
-                       if (user_dsa_key_allowed(authctxt->pw, key) &&
-                           dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
+                       if (user_key_allowed(authctxt->pw, key) &&
+                           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_done();
+                       packet_check_eom();
 
                        /* XXX fake reply and always send PK_OK ? */
                        /*
@@ -479,28 +476,104 @@ userauth_pubkey(Authctxt *authctxt)
                         * if a user is not allowed to login. is this an
                         * issue? -markus
                         */
-                       if (user_dsa_key_allowed(authctxt->pw, key)) {
+                       if (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();
-                               authenticated = -1;
+                               authctxt->postponed = 1;
                        }
                }
                if (authenticated != 1)
                        auth_clear_options();
                key_free(key);
        }
+       debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
        xfree(pkalg);
        xfree(pkblob);
 #ifdef HAVE_CYGWIN
-       if (check_nt_auth(0, authctxt->pw->pw_uid) == 0)
+       if (check_nt_auth(0, authctxt->pw) == 0)
                return(0);
 #endif
        return authenticated;
 }
 
+static int
+userauth_hostbased(Authctxt *authctxt)
+{
+       Buffer b;
+       Key *key;
+       char *pkalg, *pkblob, *sig, *cuser, *chost, *service;
+       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) {
+               debug("userauth_hostbased: cannot decode key: %s", pkalg);
+               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 */
+       if (hostbased_key_allowed(authctxt->pw, cuser, chost, key) &&
+           key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
+               authenticated = 1;
+
+       buffer_clear(&b);
+       key_free(key);
+
+done:
+       debug2("userauth_hostbased: authenticated %d", authenticated);
+       xfree(pkalg);
+       xfree(pkblob);
+       xfree(cuser);
+       xfree(chost);
+       xfree(sig);
+       return authenticated;
+}
+
 /* get current user */
 
 struct passwd*
@@ -511,39 +584,30 @@ auth_get_user(void)
 
 #define        DELIM   ","
 
-char *
+static char *
 authmethods_get(void)
 {
        Authmethod *method = NULL;
-       unsigned int size = 0;
+       Buffer b;
        char *list;
 
+       buffer_init(&b);
        for (method = authmethods; method->name != NULL; method++) {
                if (strcmp(method->name, "none") == 0)
                        continue;
                if (method->enabled != NULL && *(method->enabled) != 0) {
-                       if (size != 0)
-                               size += strlen(DELIM);
-                       size += strlen(method->name);
-               }
-       }
-       size++;                 /* trailing '\0' */
-       list = xmalloc(size);
-       list[0] = '\0';
-
-       for (method = authmethods; method->name != NULL; method++) {
-               if (strcmp(method->name, "none") == 0)
-                       continue;
-               if (method->enabled != NULL && *(method->enabled) != 0) {
-                       if (list[0] != '\0')
-                               strlcat(list, DELIM, size);
-                       strlcat(list, method->name, size);
+                       if (buffer_len(&b) > 0)
+                               buffer_append(&b, ",", 1);
+                       buffer_append(&b, method->name, strlen(method->name));
                }
        }
+       buffer_append(&b, "\0", 1);
+       list = xstrdup(buffer_ptr(&b));
+       buffer_free(&b);
        return list;
 }
 
-Authmethod *
+static Authmethod *
 authmethod_lookup(const char *name)
 {
        Authmethod *method = NULL;
@@ -558,26 +622,24 @@ authmethod_lookup(const char *name)
 }
 
 /* return 1 if user allows given key */
-int
-user_dsa_key_allowed(struct passwd *pw, Key *key)
+static int
+user_key_allowed2(struct passwd *pw, Key *key, char *file)
 {
-       char line[8192], file[1024];
+       char line[8192];
        int found_key = 0;
-       unsigned int bits = -1;
        FILE *f;
-       unsigned long linenum = 0;
+       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->pw_uid);
+       temporarily_use_uid(pw);
 
-       /* The authorized keys. */
-       snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
-           SSH_USER_PERMITTED_KEYS2);
+       debug("trying public key file %s", file);
 
        /* Fail quietly if file does not exist */
        if (stat(file, &st) < 0) {
@@ -592,46 +654,14 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
                restore_uid();
                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,
-                           "%s authentication refused for %.100s: "
-                           "bad ownership or modes for '%s'.",
-                           key_type(key), 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,
-                                           "%s authentication refused for %.100s: "
-                                           "bad ownership or modes for '%s'.",
-                                           key_type(key), pw->pw_name, line);
-                                       fail = 1;
-                                       break;
-                               }
-                       }
-               }
-               if (fail) {
-                       fclose(f);
-                       log("%s",buf);
-                       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);
 
@@ -644,10 +674,10 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
                if (!*cp || *cp == '\n' || *cp == '#')
                        continue;
 
-               bits = key_read(found, &cp);
-               if (bits == 0) {
+               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] == '"')
@@ -658,39 +688,97 @@ user_dsa_key_allowed(struct passwd *pw, Key *key)
                        /* Skip remaining whitespace. */
                        for (; *cp == ' ' || *cp == '\t'; cp++)
                                ;
-                       bits = key_read(found, &cp);
-                       if (bits == 0) {
+                       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, linenum) == 1) {
+                   auth_parse_options(pw, options, file, linenum) == 1) {
                        found_key = 1;
-                       debug("matching key found: file %s, line %ld",
+                       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;
 }
 
-struct passwd *
-pwcopy(struct passwd *pw)
+/* check whether given key is in .ssh/authorized_keys* */
+static int
+user_key_allowed(struct passwd *pw, Key *key)
 {
-       struct passwd *copy = xmalloc(sizeof(*copy));
-       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;
-#ifdef HAVE_PW_CLASS_IN_PASSWD
-       copy->pw_class = xstrdup(pw->pw_class);
-#endif
-       copy->pw_dir = xstrdup(pw->pw_dir);
-       copy->pw_shell = xstrdup(pw->pw_shell);
-       return copy;
+       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 */
+static 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.reverse_mapping_check);
+       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);
+}
+
This page took 0.076455 seconds and 4 git commands to generate.