Bugzilla – Attachment 2846 Details for
Bug 2408
Expose authentication information to PAM
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Expose successful auth methods via environments (pam and shell)
expose-authmeth-details.patch (text/plain), 16.63 KB, created by
Vincent Brillault
on 2016-07-01 22:26:04 AEST
(
hide
)
Description:
Expose successful auth methods via environments (pam and shell)
Filename:
MIME Type:
Creator:
Vincent Brillault
Created:
2016-07-01 22:26:04 AEST
Size:
16.63 KB
patch
obsolete
>diff --git a/auth-pam.c b/auth-pam.c >index 451de78..7cbda5d 100644 >--- a/auth-pam.c >+++ b/auth-pam.c >@@ -673,6 +673,11 @@ sshpam_init_ctx(Authctxt *authctxt) > return (NULL); > } > >+ /* Notify PAM about any already successful auth methods */ >+ if (options.expose_auth_methods >= EXPOSE_AUTHMETH_PAMONLY && >+ authctxt->auth_details) >+ do_pam_putenv("SSH_USER_AUTH", authctxt->auth_details); >+ > ctxt = xcalloc(1, sizeof *ctxt); > > /* Start the authentication thread */ >diff --git a/auth.h b/auth.h >index 55170af..774ea4f 100644 >--- a/auth.h >+++ b/auth.h >@@ -81,6 +81,9 @@ struct Authctxt { > > struct sshkey **prev_userkeys; > u_int nprev_userkeys; >+ >+ char *last_details; >+ char *auth_details; > }; > /* > * Every authentication method has to handle authentication requests for >diff --git a/auth2-gss.c b/auth2-gss.c >index 1ca8357..adf9e55 100644 >--- a/auth2-gss.c >+++ b/auth2-gss.c >@@ -240,6 +240,9 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) > > authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); > >+ if (authenticated) >+ authctxt->last_details = ssh_gssapi_get_displayname(); >+ > authctxt->postponed = 0; > dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); > dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); >@@ -278,6 +281,9 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) > else > logit("GSSAPI MIC check failed"); > >+ if (authenticated) >+ authctxt->last_details = ssh_gssapi_get_displayname(); >+ > buffer_free(&b); > free(mic.value); > >diff --git a/auth2-hostbased.c b/auth2-hostbased.c >index 1b3c3b2..570e760 100644 >--- a/auth2-hostbased.c >+++ b/auth2-hostbased.c >@@ -60,7 +60,7 @@ userauth_hostbased(Authctxt *authctxt) > { > Buffer b; > Key *key = NULL; >- char *pkalg, *cuser, *chost, *service; >+ char *pkalg, *cuser, *chost, *service, *pubkey; > u_char *pkblob, *sig; > u_int alen, blen, slen; > int pktype; >@@ -132,15 +132,21 @@ userauth_hostbased(Authctxt *authctxt) > buffer_dump(&b); > #endif > >- pubkey_auth_info(authctxt, key, >- "client user \"%.100s\", client host \"%.100s\"", cuser, chost); >+ pubkey = sshkey_format_oneline(key, options.fingerprint_hash); >+ auth_info(authctxt, >+ "%s, client user \"%.100s\", client host \"%.100s\"", >+ pubkey, cuser, chost); > > /* test for allowed key and correct signature */ > authenticated = 0; > if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && > PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), >- buffer_len(&b))) == 1) >+ buffer_len(&b))) == 1) { > authenticated = 1; >+ authctxt->last_details = pubkey; >+ } else { >+ free(pubkey); >+ } > > buffer_free(&b); > done: >diff --git a/auth2-pubkey.c b/auth2-pubkey.c >index 41b34ae..08812e9 100644 >--- a/auth2-pubkey.c >+++ b/auth2-pubkey.c >@@ -79,7 +79,7 @@ userauth_pubkey(Authctxt *authctxt) > { > Buffer b; > Key *key = NULL; >- char *pkalg, *userstyle, *fp = NULL; >+ char *pkalg, *userstyle, *pubkey, *fp = NULL; > u_char *pkblob, *sig; > u_int alen, blen, slen; > int have_sig, pktype; >@@ -171,7 +171,8 @@ userauth_pubkey(Authctxt *authctxt) > #ifdef DEBUG_PK > buffer_dump(&b); > #endif >- pubkey_auth_info(authctxt, key, NULL); >+ pubkey = sshkey_format_oneline(key, options.fingerprint_hash); >+ auth_info(authctxt, "%s", pubkey); > > /* test for correct signature */ > authenticated = 0; >@@ -179,9 +180,12 @@ userauth_pubkey(Authctxt *authctxt) > PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), > buffer_len(&b))) == 1) { > authenticated = 1; >+ authctxt->last_details = pubkey; > /* Record the successful key to prevent reuse */ > auth2_record_userkey(authctxt, key); > key = NULL; /* Don't free below */ >+ } else { >+ free(pubkey); > } > buffer_free(&b); > free(sig); >@@ -222,7 +226,7 @@ done: > void > pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) > { >- char *fp, *extra; >+ char *extra, *pubkey; > va_list ap; > int i; > >@@ -232,27 +236,13 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) > i = vasprintf(&extra, fmt, ap); > va_end(ap); > if (i < 0 || extra == NULL) >- fatal("%s: vasprintf failed", __func__); >+ fatal("%s: vasprintf failed", __func__); > } > >- if (key_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", >- key_type(key), key->cert->key_id, >- (unsigned long long)key->cert->serial, >- key_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", key_type(key), >- fp == NULL ? "(null)" : fp, >- extra == NULL ? "" : ", ", extra == NULL ? "" : extra); >- free(fp); >- } >+ pubkey = sshkey_format_oneline(key, options.fingerprint_hash); >+ auth_info(authctxt, "%s%s%s", pubkey, extra == NULL ? "" : ", ", >+ extra == NULL ? "" : extra); >+ free(pubkey); > free(extra); > } > >diff --git a/auth2.c b/auth2.c >index 9108b86..3a48ba0 100644 >--- a/auth2.c >+++ b/auth2.c >@@ -293,6 +293,7 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method, > const char *submethod) > { > char *methods; >+ char *prev_auth_details; > int partial = 0; > > if (!authctxt->valid && authenticated) >@@ -323,6 +324,18 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method, > if (authctxt->postponed) > return; > >+ if (authenticated || partial) { >+ prev_auth_details = authctxt->auth_details; >+ xasprintf(&authctxt->auth_details, "%s%s%s%s%s", >+ prev_auth_details ? prev_auth_details : "", >+ prev_auth_details ? ", " : "", method, >+ authctxt->last_details ? ": " : "", >+ authctxt->last_details ? authctxt->last_details : ""); >+ free(prev_auth_details); >+ } >+ free(authctxt->last_details); >+ authctxt->last_details = NULL; >+ > #ifdef USE_PAM > if (options.use_pam && authenticated) { > if (!PRIVSEP(do_pam_account())) { >diff --git a/gss-serv.c b/gss-serv.c >index 53993d6..87321f1 100644 >--- a/gss-serv.c >+++ b/gss-serv.c >@@ -384,6 +384,16 @@ ssh_gssapi_userok(char *user) > } > > /* Privileged */ >+char* >+ssh_gssapi_get_displayname(void) >+{ >+ if (gssapi_client.displayname.length != 0 && >+ gssapi_client.displayname.value != NULL) >+ return strdup((char *)gssapi_client.displayname.value); >+ return NULL; >+} >+ >+/* Privileged */ > OM_uint32 > ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) > { >diff --git a/monitor.c b/monitor.c >index 8b3c27a..06ab6d5 100644 >--- a/monitor.c >+++ b/monitor.c >@@ -335,6 +335,7 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) > { > struct mon_table *ent; > int authenticated = 0, partial = 0; >+ char *prev_auth_details; > > debug3("preauth child monitor started"); > >@@ -366,6 +367,18 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) > auth_submethod = NULL; > authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1); > >+ if (authenticated) { >+ prev_auth_details = authctxt->auth_details; >+ xasprintf(&authctxt->auth_details, "%s%s%s%s%s", >+ prev_auth_details ? prev_auth_details : "", >+ prev_auth_details ? ", " : "", auth_method, >+ authctxt->last_details ? ": " : "", >+ authctxt->last_details ? authctxt->last_details : ""); >+ free(prev_auth_details); >+ } >+ free(authctxt->last_details); >+ authctxt->last_details = NULL; >+ > /* Special handling for multiple required authentications */ > if (options.num_auth_methods != 0) { > if (!compat20) >@@ -1450,6 +1463,10 @@ mm_answer_keyverify(int sock, Buffer *m) > debug3("%s: key %p signature %s", > __func__, key, (verified == 1) ? "verified" : "unverified"); > >+ if (verified == 1) >+ authctxt->last_details = sshkey_format_oneline(key, >+ options.fingerprint_hash); >+ > /* If auth was successful then record key to ensure it isn't reused */ > if (verified == 1 && key_blobtype == MM_USERKEY) > auth2_record_userkey(authctxt, key); >@@ -2060,6 +2077,9 @@ mm_answer_gss_userok(int sock, Buffer *m) > > auth_method = "gssapi-with-mic"; > >+ if (authenticated) >+ authctxt->last_details = ssh_gssapi_get_displayname(); >+ > /* Monitor loop will terminate if authenticated */ > return (authenticated); > } >diff --git a/servconf.c b/servconf.c >index 873b0d0..57f69a1 100644 >--- a/servconf.c >+++ b/servconf.c >@@ -169,6 +169,7 @@ initialize_server_options(ServerOptions *options) > options->ip_qos_bulk = -1; > options->version_addendum = NULL; > options->fingerprint_hash = -1; >+ options->expose_auth_methods = -1; > } > > /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ >@@ -353,6 +354,8 @@ fill_default_server_options(ServerOptions *options) > options->fwd_opts.streamlocal_bind_unlink = 0; > if (options->fingerprint_hash == -1) > options->fingerprint_hash = SSH_FP_HASH_DEFAULT; >+ if (options->expose_auth_methods == -1) >+ options->expose_auth_methods = EXPOSE_AUTHMETH_NEVER; > > assemble_algorithms(options); > >@@ -438,6 +441,7 @@ typedef enum { > sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, > sStreamLocalBindMask, sStreamLocalBindUnlink, > sAllowStreamLocalForwarding, sFingerprintHash, >+ sExposeAuthenticationMethods, > sDeprecated, sUnsupported > } ServerOpCodes; > >@@ -580,6 +584,7 @@ static struct { > { "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL }, > { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL }, > { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, >+ { "exposeauthenticationmethods", sExposeAuthenticationMethods, SSHCFG_ALL }, > { NULL, sBadOption, 0 } > }; > >@@ -969,6 +974,12 @@ static const struct multistate multistate_tcpfwd[] = { > { "local", FORWARD_LOCAL }, > { NULL, -1 } > }; >+static const struct multistate multistate_exposeauthmeth[] = { >+ { "never", EXPOSE_AUTHMETH_NEVER }, >+ { "pam-only", EXPOSE_AUTHMETH_PAMONLY }, >+ { "pam-and-env", EXPOSE_AUTHMETH_PAMENV }, >+ { NULL, -1} >+}; > > int > process_server_config_line(ServerOptions *options, char *line, >@@ -1879,6 +1890,11 @@ process_server_config_line(ServerOptions *options, char *line, > options->fingerprint_hash = value; > break; > >+ case sExposeAuthenticationMethods: >+ intptr = &options->expose_auth_methods; >+ multistate_ptr = multistate_exposeauthmeth; >+ goto parse_multistate; >+ > case sDeprecated: > logit("%s line %d: Deprecated option %s", > filename, linenum, arg); >@@ -2034,6 +2050,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) > M_CP_INTOPT(ip_qos_bulk); > M_CP_INTOPT(rekey_limit); > M_CP_INTOPT(rekey_interval); >+ M_CP_INTOPT(expose_auth_methods); > > /* > * The bind_mask is a mode_t that may be unsigned, so we can't use >@@ -2148,6 +2165,8 @@ fmt_intarg(ServerOpCodes code, int val) > return fmt_multistate_int(val, multistate_tcpfwd); > case sFingerprintHash: > return ssh_digest_alg_name(val); >+ case sExposeAuthenticationMethods: >+ return fmt_multistate_int(val, multistate_exposeauthmeth); > case sProtocol: > switch (val) { > case SSH_PROTO_1: >@@ -2337,6 +2356,7 @@ dump_config(ServerOptions *o) > dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); > dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); > dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); >+ dump_cfg_fmtint(sExposeAuthenticationMethods, o->expose_auth_methods); > > /* string arguments */ > dump_cfg_string(sPidFile, o->pid_file); >diff --git a/servconf.h b/servconf.h >index f4137af..1c9ba10 100644 >--- a/servconf.h >+++ b/servconf.h >@@ -48,6 +48,11 @@ > #define FORWARD_LOCAL (1<<1) > #define FORWARD_ALLOW (FORWARD_REMOTE|FORWARD_LOCAL) > >+/* Expose AuthenticationMethods */ >+#define EXPOSE_AUTHMETH_NEVER 0 >+#define EXPOSE_AUTHMETH_PAMONLY 1 >+#define EXPOSE_AUTHMETH_PAMENV 2 >+ > #define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */ > #define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */ > >@@ -195,6 +200,8 @@ typedef struct { > char *auth_methods[MAX_AUTH_METHODS]; > > int fingerprint_hash; >+ >+ int expose_auth_methods; /* EXPOSE_AUTHMETH_* above */ > } ServerOptions; > > /* Information about the incoming connection as used by Match */ >diff --git a/session.c b/session.c >index 2235f26..ffc2c0f 100644 >--- a/session.c >+++ b/session.c >@@ -1154,6 +1154,12 @@ copy_environment(char **source, char ***env, u_int *envsize) > } > *var_val++ = '\0'; > >+ if (options.expose_auth_methods < EXPOSE_AUTHMETH_PAMENV && >+ strcmp(var_name, "SSH_USER_AUTH") == 0) { >+ free(var_name); >+ continue; >+ } >+ > debug3("Copy environment: %s=%s", var_name, var_val); > child_set_env(env, envsize, var_name, var_val); > >@@ -1336,6 +1342,11 @@ do_setup_env(Session *s, const char *shell) > } > #endif /* USE_PAM */ > >+ if (options.expose_auth_methods >= EXPOSE_AUTHMETH_PAMENV && >+ s->authctxt->auth_details) >+ child_set_env(&env, &envsize, "SSH_USER_AUTH", >+ s->authctxt->auth_details); >+ > if (auth_sock_name != NULL) > child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, > auth_sock_name); >@@ -2777,6 +2788,9 @@ do_cleanup(Authctxt *authctxt) > if (authctxt == NULL) > return; > >+ free(authctxt->auth_details); >+ authctxt->auth_details = NULL; >+ > #ifdef USE_PAM > if (options.use_pam) { > sshpam_cleanup(); >diff --git a/ssh-gss.h b/ssh-gss.h >index a99d7f0..c2052b6 100644 >--- a/ssh-gss.h >+++ b/ssh-gss.h >@@ -124,6 +124,7 @@ int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); > /* In the server */ > OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); > int ssh_gssapi_userok(char *name); >+char* ssh_gssapi_get_displayname(void); > 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); >diff --git a/ssh.1 b/ssh.1 >index a6fb5d4..741d0d9 100644 >--- a/ssh.1 >+++ b/ssh.1 >@@ -1396,6 +1396,10 @@ server IP address, and server port number. > This variable contains the original command line if a forced command > is executed. > It can be used to extract the original arguments. >+.It Ev SSH_USER_AUTH >+This variable contains, for SSH2 only, a comma-separated list of authentication >+methods that were successfuly used to authenticate. When possible, these >+methods are extended with detailed information on the credential used. > .It Ev SSH_TTY > This is set to the name of the tty (path to the device) associated > with the current shell or command. >diff --git a/sshd_config.5 b/sshd_config.5 >index babe2ae..1f53818 100644 >--- a/sshd_config.5 >+++ b/sshd_config.5 >@@ -579,6 +579,21 @@ and finally > See PATTERNS in > .Xr ssh_config 5 > for more information on patterns. >+.It Cm ExposeAuthenticationMethods >+When using SSH2, this option controls the exposure of the list of >+successful authentication methods to PAM during the authentication >+and to the shell environment via the >+.Cm SSH_USER_AUTH >+variable. See the description of this variable for more details. >+Valid options are: >+.Dq never >+(Do not expose successful authentication methods), >+.Dq pam-only >+(Only expose them to PAM during authentication, not afterwards), >+.Dq pam-and-env >+(Expose them to PAM and keep them in the shell environment). >+The default is >+.Dq never . > .It Cm FingerprintHash > Specifies the hash algorithm used when logging key fingerprints. > Valid options are: >diff --git a/sshkey.c b/sshkey.c >index c9f04cd..06c619d 100644 >--- a/sshkey.c >+++ b/sshkey.c >@@ -58,6 +58,7 @@ > #define SSHKEY_INTERNAL > #include "sshkey.h" > #include "match.h" >+#include "xmalloc.h" > > /* openssh private key file format */ > #define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" >@@ -1189,6 +1190,30 @@ sshkey_fingerprint(const struct sshkey *k, int dgst_alg, > return retval; > } > >+char * >+sshkey_format_oneline(const struct sshkey *key, int dgst_alg) >+{ >+ char *fp, *result; >+ >+ if (sshkey_is_cert(key)) { >+ fp = sshkey_fingerprint(key->cert->signature_key, dgst_alg, >+ SSH_FP_DEFAULT); >+ xasprintf(&result, "%s ID %s (serial %llu) CA %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); >+ free(fp); >+ } else { >+ fp = sshkey_fingerprint(key, dgst_alg, SSH_FP_DEFAULT); >+ xasprintf(&result, "%s %s", sshkey_type(key), >+ fp == NULL ? "(null)" : fp); >+ free(fp); >+ } >+ >+ return result; >+} >+ > #ifdef WITH_SSH1 > /* > * Reads a multiple-precision integer in decimal from the buffer, and advances >diff --git a/sshkey.h b/sshkey.h >index 8c3d866..45a0a0b 100644 >--- a/sshkey.h >+++ b/sshkey.h >@@ -123,6 +123,7 @@ char *sshkey_fingerprint(const struct sshkey *, > int, enum sshkey_fp_rep); > int sshkey_fingerprint_raw(const struct sshkey *k, > int, u_char **retp, size_t *lenp); >+char *sshkey_format_oneline(const struct sshkey *k, int dgst_alg); > const char *sshkey_type(const struct sshkey *); > const char *sshkey_cert_type(const struct sshkey *); > int sshkey_write(const struct sshkey *, FILE *);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 2408
:
2754
|
2791
|
2792
|
2812
|
2846
|
2978
|
2980
|
2999
|
3022
|
3089
|
3091