diff --git a/gsi-openssh.spec b/gsi-openssh.spec index e84c1a3..f8ab0bd 100644 --- a/gsi-openssh.spec +++ b/gsi-openssh.spec @@ -30,7 +30,7 @@ # Do we want LDAP support %global ldap 1 -%global openssh_ver 7.2p1 +%global openssh_ver 7.2p2 %global openssh_rel 1 Summary: An implementation of the SSH protocol with GSI authentication @@ -175,7 +175,7 @@ Patch936: openssh-7.1p1-iutf8.patch # This is the patch that adds GSI support # Based on http://grid.ncsa.illinois.edu/ssh/dl/patch/openssh-7.0p1.patch -Patch98: openssh-7.2p1-gsissh.patch +Patch98: openssh-7.2p2-gsissh.patch License: BSD Group: Applications/Internet @@ -543,6 +543,9 @@ getent passwd sshd >/dev/null || \ %attr(0644,root,root) %{_tmpfilesdir}/gsissh.conf %changelog +* Sat Apr 16 2016 Mattias Ellert - 7.2p2-1 +- Based on openssh-7.2p2-2.fc23 + * Fri Mar 04 2016 Mattias Ellert - 7.2p1-1 - Based on openssh-7.2p1-2.fc23 diff --git a/gsisshd-keygen b/gsisshd-keygen index b313c87..eeef6ce 100644 --- a/gsisshd-keygen +++ b/gsisshd-keygen @@ -6,8 +6,22 @@ # variable. AUTOCREATE_SERVER_KEYS="RSA ECDSA ED25519" -# source function library -. /etc/rc.d/init.d/functions +if [ -f /etc/rc.d/init.d/functions ]; then + # source function library + . /etc/rc.d/init.d/functions +else + # minimal implementation of success and failure function + success() + { + echo -en $"[ OK ]\r" + return 0 + } + failure() + { + echo -en $"[FAILED]\r" + return 1 + } +fi # Some functions to make the below more readable KEYGEN=/usr/bin/gsissh-keygen diff --git a/openssh-7.2p1-audit.patch b/openssh-7.2p1-audit.patch index e7574b5..43798ab 100644 --- a/openssh-7.2p1-audit.patch +++ b/openssh-7.2p1-audit.patch @@ -224,9 +224,9 @@ diff -up openssh-7.2p1/audit.c.audit openssh-7.2p1/audit.c +int +audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) +{ -+ debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s%s, result %d", ++ debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s, result %d", + host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits, -+ sshkey_fingerprint_prefix(), fp, rv); ++ fp, rv); +} + +/* @@ -291,8 +291,16 @@ diff -up openssh-7.2p1/audit.h.audit openssh-7.2p1/audit.h enum ssh_audit_event_type { SSH_LOGIN_EXCEED_MAXTRIES, -@@ -47,11 +48,25 @@ enum ssh_audit_event_type { +@@ -45,13 +46,33 @@ enum ssh_audit_event_type { + SSH_CONNECTION_ABANDON, /* closed without completing auth */ + SSH_AUDIT_UNKNOWN }; ++ ++enum ssh_audit_kex { ++ SSH_AUDIT_UNSUPPORTED_CIPHER, ++ SSH_AUDIT_UNSUPPORTED_MAC, ++ SSH_AUDIT_UNSUPPORTED_COMPRESSION ++}; typedef enum ssh_audit_event_type ssh_audit_event_t; +int listening_for_clients(void); @@ -365,7 +373,7 @@ diff -up openssh-7.2p1/audit-linux.c.audit openssh-7.2p1/audit-linux.c NULL, "login", username ? username : "(unknown)", username == NULL ? uid : -1, hostname, ip, ttyn, success); saved_errno = errno; -@@ -65,35 +77,154 @@ linux_audit_record_event(int uid, const +@@ -65,35 +77,150 @@ linux_audit_record_event(int uid, const if ((rc == -EPERM) && (geteuid() != 0)) rc = 0; errno = saved_errno; @@ -406,7 +414,7 @@ diff -up openssh-7.2p1/audit-linux.c.audit openssh-7.2p1/audit-linux.c + else + goto fatal_report; /* Must prevent login */ + } -+ ++ + if ((event < 0) || (event > SSH_AUDIT_UNKNOWN)) + event = SSH_AUDIT_UNKNOWN; + @@ -439,7 +447,7 @@ diff -up openssh-7.2p1/audit-linux.c.audit openssh-7.2p1/audit-linux.c + if (errno == EINVAL || errno == EPROTONOSUPPORT || + errno == EAFNOSUPPORT) + return 1; /* No audit support in kernel */ -+ else ++ else + return 0; /* Must prevent login */ + } + snprintf(buf, sizeof(buf), "%s_auth rport=%d", host_user ? "pubkey" : "hostbased", get_remote_port()); @@ -447,10 +455,6 @@ diff -up openssh-7.2p1/audit-linux.c.audit openssh-7.2p1/audit-linux.c + buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv); + if ((rc < 0) && ((rc != -1) || (getuid() == 0))) + goto out; -+ /* is the fingerprint_prefix() still needed? -+ snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s%s rport=%d", -+ type, bits, sshkey_fingerprint_prefix(), fp, get_remote_port()); -+ */ + snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s rport=%d", + type, bits, fp, get_remote_port()); + rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, @@ -479,7 +483,7 @@ diff -up openssh-7.2p1/audit-linux.c.audit openssh-7.2p1/audit-linux.c audit_run_command(const char *command) { - /* not implemented */ -+ if (!user_login_count++) ++ if (!user_login_count++) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), + NULL, "ssh", 1, AUDIT_USER_LOGIN); + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), @@ -492,7 +496,7 @@ diff -up openssh-7.2p1/audit-linux.c.audit openssh-7.2p1/audit-linux.c +{ + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), + NULL, "ssh", 1, AUDIT_USER_END); -+ if (user_login_count && !--user_login_count) ++ if (user_login_count && !--user_login_count) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), + NULL, "ssh", 1, AUDIT_USER_LOGOUT); +} @@ -509,7 +513,7 @@ diff -up openssh-7.2p1/audit-linux.c.audit openssh-7.2p1/audit-linux.c - if (linux_audit_record_event(li->uid, NULL, li->hostname, - NULL, li->line, 1) == 0) - fatal("linux_audit_write_entry failed: %s", strerror(errno)); -+ if (!user_login_count++) ++ if (!user_login_count++) + linux_audit_user_logxxx(li->uid, NULL, li->hostname, + NULL, li->line, 1, AUDIT_USER_LOGIN); + linux_audit_user_logxxx(li->uid, NULL, li->hostname, @@ -522,7 +526,7 @@ diff -up openssh-7.2p1/audit-linux.c.audit openssh-7.2p1/audit-linux.c - /* not implemented */ + linux_audit_user_logxxx(li->uid, NULL, li->hostname, + NULL, li->line, 1, AUDIT_USER_END); -+ if (user_login_count && !--user_login_count) ++ if (user_login_count && !--user_login_count) + linux_audit_user_logxxx(li->uid, NULL, li->hostname, + NULL, li->line, 1, AUDIT_USER_LOGOUT); } @@ -625,7 +629,7 @@ diff -up openssh-7.2p1/audit-linux.c.audit openssh-7.2p1/audit-linux.c + if (errno == EINVAL || errno == EPROTONOSUPPORT || + errno == EAFNOSUPPORT) + return; /* No audit support in kernel */ -+ else ++ else + fatal("cannot open audit"); /* Must prevent login */ + } + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, @@ -991,7 +995,7 @@ diff -up openssh-7.2p1/kex.c.audit openssh-7.2p1/kex.c - if (name == NULL) + if (name == NULL) { +#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(0); ++ audit_unsupported(SSH_AUDIT_UNSUPPORTED_CIPHER); +#endif return SSH_ERR_NO_CIPHER_ALG_MATCH; + } @@ -1005,7 +1009,7 @@ diff -up openssh-7.2p1/kex.c.audit openssh-7.2p1/kex.c - if (name == NULL) + if (name == NULL) { +#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(1); ++ audit_unsupported(SSH_AUDIT_UNSUPPORTED_MAC); +#endif return SSH_ERR_NO_MAC_ALG_MATCH; + } @@ -1019,7 +1023,7 @@ diff -up openssh-7.2p1/kex.c.audit openssh-7.2p1/kex.c - if (name == NULL) + if (name == NULL) { +#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(2); ++ audit_unsupported(SSH_AUDIT_UNSUPPORTED_COMPRESSION); +#endif return SSH_ERR_NO_COMPRESS_ALG_MATCH; + } @@ -1037,7 +1041,7 @@ diff -up openssh-7.2p1/kex.c.audit openssh-7.2p1/kex.c } /* XXX need runden? */ kex->we_need = need; -@@ -1052,3 +1069,34 @@ dump_digest(char *msg, u_char *digest, i +@@ -1052,3 +1069,33 @@ dump_digest(char *msg, u_char *digest, i sshbuf_dump_data(digest, len, stderr); } #endif @@ -1071,10 +1075,9 @@ diff -up openssh-7.2p1/kex.c.audit openssh-7.2p1/kex.c + mac_destroy(&newkeys->mac); + memset(&newkeys->comp, 0, sizeof(newkeys->comp)); +} -+ diff -up openssh-7.2p1/kex.h.audit openssh-7.2p1/kex.h ---- openssh-7.2p1/kex.h.audit 2016-02-12 18:24:34.201825185 +0100 -+++ openssh-7.2p1/kex.h 2016-02-12 18:24:34.222825177 +0100 +--- openssh-7.2p1/kex.h.audit 2016-03-04 14:25:52.627329892 +0100 ++++ openssh-7.2p1/kex.h 2016-03-04 14:25:52.639329883 +0100 @@ -206,6 +206,8 @@ int kexgss_client(struct ssh *); int kexgss_server(struct ssh *); #endif @@ -1690,7 +1693,7 @@ diff -up openssh-7.2p1/packet.c.audit openssh-7.2p1/packet.c + error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); + if ((r = cipher_cleanup(&state->receive_context)) != 0) + error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); -+ audit_session_key_free(2); ++ audit_session_key_free(MODE_MAX); + } free(ssh->remote_ipaddr); ssh->remote_ipaddr = NULL; @@ -1712,7 +1715,7 @@ diff -up openssh-7.2p1/packet.c.audit openssh-7.2p1/packet.c if ((r = cipher_cleanup(cc)) != 0) return r; enc = &state->newkeys[mode]->enc; -@@ -2408,6 +2420,75 @@ ssh_packet_get_output(struct ssh *ssh) +@@ -2408,6 +2420,72 @@ ssh_packet_get_output(struct ssh *ssh) return (void *)ssh->state->output; } @@ -1769,18 +1772,15 @@ diff -up openssh-7.2p1/packet.c.audit openssh-7.2p1/packet.c +packet_destroy_all(int audit_it, int privsep) +{ + if (audit_it) -+ audit_it = (active_state != NULL && packet_state_has_keys(active_state->state)) -+ || (backup_state != NULL && packet_state_has_keys(backup_state->state)); ++ audit_it = (active_state != NULL && packet_state_has_keys(active_state->state)); + if (active_state != NULL) + packet_destroy_state(active_state->state); -+ if (backup_state != NULL) -+ packet_destroy_state(backup_state->state); + if (audit_it) { +#ifdef SSH_AUDIT_EVENTS + if (privsep) -+ audit_session_key_free(2); ++ audit_session_key_free(MODE_MAX); + else -+ audit_session_key_free_body(2, getpid(), getuid()); ++ audit_session_key_free_body(MODE_MAX, getpid(), getuid()); +#endif + } +} @@ -1789,17 +1789,8 @@ diff -up openssh-7.2p1/packet.c.audit openssh-7.2p1/packet.c static int ssh_packet_set_postauth(struct ssh *ssh) diff -up openssh-7.2p1/packet.h.audit openssh-7.2p1/packet.h ---- openssh-7.2p1/packet.h.audit 2016-02-12 11:47:25.000000000 +0100 -+++ openssh-7.2p1/packet.h 2016-02-12 18:24:34.226825175 +0100 -@@ -186,7 +186,7 @@ int sshpkt_get_end(struct ssh *ssh); - const u_char *sshpkt_ptr(struct ssh *, size_t *lenp); - - /* OLD API */ --extern struct ssh *active_state; -+extern struct ssh *active_state, *backup_state; - #include "opacket.h" - - #if !defined(WITH_OPENSSL) +--- openssh-7.2p1/packet.h.audit 2016-02-26 04:40:04.000000000 +0100 ++++ openssh-7.2p1/packet.h 2016-03-04 14:25:52.640329883 +0100 @@ -200,4 +200,5 @@ extern struct ssh *active_state; # undef EC_POINT #endif @@ -1838,7 +1829,7 @@ diff -up openssh-7.2p1/session.c.audit openssh-7.2p1/session.c /* Parent. Close the slave side of the pseudo tty. */ close(ttyfd); -+#ifndef HAVE_OSF_SIA ++#if !defined(HAVE_OSF_SIA) && defined(SSH_AUDIT_EVENTS) + /* do_login in the child did not affect state in this process, + compensate. From an architectural standpoint, this is extremely + ugly. */ @@ -1902,7 +1893,7 @@ diff -up openssh-7.2p1/session.c.audit openssh-7.2p1/session.c + if (s->used) + return s; + } -+ debug("session_by_id: unknown id %d", id); ++ debug("%s: unknown id %d", __func__, id); + session_dump(); + return NULL; +} @@ -1979,8 +1970,8 @@ diff -up openssh-7.2p1/session.c.audit openssh-7.2p1/session.c + session_destroy_all(do_cleanup_one_session); } diff -up openssh-7.2p1/session.h.audit openssh-7.2p1/session.h ---- openssh-7.2p1/session.h.audit 2016-02-12 11:47:25.000000000 +0100 -+++ openssh-7.2p1/session.h 2016-02-12 18:24:34.226825175 +0100 +--- openssh-7.2p1/session.h.audit 2016-02-26 04:40:04.000000000 +0100 ++++ openssh-7.2p1/session.h 2016-03-04 14:25:52.641329882 +0100 @@ -61,6 +61,12 @@ struct Session { char *name; char *val; @@ -2041,7 +2032,7 @@ diff -up openssh-7.2p1/sshd.c.audit openssh-7.2p1/sshd.c static void close_startup_pipes(void) { -@@ -560,22 +570,45 @@ sshd_exchange_identification(int sock_in +@@ -560,22 +570,49 @@ sshd_exchange_identification(int sock_in } } @@ -2055,15 +2046,17 @@ diff -up openssh-7.2p1/sshd.c.audit openssh-7.2p1/sshd.c +destroy_sensitive_data(int privsep) { int i; ++#ifdef SSH_AUDIT_EVENTS + pid_t pid; + uid_t uid; ++ pid = getpid(); ++ uid = getuid(); ++#endif if (sensitive_data.server_key) { key_free(sensitive_data.server_key); sensitive_data.server_key = NULL; } -+ pid = getpid(); -+ uid = getuid(); for (i = 0; i < options.num_host_key_files; i++) { if (sensitive_data.host_keys[i]) { + char *fp; @@ -2075,12 +2068,14 @@ diff -up openssh-7.2p1/sshd.c.audit openssh-7.2p1/sshd.c key_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = NULL; + if (fp != NULL) { ++#ifdef SSH_AUDIT_EVENTS + if (privsep) + PRIVSEP(audit_destroy_sensitive_data(fp, + pid, uid)); + else + audit_destroy_sensitive_data(fp, + pid, uid); ++#endif + free(fp); + } } @@ -2090,21 +2085,22 @@ diff -up openssh-7.2p1/sshd.c.audit openssh-7.2p1/sshd.c key_free(sensitive_data.host_certificates[i]); sensitive_data.host_certificates[i] = NULL; } -@@ -589,6 +622,8 @@ void - demote_sensitive_data(void) +@@ -590,7 +627,13 @@ demote_sensitive_data(void) { Key *tmp; + int i; ++#ifdef SSH_AUDIT_EVENTS + pid_t pid; + uid_t uid; - int i; - - if (sensitive_data.server_key) { -@@ -597,13 +632,25 @@ demote_sensitive_data(void) - sensitive_data.server_key = tmp; - } + pid = getpid(); + uid = getuid(); ++#endif + if (sensitive_data.server_key) { + tmp = key_demote(sensitive_data.server_key); + key_free(sensitive_data.server_key); +@@ -599,11 +642,23 @@ demote_sensitive_data(void) + for (i = 0; i < options.num_host_key_files; i++) { if (sensitive_data.host_keys[i]) { + char *fp; @@ -2119,7 +2115,9 @@ diff -up openssh-7.2p1/sshd.c.audit openssh-7.2p1/sshd.c if (tmp->type == KEY_RSA1) sensitive_data.ssh1_host_key = tmp; + if (fp != NULL) { ++#ifdef SSH_AUDIT_EVENTS + audit_destroy_sensitive_data(fp, pid, uid); ++#endif + free(fp); + } } diff --git a/openssh-7.2p1-gsissh.patch b/openssh-7.2p1-gsissh.patch deleted file mode 100644 index 4ca7374..0000000 --- a/openssh-7.2p1-gsissh.patch +++ /dev/null @@ -1,3012 +0,0 @@ -diff -Nur openssh-7.2p1.orig/auth2.c openssh-7.2p1/auth2.c ---- openssh-7.2p1.orig/auth2.c 2016-03-02 19:04:36.376960285 +0100 -+++ openssh-7.2p1/auth2.c 2016-03-02 19:05:41.290212928 +0100 -@@ -50,6 +50,7 @@ - #include "dispatch.h" - #include "pathnames.h" - #include "buffer.h" -+#include "canohost.h" - - #ifdef GSSAPI - #include "ssh-gss.h" -@@ -74,6 +75,8 @@ - extern Authmethod method_gssapi; - #endif - -+static int log_flag = 0; -+ - Authmethod *authmethods[] = { - &method_none, - &method_pubkey, -@@ -228,7 +231,33 @@ - user = packet_get_cstring(NULL); - service = packet_get_cstring(NULL); - method = packet_get_cstring(NULL); -- debug("userauth-request for user %s service %s method %s", user, service, method); -+ -+#ifdef GSSAPI -+ if (user[0] == '\0') { -+ debug("received empty username for %s", method); -+ if (strcmp(method, "gssapi-keyex") == 0) { -+ char *lname = NULL; -+ PRIVSEP(ssh_gssapi_localname(&lname)); -+ if (lname && lname[0] != '\0') { -+ free(user); -+ user = lname; -+ debug("set username to %s from gssapi context", user); -+ } else { -+ debug("failed to set username from gssapi context"); -+ packet_send_debug("failed to set username from gssapi context"); -+ } -+ } -+ } -+#endif -+ -+ debug("userauth-request for user %s service %s method %s", -+ user[0] ? user : "", service, method); -+ if (!log_flag) { -+ logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s", -+ get_remote_ipaddr(), get_remote_port(), -+ user[0] ? user : ""); -+ log_flag = 1; -+ } - debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); - - #ifdef WITH_SELINUX -@@ -239,23 +268,48 @@ - if ((style = strchr(user, ':')) != NULL) - *style++ = 0; - -- if (authctxt->attempt++ == 0) { -- /* setup auth context */ -- authctxt->pw = PRIVSEP(getpwnamallow(user)); -+ /* If first time or username changed or empty username, -+ setup/reset authentication context. */ -+ if ((authctxt->attempt++ == 0) || -+ (strcmp(user, authctxt->user) != 0) || -+ (strcmp(user, "") == 0)) { -+ if (authctxt->user) { -+ free(authctxt->user); -+ authctxt->user = NULL; -+ } -+ authctxt->valid = 0; - authctxt->user = xstrdup(user); -- if (authctxt->pw && strcmp(service, "ssh-connection")==0) { -+ if (strcmp(service, "ssh-connection") != 0) { -+ packet_disconnect("Unsupported service %s", service); -+ } -+#ifdef GSSAPI -+ /* If we're going to set the username based on the -+ GSSAPI context later, then wait until then to -+ verify it. Just put in placeholders for now. */ -+ if ((strcmp(user, "") == 0) && -+ ((strcmp(method, "gssapi") == 0) || -+ (strcmp(method, "gssapi-with-mic") == 0))) { -+ authctxt->pw = fakepw(); -+ } else { -+#endif -+ authctxt->pw = PRIVSEP(getpwnamallow(user)); -+ if (authctxt->pw) { - authctxt->valid = 1; - debug2("input_userauth_request: setting up authctxt for %s", user); - } else { - logit("input_userauth_request: invalid user %s", user); - authctxt->pw = fakepw(); - } -+#ifdef GSSAPI -+ } /* endif for setting username based on GSSAPI context */ -+#endif - #ifdef USE_PAM - if (options.use_pam) - PRIVSEP(start_pam(authctxt)); - #endif - setproctitle("%s%s", authctxt->valid ? user : "unknown", - use_privsep ? " [net]" : ""); -+ if (authctxt->attempt == 1) { - authctxt->service = xstrdup(service); - authctxt->style = style ? xstrdup(style) : NULL; - #ifdef WITH_SELINUX -@@ -270,9 +324,10 @@ - userauth_banner(); - if (auth2_setup_methods_lists(authctxt) != 0) - packet_disconnect("no authentication methods enabled"); -- } else if (strcmp(user, authctxt->user) != 0 || -- strcmp(service, authctxt->service) != 0) { -- packet_disconnect("Change of username or service not allowed: " -+ } -+ } -+ if (strcmp(service, authctxt->service) != 0) { -+ packet_disconnect("Change of service not allowed: " - "(%s,%s) -> (%s,%s)", - authctxt->user, authctxt->service, user, service); - } -diff -Nur openssh-7.2p1.orig/auth2-gss.c openssh-7.2p1/auth2-gss.c ---- openssh-7.2p1.orig/auth2-gss.c 2016-03-02 19:04:36.311961033 +0100 -+++ openssh-7.2p1/auth2-gss.c 2016-03-02 19:05:41.290212928 +0100 -@@ -49,6 +49,7 @@ - - extern ServerOptions options; - -+static void ssh_gssapi_userauth_error(Gssctxt *ctxt); - static int input_gssapi_token(int type, u_int32_t plen, void *ctxt); - static int input_gssapi_mic(int type, u_int32_t plen, void *ctxt); - static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); -@@ -61,8 +62,8 @@ - userauth_gsskeyex(Authctxt *authctxt) - { - int authenticated = 0; -- Buffer b; -- gss_buffer_desc mic, gssbuf; -+ Buffer b, b2; -+ gss_buffer_desc mic, gssbuf, gssbuf2; - u_int len; - - mic.value = packet_get_string(&len); -@@ -76,13 +77,27 @@ - gssbuf.value = buffer_ptr(&b); - gssbuf.length = buffer_len(&b); - -+ /* client may have used empty username to determine target -+ name from GSSAPI context */ -+ ssh_gssapi_buildmic(&b2, "", authctxt->service, "gssapi-keyex"); -+ -+ gssbuf2.value = buffer_ptr(&b2); -+ gssbuf2.length = buffer_len(&b2); -+ - /* gss_kex_context is NULL with privsep, so we can't check it here */ - if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, -- &gssbuf, &mic)))) -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -- authctxt->pw)); -+ &gssbuf, &mic))) || -+ !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, -+ &gssbuf2, &mic)))) { -+ if (authctxt->valid && authctxt->user && authctxt->user[0]) { -+ authenticated = -+ PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 1 /* gssapi-keyex */)); -+ } -+ } - - buffer_free(&b); -+ buffer_free(&b2); - free(mic.value); - - return (authenticated); -@@ -103,7 +118,10 @@ - u_int len; - u_char *doid = NULL; - -- if (!authctxt->valid || authctxt->user == NULL) -+ /* authctxt->valid may be 0 if we haven't yet determined -+ username from gssapi context. */ -+ -+ if (authctxt->user == NULL) - return (0); - - mechs = packet_get_int(); -@@ -168,7 +186,7 @@ - Gssctxt *gssctxt; - gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; - gss_buffer_desc recv_tok; -- OM_uint32 maj_status, min_status, flags; -+ OM_uint32 maj_status, min_status, flags = 0; - u_int len; - - if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) -@@ -186,6 +204,7 @@ - free(recv_tok.value); - - if (GSS_ERROR(maj_status)) { -+ ssh_gssapi_userauth_error(gssctxt); - if (send_tok.length != 0) { - packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); - packet_put_string(send_tok.value, send_tok.length); -@@ -251,6 +270,32 @@ - return 0; - } - -+static void -+gssapi_set_username(Authctxt *authctxt) -+{ -+ char *lname = NULL; -+ -+ if ((authctxt->user == NULL) || (authctxt->user[0] == '\0')) { -+ PRIVSEP(ssh_gssapi_localname(&lname)); -+ if (lname && lname[0] != '\0') { -+ if (authctxt->user) free(authctxt->user); -+ authctxt->user = lname; -+ debug("set username to %s from gssapi context", lname); -+ authctxt->pw = PRIVSEP(getpwnamallow(authctxt->user)); -+ if (authctxt->pw) { -+ authctxt->valid = 1; -+#ifdef USE_PAM -+ if (options.use_pam) -+ PRIVSEP(start_pam(authctxt)); -+#endif -+ } -+ } else { -+ debug("failed to set username from gssapi context"); -+ packet_send_debug("failed to set username from gssapi context"); -+ } -+ } -+} -+ - /* - * This is called when the client thinks we've completed authentication. - * It should only be enabled in the dispatch handler by the function above, -@@ -266,6 +311,8 @@ - if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) - fatal("No authentication or GSSAPI context"); - -+ gssapi_set_username(authctxt); -+ - /* - * We don't need to check the status, because we're only enabled in - * the dispatcher once the exchange is complete -@@ -273,8 +320,13 @@ - - packet_check_eom(); - -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -- authctxt->pw)); -+ /* user should be set if valid but we double-check here */ -+ if (authctxt->valid && authctxt->user && authctxt->user[0]) { -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 0 /* !gssapi-keyex */)); -+ } else { -+ authenticated = 0; -+ } - - authctxt->postponed = 0; - dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); -@@ -316,9 +368,16 @@ - gssbuf.value = buffer_ptr(&b); - gssbuf.length = buffer_len(&b); - -+ gssapi_set_username(authctxt); -+ - if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) -- authenticated = -- PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw)); -+ if (authctxt->valid && authctxt->user && authctxt->user[0]) { -+ authenticated = -+ PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 0 /* !gssapi-keyex */)); -+ } else { -+ authenticated = 0; -+ } - else - logit("GSSAPI MIC check failed"); - -@@ -336,6 +395,23 @@ - return 0; - } - -+static void ssh_gssapi_userauth_error(Gssctxt *ctxt) { -+ char *errstr; -+ OM_uint32 maj,min; -+ -+ errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min)); -+ if (errstr) { -+ packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR); -+ packet_put_int(maj); -+ packet_put_int(min); -+ packet_put_cstring(errstr); -+ packet_put_cstring(""); -+ packet_send(); -+ packet_write_wait(); -+ free(errstr); -+ } -+} -+ - Authmethod method_gsskeyex = { - "gssapi-keyex", - userauth_gsskeyex, -diff -Nur openssh-7.2p1.orig/auth.c openssh-7.2p1/auth.c ---- openssh-7.2p1.orig/auth.c 2016-03-02 19:04:36.376960285 +0100 -+++ openssh-7.2p1/auth.c 2016-03-02 19:05:41.291212916 +0100 -@@ -75,6 +75,9 @@ - #include "ssherr.h" - #include "compat.h" - -+#include "version.h" -+#include "ssh-globus-usage.h" -+ - /* import */ - extern ServerOptions options; - extern int use_privsep; -@@ -299,7 +302,8 @@ - method, - submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, - authctxt->valid ? "" : "invalid user ", -- authctxt->user, -+ (authctxt->user && authctxt->user[0]) ? -+ authctxt->user : "unknown", - get_remote_ipaddr(), - get_remote_port(), - compat20 ? "ssh2" : "ssh1", -@@ -325,6 +329,23 @@ - if (authenticated == 0 && !authctxt->postponed) - audit_event(audit_classify_auth(method)); - #endif -+ if (authenticated) { -+ char *userdn = NULL; -+ char *mech_name = NULL; -+#ifdef GSSAPI -+ ssh_gssapi_get_client_info(&userdn, &mech_name); -+#endif -+ debug("REPORTING (%s) (%s) (%s) (%s) (%s) (%s) (%s)", -+ SSH_RELEASE, SSLeay_version(SSLEAY_VERSION), -+ method, mech_name?mech_name:"NULL", get_remote_ipaddr(), -+ (authctxt->user && authctxt->user[0])? -+ authctxt->user : "unknown", -+ userdn?userdn:"NULL"); -+ ssh_globus_send_usage_metrics(SSH_RELEASE, -+ SSLeay_version(SSLEAY_VERSION), -+ method, mech_name, get_remote_ipaddr(), -+ authctxt->user, userdn); -+ } - } - - -@@ -622,6 +643,10 @@ - #endif - - pw = getpwnam(user); -+#ifdef USE_PAM -+ if (options.use_pam && options.permit_pam_user_change && pw == NULL) -+ pw = sshpam_getpw(user); -+#endif - - #if defined(_AIX) && defined(HAVE_SETAUTHDB) - aix_restoreauthdb(); -@@ -641,7 +666,8 @@ - #endif - if (pw == NULL) { - logit("Invalid user %.100s from %.100s", -- user, get_remote_ipaddr()); -+ (user && user[0]) ? user : "unknown", -+ get_remote_ipaddr()); - #ifdef CUSTOM_FAILED_LOGIN - record_failed_login(user, - get_canonical_hostname(options.use_dns), "ssh"); -diff -Nur openssh-7.2p1.orig/auth-pam.c openssh-7.2p1/auth-pam.c ---- openssh-7.2p1.orig/auth-pam.c 2016-03-02 19:04:36.394960078 +0100 -+++ openssh-7.2p1/auth-pam.c 2016-03-02 19:05:41.292212905 +0100 -@@ -123,6 +123,10 @@ - */ - typedef pthread_t sp_pthread_t; - #else -+#define pthread_create openssh_pthread_create -+#define pthread_exit openssh_pthread_exit -+#define pthread_cancel openssh_pthread_cancel -+#define pthread_join openssh_pthread_join - typedef pid_t sp_pthread_t; - #endif - -@@ -278,6 +282,56 @@ - # define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b))) - #endif - -+struct passwd * -+sshpam_getpw(const char *user) -+{ -+ struct passwd *pw; -+ -+ if ((pw = getpwnam(user)) != NULL) -+ return(pw); -+ -+ debug("PAM: faking passwd struct for user '%.100s'", user); -+ if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) -+ return NULL; -+ pw->pw_name = xstrdup(user); /* XXX leak */ -+ pw->pw_shell = "/bin/true"; -+ pw->pw_gecos = "sshd fake PAM user"; -+ return (pw); -+} -+ -+void -+sshpam_check_userchanged(void) -+{ -+ int sshpam_err; -+ struct passwd *pw; -+ const char *user; -+ -+ debug("sshpam_check_userchanged"); -+ sshpam_err = pam_get_item(sshpam_handle, PAM_USER, -+ (sshpam_const void **)&user); -+ if (sshpam_err != PAM_SUCCESS) -+ fatal("PAM: could not get PAM_USER: %s", -+ pam_strerror(sshpam_handle, sshpam_err)); -+ debug("sshpam_check_userchanged: user was '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ if (strcmp(user, sshpam_authctxt->pw->pw_name) != 0) { -+ debug("PAM: user mapped from '%.100s' to '%.100s'", -+ sshpam_authctxt->pw->pw_name, user); -+ if ((pw = getpwnam(user)) == NULL) -+ fatal("PAM: could not get passwd entry for user " -+ "'%.100s' provided by PAM_USER", user); -+ pwfree(sshpam_authctxt->pw); -+ sshpam_authctxt->pw = pwcopy(pw); -+ sshpam_authctxt->valid = allowed_user(pw); -+ free(sshpam_authctxt->user); -+ sshpam_authctxt->user = xstrdup(user); -+ debug("PAM: user '%.100s' now %svalid", user, -+ sshpam_authctxt->valid ? "" : "in"); -+ } -+ debug("sshpam_check_userchanged: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+} -+ - void - sshpam_password_change_required(int reqd) - { -@@ -300,7 +354,7 @@ - static void - import_environments(Buffer *b) - { -- char *env; -+ char *env, *user; - u_int i, num_env; - int err; - -@@ -310,6 +364,17 @@ - /* Import variables set by do_pam_account */ - sshpam_account_status = buffer_get_int(b); - sshpam_password_change_required(buffer_get_int(b)); -+ if (options.permit_pam_user_change) { -+ user = buffer_get_string(b, NULL); -+ debug("PAM: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ debug("PAM: got username '%.100s' from thread", user); -+ if ((err = pam_set_item(sshpam_handle, PAM_USER, user)) != PAM_SUCCESS) -+ fatal("PAM: failed to set PAM_USER: %s", -+ pam_strerror(sshpam_handle, err)); -+ pwfree(sshpam_authctxt->pw); -+ sshpam_authctxt->pw = pwcopy(sshpam_getpw(user)); -+ } - - /* Import environment from subprocess */ - num_env = buffer_get_int(b); -@@ -476,6 +541,13 @@ - if (sshpam_err != PAM_SUCCESS) - goto auth_fail; - -+ if (options.permit_pam_user_change) { -+ debug("sshpam_thread: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ sshpam_check_userchanged(); -+ debug("sshpam_thread: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ } - if (compat20) { - if (!do_pam_account()) { - sshpam_err = PAM_ACCT_EXPIRED; -@@ -496,6 +568,11 @@ - /* Export variables set by do_pam_account */ - buffer_put_int(&buffer, sshpam_account_status); - buffer_put_int(&buffer, sshpam_authctxt->force_pwchange); -+ if (options.permit_pam_user_change) { -+ debug("sshpam_thread: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ buffer_put_cstring(&buffer, sshpam_authctxt->pw->pw_name); -+ } - - /* Export any environment strings set in child */ - for(i = 0; environ[i] != NULL; i++) -@@ -913,6 +990,18 @@ - debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, - pam_strerror(sshpam_handle, sshpam_err)); - -+ if (options.permit_pam_user_change) { -+ debug("do_pam_account: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ sshpam_check_userchanged(); -+ debug("do_pam_account: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ if (getpwnam(sshpam_authctxt->pw->pw_name) == NULL) -+ fatal("PAM: completed authentication but PAM account invalid"); -+ debug("do_pam_account: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ } -+ - if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { - sshpam_account_status = 0; - return (sshpam_account_status); -@@ -1210,6 +1299,9 @@ - pam_strerror(sshpam_handle, sshpam_err)); - - sshpam_err = pam_authenticate(sshpam_handle, flags); -+ if (options.permit_pam_user_change) { -+ sshpam_check_userchanged(); -+ } - sshpam_password = NULL; - if (sshpam_err == PAM_SUCCESS && authctxt->valid) { - debug("PAM: password authentication accepted for %.100s", -diff -Nur openssh-7.2p1.orig/auth-pam.h openssh-7.2p1/auth-pam.h ---- openssh-7.2p1.orig/auth-pam.h 2016-03-02 19:04:36.265961563 +0100 -+++ openssh-7.2p1/auth-pam.h 2016-03-02 19:05:41.292212905 +0100 -@@ -46,5 +46,6 @@ - void sshpam_cleanup(void); - int sshpam_auth_passwd(Authctxt *, const char *); - int is_pam_session_open(void); -+struct passwd *sshpam_getpw(const char *); - - #endif /* USE_PAM */ -diff -Nur openssh-7.2p1.orig/canohost.c openssh-7.2p1/canohost.c ---- openssh-7.2p1.orig/canohost.c 2016-03-02 19:04:36.333960780 +0100 -+++ openssh-7.2p1/canohost.c 2016-03-02 19:05:41.292212905 +0100 -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include /* for MAXHOSTNAMELEN */ - - #include - #include -@@ -468,3 +469,33 @@ - { - return get_port(1); - } -+ -+void -+resolve_localhost(char **host) -+{ -+ struct hostent *hostinfo; -+ -+ hostinfo = gethostbyname(*host); -+ if (hostinfo == NULL || hostinfo->h_name == NULL) { -+ debug("gethostbyname(%s) failed", *host); -+ return; -+ } -+ if (hostinfo->h_addrtype == AF_INET) { -+ struct in_addr addr; -+ addr = *(struct in_addr *)(hostinfo->h_addr); -+ if (ntohl(addr.s_addr) == INADDR_LOOPBACK) { -+ char buf[MAXHOSTNAMELEN]; -+ if (gethostname(buf, sizeof(buf)) < 0) { -+ debug("gethostname() failed"); -+ return; -+ } -+ hostinfo = gethostbyname(buf); -+ free(*host); -+ if (hostinfo == NULL || hostinfo->h_name == NULL) { -+ *host = xstrdup(buf); -+ } else { -+ *host = xstrdup(hostinfo->h_name); -+ } -+ } -+ } -+} -diff -Nur openssh-7.2p1.orig/canohost.h openssh-7.2p1/canohost.h ---- openssh-7.2p1.orig/canohost.h 2016-03-02 19:04:36.334960769 +0100 -+++ openssh-7.2p1/canohost.h 2016-03-02 19:05:41.292212905 +0100 -@@ -27,4 +27,6 @@ - int get_sock_port(int, int); - void clear_cached_addr(void); - -+void resolve_localhost(char **host); -+ - void ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *); -diff -Nur openssh-7.2p1.orig/configure.ac openssh-7.2p1/configure.ac ---- openssh-7.2p1.orig/configure.ac 2016-03-02 19:04:36.356960515 +0100 -+++ openssh-7.2p1/configure.ac 2016-03-02 19:05:41.293212893 +0100 -@@ -4330,6 +4330,14 @@ - AC_CHECK_HEADER([gssapi_krb5.h], , - [ CPPFLAGS="$oldCPP" ]) - -+ # If we're using some other GSSAPI -+ if test -n "$GSSAPI" ; then -+ AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Kerberos GSI.]) -+ fi -+ -+ if test -z "$GSSAPI"; then -+ GSSAPI="KRB5"; -+ fi - fi - if test ! -z "$need_dash_r" ; then - LDFLAGS="$LDFLAGS -R${KRB5ROOT}/lib" -@@ -4369,6 +4377,50 @@ - AC_SUBST([GSSLIBS]) - AC_SUBST([K5LIBS]) - -+# Check whether the user wants GSI (Globus) support -+gsi="no" -+AC_ARG_WITH(gsi, -+ [ --with-gsi Enable Globus GSI authentication support], -+ [ -+ gsi="$withval" -+ ] -+) -+ -+if test "x$gsi" != "xno" ; then -+ # Globus GSSAPI configuration -+ AC_MSG_CHECKING(for Globus GSI) -+ AC_DEFINE(GSI, 1, [Define if you want GSI/Globus authentication support.]) -+ -+ if test -n "$GSSAPI" ; then -+ AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Globus GSI.]) -+ fi -+ -+ if test -z "$GSSAPI" ; then -+ GSSAPI="GSI" -+ fi -+ -+ LIBS="$LIBS `pkg-config --libs globus-gss-assist globus-gssapi-gsi globus-common`" -+ CPPFLAGS="$CPPFLAGS `pkg-config --cflags globus-gss-assist globus-gssapi-gsi globus-common`" -+ -+ AC_DEFINE(GSSAPI) -+ AC_DEFINE(HAVE_GSSAPI_H) -+ -+ AC_CHECK_FUNCS(globus_gss_assist_map_and_authorize) -+ -+ dnl -+ dnl Check for globus_usage_stats_send -+ dnl -+ AC_SEARCH_LIBS(globus_usage_stats_send, -+ globus_usage, -+ AC_DEFINE([HAVE_GLOBUS_USAGE], 1, [Have Globus Usage])) -+ dnl -+ dnl Check for globus_usage_stats_send_array -+ dnl -+ AC_SEARCH_LIBS(globus_usage_stats_send_array, -+ globus_usage, -+ AC_DEFINE([HAVE_GLOBUS_USAGE_SEND_ARRAY], 1, [Have Globus Usage send_array])) -+fi -+ - # Looking for programs, paths and files - - PRIVSEP_PATH=/var/empty -diff -Nur openssh-7.2p1.orig/gss-genr.c openssh-7.2p1/gss-genr.c ---- openssh-7.2p1.orig/gss-genr.c 2016-03-02 19:04:36.363960435 +0100 -+++ openssh-7.2p1/gss-genr.c 2016-03-02 19:05:41.294212882 +0100 -@@ -40,6 +40,7 @@ - #include "xmalloc.h" - #include "buffer.h" - #include "log.h" -+#include "canohost.h" - #include "ssh2.h" - #include "cipher.h" - #include "key.h" -@@ -368,9 +369,18 @@ - ssh_gssapi_import_name(Gssctxt *ctx, const char *host) - { - gss_buffer_desc gssbuf; -+ char *xhost; - char *val; - -- xasprintf(&val, "host@%s", host); -+ /* Make a copy of the host name, in case it was returned by a -+ * previous call to gethostbyname(). */ -+ xhost = xstrdup(host); -+ -+ /* Make sure we have the FQDN. Some GSSAPI implementations don't do -+ * this for us themselves */ -+ resolve_localhost(&xhost); -+ -+ xasprintf(&val, "host@%s", xhost); - gssbuf.value = val; - gssbuf.length = strlen(gssbuf.value); - -@@ -378,6 +388,7 @@ - &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) - ssh_gssapi_error(ctx); - -+ free(xhost); - free(gssbuf.value); - return (ctx->major); - } -diff -Nur openssh-7.2p1.orig/gss-serv.c openssh-7.2p1/gss-serv.c ---- openssh-7.2p1.orig/gss-serv.c 2016-03-02 19:04:36.363960435 +0100 -+++ openssh-7.2p1/gss-serv.c 2016-03-02 19:05:41.294212882 +0100 -@@ -47,14 +47,17 @@ - #include "servconf.h" - #include "uidswap.h" - -+#include "xmalloc.h" - #include "ssh-gss.h" - #include "monitor_wrap.h" - - extern ServerOptions options; -+extern Authctxt *the_authctxt; - - static ssh_gssapi_client gssapi_client = - { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, -- GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, {NULL, NULL, NULL}, 0, 0}; -+ GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, -+ GSS_C_NO_CONTEXT, 0, 0}; - - ssh_gssapi_mech gssapi_null_mech = - { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; -@@ -62,14 +65,24 @@ - #ifdef KRB5 - extern ssh_gssapi_mech gssapi_kerberos_mech; - #endif -+#ifdef GSI -+extern ssh_gssapi_mech gssapi_gsi_mech; -+#endif - - ssh_gssapi_mech* supported_mechs[]= { - #ifdef KRB5 - &gssapi_kerberos_mech, - #endif -+#ifdef GSI -+ &gssapi_gsi_mech, -+#endif - &gssapi_null_mech, - }; - -+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG -+static int limited = 0; -+#endif -+ - /* - * ssh_gssapi_supported_oids() can cause sandbox violations, so prepare the - * list of supported mechanisms before privsep is set up. -@@ -230,6 +243,10 @@ - (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) { - if (ssh_gssapi_getclient(ctx, &gssapi_client)) - fatal("Couldn't convert client name"); -+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG -+ if (flags && (*flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG)) -+ limited=1; -+#endif - } - - return (status); -@@ -249,6 +266,17 @@ - - tok = ename->value; - -+#ifdef GSI /* GSI gss_export_name() is broken. */ -+ if ((ctx->oid->length == gssapi_gsi_mech.oid.length) && -+ (memcmp(ctx->oid->elements, gssapi_gsi_mech.oid.elements, -+ gssapi_gsi_mech.oid.length) == 0)) { -+ name->length = ename->length; -+ name->value = xmalloc(ename->length+1); -+ memcpy(name->value, ename->value, ename->length); -+ return GSS_S_COMPLETE; -+ } -+#endif -+ - /* - * Check that ename is long enough for all of the fixed length - * header, and that the initial ID bytes are correct -@@ -316,8 +344,11 @@ - return GSS_S_COMPLETE; - } - -- if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, -- ctx->client_creds, ctx->oid, &new_name, -+ /* Call gss_inquire_cred rather than gss_inquire_cred_by_mech -+ because GSI doesn't support the latter. -jbasney */ -+ -+ if ((ctx->major = gss_inquire_cred(&ctx->minor, -+ ctx->client_creds, &new_name, - NULL, NULL, NULL))) { - ssh_gssapi_error(ctx); - return (ctx->major); -@@ -360,9 +391,12 @@ - if (client->mech == NULL) - return GSS_S_FAILURE; - -+ /* Call gss_inquire_cred rather than gss_inquire_cred_by_mech -+ because GSI doesn't support the latter. -jbasney */ -+ - if (ctx->client_creds && -- (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, -- ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { -+ (ctx->major = gss_inquire_cred(&ctx->minor, -+ ctx->client_creds, &client->name, NULL, NULL, NULL))) { - ssh_gssapi_error(ctx); - return (ctx->major); - } -@@ -389,6 +423,10 @@ - /* We can't copy this structure, so we just move the pointer to it */ - client->creds = ctx->client_creds; - ctx->client_creds = GSS_C_NO_CREDENTIAL; -+ -+ /* needed for globus_gss_assist_map_and_authorize() */ -+ client->context = ctx->context; -+ - return (ctx->major); - } - -@@ -396,6 +434,7 @@ - void - ssh_gssapi_cleanup_creds(void) - { -+#ifdef KRB5 - krb5_ccache ccache = NULL; - krb5_error_code problem; - -@@ -411,6 +450,14 @@ - gssapi_client.store.data = NULL; - } - } -+#else -+ if (gssapi_client.store.filename != NULL) { -+ /* Unlink probably isn't sufficient */ -+ debug("removing gssapi cred file\"%s\"", -+ gssapi_client.store.filename); -+ unlink(gssapi_client.store.filename); -+ } -+#endif - } - - /* As user */ -@@ -418,6 +465,11 @@ - ssh_gssapi_storecreds(void) - { - if (gssapi_client.mech && gssapi_client.mech->storecreds) { -+ if (options.gss_creds_path) { -+ gssapi_client.store.filename = -+ expand_authorized_keys(options.gss_creds_path, -+ the_authctxt->pw); -+ } - (*gssapi_client.mech->storecreds)(&gssapi_client); - } else - debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism"); -@@ -441,8 +493,9 @@ - } - - /* Privileged */ -+/* gssapi_keyex arg added for Globus usage */ - int --ssh_gssapi_userok(char *user, struct passwd *pw) -+ssh_gssapi_userok(char *user, struct passwd *pw, int gssapi_keyex) - { - OM_uint32 lmin; - -@@ -451,6 +504,12 @@ - debug("No suitable client data"); - return 0; - } -+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG -+ if (limited && options.gsi_allow_limited_proxy != 1) { -+ debug("limited proxy not acceptable for remote login"); -+ return 0; -+ } -+#endif - if (gssapi_client.mech && gssapi_client.mech->userok) - if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { - gssapi_client.used = 1; -@@ -470,6 +529,24 @@ - return (0); - } - -+/* Priviledged */ -+int -+ssh_gssapi_localname(char **user) -+{ -+ *user = NULL; -+ if (gssapi_client.displayname.length == 0 || -+ gssapi_client.displayname.value == NULL) { -+ debug("No suitable client data"); -+ return(0); -+ } -+ if (gssapi_client.mech && gssapi_client.mech->localname) { -+ return((*gssapi_client.mech->localname)(&gssapi_client,user)); -+ } else { -+ debug("Unknown client authentication type"); -+ } -+ return(0); -+} -+ - /* These bits are only used for rekeying. The unpriviledged child is running - * as the user, the monitor is root. - * -@@ -496,6 +573,7 @@ - pam_handle_t *pamh = NULL; - struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; - char *envstr; -+ char **p; char **pw; - #endif - - if (gssapi_client.store.filename == NULL && -@@ -525,6 +603,18 @@ - if (ret) - return; - -+ /* Put ssh pam stack env variables in this new pam stack env -+ * Using pam-pkinit, KRB5CCNAME is set during do_pam_session -+ * this addition enables pam-pkinit to access KRB5CCNAME if used -+ * in sshd-rekey stack too -+ */ -+ pw = p = fetch_pam_environment(); -+ while ( *pw != NULL ) { -+ pam_putenv(pamh, *pw); -+ pw++; -+ } -+ free_pam_environment(p); -+ - xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, - gssapi_client.store.envval); - -@@ -556,4 +646,13 @@ - return ok; - } - -+/* added for Globus usage */ -+void -+ssh_gssapi_get_client_info(char **userdn, char **mech) { -+ *userdn = gssapi_client.displayname.value; -+ -+ if (gssapi_client.mech) -+ *mech = gssapi_client.mech->name; -+} -+ - #endif -diff -Nur openssh-7.2p1.orig/gss-serv-gsi.c openssh-7.2p1/gss-serv-gsi.c ---- openssh-7.2p1.orig/gss-serv-gsi.c 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-7.2p1/gss-serv-gsi.c 2016-03-02 19:05:41.294212882 +0100 -@@ -0,0 +1,239 @@ -+/* -+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+#include "includes.h" -+ -+#ifdef GSSAPI -+#ifdef GSI -+ -+#include -+ -+#include -+#include -+ -+#include "xmalloc.h" -+#include "key.h" -+#include "hostfile.h" -+#include "auth.h" -+#include "log.h" -+#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ -+#include "servconf.h" -+ -+#include "buffer.h" -+#include "ssh-gss.h" -+ -+extern ServerOptions options; -+ -+#include -+ -+static int ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name); -+static int ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user); -+static void ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client); -+static int ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store, -+ ssh_gssapi_client *client); -+ -+ssh_gssapi_mech gssapi_gsi_mech = { -+ "dZuIebMjgUqaxvbF7hDbAw==", -+ "GSI", -+ {9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"}, -+ NULL, -+ &ssh_gssapi_gsi_userok, -+ &ssh_gssapi_gsi_localname, -+ &ssh_gssapi_gsi_storecreds, -+ &ssh_gssapi_gsi_updatecreds -+}; -+ -+/* -+ * Check if this user is OK to login under GSI. User has been authenticated -+ * as identity in global 'client_name.value' and is trying to log in as passed -+ * username in 'name'. -+ * -+ * Returns non-zero if user is authorized, 0 otherwise. -+ */ -+static int -+ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name) -+{ -+ int authorized = 0; -+ globus_result_t res; -+#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE -+ char lname[256] = ""; -+#endif -+ -+#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE -+ if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) { -+ return 0; -+ } -+#endif -+ -+/* use new globus_gss_assist_map_and_authorize() interface if available */ -+#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE -+ debug("calling globus_gss_assist_map_and_authorize()"); -+ if (GLOBUS_SUCCESS != -+ (res = globus_gss_assist_map_and_authorize(client->context, "ssh", -+ name, lname, 256))) { -+ debug("%s", globus_error_print_chain(globus_error_get(res))); -+ } else if (lname[0] && strcmp(name, lname) != 0) { -+ debug("GSI user maps to %s, not %s", lname, name); -+ } else { -+ authorized = 1; -+ } -+#else -+ debug("calling globus_gss_assist_userok()"); -+ if (GLOBUS_SUCCESS != -+ (res = (globus_gss_assist_userok(client->displayname.value, -+ name)))) { -+ debug("%s", globus_error_print_chain(globus_error_get(res))); -+ } else { -+ authorized = 1; -+ } -+#endif -+ -+ logit("GSI user %s is%s authorized as target user %s", -+ (char *) client->displayname.value, (authorized ? "" : " not"), name); -+ -+ return authorized; -+} -+ -+/* -+ * Return the local username associated with the GSI credentials. -+ */ -+int -+ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user) -+{ -+ globus_result_t res; -+#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE -+ char lname[256] = ""; -+#endif -+ -+#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE -+ if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) { -+ return 0; -+ } -+#endif -+ -+/* use new globus_gss_assist_map_and_authorize() interface if available */ -+#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE -+ debug("calling globus_gss_assist_map_and_authorize()"); -+ if (GLOBUS_SUCCESS != -+ (res = globus_gss_assist_map_and_authorize(client->context, "ssh", -+ NULL, lname, 256))) { -+ debug("%s", globus_error_print_chain(globus_error_get(res))); -+ logit("failed to map GSI user %s", (char *)client->displayname.value); -+ return 0; -+ } -+ *user = strdup(lname); -+#else -+ debug("calling globus_gss_assist_gridmap()"); -+ if (GLOBUS_SUCCESS != -+ (res = globus_gss_assist_gridmap(client->displayname.value, user))) { -+ debug("%s", globus_error_print_chain(globus_error_get(res))); -+ logit("failed to map GSI user %s", (char *)client->displayname.value); -+ return 0; -+ } -+#endif -+ -+ logit("GSI user %s mapped to target user %s", -+ (char *) client->displayname.value, *user); -+ -+ return 1; -+} -+ -+/* -+ * Export GSI credentials to disk. -+ */ -+static void -+ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client) -+{ -+ OM_uint32 major_status; -+ OM_uint32 minor_status; -+ gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER; -+ char * p; -+ -+ if (!client || !client->creds) { -+ return; -+ } -+ -+ major_status = gss_export_cred(&minor_status, -+ client->creds, -+ GSS_C_NO_OID, -+ 1, -+ &export_cred); -+ if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) { -+ Gssctxt *ctx; -+ ssh_gssapi_build_ctx(&ctx); -+ ctx->major = major_status; -+ ctx->minor = minor_status; -+ ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech.oid); -+ ssh_gssapi_error(ctx); -+ ssh_gssapi_delete_ctx(&ctx); -+ return; -+ } -+ -+ p = strchr((char *) export_cred.value, '='); -+ if (p == NULL) { -+ logit("Failed to parse exported credentials string '%.100s'", -+ (char *)export_cred.value); -+ gss_release_buffer(&minor_status, &export_cred); -+ return; -+ } -+ *p++ = '\0'; -+ if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) { -+ client->store.envvar = strdup("X509_USER_PROXY"); -+ } else { -+ client->store.envvar = strdup((char *)export_cred.value); -+ } -+ if (access(p, R_OK) == 0) { -+ if (client->store.filename) { -+ if (rename(p, client->store.filename) < 0) { -+ logit("Failed to rename %s to %s: %s", p, -+ client->store.filename, strerror(errno)); -+ free(client->store.filename); -+ client->store.filename = strdup(p); -+ } else { -+ p = client->store.filename; -+ } -+ } else { -+ client->store.filename = strdup(p); -+ } -+ } -+ client->store.envval = strdup(p); -+#ifdef USE_PAM -+ if (options.use_pam) -+ do_pam_putenv(client->store.envvar, client->store.envval); -+#endif -+ gss_release_buffer(&minor_status, &export_cred); -+} -+ -+/* -+ * Export updated GSI credentials to disk. -+ */ -+static int -+ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store,ssh_gssapi_client *client) -+{ -+ ssh_gssapi_gsi_storecreds(client); -+ return 1; -+} -+ -+#endif /* GSI */ -+#endif /* GSSAPI */ -diff -Nur openssh-7.2p1.orig/gss-serv-krb5.c openssh-7.2p1/gss-serv-krb5.c ---- openssh-7.2p1.orig/gss-serv-krb5.c 2016-03-02 19:04:36.348960607 +0100 -+++ openssh-7.2p1/gss-serv-krb5.c 2016-03-02 19:05:41.295212870 +0100 -@@ -359,6 +359,34 @@ - return found_principal; - } - -+/* Retrieve the local username associated with a set of Kerberos -+ * credentials. Hopefully we can use this for the 'empty' username -+ * logins discussed in the draft */ -+static int -+ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user) { -+ krb5_principal princ; -+ int retval; -+ -+ if (ssh_gssapi_krb5_init() == 0) -+ return 0; -+ -+ if ((retval=krb5_parse_name(krb_context, client->displayname.value, -+ &princ))) { -+ logit("krb5_parse_name(): %.100s", -+ krb5_get_err_text(krb_context,retval)); -+ return 0; -+ } -+ -+ /* We've got to return a malloc'd string */ -+ *user = (char *)xmalloc(256); -+ if (krb5_aname_to_localname(krb_context, princ, 256, *user)) { -+ free(*user); -+ *user = NULL; -+ return(0); -+ } -+ -+ return(1); -+} - - /* This writes out any forwarded credentials from the structure populated - * during userauth. Called after we have setuid to the user */ -@@ -463,7 +491,7 @@ - return; - } - --int -+static int - ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, - ssh_gssapi_client *client) - { -@@ -534,7 +562,7 @@ - {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}, - NULL, - &ssh_gssapi_krb5_userok, -- NULL, -+ &ssh_gssapi_krb5_localname, - &ssh_gssapi_krb5_storecreds, - &ssh_gssapi_krb5_updatecreds - }; -diff -Nur openssh-7.2p1.orig/kexgsss.c openssh-7.2p1/kexgsss.c ---- openssh-7.2p1.orig/kexgsss.c 2016-03-02 19:04:36.314960999 +0100 -+++ openssh-7.2p1/kexgsss.c 2016-03-02 19:05:41.295212870 +0100 -@@ -47,6 +47,7 @@ - #include "ssh-gss.h" - #include "digest.h" - -+static void kex_gss_send_error(Gssctxt *ctxt); - extern ServerOptions options; - - int -@@ -94,8 +95,10 @@ - - debug2("%s: Acquiring credentials", __func__); - -- if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) { -+ kex_gss_send_error(ctxt); - fatal("Unable to acquire credentials for the server"); -+ } - - switch (ssh->kex->kex_type) { - case KEX_GSS_GRP1_SHA1: -@@ -181,12 +184,13 @@ - } while (maj_status & GSS_S_CONTINUE_NEEDED); - - if (GSS_ERROR(maj_status)) { -+ kex_gss_send_error(ctxt); - if (send_tok.length > 0) { - packet_start(SSH2_MSG_KEXGSS_CONTINUE); - packet_put_string(send_tok.value, send_tok.length); - packet_send(); - } -- fatal("accept_ctx died"); -+ packet_disconnect("GSSAPI Key Exchange handshake failed"); - } - - if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -@@ -292,4 +296,23 @@ - ssh_gssapi_rekey_creds(); - return 0; - } -+ -+static void -+kex_gss_send_error(Gssctxt *ctxt) { -+ char *errstr; -+ OM_uint32 maj,min; -+ -+ errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min)); -+ if (errstr) { -+ packet_start(SSH2_MSG_KEXGSS_ERROR); -+ packet_put_int(maj); -+ packet_put_int(min); -+ packet_put_cstring(errstr); -+ packet_put_cstring(""); -+ packet_send(); -+ packet_write_wait(); -+ /* XXX - We should probably log the error locally here */ -+ free(errstr); -+ } -+} - #endif /* GSSAPI */ -diff -Nur openssh-7.2p1.orig/LICENSE.globus_usage openssh-7.2p1/LICENSE.globus_usage ---- openssh-7.2p1.orig/LICENSE.globus_usage 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-7.2p1/LICENSE.globus_usage 2016-03-02 19:05:41.295212870 +0100 -@@ -0,0 +1,18 @@ -+/* -+ * Portions of the Usage Metrics suport code are derived from the -+ * Globus project's GridFTP subject to the following license. -+ * -+ * Copyright 2010 University of Chicago -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -diff -Nur openssh-7.2p1.orig/Makefile.in openssh-7.2p1/Makefile.in ---- openssh-7.2p1.orig/Makefile.in 2016-03-02 19:04:36.389960135 +0100 -+++ openssh-7.2p1/Makefile.in 2016-03-02 19:09:08.722825330 +0100 -@@ -113,8 +113,10 @@ - auth2-none.o auth2-passwd.o auth2-pubkey.o \ - monitor_mm.o monitor.o monitor_wrap.o auth-krb5.o \ - auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ -+ gss-serv-gsi.o \ - loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ - sftp-server.o sftp-common.o \ -+ ssh-globus-usage.o \ - sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ - sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \ - sandbox-solaris.o -diff -Nur openssh-7.2p1.orig/misc.c openssh-7.2p1/misc.c ---- openssh-7.2p1.orig/misc.c 2016-03-02 19:04:36.347960619 +0100 -+++ openssh-7.2p1/misc.c 2016-03-02 19:05:41.296212859 +0100 -@@ -161,11 +161,14 @@ - #define WHITESPACE " \t\r\n" - #define QUOTE "\"" - -+/* Characters considered as quotations. */ -+#define QUOTES "'\"" -+ - /* return next token in configuration line */ - char * - strdelim(char **s) - { -- char *old; -+ char *old, *p, *q; - int wspace = 0; - - if (*s == NULL) -@@ -173,6 +176,21 @@ - - old = *s; - -+ if ((q=strchr(QUOTES, (int) *old)) && *q) -+ { -+ /* find next quote character, point old to start of quoted -+ * string */ -+ for (p = ++old; *p && *p != *q; p++) -+ ; -+ -+ /* find start of next token */ -+ *s = (*p) ? p + strspn(p + 1, WHITESPACE) + 1 : NULL; -+ -+ /* terminate 'old' token */ -+ *p = '\0'; -+ return (old); -+ } -+ - *s = strpbrk(*s, WHITESPACE QUOTE "="); - if (*s == NULL) - return (old); -@@ -228,6 +246,20 @@ - return copy; - } - -+void -+pwfree(struct passwd *pw) -+{ -+ free(pw->pw_name); -+ free(pw->pw_passwd); -+ free(pw->pw_gecos); -+#ifdef HAVE_PW_CLASS_IN_PASSWD -+ free(pw->pw_class); -+#endif -+ free(pw->pw_dir); -+ free(pw->pw_shell); -+ free(pw); -+} -+ - /* - * Convert ASCII string to TCP/IP port number. - * Port must be >=0 and <=65535. -diff -Nur openssh-7.2p1.orig/misc.h openssh-7.2p1/misc.h ---- openssh-7.2p1.orig/misc.h 2016-03-02 19:04:36.335960757 +0100 -+++ openssh-7.2p1/misc.h 2016-03-02 19:05:41.296212859 +0100 -@@ -61,6 +61,7 @@ - void sock_set_v6only(int); - - struct passwd *pwcopy(struct passwd *); -+void pwfree(struct passwd *); - const char *ssh_gai_strerror(int); - - typedef struct arglist arglist; -diff -Nur openssh-7.2p1.orig/monitor.c openssh-7.2p1/monitor.c ---- openssh-7.2p1.orig/monitor.c 2016-03-02 19:04:36.396960055 +0100 -+++ openssh-7.2p1/monitor.c 2016-03-02 19:05:41.297212847 +0100 -@@ -163,6 +163,9 @@ - int mm_answer_gss_userok(int, Buffer *); - int mm_answer_gss_checkmic(int, Buffer *); - int mm_answer_gss_sign(int, Buffer *); -+int mm_answer_gss_error(int, Buffer *); -+int mm_answer_gss_indicate_mechs(int, Buffer *); -+int mm_answer_gss_localname(int, Buffer *); - int mm_answer_gss_updatecreds(int, Buffer *); - #endif - -@@ -216,7 +219,7 @@ - {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, - #endif - {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, -- {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, -+ {MONITOR_REQ_PWNAM, MON_AUTH, mm_answer_pwnamallow}, - {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, - #ifdef WITH_SELINUX - {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole}, -@@ -224,7 +227,7 @@ - {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, - {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, - #ifdef USE_PAM -- {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, -+ {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start}, - {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, - {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx}, - {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query}, -@@ -254,6 +257,9 @@ - {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, - {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, - {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, -+ {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error}, -+ {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs}, -+ {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname}, - #endif - {0, 0, NULL} - }; -@@ -263,6 +269,8 @@ - {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, - {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, - {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, -+ {MONITOR_REQ_GSSERR, 0, mm_answer_gss_error}, -+ {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs}, - {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, - #endif - #ifdef WITH_OPENSSL -@@ -303,7 +311,7 @@ - {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, - #endif - #ifdef USE_PAM -- {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, -+ {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start}, - {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, - {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx}, - {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query}, -@@ -398,6 +406,8 @@ - #ifdef GSSAPI - /* and for the GSSAPI key exchange */ - monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1); -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1); - #endif - } else { - mon_dispatch = mon_dispatch_proto15; -@@ -512,6 +522,8 @@ - #ifdef GSSAPI - /* and for the GSSAPI key exchange */ - monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1); -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1); - #endif - } else { - mon_dispatch = mon_dispatch_postauth15; -@@ -840,14 +852,17 @@ - - debug3("%s", __func__); - -- if (authctxt->attempt++ != 0) -- fatal("%s: multiple attempts for getpwnam", __func__); -- - username = buffer_get_string(m, NULL); - - pwent = getpwnamallow(username); - -+ if (authctxt->user) free(authctxt->user); - authctxt->user = xstrdup(username); -+#ifdef USE_PAM -+ if (options.permit_pam_user_change) -+ setproctitle("%s [priv]", pwent ? "[pam]" : "unknown"); -+ else -+#endif - setproctitle("%s [priv]", pwent ? username : "unknown"); - free(username); - -@@ -2222,12 +2237,15 @@ - mm_answer_gss_userok(int sock, Buffer *m) - { - int authenticated; -+ int gssapi_keyex; - - if (!options.gss_authentication && !options.gss_keyex) - fatal("In GSSAPI monitor when GSSAPI is disabled"); - -+ gssapi_keyex = buffer_get_int(m); -+ - authenticated = authctxt->valid && -- ssh_gssapi_userok(authctxt->user, authctxt->pw); -+ ssh_gssapi_userok(authctxt->user, authctxt->pw, gssapi_keyex); - - buffer_clear(m); - buffer_put_int(m, authenticated); -@@ -2235,12 +2253,77 @@ - debug3("%s: sending result %d", __func__, authenticated); - mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m); - -- auth_method = "gssapi-with-mic"; -+ if (gssapi_keyex) -+ auth_method = "gssapi-keyex"; -+ else -+ auth_method = "gssapi-with-mic"; - - /* Monitor loop will terminate if authenticated */ - return (authenticated); - } - -+int -+mm_answer_gss_error(int socket, Buffer *m) { -+ OM_uint32 major, minor; -+ char *msg; -+ -+ msg=ssh_gssapi_last_error(gsscontext, &major, &minor); -+ buffer_clear(m); -+ buffer_put_int(m, major); -+ buffer_put_int(m, minor); -+ buffer_put_cstring(m, msg); -+ -+ mm_request_send(socket, MONITOR_ANS_GSSERR, m); -+ -+ free(msg); -+ -+ return(0); -+} -+ -+int -+mm_answer_gss_indicate_mechs(int socket, Buffer *m) { -+ OM_uint32 major, minor; -+ gss_OID_set mech_set; -+ size_t i; -+ -+ major=gss_indicate_mechs(&minor, &mech_set); -+ -+ buffer_clear(m); -+ buffer_put_int(m, major); -+ buffer_put_int(m, mech_set->count); -+ for (i = 0; i < mech_set->count; i++) { -+ buffer_put_string(m, mech_set->elements[i].elements, -+ mech_set->elements[i].length); -+ } -+ -+ gss_release_oid_set(&minor, &mech_set); -+ -+ mm_request_send(socket, MONITOR_ANS_GSSMECHS, m); -+ -+ return(0); -+} -+ -+int -+mm_answer_gss_localname(int socket, Buffer *m) { -+ char *name; -+ -+ ssh_gssapi_localname(&name); -+ -+ buffer_clear(m); -+ if (name) { -+ buffer_put_cstring(m, name); -+ debug3("%s: sending result %s", __func__, name); -+ free(name); -+ } else { -+ buffer_put_cstring(m, ""); -+ debug3("%s: sending result \"\"", __func__); -+ } -+ -+ mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m); -+ -+ return(0); -+} -+ - int - mm_answer_gss_sign(int socket, Buffer *m) - { -diff -Nur openssh-7.2p1.orig/monitor.h openssh-7.2p1/monitor.h ---- openssh-7.2p1.orig/monitor.h 2016-03-02 19:04:36.379960251 +0100 -+++ openssh-7.2p1/monitor.h 2016-03-02 19:05:41.298212836 +0100 -@@ -75,8 +75,10 @@ - MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119, - MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121, - MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123, -- MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124 -- -+ MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, -+ MONITOR_REQ_GSSMECHS = 200, MONITOR_ANS_GSSMECHS = 201, -+ MONITOR_REQ_GSSLOCALNAME = 202, MONITOR_ANS_GSSLOCALNAME = 203, -+ MONITOR_REQ_GSSERR = 204, MONITOR_ANS_GSSERR = 205 - }; - - struct mm_master; -diff -Nur openssh-7.2p1.orig/monitor_wrap.c openssh-7.2p1/monitor_wrap.c ---- openssh-7.2p1.orig/monitor_wrap.c 2016-03-02 19:04:36.396960055 +0100 -+++ openssh-7.2p1/monitor_wrap.c 2016-03-02 19:05:41.298212836 +0100 -@@ -1121,12 +1121,13 @@ - } - - int --mm_ssh_gssapi_userok(char *user, struct passwd *pw) -+mm_ssh_gssapi_userok(char *user, struct passwd *pw, int gssapi_keyex) - { - Buffer m; - int authenticated = 0; - - buffer_init(&m); -+ buffer_put_int(&m, gssapi_keyex); - - mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m); - mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK, -@@ -1139,6 +1140,83 @@ - return (authenticated); - } - -+char * -+mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) { -+ Buffer m; -+ OM_uint32 maj,min; -+ char *errstr; -+ -+ buffer_init(&m); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSERR, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSERR, &m); -+ -+ maj = buffer_get_int(&m); -+ min = buffer_get_int(&m); -+ -+ if (major) *major=maj; -+ if (minor) *minor=min; -+ -+ errstr=buffer_get_string(&m,NULL); -+ -+ buffer_free(&m); -+ -+ return(errstr); -+} -+ -+OM_uint32 -+mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set) -+{ -+ Buffer m; -+ OM_uint32 major,minor; -+ int count; -+ gss_OID_desc oid; -+ u_int length; -+ -+ buffer_init(&m); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS, -+ &m); -+ major=buffer_get_int(&m); -+ count=buffer_get_int(&m); -+ -+ gss_create_empty_oid_set(&minor,mech_set); -+ while(count-->0) { -+ oid.elements=buffer_get_string(&m,&length); -+ oid.length=length; -+ gss_add_oid_set_member(&minor,&oid,mech_set); -+ } -+ -+ buffer_free(&m); -+ -+ return(major); -+} -+ -+int -+mm_ssh_gssapi_localname(char **lname) -+{ -+ Buffer m; -+ -+ buffer_init(&m); -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m); -+ -+ debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME, -+ &m); -+ -+ *lname = buffer_get_string(&m, NULL); -+ -+ buffer_free(&m); -+ if (lname[0] == '\0') { -+ debug3("%s: gssapi identity mapping failed", __func__); -+ } else { -+ debug3("%s: gssapi identity mapped to %s", __func__, *lname); -+ } -+ -+ return(0); -+} -+ - OM_uint32 - mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) - { -diff -Nur openssh-7.2p1.orig/monitor_wrap.h openssh-7.2p1/monitor_wrap.h ---- openssh-7.2p1.orig/monitor_wrap.h 2016-03-02 19:04:36.385960182 +0100 -+++ openssh-7.2p1/monitor_wrap.h 2016-03-02 19:05:41.298212836 +0100 -@@ -62,9 +62,13 @@ - OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); - OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, - gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); --int mm_ssh_gssapi_userok(char *user, struct passwd *); -+int mm_ssh_gssapi_userok(char *user, struct passwd *, int gssapi_keyex); - OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); - OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); -+int mm_ssh_gssapi_localname(char **user); -+OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status, -+ gss_OID_set *mech_set); -+char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min); - int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *); - #endif - -diff -Nur openssh-7.2p1.orig/readconf.c openssh-7.2p1/readconf.c ---- openssh-7.2p1.orig/readconf.c 2016-03-02 19:04:36.390960124 +0100 -+++ openssh-7.2p1/readconf.c 2016-03-02 19:05:41.299212824 +0100 -@@ -1830,13 +1830,13 @@ - if (options->challenge_response_authentication == -1) - options->challenge_response_authentication = 1; - if (options->gss_authentication == -1) -- options->gss_authentication = 0; -+ options->gss_authentication = 1; - if (options->gss_keyex == -1) -- options->gss_keyex = 0; -+ options->gss_keyex = 1; - if (options->gss_deleg_creds == -1) -- options->gss_deleg_creds = 0; -+ options->gss_deleg_creds = 1; - if (options->gss_trust_dns == -1) -- options->gss_trust_dns = 0; -+ options->gss_trust_dns = 1; - if (options->gss_renewal_rekey == -1) - options->gss_renewal_rekey = 0; - #ifdef GSSAPI -diff -Nur openssh-7.2p1.orig/readconf.h openssh-7.2p1/readconf.h ---- openssh-7.2p1.orig/readconf.h 2016-03-02 19:04:36.370960354 +0100 -+++ openssh-7.2p1/readconf.h 2016-03-02 19:05:41.299212824 +0100 -@@ -86,6 +86,8 @@ - char *host_key_alias; /* hostname alias for .ssh/known_hosts */ - char *proxy_command; /* Proxy command for connecting the host. */ - char *user; /* User to log in as. */ -+ int implicit; /* Login user was not specified. -+ Server may choose based on authctxt. */ - int escape_char; /* Escape character; -2 = none */ - - u_int num_system_hostfiles; /* Paths for /etc/ssh/ssh_known_hosts */ -diff -Nur openssh-7.2p1.orig/servconf.c openssh-7.2p1/servconf.c ---- openssh-7.2p1.orig/servconf.c 2016-03-02 19:04:36.397960043 +0100 -+++ openssh-7.2p1/servconf.c 2016-03-02 19:05:41.300212813 +0100 -@@ -75,6 +75,7 @@ - - /* Portable-specific options */ - options->use_pam = -1; -+ options->permit_pam_user_change = -1; - - /* Standard Options */ - options->num_ports = 0; -@@ -118,9 +119,11 @@ - options->kerberos_ticket_cleanup = -1; - options->kerberos_get_afs_token = -1; - options->gss_authentication=-1; -+ options->gss_deleg_creds = -1; - options->gss_keyex = -1; - options->gss_cleanup_creds = -1; - options->gss_strict_acceptor = -1; -+ options->gsi_allow_limited_proxy = -1; - options->gss_store_rekey = -1; - options->gss_kex_algorithms = NULL; - options->password_authentication = -1; -@@ -165,6 +168,8 @@ - options->chroot_directory = NULL; - options->authorized_keys_command = NULL; - options->authorized_keys_command_user = NULL; -+ options->disable_usage_stats = 0; -+ options->usage_stats_targets = NULL; - options->revoked_keys_file = NULL; - options->trusted_user_ca_keys = NULL; - options->authorized_principals_file = NULL; -@@ -210,6 +215,8 @@ - /* Portable-specific options */ - if (options->use_pam == -1) - options->use_pam = 0; -+ if (options->permit_pam_user_change == -1) -+ options->permit_pam_user_change = 0; - - /* Standard Options */ - if (options->protocol == SSH_PROTO_UNKNOWN) -@@ -296,13 +303,17 @@ - if (options->kerberos_get_afs_token == -1) - options->kerberos_get_afs_token = 0; - if (options->gss_authentication == -1) -- options->gss_authentication = 0; -+ options->gss_authentication = 1; -+ if (options->gss_deleg_creds == -1) -+ options->gss_deleg_creds = 1; - if (options->gss_keyex == -1) -- options->gss_keyex = 0; -+ options->gss_keyex = 1; - if (options->gss_cleanup_creds == -1) - options->gss_cleanup_creds = 1; - if (options->gss_strict_acceptor == -1) -- options->gss_strict_acceptor = 0; -+ options->gss_strict_acceptor = 1; -+ if (options->gsi_allow_limited_proxy == -1) -+ options->gsi_allow_limited_proxy = 0; - if (options->gss_store_rekey == -1) - options->gss_store_rekey = 0; - #ifdef GSSAPI -@@ -420,7 +431,7 @@ - typedef enum { - sBadOption, /* == unknown option */ - /* Portable-specific options */ -- sUsePAM, -+ sUsePAM, sPermitPAMUserChange, - /* Standard Options */ - sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, - sKeyRegenerationTime, sPermitRootLogin, sLogFacility, sLogLevel, -@@ -442,10 +453,14 @@ - sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes, - sHostKeyAlgorithms, - sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, -+ sGssDelegateCreds, -+ sGssCredsPath, -+ sGsiAllowLimitedProxy, - sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, - sGssKeyEx, sGssStoreRekey, sGssKexAlgorithms, sAcceptEnv, sPermitTunnel, - sMatch, sPermitOpen, sForceCommand, sChrootDirectory, - sUsePrivilegeSeparation, sAllowAgentForwarding, -+ sDisUsageStats, sUsageStatsTarg, - sHostCertificate, - sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, - sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser, -@@ -470,8 +485,10 @@ - /* Portable-specific options */ - #ifdef USE_PAM - { "usepam", sUsePAM, SSHCFG_GLOBAL }, -+ { "permitpamuserchange", sPermitPAMUserChange, SSHCFG_GLOBAL }, - #else - { "usepam", sUnsupported, SSHCFG_GLOBAL }, -+ { "permitpamuserchange", sUnsupported, SSHCFG_GLOBAL }, - #endif - { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL }, - /* Standard Options */ -@@ -517,7 +534,14 @@ - { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, - #ifdef GSSAPI - { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, -+ { "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_ALL }, - { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, -+ { "gssapicredentialspath", sGssCredsPath, SSHCFG_GLOBAL }, -+#ifdef GSI -+ { "gsiallowlimitedproxy", sGsiAllowLimitedProxy, SSHCFG_GLOBAL }, -+#else -+ { "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL }, -+#endif - { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, - { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, - { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, -@@ -525,7 +549,10 @@ - { "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL }, - #else - { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, -+ { "gssapidelegatecredentials", sUnsupported, SSHCFG_ALL }, - { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapicredentialspath", sUnsupported, SSHCFG_GLOBAL }, -+ { "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, - { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, -@@ -593,6 +620,8 @@ - { "permitopen", sPermitOpen, SSHCFG_ALL }, - { "forcecommand", sForceCommand, SSHCFG_ALL }, - { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, -+ { "disableusagestats", sDisUsageStats, SSHCFG_GLOBAL}, -+ { "usagestatstargets", sUsageStatsTarg, SSHCFG_GLOBAL}, - { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, - { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, - { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, -@@ -1048,6 +1077,10 @@ - intptr = &options->use_pam; - goto parse_flag; - -+ case sPermitPAMUserChange: -+ intptr = &options->permit_pam_user_change; -+ goto parse_flag; -+ - /* Standard Options */ - case sBadOption: - return -1; -@@ -1279,6 +1312,10 @@ - intptr = &options->gss_authentication; - goto parse_flag; - -+ case sGssDelegateCreds: -+ intptr = &options->gss_deleg_creds; -+ goto parse_flag; -+ - case sGssKeyEx: - intptr = &options->gss_keyex; - goto parse_flag; -@@ -1287,6 +1324,10 @@ - intptr = &options->gss_cleanup_creds; - goto parse_flag; - -+ case sGssCredsPath: -+ charptr = &options->gss_creds_path; -+ goto parse_filename; -+ - case sGssStrictAcceptor: - intptr = &options->gss_strict_acceptor; - goto parse_flag; -@@ -1307,6 +1348,12 @@ - options->gss_kex_algorithms = xstrdup(arg); - break; - -+#ifdef GSI -+ case sGsiAllowLimitedProxy: -+ intptr = &options->gsi_allow_limited_proxy; -+ goto parse_flag; -+#endif -+ - case sPasswordAuthentication: - intptr = &options->password_authentication; - goto parse_flag; -@@ -1777,6 +1824,35 @@ - *charptr = xstrdup(arg); - break; - -+ case sDisUsageStats: -+ arg = strdelim(&cp); -+ if (!arg || *arg == '\0') -+ fatal("%s line %d: missing value.", -+ filename, linenum); -+ if (!strcasecmp(arg, "true") || -+ !strcasecmp(arg, "enabled") || -+ !strcasecmp(arg, "yes") || -+ !strcasecmp(arg, "on") || -+ !strcasecmp(arg, "1")) -+ options->disable_usage_stats = 1; -+ else if (!strcasecmp(arg, "false") || -+ !strcasecmp(arg, "disabled") || -+ !strcasecmp(arg, "no") || -+ !strcasecmp(arg, "off") || -+ !strcasecmp(arg, "0")) -+ options->disable_usage_stats = 0; -+ else -+ fatal("Incorrect value for disable_usage_stats"); -+ break; -+ -+ case sUsageStatsTarg: -+ arg = strdelim(&cp); -+ if (!arg || *arg == '\0') -+ fatal("%s line %d: missing value.", -+ filename, linenum); -+ options->usage_stats_targets = xstrdup(arg); -+ break; -+ - case sTrustedUserCAKeys: - charptr = &options->trusted_user_ca_keys; - goto parse_filename; -@@ -2053,6 +2129,7 @@ - - M_CP_INTOPT(password_authentication); - M_CP_INTOPT(gss_authentication); -+ M_CP_INTOPT(gss_deleg_creds); - M_CP_INTOPT(rsa_authentication); - M_CP_INTOPT(pubkey_authentication); - M_CP_INTOPT(kerberos_authentication); -diff -Nur openssh-7.2p1.orig/servconf.h openssh-7.2p1/servconf.h ---- openssh-7.2p1.orig/servconf.h 2016-03-02 19:04:36.366960400 +0100 -+++ openssh-7.2p1/servconf.h 2016-03-02 19:05:41.300212813 +0100 -@@ -117,9 +117,12 @@ - * file on logout. */ - int kerberos_get_afs_token; /* If true, try to get AFS token if - * authenticated with Kerberos. */ -+ int gsi_allow_limited_proxy; /* If true, accept limited proxies */ - int gss_authentication; /* If true, permit GSSAPI authentication */ -+ int gss_deleg_creds; /* If true, store delegated GSSAPI credentials*/ - int gss_keyex; /* If true, permit GSSAPI key exchange */ - int gss_cleanup_creds; /* If true, destroy cred cache on logout */ -+ char *gss_creds_path; /* Use non-default credentials path */ - int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ - int gss_store_rekey; - char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */ -@@ -176,6 +179,7 @@ - char *adm_forced_command; - - int use_pam; /* Enable auth via PAM */ -+ int permit_pam_user_change; /* Allow PAM to change user name */ - - int permit_tun; - -@@ -184,6 +188,10 @@ - int use_kuserok; - int enable_k5users; - char *chroot_directory; -+ -+ int disable_usage_stats; -+ char *usage_stats_targets; -+ - char *revoked_keys_file; - char *trusted_user_ca_keys; - char *authorized_keys_command; -diff -Nur openssh-7.2p1.orig/ssh.1 openssh-7.2p1/ssh.1 ---- openssh-7.2p1.orig/ssh.1 2016-03-02 19:04:36.366960400 +0100 -+++ openssh-7.2p1/ssh.1 2016-03-02 19:05:41.301212801 +0100 -@@ -1407,6 +1407,18 @@ - on to new connections). - .It Ev USER - Set to the name of the user logging in. -+.It Ev X509_CERT_DIR -+Used for GSI authentication. Specifies a non-standard location for the -+CA certificates directory. -+.It Ev X509_USER_CERT -+Used for GSI authentication. Specifies a non-standard location for the -+certificate to be used for authentication to the server. -+.It Ev X509_USER_KEY -+Used for GSI authentication. Specifies a non-standard location for the -+private key to be used for authentication to the server. -+.It Ev X509_USER_PROXY -+Used for GSI authentication. Specifies a non-standard location for the -+proxy credential to be used for authentication to the server. - .El - .Pp - Additionally, -diff -Nur openssh-7.2p1.orig/ssh.c openssh-7.2p1/ssh.c ---- openssh-7.2p1.orig/ssh.c 2016-03-02 19:04:36.391960112 +0100 -+++ openssh-7.2p1/ssh.c 2016-03-02 19:05:41.301212801 +0100 -@@ -475,6 +475,32 @@ - fatal("Can't open user config file %.100s: " - "%.100s", config, strerror(errno)); - } else { -+ /* -+ * Since the config file parsing code aborts if it sees -+ * options it doesn't recognize, allow users to put -+ * options specific to compile-time add-ons in alternate -+ * config files so their primary config file will -+ * interoperate SSH versions that don't support those -+ * options. -+ */ -+#ifdef GSSAPI -+ r = snprintf(buf, sizeof buf, "%s/%s.gssapi", pw->pw_dir, -+ _PATH_SSH_USER_CONFFILE); -+ if (r > 0 && (size_t)r < sizeof(buf)) -+ (void)read_config_file(buf, pw, host, host_arg, &options, 1); -+#ifdef GSI -+ r = snprintf(buf, sizeof buf, "%s/%s.gsi", pw->pw_dir, -+ _PATH_SSH_USER_CONFFILE); -+ if (r > 0 && (size_t)r < sizeof(buf)) -+ (void)read_config_file(buf, pw, host, host_arg, &options, 1); -+#endif -+#if defined(KRB5) -+ r = snprintf(buf, sizeof buf, "%s/%s.krb", pw->pw_dir, -+ _PATH_SSH_USER_CONFFILE); -+ if (r > 0 && (size_t)r < sizeof(buf)) -+ (void)read_config_file(buf, pw, host, host_arg, &options, 1); -+#endif -+#endif - r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, - _PATH_SSH_USER_CONFFILE); - if (r > 0 && (size_t)r < sizeof(buf)) -@@ -1143,8 +1169,12 @@ - logit("FIPS mode initialized"); - } - -- if (options.user == NULL) -+ if (options.user == NULL) { - options.user = xstrdup(pw->pw_name); -+ options.implicit = 1; -+ } else { -+ options.implicit = 0; -+ } - - if (gethostname(thishost, sizeof(thishost)) == -1) - fatal("gethostname: %s", strerror(errno)); -diff -Nur openssh-7.2p1.orig/ssh_config openssh-7.2p1/ssh_config ---- openssh-7.2p1.orig/ssh_config 2016-03-02 19:04:36.318960953 +0100 -+++ openssh-7.2p1/ssh_config 2016-03-02 19:05:41.302212790 +0100 -@@ -24,10 +24,10 @@ - # RSAAuthentication yes - # PasswordAuthentication yes - # HostbasedAuthentication no --# GSSAPIAuthentication no --# GSSAPIDelegateCredentials no --# GSSAPIKeyExchange no --# GSSAPITrustDNS no -+# GSSAPIAuthentication yes -+# GSSAPIDelegateCredentials yes -+# GSSAPIKeyExchange yes -+# GSSAPITrustDNS yes - # BatchMode no - # CheckHostIP yes - # AddressFamily any -diff -Nur openssh-7.2p1.orig/ssh_config.5 openssh-7.2p1/ssh_config.5 ---- openssh-7.2p1.orig/ssh_config.5 2016-03-02 19:04:36.370960354 +0100 -+++ openssh-7.2p1/ssh_config.5 2016-03-02 19:05:41.302212790 +0100 -@@ -55,6 +55,12 @@ - user's configuration file - .Pq Pa ~/.ssh/config - .It -+GSSAPI configuration file -+.Pq Pa $HOME/.ssh/config.gssapi -+.It -+Kerberos configuration file -+.Pq Pa $HOME/.ssh/config.krb -+.It - system-wide configuration file - .Pq Pa /etc/ssh/ssh_config - .El -diff -Nur openssh-7.2p1.orig/sshconnect2.c openssh-7.2p1/sshconnect2.c ---- openssh-7.2p1.orig/sshconnect2.c 2016-03-02 19:04:36.391960112 +0100 -+++ openssh-7.2p1/sshconnect2.c 2016-03-02 19:05:41.303212778 +0100 -@@ -728,6 +728,11 @@ - int ok = 0; - const char *gss_host = NULL; - -+ if (!options.gss_authentication) { -+ verbose("GSSAPI authentication disabled."); -+ return 0; -+ } -+ - if (options.gss_server_identity) - gss_host = options.gss_server_identity; - else if (options.gss_trust_dns) { -@@ -965,6 +970,15 @@ - return 0; - } - -+#ifdef GSI -+extern -+const gss_OID_desc * const gss_mech_globus_gssapi_openssl; -+#define is_gsi_oid(oid) \ -+ (oid->length == gss_mech_globus_gssapi_openssl->length && \ -+ (memcmp(oid->elements, gss_mech_globus_gssapi_openssl->elements, \ -+ oid->length) == 0)) -+#endif -+ - int - userauth_gsskeyex(Authctxt *authctxt) - { -@@ -982,8 +996,16 @@ - return (0); - } - -+#ifdef GSI -+ if (options.implicit && is_gsi_oid(gss_kex_context->oid)) { -+ ssh_gssapi_buildmic(&b, "", authctxt->service, "gssapi-keyex"); -+ } else { -+#endif - ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, - "gssapi-keyex"); -+#ifdef GSI -+ } -+#endif - - gssbuf.value = buffer_ptr(&b); - gssbuf.length = buffer_len(&b); -@@ -994,7 +1016,15 @@ - } - - packet_start(SSH2_MSG_USERAUTH_REQUEST); -+#ifdef GSI -+ if (options.implicit && is_gsi_oid(gss_kex_context->oid)) { -+ packet_put_cstring(""); -+ } else { -+#endif - packet_put_cstring(authctxt->server_user); -+#ifdef GSI -+ } -+#endif - packet_put_cstring(authctxt->service); - packet_put_cstring(authctxt->method->name); - packet_put_string(mic.value, mic.length); -diff -Nur openssh-7.2p1.orig/sshd.8 openssh-7.2p1/sshd.8 ---- openssh-7.2p1.orig/sshd.8 2016-03-02 19:04:36.352960561 +0100 -+++ openssh-7.2p1/sshd.8 2016-03-02 19:05:41.303212778 +0100 -@@ -795,6 +795,44 @@ - # A CA key, accepted for any host in *.mydomain.com or *.mydomain.org - @cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W... - .Ed -+.Sh ENVIRONMENT -+.Nm -+will normally set the following environment variables: -+.Bl -tag -width "SSH_ORIGINAL_COMMAND" -+.It Ev GLOBUS_USAGE_OPTOUT -+Setting this environment variable to "1" will disable the reporting -+of usage metrics. Usage metrics can also be disabled using the -+.Cm DisableUsageStats -+setting in -+.Xr sshd_config 5 . -+.It Ev GLOBUS_USAGE_TARGETS -+If -+.Cm UsageStatsTargets -+is not specified in -+.Xr sshd_config 5 , -+a comma-separated list of targets (without any tags specified) if -+specified in the environment variable -+.Ev GLOBUS_USAGE_TARGETS -+will be used. -+.It Ev GRIDMAP -+Applies to GSI authentication/authorization. Specifies the location of the -+gridmapfile. If not specified, the gridmap file is assumed to be available at -+/etc/grid-security/grid-mapfile for services running as root and at -+HOME/.gridmap for services running as non-root where HOME is the home directory -+of the effective user from the password file entry. -+.It Ev X509_CERT_DIR -+Used for GSI authentication. Specifies a non-standard location for the -+CA certificates directory. -+.It Ev X509_USER_CERT -+Used for GSI authentication. Specifies a non-standard location for the -+certificate to be used for authentication to the client. -+.It Ev X509_USER_KEY -+Used for GSI authentication. Specifies a non-standard location for the -+private key to be used for authentication to the client. -+.It Ev X509_USER_PROXY -+Used for GSI authentication. Specifies a non-standard location for the -+proxy credential to be used for authentication to the client. -+.El - .Sh FILES - .Bl -tag -width Ds -compact - .It Pa ~/.hushlogin -diff -Nur openssh-7.2p1.orig/sshd.c openssh-7.2p1/sshd.c ---- openssh-7.2p1.orig/sshd.c 2016-03-02 19:04:36.399960020 +0100 -+++ openssh-7.2p1/sshd.c 2016-03-02 19:05:41.304212767 +0100 -@@ -128,6 +128,7 @@ - #include "ssh-sandbox.h" - #include "version.h" - #include "ssherr.h" -+#include "ssh-globus-usage.h" - - #ifdef LIBWRAP - #include -@@ -1797,6 +1798,13 @@ - /* Fill in default values for those options not explicitly set. */ - fill_default_server_options(&options); - -+#ifdef HAVE_GLOBUS_USAGE -+ if (ssh_usage_stats_init(options.disable_usage_stats, -+ options.usage_stats_targets) != GLOBUS_SUCCESS) { -+ error("Error initializing Globus Usage Metrics, but continuing ..."); -+ } -+#endif /* HAVE_GLOBUS_USAGE */ -+ - /* challenge-response is implemented via keyboard interactive */ - if (options.challenge_response_authentication) - options.kbd_interactive_authentication = 1; -@@ -2362,7 +2370,7 @@ - #endif - - #ifdef GSSAPI -- if (options.gss_authentication) { -+ if (options.gss_authentication && options.gss_deleg_creds) { - temporarily_use_uid(authctxt->pw); - ssh_gssapi_storecreds(); - restore_uid(); -diff -Nur openssh-7.2p1.orig/sshd_config openssh-7.2p1/sshd_config ---- openssh-7.2p1.orig/sshd_config 2016-03-02 19:04:36.361960458 +0100 -+++ openssh-7.2p1/sshd_config 2016-03-02 19:05:41.304212767 +0100 -@@ -90,10 +90,11 @@ - #KerberosUseKuserok yes - - # GSSAPI options --GSSAPIAuthentication yes -+#GSSAPIAuthentication yes -+#GSSAPIDelegateCredentials yes - GSSAPICleanupCredentials no - #GSSAPIStrictAcceptorCheck yes --#GSSAPIKeyExchange no -+#GSSAPIKeyExchange yes - #GSSAPIEnablek5users no - - # Set this to 'yes' to enable PAM authentication, account processing, -@@ -109,6 +110,10 @@ - # problems. - UsePAM yes - -+# Set to 'yes' to allow the PAM stack to change the user name during -+# calls to authentication -+#PermitPAMUserChange no -+ - #AllowAgentForwarding yes - #AllowTcpForwarding yes - #GatewayPorts no -@@ -151,3 +156,6 @@ - # AllowTcpForwarding no - # PermitTTY no - # ForceCommand cvs server -+ -+# Usage Metrics -+#UsageStatsTargets usage-stats.example.edu:4810 -diff -Nur openssh-7.2p1.orig/sshd_config.5 openssh-7.2p1/sshd_config.5 ---- openssh-7.2p1.orig/sshd_config.5 2016-03-02 19:04:36.367960389 +0100 -+++ openssh-7.2p1/sshd_config.5 2016-03-02 19:07:15.338130138 +0100 -@@ -570,6 +570,15 @@ - See PATTERNS in - .Xr ssh_config 5 - for more information on patterns. -+.It Cm DisableUsageStats -+This keyword can be followed by one of the keywords "true", "enabled", "yes", -+"on" or "1" to disable reporting of usage metrics. Or it can be set to "false", -+"disabled", "no", "off", "0" to enable reporting of usage metrics. Setting the -+.Cm GLOBUS_USAGE_OPTOUT -+environment variable to "1" will also disable the reporting of usage metrics. -+Disabling reporting of usage metrics will cause the -+.Cm UsageStatsTargets -+setting to be ignored. - .It Cm FingerprintHash - Specifies the hash algorithm used when logging key fingerprints. - Valid options are: -@@ -623,6 +632,10 @@ - Specifies whether user authentication based on GSSAPI is allowed. - The default is - .Dq no . -+.It Cm GSSAPIDelegateCredentials -+Specifies whether delegated credentials are stored in the user's environment. -+The default is -+.Dq yes . - .It Cm GSSAPIKeyExchange - Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange - doesn't rely on ssh keys to verify host identity. -@@ -639,6 +652,22 @@ - .Xr ksu 1 . - The default is - .Dq no . -+.It Cm GSSAPICredentialsPath -+If specified, the delegated GSSAPI credential is stored in the -+given path, overwriting any existing credentials. -+Paths can be specified with syntax similar to the AuthorizedKeysFile -+option (i.e., accepting %h and %u tokens). -+When using this option, -+setting 'GssapiCleanupCredentials no' is recommended, -+so logging out of one session -+doesn't remove the credentials in use by another session of -+the same user. -+Currently only implemented for the GSI mechanism. -+.It Cm GSIAllowLimitedProxy -+Specifies whether to accept limited proxy credentials for -+authentication. -+The default is -+.Dq no . - .It Cm GSSAPIStrictAcceptorCheck - Determines whether to be strict about the identity of the GSSAPI acceptor - a client authenticates against. -@@ -1552,6 +1581,103 @@ - .Pp - To disable TCP keepalive messages, the value should be set to - .Dq no . -+.It Cm UsageStatsTargets -+This option can be used to specify the target collector hosts to which usage -+metrics should be reported. This setting will be ignored if -+.Cm DisableUsageStats -+is enabled. Multiple targets can be specified separated by comma(s), but no -+space(s). Each target specification is of the format -+.Pa host:port[!tags]. -+Tags control what data elements are reported. The following list specifies -+the tags for the corresponding data elements. -+.Pp -+.Bl -item -offset indent -compact -+.It -+.Cm V -+.Sm off -+- OpenSSH version, reported by default. -+.Sm on -+.It -+.Cm v -+.Sm off -+- SSL version, reported by default. -+.Sm on -+.It -+.Cm M -+.Sm off -+- User authentication method used such as "gssapi-keyex", "gssapi-with-mic", etc. Reported by default. -+.Sm on -+.It -+.Cm m -+.Sm off -+- User authentication mechanism used such as "GSI", "Kerberos", etc. Reported by default. -+.Sm on -+.It -+.Cm I -+.Sm off -+- Client IP address. Not reported by default. -+.Sm on -+.It -+.Cm u -+.Sm off -+- User name. Not reported by default. -+.Sm on -+.It -+.Cm U -+.Sm off -+- User DN. Not reported by default. -+.Sm on -+.Pp -+In addition to the above selected information, the following data are -+reported to ALL the specified/default target collectors. There's no way to -+exclude these from being reported other than by disabling the reporting of -+usage metrics altogether: -+.Pp -+.It -+.Cm Component code -+.Sm off -+- 12 for GSI OpenSSH -+.Sm on -+.It -+.Cm Component Data Format version -+.Sm off -+- 0 currently -+.Sm on -+.It -+.Cm IP Address -+.Sm off -+- IP address of reporting server -+.Sm on -+.It -+.Cm Timestamp -+.It -+.Cm Hostname -+.Sm off -+- Host name of reporting server -+.Sm on -+.Pp -+If no tags are specified in a host spec, or the special string -+.Dq default -+is specified, the tags -+.Dq VvMm -+are assumed. A site could choose to allow a -+different set of data to be reported by specifying a different tag set. The -+last 3 tags -+.Dq I , -+.Dq u -+and -+.Dq U -+above are more meant for a local collector that a -+site might like to deploy since they could be construed as private information. -+The special string -+.Dq all -+denotes all tags. -+.El -+.Pp -+Usage Metrics reporting is disabled unless -+.Cm UsageStatsTargets -+is specified. -+.Pp - .It Cm TrustedUserCAKeys - Specifies a file containing public keys of certificate authorities that are - trusted to sign user certificates for authentication, or -@@ -1628,6 +1754,12 @@ - as a non-root user. - The default is - .Dq no . -+.It Cm PermitPAMUserChange -+If set to -+.Dq yes -+this will enable PAM authentication to change the name of the user being -+authenticated. The default is -+.Dq no . - .It Cm UsePrivilegeSeparation - Specifies whether - .Xr sshd 8 -diff -Nur openssh-7.2p1.orig/ssh-globus-usage.c openssh-7.2p1/ssh-globus-usage.c ---- openssh-7.2p1.orig/ssh-globus-usage.c 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-7.2p1/ssh-globus-usage.c 2016-03-02 19:05:41.306212744 +0100 -@@ -0,0 +1,396 @@ -+/* -+ * Copyright 2009 The Board of Trustees of the University -+ * of Illinois. See the LICENSE file for detailed license information. -+ * -+ * Portions, specifically log_usage_stats(), ssh_usage_stats_init(), -+ * ssh_usage_stats_close(), ssh_usage_ent_s, ssh_usage_tag_e and -+ * TAG #defines were based on those from Usage Metrics portions of: -+ * gridftp/server/source/globus_i_gfs_log.c -+ * -+ * Copyright 1999-2006 University of Chicago -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+#include "includes.h" -+ -+#ifdef HAVE_GLOBUS_USAGE -+ -+#include -+#include -+ -+#include "log.h" -+#include "ssh-globus-usage.h" -+ -+static globus_list_t *usage_handle_list = NULL; -+ -+#define SSH_GLOBUS_USAGE_ID 12 -+#define SSH_GLOBUS_USAGE_VER 0 -+ -+#define SSH_GLOBUS_DEFAULT_TAGLIST "VvMm" -+#define SSH_GLOBUS_ALL_TAGLIST "VvMmIuU" -+#define SSH_GLOBUS_TAGCOUNT 25 -+ -+typedef enum ssh_usage_tag_e -+{ -+ SSH_GLOBUS_USAGE_SSH_VER = 'V', -+ SSH_GLOBUS_USAGE_SSL_VER = 'v', -+ SSH_GLOBUS_USAGE_METHOD = 'M', -+ SSH_GLOBUS_USAGE_MECHANISM = 'm', -+ SSH_GLOBUS_USAGE_CLIENTIP = 'I', -+ SSH_GLOBUS_USAGE_USERNAME = 'u', -+ SSH_GLOBUS_USAGE_USERDN = 'U' -+ /* !! ADD to ALL_TAGLIST above and to globus_usage_stats_send() -+ invocation below when adding here */ -+} ssh_usage_tag_t; -+ -+typedef struct ssh_usage_ent_s -+{ -+ globus_usage_stats_handle_t handle; -+ char * target; -+ char * taglist; -+} ssh_usage_ent_t; -+ -+ -+globus_result_t -+ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets) -+{ -+ globus_result_t result; -+ char * target_str = NULL; -+ char * ptr = ptr; -+ char * target = NULL; -+ char * entry = NULL; -+ globus_list_t * list = NULL; -+ ssh_usage_ent_t * usage_ent = NULL; -+ -+ if (disable_usage_stats || !usage_stats_targets) -+ return GLOBUS_SUCCESS; -+ -+ result = globus_module_activate(GLOBUS_USAGE_MODULE); -+ if (result != GLOBUS_SUCCESS) -+ { -+ error("ERROR: couldn't activate USAGE STATS module"); -+ return result; -+ } -+ -+ target_str = strdup(usage_stats_targets); -+ if (target_str == NULL) -+ { -+ error("ERROR: strdup failure for target_str"); -+ goto error; -+ } -+ debug("Processing usage_stats_target (%s)\n", target_str); -+ -+ if(target_str && (strchr(target_str, ',') || strchr(target_str, '!'))) -+ { -+ target = target_str; -+ -+ do { -+ usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t)); -+ if (usage_ent == NULL) -+ { -+ error("ERROR: couldn't allocate for ssh_usage_ent_t"); -+ goto error; -+ } -+ -+ if ((ptr = strchr(target, ',')) != NULL) -+ *ptr = '\0'; -+ -+ entry = strdup(target); -+ if (entry == NULL) -+ { -+ error("ERROR: strdup failure for target"); -+ goto error; -+ } -+ -+ if (ptr) -+ target = ptr + 1; -+ else -+ target = NULL; -+ -+ if((ptr = strchr(entry, '!')) != NULL) -+ { -+ *ptr = '\0'; -+ usage_ent->taglist = strdup(ptr + 1); -+ if (usage_ent->taglist == NULL) -+ { -+ error("ERROR: strdup failure for taglist"); -+ goto error; -+ } -+ if(strlen(usage_ent->taglist) > SSH_GLOBUS_TAGCOUNT) -+ { -+ usage_ent->taglist[SSH_GLOBUS_TAGCOUNT + 1] = '\0'; -+ } -+ } -+ else -+ { -+ usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST); -+ if (usage_ent->taglist == NULL) -+ { -+ error("ERROR: couldn't allocate for taglist"); -+ goto error; -+ } -+ } -+ -+ if(strcasecmp(usage_ent->taglist, "default") == 0) -+ { -+ free(usage_ent->taglist); -+ usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST); -+ if (usage_ent->taglist == NULL) -+ { -+ error("ERROR: couldn't allocate for taglist"); -+ goto error; -+ } -+ } -+ else if(strcasecmp(usage_ent->taglist, "all") == 0) -+ { -+ free(usage_ent->taglist); -+ usage_ent->taglist = strdup(SSH_GLOBUS_ALL_TAGLIST); -+ if (usage_ent->taglist == NULL) -+ { -+ error("ERROR: couldn't allocate for taglist"); -+ goto error; -+ } -+ } -+ -+ usage_ent->target = entry; -+ -+ globus_list_insert(&usage_handle_list, usage_ent); -+ } -+ while(target != NULL); -+ -+ free(target_str); -+ } -+ else -+ { -+ usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t)); -+ if (usage_ent == NULL) -+ { -+ error("ERROR: couldn't allocate for usage_ent"); -+ goto error; -+ } -+ -+ usage_ent->target = target_str; -+ usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST); -+ if (usage_ent->taglist == NULL) -+ { -+ error("ERROR: couldn't allocate for taglist"); -+ goto error; -+ } -+ -+ globus_list_insert(&usage_handle_list, usage_ent); -+ } -+ -+ result = GLOBUS_SUCCESS; -+ for(list = usage_handle_list; -+ !globus_list_empty(list); -+ list = globus_list_rest(list)) -+ { -+ usage_ent = (ssh_usage_ent_t *) globus_list_first(list); -+ -+ usage_ent->handle = NULL; -+ if (globus_usage_stats_handle_init( -+ &usage_ent->handle, -+ SSH_GLOBUS_USAGE_ID, -+ SSH_GLOBUS_USAGE_VER, -+ usage_ent->target) != GLOBUS_SUCCESS) -+ { -+ error("USAGE-STATS: Error initializing (%s) (%s)", -+ usage_ent->target?:"NULL", -+ usage_ent->taglist?:"NULL"); -+ result = GLOBUS_FAILURE; -+ } else -+ debug("USAGE-STATS: Initialized (%s) (%s)", usage_ent->target?:"NULL", -+ usage_ent->taglist?:"NULL"); -+ -+ } -+ -+ return result; -+ -+error: -+ if (target_str) -+ { -+ free(target_str); -+ target_str = NULL; -+ } -+ if (entry) -+ { -+ free(target_str); -+ target_str = NULL; -+ } -+ return GLOBUS_FAILURE; -+} -+ -+void -+ssh_usage_stats_close(int disable_usage_stats) -+{ -+ globus_list_t *list; -+ -+ if (disable_usage_stats) -+ return; -+ -+ list = usage_handle_list; -+ -+ while(!globus_list_empty(list)) -+ { -+ ssh_usage_ent_t *usage_ent; -+ -+ usage_ent = (ssh_usage_ent_t *) -+ globus_list_remove(&list, list); -+ -+ if(usage_ent) -+ { -+ if(usage_ent->handle) -+ { -+ globus_usage_stats_handle_destroy(usage_ent->handle); -+ } -+ if(usage_ent->target) -+ { -+ free(usage_ent->target); -+ } -+ if(usage_ent->taglist) -+ { -+ free(usage_ent->taglist); -+ } -+ free(usage_ent); -+ } -+ } -+ usage_handle_list = NULL; -+} -+ -+static void -+log_usage_stats(const char *ssh_release, const char *ssl_release, -+ const char *method, const char *mechanism, -+ const char *clientip, -+ const char *username, const char *userdn) -+{ -+ globus_result_t result; -+ globus_list_t * list; -+ ssh_usage_ent_t * usage_ent; -+ char * keys[SSH_GLOBUS_TAGCOUNT]; -+ char * values[SSH_GLOBUS_TAGCOUNT]; -+ char * ptr; -+ char * key; -+ char * value; -+ int i = 0; -+ char * save_taglist = NULL; -+ -+ for(list = usage_handle_list; -+ !globus_list_empty(list); -+ list = globus_list_rest(list)) -+ { -+ usage_ent = (ssh_usage_ent_t *) globus_list_first(list); -+ -+ if(!usage_ent || usage_ent->handle == NULL) -+ continue; -+ -+ if(save_taglist == NULL || -+ strcmp(save_taglist, usage_ent->taglist) != 0) -+ { -+ save_taglist = usage_ent->taglist; -+ -+ ptr = usage_ent->taglist; -+ i = 0; -+ while(ptr && *ptr) -+ { -+ switch(*ptr) -+ { -+ case SSH_GLOBUS_USAGE_SSH_VER: -+ key = "SSH_VER"; -+ value = (char *) ssh_release; -+ break; -+ -+ case SSH_GLOBUS_USAGE_SSL_VER: -+ key = "SSL_VER"; -+ value = (char *) ssl_release; -+ break; -+ -+ case SSH_GLOBUS_USAGE_METHOD: -+ key = "METHOD"; -+ value = (char *) method; -+ break; -+ -+ case SSH_GLOBUS_USAGE_MECHANISM: -+ key = "MECH"; -+ value = (char *) mechanism?:""; -+ break; -+ -+ case SSH_GLOBUS_USAGE_CLIENTIP: -+ key = "CLIENTIP"; -+ value = (char *) clientip?:""; -+ break; -+ -+ case SSH_GLOBUS_USAGE_USERNAME: -+ key = "USER"; -+ value = (char *) username?:""; -+ break; -+ -+ case SSH_GLOBUS_USAGE_USERDN: -+ key = "USERDN"; -+ value = (char *) userdn?:""; -+ break; -+ -+ default: -+ key = NULL; -+ value = NULL; -+ break; -+ } -+ -+ if(key != NULL && value != NULL) -+ { -+ keys[i] = key; -+ values[i] = value; -+ i++; -+ } -+ -+ ptr++; -+ } -+ } -+ -+#ifdef HAVE_GLOBUS_USAGE_SEND_ARRAY -+ result = globus_usage_stats_send_array( -+ usage_ent->handle, i, keys, values); -+#else -+ if (i) -+ result = globus_usage_stats_send( -+ usage_ent->handle, i, -+ i>0?keys[0]:NULL, i>0?values[0]:NULL, -+ i>1?keys[1]:NULL, i>1?values[1]:NULL, -+ i>2?keys[2]:NULL, i>2?values[2]:NULL, -+ i>3?keys[3]:NULL, i>3?values[3]:NULL, -+ i>4?keys[4]:NULL, i>4?values[4]:NULL, -+ i>5?keys[5]:NULL, i>5?values[5]:NULL, -+ i>6?keys[6]:NULL, i>6?values[6]:NULL); -+#endif /* HAVE_GLOBUS_USAGE_SEND_ARRAY */ -+ } -+ -+ return; -+} -+#endif /* HAVE_GLOBUS_USAGE */ -+ -+void -+ssh_globus_send_usage_metrics(const char *ssh_release, -+ const char *ssl_release, -+ const char *method, -+ const char *mechanism, -+ const char *client_ip, -+ const char *username, -+ const char *userdn) -+{ -+#ifdef HAVE_GLOBUS_USAGE -+ -+ log_usage_stats(ssh_release, ssl_release, method, mechanism, -+ client_ip, username, userdn); -+ -+#endif /* HAVE_GLOBUS_USAGE */ -+} -diff -Nur openssh-7.2p1.orig/ssh-globus-usage.h openssh-7.2p1/ssh-globus-usage.h ---- openssh-7.2p1.orig/ssh-globus-usage.h 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-7.2p1/ssh-globus-usage.h 2016-03-02 19:05:41.306212744 +0100 -@@ -0,0 +1,48 @@ -+/* -+ * Copyright 2009 The Board of Trustees of the University -+ * of Illinois. See the LICENSE file for detailed license information. -+ * -+ * Portions, specifically ssh_usage_stats_init(), ssh_usage_stats_close() -+ * were based on those from: gridftp/server/source/globus_i_gfs_log.h -+ * Copyright 1999-2006 University of Chicago -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+#ifndef __SSH_GLOBUS_USAGE_H -+#define __SSH_GLOBUS_USAGE_H -+ -+#include "includes.h" -+ -+#ifdef HAVE_GLOBUS_USAGE -+ -+#include "globus_usage.h" -+ -+globus_result_t -+ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets); -+ -+void -+ssh_usage_stats_close(int disable_usage_stats); -+ -+#endif /* HAVE_GLOBUS_USAGE */ -+ -+void -+ssh_globus_send_usage_metrics(const char *ssh_release, -+ const char *ssl_release, -+ const char *method, -+ const char *mechanism, -+ const char *client_ip, -+ const char *username, -+ const char *userdn); -+ -+#endif /* __SSH_GLOBUS_USAGE_H */ -diff -Nur openssh-7.2p1.orig/ssh-gss.h openssh-7.2p1/ssh-gss.h ---- openssh-7.2p1.orig/ssh-gss.h 2016-03-02 19:04:36.367960389 +0100 -+++ openssh-7.2p1/ssh-gss.h 2016-03-02 19:05:41.306212744 +0100 -@@ -95,6 +95,7 @@ - gss_name_t name; - struct ssh_gssapi_mech_struct *mech; - ssh_gssapi_ccache store; -+ gss_ctx_id_t context; /* needed for globus_gss_assist_map_and_authorize() */ - int used; - int updated; - } ssh_gssapi_client; -@@ -115,7 +116,7 @@ - OM_uint32 minor; /* both */ - gss_ctx_id_t context; /* both */ - gss_name_t name; /* both */ -- gss_OID oid; /* client */ -+ gss_OID oid; /* both */ - gss_cred_id_t creds; /* server */ - gss_name_t client; /* server */ - gss_cred_id_t client_creds; /* both */ -@@ -148,6 +149,9 @@ - OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); - int ssh_gssapi_credentials_updated(Gssctxt *); - -+int ssh_gssapi_localname(char **name); -+void ssh_gssapi_rekey_creds(); -+ - /* In the server */ - typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, - const char *); -@@ -158,7 +162,7 @@ - int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, - const char *); - OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); --int ssh_gssapi_userok(char *name, struct passwd *); -+int ssh_gssapi_userok(char *name, struct passwd *, int gssapi_keyex); - 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); -@@ -170,6 +174,7 @@ - int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); - - void ssh_gssapi_rekey_creds(void); -+void ssh_gssapi_get_client_info(char **userdn, char **mech); - #endif /* GSSAPI */ - - #endif /* _SSH_GSS_H */ -diff -Nur openssh-7.2p1.orig/version.h openssh-7.2p1/version.h ---- openssh-7.2p1.orig/version.h 2016-02-26 04:40:04.000000000 +0100 -+++ openssh-7.2p1/version.h 2016-03-02 19:10:52.953628948 +0100 -@@ -1,6 +1,21 @@ - /* $OpenBSD: version.h,v 1.76 2016/02/23 09:14:34 djm Exp $ */ - -+#ifdef GSI -+#define GSI_VERSION " GSI" -+#else -+#define GSI_VERSION "" -+#endif -+ -+#ifdef KRB5 -+#define KRB5_VERSION " KRB5" -+#else -+#define KRB5_VERSION "" -+#endif -+ -+#define NCSA_VERSION " GSI_GSSAPI_20150812" -+ - #define SSH_VERSION "OpenSSH_7.2" - - #define SSH_PORTABLE "p1" --#define SSH_RELEASE SSH_VERSION SSH_PORTABLE -+#define SSH_RELEASE SSH_VERSION SSH_PORTABLE \ -+ NCSA_VERSION GSI_VERSION KRB5_VERSION diff --git a/openssh-7.2p1-gsskex.patch b/openssh-7.2p1-gsskex.patch index ab08b96..4544c54 100644 --- a/openssh-7.2p1-gsskex.patch +++ b/openssh-7.2p1-gsskex.patch @@ -2739,3 +2739,41 @@ diff -up openssh-7.2p1/sshkey.h.gsskex openssh-7.2p1/sshkey.h KEY_UNSPEC }; +diff --git a/kexgsss.c b/kexgsss.c +index b2f9658..2d33ff7 100644 +--- a/kexgsss.c ++++ b/kexgsss.c +@@ -69,6 +69,7 @@ kexgss_server(struct ssh *ssh) + u_char *kbuf; + DH *dh; + int min = -1, max = -1, nbits = -1; ++ int cmin = -1, cmax = -1; /* client proposal */ + BIGNUM *shared_secret = NULL; + BIGNUM *dh_client_pub = NULL; + int type = 0; +@@ -107,11 +108,12 @@ kexgss_server(struct ssh *ssh) + case KEX_GSS_GEX_SHA1: + debug("Doing group exchange"); + packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ); +- min = packet_get_int(); ++ /* store client proposal to provide valid signature */ ++ cmin = packet_get_int(); + nbits = packet_get_int(); +- max = packet_get_int(); +- min = MAX(DH_GRP_MIN, min); +- max = MIN(DH_GRP_MAX, max); ++ cmax = packet_get_int(); ++ min = MAX(DH_GRP_MIN, cmin); ++ max = MIN(DH_GRP_MAX, cmax); + packet_check_eom(); + if (max < min || nbits < min || max < nbits) + fatal("GSS_GEX, bad parameters: %d !< %d !< %d", +@@ -234,7 +236,7 @@ kexgss_server(struct ssh *ssh) + buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), + buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), + NULL, 0, +- min, nbits, max, ++ cmin, nbits, cmax, + dh->p, dh->g, + dh_client_pub, + dh->pub_key, diff --git a/openssh-7.2p2-gsissh.patch b/openssh-7.2p2-gsissh.patch new file mode 100644 index 0000000..ed64b48 --- /dev/null +++ b/openssh-7.2p2-gsissh.patch @@ -0,0 +1,3012 @@ +diff -Nur openssh-7.2p1.orig/auth2.c openssh-7.2p1/auth2.c +--- openssh-7.2p1.orig/auth2.c 2016-03-02 19:04:36.376960285 +0100 ++++ openssh-7.2p1/auth2.c 2016-03-02 19:05:41.290212928 +0100 +@@ -50,6 +50,7 @@ + #include "dispatch.h" + #include "pathnames.h" + #include "buffer.h" ++#include "canohost.h" + + #ifdef GSSAPI + #include "ssh-gss.h" +@@ -74,6 +75,8 @@ + extern Authmethod method_gssapi; + #endif + ++static int log_flag = 0; ++ + Authmethod *authmethods[] = { + &method_none, + &method_pubkey, +@@ -228,7 +231,33 @@ + user = packet_get_cstring(NULL); + service = packet_get_cstring(NULL); + method = packet_get_cstring(NULL); +- debug("userauth-request for user %s service %s method %s", user, service, method); ++ ++#ifdef GSSAPI ++ if (user[0] == '\0') { ++ debug("received empty username for %s", method); ++ if (strcmp(method, "gssapi-keyex") == 0) { ++ char *lname = NULL; ++ PRIVSEP(ssh_gssapi_localname(&lname)); ++ if (lname && lname[0] != '\0') { ++ free(user); ++ user = lname; ++ debug("set username to %s from gssapi context", user); ++ } else { ++ debug("failed to set username from gssapi context"); ++ packet_send_debug("failed to set username from gssapi context"); ++ } ++ } ++ } ++#endif ++ ++ debug("userauth-request for user %s service %s method %s", ++ user[0] ? user : "", service, method); ++ if (!log_flag) { ++ logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s", ++ get_remote_ipaddr(), get_remote_port(), ++ user[0] ? user : ""); ++ log_flag = 1; ++ } + debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); + + #ifdef WITH_SELINUX +@@ -239,23 +268,48 @@ + if ((style = strchr(user, ':')) != NULL) + *style++ = 0; + +- if (authctxt->attempt++ == 0) { +- /* setup auth context */ +- authctxt->pw = PRIVSEP(getpwnamallow(user)); ++ /* If first time or username changed or empty username, ++ setup/reset authentication context. */ ++ if ((authctxt->attempt++ == 0) || ++ (strcmp(user, authctxt->user) != 0) || ++ (strcmp(user, "") == 0)) { ++ if (authctxt->user) { ++ free(authctxt->user); ++ authctxt->user = NULL; ++ } ++ authctxt->valid = 0; + authctxt->user = xstrdup(user); +- if (authctxt->pw && strcmp(service, "ssh-connection")==0) { ++ if (strcmp(service, "ssh-connection") != 0) { ++ packet_disconnect("Unsupported service %s", service); ++ } ++#ifdef GSSAPI ++ /* If we're going to set the username based on the ++ GSSAPI context later, then wait until then to ++ verify it. Just put in placeholders for now. */ ++ if ((strcmp(user, "") == 0) && ++ ((strcmp(method, "gssapi") == 0) || ++ (strcmp(method, "gssapi-with-mic") == 0))) { ++ authctxt->pw = fakepw(); ++ } else { ++#endif ++ authctxt->pw = PRIVSEP(getpwnamallow(user)); ++ if (authctxt->pw) { + authctxt->valid = 1; + debug2("input_userauth_request: setting up authctxt for %s", user); + } else { + logit("input_userauth_request: invalid user %s", user); + authctxt->pw = fakepw(); + } ++#ifdef GSSAPI ++ } /* endif for setting username based on GSSAPI context */ ++#endif + #ifdef USE_PAM + if (options.use_pam) + PRIVSEP(start_pam(authctxt)); + #endif + setproctitle("%s%s", authctxt->valid ? user : "unknown", + use_privsep ? " [net]" : ""); ++ if (authctxt->attempt == 1) { + authctxt->service = xstrdup(service); + authctxt->style = style ? xstrdup(style) : NULL; + #ifdef WITH_SELINUX +@@ -270,9 +324,10 @@ + userauth_banner(); + if (auth2_setup_methods_lists(authctxt) != 0) + packet_disconnect("no authentication methods enabled"); +- } else if (strcmp(user, authctxt->user) != 0 || +- strcmp(service, authctxt->service) != 0) { +- packet_disconnect("Change of username or service not allowed: " ++ } ++ } ++ if (strcmp(service, authctxt->service) != 0) { ++ packet_disconnect("Change of service not allowed: " + "(%s,%s) -> (%s,%s)", + authctxt->user, authctxt->service, user, service); + } +diff -Nur openssh-7.2p1.orig/auth2-gss.c openssh-7.2p1/auth2-gss.c +--- openssh-7.2p1.orig/auth2-gss.c 2016-03-02 19:04:36.311961033 +0100 ++++ openssh-7.2p1/auth2-gss.c 2016-03-02 19:05:41.290212928 +0100 +@@ -49,6 +49,7 @@ + + extern ServerOptions options; + ++static void ssh_gssapi_userauth_error(Gssctxt *ctxt); + static int input_gssapi_token(int type, u_int32_t plen, void *ctxt); + static int input_gssapi_mic(int type, u_int32_t plen, void *ctxt); + static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); +@@ -61,8 +62,8 @@ + userauth_gsskeyex(Authctxt *authctxt) + { + int authenticated = 0; +- Buffer b; +- gss_buffer_desc mic, gssbuf; ++ Buffer b, b2; ++ gss_buffer_desc mic, gssbuf, gssbuf2; + u_int len; + + mic.value = packet_get_string(&len); +@@ -76,13 +77,27 @@ + gssbuf.value = buffer_ptr(&b); + gssbuf.length = buffer_len(&b); + ++ /* client may have used empty username to determine target ++ name from GSSAPI context */ ++ ssh_gssapi_buildmic(&b2, "", authctxt->service, "gssapi-keyex"); ++ ++ gssbuf2.value = buffer_ptr(&b2); ++ gssbuf2.length = buffer_len(&b2); ++ + /* gss_kex_context is NULL with privsep, so we can't check it here */ + if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, +- &gssbuf, &mic)))) +- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, +- authctxt->pw)); ++ &gssbuf, &mic))) || ++ !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, ++ &gssbuf2, &mic)))) { ++ if (authctxt->valid && authctxt->user && authctxt->user[0]) { ++ authenticated = ++ PRIVSEP(ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 1 /* gssapi-keyex */)); ++ } ++ } + + buffer_free(&b); ++ buffer_free(&b2); + free(mic.value); + + return (authenticated); +@@ -103,7 +118,10 @@ + u_int len; + u_char *doid = NULL; + +- if (!authctxt->valid || authctxt->user == NULL) ++ /* authctxt->valid may be 0 if we haven't yet determined ++ username from gssapi context. */ ++ ++ if (authctxt->user == NULL) + return (0); + + mechs = packet_get_int(); +@@ -168,7 +186,7 @@ + Gssctxt *gssctxt; + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; + gss_buffer_desc recv_tok; +- OM_uint32 maj_status, min_status, flags; ++ OM_uint32 maj_status, min_status, flags = 0; + u_int len; + + if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) +@@ -186,6 +204,7 @@ + free(recv_tok.value); + + if (GSS_ERROR(maj_status)) { ++ ssh_gssapi_userauth_error(gssctxt); + if (send_tok.length != 0) { + packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); + packet_put_string(send_tok.value, send_tok.length); +@@ -251,6 +270,32 @@ + return 0; + } + ++static void ++gssapi_set_username(Authctxt *authctxt) ++{ ++ char *lname = NULL; ++ ++ if ((authctxt->user == NULL) || (authctxt->user[0] == '\0')) { ++ PRIVSEP(ssh_gssapi_localname(&lname)); ++ if (lname && lname[0] != '\0') { ++ if (authctxt->user) free(authctxt->user); ++ authctxt->user = lname; ++ debug("set username to %s from gssapi context", lname); ++ authctxt->pw = PRIVSEP(getpwnamallow(authctxt->user)); ++ if (authctxt->pw) { ++ authctxt->valid = 1; ++#ifdef USE_PAM ++ if (options.use_pam) ++ PRIVSEP(start_pam(authctxt)); ++#endif ++ } ++ } else { ++ debug("failed to set username from gssapi context"); ++ packet_send_debug("failed to set username from gssapi context"); ++ } ++ } ++} ++ + /* + * This is called when the client thinks we've completed authentication. + * It should only be enabled in the dispatch handler by the function above, +@@ -266,6 +311,8 @@ + if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) + fatal("No authentication or GSSAPI context"); + ++ gssapi_set_username(authctxt); ++ + /* + * We don't need to check the status, because we're only enabled in + * the dispatcher once the exchange is complete +@@ -273,8 +320,13 @@ + + packet_check_eom(); + +- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, +- authctxt->pw)); ++ /* user should be set if valid but we double-check here */ ++ if (authctxt->valid && authctxt->user && authctxt->user[0]) { ++ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 0 /* !gssapi-keyex */)); ++ } else { ++ authenticated = 0; ++ } + + authctxt->postponed = 0; + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); +@@ -316,9 +368,16 @@ + gssbuf.value = buffer_ptr(&b); + gssbuf.length = buffer_len(&b); + ++ gssapi_set_username(authctxt); ++ + if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) +- authenticated = +- PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw)); ++ if (authctxt->valid && authctxt->user && authctxt->user[0]) { ++ authenticated = ++ PRIVSEP(ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 0 /* !gssapi-keyex */)); ++ } else { ++ authenticated = 0; ++ } + else + logit("GSSAPI MIC check failed"); + +@@ -336,6 +395,23 @@ + return 0; + } + ++static void ssh_gssapi_userauth_error(Gssctxt *ctxt) { ++ char *errstr; ++ OM_uint32 maj,min; ++ ++ errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min)); ++ if (errstr) { ++ packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR); ++ packet_put_int(maj); ++ packet_put_int(min); ++ packet_put_cstring(errstr); ++ packet_put_cstring(""); ++ packet_send(); ++ packet_write_wait(); ++ free(errstr); ++ } ++} ++ + Authmethod method_gsskeyex = { + "gssapi-keyex", + userauth_gsskeyex, +diff -Nur openssh-7.2p1.orig/auth.c openssh-7.2p1/auth.c +--- openssh-7.2p1.orig/auth.c 2016-03-02 19:04:36.376960285 +0100 ++++ openssh-7.2p1/auth.c 2016-03-02 19:05:41.291212916 +0100 +@@ -75,6 +75,9 @@ + #include "ssherr.h" + #include "compat.h" + ++#include "version.h" ++#include "ssh-globus-usage.h" ++ + /* import */ + extern ServerOptions options; + extern int use_privsep; +@@ -299,7 +302,8 @@ + method, + submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, + authctxt->valid ? "" : "invalid user ", +- authctxt->user, ++ (authctxt->user && authctxt->user[0]) ? ++ authctxt->user : "unknown", + get_remote_ipaddr(), + get_remote_port(), + compat20 ? "ssh2" : "ssh1", +@@ -325,6 +329,23 @@ + if (authenticated == 0 && !authctxt->postponed) + audit_event(audit_classify_auth(method)); + #endif ++ if (authenticated) { ++ char *userdn = NULL; ++ char *mech_name = NULL; ++#ifdef GSSAPI ++ ssh_gssapi_get_client_info(&userdn, &mech_name); ++#endif ++ debug("REPORTING (%s) (%s) (%s) (%s) (%s) (%s) (%s)", ++ SSH_RELEASE, SSLeay_version(SSLEAY_VERSION), ++ method, mech_name?mech_name:"NULL", get_remote_ipaddr(), ++ (authctxt->user && authctxt->user[0])? ++ authctxt->user : "unknown", ++ userdn?userdn:"NULL"); ++ ssh_globus_send_usage_metrics(SSH_RELEASE, ++ SSLeay_version(SSLEAY_VERSION), ++ method, mech_name, get_remote_ipaddr(), ++ authctxt->user, userdn); ++ } + } + + +@@ -622,6 +643,10 @@ + #endif + + pw = getpwnam(user); ++#ifdef USE_PAM ++ if (options.use_pam && options.permit_pam_user_change && pw == NULL) ++ pw = sshpam_getpw(user); ++#endif + + #if defined(_AIX) && defined(HAVE_SETAUTHDB) + aix_restoreauthdb(); +@@ -641,7 +666,8 @@ + #endif + if (pw == NULL) { + logit("Invalid user %.100s from %.100s", +- user, get_remote_ipaddr()); ++ (user && user[0]) ? user : "unknown", ++ get_remote_ipaddr()); + #ifdef CUSTOM_FAILED_LOGIN + record_failed_login(user, + get_canonical_hostname(options.use_dns), "ssh"); +diff -Nur openssh-7.2p1.orig/auth-pam.c openssh-7.2p1/auth-pam.c +--- openssh-7.2p1.orig/auth-pam.c 2016-03-02 19:04:36.394960078 +0100 ++++ openssh-7.2p1/auth-pam.c 2016-03-02 19:05:41.292212905 +0100 +@@ -123,6 +123,10 @@ + */ + typedef pthread_t sp_pthread_t; + #else ++#define pthread_create openssh_pthread_create ++#define pthread_exit openssh_pthread_exit ++#define pthread_cancel openssh_pthread_cancel ++#define pthread_join openssh_pthread_join + typedef pid_t sp_pthread_t; + #endif + +@@ -278,6 +282,56 @@ + # define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b))) + #endif + ++struct passwd * ++sshpam_getpw(const char *user) ++{ ++ struct passwd *pw; ++ ++ if ((pw = getpwnam(user)) != NULL) ++ return(pw); ++ ++ debug("PAM: faking passwd struct for user '%.100s'", user); ++ if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) ++ return NULL; ++ pw->pw_name = xstrdup(user); /* XXX leak */ ++ pw->pw_shell = "/bin/true"; ++ pw->pw_gecos = "sshd fake PAM user"; ++ return (pw); ++} ++ ++void ++sshpam_check_userchanged(void) ++{ ++ int sshpam_err; ++ struct passwd *pw; ++ const char *user; ++ ++ debug("sshpam_check_userchanged"); ++ sshpam_err = pam_get_item(sshpam_handle, PAM_USER, ++ (sshpam_const void **)&user); ++ if (sshpam_err != PAM_SUCCESS) ++ fatal("PAM: could not get PAM_USER: %s", ++ pam_strerror(sshpam_handle, sshpam_err)); ++ debug("sshpam_check_userchanged: user was '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ if (strcmp(user, sshpam_authctxt->pw->pw_name) != 0) { ++ debug("PAM: user mapped from '%.100s' to '%.100s'", ++ sshpam_authctxt->pw->pw_name, user); ++ if ((pw = getpwnam(user)) == NULL) ++ fatal("PAM: could not get passwd entry for user " ++ "'%.100s' provided by PAM_USER", user); ++ pwfree(sshpam_authctxt->pw); ++ sshpam_authctxt->pw = pwcopy(pw); ++ sshpam_authctxt->valid = allowed_user(pw); ++ free(sshpam_authctxt->user); ++ sshpam_authctxt->user = xstrdup(user); ++ debug("PAM: user '%.100s' now %svalid", user, ++ sshpam_authctxt->valid ? "" : "in"); ++ } ++ debug("sshpam_check_userchanged: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++} ++ + void + sshpam_password_change_required(int reqd) + { +@@ -300,7 +354,7 @@ + static void + import_environments(Buffer *b) + { +- char *env; ++ char *env, *user; + u_int i, num_env; + int err; + +@@ -310,6 +364,17 @@ + /* Import variables set by do_pam_account */ + sshpam_account_status = buffer_get_int(b); + sshpam_password_change_required(buffer_get_int(b)); ++ if (options.permit_pam_user_change) { ++ user = buffer_get_string(b, NULL); ++ debug("PAM: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ debug("PAM: got username '%.100s' from thread", user); ++ if ((err = pam_set_item(sshpam_handle, PAM_USER, user)) != PAM_SUCCESS) ++ fatal("PAM: failed to set PAM_USER: %s", ++ pam_strerror(sshpam_handle, err)); ++ pwfree(sshpam_authctxt->pw); ++ sshpam_authctxt->pw = pwcopy(sshpam_getpw(user)); ++ } + + /* Import environment from subprocess */ + num_env = buffer_get_int(b); +@@ -476,6 +541,13 @@ + if (sshpam_err != PAM_SUCCESS) + goto auth_fail; + ++ if (options.permit_pam_user_change) { ++ debug("sshpam_thread: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ sshpam_check_userchanged(); ++ debug("sshpam_thread: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ } + if (compat20) { + if (!do_pam_account()) { + sshpam_err = PAM_ACCT_EXPIRED; +@@ -496,6 +568,11 @@ + /* Export variables set by do_pam_account */ + buffer_put_int(&buffer, sshpam_account_status); + buffer_put_int(&buffer, sshpam_authctxt->force_pwchange); ++ if (options.permit_pam_user_change) { ++ debug("sshpam_thread: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ buffer_put_cstring(&buffer, sshpam_authctxt->pw->pw_name); ++ } + + /* Export any environment strings set in child */ + for(i = 0; environ[i] != NULL; i++) +@@ -913,6 +990,18 @@ + debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, + pam_strerror(sshpam_handle, sshpam_err)); + ++ if (options.permit_pam_user_change) { ++ debug("do_pam_account: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ sshpam_check_userchanged(); ++ debug("do_pam_account: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ if (getpwnam(sshpam_authctxt->pw->pw_name) == NULL) ++ fatal("PAM: completed authentication but PAM account invalid"); ++ debug("do_pam_account: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ } ++ + if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { + sshpam_account_status = 0; + return (sshpam_account_status); +@@ -1210,6 +1299,9 @@ + pam_strerror(sshpam_handle, sshpam_err)); + + sshpam_err = pam_authenticate(sshpam_handle, flags); ++ if (options.permit_pam_user_change) { ++ sshpam_check_userchanged(); ++ } + sshpam_password = NULL; + if (sshpam_err == PAM_SUCCESS && authctxt->valid) { + debug("PAM: password authentication accepted for %.100s", +diff -Nur openssh-7.2p1.orig/auth-pam.h openssh-7.2p1/auth-pam.h +--- openssh-7.2p1.orig/auth-pam.h 2016-03-02 19:04:36.265961563 +0100 ++++ openssh-7.2p1/auth-pam.h 2016-03-02 19:05:41.292212905 +0100 +@@ -46,5 +46,6 @@ + void sshpam_cleanup(void); + int sshpam_auth_passwd(Authctxt *, const char *); + int is_pam_session_open(void); ++struct passwd *sshpam_getpw(const char *); + + #endif /* USE_PAM */ +diff -Nur openssh-7.2p1.orig/canohost.c openssh-7.2p1/canohost.c +--- openssh-7.2p1.orig/canohost.c 2016-03-02 19:04:36.333960780 +0100 ++++ openssh-7.2p1/canohost.c 2016-03-02 19:05:41.292212905 +0100 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include /* for MAXHOSTNAMELEN */ + + #include + #include +@@ -468,3 +469,33 @@ + { + return get_port(1); + } ++ ++void ++resolve_localhost(char **host) ++{ ++ struct hostent *hostinfo; ++ ++ hostinfo = gethostbyname(*host); ++ if (hostinfo == NULL || hostinfo->h_name == NULL) { ++ debug("gethostbyname(%s) failed", *host); ++ return; ++ } ++ if (hostinfo->h_addrtype == AF_INET) { ++ struct in_addr addr; ++ addr = *(struct in_addr *)(hostinfo->h_addr); ++ if (ntohl(addr.s_addr) == INADDR_LOOPBACK) { ++ char buf[MAXHOSTNAMELEN]; ++ if (gethostname(buf, sizeof(buf)) < 0) { ++ debug("gethostname() failed"); ++ return; ++ } ++ hostinfo = gethostbyname(buf); ++ free(*host); ++ if (hostinfo == NULL || hostinfo->h_name == NULL) { ++ *host = xstrdup(buf); ++ } else { ++ *host = xstrdup(hostinfo->h_name); ++ } ++ } ++ } ++} +diff -Nur openssh-7.2p1.orig/canohost.h openssh-7.2p1/canohost.h +--- openssh-7.2p1.orig/canohost.h 2016-03-02 19:04:36.334960769 +0100 ++++ openssh-7.2p1/canohost.h 2016-03-02 19:05:41.292212905 +0100 +@@ -27,4 +27,6 @@ + int get_sock_port(int, int); + void clear_cached_addr(void); + ++void resolve_localhost(char **host); ++ + void ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *); +diff -Nur openssh-7.2p1.orig/configure.ac openssh-7.2p1/configure.ac +--- openssh-7.2p1.orig/configure.ac 2016-03-02 19:04:36.356960515 +0100 ++++ openssh-7.2p1/configure.ac 2016-03-02 19:05:41.293212893 +0100 +@@ -4330,6 +4330,14 @@ + AC_CHECK_HEADER([gssapi_krb5.h], , + [ CPPFLAGS="$oldCPP" ]) + ++ # If we're using some other GSSAPI ++ if test -n "$GSSAPI" ; then ++ AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Kerberos GSI.]) ++ fi ++ ++ if test -z "$GSSAPI"; then ++ GSSAPI="KRB5"; ++ fi + fi + if test ! -z "$need_dash_r" ; then + LDFLAGS="$LDFLAGS -R${KRB5ROOT}/lib" +@@ -4369,6 +4377,50 @@ + AC_SUBST([GSSLIBS]) + AC_SUBST([K5LIBS]) + ++# Check whether the user wants GSI (Globus) support ++gsi="no" ++AC_ARG_WITH(gsi, ++ [ --with-gsi Enable Globus GSI authentication support], ++ [ ++ gsi="$withval" ++ ] ++) ++ ++if test "x$gsi" != "xno" ; then ++ # Globus GSSAPI configuration ++ AC_MSG_CHECKING(for Globus GSI) ++ AC_DEFINE(GSI, 1, [Define if you want GSI/Globus authentication support.]) ++ ++ if test -n "$GSSAPI" ; then ++ AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Globus GSI.]) ++ fi ++ ++ if test -z "$GSSAPI" ; then ++ GSSAPI="GSI" ++ fi ++ ++ LIBS="$LIBS `pkg-config --libs globus-gss-assist globus-gssapi-gsi globus-common`" ++ CPPFLAGS="$CPPFLAGS `pkg-config --cflags globus-gss-assist globus-gssapi-gsi globus-common`" ++ ++ AC_DEFINE(GSSAPI) ++ AC_DEFINE(HAVE_GSSAPI_H) ++ ++ AC_CHECK_FUNCS(globus_gss_assist_map_and_authorize) ++ ++ dnl ++ dnl Check for globus_usage_stats_send ++ dnl ++ AC_SEARCH_LIBS(globus_usage_stats_send, ++ globus_usage, ++ AC_DEFINE([HAVE_GLOBUS_USAGE], 1, [Have Globus Usage])) ++ dnl ++ dnl Check for globus_usage_stats_send_array ++ dnl ++ AC_SEARCH_LIBS(globus_usage_stats_send_array, ++ globus_usage, ++ AC_DEFINE([HAVE_GLOBUS_USAGE_SEND_ARRAY], 1, [Have Globus Usage send_array])) ++fi ++ + # Looking for programs, paths and files + + PRIVSEP_PATH=/var/empty +diff -Nur openssh-7.2p1.orig/gss-genr.c openssh-7.2p1/gss-genr.c +--- openssh-7.2p1.orig/gss-genr.c 2016-03-02 19:04:36.363960435 +0100 ++++ openssh-7.2p1/gss-genr.c 2016-03-02 19:05:41.294212882 +0100 +@@ -40,6 +40,7 @@ + #include "xmalloc.h" + #include "buffer.h" + #include "log.h" ++#include "canohost.h" + #include "ssh2.h" + #include "cipher.h" + #include "key.h" +@@ -368,9 +369,18 @@ + ssh_gssapi_import_name(Gssctxt *ctx, const char *host) + { + gss_buffer_desc gssbuf; ++ char *xhost; + char *val; + +- xasprintf(&val, "host@%s", host); ++ /* Make a copy of the host name, in case it was returned by a ++ * previous call to gethostbyname(). */ ++ xhost = xstrdup(host); ++ ++ /* Make sure we have the FQDN. Some GSSAPI implementations don't do ++ * this for us themselves */ ++ resolve_localhost(&xhost); ++ ++ xasprintf(&val, "host@%s", xhost); + gssbuf.value = val; + gssbuf.length = strlen(gssbuf.value); + +@@ -378,6 +388,7 @@ + &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) + ssh_gssapi_error(ctx); + ++ free(xhost); + free(gssbuf.value); + return (ctx->major); + } +diff -Nur openssh-7.2p1.orig/gss-serv.c openssh-7.2p1/gss-serv.c +--- openssh-7.2p1.orig/gss-serv.c 2016-03-02 19:04:36.363960435 +0100 ++++ openssh-7.2p1/gss-serv.c 2016-03-02 19:05:41.294212882 +0100 +@@ -47,14 +47,17 @@ + #include "servconf.h" + #include "uidswap.h" + ++#include "xmalloc.h" + #include "ssh-gss.h" + #include "monitor_wrap.h" + + extern ServerOptions options; ++extern Authctxt *the_authctxt; + + static ssh_gssapi_client gssapi_client = + { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, +- GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, {NULL, NULL, NULL}, 0, 0}; ++ GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, ++ GSS_C_NO_CONTEXT, 0, 0}; + + ssh_gssapi_mech gssapi_null_mech = + { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; +@@ -62,14 +65,24 @@ + #ifdef KRB5 + extern ssh_gssapi_mech gssapi_kerberos_mech; + #endif ++#ifdef GSI ++extern ssh_gssapi_mech gssapi_gsi_mech; ++#endif + + ssh_gssapi_mech* supported_mechs[]= { + #ifdef KRB5 + &gssapi_kerberos_mech, + #endif ++#ifdef GSI ++ &gssapi_gsi_mech, ++#endif + &gssapi_null_mech, + }; + ++#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG ++static int limited = 0; ++#endif ++ + /* + * ssh_gssapi_supported_oids() can cause sandbox violations, so prepare the + * list of supported mechanisms before privsep is set up. +@@ -230,6 +243,10 @@ + (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) { + if (ssh_gssapi_getclient(ctx, &gssapi_client)) + fatal("Couldn't convert client name"); ++#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG ++ if (flags && (*flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG)) ++ limited=1; ++#endif + } + + return (status); +@@ -249,6 +266,17 @@ + + tok = ename->value; + ++#ifdef GSI /* GSI gss_export_name() is broken. */ ++ if ((ctx->oid->length == gssapi_gsi_mech.oid.length) && ++ (memcmp(ctx->oid->elements, gssapi_gsi_mech.oid.elements, ++ gssapi_gsi_mech.oid.length) == 0)) { ++ name->length = ename->length; ++ name->value = xmalloc(ename->length+1); ++ memcpy(name->value, ename->value, ename->length); ++ return GSS_S_COMPLETE; ++ } ++#endif ++ + /* + * Check that ename is long enough for all of the fixed length + * header, and that the initial ID bytes are correct +@@ -316,8 +344,11 @@ + return GSS_S_COMPLETE; + } + +- if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, +- ctx->client_creds, ctx->oid, &new_name, ++ /* Call gss_inquire_cred rather than gss_inquire_cred_by_mech ++ because GSI doesn't support the latter. -jbasney */ ++ ++ if ((ctx->major = gss_inquire_cred(&ctx->minor, ++ ctx->client_creds, &new_name, + NULL, NULL, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); +@@ -360,9 +391,12 @@ + if (client->mech == NULL) + return GSS_S_FAILURE; + ++ /* Call gss_inquire_cred rather than gss_inquire_cred_by_mech ++ because GSI doesn't support the latter. -jbasney */ ++ + if (ctx->client_creds && +- (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, +- ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { ++ (ctx->major = gss_inquire_cred(&ctx->minor, ++ ctx->client_creds, &client->name, NULL, NULL, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } +@@ -389,6 +423,10 @@ + /* We can't copy this structure, so we just move the pointer to it */ + client->creds = ctx->client_creds; + ctx->client_creds = GSS_C_NO_CREDENTIAL; ++ ++ /* needed for globus_gss_assist_map_and_authorize() */ ++ client->context = ctx->context; ++ + return (ctx->major); + } + +@@ -396,6 +434,7 @@ + void + ssh_gssapi_cleanup_creds(void) + { ++#ifdef KRB5 + krb5_ccache ccache = NULL; + krb5_error_code problem; + +@@ -411,6 +450,14 @@ + gssapi_client.store.data = NULL; + } + } ++#else ++ if (gssapi_client.store.filename != NULL) { ++ /* Unlink probably isn't sufficient */ ++ debug("removing gssapi cred file\"%s\"", ++ gssapi_client.store.filename); ++ unlink(gssapi_client.store.filename); ++ } ++#endif + } + + /* As user */ +@@ -418,6 +465,11 @@ + ssh_gssapi_storecreds(void) + { + if (gssapi_client.mech && gssapi_client.mech->storecreds) { ++ if (options.gss_creds_path) { ++ gssapi_client.store.filename = ++ expand_authorized_keys(options.gss_creds_path, ++ the_authctxt->pw); ++ } + (*gssapi_client.mech->storecreds)(&gssapi_client); + } else + debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism"); +@@ -441,8 +493,9 @@ + } + + /* Privileged */ ++/* gssapi_keyex arg added for Globus usage */ + int +-ssh_gssapi_userok(char *user, struct passwd *pw) ++ssh_gssapi_userok(char *user, struct passwd *pw, int gssapi_keyex) + { + OM_uint32 lmin; + +@@ -451,6 +504,12 @@ + debug("No suitable client data"); + return 0; + } ++#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG ++ if (limited && options.gsi_allow_limited_proxy != 1) { ++ debug("limited proxy not acceptable for remote login"); ++ return 0; ++ } ++#endif + if (gssapi_client.mech && gssapi_client.mech->userok) + if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { + gssapi_client.used = 1; +@@ -470,6 +529,24 @@ + return (0); + } + ++/* Priviledged */ ++int ++ssh_gssapi_localname(char **user) ++{ ++ *user = NULL; ++ if (gssapi_client.displayname.length == 0 || ++ gssapi_client.displayname.value == NULL) { ++ debug("No suitable client data"); ++ return(0); ++ } ++ if (gssapi_client.mech && gssapi_client.mech->localname) { ++ return((*gssapi_client.mech->localname)(&gssapi_client,user)); ++ } else { ++ debug("Unknown client authentication type"); ++ } ++ return(0); ++} ++ + /* These bits are only used for rekeying. The unpriviledged child is running + * as the user, the monitor is root. + * +@@ -496,6 +573,7 @@ + pam_handle_t *pamh = NULL; + struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; + char *envstr; ++ char **p; char **pw; + #endif + + if (gssapi_client.store.filename == NULL && +@@ -525,6 +603,18 @@ + if (ret) + return; + ++ /* Put ssh pam stack env variables in this new pam stack env ++ * Using pam-pkinit, KRB5CCNAME is set during do_pam_session ++ * this addition enables pam-pkinit to access KRB5CCNAME if used ++ * in sshd-rekey stack too ++ */ ++ pw = p = fetch_pam_environment(); ++ while ( *pw != NULL ) { ++ pam_putenv(pamh, *pw); ++ pw++; ++ } ++ free_pam_environment(p); ++ + xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, + gssapi_client.store.envval); + +@@ -556,4 +646,13 @@ + return ok; + } + ++/* added for Globus usage */ ++void ++ssh_gssapi_get_client_info(char **userdn, char **mech) { ++ *userdn = gssapi_client.displayname.value; ++ ++ if (gssapi_client.mech) ++ *mech = gssapi_client.mech->name; ++} ++ + #endif +diff -Nur openssh-7.2p1.orig/gss-serv-gsi.c openssh-7.2p1/gss-serv-gsi.c +--- openssh-7.2p1.orig/gss-serv-gsi.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-7.2p1/gss-serv-gsi.c 2016-03-02 19:05:41.294212882 +0100 +@@ -0,0 +1,239 @@ ++/* ++ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "includes.h" ++ ++#ifdef GSSAPI ++#ifdef GSI ++ ++#include ++ ++#include ++#include ++ ++#include "xmalloc.h" ++#include "key.h" ++#include "hostfile.h" ++#include "auth.h" ++#include "log.h" ++#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ ++#include "servconf.h" ++ ++#include "buffer.h" ++#include "ssh-gss.h" ++ ++extern ServerOptions options; ++ ++#include ++ ++static int ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name); ++static int ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user); ++static void ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client); ++static int ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store, ++ ssh_gssapi_client *client); ++ ++ssh_gssapi_mech gssapi_gsi_mech = { ++ "dZuIebMjgUqaxvbF7hDbAw==", ++ "GSI", ++ {9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"}, ++ NULL, ++ &ssh_gssapi_gsi_userok, ++ &ssh_gssapi_gsi_localname, ++ &ssh_gssapi_gsi_storecreds, ++ &ssh_gssapi_gsi_updatecreds ++}; ++ ++/* ++ * Check if this user is OK to login under GSI. User has been authenticated ++ * as identity in global 'client_name.value' and is trying to log in as passed ++ * username in 'name'. ++ * ++ * Returns non-zero if user is authorized, 0 otherwise. ++ */ ++static int ++ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name) ++{ ++ int authorized = 0; ++ globus_result_t res; ++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE ++ char lname[256] = ""; ++#endif ++ ++#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE ++ if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) { ++ return 0; ++ } ++#endif ++ ++/* use new globus_gss_assist_map_and_authorize() interface if available */ ++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE ++ debug("calling globus_gss_assist_map_and_authorize()"); ++ if (GLOBUS_SUCCESS != ++ (res = globus_gss_assist_map_and_authorize(client->context, "ssh", ++ name, lname, 256))) { ++ debug("%s", globus_error_print_chain(globus_error_get(res))); ++ } else if (lname[0] && strcmp(name, lname) != 0) { ++ debug("GSI user maps to %s, not %s", lname, name); ++ } else { ++ authorized = 1; ++ } ++#else ++ debug("calling globus_gss_assist_userok()"); ++ if (GLOBUS_SUCCESS != ++ (res = (globus_gss_assist_userok(client->displayname.value, ++ name)))) { ++ debug("%s", globus_error_print_chain(globus_error_get(res))); ++ } else { ++ authorized = 1; ++ } ++#endif ++ ++ logit("GSI user %s is%s authorized as target user %s", ++ (char *) client->displayname.value, (authorized ? "" : " not"), name); ++ ++ return authorized; ++} ++ ++/* ++ * Return the local username associated with the GSI credentials. ++ */ ++int ++ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user) ++{ ++ globus_result_t res; ++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE ++ char lname[256] = ""; ++#endif ++ ++#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE ++ if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) { ++ return 0; ++ } ++#endif ++ ++/* use new globus_gss_assist_map_and_authorize() interface if available */ ++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE ++ debug("calling globus_gss_assist_map_and_authorize()"); ++ if (GLOBUS_SUCCESS != ++ (res = globus_gss_assist_map_and_authorize(client->context, "ssh", ++ NULL, lname, 256))) { ++ debug("%s", globus_error_print_chain(globus_error_get(res))); ++ logit("failed to map GSI user %s", (char *)client->displayname.value); ++ return 0; ++ } ++ *user = strdup(lname); ++#else ++ debug("calling globus_gss_assist_gridmap()"); ++ if (GLOBUS_SUCCESS != ++ (res = globus_gss_assist_gridmap(client->displayname.value, user))) { ++ debug("%s", globus_error_print_chain(globus_error_get(res))); ++ logit("failed to map GSI user %s", (char *)client->displayname.value); ++ return 0; ++ } ++#endif ++ ++ logit("GSI user %s mapped to target user %s", ++ (char *) client->displayname.value, *user); ++ ++ return 1; ++} ++ ++/* ++ * Export GSI credentials to disk. ++ */ ++static void ++ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client) ++{ ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER; ++ char * p; ++ ++ if (!client || !client->creds) { ++ return; ++ } ++ ++ major_status = gss_export_cred(&minor_status, ++ client->creds, ++ GSS_C_NO_OID, ++ 1, ++ &export_cred); ++ if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) { ++ Gssctxt *ctx; ++ ssh_gssapi_build_ctx(&ctx); ++ ctx->major = major_status; ++ ctx->minor = minor_status; ++ ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech.oid); ++ ssh_gssapi_error(ctx); ++ ssh_gssapi_delete_ctx(&ctx); ++ return; ++ } ++ ++ p = strchr((char *) export_cred.value, '='); ++ if (p == NULL) { ++ logit("Failed to parse exported credentials string '%.100s'", ++ (char *)export_cred.value); ++ gss_release_buffer(&minor_status, &export_cred); ++ return; ++ } ++ *p++ = '\0'; ++ if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) { ++ client->store.envvar = strdup("X509_USER_PROXY"); ++ } else { ++ client->store.envvar = strdup((char *)export_cred.value); ++ } ++ if (access(p, R_OK) == 0) { ++ if (client->store.filename) { ++ if (rename(p, client->store.filename) < 0) { ++ logit("Failed to rename %s to %s: %s", p, ++ client->store.filename, strerror(errno)); ++ free(client->store.filename); ++ client->store.filename = strdup(p); ++ } else { ++ p = client->store.filename; ++ } ++ } else { ++ client->store.filename = strdup(p); ++ } ++ } ++ client->store.envval = strdup(p); ++#ifdef USE_PAM ++ if (options.use_pam) ++ do_pam_putenv(client->store.envvar, client->store.envval); ++#endif ++ gss_release_buffer(&minor_status, &export_cred); ++} ++ ++/* ++ * Export updated GSI credentials to disk. ++ */ ++static int ++ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store,ssh_gssapi_client *client) ++{ ++ ssh_gssapi_gsi_storecreds(client); ++ return 1; ++} ++ ++#endif /* GSI */ ++#endif /* GSSAPI */ +diff -Nur openssh-7.2p1.orig/gss-serv-krb5.c openssh-7.2p1/gss-serv-krb5.c +--- openssh-7.2p1.orig/gss-serv-krb5.c 2016-03-02 19:04:36.348960607 +0100 ++++ openssh-7.2p1/gss-serv-krb5.c 2016-03-02 19:05:41.295212870 +0100 +@@ -359,6 +359,34 @@ + return found_principal; + } + ++/* Retrieve the local username associated with a set of Kerberos ++ * credentials. Hopefully we can use this for the 'empty' username ++ * logins discussed in the draft */ ++static int ++ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user) { ++ krb5_principal princ; ++ int retval; ++ ++ if (ssh_gssapi_krb5_init() == 0) ++ return 0; ++ ++ if ((retval=krb5_parse_name(krb_context, client->displayname.value, ++ &princ))) { ++ logit("krb5_parse_name(): %.100s", ++ krb5_get_err_text(krb_context,retval)); ++ return 0; ++ } ++ ++ /* We've got to return a malloc'd string */ ++ *user = (char *)xmalloc(256); ++ if (krb5_aname_to_localname(krb_context, princ, 256, *user)) { ++ free(*user); ++ *user = NULL; ++ return(0); ++ } ++ ++ return(1); ++} + + /* This writes out any forwarded credentials from the structure populated + * during userauth. Called after we have setuid to the user */ +@@ -463,7 +491,7 @@ + return; + } + +-int ++static int + ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, + ssh_gssapi_client *client) + { +@@ -534,7 +562,7 @@ + {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}, + NULL, + &ssh_gssapi_krb5_userok, +- NULL, ++ &ssh_gssapi_krb5_localname, + &ssh_gssapi_krb5_storecreds, + &ssh_gssapi_krb5_updatecreds + }; +diff -Nur openssh-7.2p1.orig/kexgsss.c openssh-7.2p1/kexgsss.c +--- openssh-7.2p1.orig/kexgsss.c 2016-03-02 19:04:36.314960999 +0100 ++++ openssh-7.2p1/kexgsss.c 2016-03-02 19:05:41.295212870 +0100 +@@ -47,6 +47,7 @@ + #include "ssh-gss.h" + #include "digest.h" + ++static void kex_gss_send_error(Gssctxt *ctxt); + extern ServerOptions options; + + int +@@ -94,8 +95,10 @@ + + debug2("%s: Acquiring credentials", __func__); + +- if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) ++ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) { ++ kex_gss_send_error(ctxt); + fatal("Unable to acquire credentials for the server"); ++ } + + switch (ssh->kex->kex_type) { + case KEX_GSS_GRP1_SHA1: +@@ -181,12 +184,13 @@ + } while (maj_status & GSS_S_CONTINUE_NEEDED); + + if (GSS_ERROR(maj_status)) { ++ kex_gss_send_error(ctxt); + if (send_tok.length > 0) { + packet_start(SSH2_MSG_KEXGSS_CONTINUE); + packet_put_string(send_tok.value, send_tok.length); + packet_send(); + } +- fatal("accept_ctx died"); ++ packet_disconnect("GSSAPI Key Exchange handshake failed"); + } + + if (!(ret_flags & GSS_C_MUTUAL_FLAG)) +@@ -292,4 +296,23 @@ + ssh_gssapi_rekey_creds(); + return 0; + } ++ ++static void ++kex_gss_send_error(Gssctxt *ctxt) { ++ char *errstr; ++ OM_uint32 maj,min; ++ ++ errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min)); ++ if (errstr) { ++ packet_start(SSH2_MSG_KEXGSS_ERROR); ++ packet_put_int(maj); ++ packet_put_int(min); ++ packet_put_cstring(errstr); ++ packet_put_cstring(""); ++ packet_send(); ++ packet_write_wait(); ++ /* XXX - We should probably log the error locally here */ ++ free(errstr); ++ } ++} + #endif /* GSSAPI */ +diff -Nur openssh-7.2p1.orig/LICENSE.globus_usage openssh-7.2p1/LICENSE.globus_usage +--- openssh-7.2p1.orig/LICENSE.globus_usage 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-7.2p1/LICENSE.globus_usage 2016-03-02 19:05:41.295212870 +0100 +@@ -0,0 +1,18 @@ ++/* ++ * Portions of the Usage Metrics suport code are derived from the ++ * Globus project's GridFTP subject to the following license. ++ * ++ * Copyright 2010 University of Chicago ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ +diff -Nur openssh-7.2p1.orig/Makefile.in openssh-7.2p1/Makefile.in +--- openssh-7.2p1.orig/Makefile.in 2016-03-02 19:04:36.389960135 +0100 ++++ openssh-7.2p1/Makefile.in 2016-03-02 19:09:08.722825330 +0100 +@@ -113,8 +113,10 @@ + auth2-none.o auth2-passwd.o auth2-pubkey.o \ + monitor_mm.o monitor.o monitor_wrap.o auth-krb5.o \ + auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ ++ gss-serv-gsi.o \ + loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ + sftp-server.o sftp-common.o \ ++ ssh-globus-usage.o \ + sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ + sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \ + sandbox-solaris.o +diff -Nur openssh-7.2p1.orig/misc.c openssh-7.2p1/misc.c +--- openssh-7.2p1.orig/misc.c 2016-03-02 19:04:36.347960619 +0100 ++++ openssh-7.2p1/misc.c 2016-03-02 19:05:41.296212859 +0100 +@@ -161,11 +161,14 @@ + #define WHITESPACE " \t\r\n" + #define QUOTE "\"" + ++/* Characters considered as quotations. */ ++#define QUOTES "'\"" ++ + /* return next token in configuration line */ + char * + strdelim(char **s) + { +- char *old; ++ char *old, *p, *q; + int wspace = 0; + + if (*s == NULL) +@@ -173,6 +176,21 @@ + + old = *s; + ++ if ((q=strchr(QUOTES, (int) *old)) && *q) ++ { ++ /* find next quote character, point old to start of quoted ++ * string */ ++ for (p = ++old; *p && *p != *q; p++) ++ ; ++ ++ /* find start of next token */ ++ *s = (*p) ? p + strspn(p + 1, WHITESPACE) + 1 : NULL; ++ ++ /* terminate 'old' token */ ++ *p = '\0'; ++ return (old); ++ } ++ + *s = strpbrk(*s, WHITESPACE QUOTE "="); + if (*s == NULL) + return (old); +@@ -228,6 +246,20 @@ + return copy; + } + ++void ++pwfree(struct passwd *pw) ++{ ++ free(pw->pw_name); ++ free(pw->pw_passwd); ++ free(pw->pw_gecos); ++#ifdef HAVE_PW_CLASS_IN_PASSWD ++ free(pw->pw_class); ++#endif ++ free(pw->pw_dir); ++ free(pw->pw_shell); ++ free(pw); ++} ++ + /* + * Convert ASCII string to TCP/IP port number. + * Port must be >=0 and <=65535. +diff -Nur openssh-7.2p1.orig/misc.h openssh-7.2p1/misc.h +--- openssh-7.2p1.orig/misc.h 2016-03-02 19:04:36.335960757 +0100 ++++ openssh-7.2p1/misc.h 2016-03-02 19:05:41.296212859 +0100 +@@ -61,6 +61,7 @@ + void sock_set_v6only(int); + + struct passwd *pwcopy(struct passwd *); ++void pwfree(struct passwd *); + const char *ssh_gai_strerror(int); + + typedef struct arglist arglist; +diff -Nur openssh-7.2p1.orig/monitor.c openssh-7.2p1/monitor.c +--- openssh-7.2p1.orig/monitor.c 2016-03-02 19:04:36.396960055 +0100 ++++ openssh-7.2p1/monitor.c 2016-03-02 19:05:41.297212847 +0100 +@@ -163,6 +163,9 @@ + int mm_answer_gss_userok(int, Buffer *); + int mm_answer_gss_checkmic(int, Buffer *); + int mm_answer_gss_sign(int, Buffer *); ++int mm_answer_gss_error(int, Buffer *); ++int mm_answer_gss_indicate_mechs(int, Buffer *); ++int mm_answer_gss_localname(int, Buffer *); + int mm_answer_gss_updatecreds(int, Buffer *); + #endif + +@@ -216,7 +219,7 @@ + {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, + #endif + {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, +- {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, ++ {MONITOR_REQ_PWNAM, MON_AUTH, mm_answer_pwnamallow}, + {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, + #ifdef WITH_SELINUX + {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole}, +@@ -224,7 +227,7 @@ + {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, + {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, + #ifdef USE_PAM +- {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, ++ {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start}, + {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, + {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx}, + {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query}, +@@ -254,6 +257,9 @@ + {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, + {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, + {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, ++ {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error}, ++ {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs}, ++ {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname}, + #endif + {0, 0, NULL} + }; +@@ -263,6 +269,8 @@ + {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, + {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, + {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, ++ {MONITOR_REQ_GSSERR, 0, mm_answer_gss_error}, ++ {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs}, + {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, + #endif + #ifdef WITH_OPENSSL +@@ -303,7 +311,7 @@ + {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, + #endif + #ifdef USE_PAM +- {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, ++ {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start}, + {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, + {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx}, + {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query}, +@@ -398,6 +406,8 @@ + #ifdef GSSAPI + /* and for the GSSAPI key exchange */ + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1); ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1); + #endif + } else { + mon_dispatch = mon_dispatch_proto15; +@@ -512,6 +522,8 @@ + #ifdef GSSAPI + /* and for the GSSAPI key exchange */ + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1); ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1); + #endif + } else { + mon_dispatch = mon_dispatch_postauth15; +@@ -840,14 +852,17 @@ + + debug3("%s", __func__); + +- if (authctxt->attempt++ != 0) +- fatal("%s: multiple attempts for getpwnam", __func__); +- + username = buffer_get_string(m, NULL); + + pwent = getpwnamallow(username); + ++ if (authctxt->user) free(authctxt->user); + authctxt->user = xstrdup(username); ++#ifdef USE_PAM ++ if (options.permit_pam_user_change) ++ setproctitle("%s [priv]", pwent ? "[pam]" : "unknown"); ++ else ++#endif + setproctitle("%s [priv]", pwent ? username : "unknown"); + free(username); + +@@ -2222,12 +2237,15 @@ + mm_answer_gss_userok(int sock, Buffer *m) + { + int authenticated; ++ int gssapi_keyex; + + if (!options.gss_authentication && !options.gss_keyex) + fatal("In GSSAPI monitor when GSSAPI is disabled"); + ++ gssapi_keyex = buffer_get_int(m); ++ + authenticated = authctxt->valid && +- ssh_gssapi_userok(authctxt->user, authctxt->pw); ++ ssh_gssapi_userok(authctxt->user, authctxt->pw, gssapi_keyex); + + buffer_clear(m); + buffer_put_int(m, authenticated); +@@ -2235,12 +2253,77 @@ + debug3("%s: sending result %d", __func__, authenticated); + mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m); + +- auth_method = "gssapi-with-mic"; ++ if (gssapi_keyex) ++ auth_method = "gssapi-keyex"; ++ else ++ auth_method = "gssapi-with-mic"; + + /* Monitor loop will terminate if authenticated */ + return (authenticated); + } + ++int ++mm_answer_gss_error(int socket, Buffer *m) { ++ OM_uint32 major, minor; ++ char *msg; ++ ++ msg=ssh_gssapi_last_error(gsscontext, &major, &minor); ++ buffer_clear(m); ++ buffer_put_int(m, major); ++ buffer_put_int(m, minor); ++ buffer_put_cstring(m, msg); ++ ++ mm_request_send(socket, MONITOR_ANS_GSSERR, m); ++ ++ free(msg); ++ ++ return(0); ++} ++ ++int ++mm_answer_gss_indicate_mechs(int socket, Buffer *m) { ++ OM_uint32 major, minor; ++ gss_OID_set mech_set; ++ size_t i; ++ ++ major=gss_indicate_mechs(&minor, &mech_set); ++ ++ buffer_clear(m); ++ buffer_put_int(m, major); ++ buffer_put_int(m, mech_set->count); ++ for (i = 0; i < mech_set->count; i++) { ++ buffer_put_string(m, mech_set->elements[i].elements, ++ mech_set->elements[i].length); ++ } ++ ++ gss_release_oid_set(&minor, &mech_set); ++ ++ mm_request_send(socket, MONITOR_ANS_GSSMECHS, m); ++ ++ return(0); ++} ++ ++int ++mm_answer_gss_localname(int socket, Buffer *m) { ++ char *name; ++ ++ ssh_gssapi_localname(&name); ++ ++ buffer_clear(m); ++ if (name) { ++ buffer_put_cstring(m, name); ++ debug3("%s: sending result %s", __func__, name); ++ free(name); ++ } else { ++ buffer_put_cstring(m, ""); ++ debug3("%s: sending result \"\"", __func__); ++ } ++ ++ mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m); ++ ++ return(0); ++} ++ + int + mm_answer_gss_sign(int socket, Buffer *m) + { +diff -Nur openssh-7.2p1.orig/monitor.h openssh-7.2p1/monitor.h +--- openssh-7.2p1.orig/monitor.h 2016-03-02 19:04:36.379960251 +0100 ++++ openssh-7.2p1/monitor.h 2016-03-02 19:05:41.298212836 +0100 +@@ -75,8 +75,10 @@ + MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119, + MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121, + MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123, +- MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124 +- ++ MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, ++ MONITOR_REQ_GSSMECHS = 200, MONITOR_ANS_GSSMECHS = 201, ++ MONITOR_REQ_GSSLOCALNAME = 202, MONITOR_ANS_GSSLOCALNAME = 203, ++ MONITOR_REQ_GSSERR = 204, MONITOR_ANS_GSSERR = 205 + }; + + struct mm_master; +diff -Nur openssh-7.2p1.orig/monitor_wrap.c openssh-7.2p1/monitor_wrap.c +--- openssh-7.2p1.orig/monitor_wrap.c 2016-03-02 19:04:36.396960055 +0100 ++++ openssh-7.2p1/monitor_wrap.c 2016-03-02 19:05:41.298212836 +0100 +@@ -1121,12 +1121,13 @@ + } + + int +-mm_ssh_gssapi_userok(char *user, struct passwd *pw) ++mm_ssh_gssapi_userok(char *user, struct passwd *pw, int gssapi_keyex) + { + Buffer m; + int authenticated = 0; + + buffer_init(&m); ++ buffer_put_int(&m, gssapi_keyex); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK, +@@ -1139,6 +1140,83 @@ + return (authenticated); + } + ++char * ++mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) { ++ Buffer m; ++ OM_uint32 maj,min; ++ char *errstr; ++ ++ buffer_init(&m); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSERR, &m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSERR, &m); ++ ++ maj = buffer_get_int(&m); ++ min = buffer_get_int(&m); ++ ++ if (major) *major=maj; ++ if (minor) *minor=min; ++ ++ errstr=buffer_get_string(&m,NULL); ++ ++ buffer_free(&m); ++ ++ return(errstr); ++} ++ ++OM_uint32 ++mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set) ++{ ++ Buffer m; ++ OM_uint32 major,minor; ++ int count; ++ gss_OID_desc oid; ++ u_int length; ++ ++ buffer_init(&m); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, &m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS, ++ &m); ++ major=buffer_get_int(&m); ++ count=buffer_get_int(&m); ++ ++ gss_create_empty_oid_set(&minor,mech_set); ++ while(count-->0) { ++ oid.elements=buffer_get_string(&m,&length); ++ oid.length=length; ++ gss_add_oid_set_member(&minor,&oid,mech_set); ++ } ++ ++ buffer_free(&m); ++ ++ return(major); ++} ++ ++int ++mm_ssh_gssapi_localname(char **lname) ++{ ++ Buffer m; ++ ++ buffer_init(&m); ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m); ++ ++ debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME, ++ &m); ++ ++ *lname = buffer_get_string(&m, NULL); ++ ++ buffer_free(&m); ++ if (lname[0] == '\0') { ++ debug3("%s: gssapi identity mapping failed", __func__); ++ } else { ++ debug3("%s: gssapi identity mapped to %s", __func__, *lname); ++ } ++ ++ return(0); ++} ++ + OM_uint32 + mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) + { +diff -Nur openssh-7.2p1.orig/monitor_wrap.h openssh-7.2p1/monitor_wrap.h +--- openssh-7.2p1.orig/monitor_wrap.h 2016-03-02 19:04:36.385960182 +0100 ++++ openssh-7.2p1/monitor_wrap.h 2016-03-02 19:05:41.298212836 +0100 +@@ -62,9 +62,13 @@ + OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); + OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, + gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); +-int mm_ssh_gssapi_userok(char *user, struct passwd *); ++int mm_ssh_gssapi_userok(char *user, struct passwd *, int gssapi_keyex); + OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); + OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); ++int mm_ssh_gssapi_localname(char **user); ++OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status, ++ gss_OID_set *mech_set); ++char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min); + int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *); + #endif + +diff -Nur openssh-7.2p1.orig/readconf.c openssh-7.2p1/readconf.c +--- openssh-7.2p1.orig/readconf.c 2016-03-02 19:04:36.390960124 +0100 ++++ openssh-7.2p1/readconf.c 2016-03-02 19:05:41.299212824 +0100 +@@ -1830,13 +1830,13 @@ + if (options->challenge_response_authentication == -1) + options->challenge_response_authentication = 1; + if (options->gss_authentication == -1) +- options->gss_authentication = 0; ++ options->gss_authentication = 1; + if (options->gss_keyex == -1) +- options->gss_keyex = 0; ++ options->gss_keyex = 1; + if (options->gss_deleg_creds == -1) +- options->gss_deleg_creds = 0; ++ options->gss_deleg_creds = 1; + if (options->gss_trust_dns == -1) +- options->gss_trust_dns = 0; ++ options->gss_trust_dns = 1; + if (options->gss_renewal_rekey == -1) + options->gss_renewal_rekey = 0; + #ifdef GSSAPI +diff -Nur openssh-7.2p1.orig/readconf.h openssh-7.2p1/readconf.h +--- openssh-7.2p1.orig/readconf.h 2016-03-02 19:04:36.370960354 +0100 ++++ openssh-7.2p1/readconf.h 2016-03-02 19:05:41.299212824 +0100 +@@ -86,6 +86,8 @@ + char *host_key_alias; /* hostname alias for .ssh/known_hosts */ + char *proxy_command; /* Proxy command for connecting the host. */ + char *user; /* User to log in as. */ ++ int implicit; /* Login user was not specified. ++ Server may choose based on authctxt. */ + int escape_char; /* Escape character; -2 = none */ + + u_int num_system_hostfiles; /* Paths for /etc/ssh/ssh_known_hosts */ +diff -Nur openssh-7.2p1.orig/servconf.c openssh-7.2p1/servconf.c +--- openssh-7.2p1.orig/servconf.c 2016-03-02 19:04:36.397960043 +0100 ++++ openssh-7.2p1/servconf.c 2016-03-02 19:05:41.300212813 +0100 +@@ -75,6 +75,7 @@ + + /* Portable-specific options */ + options->use_pam = -1; ++ options->permit_pam_user_change = -1; + + /* Standard Options */ + options->num_ports = 0; +@@ -118,9 +119,11 @@ + options->kerberos_ticket_cleanup = -1; + options->kerberos_get_afs_token = -1; + options->gss_authentication=-1; ++ options->gss_deleg_creds = -1; + options->gss_keyex = -1; + options->gss_cleanup_creds = -1; + options->gss_strict_acceptor = -1; ++ options->gsi_allow_limited_proxy = -1; + options->gss_store_rekey = -1; + options->gss_kex_algorithms = NULL; + options->password_authentication = -1; +@@ -165,6 +168,8 @@ + options->chroot_directory = NULL; + options->authorized_keys_command = NULL; + options->authorized_keys_command_user = NULL; ++ options->disable_usage_stats = 0; ++ options->usage_stats_targets = NULL; + options->revoked_keys_file = NULL; + options->trusted_user_ca_keys = NULL; + options->authorized_principals_file = NULL; +@@ -210,6 +215,8 @@ + /* Portable-specific options */ + if (options->use_pam == -1) + options->use_pam = 0; ++ if (options->permit_pam_user_change == -1) ++ options->permit_pam_user_change = 0; + + /* Standard Options */ + if (options->protocol == SSH_PROTO_UNKNOWN) +@@ -296,13 +303,17 @@ + if (options->kerberos_get_afs_token == -1) + options->kerberos_get_afs_token = 0; + if (options->gss_authentication == -1) +- options->gss_authentication = 0; ++ options->gss_authentication = 1; ++ if (options->gss_deleg_creds == -1) ++ options->gss_deleg_creds = 1; + if (options->gss_keyex == -1) +- options->gss_keyex = 0; ++ options->gss_keyex = 1; + if (options->gss_cleanup_creds == -1) + options->gss_cleanup_creds = 1; + if (options->gss_strict_acceptor == -1) +- options->gss_strict_acceptor = 0; ++ options->gss_strict_acceptor = 1; ++ if (options->gsi_allow_limited_proxy == -1) ++ options->gsi_allow_limited_proxy = 0; + if (options->gss_store_rekey == -1) + options->gss_store_rekey = 0; + #ifdef GSSAPI +@@ -420,7 +431,7 @@ + typedef enum { + sBadOption, /* == unknown option */ + /* Portable-specific options */ +- sUsePAM, ++ sUsePAM, sPermitPAMUserChange, + /* Standard Options */ + sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, + sKeyRegenerationTime, sPermitRootLogin, sLogFacility, sLogLevel, +@@ -442,10 +453,14 @@ + sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes, + sHostKeyAlgorithms, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, ++ sGssDelegateCreds, ++ sGssCredsPath, ++ sGsiAllowLimitedProxy, + sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, + sGssKeyEx, sGssStoreRekey, sGssKexAlgorithms, sAcceptEnv, sPermitTunnel, + sMatch, sPermitOpen, sForceCommand, sChrootDirectory, + sUsePrivilegeSeparation, sAllowAgentForwarding, ++ sDisUsageStats, sUsageStatsTarg, + sHostCertificate, + sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, + sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser, +@@ -470,8 +485,10 @@ + /* Portable-specific options */ + #ifdef USE_PAM + { "usepam", sUsePAM, SSHCFG_GLOBAL }, ++ { "permitpamuserchange", sPermitPAMUserChange, SSHCFG_GLOBAL }, + #else + { "usepam", sUnsupported, SSHCFG_GLOBAL }, ++ { "permitpamuserchange", sUnsupported, SSHCFG_GLOBAL }, + #endif + { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL }, + /* Standard Options */ +@@ -517,7 +534,14 @@ + { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, + #ifdef GSSAPI + { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, ++ { "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_ALL }, + { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, ++ { "gssapicredentialspath", sGssCredsPath, SSHCFG_GLOBAL }, ++#ifdef GSI ++ { "gsiallowlimitedproxy", sGsiAllowLimitedProxy, SSHCFG_GLOBAL }, ++#else ++ { "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL }, ++#endif + { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, + { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, +@@ -525,7 +549,10 @@ + { "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL }, + #else + { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, ++ { "gssapidelegatecredentials", sUnsupported, SSHCFG_ALL }, + { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, ++ { "gssapicredentialspath", sUnsupported, SSHCFG_GLOBAL }, ++ { "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL }, + { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, + { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, +@@ -593,6 +620,8 @@ + { "permitopen", sPermitOpen, SSHCFG_ALL }, + { "forcecommand", sForceCommand, SSHCFG_ALL }, + { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, ++ { "disableusagestats", sDisUsageStats, SSHCFG_GLOBAL}, ++ { "usagestatstargets", sUsageStatsTarg, SSHCFG_GLOBAL}, + { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, + { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, + { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, +@@ -1048,6 +1077,10 @@ + intptr = &options->use_pam; + goto parse_flag; + ++ case sPermitPAMUserChange: ++ intptr = &options->permit_pam_user_change; ++ goto parse_flag; ++ + /* Standard Options */ + case sBadOption: + return -1; +@@ -1279,6 +1312,10 @@ + intptr = &options->gss_authentication; + goto parse_flag; + ++ case sGssDelegateCreds: ++ intptr = &options->gss_deleg_creds; ++ goto parse_flag; ++ + case sGssKeyEx: + intptr = &options->gss_keyex; + goto parse_flag; +@@ -1287,6 +1324,10 @@ + intptr = &options->gss_cleanup_creds; + goto parse_flag; + ++ case sGssCredsPath: ++ charptr = &options->gss_creds_path; ++ goto parse_filename; ++ + case sGssStrictAcceptor: + intptr = &options->gss_strict_acceptor; + goto parse_flag; +@@ -1307,6 +1348,12 @@ + options->gss_kex_algorithms = xstrdup(arg); + break; + ++#ifdef GSI ++ case sGsiAllowLimitedProxy: ++ intptr = &options->gsi_allow_limited_proxy; ++ goto parse_flag; ++#endif ++ + case sPasswordAuthentication: + intptr = &options->password_authentication; + goto parse_flag; +@@ -1777,6 +1824,35 @@ + *charptr = xstrdup(arg); + break; + ++ case sDisUsageStats: ++ arg = strdelim(&cp); ++ if (!arg || *arg == '\0') ++ fatal("%s line %d: missing value.", ++ filename, linenum); ++ if (!strcasecmp(arg, "true") || ++ !strcasecmp(arg, "enabled") || ++ !strcasecmp(arg, "yes") || ++ !strcasecmp(arg, "on") || ++ !strcasecmp(arg, "1")) ++ options->disable_usage_stats = 1; ++ else if (!strcasecmp(arg, "false") || ++ !strcasecmp(arg, "disabled") || ++ !strcasecmp(arg, "no") || ++ !strcasecmp(arg, "off") || ++ !strcasecmp(arg, "0")) ++ options->disable_usage_stats = 0; ++ else ++ fatal("Incorrect value for disable_usage_stats"); ++ break; ++ ++ case sUsageStatsTarg: ++ arg = strdelim(&cp); ++ if (!arg || *arg == '\0') ++ fatal("%s line %d: missing value.", ++ filename, linenum); ++ options->usage_stats_targets = xstrdup(arg); ++ break; ++ + case sTrustedUserCAKeys: + charptr = &options->trusted_user_ca_keys; + goto parse_filename; +@@ -2053,6 +2129,7 @@ + + M_CP_INTOPT(password_authentication); + M_CP_INTOPT(gss_authentication); ++ M_CP_INTOPT(gss_deleg_creds); + M_CP_INTOPT(rsa_authentication); + M_CP_INTOPT(pubkey_authentication); + M_CP_INTOPT(kerberos_authentication); +diff -Nur openssh-7.2p1.orig/servconf.h openssh-7.2p1/servconf.h +--- openssh-7.2p1.orig/servconf.h 2016-03-02 19:04:36.366960400 +0100 ++++ openssh-7.2p1/servconf.h 2016-03-02 19:05:41.300212813 +0100 +@@ -117,9 +117,12 @@ + * file on logout. */ + int kerberos_get_afs_token; /* If true, try to get AFS token if + * authenticated with Kerberos. */ ++ int gsi_allow_limited_proxy; /* If true, accept limited proxies */ + int gss_authentication; /* If true, permit GSSAPI authentication */ ++ int gss_deleg_creds; /* If true, store delegated GSSAPI credentials*/ + int gss_keyex; /* If true, permit GSSAPI key exchange */ + int gss_cleanup_creds; /* If true, destroy cred cache on logout */ ++ char *gss_creds_path; /* Use non-default credentials path */ + int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ + int gss_store_rekey; + char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */ +@@ -176,6 +179,7 @@ + char *adm_forced_command; + + int use_pam; /* Enable auth via PAM */ ++ int permit_pam_user_change; /* Allow PAM to change user name */ + + int permit_tun; + +@@ -184,6 +188,10 @@ + int use_kuserok; + int enable_k5users; + char *chroot_directory; ++ ++ int disable_usage_stats; ++ char *usage_stats_targets; ++ + char *revoked_keys_file; + char *trusted_user_ca_keys; + char *authorized_keys_command; +diff -Nur openssh-7.2p1.orig/ssh.1 openssh-7.2p1/ssh.1 +--- openssh-7.2p1.orig/ssh.1 2016-03-02 19:04:36.366960400 +0100 ++++ openssh-7.2p1/ssh.1 2016-03-02 19:05:41.301212801 +0100 +@@ -1407,6 +1407,18 @@ + on to new connections). + .It Ev USER + Set to the name of the user logging in. ++.It Ev X509_CERT_DIR ++Used for GSI authentication. Specifies a non-standard location for the ++CA certificates directory. ++.It Ev X509_USER_CERT ++Used for GSI authentication. Specifies a non-standard location for the ++certificate to be used for authentication to the server. ++.It Ev X509_USER_KEY ++Used for GSI authentication. Specifies a non-standard location for the ++private key to be used for authentication to the server. ++.It Ev X509_USER_PROXY ++Used for GSI authentication. Specifies a non-standard location for the ++proxy credential to be used for authentication to the server. + .El + .Pp + Additionally, +diff -Nur openssh-7.2p1.orig/ssh.c openssh-7.2p1/ssh.c +--- openssh-7.2p1.orig/ssh.c 2016-03-02 19:04:36.391960112 +0100 ++++ openssh-7.2p1/ssh.c 2016-03-02 19:05:41.301212801 +0100 +@@ -475,6 +475,32 @@ + fatal("Can't open user config file %.100s: " + "%.100s", config, strerror(errno)); + } else { ++ /* ++ * Since the config file parsing code aborts if it sees ++ * options it doesn't recognize, allow users to put ++ * options specific to compile-time add-ons in alternate ++ * config files so their primary config file will ++ * interoperate SSH versions that don't support those ++ * options. ++ */ ++#ifdef GSSAPI ++ r = snprintf(buf, sizeof buf, "%s/%s.gssapi", pw->pw_dir, ++ _PATH_SSH_USER_CONFFILE); ++ if (r > 0 && (size_t)r < sizeof(buf)) ++ (void)read_config_file(buf, pw, host, host_arg, &options, 1); ++#ifdef GSI ++ r = snprintf(buf, sizeof buf, "%s/%s.gsi", pw->pw_dir, ++ _PATH_SSH_USER_CONFFILE); ++ if (r > 0 && (size_t)r < sizeof(buf)) ++ (void)read_config_file(buf, pw, host, host_arg, &options, 1); ++#endif ++#if defined(KRB5) ++ r = snprintf(buf, sizeof buf, "%s/%s.krb", pw->pw_dir, ++ _PATH_SSH_USER_CONFFILE); ++ if (r > 0 && (size_t)r < sizeof(buf)) ++ (void)read_config_file(buf, pw, host, host_arg, &options, 1); ++#endif ++#endif + r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, + _PATH_SSH_USER_CONFFILE); + if (r > 0 && (size_t)r < sizeof(buf)) +@@ -1143,8 +1169,12 @@ + logit("FIPS mode initialized"); + } + +- if (options.user == NULL) ++ if (options.user == NULL) { + options.user = xstrdup(pw->pw_name); ++ options.implicit = 1; ++ } else { ++ options.implicit = 0; ++ } + + if (gethostname(thishost, sizeof(thishost)) == -1) + fatal("gethostname: %s", strerror(errno)); +diff -Nur openssh-7.2p1.orig/ssh_config openssh-7.2p1/ssh_config +--- openssh-7.2p1.orig/ssh_config 2016-03-02 19:04:36.318960953 +0100 ++++ openssh-7.2p1/ssh_config 2016-03-02 19:05:41.302212790 +0100 +@@ -24,10 +24,10 @@ + # RSAAuthentication yes + # PasswordAuthentication yes + # HostbasedAuthentication no +-# GSSAPIAuthentication no +-# GSSAPIDelegateCredentials no +-# GSSAPIKeyExchange no +-# GSSAPITrustDNS no ++# GSSAPIAuthentication yes ++# GSSAPIDelegateCredentials yes ++# GSSAPIKeyExchange yes ++# GSSAPITrustDNS yes + # BatchMode no + # CheckHostIP yes + # AddressFamily any +diff -Nur openssh-7.2p1.orig/ssh_config.5 openssh-7.2p1/ssh_config.5 +--- openssh-7.2p1.orig/ssh_config.5 2016-03-02 19:04:36.370960354 +0100 ++++ openssh-7.2p1/ssh_config.5 2016-03-02 19:05:41.302212790 +0100 +@@ -55,6 +55,12 @@ + user's configuration file + .Pq Pa ~/.ssh/config + .It ++GSSAPI configuration file ++.Pq Pa $HOME/.ssh/config.gssapi ++.It ++Kerberos configuration file ++.Pq Pa $HOME/.ssh/config.krb ++.It + system-wide configuration file + .Pq Pa /etc/ssh/ssh_config + .El +diff -Nur openssh-7.2p1.orig/sshconnect2.c openssh-7.2p1/sshconnect2.c +--- openssh-7.2p1.orig/sshconnect2.c 2016-03-02 19:04:36.391960112 +0100 ++++ openssh-7.2p1/sshconnect2.c 2016-03-02 19:05:41.303212778 +0100 +@@ -728,6 +728,11 @@ + int ok = 0; + const char *gss_host = NULL; + ++ if (!options.gss_authentication) { ++ verbose("GSSAPI authentication disabled."); ++ return 0; ++ } ++ + if (options.gss_server_identity) + gss_host = options.gss_server_identity; + else if (options.gss_trust_dns) { +@@ -965,6 +970,15 @@ + return 0; + } + ++#ifdef GSI ++extern ++const gss_OID_desc * const gss_mech_globus_gssapi_openssl; ++#define is_gsi_oid(oid) \ ++ (oid->length == gss_mech_globus_gssapi_openssl->length && \ ++ (memcmp(oid->elements, gss_mech_globus_gssapi_openssl->elements, \ ++ oid->length) == 0)) ++#endif ++ + int + userauth_gsskeyex(Authctxt *authctxt) + { +@@ -982,8 +996,16 @@ + return (0); + } + ++#ifdef GSI ++ if (options.implicit && is_gsi_oid(gss_kex_context->oid)) { ++ ssh_gssapi_buildmic(&b, "", authctxt->service, "gssapi-keyex"); ++ } else { ++#endif + ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, + "gssapi-keyex"); ++#ifdef GSI ++ } ++#endif + + gssbuf.value = buffer_ptr(&b); + gssbuf.length = buffer_len(&b); +@@ -994,7 +1016,15 @@ + } + + packet_start(SSH2_MSG_USERAUTH_REQUEST); ++#ifdef GSI ++ if (options.implicit && is_gsi_oid(gss_kex_context->oid)) { ++ packet_put_cstring(""); ++ } else { ++#endif + packet_put_cstring(authctxt->server_user); ++#ifdef GSI ++ } ++#endif + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_put_string(mic.value, mic.length); +diff -Nur openssh-7.2p1.orig/sshd.8 openssh-7.2p1/sshd.8 +--- openssh-7.2p1.orig/sshd.8 2016-03-02 19:04:36.352960561 +0100 ++++ openssh-7.2p1/sshd.8 2016-03-02 19:05:41.303212778 +0100 +@@ -795,6 +795,44 @@ + # A CA key, accepted for any host in *.mydomain.com or *.mydomain.org + @cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W... + .Ed ++.Sh ENVIRONMENT ++.Nm ++will normally set the following environment variables: ++.Bl -tag -width "SSH_ORIGINAL_COMMAND" ++.It Ev GLOBUS_USAGE_OPTOUT ++Setting this environment variable to "1" will disable the reporting ++of usage metrics. Usage metrics can also be disabled using the ++.Cm DisableUsageStats ++setting in ++.Xr sshd_config 5 . ++.It Ev GLOBUS_USAGE_TARGETS ++If ++.Cm UsageStatsTargets ++is not specified in ++.Xr sshd_config 5 , ++a comma-separated list of targets (without any tags specified) if ++specified in the environment variable ++.Ev GLOBUS_USAGE_TARGETS ++will be used. ++.It Ev GRIDMAP ++Applies to GSI authentication/authorization. Specifies the location of the ++gridmapfile. If not specified, the gridmap file is assumed to be available at ++/etc/grid-security/grid-mapfile for services running as root and at ++HOME/.gridmap for services running as non-root where HOME is the home directory ++of the effective user from the password file entry. ++.It Ev X509_CERT_DIR ++Used for GSI authentication. Specifies a non-standard location for the ++CA certificates directory. ++.It Ev X509_USER_CERT ++Used for GSI authentication. Specifies a non-standard location for the ++certificate to be used for authentication to the client. ++.It Ev X509_USER_KEY ++Used for GSI authentication. Specifies a non-standard location for the ++private key to be used for authentication to the client. ++.It Ev X509_USER_PROXY ++Used for GSI authentication. Specifies a non-standard location for the ++proxy credential to be used for authentication to the client. ++.El + .Sh FILES + .Bl -tag -width Ds -compact + .It Pa ~/.hushlogin +diff -Nur openssh-7.2p1.orig/sshd.c openssh-7.2p1/sshd.c +--- openssh-7.2p1.orig/sshd.c 2016-03-02 19:04:36.399960020 +0100 ++++ openssh-7.2p1/sshd.c 2016-03-02 19:05:41.304212767 +0100 +@@ -128,6 +128,7 @@ + #include "ssh-sandbox.h" + #include "version.h" + #include "ssherr.h" ++#include "ssh-globus-usage.h" + + #ifdef LIBWRAP + #include +@@ -1797,6 +1798,13 @@ + /* Fill in default values for those options not explicitly set. */ + fill_default_server_options(&options); + ++#ifdef HAVE_GLOBUS_USAGE ++ if (ssh_usage_stats_init(options.disable_usage_stats, ++ options.usage_stats_targets) != GLOBUS_SUCCESS) { ++ error("Error initializing Globus Usage Metrics, but continuing ..."); ++ } ++#endif /* HAVE_GLOBUS_USAGE */ ++ + /* challenge-response is implemented via keyboard interactive */ + if (options.challenge_response_authentication) + options.kbd_interactive_authentication = 1; +@@ -2362,7 +2370,7 @@ + #endif + + #ifdef GSSAPI +- if (options.gss_authentication) { ++ if (options.gss_authentication && options.gss_deleg_creds) { + temporarily_use_uid(authctxt->pw); + ssh_gssapi_storecreds(); + restore_uid(); +diff -Nur openssh-7.2p1.orig/sshd_config openssh-7.2p1/sshd_config +--- openssh-7.2p1.orig/sshd_config 2016-03-02 19:04:36.361960458 +0100 ++++ openssh-7.2p1/sshd_config 2016-03-02 19:05:41.304212767 +0100 +@@ -90,10 +90,11 @@ + #KerberosUseKuserok yes + + # GSSAPI options +-GSSAPIAuthentication yes ++#GSSAPIAuthentication yes ++#GSSAPIDelegateCredentials yes + GSSAPICleanupCredentials no + #GSSAPIStrictAcceptorCheck yes +-#GSSAPIKeyExchange no ++#GSSAPIKeyExchange yes + #GSSAPIEnablek5users no + + # Set this to 'yes' to enable PAM authentication, account processing, +@@ -109,6 +110,10 @@ + # problems. + UsePAM yes + ++# Set to 'yes' to allow the PAM stack to change the user name during ++# calls to authentication ++#PermitPAMUserChange no ++ + #AllowAgentForwarding yes + #AllowTcpForwarding yes + #GatewayPorts no +@@ -151,3 +156,6 @@ + # AllowTcpForwarding no + # PermitTTY no + # ForceCommand cvs server ++ ++# Usage Metrics ++#UsageStatsTargets usage-stats.example.edu:4810 +diff -Nur openssh-7.2p1.orig/sshd_config.5 openssh-7.2p1/sshd_config.5 +--- openssh-7.2p1.orig/sshd_config.5 2016-03-02 19:04:36.367960389 +0100 ++++ openssh-7.2p1/sshd_config.5 2016-03-02 19:07:15.338130138 +0100 +@@ -570,6 +570,15 @@ + See PATTERNS in + .Xr ssh_config 5 + for more information on patterns. ++.It Cm DisableUsageStats ++This keyword can be followed by one of the keywords "true", "enabled", "yes", ++"on" or "1" to disable reporting of usage metrics. Or it can be set to "false", ++"disabled", "no", "off", "0" to enable reporting of usage metrics. Setting the ++.Cm GLOBUS_USAGE_OPTOUT ++environment variable to "1" will also disable the reporting of usage metrics. ++Disabling reporting of usage metrics will cause the ++.Cm UsageStatsTargets ++setting to be ignored. + .It Cm FingerprintHash + Specifies the hash algorithm used when logging key fingerprints. + Valid options are: +@@ -623,6 +632,10 @@ + Specifies whether user authentication based on GSSAPI is allowed. + The default is + .Dq no . ++.It Cm GSSAPIDelegateCredentials ++Specifies whether delegated credentials are stored in the user's environment. ++The default is ++.Dq yes . + .It Cm GSSAPIKeyExchange + Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange + doesn't rely on ssh keys to verify host identity. +@@ -639,6 +652,22 @@ + .Xr ksu 1 . + The default is + .Dq no . ++.It Cm GSSAPICredentialsPath ++If specified, the delegated GSSAPI credential is stored in the ++given path, overwriting any existing credentials. ++Paths can be specified with syntax similar to the AuthorizedKeysFile ++option (i.e., accepting %h and %u tokens). ++When using this option, ++setting 'GssapiCleanupCredentials no' is recommended, ++so logging out of one session ++doesn't remove the credentials in use by another session of ++the same user. ++Currently only implemented for the GSI mechanism. ++.It Cm GSIAllowLimitedProxy ++Specifies whether to accept limited proxy credentials for ++authentication. ++The default is ++.Dq no . + .It Cm GSSAPIStrictAcceptorCheck + Determines whether to be strict about the identity of the GSSAPI acceptor + a client authenticates against. +@@ -1552,6 +1581,103 @@ + .Pp + To disable TCP keepalive messages, the value should be set to + .Dq no . ++.It Cm UsageStatsTargets ++This option can be used to specify the target collector hosts to which usage ++metrics should be reported. This setting will be ignored if ++.Cm DisableUsageStats ++is enabled. Multiple targets can be specified separated by comma(s), but no ++space(s). Each target specification is of the format ++.Pa host:port[!tags]. ++Tags control what data elements are reported. The following list specifies ++the tags for the corresponding data elements. ++.Pp ++.Bl -item -offset indent -compact ++.It ++.Cm V ++.Sm off ++- OpenSSH version, reported by default. ++.Sm on ++.It ++.Cm v ++.Sm off ++- SSL version, reported by default. ++.Sm on ++.It ++.Cm M ++.Sm off ++- User authentication method used such as "gssapi-keyex", "gssapi-with-mic", etc. Reported by default. ++.Sm on ++.It ++.Cm m ++.Sm off ++- User authentication mechanism used such as "GSI", "Kerberos", etc. Reported by default. ++.Sm on ++.It ++.Cm I ++.Sm off ++- Client IP address. Not reported by default. ++.Sm on ++.It ++.Cm u ++.Sm off ++- User name. Not reported by default. ++.Sm on ++.It ++.Cm U ++.Sm off ++- User DN. Not reported by default. ++.Sm on ++.Pp ++In addition to the above selected information, the following data are ++reported to ALL the specified/default target collectors. There's no way to ++exclude these from being reported other than by disabling the reporting of ++usage metrics altogether: ++.Pp ++.It ++.Cm Component code ++.Sm off ++- 12 for GSI OpenSSH ++.Sm on ++.It ++.Cm Component Data Format version ++.Sm off ++- 0 currently ++.Sm on ++.It ++.Cm IP Address ++.Sm off ++- IP address of reporting server ++.Sm on ++.It ++.Cm Timestamp ++.It ++.Cm Hostname ++.Sm off ++- Host name of reporting server ++.Sm on ++.Pp ++If no tags are specified in a host spec, or the special string ++.Dq default ++is specified, the tags ++.Dq VvMm ++are assumed. A site could choose to allow a ++different set of data to be reported by specifying a different tag set. The ++last 3 tags ++.Dq I , ++.Dq u ++and ++.Dq U ++above are more meant for a local collector that a ++site might like to deploy since they could be construed as private information. ++The special string ++.Dq all ++denotes all tags. ++.El ++.Pp ++Usage Metrics reporting is disabled unless ++.Cm UsageStatsTargets ++is specified. ++.Pp + .It Cm TrustedUserCAKeys + Specifies a file containing public keys of certificate authorities that are + trusted to sign user certificates for authentication, or +@@ -1628,6 +1754,12 @@ + as a non-root user. + The default is + .Dq no . ++.It Cm PermitPAMUserChange ++If set to ++.Dq yes ++this will enable PAM authentication to change the name of the user being ++authenticated. The default is ++.Dq no . + .It Cm UsePrivilegeSeparation + Specifies whether + .Xr sshd 8 +diff -Nur openssh-7.2p1.orig/ssh-globus-usage.c openssh-7.2p1/ssh-globus-usage.c +--- openssh-7.2p1.orig/ssh-globus-usage.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-7.2p1/ssh-globus-usage.c 2016-03-02 19:05:41.306212744 +0100 +@@ -0,0 +1,396 @@ ++/* ++ * Copyright 2009 The Board of Trustees of the University ++ * of Illinois. See the LICENSE file for detailed license information. ++ * ++ * Portions, specifically log_usage_stats(), ssh_usage_stats_init(), ++ * ssh_usage_stats_close(), ssh_usage_ent_s, ssh_usage_tag_e and ++ * TAG #defines were based on those from Usage Metrics portions of: ++ * gridftp/server/source/globus_i_gfs_log.c ++ * ++ * Copyright 1999-2006 University of Chicago ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#include "includes.h" ++ ++#ifdef HAVE_GLOBUS_USAGE ++ ++#include ++#include ++ ++#include "log.h" ++#include "ssh-globus-usage.h" ++ ++static globus_list_t *usage_handle_list = NULL; ++ ++#define SSH_GLOBUS_USAGE_ID 12 ++#define SSH_GLOBUS_USAGE_VER 0 ++ ++#define SSH_GLOBUS_DEFAULT_TAGLIST "VvMm" ++#define SSH_GLOBUS_ALL_TAGLIST "VvMmIuU" ++#define SSH_GLOBUS_TAGCOUNT 25 ++ ++typedef enum ssh_usage_tag_e ++{ ++ SSH_GLOBUS_USAGE_SSH_VER = 'V', ++ SSH_GLOBUS_USAGE_SSL_VER = 'v', ++ SSH_GLOBUS_USAGE_METHOD = 'M', ++ SSH_GLOBUS_USAGE_MECHANISM = 'm', ++ SSH_GLOBUS_USAGE_CLIENTIP = 'I', ++ SSH_GLOBUS_USAGE_USERNAME = 'u', ++ SSH_GLOBUS_USAGE_USERDN = 'U' ++ /* !! ADD to ALL_TAGLIST above and to globus_usage_stats_send() ++ invocation below when adding here */ ++} ssh_usage_tag_t; ++ ++typedef struct ssh_usage_ent_s ++{ ++ globus_usage_stats_handle_t handle; ++ char * target; ++ char * taglist; ++} ssh_usage_ent_t; ++ ++ ++globus_result_t ++ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets) ++{ ++ globus_result_t result; ++ char * target_str = NULL; ++ char * ptr = ptr; ++ char * target = NULL; ++ char * entry = NULL; ++ globus_list_t * list = NULL; ++ ssh_usage_ent_t * usage_ent = NULL; ++ ++ if (disable_usage_stats || !usage_stats_targets) ++ return GLOBUS_SUCCESS; ++ ++ result = globus_module_activate(GLOBUS_USAGE_MODULE); ++ if (result != GLOBUS_SUCCESS) ++ { ++ error("ERROR: couldn't activate USAGE STATS module"); ++ return result; ++ } ++ ++ target_str = strdup(usage_stats_targets); ++ if (target_str == NULL) ++ { ++ error("ERROR: strdup failure for target_str"); ++ goto error; ++ } ++ debug("Processing usage_stats_target (%s)\n", target_str); ++ ++ if(target_str && (strchr(target_str, ',') || strchr(target_str, '!'))) ++ { ++ target = target_str; ++ ++ do { ++ usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t)); ++ if (usage_ent == NULL) ++ { ++ error("ERROR: couldn't allocate for ssh_usage_ent_t"); ++ goto error; ++ } ++ ++ if ((ptr = strchr(target, ',')) != NULL) ++ *ptr = '\0'; ++ ++ entry = strdup(target); ++ if (entry == NULL) ++ { ++ error("ERROR: strdup failure for target"); ++ goto error; ++ } ++ ++ if (ptr) ++ target = ptr + 1; ++ else ++ target = NULL; ++ ++ if((ptr = strchr(entry, '!')) != NULL) ++ { ++ *ptr = '\0'; ++ usage_ent->taglist = strdup(ptr + 1); ++ if (usage_ent->taglist == NULL) ++ { ++ error("ERROR: strdup failure for taglist"); ++ goto error; ++ } ++ if(strlen(usage_ent->taglist) > SSH_GLOBUS_TAGCOUNT) ++ { ++ usage_ent->taglist[SSH_GLOBUS_TAGCOUNT + 1] = '\0'; ++ } ++ } ++ else ++ { ++ usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST); ++ if (usage_ent->taglist == NULL) ++ { ++ error("ERROR: couldn't allocate for taglist"); ++ goto error; ++ } ++ } ++ ++ if(strcasecmp(usage_ent->taglist, "default") == 0) ++ { ++ free(usage_ent->taglist); ++ usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST); ++ if (usage_ent->taglist == NULL) ++ { ++ error("ERROR: couldn't allocate for taglist"); ++ goto error; ++ } ++ } ++ else if(strcasecmp(usage_ent->taglist, "all") == 0) ++ { ++ free(usage_ent->taglist); ++ usage_ent->taglist = strdup(SSH_GLOBUS_ALL_TAGLIST); ++ if (usage_ent->taglist == NULL) ++ { ++ error("ERROR: couldn't allocate for taglist"); ++ goto error; ++ } ++ } ++ ++ usage_ent->target = entry; ++ ++ globus_list_insert(&usage_handle_list, usage_ent); ++ } ++ while(target != NULL); ++ ++ free(target_str); ++ } ++ else ++ { ++ usage_ent = (ssh_usage_ent_t *) malloc(sizeof(ssh_usage_ent_t)); ++ if (usage_ent == NULL) ++ { ++ error("ERROR: couldn't allocate for usage_ent"); ++ goto error; ++ } ++ ++ usage_ent->target = target_str; ++ usage_ent->taglist = strdup(SSH_GLOBUS_DEFAULT_TAGLIST); ++ if (usage_ent->taglist == NULL) ++ { ++ error("ERROR: couldn't allocate for taglist"); ++ goto error; ++ } ++ ++ globus_list_insert(&usage_handle_list, usage_ent); ++ } ++ ++ result = GLOBUS_SUCCESS; ++ for(list = usage_handle_list; ++ !globus_list_empty(list); ++ list = globus_list_rest(list)) ++ { ++ usage_ent = (ssh_usage_ent_t *) globus_list_first(list); ++ ++ usage_ent->handle = NULL; ++ if (globus_usage_stats_handle_init( ++ &usage_ent->handle, ++ SSH_GLOBUS_USAGE_ID, ++ SSH_GLOBUS_USAGE_VER, ++ usage_ent->target) != GLOBUS_SUCCESS) ++ { ++ error("USAGE-STATS: Error initializing (%s) (%s)", ++ usage_ent->target?:"NULL", ++ usage_ent->taglist?:"NULL"); ++ result = GLOBUS_FAILURE; ++ } else ++ debug("USAGE-STATS: Initialized (%s) (%s)", usage_ent->target?:"NULL", ++ usage_ent->taglist?:"NULL"); ++ ++ } ++ ++ return result; ++ ++error: ++ if (target_str) ++ { ++ free(target_str); ++ target_str = NULL; ++ } ++ if (entry) ++ { ++ free(target_str); ++ target_str = NULL; ++ } ++ return GLOBUS_FAILURE; ++} ++ ++void ++ssh_usage_stats_close(int disable_usage_stats) ++{ ++ globus_list_t *list; ++ ++ if (disable_usage_stats) ++ return; ++ ++ list = usage_handle_list; ++ ++ while(!globus_list_empty(list)) ++ { ++ ssh_usage_ent_t *usage_ent; ++ ++ usage_ent = (ssh_usage_ent_t *) ++ globus_list_remove(&list, list); ++ ++ if(usage_ent) ++ { ++ if(usage_ent->handle) ++ { ++ globus_usage_stats_handle_destroy(usage_ent->handle); ++ } ++ if(usage_ent->target) ++ { ++ free(usage_ent->target); ++ } ++ if(usage_ent->taglist) ++ { ++ free(usage_ent->taglist); ++ } ++ free(usage_ent); ++ } ++ } ++ usage_handle_list = NULL; ++} ++ ++static void ++log_usage_stats(const char *ssh_release, const char *ssl_release, ++ const char *method, const char *mechanism, ++ const char *clientip, ++ const char *username, const char *userdn) ++{ ++ globus_result_t result; ++ globus_list_t * list; ++ ssh_usage_ent_t * usage_ent; ++ char * keys[SSH_GLOBUS_TAGCOUNT]; ++ char * values[SSH_GLOBUS_TAGCOUNT]; ++ char * ptr; ++ char * key; ++ char * value; ++ int i = 0; ++ char * save_taglist = NULL; ++ ++ for(list = usage_handle_list; ++ !globus_list_empty(list); ++ list = globus_list_rest(list)) ++ { ++ usage_ent = (ssh_usage_ent_t *) globus_list_first(list); ++ ++ if(!usage_ent || usage_ent->handle == NULL) ++ continue; ++ ++ if(save_taglist == NULL || ++ strcmp(save_taglist, usage_ent->taglist) != 0) ++ { ++ save_taglist = usage_ent->taglist; ++ ++ ptr = usage_ent->taglist; ++ i = 0; ++ while(ptr && *ptr) ++ { ++ switch(*ptr) ++ { ++ case SSH_GLOBUS_USAGE_SSH_VER: ++ key = "SSH_VER"; ++ value = (char *) ssh_release; ++ break; ++ ++ case SSH_GLOBUS_USAGE_SSL_VER: ++ key = "SSL_VER"; ++ value = (char *) ssl_release; ++ break; ++ ++ case SSH_GLOBUS_USAGE_METHOD: ++ key = "METHOD"; ++ value = (char *) method; ++ break; ++ ++ case SSH_GLOBUS_USAGE_MECHANISM: ++ key = "MECH"; ++ value = (char *) mechanism?:""; ++ break; ++ ++ case SSH_GLOBUS_USAGE_CLIENTIP: ++ key = "CLIENTIP"; ++ value = (char *) clientip?:""; ++ break; ++ ++ case SSH_GLOBUS_USAGE_USERNAME: ++ key = "USER"; ++ value = (char *) username?:""; ++ break; ++ ++ case SSH_GLOBUS_USAGE_USERDN: ++ key = "USERDN"; ++ value = (char *) userdn?:""; ++ break; ++ ++ default: ++ key = NULL; ++ value = NULL; ++ break; ++ } ++ ++ if(key != NULL && value != NULL) ++ { ++ keys[i] = key; ++ values[i] = value; ++ i++; ++ } ++ ++ ptr++; ++ } ++ } ++ ++#ifdef HAVE_GLOBUS_USAGE_SEND_ARRAY ++ result = globus_usage_stats_send_array( ++ usage_ent->handle, i, keys, values); ++#else ++ if (i) ++ result = globus_usage_stats_send( ++ usage_ent->handle, i, ++ i>0?keys[0]:NULL, i>0?values[0]:NULL, ++ i>1?keys[1]:NULL, i>1?values[1]:NULL, ++ i>2?keys[2]:NULL, i>2?values[2]:NULL, ++ i>3?keys[3]:NULL, i>3?values[3]:NULL, ++ i>4?keys[4]:NULL, i>4?values[4]:NULL, ++ i>5?keys[5]:NULL, i>5?values[5]:NULL, ++ i>6?keys[6]:NULL, i>6?values[6]:NULL); ++#endif /* HAVE_GLOBUS_USAGE_SEND_ARRAY */ ++ } ++ ++ return; ++} ++#endif /* HAVE_GLOBUS_USAGE */ ++ ++void ++ssh_globus_send_usage_metrics(const char *ssh_release, ++ const char *ssl_release, ++ const char *method, ++ const char *mechanism, ++ const char *client_ip, ++ const char *username, ++ const char *userdn) ++{ ++#ifdef HAVE_GLOBUS_USAGE ++ ++ log_usage_stats(ssh_release, ssl_release, method, mechanism, ++ client_ip, username, userdn); ++ ++#endif /* HAVE_GLOBUS_USAGE */ ++} +diff -Nur openssh-7.2p1.orig/ssh-globus-usage.h openssh-7.2p1/ssh-globus-usage.h +--- openssh-7.2p1.orig/ssh-globus-usage.h 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-7.2p1/ssh-globus-usage.h 2016-03-02 19:05:41.306212744 +0100 +@@ -0,0 +1,48 @@ ++/* ++ * Copyright 2009 The Board of Trustees of the University ++ * of Illinois. See the LICENSE file for detailed license information. ++ * ++ * Portions, specifically ssh_usage_stats_init(), ssh_usage_stats_close() ++ * were based on those from: gridftp/server/source/globus_i_gfs_log.h ++ * Copyright 1999-2006 University of Chicago ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef __SSH_GLOBUS_USAGE_H ++#define __SSH_GLOBUS_USAGE_H ++ ++#include "includes.h" ++ ++#ifdef HAVE_GLOBUS_USAGE ++ ++#include "globus_usage.h" ++ ++globus_result_t ++ssh_usage_stats_init(int disable_usage_stats, char *usage_stats_targets); ++ ++void ++ssh_usage_stats_close(int disable_usage_stats); ++ ++#endif /* HAVE_GLOBUS_USAGE */ ++ ++void ++ssh_globus_send_usage_metrics(const char *ssh_release, ++ const char *ssl_release, ++ const char *method, ++ const char *mechanism, ++ const char *client_ip, ++ const char *username, ++ const char *userdn); ++ ++#endif /* __SSH_GLOBUS_USAGE_H */ +diff -Nur openssh-7.2p1.orig/ssh-gss.h openssh-7.2p1/ssh-gss.h +--- openssh-7.2p1.orig/ssh-gss.h 2016-03-02 19:04:36.367960389 +0100 ++++ openssh-7.2p1/ssh-gss.h 2016-03-02 19:05:41.306212744 +0100 +@@ -95,6 +95,7 @@ + gss_name_t name; + struct ssh_gssapi_mech_struct *mech; + ssh_gssapi_ccache store; ++ gss_ctx_id_t context; /* needed for globus_gss_assist_map_and_authorize() */ + int used; + int updated; + } ssh_gssapi_client; +@@ -115,7 +116,7 @@ + OM_uint32 minor; /* both */ + gss_ctx_id_t context; /* both */ + gss_name_t name; /* both */ +- gss_OID oid; /* client */ ++ gss_OID oid; /* both */ + gss_cred_id_t creds; /* server */ + gss_name_t client; /* server */ + gss_cred_id_t client_creds; /* both */ +@@ -148,6 +149,9 @@ + OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); + int ssh_gssapi_credentials_updated(Gssctxt *); + ++int ssh_gssapi_localname(char **name); ++void ssh_gssapi_rekey_creds(); ++ + /* In the server */ + typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, + const char *); +@@ -158,7 +162,7 @@ + int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, + const char *); + OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); +-int ssh_gssapi_userok(char *name, struct passwd *); ++int ssh_gssapi_userok(char *name, struct passwd *, int gssapi_keyex); + 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); +@@ -170,6 +174,7 @@ + int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); + + void ssh_gssapi_rekey_creds(void); ++void ssh_gssapi_get_client_info(char **userdn, char **mech); + #endif /* GSSAPI */ + + #endif /* _SSH_GSS_H */ +diff -Nur openssh-7.2p1.orig/version.h openssh-7.2p1/version.h +--- openssh-7.2p1.orig/version.h 2016-02-26 04:40:04.000000000 +0100 ++++ openssh-7.2p1/version.h 2016-03-02 19:10:52.953628948 +0100 +@@ -1,6 +1,21 @@ + /* $OpenBSD: version.h,v 1.76 2016/02/23 09:14:34 djm Exp $ */ + ++#ifdef GSI ++#define GSI_VERSION " GSI" ++#else ++#define GSI_VERSION "" ++#endif ++ ++#ifdef KRB5 ++#define KRB5_VERSION " KRB5" ++#else ++#define KRB5_VERSION "" ++#endif ++ ++#define NCSA_VERSION " GSI_GSSAPI_20150812" ++ + #define SSH_VERSION "OpenSSH_7.2" + + #define SSH_PORTABLE "p2" +-#define SSH_RELEASE SSH_VERSION SSH_PORTABLE ++#define SSH_RELEASE SSH_VERSION SSH_PORTABLE \ ++ NCSA_VERSION GSI_VERSION KRB5_VERSION diff --git a/sources b/sources index 03053e3..7c814f0 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -b984775f0cfff1f7ff18b8797fce8a28 openssh-7.2p1.tar.gz +13009a9156510d8f27e752659075cced openssh-7.2p2.tar.gz