refactor authentication logging
authordjm <djm@openbsd.org>
Sat, 24 Jun 2017 06:34:38 +0000 (06:34 +0000)
committerdjm <djm@openbsd.org>
Sat, 24 Jun 2017 06:34:38 +0000 (06:34 +0000)
optionally record successful auth methods and public credentials
used in a file accessible to user sessions

feedback and ok markus@

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

index 8f0b8ed..ab43361 100644 (file)
@@ -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.
  *
@@ -195,21 +195,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
@@ -218,7 +238,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;
@@ -237,6 +258,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,
@@ -245,10 +271,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);
 }
 
 void
index 1fea67c..96fd1a7 100644 (file)
@@ -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.
@@ -57,22 +57,34 @@ struct Authctxt {
        char            *service;
        struct passwd   *pw;            /* set if 'valid' */
        char            *style;
-       void            *kbdintctxt;
-       char            *info;          /* Extra info for next auth_log */
-       auth_session_t  *as;
+
+       /* 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;
+       auth_session_t  *as;
 #ifdef KRB5
        krb5_context     krb5_ctx;
        krb5_ccache      krb5_fwd_ccache;
        krb5_principal   krb5_user;
        char            *krb5_ticket_file;
 #endif
-       void            *methoddata;
 
-       struct sshkey   **prev_userkeys;
-       u_int            nprev_userkeys;
+       /* Authentication keys already used; these will be refused henceforth */
+       struct sshkey   **prev_keys;
+       u_int            nprev_keys;
+
+       /* 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
@@ -111,10 +123,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,
@@ -129,9 +149,6 @@ void        krb5_cleanup_proc(Authctxt *authctxt);
 
 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 18cfaf7..c9c11a1 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.
@@ -223,6 +223,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");
@@ -236,6 +237,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);
@@ -254,6 +259,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");
@@ -277,6 +283,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 e982d19..3ea8311 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.
  *
@@ -136,7 +136,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 */
@@ -146,11 +146,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 6783729..c79a2f2 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.
  *
@@ -134,7 +134,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;
        }
@@ -191,7 +191,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;
@@ -199,12 +198,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);
@@ -234,8 +231,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);
@@ -243,44 +239,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
@@ -1145,36 +1103,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,
index f83131a..68aca4d 100644 (file)
@@ -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.
  *
@@ -29,6 +29,7 @@
 #include <sys/uio.h>
 
 #include <fcntl.h>
+#include <limits.h>
 #include <pwd.h>
 #include <stdarg.h>
 #include <string.h>
@@ -52,6 +53,7 @@
 #include "ssh-gss.h"
 #endif
 #include "monitor_wrap.h"
+#include "ssherr.h"
 
 /* import */
 extern ServerOptions options;
@@ -257,6 +259,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;
 
@@ -303,6 +306,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;
 
@@ -573,4 +580,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 f26db42..add350d 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.
@@ -389,4 +389,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 ef5e9fc..08fb96d 100644 (file)
@@ -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>
@@ -247,6 +247,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 */
@@ -274,6 +276,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);
+                       }
                }
        }
 
@@ -856,12 +862,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))
@@ -869,11 +874,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";
@@ -884,11 +890,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();
@@ -1062,10 +1067,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;
@@ -1076,23 +1083,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 */
@@ -1459,6 +1460,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__);
@@ -1473,6 +1475,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 747e8df..10fed9b 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
@@ -154,6 +154,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. */
@@ -316,6 +317,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);
 
@@ -388,6 +391,7 @@ typedef enum {
        sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
        sStreamLocalBindMask, sStreamLocalBindUnlink,
        sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
+       sExposeAuthInfo,
        sDeprecated, sIgnore, sUnsupported
 } ServerOpCodes;
 
@@ -515,6 +519,7 @@ static struct {
        { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
        { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
        { "disableforwarding", sDisableForwarding, SSHCFG_ALL },
+       { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
        { NULL, sBadOption, 0 }
 };
 
@@ -1783,6 +1788,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:
@@ -1921,6 +1930,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);
@@ -2213,6 +2223,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 712e756..0ccafdd 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>
@@ -187,6 +187,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 32046ef..2f4ca7a 100644 (file)
@@ -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
@@ -85,6 +85,7 @@
 #endif
 #include "monitor_wrap.h"
 #include "sftp.h"
+#include "atomicio.h"
 
 #ifdef KRB5
 #include <kafs.h>
@@ -142,6 +143,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;
@@ -231,6 +235,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)
 {
@@ -246,7 +284,10 @@ do_authenticated(Authctxt *authctxt)
 
        auth_debug_send();
 
+       prepare_auth_info_file(authctxt->pw, authctxt->session_info);
+
        do_authenticated2(authctxt);
+
        do_cleanup(authctxt);
 }
 
@@ -845,6 +886,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)
@@ -2147,6 +2190,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 f5e744f..09ea35a 100644 (file)
@@ -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.
  *
@@ -107,6 +107,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 48b551a..d52abbb 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
@@ -565,6 +565,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: