]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream commit
authordjm@openbsd.org <djm@openbsd.org>
Sat, 24 Jun 2017 06:34:38 +0000 (06:34 +0000)
committerDamien Miller <djm@mindrot.org>
Sat, 24 Jun 2017 06:56:11 +0000 (16:56 +1000)
refactor authentication logging

optionally record successful auth methods and public credentials
used in a file accessible to user sessions

feedback and ok markus@

Upstream-ID: 090b93036967015717b9a54fd0467875ae9d32fb

13 files changed:
auth.c
auth.h
auth2-gss.c
auth2-hostbased.c
auth2-pubkey.c
auth2.c
gss-serv.c
monitor.c
servconf.c
servconf.h
session.c
ssh-gss.h
sshd_config.5

diff --git a/auth.c b/auth.c
index fd8211505006bac35b8c50307db4cee6e5a06192..96116ecfe25c8e3fd60445edf7890d2d2b150354 100644 (file)
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.121 2017/05/30 08:52:19 markus Exp $ */
+/* $OpenBSD: auth.c,v 1.122 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -267,21 +267,41 @@ allowed_user(struct passwd * pw)
        return 1;
 }
 
-void
-auth_info(Authctxt *authctxt, const char *fmt, ...)
+/*
+ * Formats any key left in authctxt->auth_method_key for inclusion in
+ * auth_log()'s message. Also includes authxtct->auth_method_info if present.
+ */
+static char *
+format_method_key(Authctxt *authctxt)
 {
-       va_list ap;
-        int i;
-
-       free(authctxt->info);
-       authctxt->info = NULL;
+       const struct sshkey *key = authctxt->auth_method_key;
+       const char *methinfo = authctxt->auth_method_info;
+       char *fp, *ret = NULL;
 
-       va_start(ap, fmt);
-       i = vasprintf(&authctxt->info, fmt, ap);
-       va_end(ap);
+       if (key == NULL)
+               return NULL;
 
-       if (i < 0 || authctxt->info == NULL)
-               fatal("vasprintf failed");
+       if (key_is_cert(key)) {
+               fp = sshkey_fingerprint(key->cert->signature_key,
+                   options.fingerprint_hash, SSH_FP_DEFAULT);
+               xasprintf(&ret, "%s ID %s (serial %llu) CA %s %s%s%s",
+                   sshkey_type(key), key->cert->key_id,
+                   (unsigned long long)key->cert->serial,
+                   sshkey_type(key->cert->signature_key),
+                   fp == NULL ? "(null)" : fp,
+                   methinfo == NULL ? "" : ", ",
+                   methinfo == NULL ? "" : methinfo);
+               free(fp);
+       } else {
+               fp = sshkey_fingerprint(key, options.fingerprint_hash,
+                   SSH_FP_DEFAULT);
+               xasprintf(&ret, "%s %s%s%s", sshkey_type(key),
+                   fp == NULL ? "(null)" : fp,
+                   methinfo == NULL ? "" : ", ",
+                   methinfo == NULL ? "" : methinfo);
+               free(fp);
+       }
+       return ret;
 }
 
 void
@@ -290,7 +310,8 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
 {
        struct ssh *ssh = active_state; /* XXX */
        void (*authlog) (const char *fmt,...) = verbose;
-       char *authmsg;
+       const char *authmsg;
+       char *extra = NULL;
 
        if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
                return;
@@ -309,6 +330,11 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
        else
                authmsg = authenticated ? "Accepted" : "Failed";
 
+       if ((extra = format_method_key(authctxt)) == NULL) {
+               if (authctxt->auth_method_info != NULL)
+                       extra = xstrdup(authctxt->auth_method_info);
+       }
+
        authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
            authmsg,
            method,
@@ -317,10 +343,10 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
            authctxt->user,
            ssh_remote_ipaddr(ssh),
            ssh_remote_port(ssh),
-           authctxt->info != NULL ? ": " : "",
-           authctxt->info != NULL ? authctxt->info : "");
-       free(authctxt->info);
-       authctxt->info = NULL;
+           extra != NULL ? ": " : "",
+           extra != NULL ? extra : "");
+
+       free(extra);
 
 #ifdef CUSTOM_FAILED_LOGIN
        if (authenticated == 0 && !authctxt->postponed &&
diff --git a/auth.h b/auth.h
index 677935463827b8d0340bd66c0d432df3f41c0518..cbbc9623f5c55543e870e913af5495c2196f6dbb 100644 (file)
--- a/auth.h
+++ b/auth.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.h,v 1.91 2017/05/30 14:29:59 markus Exp $ */
+/* $OpenBSD: auth.h,v 1.92 2017/06/24 06:34:38 djm Exp $ */
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
@@ -44,6 +44,7 @@
 
 struct ssh;
 struct sshkey;
+struct sshbuf;
 
 typedef struct Authctxt Authctxt;
 typedef struct Authmethod Authmethod;
@@ -62,13 +63,17 @@ struct Authctxt {
        char            *service;
        struct passwd   *pw;            /* set if 'valid' */
        char            *style;
+
+       /* Method lists for multiple authentication */
+       char            **auth_methods; /* modified from server config */
+       u_int            num_auth_methods;
+
+       /* Authentication method-specific data */
+       void            *methoddata;
        void            *kbdintctxt;
-       char            *info;          /* Extra info for next auth_log */
 #ifdef BSD_AUTH
        auth_session_t  *as;
 #endif
-       char            **auth_methods; /* modified from server config */
-       u_int            num_auth_methods;
 #ifdef KRB5
        krb5_context     krb5_ctx;
        krb5_ccache      krb5_fwd_ccache;
@@ -76,12 +81,20 @@ struct Authctxt {
        char            *krb5_ticket_file;
        char            *krb5_ccname;
 #endif
-       Buffer          *loginmsg;
-       void            *methoddata;
+       struct sshbuf   *loginmsg;
+
+       /* Authentication keys already used; these will be refused henceforth */
+       struct sshkey   **prev_keys;
+       u_int            nprev_keys;
 
-       struct sshkey   **prev_userkeys;
-       u_int            nprev_userkeys;
+       /* Last used key and ancilliary information from active auth method */
+       struct sshkey   *auth_method_key;
+       char            *auth_method_info;
+
+       /* Information exposed to session */
+       struct sshbuf   *session_info;  /* Auth info for environment */
 };
+
 /*
  * Every authentication method has to handle authentication requests for
  * non-existing users, or for users that are not allowed to login. In this
@@ -120,10 +133,18 @@ int      auth_password(Authctxt *, const char *);
 int     hostbased_key_allowed(struct passwd *, const char *, char *,
            struct sshkey *);
 int     user_key_allowed(struct passwd *, struct sshkey *, int);
-void    pubkey_auth_info(Authctxt *, const struct sshkey *, const char *, ...)
-           __attribute__((__format__ (printf, 3, 4)));
-void    auth2_record_userkey(Authctxt *, struct sshkey *);
-int     auth2_userkey_already_used(Authctxt *, struct sshkey *);
+int     auth2_key_already_used(Authctxt *, const struct sshkey *);
+
+/*
+ * Handling auth method-specific information for logging and prevention
+ * of key reuse during multiple authentication.
+ */
+void    auth2_authctxt_reset_info(Authctxt *);
+void    auth2_record_key(Authctxt *, int, const struct sshkey *);
+void    auth2_record_info(Authctxt *authctxt, const char *, ...)
+           __attribute__((__format__ (printf, 2, 3)))
+           __attribute__((__nonnull__ (2)));
+void    auth2_update_session_info(Authctxt *, const char *, const char *);
 
 struct stat;
 int     auth_secure_path(const char *, struct stat *, const char *, uid_t,
@@ -150,9 +171,6 @@ void disable_forwarding(void);
 
 void   do_authentication2(Authctxt *);
 
-void   auth_info(Authctxt *authctxt, const char *, ...)
-           __attribute__((__format__ (printf, 2, 3)))
-           __attribute__((__nonnull__ (2)));
 void   auth_log(Authctxt *, int, int, const char *, const char *);
 void   auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn));
 void   userauth_finish(struct ssh *, int, const char *, const char *);
index 680d5e71239892aff9a0028529767af113ca5498..589283b720415332ee04bb44fe42b811f8e28b19 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-gss.c,v 1.25 2017/05/30 14:29:59 markus Exp $ */
+/* $OpenBSD: auth2-gss.c,v 1.26 2017/06/24 06:34:38 djm Exp $ */
 
 /*
  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@@ -228,6 +228,7 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
 {
        Authctxt *authctxt = ssh->authctxt;
        int authenticated;
+       const char *displayname;
 
        if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
                fatal("No authentication or GSSAPI context");
@@ -241,6 +242,10 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
 
        authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
 
+       if ((!use_privsep || mm_is_monitor()) &&
+           (displayname = ssh_gssapi_displayname()) != NULL)
+               auth2_record_info(authctxt, "%s", displayname);
+
        authctxt->postponed = 0;
        ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
        ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
@@ -259,6 +264,7 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
        Buffer b;
        gss_buffer_desc mic, gssbuf;
        u_int len;
+       const char *displayname;
 
        if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
                fatal("No authentication or GSSAPI context");
@@ -282,6 +288,10 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
        buffer_free(&b);
        free(mic.value);
 
+       if ((!use_privsep || mm_is_monitor()) &&
+           (displayname = ssh_gssapi_displayname()) != NULL)
+               auth2_record_info(authctxt, "%s", displayname);
+
        authctxt->postponed = 0;
        ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
        ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
index 63fe9ae654fcc2fe6cecb181d8e4983c8c6103c1..92758b38c19daf789732c98ceb17ab923753cb2d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-hostbased.c,v 1.30 2017/05/30 14:29:59 markus Exp $ */
+/* $OpenBSD: auth2-hostbased.c,v 1.31 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -137,7 +137,7 @@ userauth_hostbased(struct ssh *ssh)
        sshbuf_dump(b, stderr);
 #endif
 
-       pubkey_auth_info(authctxt, key,
+       auth2_record_info(authctxt,
            "client user \"%.100s\", client host \"%.100s\"", cuser, chost);
 
        /* test for allowed key and correct signature */
@@ -147,11 +147,11 @@ userauth_hostbased(struct ssh *ssh)
            sshbuf_ptr(b), sshbuf_len(b), ssh->compat)) == 0)
                authenticated = 1;
 
+       auth2_record_key(authctxt, authenticated, key);
        sshbuf_free(b);
 done:
        debug2("%s: authenticated %d", __func__, authenticated);
-       if (key != NULL)
-               sshkey_free(key);
+       sshkey_free(key);
        free(pkalg);
        free(pkblob);
        free(cuser);
index 5794f1f4d76cf3403f0a34126de6a5b2d77708ac..1c59b5bb02bbbf0376ba7a624d1f3d719f19a272 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.67 2017/05/31 10:54:00 markus Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.68 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -137,7 +137,7 @@ userauth_pubkey(struct ssh *ssh)
                goto done;
        }
        fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
-       if (auth2_userkey_already_used(authctxt, key)) {
+       if (auth2_key_already_used(authctxt, key)) {
                logit("refusing previously-used %s key", sshkey_type(key));
                goto done;
        }
@@ -194,7 +194,6 @@ userauth_pubkey(struct ssh *ssh)
 #ifdef DEBUG_PK
                sshbuf_dump(b, stderr);
 #endif
-               pubkey_auth_info(authctxt, key, NULL);
 
                /* test for correct signature */
                authenticated = 0;
@@ -202,12 +201,10 @@ userauth_pubkey(struct ssh *ssh)
                    PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
                    sshbuf_len(b), ssh->compat)) == 0) {
                        authenticated = 1;
-                       /* Record the successful key to prevent reuse */
-                       auth2_record_userkey(authctxt, key);
-                       key = NULL; /* Don't free below */
                }
                sshbuf_free(b);
                free(sig);
+               auth2_record_key(authctxt, authenticated, key);
        } else {
                debug("%s: test whether pkalg/pkblob are acceptable for %s %s",
                    __func__, sshkey_type(key), fp);
@@ -237,8 +234,7 @@ userauth_pubkey(struct ssh *ssh)
                auth_clear_options();
 done:
        debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
-       if (key != NULL)
-               sshkey_free(key);
+       sshkey_free(key);
        free(userstyle);
        free(pkalg);
        free(pkblob);
@@ -246,44 +242,6 @@ done:
        return authenticated;
 }
 
-void
-pubkey_auth_info(Authctxt *authctxt, const struct sshkey *key,
-    const char *fmt, ...)
-{
-       char *fp, *extra;
-       va_list ap;
-       int i;
-
-       extra = NULL;
-       if (fmt != NULL) {
-               va_start(ap, fmt);
-               i = vasprintf(&extra, fmt, ap);
-               va_end(ap);
-               if (i < 0 || extra == NULL)
-                       fatal("%s: vasprintf failed", __func__);
-       }
-
-       if (sshkey_is_cert(key)) {
-               fp = sshkey_fingerprint(key->cert->signature_key,
-                   options.fingerprint_hash, SSH_FP_DEFAULT);
-               auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", 
-                   sshkey_type(key), key->cert->key_id,
-                   (unsigned long long)key->cert->serial,
-                   sshkey_type(key->cert->signature_key),
-                   fp == NULL ? "(null)" : fp,
-                   extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
-               free(fp);
-       } else {
-               fp = sshkey_fingerprint(key, options.fingerprint_hash,
-                   SSH_FP_DEFAULT);
-               auth_info(authctxt, "%s %s%s%s", sshkey_type(key),
-                   fp == NULL ? "(null)" : fp,
-                   extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
-               free(fp);
-       }
-       free(extra);
-}
-
 /*
  * Splits 's' into an argument vector. Handles quoted string and basic
  * escape characters (\\, \", \'). Caller must free the argument vector
@@ -1148,36 +1106,6 @@ user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt)
        return success;
 }
 
-/* Records a public key in the list of previously-successful keys */
-void
-auth2_record_userkey(Authctxt *authctxt, struct sshkey *key)
-{
-       struct sshkey **tmp;
-
-       if (authctxt->nprev_userkeys >= INT_MAX ||
-           (tmp = recallocarray(authctxt->prev_userkeys,
-           authctxt->nprev_userkeys, authctxt->nprev_userkeys + 1,
-           sizeof(*tmp))) == NULL)
-               fatal("%s: recallocarray failed", __func__);
-       authctxt->prev_userkeys = tmp;
-       authctxt->prev_userkeys[authctxt->nprev_userkeys] = key;
-       authctxt->nprev_userkeys++;
-}
-
-/* Checks whether a key has already been used successfully for authentication */
-int
-auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key)
-{
-       u_int i;
-
-       for (i = 0; i < authctxt->nprev_userkeys; i++) {
-               if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) {
-                       return 1;
-               }
-       }
-       return 0;
-}
-
 Authmethod method_pubkey = {
        "publickey",
        userauth_pubkey,
diff --git a/auth2.c b/auth2.c
index cb4c2fd5d237a04d7d29ebd14bfd2e84c4a97d2f..862e09960b291253b128b0ab2f26cc3ceadd38df 100644 (file)
--- a/auth2.c
+++ b/auth2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2.c,v 1.142 2017/05/31 07:00:13 markus Exp $ */
+/* $OpenBSD: auth2.c,v 1.143 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -30,6 +30,7 @@
 #include <sys/uio.h>
 
 #include <fcntl.h>
+#include <limits.h>
 #include <pwd.h>
 #include <stdarg.h>
 #include <string.h>
@@ -55,6 +56,7 @@
 #include "ssh-gss.h"
 #endif
 #include "monitor_wrap.h"
+#include "ssherr.h"
 
 /* import */
 extern ServerOptions options;
@@ -277,6 +279,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
        ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
 #endif
 
+       auth2_authctxt_reset_info(authctxt);
        authctxt->postponed = 0;
        authctxt->server_caused_failure = 0;
 
@@ -327,6 +330,10 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method,
        /* Log before sending the reply */
        auth_log(authctxt, authenticated, partial, method, submethod);
 
+       /* Update information exposed to session */
+       if (authenticated || partial)
+               auth2_update_session_info(authctxt, method, submethod);
+
        if (authctxt->postponed)
                return;
 
@@ -624,4 +631,128 @@ auth2_update_methods_lists(Authctxt *authctxt, const char *method,
        return 0;
 }
 
+/* Reset method-specific information */
+void auth2_authctxt_reset_info(Authctxt *authctxt)
+{
+       sshkey_free(authctxt->auth_method_key);
+       free(authctxt->auth_method_info);
+       authctxt->auth_method_key = NULL;
+       authctxt->auth_method_info = NULL;
+}
+
+/* Record auth method-specific information for logs */
+void
+auth2_record_info(Authctxt *authctxt, const char *fmt, ...)
+{
+       va_list ap;
+        int i;
+
+       free(authctxt->auth_method_info);
+       authctxt->auth_method_info = NULL;
+
+       va_start(ap, fmt);
+       i = vasprintf(&authctxt->auth_method_info, fmt, ap);
+       va_end(ap);
+
+       if (i < 0 || authctxt->auth_method_info == NULL)
+               fatal("%s: vasprintf failed", __func__);
+}
+
+/*
+ * Records a public key used in authentication. This is used for logging
+ * and to ensure that the same key is not subsequently accepted again for
+ * multiple authentication.
+ */
+void
+auth2_record_key(Authctxt *authctxt, int authenticated,
+    const struct sshkey *key)
+{
+       struct sshkey **tmp, *dup;
+       int r;
+
+       if ((r = sshkey_demote(key, &dup)) != 0)
+               fatal("%s: copy key: %s", __func__, ssh_err(r));
+       sshkey_free(authctxt->auth_method_key);
+       authctxt->auth_method_key = dup;
+
+       if (!authenticated)
+               return;
+
+       /* If authenticated, make sure we don't accept this key again */
+       if ((r = sshkey_demote(key, &dup)) != 0)
+               fatal("%s: copy key: %s", __func__, ssh_err(r));
+       if (authctxt->nprev_keys >= INT_MAX ||
+           (tmp = recallocarray(authctxt->prev_keys, authctxt->nprev_keys,
+           authctxt->nprev_keys + 1, sizeof(*authctxt->prev_keys))) == NULL)
+               fatal("%s: reallocarray failed", __func__);
+       authctxt->prev_keys = tmp;
+       authctxt->prev_keys[authctxt->nprev_keys] = dup;
+       authctxt->nprev_keys++;
+
+}
+
+/* Checks whether a key has already been previously used for authentication */
+int
+auth2_key_already_used(Authctxt *authctxt, const struct sshkey *key)
+{
+       u_int i;
+       char *fp;
+
+       for (i = 0; i < authctxt->nprev_keys; i++) {
+               if (sshkey_equal_public(key, authctxt->prev_keys[i])) {
+                       fp = sshkey_fingerprint(authctxt->prev_keys[i],
+                           options.fingerprint_hash, SSH_FP_DEFAULT);
+                       debug3("%s: key already used: %s %s", __func__,
+                           sshkey_type(authctxt->prev_keys[i]),
+                           fp == NULL ? "UNKNOWN" : fp);
+                       free(fp);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Updates authctxt->session_info with details of authentication. Should be
+ * whenever an authentication method succeeds.
+ */
+void
+auth2_update_session_info(Authctxt *authctxt, const char *method,
+    const char *submethod)
+{
+       int r;
+
+       if (authctxt->session_info == NULL) {
+               if ((authctxt->session_info = sshbuf_new()) == NULL)
+                       fatal("%s: sshbuf_new", __func__);
+       }
+
+       /* Append method[/submethod] */
+       if ((r = sshbuf_putf(authctxt->session_info, "%s%s%s",
+           method, submethod == NULL ? "" : "/",
+           submethod == NULL ? "" : submethod)) != 0)
+               fatal("%s: append method: %s", __func__, ssh_err(r));
+
+       /* Append key if present */
+       if (authctxt->auth_method_key != NULL) {
+               if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 ||
+                   (r = sshkey_format_text(authctxt->auth_method_key,
+                   authctxt->session_info)) != 0)
+                       fatal("%s: append key: %s", __func__, ssh_err(r));
+       }
+
+       if (authctxt->auth_method_info != NULL) {
+               /* Ensure no ambiguity here */
+               if (strchr(authctxt->auth_method_info, '\n') != NULL)
+                       fatal("%s: auth_method_info contains \\n", __func__);
+               if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 ||
+                   (r = sshbuf_putf(authctxt->session_info, "%s",
+                   authctxt->auth_method_info)) != 0) {
+                       fatal("%s: append method info: %s",
+                           __func__, ssh_err(r));
+               }
+       }
+       if ((r = sshbuf_put_u8(authctxt->session_info, '\n')) != 0)
+               fatal("%s: append: %s", __func__, ssh_err(r));
+}
 
index 53993d674cfbbee44c157530495207a3aa3a2a84..6cae720e5d9b3546ab4db7e23e7a655c4cd73e31 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: gss-serv.c,v 1.29 2015/05/22 03:50:02 djm Exp $ */
+/* $OpenBSD: gss-serv.c,v 1.30 2017/06/24 06:34:38 djm Exp $ */
 
 /*
  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
@@ -393,4 +393,13 @@ ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
        return (ctx->major);
 }
 
+/* Privileged */
+const char *ssh_gssapi_displayname(void)
+{
+       if (gssapi_client.displayname.length == 0 ||
+           gssapi_client.displayname.value == NULL)
+               return NULL;
+       return (char *)gssapi_client.displayname.value;
+}
+
 #endif
index 8897f6a824d8de23b291ab1b738550a801774904..8a7897bde1854c1c9cbdc380957bcfce7e282fe2 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.171 2017/05/31 10:04:29 markus Exp $ */
+/* $OpenBSD: monitor.c,v 1.172 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -308,6 +308,8 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
                partial = 0;
                auth_method = "unknown";
                auth_submethod = NULL;
+               auth2_authctxt_reset_info(authctxt);
+
                authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1);
 
                /* Special handling for multiple required authentications */
@@ -347,6 +349,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
                            auth_method, auth_submethod);
                        if (!partial && !authenticated)
                                authctxt->failures++;
+                       if (authenticated || partial) {
+                               auth2_update_session_info(authctxt,
+                                   auth_method, auth_submethod);
+                       }
                }
        }
 
@@ -1147,12 +1153,11 @@ mm_answer_keyallowed(int sock, Buffer *m)
                switch (type) {
                case MM_USERKEY:
                        allowed = options.pubkey_authentication &&
-                           !auth2_userkey_already_used(authctxt, key) &&
+                           !auth2_key_already_used(authctxt, key) &&
                            match_pattern_list(sshkey_ssh_name(key),
                            options.pubkey_key_types, 0) == 1 &&
                            user_key_allowed(authctxt->pw, key,
                            pubkey_auth_attempt);
-                       pubkey_auth_info(authctxt, key, NULL);
                        auth_method = "publickey";
                        if (options.pubkey_authentication &&
                            (!pubkey_auth_attempt || allowed != 1))
@@ -1160,11 +1165,12 @@ mm_answer_keyallowed(int sock, Buffer *m)
                        break;
                case MM_HOSTKEY:
                        allowed = options.hostbased_authentication &&
+                           !auth2_key_already_used(authctxt, key) &&
                            match_pattern_list(sshkey_ssh_name(key),
                            options.hostbased_key_types, 0) == 1 &&
                            hostbased_key_allowed(authctxt->pw,
                            cuser, chost, key);
-                       pubkey_auth_info(authctxt, key,
+                       auth2_record_info(authctxt,
                            "client user \"%.100s\", client host \"%.100s\"",
                            cuser, chost);
                        auth_method = "hostbased";
@@ -1175,11 +1181,10 @@ mm_answer_keyallowed(int sock, Buffer *m)
                }
        }
 
-       debug3("%s: key %p is %s",
-           __func__, key, allowed ? "allowed" : "not allowed");
+       debug3("%s: key is %s", __func__, allowed ? "allowed" : "not allowed");
 
-       if (key != NULL)
-               key_free(key);
+       auth2_record_key(authctxt, 0, key);
+       sshkey_free(key);
 
        /* clear temporarily storage (used by verify) */
        monitor_reset_key_state();
@@ -1353,10 +1358,12 @@ mm_answer_keyverify(int sock, struct sshbuf *m)
        switch (key_blobtype) {
        case MM_USERKEY:
                valid_data = monitor_valid_userblob(data, datalen);
+               auth_method = "publickey";
                break;
        case MM_HOSTKEY:
                valid_data = monitor_valid_hostbasedblob(data, datalen,
                    hostbased_cuser, hostbased_chost);
+               auth_method = "hostbased";
                break;
        default:
                valid_data = 0;
@@ -1367,23 +1374,17 @@ mm_answer_keyverify(int sock, struct sshbuf *m)
 
        ret = sshkey_verify(key, signature, signaturelen, data, datalen,
            active_state->compat);
-       debug3("%s: key %p signature %s",
-           __func__, key, (ret == 0) ? "verified" : "unverified");
-
-       /* If auth was successful then record key to ensure it isn't reused */
-       if (ret == 0 && key_blobtype == MM_USERKEY)
-               auth2_record_userkey(authctxt, key);
-       else
-               sshkey_free(key);
+       debug3("%s: %s %p signature %s", __func__, auth_method, key,
+           (ret == 0) ? "verified" : "unverified");
+       auth2_record_key(authctxt, ret == 0, key);
 
        free(blob);
        free(signature);
        free(data);
 
-       auth_method = key_blobtype == MM_USERKEY ? "publickey" : "hostbased";
-
        monitor_reset_key_state();
 
+       sshkey_free(key);
        sshbuf_reset(m);
 
        /* encode ret != 0 as positive integer, since we're sending u32 */
@@ -1799,6 +1800,7 @@ int
 mm_answer_gss_userok(int sock, Buffer *m)
 {
        int authenticated;
+       const char *displayname;
 
        if (!options.gss_authentication)
                fatal("%s: GSSAPI authentication not enabled", __func__);
@@ -1813,6 +1815,9 @@ mm_answer_gss_userok(int sock, Buffer *m)
 
        auth_method = "gssapi-with-mic";
 
+       if ((displayname = ssh_gssapi_displayname()) != NULL)
+               auth2_record_info(authctxt, "%s", displayname);
+
        /* Monitor loop will terminate if authenticated */
        return (authenticated);
 }
index a112798e496bacd4aba856c0988aa2792071f723..ed1fc71cff63367a8813b515e7809da408cfa126 100644 (file)
@@ -1,5 +1,5 @@
 
-/* $OpenBSD: servconf.c,v 1.308 2017/05/17 01:24:17 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.309 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -164,6 +164,7 @@ initialize_server_options(ServerOptions *options)
        options->version_addendum = NULL;
        options->fingerprint_hash = -1;
        options->disable_forwarding = -1;
+       options->expose_userauth_info = -1;
 }
 
 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
@@ -333,6 +334,8 @@ fill_default_server_options(ServerOptions *options)
                options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
        if (options->disable_forwarding == -1)
                options->disable_forwarding = 0;
+       if (options->expose_userauth_info == -1)
+               options->expose_userauth_info = 0;
 
        assemble_algorithms(options);
 
@@ -418,6 +421,7 @@ typedef enum {
        sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
        sStreamLocalBindMask, sStreamLocalBindUnlink,
        sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
+       sExposeAuthInfo,
        sDeprecated, sIgnore, sUnsupported
 } ServerOpCodes;
 
@@ -561,6 +565,7 @@ static struct {
        { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
        { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
        { "disableforwarding", sDisableForwarding, SSHCFG_ALL },
+       { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
        { NULL, sBadOption, 0 }
 };
 
@@ -1835,6 +1840,10 @@ process_server_config_line(ServerOptions *options, char *line,
                        options->fingerprint_hash = value;
                break;
 
+       case sExposeAuthInfo:
+               intptr = &options->expose_userauth_info;
+               goto parse_flag;
+
        case sDeprecated:
        case sIgnore:
        case sUnsupported:
@@ -1973,6 +1982,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
        M_CP_INTOPT(allow_streamlocal_forwarding);
        M_CP_INTOPT(allow_agent_forwarding);
        M_CP_INTOPT(disable_forwarding);
+       M_CP_INTOPT(expose_userauth_info);
        M_CP_INTOPT(permit_tun);
        M_CP_INTOPT(fwd_opts.gateway_ports);
        M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink);
@@ -2272,6 +2282,7 @@ dump_config(ServerOptions *o)
        dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
        dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink);
        dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
+       dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info);
 
        /* string arguments */
        dump_cfg_string(sPidFile, o->pid_file);
index 5853a97470aec51f818e880f85a80cbe1b797086..c2848a7655ee2b2f879eb99c9e71a7f16c3bbf8b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.123 2016/11/30 03:00:05 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.124 2017/06/24 06:34:38 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -189,6 +189,7 @@ typedef struct {
        char   *auth_methods[MAX_AUTH_METHODS];
 
        int     fingerprint_hash;
+       int     expose_userauth_info;
 }       ServerOptions;
 
 /* Information about the incoming connection as used by Match */
index 295204c6e8f9b51f42ceaaea32ce0e6e5e57fd25..a2588e74be45e910fc1c9fcc09d85a9a419d8125 100644 (file)
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.289 2017/06/24 05:24:11 djm Exp $ */
+/* $OpenBSD: session.c,v 1.290 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -94,6 +94,7 @@
 #include "kex.h"
 #include "monitor_wrap.h"
 #include "sftp.h"
+#include "atomicio.h"
 
 #if defined(KRB5) && defined(USE_AFS)
 #include <kafs.h>
@@ -160,6 +161,9 @@ login_cap_t *lc;
 static int is_child = 0;
 static int in_chroot = 0;
 
+/* File containing userauth info, if ExposeAuthInfo set */
+static char *auth_info_file = NULL;
+
 /* Name and directory of socket for authentication agent forwarding. */
 static char *auth_sock_name = NULL;
 static char *auth_sock_dir = NULL;
@@ -249,6 +253,40 @@ display_loginmsg(void)
        }
 }
 
+static void
+prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
+{
+       int fd = -1, success = 0;
+
+       if (!options.expose_userauth_info || info == NULL)
+               return;
+
+       temporarily_use_uid(pw);
+       auth_info_file = xstrdup("/tmp/sshauth.XXXXXXXXXXXXXXX");
+       if ((fd = mkstemp(auth_info_file)) == -1) {
+               error("%s: mkstemp: %s", __func__, strerror(errno));
+               goto out;
+       }
+       if (atomicio(vwrite, fd, sshbuf_mutable_ptr(info),
+           sshbuf_len(info)) != sshbuf_len(info)) {
+               error("%s: write: %s", __func__, strerror(errno));
+               goto out;
+       }
+       if (close(fd) != 0) {
+               error("%s: close: %s", __func__, strerror(errno));
+               goto out;
+       }
+       success = 1;
+ out:
+       if (!success) {
+               if (fd != -1)
+                       close(fd);
+               free(auth_info_file);
+               auth_info_file = NULL;
+       }
+       restore_uid();
+}
+
 void
 do_authenticated(Authctxt *authctxt)
 {
@@ -264,7 +302,10 @@ do_authenticated(Authctxt *authctxt)
 
        auth_debug_send();
 
+       prepare_auth_info_file(authctxt->pw, authctxt->session_info);
+
        do_authenticated2(authctxt);
+
        do_cleanup(authctxt);
 }
 
@@ -1077,6 +1118,8 @@ do_setup_env(Session *s, const char *shell)
        free(laddr);
        child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
 
+       if (auth_info_file != NULL)
+               child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file);
        if (s->ttyfd != -1)
                child_set_env(&env, &envsize, "SSH_TTY", s->tty);
        if (s->term)
@@ -2549,6 +2592,15 @@ do_cleanup(Authctxt *authctxt)
        /* remove agent socket */
        auth_sock_cleanup_proc(authctxt->pw);
 
+       /* remove userauth info */
+       if (auth_info_file != NULL) {
+               temporarily_use_uid(authctxt->pw);
+               unlink(auth_info_file);
+               restore_uid();
+               free(auth_info_file);
+               auth_info_file = NULL;
+       }
+
        /*
         * Cleanup ptys/utmp only if privsep is disabled,
         * or if running in monitor.
index a99d7f08b30b90536db2bd215754dd548d6f2a1a..6593e422d929d92b64812a93dc87575489fff920 100644 (file)
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 djm Exp $ */
+/* $OpenBSD: ssh-gss.h,v 1.12 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  *
@@ -128,6 +128,7 @@ OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
 void ssh_gssapi_do_child(char ***, u_int *);
 void ssh_gssapi_cleanup_creds(void);
 void ssh_gssapi_storecreds(void);
+const char *ssh_gssapi_displayname(void);
 
 #endif /* GSSAPI */
 
index 7b4cb1d9a8547efdfa2240dd8cb8183734a8dd97..cfe1db82a36f4ff9ab1deb624a12f891bc81a90b 100644 (file)
@@ -33,8 +33,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: sshd_config.5,v 1.245 2017/05/17 01:24:17 djm Exp $
-.Dd $Mdocdate: May 17 2017 $
+.\" $OpenBSD: sshd_config.5,v 1.246 2017/06/24 06:34:38 djm Exp $
+.Dd $Mdocdate: June 24 2017 $
 .Dt SSHD_CONFIG 5
 .Os
 .Sh NAME
@@ -564,6 +564,12 @@ Disables all forwarding features, including X11,
 TCP and StreamLocal.
 This option overrides all other forwarding-related options and may
 simplify restricted configurations.
+.It Cm ExposeAuthInfo
+Enables writing a file containing a list of authentication methods and
+public credentials (e.g. keys) used to authenticate the user.
+The location of the file is exposed to the user session though the
+.Ev SSH_AUTH_INFO
+enviornment variable.
 .It Cm FingerprintHash
 Specifies the hash algorithm used when logging key fingerprints.
 Valid options are: