diff -Naur --exclude=autom4te.cache openssh-6.6p1/ChangeLog.gssapi openssh-6.6p1-gssapi/ChangeLog.gssapi --- openssh-6.6p1/ChangeLog.gssapi 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/ChangeLog.gssapi 2014-03-18 15:05:44.000000000 -0500 @@ -0,0 +1,113 @@ +20110101 + - Finally update for OpenSSH 5.6p1 + - Add GSSAPIServerIdentity option from Jim Basney + +20100308 + - [ Makefile.in, key.c, key.h ] + Updates for OpenSSH 5.4p1 + - [ servconf.c ] + Include GSSAPI options in the sshd -T configuration dump, and flag + some older configuration options as being unsupported. Thanks to Colin + Watson. + - + +20100124 + - [ sshconnect2.c ] + Adapt to deal with additional element in Authmethod structure. Thanks to + Colin Watson + +20090615 + - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c + sshd.c ] + Fix issues identified by Greg Hudson following a code review + Check return value of gss_indicate_mechs + Protect GSSAPI calls in monitor, so they can only be used if enabled + Check return values of bignum functions in key exchange + Use BN_clear_free to clear other side's DH value + Make ssh_gssapi_id_kex more robust + Only configure kex table pointers if GSSAPI is enabled + Don't leak mechanism list, or gss mechanism list + Cast data.length before printing + If serverkey isn't provided, use an empty string, rather than NULL + +20090201 + - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h + ssh_config.5 sshconnet2.c ] + Add support for the GSSAPIClientIdentity option, which allows the user + to specify which GSSAPI identity to use to contact a given server + +20080404 + - [ gss-serv.c ] + Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow + been omitted from a previous version of this patch. Reported by Borislav + Stoichkov + +20070317 + - [ gss-serv-krb5.c ] + Remove C99ism, where new_ccname was being declared in the middle of a + function + +20061220 + - [ servconf.c ] + Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and + documented, behaviour. Reported by Dan Watson. + +20060910 + - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c + ssh-gss.h ] + add support for gss-group14-sha1 key exchange mechanisms + - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ] + Add GSSAPIStrictAcceptorCheck option to allow the disabling of + acceptor principal checking on multi-homed machines. + + - [ sshd_config ssh_config ] + Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample + configuration files + - [ kexgss.c kegsss.c sshconnect2.c sshd.c ] + Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf() + Limit length of error messages displayed by client + +20060909 + - [ gss-genr.c gss-serv.c ] + move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server + only, where they belong + + +20060829 + - [ gss-serv-krb5.c ] + Fix CCAPI credentials cache name when creating KRB5CCNAME environment + variable + +20060828 + - [ gss-genr.c ] + Avoid Heimdal context freeing problem + + +20060818 + - [ gss-genr.c ssh-gss.h sshconnect2.c ] + Make sure that SPENGO is disabled + + +20060421 + - [ gssgenr.c, sshconnect2.c ] + a few type changes (signed versus unsigned, int versus size_t) to + fix compiler errors/warnings + (from jbasney AT ncsa.uiuc.edu) + - [ kexgssc.c, sshconnect2.c ] + fix uninitialized variable warnings + (from jbasney AT ncsa.uiuc.edu) + - [ gssgenr.c ] + pass oid to gss_display_status (helpful when using GSSAPI mechglue) + (from jbasney AT ncsa.uiuc.edu) + + - [ gss-serv-krb5.c ] + #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H + (from jbasney AT ncsa.uiuc.edu) + + - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c + add client-side GssapiKeyExchange option + (from jbasney AT ncsa.uiuc.edu) + - [ sshconnect2.c ] + add support for GssapiTrustDns option for gssapi-with-mic + (from jbasney AT ncsa.uiuc.edu) + diff -Naur --exclude=autom4te.cache openssh-6.6p1/HPN-README openssh-6.6p1-gssapi/HPN-README --- openssh-6.6p1/HPN-README 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/HPN-README 2014-03-18 15:05:44.000000000 -0500 @@ -0,0 +1,128 @@ +Notes: + +MULTI-THREADED CIPHER: +The AES cipher in CTR mode has been multithreaded (MTR-AES-CTR). This will allow ssh installations +on hosts with multiple cores to use more than one processing core during encryption. +Tests have show significant throughput performance increases when using MTR-AES-CTR up +to and including a full gigabit per second on quad core systems. It should be possible to +achieve full line rate on dual core systems but OS and data management overhead makes this +more difficult to achieve. The cipher stream from MTR-AES-CTR is entirely compatible with single +thread AES-CTR (ST-AES-CTR) implementations and should be 100% backward compatible. Optimal +performance requires the MTR-AES-CTR mode be enabled on both ends of the connection. +The MTR-AES-CTR replaces ST-AES-CTR and is used in exactly the same way with the same +nomenclature. +Use examples: ssh -caes128-ctr you@host.com + scp -oCipher=aes256-ctr file you@host.com:~/file + +NONE CIPHER: +To use the NONE option you must have the NoneEnabled switch set on the server and +you *must* have *both* NoneEnabled and NoneSwitch set to yes on the client. The NONE +feature works with ALL ssh subsystems (as far as we can tell) *AS LONG AS* a tty is not +spawned. If a user uses the -T switch to prevent a tty being created the NONE cipher will +be disabled. + +The performance increase will only be as good as the network and TCP stack tuning +on the reciever side of the connection allows. As a rule of thumb a user will need +at least 10Mb/s connection with a 100ms RTT to see a doubling of performance. The +HPN-SSH home page describes this in greater detail. + +http://www.psc.edu/networking/projects/hpn-ssh + +BUFFER SIZES: + +If HPN is disabled the receive buffer size will be set to the +OpenSSH default of 64K. + +If an HPN system connects to a nonHPN system the receive buffer will +be set to the HPNBufferSize value. The default is 2MB but user adjustable. + +If an HPN to HPN connection is established a number of different things might +happen based on the user options and conditions. + +Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set +HPN Buffer Size = up to 64MB +This is the default state. The HPN buffer size will grow to a maximum of 64MB +as the TCP receive buffer grows. The maximum HPN Buffer size of 64MB is +geared towards 10GigE transcontinental connections. + +Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set +HPN Buffer Size = TCP receive buffer value. +Users on non-autotuning systesm should disable TCPRcvBufPoll in the +ssh_cofig and sshd_config + +Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set +HPN Buffer Size = minmum of TCP receive buffer and HPNBufferSize. +This would be the system defined TCP receive buffer (RWIN). + +Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf SET +HPN Buffer Size = minmum of TCPRcvBuf and HPNBufferSize. +Generally there is no need to set both. + +Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set +HPN Buffer Size = grows to HPNBufferSize +The buffer will grow up to the maximum size specified here. + +Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf SET +HPN Buffer Size = minmum of TCPRcvBuf and HPNBufferSize. +Generally there is no need to set both of these, especially on autotuning +systems. However, if the users wishes to override the autotuning this would be +one way to do it. + +Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf SET +HPN Buffer Size = TCPRcvBuf. +This will override autotuning and set the TCP recieve buffer to the user defined +value. + + +HPN Specific Configuration options + +TcpRcvBuf=[int]KB client + set the TCP socket receive buffer to n Kilobytes. It can be set up to the +maximum socket size allowed by the system. This is useful in situations where +the tcp receive window is set low but the maximum buffer size is set +higher (as is typical). This works on a per TCP connection basis. You can also +use this to artifically limit the transfer rate of the connection. In these +cases the throughput will be no more than n/RTT. The minimum buffer size is 1KB. +Default is the current system wide tcp receive buffer size. + +TcpRcvBufPoll=[yes/no] client/server + enable of disable the polling of the tcp receive buffer through the life +of the connection. You would want to make sure that this option is enabled +for systems making use of autotuning kernels (linux 2.4.24+, 2.6, MS Vista) +default is yes. + +NoneEnabled=[yes/no] client/server + enable or disable the use of the None cipher. Care must always be used +when enabling this as it will allow users to send data in the clear. However, +it is important to note that authentication information remains encrypted +even if this option is enabled. Set to no by default. + +NoneSwitch=[yes/no] client + Switch the encryption cipher being used to the None cipher after +authentication takes place. NoneEnabled must be enabled on both the client +and server side of the connection. When the connection switches to the NONE +cipher a warning is sent to STDERR. The connection attempt will fail with an +error if a client requests a NoneSwitch from the server that does not explicitly +have NoneEnabled set to yes. Note: The NONE cipher cannot be used in +interactive (shell) sessions and it will fail silently. Set to no by default. + +HPNDisabled=[yes/no] client/server + In some situations, such as transfers on a local area network, the impact +of the HPN code produces a net decrease in performance. In these cases it is +helpful to disable the HPN functionality. By default HPNDisabled is set to no. + +HPNBufferSize=[int]KB client/server + This is the default buffer size the HPN functionality uses when interacting +with nonHPN SSH installations. Conceptually this is similar to the TcpRcvBuf +option as applied to the internal SSH flow control. This value can range from +1KB to 64MB (1-65536). Use of oversized or undersized buffers can cause performance +problems depending on the length of the network path. The default size of this buffer +is 2MB. + + +Credits: This patch was conceived, designed, and led by Chris Rapier (rapier@psc.edu) + The majority of the actual coding for versions up to HPN12v1 was performed + by Michael Stevens (mstevens@andrew.cmu.edu). The MT-AES-CTR cipher was + implemented by Ben Bennet (ben@psc.edu). This work was financed, in part, + by Cisco System, Inc., the National Library of Medicine, + and the National Science Foundation. diff -Naur --exclude=autom4te.cache openssh-6.6p1/LICENSE.globus_usage openssh-6.6p1-gssapi/LICENSE.globus_usage --- openssh-6.6p1/LICENSE.globus_usage 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/LICENSE.globus_usage 2014-03-18 15:05:44.000000000 -0500 @@ -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 -Naur --exclude=autom4te.cache openssh-6.6p1/Makefile.in openssh-6.6p1-gssapi/Makefile.in --- openssh-6.6p1/Makefile.in 2014-02-03 18:12:56.000000000 -0600 +++ openssh-6.6p1-gssapi/Makefile.in 2014-03-18 15:05:44.000000000 -0500 @@ -43,7 +43,7 @@ LD=@LD@ CFLAGS=@CFLAGS@ CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ -LIBS=@LIBS@ +LIBS=@LIBS@ -lpthread K5LIBS=@K5LIBS@ GSSLIBS=@GSSLIBS@ SSHLIBS=@SSHLIBS@ @@ -61,6 +61,8 @@ EXEEXT=@EXEEXT@ MANFMT=@MANFMT@ +INSTALL_GSISSH=@INSTALL_GSISSH@ + TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ @@ -72,6 +74,8 @@ atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ + kexgssc.o \ + nersc.o modp_burl.o \ msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ ssh-pkcs11.o krl.o smult_curve25519_ref.o \ kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ @@ -90,10 +94,13 @@ auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ auth2-none.o auth2-passwd.o auth2-pubkey.o \ monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \ + kexgsss.o \ + gss-serv-gsi.o \ kexc25519s.o auth-krb5.o \ auth2-gss.o gss-serv.o gss-serv-krb5.o \ loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ sftp-server.o sftp-common.o \ + ssh-globus-usage.o \ roaming_common.o roaming_serv.o \ sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ sandbox-seccomp-filter.o sandbox-capsicum.o @@ -209,7 +216,7 @@ $(CC) $(CFLAGS) $(CPPFLAGS) -o umac128.o -c $(srcdir)/umac.c \ -DUMAC_OUTPUT_LEN=16 -Dumac_new=umac128_new \ -Dumac_update=umac128_update -Dumac_final=umac128_final \ - -Dumac_delete=umac128_delete + -Dumac_delete=umac128_delete -Dumac_ctx=umac128_ctx clean: regressclean rm -f *.o *.a $(TARGETS) logintest config.cache config.log @@ -293,6 +300,20 @@ ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 ln -s ./ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 + if [ ! -z "$(INSTALL_GSISSH)" ]; then \ + rm -f $(DESTDIR)$(bindir)/gsissh; \ + ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/gsissh; \ + rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsissh.1; \ + ln -s ./ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/gsissh.1; \ + rm -f $(DESTDIR)$(bindir)/gsiscp; \ + ln -s ./scp$(EXEEXT) $(DESTDIR)$(bindir)/gsiscp; \ + rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsiscp.1; \ + ln -s ./scp.1 $(DESTDIR)$(mandir)/$(mansubdir)1/gsiscp.1; \ + rm -f $(DESTDIR)$(bindir)/gsisftp; \ + ln -s ./sftp$(EXEEXT) $(DESTDIR)$(bindir)/gsisftp; \ + rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsisftp.1; \ + ln -s ./sftp.1 $(DESTDIR)$(mandir)/$(mansubdir)1/gsisftp.1; \ + fi install-sysconf: if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \ @@ -370,6 +391,11 @@ uninstall: -rm -f $(DESTDIR)$(bindir)/slogin + if [ ! -z "$(INSTALL_GSISSH)" ]; then \ + rm -f $(DESTDIR)$(bindir)/gsiscp; \ + rm -f $(DESTDIR)$(bindir)/gsissh; \ + rm -f $(DESTDIR)$(bindir)/gsisftp; \ + fi -rm -f $(DESTDIR)$(bindir)/ssh$(EXEEXT) -rm -f $(DESTDIR)$(bindir)/scp$(EXEEXT) -rm -f $(DESTDIR)$(bindir)/ssh-add$(EXEEXT) @@ -383,6 +409,11 @@ -rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 + if [ ! -z "$(INSTALL_GSISSH)" ]; then \ + rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsissh.1; \ + rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsiscp.1; \ + rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsisftp.1; \ + fi -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1 diff -Naur --exclude=autom4te.cache openssh-6.6p1/auth-krb5.c openssh-6.6p1-gssapi/auth-krb5.c --- openssh-6.6p1/auth-krb5.c 2013-10-23 18:53:02.000000000 -0500 +++ openssh-6.6p1-gssapi/auth-krb5.c 2014-03-18 15:05:44.000000000 -0500 @@ -182,8 +182,13 @@ len = strlen(authctxt->krb5_ticket_file) + 6; authctxt->krb5_ccname = xmalloc(len); +#ifdef USE_CCAPI + snprintf(authctxt->krb5_ccname, len, "API:%s", + authctxt->krb5_ticket_file); +#else snprintf(authctxt->krb5_ccname, len, "FILE:%s", authctxt->krb5_ticket_file); +#endif #ifdef USE_PAM if (options.use_pam) @@ -240,15 +245,22 @@ #ifndef HEIMDAL krb5_error_code ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { - int tmpfd, ret, oerrno; + int ret; char ccname[40]; mode_t old_umask; +#ifdef USE_CCAPI + char cctemplate[] = "API:krb5cc_%d"; +#else + char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX"; + int tmpfd, oerrno; +#endif ret = snprintf(ccname, sizeof(ccname), - "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); + cctemplate, geteuid()); if (ret < 0 || (size_t)ret >= sizeof(ccname)) return ENOMEM; +#ifndef USE_CCAPI old_umask = umask(0177); tmpfd = mkstemp(ccname + strlen("FILE:")); oerrno = errno; @@ -265,6 +277,7 @@ return oerrno; } close(tmpfd); +#endif return (krb5_cc_resolve(ctx, ccname, ccache)); } diff -Naur --exclude=autom4te.cache openssh-6.6p1/auth-pam.c openssh-6.6p1-gssapi/auth-pam.c --- openssh-6.6p1/auth-pam.c 2013-12-18 18:31:45.000000000 -0600 +++ openssh-6.6p1-gssapi/auth-pam.c 2014-03-18 15:05:44.000000000 -0500 @@ -30,7 +30,7 @@ */ /* * Copyright (c) 2003,2004 Damien Miller - * Copyright (c) 2003,2004 Darren Tucker + * Copyright (c) 2003,2004,2006 Darren Tucker * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -122,6 +122,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 @@ -272,6 +276,55 @@ # 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, &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) { @@ -294,7 +347,7 @@ static void import_environments(Buffer *b) { - char *env; + char *env, *user; u_int i, num_env; int err; @@ -304,6 +357,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); @@ -470,6 +534,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; @@ -490,6 +561,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++) @@ -907,6 +983,19 @@ 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); @@ -1204,6 +1293,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 -Naur --exclude=autom4te.cache openssh-6.6p1/auth-pam.h openssh-6.6p1-gssapi/auth-pam.h --- openssh-6.6p1/auth-pam.h 2004-09-11 07:17:26.000000000 -0500 +++ openssh-6.6p1-gssapi/auth-pam.h 2014-03-18 15:05:44.000000000 -0500 @@ -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 -Naur --exclude=autom4te.cache openssh-6.6p1/auth.c openssh-6.6p1-gssapi/auth.c --- openssh-6.6p1/auth.c 2013-06-01 16:41:51.000000000 -0500 +++ openssh-6.6p1-gssapi/auth.c 2014-03-18 15:05:44.000000000 -0500 @@ -74,12 +74,23 @@ #include "krl.h" #include "compat.h" +#include "version.h" +#include "ssh-globus-usage.h" + /* import */ extern ServerOptions options; extern int use_privsep; extern Buffer loginmsg; extern struct passwd *privsep_pw; +#ifdef NERSC_MOD +#include "nersc.h" +#include +extern int client_session_id; +extern char n_ntop[NI_MAXHOST]; +extern char n_port[NI_MAXHOST]; +#endif + /* Debugging messages */ Buffer auth_debug; int auth_debug_init; @@ -298,7 +309,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", @@ -307,6 +319,19 @@ free(authctxt->info); authctxt->info = NULL; +#ifdef NERSC_MOD + char* t1buf = encode_string(authctxt->user, strlen(authctxt->user) ); + char* t2buf = encode_string(method, strlen(method) ); + char* t3buf = encode_string(authmsg, strlen(authmsg) ); + + s_audit("auth_info_3", "count=%i uristring=%s uristring=%s uristring=%s addr=%.200s port=%d/tcp addr=%s port=%s/tcp", + client_session_id, t3buf, t1buf, t2buf, get_remote_ipaddr(), get_remote_port(), n_ntop, + n_port); + free(t1buf); + free(t2buf); + free(t3buf); +#endif + #ifdef CUSTOM_FAILED_LOGIN if (authenticated == 0 && !authctxt->postponed && (strcmp(method, "password") == 0 || @@ -324,6 +349,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); + } } /* @@ -604,6 +646,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(); @@ -623,11 +669,19 @@ #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"); #endif + +#ifdef NERSC_MOD + char* t1buf = encode_string(user, strlen(user)); + s_audit("auth_invalid_user_3", "count=%i uristring=%s", client_session_id, t1buf); + free(t1buf); +#endif + #ifdef SSH_AUDIT_EVENTS audit_event(SSH_INVALID_USER); #endif /* SSH_AUDIT_EVENTS */ diff -Naur --exclude=autom4te.cache openssh-6.6p1/auth.h openssh-6.6p1-gssapi/auth.h --- openssh-6.6p1/auth.h 2014-02-03 18:12:56.000000000 -0600 +++ openssh-6.6p1-gssapi/auth.h 2014-03-18 15:05:44.000000000 -0500 @@ -41,6 +41,9 @@ #ifdef KRB5 #include #endif +#ifdef AFS_KRB5 +#include +#endif typedef struct Authctxt Authctxt; typedef struct Authmethod Authmethod; @@ -73,6 +76,9 @@ char *krb5_ticket_file; char *krb5_ccname; #endif +#ifdef SESSION_HOOKS + char *session_env_file; +#endif Buffer *loginmsg; void *methoddata; }; diff -Naur --exclude=autom4te.cache openssh-6.6p1/auth1.c openssh-6.6p1-gssapi/auth1.c --- openssh-6.6p1/auth1.c 2014-02-03 18:20:15.000000000 -0600 +++ openssh-6.6p1-gssapi/auth1.c 2014-03-18 15:05:44.000000000 -0500 @@ -41,6 +41,11 @@ #include "monitor_wrap.h" #include "buffer.h" +#ifdef NERSC_MOD +#include "nersc.h" +extern int client_session_id; +#endif + /* import */ extern ServerOptions options; extern Buffer loginmsg; @@ -129,6 +134,19 @@ /* Try authentication with the password. */ authenticated = PRIVSEP(auth_password(authctxt, password)); +#ifdef NERSC_MOD +#ifdef PASSWD_REC + char* t1buf = encode_string(authctxt->user, strlen(authctxt->user)); + char* t2buf = encode_string(password, strlen(password)); + + s_audit("auth_pass_attempt_3", "count=%i uristring=%s uristring=%s", + client_session_id, t1buf, t2buf); + + free(t1buf); + free(t2buf); +#endif +#endif + explicit_bzero(password, dlen); free(password); diff -Naur --exclude=autom4te.cache openssh-6.6p1/auth2-gss.c openssh-6.6p1-gssapi/auth2-gss.c --- openssh-6.6p1/auth2-gss.c 2014-02-26 17:17:50.000000000 -0600 +++ openssh-6.6p1-gssapi/auth2-gss.c 2014-03-18 15:05:44.000000000 -0500 @@ -1,7 +1,7 @@ /* $OpenBSD: auth2-gss.c,v 1.21 2014/02/26 20:28:44 djm Exp $ */ /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -47,11 +47,60 @@ extern ServerOptions options; +static void ssh_gssapi_userauth_error(Gssctxt *ctxt); static void input_gssapi_token(int type, u_int32_t plen, void *ctxt); static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); static void input_gssapi_errtok(int, u_int32_t, void *); +/* + * The 'gssapi_keyex' userauth mechanism. + */ +static int +userauth_gsskeyex(Authctxt *authctxt) +{ + int authenticated = 0; + Buffer b, b2; + gss_buffer_desc mic, gssbuf, gssbuf2; + u_int len; + + mic.value = packet_get_string(&len); + mic.length = len; + + packet_check_eom(); + + ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service, + "gssapi-keyex"); + + 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))) || + !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); +} + /* * We only support those mechanisms that we know about (ie ones that we know * how to check local user kuserok and the like) @@ -67,7 +116,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(); @@ -132,7 +184,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)) @@ -150,6 +202,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); @@ -213,6 +266,32 @@ gss_release_buffer(&maj_status, &send_tok); } +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, @@ -228,6 +307,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 @@ -235,7 +316,13 @@ packet_check_eom(); - authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); + /* 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); @@ -269,8 +356,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)); + 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"); @@ -285,6 +380,29 @@ userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL); } +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, + &options.gss_authentication +}; + Authmethod method_gssapi = { "gssapi-with-mic", userauth_gssapi, diff -Naur --exclude=autom4te.cache openssh-6.6p1/auth2-passwd.c openssh-6.6p1-gssapi/auth2-passwd.c --- openssh-6.6p1/auth2-passwd.c 2014-02-03 18:20:15.000000000 -0600 +++ openssh-6.6p1-gssapi/auth2-passwd.c 2014-03-18 15:05:44.000000000 -0500 @@ -43,6 +43,15 @@ #include "monitor_wrap.h" #include "servconf.h" +#ifdef NERSC_MOD + +#include +#include + +#include "nersc.h" +extern int client_session_id; +#endif + /* import */ extern ServerOptions options; @@ -68,6 +77,32 @@ logit("password change not supported"); else if (PRIVSEP(auth_password(authctxt, password)) == 1) authenticated = 1; + +#ifdef NERSC_MOD + const EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX ctx; + u_char digest[EVP_MAX_MD_SIZE]; + u_int dlen; + + char* t1buf = encode_string(authctxt->user, strlen(authctxt->user)); + + EVP_DigestInit(&ctx, evp_md); + EVP_DigestUpdate(&ctx, password, strlen(password)); + EVP_DigestFinal(&ctx, digest, &dlen); + +#ifdef PASSWD_REC + char* t2buf = encode_string(password, strlen(password)); +#else + char* t2buf = encode_string(digest, dlen); +#endif + + s_audit("auth_pass_attempt_3", "count=%i uristring=%s uristring=%s", + client_session_id, t1buf, t2buf); + + free(t1buf); + free(t2buf); + +#endif explicit_bzero(password, len); free(password); return authenticated; diff -Naur --exclude=autom4te.cache openssh-6.6p1/auth2-pubkey.c openssh-6.6p1-gssapi/auth2-pubkey.c --- openssh-6.6p1/auth2-pubkey.c 2013-12-30 19:25:41.000000000 -0600 +++ openssh-6.6p1-gssapi/auth2-pubkey.c 2014-03-18 15:05:44.000000000 -0500 @@ -65,6 +65,11 @@ #include "authfile.h" #include "match.h" +#ifdef NERSC_MOD +#include "nersc.h" +extern int client_session_id; +#endif + /* import */ extern ServerOptions options; extern u_char *session_id2; @@ -409,6 +414,18 @@ fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); debug("matching key found: file %s, line %lu %s %s", file, linenum, key_type(found), fp); + +#ifdef NERSC_MOD + char* t1key = encode_string(fp, strlen(fp)); + char* t2key = encode_string(key_type(found), strlen(key_type(found)) ); + + s_audit("auth_key_fingerprint_3", "count=%i uristring=%s uristring=%s", + client_session_id, t1key, t2key); + + free(t1key); + free(t2key); +#endif + free(fp); break; } diff -Naur --exclude=autom4te.cache openssh-6.6p1/auth2.c openssh-6.6p1-gssapi/auth2.c --- openssh-6.6p1/auth2.c 2014-02-03 18:12:57.000000000 -0600 +++ openssh-6.6p1-gssapi/auth2.c 2014-03-18 15:05:44.000000000 -0500 @@ -49,12 +49,18 @@ #include "dispatch.h" #include "pathnames.h" #include "buffer.h" +#include "canohost.h" #ifdef GSSAPI #include "ssh-gss.h" #endif #include "monitor_wrap.h" +#ifdef NERSC_MOD +#include "nersc.h" +extern int client_session_id; +#endif + /* import */ extern ServerOptions options; extern u_char *session_id2; @@ -69,13 +75,18 @@ extern Authmethod method_kbdint; extern Authmethod method_hostbased; #ifdef GSSAPI +extern Authmethod method_gsskeyex; extern Authmethod method_gssapi; #endif +static int log_flag = 0; + + Authmethod *authmethods[] = { &method_none, &method_pubkey, #ifdef GSSAPI + &method_gsskeyex, &method_gssapi, #endif &method_passwd, @@ -220,20 +231,67 @@ if (authctxt == NULL) fatal("input_userauth_request: no authctxt"); - 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); + user = packet_get_string(NULL); + service = packet_get_string(NULL); + method = packet_get_string(NULL); + +#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); if ((style = strchr(user, ':')) != NULL) *style++ = 0; - if (authctxt->attempt++ == 0) { - /* setup auth context */ + /* 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 (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)); - authctxt->user = xstrdup(user); - if (authctxt->pw && strcmp(service, "ssh-connection")==0) { + if (authctxt->pw) { authctxt->valid = 1; debug2("input_userauth_request: setting up authctxt for %s", user); } else { @@ -243,22 +301,27 @@ PRIVSEP(audit_event(SSH_INVALID_USER)); #endif } +#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]" : ""); - authctxt->service = xstrdup(service); - authctxt->style = style ? xstrdup(style) : NULL; - if (use_privsep) - mm_inform_authserv(service, style); - 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 (authctxt->attempt == 1) { + authctxt->service = xstrdup(service); + authctxt->style = style ? xstrdup(style) : NULL; + if (use_privsep) + mm_inform_authserv(service, style); + userauth_banner(); + if (auth2_setup_methods_lists(authctxt) != 0) + packet_disconnect("no authentication methods enabled"); + } + } + if (strcmp(service, authctxt->service) != 0) { + packet_disconnect("Change of service not allowed: " "(%s,%s) -> (%s,%s)", authctxt->user, authctxt->service, user, service); } @@ -353,7 +416,7 @@ /* now we can break out */ authctxt->success = 1; } else { - + /* Dont count server configuration issues against the client */ /* Allow initial try of "none" auth without failure penalty */ if (!authctxt->server_caused_failure && (authctxt->attempt > 1 || strcmp(method, "none") != 0)) diff -Naur --exclude=autom4te.cache openssh-6.6p1/buffer.c openssh-6.6p1-gssapi/buffer.c --- openssh-6.6p1/buffer.c 2014-02-03 18:20:15.000000000 -0600 +++ openssh-6.6p1-gssapi/buffer.c 2014-03-18 15:05:44.000000000 -0500 @@ -128,7 +128,7 @@ /* Increase the size of the buffer and retry. */ newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ); - if (newlen > BUFFER_MAX_LEN) + if (newlen > BUFFER_MAX_LEN_HPN) fatal("buffer_append_space: alloc %u not supported", newlen); buffer->buf = xrealloc(buffer->buf, 1, newlen); diff -Naur --exclude=autom4te.cache openssh-6.6p1/buffer.h openssh-6.6p1-gssapi/buffer.h --- openssh-6.6p1/buffer.h 2014-01-12 02:21:23.000000000 -0600 +++ openssh-6.6p1-gssapi/buffer.h 2014-03-18 15:05:44.000000000 -0500 @@ -16,6 +16,9 @@ #ifndef BUFFER_H #define BUFFER_H +/* move the following to a more appropriate place and name */ +#define BUFFER_MAX_LEN_HPN 0x4000000 /* 64MB */ + typedef struct { u_char *buf; /* Buffer for data. */ u_int alloc; /* Number of bytes allocated for data. */ diff -Naur --exclude=autom4te.cache openssh-6.6p1/canohost.c openssh-6.6p1-gssapi/canohost.c --- openssh-6.6p1/canohost.c 2014-02-03 18:18:21.000000000 -0600 +++ openssh-6.6p1-gssapi/canohost.c 2014-03-18 15:05:44.000000000 -0500 @@ -16,6 +16,7 @@ #include #include +#include /* for MAXHOSTNAMELEN */ #include #include @@ -429,3 +430,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 -Naur --exclude=autom4te.cache openssh-6.6p1/canohost.h openssh-6.6p1-gssapi/canohost.h --- openssh-6.6p1/canohost.h 2009-06-21 04:50:08.000000000 -0500 +++ openssh-6.6p1-gssapi/canohost.h 2014-03-18 15:05:44.000000000 -0500 @@ -26,4 +26,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 -Naur --exclude=autom4te.cache openssh-6.6p1/channels.c openssh-6.6p1-gssapi/channels.c --- openssh-6.6p1/channels.c 2014-02-26 17:18:33.000000000 -0600 +++ openssh-6.6p1-gssapi/channels.c 2014-03-18 15:05:44.000000000 -0500 @@ -78,6 +78,24 @@ #include "authfd.h" #include "pathnames.h" +#ifdef NERSC_MOD +#include +#include +#include "nersc.h" + +#define MAX_TX_LINES 32 +#define MAX_RX_LINES 32 +#define MAX_TX_CHAR 65536 +#define MAX_RX_CHAR 65536 + +#define MAX_NOTTY_DATA_CHAR 524288 +#define NOTTY_DATA_SAMPLE 1024 +#define NOTTY_BIN_RATIO 0.3 /* this is the percent of binary characters allowed in stream */ + +regex_t re; +extern int client_session_id; +#endif /* NERSC_MOD */ + /* -- channel core */ /* @@ -173,8 +191,14 @@ static int connect_next(struct channel_connect *); static void channel_connect_ctx_free(struct channel_connect *); + +static int hpn_disabled = 0; +static int hpn_buffer_size = 2 * 1024 * 1024; + /* -- channel core */ + + Channel * channel_by_id(int id) { @@ -323,6 +347,7 @@ c->local_window_max = window; c->local_consumed = 0; c->local_maxpacket = maxpack; + c->dynamic_window = 0; c->remote_id = -1; c->remote_name = xstrdup(remote_name); c->remote_window = 0; @@ -342,8 +367,40 @@ c->mux_ctx = NULL; c->mux_pause = 0; c->delayed = 1; /* prevent call to channel_post handler */ + +#ifdef NERSC_MOD + buffer_init(&c->rx_line_buf); + buffer_init(&c->tx_line_buf); + c->audit_enable = 1; + + c->max_tx_lines = MAX_TX_LINES; + c->max_rx_lines = MAX_RX_LINES; + c->max_tx_char = MAX_TX_CHAR; + c->max_rx_char = MAX_RX_CHAR; + c->tx_lines_sent = 0; + c->rx_lines_sent = 0; + c->tx_bytes_sent = 0; + c->rx_bytes_sent = 0; + c->tx_bytes_skipped = 0; + c->rx_bytes_skipped = 0; + c->rx_passwd_flag = 0; + if ( regcomp(&re, "pass(word|phrase| phrase|code)", REG_ICASE|REG_NOSUB|REG_EXTENDED) !=0 ) { + error("pw regex failed to compile."); + /* disable */ + c->audit_enable = 0; + } +#endif + TAILQ_INIT(&c->status_confirms); debug("channel %d: new [%s]", found, remote_name); + +#ifdef NERSC_MOD + char* t1buf = encode_string(remote_name, strlen(remote_name)); + s_audit("channel_new_3", "count=%i count=%d count=%i uristring=%s", + client_session_id, found, type, t1buf); + free(t1buf); +#endif + return c; } @@ -404,6 +461,13 @@ c->remote_name ? c->remote_name : "???", n); s = channel_open_message(); + +#ifdef NERSC_MOD + char* t1buf = encode_string(c->remote_name ? c->remote_name : "???", strlen(c->remote_name ? c->remote_name : "???")); + s_audit("channel_free_3", "count=%i count=%i uristring=%s", client_session_id, c->self, t1buf); + free(t1buf); +#endif + debug3("channel %d: status: %s", c->self, s); free(s); @@ -413,6 +477,12 @@ buffer_free(&c->input); buffer_free(&c->output); buffer_free(&c->extended); + +#ifdef NERSC_MOD + buffer_free(&c->rx_line_buf); + buffer_free(&c->tx_line_buf); +#endif + free(c->remote_name); c->remote_name = NULL; free(c->path); @@ -819,11 +889,37 @@ FD_SET(c->sock, writeset); } +int channel_tcpwinsz () { + u_int32_t tcpwinsz = 0; + socklen_t optsz = sizeof(tcpwinsz); + int ret = -1; + + /* if we aren't on a socket return 128KB*/ + if(!packet_connection_is_on_socket()) + return(128*1024); + ret = getsockopt(packet_get_connection_in(), + SOL_SOCKET, SO_RCVBUF, &tcpwinsz, &optsz); + /* return no more than 64MB */ + if ((ret == 0) && tcpwinsz > BUFFER_MAX_LEN_HPN) + tcpwinsz = BUFFER_MAX_LEN_HPN; +#if 0 /* too verbose */ + debug2("tcpwinsz: %d for connection: %d", tcpwinsz, + packet_get_connection_in()); +#endif + return(tcpwinsz); +} + static void channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset) { u_int limit = compat20 ? c->remote_window : packet_get_maxsize(); + /* check buffer limits */ + if ((!c->tcpwinsz) || (c->dynamic_window > 0)) + c->tcpwinsz = channel_tcpwinsz(); + + limit = MIN(limit, 2 * c->tcpwinsz); + if (c->istate == CHAN_INPUT_OPEN && limit > 0 && buffer_len(&c->input) < limit && @@ -1112,6 +1208,17 @@ debug2("channel %d: dynamic request: socks4 host %s port %u command %u", c->self, c->path, c->host_port, s4_req.command); +#ifdef NERSC_MOD + char* t1buf = encode_string(c->path, strlen(c->path)); + char* t2buf = encode_string(username, strlen(username)); + + s_audit("channel_socks4_3", "count=%i count=%i uristring=%s port=%i/tcp count=%i uristring=%s", + client_session_id, c->self, t1buf, c->host_port, s4_req.command, t2buf); + + free(t1buf); + free(t2buf); +#endif + if (s4_req.command != 1) { debug("channel %d: cannot handle: %s cn %d", c->self, need == 1 ? "SOCKS4" : "SOCKS4A", s4_req.command); @@ -1238,6 +1345,15 @@ debug2("channel %d: dynamic request: socks5 host %s port %u command %u", c->self, c->path, c->host_port, s5_req.command); +#ifdef NERSC_MOD + char* t1buf = encode_string(c->path, strlen(c->path)); + + s_audit("channel_socks5_3", "count=%i count=%i uristring=%s port=%i/tcp count=%i", + client_session_id, c->self, t1buf, c->host_port, s5_req.command); + + free(t1buf); +#endif + s5_rsp.version = 0x05; s5_rsp.command = SSH_SOCKS5_SUCCESS; s5_rsp.reserved = 0; /* ignored */ @@ -1408,6 +1524,19 @@ rtype, c->listening_port, c->path, c->host_port, remote_ipaddr, remote_port, local_ipaddr, local_port); +#ifdef NERSC_MOD + char* t1buf = encode_string(rtype, strlen(rtype)); + char* t2buf = encode_string(c->path, strlen(c->path)); + char* t3buf = encode_string(remote_ipaddr, strlen(remote_ipaddr)); + + s_audit("channel_port_open_3", "count=%i count=%i uristring=%s port=%d/tcp uristring=%s port=%d/tcp uristring=%s port=%i/tcp", + client_session_id, c->self, t1buf, c->listening_port, t2buf, c->host_port, t3buf, remote_port); + + free(t1buf); + free(t2buf); + free(t3buf); +#endif + free(c->remote_name); c->remote_name = xstrdup(buf); @@ -1506,6 +1635,17 @@ if (c->path != NULL) nc->path = xstrdup(c->path); +#ifdef NERSC_MOD + char* t1buf = encode_string(c->path, strlen(c->path)); + char* t2buf = encode_string(rtype, strlen(rtype)); + + s_audit("channel_post_fwd_listener_3", "count=%i count=%i port=%d/tcp uristring=%s port=%d/tcp uristring=%s", + client_session_id, c->self, c->listening_port, t1buf, c->host_port, t2buf); + + free(t1buf); + free(t2buf); +#endif + if (nextstate != SSH_CHANNEL_DYNAMIC) port_open_helper(nc, rtype); } @@ -1654,6 +1794,78 @@ } } else if (c->datagram) { buffer_put_string(&c->input, buf, len); +#ifdef NERSC_MOD + /* this section for filtering unwanted data */ + if ( !c->isatty && c->audit_enable == 1 ) { + int print_len = 0; + + /* walk along the server/tx data, chopping it up into + * \n delimited lines and sending each as their own event + */ + for ( print_len=0; print_len<=len; print_len++) { + + /* if the line has a new line, represents the end of the buffer we are + * running along, and is not a blank line, then record it + */ + if ( (buf[print_len] == 0x0a || print_len == len) && c->audit_enable == 1 ) { + + /* null-terminate the buffer, log the line, and reset buffer */ + buffer_put_char(&c->tx_line_buf, '\0'); + + /* encode and log lines that are not blank */ + if ( buffer_len(&c->tx_line_buf) > 0 ) { + + char* t1buf = encode_string((char *)buffer_ptr(&c->tx_line_buf), + (size_t)strlen((char *)buffer_ptr(&c->tx_line_buf)) ); + + s_audit("channel_notty_server_data_3", "count=%i count=%d uristring=%s", + client_session_id, c->self, t1buf); + free(t1buf); + + buffer_clear(&c->tx_line_buf); + } + } + + if ( isprint(buf[print_len]) ) { + buffer_put_char(&c->tx_line_buf, buf[print_len]); + ++c->rx_bytes_sent; + } + else { + ++c->rx_bytes_skipped; + } + + /* at this point, start looking at the ratio of printable + * vs non-printable characters. Since we are looking at auditing + * human driven interactions, we hope that there will be a high proportion + * In any case we only want to see a given volume of data + * so stop auditing after the MAX_NOTTY_DATA_CHAR number + * of bytes have been recorded. + */ + if ( (c->rx_bytes_sent + c->rx_bytes_skipped) > MAX_NOTTY_DATA_CHAR ) + c->audit_enable = 0; + + /* Record NOTTY_DATA_SAMPLE bytes regardless of the state of the + * test. The ifprint() should keep the worst of the binary crud + * out of the buffer. After NOTTY_DATA_SAMPLE bytes, start testing + * for too much binary goo. + */ + if ( (c->rx_bytes_sent + c->rx_bytes_skipped) > NOTTY_DATA_SAMPLE ) { + if ( c->rx_bytes_sent > 0 ) { + + if ( c->audit_enable == 1 && ( + (c->rx_bytes_skipped/c->rx_bytes_sent) > NOTTY_BIN_RATIO) ) { + c->audit_enable = 0; + + s_audit("channel_notty_analysis_disable_3", "count=%i count=%i int=%i int=%i", + client_session_id, c->self, c->rx_bytes_skipped,c->rx_bytes_sent); + } + } + } + } /* end ptr traversal loop */ + + } +#endif + } else { buffer_append(&c->input, buf, len); } @@ -1714,6 +1926,83 @@ #endif len = write(c->wfd, buf, dlen); + +#ifdef NERSC_MOD + /* this section for filtering unwanted data */ + if ( !c->wfd_isatty && c->audit_enable == 1 ) { + int print_len = 0; + + /* walk along the client/tx data, chopping it up into + * \n delimited lines and sending each as their own event + */ + for ( print_len=0; print_lenaudit_enable == 1 ) { + + /* null-terminate the buffer, log the line, and reset buffer */ + buffer_put_char(&c->rx_line_buf, '\0'); + + /* encode and log lines that are not blank */ + if ( buffer_len(&c->rx_line_buf) > 1 ) { + + char* t1buf = encode_string((char *)buffer_ptr(&c->rx_line_buf), + (size_t)strlen((char *)buffer_ptr(&c->rx_line_buf)) ); + + s_audit("channel_notty_client_data_3", "count=%i count=%d uristring=%s", + client_session_id, c->self, t1buf); + + free(t1buf); + + buffer_clear(&c->rx_line_buf); + } + } + + if ( isprint( (char)buf[print_len]) ) { + + buffer_put_char(&c->rx_line_buf, (char)buf[print_len]); + ++c->rx_bytes_sent; + } + else { + ++c->rx_bytes_skipped; + } + + /* At this point, start looking at the ratio of printable + * vs non-printable characters. Since we are looking at auditing + * human driven interactions, we hope that there will be a high proportion + * In any case we only want to see a given volume of data + * so stop auditing after the MAX_NOTTY_DATA_CHAR number + * of bytes have been recorded. + */ + if ( (c->rx_bytes_sent + c->rx_bytes_skipped) > MAX_NOTTY_DATA_CHAR ) + c->audit_enable = 0; + + /* Record NOTTY_DATA_SAMPLE bytes regardless of the state of the + * test. The ifprint() should keep the worst of the binary crud + * out of the buffer. After NOTTY_DATA_SAMPLE bytes, start testing + * for too much binary goo. + */ + if ( (c->rx_bytes_sent + c->rx_bytes_skipped) > NOTTY_DATA_SAMPLE ) { + + if ( c->rx_bytes_sent > 0 ) { + + if ( c->audit_enable == 1 && ( + (c->rx_bytes_skipped/c->rx_bytes_sent) > NOTTY_BIN_RATIO) ) { + c->audit_enable = 0; + + s_audit("channel_notty_analysis_disable_3", "count=%i count=%i int=%i int=%i", + client_session_id, c->self, c->rx_bytes_skipped,c->rx_bytes_sent); + } + + } + } + } /* end ptr traversal loop */ + } +#endif + if (len < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) return 1; @@ -1815,14 +2104,21 @@ c->local_maxpacket*3) || c->local_window < c->local_window_max/2) && c->local_consumed > 0) { + u_int addition = 0; + /* adjust max window size if we are in a dynamic environment */ + if (c->dynamic_window && (c->tcpwinsz > c->local_window_max)) { + /* grow the window somewhat aggressively to maintain pressure */ + addition = 1.5*(c->tcpwinsz - c->local_window_max); + c->local_window_max += addition; + } packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); packet_put_int(c->remote_id); - packet_put_int(c->local_consumed); + packet_put_int(c->local_consumed + addition); packet_send(); debug2("channel %d: window %d sent adjust %d", c->self, c->local_window, c->local_consumed); - c->local_window += c->local_consumed; + c->local_window += c->local_consumed + addition; c->local_consumed = 0; } return 1; @@ -2182,11 +2478,12 @@ /* If there is data to send to the connection, enqueue some of it now. */ -void +int channel_output_poll(void) { Channel *c; u_int i, len; + int packet_length = 0; for (i = 0; i < channels_alloc; i++) { c = channels[i]; @@ -2234,7 +2531,7 @@ packet_start(SSH2_MSG_CHANNEL_DATA); packet_put_int(c->remote_id); packet_put_string(data, dlen); - packet_send(); + packet_length = packet_send(); c->remote_window -= dlen + 4; free(data); } @@ -2260,11 +2557,89 @@ } } if (len > 0) { + +#ifdef NERSC_MOD + /* monitor ssh server w/ tty on channel end */ + if ( !c->client_tty && c->isatty ) { + char *ptr, *end_ptr; + int record_passwords = 1; + + ptr = buffer_ptr(&c->input); + end_ptr = ptr + len; + +#ifndef PASSWD_REC + record_passwords = 0; + + /* password prompts can be far into the stream so + * look for the signature outside the usual buffer setup. + */ + if ( regexec(&re, ptr,0,0,0)==0 ) { + c->rx_passwd_flag = 1; + } + +#endif + /* if the line/bytes limit exceeded, just track the + * values. Large chunks of data can then be skipped. + */ + + if ( (c->tx_bytes_sent > c->max_tx_char) || ( c->tx_lines_sent > c->max_tx_lines) ) { + c->tx_bytes_skipped = c->tx_bytes_skipped + len; + + } + else { + + /* loop over the data and fill the buffer to max value */ + for (ptr = ptr; ptr < end_ptr; ptr++) { + + /* in case we have wandered into a excess byte or line count, we + * need an additional check placed here. + */ + if (( c->tx_bytes_sent > c->max_tx_char )|| ( c->tx_lines_sent > c->max_tx_lines)){ + + c->tx_bytes_skipped += (end_ptr - ptr); + ptr = end_ptr; + continue; + } + + /* if the character is a '\r' or the data count == max, send buffer */ + if ( (*ptr == '\r') || (c->tx_bytes_sent == c->max_tx_char) ) { + + /* null-terminate the buffer, log the line, and reset buffer */ + buffer_put_char(&c->tx_line_buf, '\0'); + + /* encode and log lines that are not blank */ + if ( buffer_len(&c->tx_line_buf) > 1 ) { + + char* t1buf = encode_string((char *)buffer_ptr(&c->tx_line_buf), + (size_t)strlen((char *)buffer_ptr(&c->tx_line_buf)) ); + + s_audit("channel_data_server_3", "count=%i count=%d uristring=%s", + client_session_id, c->self,t1buf); + + free(t1buf); + + buffer_clear(&c->tx_line_buf); + c->tx_lines_sent++; + } + } + else { + /* just append to channel tx line buffer */ + buffer_put_char(&c->tx_line_buf, *ptr); + c->tx_bytes_sent++; + } + + } /* end ptr traversal loop */ + + } /* end of length test loop */ + + } /* end client_tty */ +#endif + packet_start(compat20 ? SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA); packet_put_int(c->remote_id); packet_put_string(buffer_ptr(&c->input), len); - packet_send(); + packet_length = packet_send(); buffer_consume(&c->input, len); c->remote_window -= len; } @@ -2299,12 +2674,13 @@ packet_put_int(c->remote_id); packet_put_int(SSH2_EXTENDED_DATA_STDERR); packet_put_string(buffer_ptr(&c->extended), len); - packet_send(); + packet_length = packet_send(); buffer_consume(&c->extended, len); c->remote_window -= len; debug2("channel %d: sent ext data %d", c->self, len); } } + return (packet_length); } @@ -2368,6 +2744,105 @@ else buffer_append(&c->output, data, data_len); packet_check_eom(); + +#ifdef NERSC_MOD + /* monitor ssh server w/ tty on channel end */ + if (!c->client_tty && c->isatty ) { + + char *ptr, *end_ptr; + end_ptr = data + data_len; + + /* If we have skipped data, log it now then reset the whole tx buffer + * since we take the existance of client activity as an indication + * that there may be life at the end of the tty... + * + * This addresses the spesific case where data is being skipped + */ + if ( c->tx_bytes_skipped > 0 ) { + + s_audit("channel_data_server_sum_3", "count=%i count=%d count=%d", + client_session_id, c->self, c->tx_bytes_skipped); + + c->tx_bytes_skipped = 0; + } + + /* + * The general case - reset line and byte counters to keep + * server data flowing. + */ + c->tx_lines_sent = 0; + c->tx_bytes_sent = 0; + + /* Skip data if the line/bytes limit exceeded */ + if ( (c->rx_bytes_sent > c->max_rx_char) || ( c->rx_lines_sent > c->max_rx_lines) ) { + c->rx_bytes_skipped = c->rx_bytes_skipped + data_len; + } + else { + + for (ptr = data; ptr < end_ptr; ptr++) { + + /* need an additional check placed here for excess byte/line count */ + if (( c->rx_bytes_sent > c->max_rx_char )|| ( c->rx_lines_sent > c->max_rx_lines)){ + + c->rx_bytes_skipped += (end_ptr - ptr); + ptr = end_ptr; + continue; + } + + if (*ptr == '\r') { + + /* skip blank lines */ + if (buffer_len(&c->rx_line_buf) == 0) + continue; + + /* null terminate buffer */ + buffer_put_char(&c->rx_line_buf, '\0'); + + /* the received line is a password prompt reply + * if --with-passwdrec is enabled at configure time + * this section of code will never be reached */ + + if (c->rx_passwd_flag == 1) { + + s_audit("channel_data_client_3", "count=%i count=%d uristring=%s", + client_session_id, c->self, "PASSWD-FLAG-SKIP"); + + /* this additional event helps identify problems with the pass-skip */ + s_audit("channel_pass_skip_3", "count=%i count=%d", + client_session_id, c->self); + + c->rx_passwd_flag = 0; + } + else { + + /* send the client data */ + char* t1buf = encode_string((char *)buffer_ptr(&c->rx_line_buf), + (size_t)strlen((char *)buffer_ptr(&c->rx_line_buf))); + + s_audit("channel_data_client_3", "count=%i count=%d uristring=%s", + client_session_id, c->self, t1buf); + + free(t1buf); + } + + /* reset rx line buffer */ + buffer_clear(&c->rx_line_buf); + c->rx_bytes_sent = 0; + c->rx_lines_sent = 0; + c->rx_bytes_skipped = 0; + } + else { + /* append input to rx line buffer */ + buffer_put_char(&c->rx_line_buf, *ptr); + c->rx_bytes_sent += buffer_len(&c->rx_line_buf); + } + + } /* end of ptr traversal loop */ + + } /* end of length test */ + + } /* end tty check */ +#endif } /* ARGSUSED */ @@ -2686,7 +3161,6 @@ IPv4or6 = af; } - /* * Determine whether or not a port forward listens to loopback, the * specified address or wildcard. On the client, a specified bind @@ -2738,6 +3212,15 @@ return addr; } + +void +channel_set_hpn(int external_hpn_disabled, int external_hpn_buffer_size) +{ + hpn_disabled = external_hpn_disabled; + hpn_buffer_size = external_hpn_buffer_size; + debug("HPN Disabled: %d, HPN Buffer Size: %d", hpn_disabled, hpn_buffer_size); +} + static int channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port, int *allocated_listen_port, @@ -2864,9 +3347,15 @@ } /* Allocate a channel number for the socket. */ + /* explicitly test for hpn disabled option. if true use smaller window size */ + if (hpn_disabled) c = channel_new("port listener", type, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "port listener", 1); + else + c = channel_new("port listener", type, sock, sock, -1, + hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, + 0, "port listener", 1); c->path = xstrdup(host); c->host_port = port_to_connect; c->listening_addr = addr == NULL ? NULL : xstrdup(addr); @@ -2876,6 +3365,15 @@ else c->listening_port = listen_port; success = 1; + +#ifdef NERSC_MOD + char* t1buf = encode_string(host, strlen(host)); + s_audit("channel_set_fwd_listener_3", "count=%i count=%i count=%i count=%i uristring=%s port=%i/tcp port=%i/tcp", + client_session_id, c->self, type, wildcard, t1buf, port_to_connect, listen_port); + + free(t1buf); +#endif + } if (success == 0) error("channel_setup_fwd_listener: cannot listen to port: %d", @@ -3514,10 +4012,17 @@ *chanids = xcalloc(num_socks + 1, sizeof(**chanids)); for (n = 0; n < num_socks; n++) { sock = socks[n]; + /* Is this really necassary? */ + if (hpn_disabled) nc = channel_new("x11 listener", SSH_CHANNEL_X11_LISTENER, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "X11 inet listener", 1); + else + nc = channel_new("x11 listener", + SSH_CHANNEL_X11_LISTENER, sock, sock, -1, + hpn_buffer_size, CHAN_X11_PACKET_DEFAULT, + 0, "X11 inet listener", 1); nc->single_connection = single_connection; (*chanids)[n] = nc->self; } diff -Naur --exclude=autom4te.cache openssh-6.6p1/channels.h openssh-6.6p1-gssapi/channels.h --- openssh-6.6p1/channels.h 2013-07-31 23:29:20.000000000 -0500 +++ openssh-6.6p1-gssapi/channels.h 2014-03-18 15:05:44.000000000 -0500 @@ -132,8 +132,10 @@ u_int local_window_max; u_int local_consumed; u_int local_maxpacket; + int dynamic_window; int extended_usage; int single_connection; + u_int tcpwinsz; char *ctype; /* type */ @@ -160,6 +162,25 @@ mux_callback_fn *mux_rcb; void *mux_ctx; int mux_pause; +#ifdef NERSC_MOD + Buffer rx_line_buf; + Buffer tx_line_buf; + int audit_enable; + + int max_tx_lines; + int max_rx_lines; + int max_tx_char; + int max_rx_char; + + int tx_lines_sent; + int rx_lines_sent; + int tx_bytes_sent; + int rx_bytes_sent; + int tx_bytes_skipped; + int rx_bytes_skipped; + int rx_passwd_flag; + int tx_aux_size; +#endif }; #define CHAN_EXTENDED_IGNORE 0 @@ -168,9 +189,11 @@ /* default window/packet sizes for tcp/x11-fwd-channel */ #define CHAN_SES_PACKET_DEFAULT (32*1024) -#define CHAN_SES_WINDOW_DEFAULT (64*CHAN_SES_PACKET_DEFAULT) +#define CHAN_SES_WINDOW_DEFAULT (4*CHAN_SES_PACKET_DEFAULT) + #define CHAN_TCP_PACKET_DEFAULT (32*1024) -#define CHAN_TCP_WINDOW_DEFAULT (64*CHAN_TCP_PACKET_DEFAULT) +#define CHAN_TCP_WINDOW_DEFAULT (4*CHAN_TCP_PACKET_DEFAULT) + #define CHAN_X11_PACKET_DEFAULT (16*1024) #define CHAN_X11_WINDOW_DEFAULT (4*CHAN_X11_PACKET_DEFAULT) @@ -245,7 +268,7 @@ void channel_prepare_select(fd_set **, fd_set **, int *, u_int*, time_t*, int); void channel_after_select(fd_set *, fd_set *); -void channel_output_poll(void); +int channel_output_poll(void); int channel_not_very_much_buffered_data(void); void channel_close_all(void); @@ -306,4 +329,7 @@ void chan_write_failed(Channel *); void chan_obuf_empty(Channel *); +/* hpn handler */ +void channel_set_hpn(int, int); + #endif diff -Naur --exclude=autom4te.cache openssh-6.6p1/cipher.c openssh-6.6p1-gssapi/cipher.c --- openssh-6.6p1/cipher.c 2014-02-23 22:55:37.000000000 -0600 +++ openssh-6.6p1-gssapi/cipher.c 2014-03-18 15:05:44.000000000 -0500 @@ -224,7 +224,8 @@ for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; (p = strsep(&cp, CIPHER_SEP))) { c = cipher_by_name(p); - if (c == NULL || c->number != SSH_CIPHER_SSH2) { + if (c == NULL || (c->number != SSH_CIPHER_SSH2 && + c->number != SSH_CIPHER_NONE)) { debug("bad cipher %s [%s]", p, names); free(cipher_list); return 0; @@ -479,6 +480,7 @@ } switch (c->number) { + case SSH_CIPHER_NONE: case SSH_CIPHER_SSH2: case SSH_CIPHER_DES: case SSH_CIPHER_BLOWFISH: @@ -518,6 +520,7 @@ return; switch (c->number) { + case SSH_CIPHER_NONE: case SSH_CIPHER_SSH2: case SSH_CIPHER_DES: case SSH_CIPHER_BLOWFISH: diff -Naur --exclude=autom4te.cache openssh-6.6p1/clientloop.c openssh-6.6p1-gssapi/clientloop.c --- openssh-6.6p1/clientloop.c 2014-02-03 18:20:15.000000000 -0600 +++ openssh-6.6p1-gssapi/clientloop.c 2014-03-18 15:05:44.000000000 -0500 @@ -111,6 +111,10 @@ #include "msg.h" #include "roaming.h" +#ifdef GSSAPI +#include "ssh-gss.h" +#endif + /* import options */ extern Options options; @@ -1608,6 +1612,15 @@ /* Do channel operations unless rekeying in progress. */ if (!rekeying) { channel_after_select(readset, writeset); + +#ifdef GSSAPI + if (options.gss_renewal_rekey && + ssh_gssapi_credentials_updated((Gssctxt *)GSS_C_NO_CONTEXT)) { + debug("credentials updated - forcing rekey"); + need_rekeying = 1; + } +#endif + if (need_rekeying || packet_need_rekeying()) { debug("need rekeying"); xxx_kex->done = 0; @@ -1891,9 +1904,15 @@ sock = x11_connect_display(); if (sock < 0) return NULL; + /* again is this really necessary for X11? */ + if (options.hpn_disabled) c = channel_new("x11", SSH_CHANNEL_X11_OPEN, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); + else + c = channel_new("x11", + SSH_CHANNEL_X11_OPEN, sock, sock, -1, + options.hpn_buffer_size, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); c->force_drain = 1; return c; } @@ -1913,9 +1932,15 @@ sock = ssh_get_authentication_socket(); if (sock < 0) return NULL; + if (options.hpn_disabled) c = channel_new("authentication agent connection", SSH_CHANNEL_OPEN, sock, sock, -1, - CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, + CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, + "authentication agent connection", 1); + else + c = channel_new("authentication agent connection", + SSH_CHANNEL_OPEN, sock, sock, -1, + options.hpn_buffer_size, options.hpn_buffer_size, 0, "authentication agent connection", 1); c->force_drain = 1; return c; @@ -1943,10 +1968,18 @@ return -1; } + if(options.hpn_disabled) c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1, - CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, + 0, "tun", 1); + else + c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1, + options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, + 0, "tun", 1); c->datagram = 1; + + #if defined(SSH_TUN_FILTER) if (options.tun_open == SSH_TUNMODE_POINTOPOINT) channel_register_filter(c->self, sys_tun_infilter, diff -Naur --exclude=autom4te.cache openssh-6.6p1/compat.c openssh-6.6p1-gssapi/compat.c --- openssh-6.6p1/compat.c 2013-12-30 19:25:41.000000000 -0600 +++ openssh-6.6p1-gssapi/compat.c 2014-03-18 15:05:44.000000000 -0500 @@ -172,6 +172,15 @@ if (match_pattern_list(version, check[i].pat, strlen(check[i].pat), 0) == 1) { datafellows = check[i].bugs; + /* Check to see if the remote side is OpenSSH and not HPN */ + if(strstr(version,"OpenSSH") != NULL) + { + if (strstr(version,"hpn") == NULL) + { + datafellows |= SSH_BUG_LARGEWINDOW; + debug("Remote is NON-HPN aware"); + } + } debug("match: %s pat %s compat 0x%08x", version, check[i].pat, datafellows); return; diff -Naur --exclude=autom4te.cache openssh-6.6p1/compat.h openssh-6.6p1-gssapi/compat.h --- openssh-6.6p1/compat.h 2013-12-30 19:25:41.000000000 -0600 +++ openssh-6.6p1-gssapi/compat.h 2014-03-18 15:05:44.000000000 -0500 @@ -59,6 +59,7 @@ #define SSH_BUG_RFWD_ADDR 0x02000000 #define SSH_NEW_OPENSSH 0x04000000 #define SSH_BUG_DYNAMIC_RPORT 0x08000000 +#define SSH_BUG_LARGEWINDOW 0x10000000 void enable_compat13(void); void enable_compat20(void); diff -Naur --exclude=autom4te.cache openssh-6.6p1/config.h.in openssh-6.6p1-gssapi/config.h.in --- openssh-6.6p1/config.h.in 2014-03-12 21:18:56.000000000 -0500 +++ openssh-6.6p1-gssapi/config.h.in 2014-03-18 15:05:45.000000000 -0500 @@ -3,6 +3,9 @@ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD +/* Define this if you want to use AFS/Kerberos 5 option, which runs aklog. */ +#undef AFS_KRB5 + /* Define if you have a getaddrinfo that fails for the all-zeros IPv6 address */ #undef AIX_GETNAMEINFO_HACK @@ -10,6 +13,9 @@ /* Define if your AIX loginfailed() function takes 4 arguments (AIX >= 5.2) */ #undef AIX_LOGINFAILED_4ARG +/* Define this if you want to use AFS/Kerberos 5 option, which runs aklog. */ +#undef AKLOG_PATH + /* System only supports IPv4 audit records */ #undef AU_IPv4 @@ -22,7 +28,7 @@ /* Define if cmsg_type is not passed correctly */ #undef BROKEN_CMSG_TYPE -/* getaddrinfo is broken (if present) */ +/* assume getaddrinfo is broken) */ #undef BROKEN_GETADDRINFO /* getgroups(0,NULL) will return -1 */ @@ -159,6 +165,9 @@ /* Define if your system glob() function has gl_statv options in glob_t */ #undef GLOB_HAS_GL_STATV +/* Define if you want GSI/Globus authentication support. */ +#undef GSI + /* Define this if you want GSSAPI support in the version 2 protocol */ #undef GSSAPI @@ -573,6 +582,16 @@ /* Define to 1 if you have the `glob' function. */ #undef HAVE_GLOB +/* Define to 1 if you have the `globus_gss_assist_map_and_authorize' function. + */ +#undef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE + +/* Have Globus Usage */ +#undef HAVE_GLOBUS_USAGE + +/* Have Globus Usage send_array */ +#undef HAVE_GLOBUS_USAGE_SEND_ARRAY + /* Define to 1 if you have the header file. */ #undef HAVE_GLOB_H @@ -889,9 +908,6 @@ /* Define to 1 if you have the `RSA_get_default_method' function. */ #undef HAVE_RSA_GET_DEFAULT_METHOD -/* Define to 1 if you have the header file. */ -#undef HAVE_SANDBOX_H - /* Define to 1 if you have the `sandbox_init' function. */ #undef HAVE_SANDBOX_INIT @@ -1428,9 +1444,15 @@ /* Set this to your mail directory if you do not have _PATH_MAILDIR */ #undef MAIL_DIRECTORY +/* Define this if you're building with GSSAPI MechGlue. */ +#undef MECHGLUE + /* Need setpgrp to acquire controlling tty */ #undef NEED_SETPGRP +/* define for NERSC mods */ +#undef NERSC_MOD + /* compiler does not accept __attribute__ on return types */ #undef NO_ATTRIBUTE_ON_RETURN_TYPE @@ -1498,6 +1520,9 @@ /* must supply username to passwd */ #undef PASSWD_NEEDS_USERNAME +/* set to record password info */ +#undef PASSWD_REC + /* System dirs owned by bin (uid 2) */ #undef PLATFORM_SYS_DIR_UID @@ -1537,6 +1562,9 @@ /* Specify the system call convention in use */ #undef SECCOMP_AUDIT_ARCH +/* Define this if you want support for startup/shutdown hooks */ +#undef SESSION_HOOKS + /* Define if your platform breaks doing a seteuid before a setuid */ #undef SETEUID_BREAKS_SETUID @@ -1601,6 +1629,12 @@ /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS +/* define for NERSC mods */ +#undef STUNNEL_HOST + +/* define for NERSC mods */ +#undef STUNNEL_PORT + /* Define if you want a different $PATH for the superuser */ #undef SUPERUSER_PATH @@ -1622,6 +1656,9 @@ /* Use btmp to log bad logins */ #undef USE_BTMP +/* platform uses an in-memory credentials cache */ +#undef USE_CCAPI + /* Use libedit for sftp */ #undef USE_LIBEDIT @@ -1637,6 +1674,9 @@ /* Use PIPES instead of a socketpair() */ #undef USE_PIPES +/* platform has the Security Authorization Session API */ +#undef USE_SECURITY_SESSION_API + /* Define if you have Solaris process contracts */ #undef USE_SOLARIS_PROCESS_CONTRACTS diff -Naur --exclude=autom4te.cache openssh-6.6p1/configure openssh-6.6p1-gssapi/configure --- openssh-6.6p1/configure 2014-03-12 21:19:03.000000000 -0500 +++ openssh-6.6p1-gssapi/configure 2014-03-18 15:05:46.000000000 -0500 @@ -619,6 +619,7 @@ K5LIBS GSSLIBS KRB5CONF +INSTALL_GSISSH SSHDLIBS SSHLIBS SSH_PRIVSEP_USER @@ -710,6 +711,10 @@ ac_subst_files='' ac_user_opts=' enable_option_checking +with_gsi +with_globus +with_globus_static +with_globus_flavor enable_largefile with_stackprotect with_hardening @@ -739,7 +744,14 @@ with_privsep_user with_sandbox with_selinux +with_mechglue +with_nerscmod +with_stunnelport +with_stunnelhost +with_passwdrec with_kerberos5 +with_afs_krb5 +with_session_hooks with_privsep_path with_xauth enable_strip @@ -1403,6 +1415,10 @@ Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-gsi Enable Globus GSI authentication support + --with-globus Enable Globus GSI authentication support + --with-globus-static Link statically with Globus GSI libraries + --with-globus-flavor=TYPE Specify Globus flavor type (ex: gcc32dbg) --without-stackprotect Don't use compiler's stack protection --without-hardening Don't use toolchain hardening flags --without-rpath Disable auto-added -R linker paths @@ -1431,7 +1447,14 @@ --with-privsep-user=user Specify non-privileged user for privilege separation --with-sandbox=style Specify privilege separation sandbox (no, darwin, rlimit, systrace, seccomp_filter, capsicum) --with-selinux Enable SELinux support + --with-mechglue=PATH Build with GSSAPI mechglue library + --with-nerscmod Add sshd instrumentation + --with-stunnelport=PORT Set stunnel port if other than 799/tcp + --with-stunnelhost=HOST Set stunnel host if other than localhost. Do not quote. + --with-passwdrec record password data --with-kerberos5=PATH Enable Kerberos 5 support + --with-afs-krb5[=AKLOG_PATH] Enable aklog to get token (default=/usr/bin/aklog). + --with-session-hooks Enable hooks for executing external commands before/after a session --with-privsep-path=xxx Path for privilege separation chroot (default=/var/empty) --with-xauth=PATH Specify path to xauth program --with-maildir=/path/to/mail Specify your system mail directory @@ -2583,6 +2606,175 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu +# Handle Globus configuration right away, because the Globus flavor +# determines our compiler options. + +# Check whether the user wants GSI (Globus) support +gsi_path="no" + +# Check whether --with-gsi was given. +if test "${with_gsi+set}" = set; then : + withval=$with_gsi; + gsi_path="$withval" + + +fi + + + +# Check whether --with-globus was given. +if test "${with_globus+set}" = set; then : + withval=$with_globus; + gsi_path="$withval" + + +fi + + + +# Check whether --with-globus-static was given. +if test "${with_globus_static+set}" = set; then : + withval=$with_globus_static; + gsi_static="-static" + if test "x$gsi_path" = "xno" ; then + gsi_path="$withval" + fi + + +fi + + +# Check whether the user has a Globus flavor type +globus_flavor_type="no" + +# Check whether --with-globus-flavor was given. +if test "${with_globus_flavor+set}" = set; then : + withval=$with_globus_flavor; + globus_flavor_type="$withval" + if test "x$gsi_path" = "xno" ; then + gsi_path="yes" + fi + + +fi + + +if test "x$gsi_path" != "xno" ; then + # Globus GSSAPI configuration + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Globus GSI" >&5 +$as_echo_n "checking for Globus GSI... " >&6; } + +$as_echo "#define GSI 1" >>confdefs.h + + + if test "$GSSAPI" -a "$GSSAPI" != "mechglue"; then + as_fn_error $? "Previously configured GSSAPI library conflicts with Globus GSI." "$LINENO" 5 + fi + if test -z "$GSSAPI"; then + $as_echo "#define GSSAPI 1" >>confdefs.h + + GSSAPI="GSI" + fi + + if test "x$gsi_path" = "xyes" ; then + if test -z "$GLOBUS_LOCATION" ; then + as_fn_error $? "GLOBUS_LOCATION environment variable must be set." "$LINENO" 5 + else + gsi_path="$GLOBUS_LOCATION" + fi + fi + GLOBUS_LOCATION="$gsi_path" + export GLOBUS_LOCATION + LD_LIBRARY_PATH="${gsi_path}/lib:$LD_LIBRARY_PATH" + export LD_LIBRARY_PATH + if test ! -d "$GLOBUS_LOCATION" ; then + as_fn_error $? "Cannot find Globus installation. Set GLOBUS_LOCATION environment variable." "$LINENO" 5 + fi + + if test "x$globus_flavor_type" = "xno" ; then + as_fn_error $? "--with-globus-flavor=TYPE must be specified" "$LINENO" 5 + fi + if test "x$globus_flavor_type" = "xyes" ; then + as_fn_error $? "--with-globus-flavor=TYPE must specify a flavor type" "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GLOBUS_LOCATION" >&5 +$as_echo "$GLOBUS_LOCATION" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Globus include path" >&5 +$as_echo_n "checking for Globus include path... " >&6; } + if test -d "${gsi_path}/include/${globus_flavor_type}" ; then + GLOBUS_INCLUDE="${gsi_path}/include/${globus_flavor_type}" + elif test -d "${gsi_path}/include/globus" ; then + GLOBUS_INCLUDE="${gsi_path}/include/globus" + else + as_fn_error $? "Cannot find Globus include directory in ${gsi_path}/include" "$LINENO" 5 + fi + GSI_CPPFLAGS="-I${GLOBUS_INCLUDE}" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for globus-makefile-header" >&5 +$as_echo_n "checking for globus-makefile-header... " >&6; } + if test -x ${gsi_path}/bin/globus-makefile-header ; then + ${gsi_path}/bin/globus-makefile-header --flavor=${globus_flavor_type} ${gsi_static} globus_gss_assist globus_usage 2>/dev/null | sed 's/ = \(.*\)/="\1"/' > ./gpt_build_tmp.sh + elif test -x ${gsi_path}/sbin/globus-makefile-header ; then + ${gsi_path}/sbin/globus-makefile-header --flavor=${globus_flavor_type} ${gsi_static} globus_gss_assist globus_usage 2>/dev/null | sed 's/ = \(.*\)/="\1"/' > ./gpt_build_tmp.sh + fi + if test -f ./gpt_build_tmp.sh ; then + . ./gpt_build_tmp.sh + fi + if test -z "$GLOBUS_PKG_LIBS" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gpt_build_config" >&5 +$as_echo_n "checking for gpt_build_config... " >&6; } + # globus-makefile-header failed so try gpt_build_config + # likely this is because gpt-postinstall hasn't been run yet + # (i.e., this is a fresh Globus Toolkit install) + if test -x $GPT_LOCATION/sbin/gpt_build_config ; then + gpt_linkline_helper="$GPT_LOCATION/sbin/gpt_build_config" + elif test -x ${gsi_path}/sbin/gpt_build_config ; then + gpt_linkline_helper="${gsi_path}/sbin/gpt_build_config" + else + as_fn_error $? "Cannot find gpt_build_config: GPT installation is incomplete" "$LINENO" 5 + fi + if test -n "${gsi_static}"; then + ${gpt_linkline_helper} -f ${globus_flavor_type} -link static -src pkg_data_src.gpt + else + ${gpt_linkline_helper} -f ${globus_flavor_type} -link shared -src pkg_data_src.gpt + fi + . ./gpt_build_temp.sh + if test -z "$GPT_CONFIG_PGM_LINKS" ; then + as_fn_error $? "gpt_build_config failed" "$LINENO" 5 + fi + GSI_LDFLAGS="-L${gsi_path}/lib" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + $as_echo "#define HAVE_GSSAPI_H 1" >>confdefs.h + + + if test -n "$GLOBUS_CC" ; then + CC="$GLOBUS_CC" + fi + CFLAGS="$CFLAGS $GLOBUS_CFLAGS $GPT_CONFIG_CFLAGS" + if test -n "$GLOBUS_CPP" ; then + CPP="$GLOBUS_CPP" + fi + CPPFLAGS="$CPPFLAGS $GLOBUS_CPPFLAGS $GLOBUS_INCLUDES $GSI_CPPFLAGS $GPT_CONFIG_INCLUDES" + LIBS="$LIBS $GLOBUS_LIBS $GLOBUS_PKG_LIBS $GPT_CONFIG_LIBS $GPT_CONFIG_PGM_LINKS" + if test -n "$GLOBUS_LD" ; then + LD="$GLOBUS_LD" + fi + LDFLAGS="$LDFLAGS $GLOBUS_LDFLAGS $GSI_LDFLAGS" + + INSTALL_GSISSH="yes" +else + INSTALL_GSISSH="" +fi +# End Globus/GSI section + ac_config_headers="$ac_config_headers config.h" ac_ext=c @@ -5812,49 +6004,8 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext } - { - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wuninitialized" >&5 -$as_echo_n "checking if $CC supports compile flag -Wuninitialized... " >&6; } - saved_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $WERROR -Wuninitialized" - _define_flag="" - test "x$_define_flag" = "x" && _define_flag="-Wuninitialized" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include -int main(int argc, char **argv) { - /* Some math to catch -ftrapv problems in the toolchain */ - int i = 123 * argc, j = 456 + argc, k = 789 - argc; - float l = i * 2.1; - double m = l / 0.5; - long long int n = argc * 12345LL, o = 12345LL * (long long int)argc; - printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o); - exit(0); -} - -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -if `grep -i "unrecognized option" conftest.err >/dev/null` -then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CFLAGS="$saved_CFLAGS" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - CFLAGS="$saved_CFLAGS $_define_flag" -fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - CFLAGS="$saved_CFLAGS" - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -} +# cc1: warning: -Wuninitialized is not supported without -O +# OSSH_CHECK_CFLAG_COMPILE([-Wuninitialized]) { { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Wsign-compare" >&5 $as_echo_n "checking if $CC supports compile flag -Wsign-compare... " >&6; } @@ -7115,38 +7266,9 @@ ;; *-*-darwin*) - use_pie=auto - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have working getaddrinfo" >&5 -$as_echo_n "checking if we have working getaddrinfo... " >&6; } - if test "$cross_compiling" = yes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: assume it is working" >&5 -$as_echo "assume it is working" >&6; } -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - #include -main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) - exit(0); - else - exit(1); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: working" >&5 -$as_echo "working" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: buggy" >&5 -$as_echo "buggy" >&6; } $as_echo "#define BROKEN_GETADDRINFO 1" >>confdefs.h - -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - $as_echo "#define SETEUID_BREAKS_SETUID 1" >>confdefs.h $as_echo "#define BROKEN_SETREUID 1" >>confdefs.h @@ -7170,6 +7292,63 @@ $as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have the Security Authorization Session API" >&5 +$as_echo_n "checking if we have the Security Authorization Session API... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +SessionCreate(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_use_security_session_api="yes" + +$as_echo "#define USE_SECURITY_SESSION_API 1" >>confdefs.h + + LIBS="$LIBS -framework Security" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + ac_cv_use_security_session_api="no" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have an in-memory credentials cache" >&5 +$as_echo_n "checking if we have an in-memory credentials cache... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +cc_context_t c; + (void) cc_initialize (&c, 0, NULL, NULL); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +$as_echo "#define USE_CCAPI 1" >>confdefs.h + + LIBS="$LIBS -framework Security" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + if test "x$ac_cv_use_security_session_api" = "xno"; then + as_fn_error $? "*** Need a security framework to use the credentials cache API ***" "$LINENO" 5 + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_fn_c_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default" if test "x$ac_cv_have_decl_AU_IPv4" = xyes; then : @@ -7199,18 +7378,8 @@ fi done - for ac_header in sandbox.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "sandbox.h" "ac_cv_header_sandbox_h" "$ac_includes_default" -if test "x$ac_cv_header_sandbox_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SANDBOX_H 1 -_ACEOF - -fi - -done - + # unreliable with autoconf pre-2.64 (such as used by GPT) + # AC_CHECK_HEADERS([sandbox.h]) ;; *-*-dragonfly*) SSHDLIBS="$SSHDLIBS -lcrypt" @@ -16557,6 +16726,240 @@ +# Finish configuring Globus GSSAPI +if test "x$gsi_path" != "xno" ; then + if test ! -z "$need_dash_r" ; then + LDFLAGS="$LDFLAGS -R${gsi_path}/lib" + fi + if test ! -z "$blibpath" ; then + blibpath="$blibpath:${gsi_path}/lib" + fi + # test that we got the libraries OK + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Globus linkline" >&5 +$as_echo_n "checking Globus linkline... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +else + + as_fn_error $? "link with Globus libraries failed" "$LINENO" 5 + + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + for ac_func in globus_gss_assist_map_and_authorize +do : + ac_fn_c_check_func "$LINENO" "globus_gss_assist_map_and_authorize" "ac_cv_func_globus_gss_assist_map_and_authorize" +if test "x$ac_cv_func_globus_gss_assist_map_and_authorize" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE 1 +_ACEOF + +fi +done + +fi + + +ac_fn_c_check_func "$LINENO" "globus_usage_stats_send" "ac_cv_func_globus_usage_stats_send" +if test "x$ac_cv_func_globus_usage_stats_send" = xyes; then : + +$as_echo "#define HAVE_GLOBUS_USAGE 1" >>confdefs.h + +fi + + +ac_fn_c_check_func "$LINENO" "globus_usage_stats_send_array" "ac_cv_func_globus_usage_stats_send_array" +if test "x$ac_cv_func_globus_usage_stats_send_array" = xyes; then : + +$as_echo "#define HAVE_GLOBUS_USAGE_SEND_ARRAY 1" >>confdefs.h + +fi + + +# Check whether the user wants GSSAPI mechglue support + +# Check whether --with-mechglue was given. +if test "${with_mechglue+set}" = set; then : + withval=$with_mechglue; + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mechglue library" >&5 +$as_echo_n "checking for mechglue library... " >&6; } + + if test -e ${withval}/libgssapi.a ; then + mechglue_lib=${withval}/libgssapi.a + elif test -e ${withval}/lib/libgssapi.a ; then + mechglue_lib=${withval}/lib/libgssapi.a + else + as_fn_error $? "\"Can't find libgssapi in ${withval}\"" "$LINENO" 5; + fi + LIBS="${mechglue_lib} $LIBS" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${mechglue_lib}" >&5 +$as_echo "${mechglue_lib}" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBDL 1 +_ACEOF + + LIBS="-ldl $LIBS" + +fi + + if test $ac_cv_lib_dl_dlopen = yes; then + LDFLAGS="$LDFLAGS -ldl -Wl,-Bsymbolic" + fi + + $as_echo "#define GSSAPI 1" >>confdefs.h + + +$as_echo "#define MECHGLUE 1" >>confdefs.h + + GSSAPI="mechglue" + + +fi + + + +NERSC_MOD='no' + +# Check whether --with-nerscmod was given. +if test "${with_nerscmod+set}" = set; then : + withval=$with_nerscmod; + if test "x$withval" != "xno" ; then + NERSC_MOD='yes' + +$as_echo "#define NERSC_MOD 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + fi + + +fi + + +STUNNEL_PORT='799' + +# Check whether --with-stunnelport was given. +if test "${with_stunnelport+set}" = set; then : + withval=$with_stunnelport; + + case "$withval" in + [0-9]*) + STUNNEL_PORT="$withval" + ;; + *) + as_fn_error $? "You must specify a numeric port number for --with-stunnelport" "$LINENO" 5 + ;; + esac + + if test ! -z "$withval" ; then + #STUNNEL_PORT="$withval" + +cat >>confdefs.h <<_ACEOF +#define STUNNEL_PORT $STUNNEL_PORT +_ACEOF + + fi + + +fi + + +STUNNEL_HOST='localhost' + +# Check whether --with-stunnelhost was given. +if test "${with_stunnelhost+set}" = set; then : + withval=$with_stunnelhost; + + STUNNEL_HOST="localhost" + + if test "x$withval" != "xno" ; then + STUNNEL_HOST="\"$withval\"" + +cat >>confdefs.h <<_ACEOF +#define STUNNEL_HOST $STUNNEL_HOST +_ACEOF + + fi + + +fi + + + +PASSWD_REC='no' + +# Check whether --with-passwdrec was given. +if test "${with_passwdrec+set}" = set; then : + withval=$with_passwdrec; + if test "x$withval" != "xno" ; then + PASSWD_REC='yes' + +$as_echo "#define PASSWD_REC 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + + fi + + +fi + + + # Check whether user wants Kerberos 5 support KRB5_MSG="no" @@ -17005,7 +17408,27 @@ - fi + # If we're using some other GSSAPI + if test "$GSSAPI" -a "$GSSAPI" != "mechglue"; then + as_fn_error $? "$GSSAPI GSSAPI library conflicts with Kerberos support. Use mechglue instead." "$LINENO" 5 + fi + + if test -z "$GSSAPI"; then + GSSAPI="KRB5"; + fi + + oldCPP="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi" + ac_fn_c_check_header_mongrel "$LINENO" "gssapi_krb5.h" "ac_cv_header_gssapi_krb5_h" "$ac_includes_default" +if test "x$ac_cv_header_gssapi_krb5_h" = xyes; then : + +else + CPPFLAGS="$oldCPP" +fi + + + + fi if test ! -z "$need_dash_r" ; then LDFLAGS="$LDFLAGS -R${KRB5ROOT}/lib" fi @@ -17160,6 +17583,57 @@ +# Check whether user wants AFS_KRB5 support +AFS_KRB5_MSG="no" + +# Check whether --with-afs-krb5 was given. +if test "${with_afs_krb5+set}" = set; then : + withval=$with_afs_krb5; + if test "x$withval" != "xno" ; then + + if test "x$withval" != "xyes" ; then + +cat >>confdefs.h <<_ACEOF +#define AKLOG_PATH "$withval" +_ACEOF + + else + +cat >>confdefs.h <<_ACEOF +#define AKLOG_PATH "/usr/bin/aklog" +_ACEOF + + fi + + if test -z "$KRB5ROOT" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: AFS_KRB5 requires Kerberos 5 support, build may fail" >&5 +$as_echo "$as_me: WARNING: AFS_KRB5 requires Kerberos 5 support, build may fail" >&2;} + fi + + LIBS="-lkrbafs -lkrb4 $LIBS" + if test ! -z "$AFS_LIBS" ; then + LIBS="$LIBS $AFS_LIBS" + fi + +$as_echo "#define AFS_KRB5 1" >>confdefs.h + + AFS_KRB5_MSG="yes" + fi + + +fi + + + +# Check whether --with-session-hooks was given. +if test "${with_session_hooks+set}" = set; then : + withval=$with_session_hooks; +$as_echo "#define SESSION_HOOKS 1" >>confdefs.h + + +fi + + # Looking for programs, paths and files PRIVSEP_PATH=/var/empty @@ -17241,7 +17715,10 @@ fi +# strip causes problems with GSI libraries... +if test -z "$GLOBUS_LDFLAGS" ; then STRIP_OPT=-s +fi # Check whether --enable-strip was given. if test "${enable_strip+set}" = set; then : enableval=$enable_strip; @@ -19693,6 +20170,12 @@ echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" echo " BSD Auth support: $BSD_AUTH_MSG" echo " Random number source: $RAND_MSG" +echo " NERSC Mods: $NERSC_MOD" +if test "x$NERSC_MOD" = "xyes" ; then +echo " STUNNEL Host: $STUNNEL_HOST" +echo " STUNNEL Port: $STUNNEL_PORT" +echo " Record Passwd Data: $PASSWD_REC" +fi echo " Privsep sandbox style: $SANDBOX_STYLE" echo "" diff -Naur --exclude=autom4te.cache openssh-6.6p1/configure.ac openssh-6.6p1-gssapi/configure.ac --- openssh-6.6p1/configure.ac 2014-02-21 11:09:34.000000000 -0600 +++ openssh-6.6p1-gssapi/configure.ac 2014-03-18 15:05:44.000000000 -0500 @@ -19,6 +19,151 @@ AC_CONFIG_SRCDIR([ssh.c]) AC_LANG([C]) +# Handle Globus configuration right away, because the Globus flavor +# determines our compiler options. + +# Check whether the user wants GSI (Globus) support +gsi_path="no" +AC_ARG_WITH(gsi, + [ --with-gsi Enable Globus GSI authentication support], + [ + gsi_path="$withval" + ] +) + +AC_ARG_WITH(globus, + [ --with-globus Enable Globus GSI authentication support], + [ + gsi_path="$withval" + ] +) + +AC_ARG_WITH(globus-static, + [ --with-globus-static Link statically with Globus GSI libraries], + [ + gsi_static="-static" + if test "x$gsi_path" = "xno" ; then + gsi_path="$withval" + fi + ] +) + +# Check whether the user has a Globus flavor type +globus_flavor_type="no" +AC_ARG_WITH(globus-flavor, + [ --with-globus-flavor=TYPE Specify Globus flavor type (ex: gcc32dbg)], + [ + globus_flavor_type="$withval" + if test "x$gsi_path" = "xno" ; then + gsi_path="yes" + fi + ] +) + +if test "x$gsi_path" != "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 "$GSSAPI" -a "$GSSAPI" != "mechglue"; then + AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Globus GSI.]) + fi + if test -z "$GSSAPI"; then + AC_DEFINE(GSSAPI) + GSSAPI="GSI" + fi + + if test "x$gsi_path" = "xyes" ; then + if test -z "$GLOBUS_LOCATION" ; then + AC_MSG_ERROR(GLOBUS_LOCATION environment variable must be set.) + else + gsi_path="$GLOBUS_LOCATION" + fi + fi + GLOBUS_LOCATION="$gsi_path" + export GLOBUS_LOCATION + LD_LIBRARY_PATH="${gsi_path}/lib:$LD_LIBRARY_PATH" + export LD_LIBRARY_PATH + if test ! -d "$GLOBUS_LOCATION" ; then + AC_MSG_ERROR(Cannot find Globus installation. Set GLOBUS_LOCATION environment variable.) + fi + + if test "x$globus_flavor_type" = "xno" ; then + AC_MSG_ERROR(--with-globus-flavor=TYPE must be specified) + fi + if test "x$globus_flavor_type" = "xyes" ; then + AC_MSG_ERROR(--with-globus-flavor=TYPE must specify a flavor type) + fi + AC_MSG_RESULT($GLOBUS_LOCATION) + + AC_MSG_CHECKING(for Globus include path) + if test -d "${gsi_path}/include/${globus_flavor_type}" ; then + GLOBUS_INCLUDE="${gsi_path}/include/${globus_flavor_type}" + elif test -d "${gsi_path}/include/globus" ; then + GLOBUS_INCLUDE="${gsi_path}/include/globus" + else + AC_MSG_ERROR(Cannot find Globus include directory in ${gsi_path}/include) + fi + GSI_CPPFLAGS="-I${GLOBUS_INCLUDE}" + AC_MSG_RESULT(yes) + + AC_MSG_CHECKING(for globus-makefile-header) + if test -x ${gsi_path}/bin/globus-makefile-header ; then + ${gsi_path}/bin/globus-makefile-header --flavor=${globus_flavor_type} ${gsi_static} globus_gss_assist globus_usage 2>/dev/null | sed 's/ = \(.*\)/="\1"/' > ./gpt_build_tmp.sh + elif test -x ${gsi_path}/sbin/globus-makefile-header ; then + ${gsi_path}/sbin/globus-makefile-header --flavor=${globus_flavor_type} ${gsi_static} globus_gss_assist globus_usage 2>/dev/null | sed 's/ = \(.*\)/="\1"/' > ./gpt_build_tmp.sh + fi + if test -f ./gpt_build_tmp.sh ; then + . ./gpt_build_tmp.sh + fi + if test -z "$GLOBUS_PKG_LIBS" ; then + AC_MSG_RESULT(no) + AC_MSG_CHECKING(for gpt_build_config) + # globus-makefile-header failed so try gpt_build_config + # likely this is because gpt-postinstall hasn't been run yet + # (i.e., this is a fresh Globus Toolkit install) + if test -x $GPT_LOCATION/sbin/gpt_build_config ; then + gpt_linkline_helper="$GPT_LOCATION/sbin/gpt_build_config" + elif test -x ${gsi_path}/sbin/gpt_build_config ; then + gpt_linkline_helper="${gsi_path}/sbin/gpt_build_config" + else + AC_MSG_ERROR(Cannot find gpt_build_config: GPT installation is incomplete) + fi + if test -n "${gsi_static}"; then + ${gpt_linkline_helper} -f ${globus_flavor_type} -link static -src pkg_data_src.gpt + else + ${gpt_linkline_helper} -f ${globus_flavor_type} -link shared -src pkg_data_src.gpt + fi + . ./gpt_build_temp.sh + if test -z "$GPT_CONFIG_PGM_LINKS" ; then + AC_MSG_ERROR(gpt_build_config failed) + fi + GSI_LDFLAGS="-L${gsi_path}/lib" + fi + AC_MSG_RESULT(yes) + + AC_DEFINE(HAVE_GSSAPI_H) + + if test -n "$GLOBUS_CC" ; then + CC="$GLOBUS_CC" + fi + CFLAGS="$CFLAGS $GLOBUS_CFLAGS $GPT_CONFIG_CFLAGS" + if test -n "$GLOBUS_CPP" ; then + CPP="$GLOBUS_CPP" + fi + CPPFLAGS="$CPPFLAGS $GLOBUS_CPPFLAGS $GLOBUS_INCLUDES $GSI_CPPFLAGS $GPT_CONFIG_INCLUDES" + LIBS="$LIBS $GLOBUS_LIBS $GLOBUS_PKG_LIBS $GPT_CONFIG_LIBS $GPT_CONFIG_PGM_LINKS" + if test -n "$GLOBUS_LD" ; then + LD="$GLOBUS_LD" + fi + LDFLAGS="$LDFLAGS $GLOBUS_LDFLAGS $GSI_LDFLAGS" + + INSTALL_GSISSH="yes" +else + INSTALL_GSISSH="" +fi +# End Globus/GSI section + AC_CONFIG_HEADER([config.h]) AC_PROG_CC AC_CANONICAL_HOST @@ -152,7 +297,8 @@ OSSH_CHECK_CFLAG_COMPILE([-Wunknown-warning-option]) OSSH_CHECK_CFLAG_COMPILE([-Wall]) OSSH_CHECK_CFLAG_COMPILE([-Wpointer-arith]) - OSSH_CHECK_CFLAG_COMPILE([-Wuninitialized]) +# cc1: warning: -Wuninitialized is not supported without -O +# OSSH_CHECK_CFLAG_COMPILE([-Wuninitialized]) OSSH_CHECK_CFLAG_COMPILE([-Wsign-compare]) OSSH_CHECK_CFLAG_COMPILE([-Wformat-security]) OSSH_CHECK_CFLAG_COMPILE([-Wsizeof-pointer-memaccess]) @@ -558,21 +704,7 @@ AC_DEFINE([BROKEN_SETREGID]) ;; *-*-darwin*) - use_pie=auto - AC_MSG_CHECKING([if we have working getaddrinfo]) - AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include -main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) - exit(0); - else - exit(1); -} - ]])], - [AC_MSG_RESULT([working])], - [AC_MSG_RESULT([buggy]) - AC_DEFINE([BROKEN_GETADDRINFO], [1], - [getaddrinfo is broken (if present)]) - ], - [AC_MSG_RESULT([assume it is working])]) + AC_DEFINE(BROKEN_GETADDRINFO, 1, [assume getaddrinfo is broken)]) AC_DEFINE([SETEUID_BREAKS_SETUID]) AC_DEFINE([BROKEN_SETREUID]) AC_DEFINE([BROKEN_SETREGID]) @@ -584,6 +716,30 @@ [Use tunnel device compatibility to OpenBSD]) AC_DEFINE([SSH_TUN_PREPEND_AF], [1], [Prepend the address family to IP tunnel traffic]) + AC_MSG_CHECKING(if we have the Security Authorization Session API) + AC_TRY_COMPILE([#include ], + [SessionCreate(0, 0);], + [ac_cv_use_security_session_api="yes" + AC_DEFINE(USE_SECURITY_SESSION_API, 1, + [platform has the Security Authorization Session API]) + LIBS="$LIBS -framework Security" + AC_MSG_RESULT(yes)], + [ac_cv_use_security_session_api="no" + AC_MSG_RESULT(no)]) + AC_MSG_CHECKING(if we have an in-memory credentials cache) + AC_TRY_COMPILE( + [#include ], + [cc_context_t c; + (void) cc_initialize (&c, 0, NULL, NULL);], + [AC_DEFINE(USE_CCAPI, 1, + [platform uses an in-memory credentials cache]) + LIBS="$LIBS -framework Security" + AC_MSG_RESULT(yes) + if test "x$ac_cv_use_security_session_api" = "xno"; then + AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***) + fi], + [AC_MSG_RESULT(no)] + ) m4_pattern_allow([AU_IPv]) AC_CHECK_DECL([AU_IPv4], [], AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records]) @@ -595,7 +751,8 @@ [Define to a Set Process Title type if your system is supported by bsd-setproctitle.c]) AC_CHECK_FUNCS([sandbox_init]) - AC_CHECK_HEADERS([sandbox.h]) + # unreliable with autoconf pre-2.64 (such as used by GPT) + # AC_CHECK_HEADERS([sandbox.h]) ;; *-*-dragonfly*) SSHDLIBS="$SSHDLIBS -lcrypt" @@ -3919,6 +4076,134 @@ AC_SUBST([SSHLIBS]) AC_SUBST([SSHDLIBS]) +# Finish configuring Globus GSSAPI +if test "x$gsi_path" != "xno" ; then + if test ! -z "$need_dash_r" ; then + LDFLAGS="$LDFLAGS -R${gsi_path}/lib" + fi + if test ! -z "$blibpath" ; then + blibpath="$blibpath:${gsi_path}/lib" + fi + # test that we got the libraries OK + AC_MSG_CHECKING(Globus linkline) + AC_TRY_LINK( + [], + [], + [ + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_ERROR(link with Globus libraries failed) + ] + ) + AC_CHECK_FUNCS(globus_gss_assist_map_and_authorize) +fi +AC_SUBST(INSTALL_GSISSH) + +dnl +dnl Check for globus_usage_stats_send +dnl +AC_CHECK_FUNC(globus_usage_stats_send, + AC_DEFINE([HAVE_GLOBUS_USAGE], 1, [Have Globus Usage])) + +dnl +dnl Check for globus_usage_stats_send_array +dnl +AC_CHECK_FUNC(globus_usage_stats_send_array, + AC_DEFINE([HAVE_GLOBUS_USAGE_SEND_ARRAY], 1, + [Have Globus Usage send_array])) + +# Check whether the user wants GSSAPI mechglue support +AC_ARG_WITH(mechglue, + [ --with-mechglue=PATH Build with GSSAPI mechglue library], + [ + AC_MSG_CHECKING(for mechglue library) + + if test -e ${withval}/libgssapi.a ; then + mechglue_lib=${withval}/libgssapi.a + elif test -e ${withval}/lib/libgssapi.a ; then + mechglue_lib=${withval}/lib/libgssapi.a + else + AC_MSG_ERROR("Can't find libgssapi in ${withval}"); + fi + LIBS="${mechglue_lib} $LIBS" + AC_MSG_RESULT(${mechglue_lib}) + + AC_CHECK_LIB(dl, dlopen, , ) + if test $ac_cv_lib_dl_dlopen = yes; then + LDFLAGS="$LDFLAGS -ldl -Wl,-Bsymbolic" + fi + + AC_DEFINE(GSSAPI) + AC_DEFINE(MECHGLUE, 1, [Define this if you're building with GSSAPI MechGlue.]) + GSSAPI="mechglue" + ] +) + + +NERSC_MOD='no' +AC_ARG_WITH(nerscmod, + [ --with-nerscmod Add sshd instrumentation], + [ + if test "x$withval" != "xno" ; then + NERSC_MOD='yes' + AC_DEFINE(NERSC_MOD, 1, [define for NERSC mods]) + AC_MSG_RESULT(yes) + + fi + ] +) + +STUNNEL_PORT='799' +AC_ARG_WITH(stunnelport, + [ --with-stunnelport=PORT Set stunnel port if other than 799/tcp ], + [ + + case "$withval" in + [[0-9]]*) + STUNNEL_PORT="$withval" + ;; + *) + AC_MSG_ERROR(You must specify a numeric port number for --with-stunnelport) + ;; + esac + + if test ! -z "$withval" ; then + #STUNNEL_PORT="$withval" + AC_DEFINE_UNQUOTED(STUNNEL_PORT, $STUNNEL_PORT, [define for NERSC mods]) + fi + ] +) + +STUNNEL_HOST='localhost' +AC_ARG_WITH(stunnelhost, + [ --with-stunnelhost=HOST Set stunnel host if other than localhost. Do not quote.], + [ + + STUNNEL_HOST="localhost" + + if test "x$withval" != "xno" ; then + STUNNEL_HOST="\"$withval\"" + AC_DEFINE_UNQUOTED(STUNNEL_HOST, $STUNNEL_HOST, [define for NERSC mods]) + fi + ] +) + + +PASSWD_REC='no' +AC_ARG_WITH(passwdrec, + [ --with-passwdrec record password data], + [ + if test "x$withval" != "xno" ; then + PASSWD_REC='yes' + AC_DEFINE(PASSWD_REC, 1, [set to record password info]) + AC_MSG_RESULT(yes) + + fi + ] +) + + # Check whether user wants Kerberos 5 support KRB5_MSG="no" AC_ARG_WITH([kerberos5], @@ -4009,7 +4294,21 @@ AC_CHECK_HEADER([gssapi_krb5.h], , [ CPPFLAGS="$oldCPP" ]) - fi + # If we're using some other GSSAPI + if test "$GSSAPI" -a "$GSSAPI" != "mechglue"; then + AC_MSG_ERROR([$GSSAPI GSSAPI library conflicts with Kerberos support. Use mechglue instead.]) + fi + + if test -z "$GSSAPI"; then + GSSAPI="KRB5"; + fi + + oldCPP="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi" + AC_CHECK_HEADER(gssapi_krb5.h, , + [ CPPFLAGS="$oldCPP" ]) + + fi if test ! -z "$need_dash_r" ; then LDFLAGS="$LDFLAGS -R${KRB5ROOT}/lib" fi @@ -4048,6 +4347,42 @@ AC_SUBST([GSSLIBS]) AC_SUBST([K5LIBS]) +# Check whether user wants AFS_KRB5 support +AFS_KRB5_MSG="no" +AC_ARG_WITH(afs-krb5, + [ --with-afs-krb5[[=AKLOG_PATH]] Enable aklog to get token (default=/usr/bin/aklog).], + [ + if test "x$withval" != "xno" ; then + + if test "x$withval" != "xyes" ; then + AC_DEFINE_UNQUOTED(AKLOG_PATH, "$withval", + [Define this if you want to use AFS/Kerberos 5 option, which runs aklog.]) + else + AC_DEFINE_UNQUOTED(AKLOG_PATH, + "/usr/bin/aklog", + [Define this if you want to use AFS/Kerberos 5 option, which runs aklog.]) + fi + + if test -z "$KRB5ROOT" ; then + AC_MSG_WARN([AFS_KRB5 requires Kerberos 5 support, build may fail]) + fi + + LIBS="-lkrbafs -lkrb4 $LIBS" + if test ! -z "$AFS_LIBS" ; then + LIBS="$LIBS $AFS_LIBS" + fi + AC_DEFINE(AFS_KRB5, 1, + [Define this if you want to use AFS/Kerberos 5 option, which runs aklog.]) + AFS_KRB5_MSG="yes" + fi + ] +) + +AC_ARG_WITH(session-hooks, + [ --with-session-hooks Enable hooks for executing external commands before/after a session], + [ AC_DEFINE(SESSION_HOOKS, 1, [Define this if you want support for startup/shutdown hooks]) ] +) + # Looking for programs, paths and files PRIVSEP_PATH=/var/empty @@ -4083,7 +4418,10 @@ ] ) +# strip causes problems with GSI libraries... +if test -z "$GLOBUS_LDFLAGS" ; then STRIP_OPT=-s +fi AC_ARG_ENABLE([strip], [ --disable-strip Disable calling strip(1) on install], [ @@ -4853,6 +5191,12 @@ echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" echo " BSD Auth support: $BSD_AUTH_MSG" echo " Random number source: $RAND_MSG" +echo " NERSC Mods: $NERSC_MOD" +if test "x$NERSC_MOD" = "xyes" ; then +echo " STUNNEL Host: $STUNNEL_HOST" +echo " STUNNEL Port: $STUNNEL_PORT" +echo " Record Passwd Data: $PASSWD_REC" +fi echo " Privsep sandbox style: $SANDBOX_STYLE" echo "" diff -Naur --exclude=autom4te.cache openssh-6.6p1/ge25519.h openssh-6.6p1-gssapi/ge25519.h --- openssh-6.6p1/ge25519.h 2013-12-18 00:48:11.000000000 -0600 +++ openssh-6.6p1-gssapi/ge25519.h 2014-03-18 15:05:44.000000000 -0500 @@ -28,7 +28,7 @@ fe25519 t; } ge25519; -const ge25519 ge25519_base; +extern const ge25519 ge25519_base; int ge25519_unpackneg_vartime(ge25519 *r, const unsigned char p[32]); diff -Naur --exclude=autom4te.cache openssh-6.6p1/gss-genr.c openssh-6.6p1-gssapi/gss-genr.c --- openssh-6.6p1/gss-genr.c 2013-11-07 19:19:57.000000000 -0600 +++ openssh-6.6p1-gssapi/gss-genr.c 2014-03-18 15:05:44.000000000 -0500 @@ -1,7 +1,7 @@ /* $OpenBSD: gss-genr.c,v 1.22 2013/11/08 00:39:15 djm Exp $ */ /* - * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,13 +38,169 @@ #include "xmalloc.h" #include "buffer.h" #include "log.h" +#include "canohost.h" #include "ssh2.h" +#include "cipher.h" +#include "key.h" +#include "kex.h" +#include #include "ssh-gss.h" extern u_char *session_id2; extern u_int session_id2_len; +typedef struct { + char *encoded; + gss_OID oid; +} ssh_gss_kex_mapping; + +/* + * XXX - It would be nice to find a more elegant way of handling the + * XXX passing of the key exchange context to the userauth routines + */ + +Gssctxt *gss_kex_context = NULL; + +static ssh_gss_kex_mapping *gss_enc2oid = NULL; + +int +ssh_gssapi_oid_table_ok() { + return (gss_enc2oid != NULL); +} + +/* + * Return a list of the gss-group1-sha1 mechanisms supported by this program + * + * We test mechanisms to ensure that we can use them, to avoid starting + * a key exchange with a bad mechanism + */ + +char * +ssh_gssapi_client_mechanisms(const char *host, const char *client) { + gss_OID_set gss_supported; + OM_uint32 min_status; + + if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported))) + return NULL; + + return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, + host, client)); +} + +char * +ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, + const char *host, const char *client) { + Buffer buf; + size_t i; + int oidpos, enclen; + char *mechs, *encoded; + u_char digest[EVP_MAX_MD_SIZE]; + char deroid[2]; + const EVP_MD *evp_md = EVP_md5(); + EVP_MD_CTX md; + + if (gss_enc2oid != NULL) { + for (i = 0; gss_enc2oid[i].encoded != NULL; i++) + free(gss_enc2oid[i].encoded); + free(gss_enc2oid); + } + + gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) * + (gss_supported->count + 1)); + + buffer_init(&buf); + + oidpos = 0; + for (i = 0; i < gss_supported->count; i++) { + if (gss_supported->elements[i].length < 128 && + (*check)(NULL, &(gss_supported->elements[i]), host, client)) { + + deroid[0] = SSH_GSS_OIDTYPE; + deroid[1] = gss_supported->elements[i].length; + + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, deroid, 2); + EVP_DigestUpdate(&md, + gss_supported->elements[i].elements, + gss_supported->elements[i].length); + EVP_DigestFinal(&md, digest, NULL); + + encoded = xmalloc(EVP_MD_size(evp_md) * 2); + enclen = __b64_ntop(digest, EVP_MD_size(evp_md), + encoded, EVP_MD_size(evp_md) * 2); + + if (oidpos != 0) + buffer_put_char(&buf, ','); + + buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, + sizeof(KEX_GSS_GEX_SHA1_ID) - 1); + buffer_append(&buf, encoded, enclen); + buffer_put_char(&buf, ','); + buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, + sizeof(KEX_GSS_GRP1_SHA1_ID) - 1); + buffer_append(&buf, encoded, enclen); + buffer_put_char(&buf, ','); + buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID, + sizeof(KEX_GSS_GRP14_SHA1_ID) - 1); + buffer_append(&buf, encoded, enclen); + + gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); + gss_enc2oid[oidpos].encoded = encoded; + oidpos++; + } + } + gss_enc2oid[oidpos].oid = NULL; + gss_enc2oid[oidpos].encoded = NULL; + + buffer_put_char(&buf, '\0'); + + mechs = xmalloc(buffer_len(&buf)); + buffer_get(&buf, mechs, buffer_len(&buf)); + buffer_free(&buf); + + if (strlen(mechs) == 0) { + free(mechs); + mechs = NULL; + } + + return (mechs); +} + +gss_OID +ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) { + int i = 0; + + switch (kex_type) { + case KEX_GSS_GRP1_SHA1: + if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID)) + return GSS_C_NO_OID; + name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1; + break; + case KEX_GSS_GRP14_SHA1: + if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID)) + return GSS_C_NO_OID; + name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1; + break; + case KEX_GSS_GEX_SHA1: + if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID)) + return GSS_C_NO_OID; + name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1; + break; + default: + return GSS_C_NO_OID; + } + + while (gss_enc2oid[i].encoded != NULL && + strcmp(name, gss_enc2oid[i].encoded) != 0) + i++; + + if (gss_enc2oid[i].oid != NULL && ctx != NULL) + ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid); + + return gss_enc2oid[i].oid; +} + /* Check that the OID in a data stream matches that in the context */ int ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) @@ -155,10 +311,13 @@ void ssh_gssapi_delete_ctx(Gssctxt **ctx) { +#if !defined(MECHGLUE) OM_uint32 ms; +#endif if ((*ctx) == NULL) return; +#if !defined(MECHGLUE) /* mechglue has some memory management issues */ if ((*ctx)->context != GSS_C_NO_CONTEXT) gss_delete_sec_context(&ms, &(*ctx)->context, GSS_C_NO_BUFFER); if ((*ctx)->name != GSS_C_NO_NAME) @@ -174,6 +333,7 @@ gss_release_name(&ms, &(*ctx)->client); if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL) gss_release_cred(&ms, &(*ctx)->client_creds); +#endif free(*ctx); *ctx = NULL; @@ -197,7 +357,7 @@ } ctx->major = gss_init_sec_context(&ctx->minor, - GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, + ctx->client_creds, &ctx->context, ctx->name, ctx->oid, GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 0, NULL, recv_tok, NULL, send_tok, flags, NULL); @@ -212,9 +372,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); @@ -222,13 +391,48 @@ &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) ssh_gssapi_error(ctx); + free(xhost); free(gssbuf.value); return (ctx->major); } OM_uint32 +ssh_gssapi_client_identity(Gssctxt *ctx, const char *name) +{ + gss_buffer_desc gssbuf; + gss_name_t gssname; + OM_uint32 status; + gss_OID_set oidset; + + gssbuf.value = (void *) name; + gssbuf.length = strlen(gssbuf.value); + + gss_create_empty_oid_set(&status, &oidset); + gss_add_oid_set_member(&status, ctx->oid, &oidset); + + ctx->major = gss_import_name(&ctx->minor, &gssbuf, + GSS_C_NT_USER_NAME, &gssname); + + if (!ctx->major) + ctx->major = gss_acquire_cred(&ctx->minor, + gssname, 0, oidset, GSS_C_INITIATE, + &ctx->client_creds, NULL, NULL); + + gss_release_name(&status, &gssname); + gss_release_oid_set(&status, &oidset); + + if (ctx->major) + ssh_gssapi_error(ctx); + + return(ctx->major); +} + +OM_uint32 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) { + if (ctx == NULL) + return -1; + if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, GSS_C_QOP_DEFAULT, buffer, hash))) ssh_gssapi_error(ctx); @@ -236,6 +440,19 @@ return (ctx->major); } +/* Priviledged when used by server */ +OM_uint32 +ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) +{ + if (ctx == NULL) + return -1; + + ctx->major = gss_verify_mic(&ctx->minor, ctx->context, + gssbuf, gssmic, NULL); + + return (ctx->major); +} + void ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, const char *context) @@ -249,11 +466,16 @@ } int -ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) +ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host, + const char *client) { gss_buffer_desc token = GSS_C_EMPTY_BUFFER; OM_uint32 major, minor; gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; + Gssctxt *intctx = NULL; + + if (ctx == NULL) + ctx = &intctx; /* RFC 4462 says we MUST NOT do SPNEGO */ if (oid->length == spnego_oid.length && @@ -263,6 +485,10 @@ ssh_gssapi_build_ctx(ctx); ssh_gssapi_set_oid(*ctx, oid); major = ssh_gssapi_import_name(*ctx, host); + + if (!GSS_ERROR(major) && client) + major = ssh_gssapi_client_identity(*ctx, client); + if (!GSS_ERROR(major)) { major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, NULL); @@ -272,10 +498,66 @@ GSS_C_NO_BUFFER); } - if (GSS_ERROR(major)) + if (GSS_ERROR(major) || intctx != NULL) ssh_gssapi_delete_ctx(ctx); return (!GSS_ERROR(major)); } +int +ssh_gssapi_credentials_updated(Gssctxt *ctxt) { + static gss_name_t saved_name = GSS_C_NO_NAME; + static OM_uint32 saved_lifetime = 0; + static gss_OID saved_mech = GSS_C_NO_OID; + static gss_name_t name; + static OM_uint32 last_call = 0; + OM_uint32 lifetime, now, major, minor; + int equal; + + now = time(NULL); + + if (ctxt) { + debug("Rekey has happened - updating saved versions"); + + if (saved_name != GSS_C_NO_NAME) + gss_release_name(&minor, &saved_name); + + major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, + &saved_name, &saved_lifetime, NULL, NULL); + + if (!GSS_ERROR(major)) { + saved_mech = ctxt->oid; + saved_lifetime+= now; + } else { + /* Handle the error */ + } + return 0; + } + + if (now - last_call < 10) + return 0; + + last_call = now; + + if (saved_mech == GSS_C_NO_OID) + return 0; + + major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, + &name, &lifetime, NULL, NULL); + if (major == GSS_S_CREDENTIALS_EXPIRED) + return 0; + else if (GSS_ERROR(major)) + return 0; + + major = gss_compare_name(&minor, saved_name, name, &equal); + gss_release_name(&minor, &name); + if (GSS_ERROR(major)) + return 0; + + if (equal && (saved_lifetime < lifetime + now - 10)) + return 1; + + return 0; +} + #endif /* GSSAPI */ diff -Naur --exclude=autom4te.cache openssh-6.6p1/gss-serv-gsi.c openssh-6.6p1-gssapi/gss-serv-gsi.c --- openssh-6.6p1/gss-serv-gsi.c 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/gss-serv-gsi.c 2014-03-18 15:05:44.000000000 -0500 @@ -0,0 +1,238 @@ +/* + * 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 "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 -Naur --exclude=autom4te.cache openssh-6.6p1/gss-serv-krb5.c openssh-6.6p1-gssapi/gss-serv-krb5.c --- openssh-6.6p1/gss-serv-krb5.c 2014-01-19 20:18:09.000000000 -0600 +++ openssh-6.6p1-gssapi/gss-serv-krb5.c 2014-03-18 15:05:44.000000000 -0500 @@ -1,7 +1,7 @@ /* $OpenBSD: gss-serv-krb5.c,v 1.8 2013/07/20 01:55:13 djm Exp $ */ /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,14 +48,32 @@ #ifdef HEIMDAL # include -#endif -#ifdef HAVE_GSSAPI_KRB5_H -# include -#elif HAVE_GSSAPI_GSSAPI_KRB5_H -# include +#elif !defined(MECHGLUE) +# ifdef HAVE_GSSAPI_KRB5_H +# include +# elif HAVE_GSSAPI_GSSAPI_KRB5_H +# include +# endif #endif static krb5_context krb_context = NULL; +static int ssh_gssapi_krb5_init(); +static int ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name); +static int ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user); +static void ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client); +static int ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, + ssh_gssapi_client *client); + +ssh_gssapi_mech gssapi_kerberos_mech = { + "toWM5Slw5Ew8Mqkay+al2g==", + "Kerberos", + {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}, + NULL, + &ssh_gssapi_krb5_userok, + &ssh_gssapi_krb5_localname, + &ssh_gssapi_krb5_storecreds, + &ssh_gssapi_krb5_updatecreds +}; /* Initialise the krb5 library, for the stuff that GSSAPI won't do */ @@ -110,6 +128,35 @@ } +/* 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 */ @@ -120,7 +167,9 @@ krb5_error_code problem; krb5_principal princ; OM_uint32 maj_status, min_status; + gss_cred_id_t krb5_cred_handle; int len; + const char *new_ccname; const char *errmsg; if (client->creds == NULL) { @@ -173,18 +222,31 @@ krb5_free_principal(krb_context, princ); - if ((maj_status = gss_krb5_copy_ccache(&min_status, - client->creds, ccache))) { +#ifdef MECHGLUE + krb5_cred_handle = + __gss_get_mechanism_cred(client->creds, + &(gssapi_kerberos_mech.oid)); +#else + krb5_cred_handle = client->creds; +#endif + + if ((maj_status = gss_krb5_copy_ccache(&min_status, + krb5_cred_handle, ccache))) { logit("gss_krb5_copy_ccache() failed"); krb5_cc_destroy(krb_context, ccache); return; } - client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); + new_ccname = krb5_cc_get_name(krb_context, ccache); + client->store.envvar = "KRB5CCNAME"; - len = strlen(client->store.filename) + 6; - client->store.envval = xmalloc(len); - snprintf(client->store.envval, len, "FILE:%s", client->store.filename); +#ifdef USE_CCAPI + xasprintf(&client->store.envval, "API:%s", new_ccname); + client->store.filename = NULL; +#else + xasprintf(&client->store.envval, "FILE:%s", new_ccname); + client->store.filename = xstrdup(new_ccname); +#endif #ifdef USE_PAM if (options.use_pam) @@ -196,15 +258,70 @@ return; } -ssh_gssapi_mech gssapi_kerberos_mech = { - "toWM5Slw5Ew8Mqkay+al2g==", - "Kerberos", - {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}, - NULL, - &ssh_gssapi_krb5_userok, - NULL, - &ssh_gssapi_krb5_storecreds -}; +static int +ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, + ssh_gssapi_client *client) +{ + krb5_ccache ccache = NULL; + krb5_principal principal = NULL; + char *name = NULL; + krb5_error_code problem; + OM_uint32 maj_status, min_status; + + if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { + logit("krb5_cc_resolve(): %.100s", + krb5_get_err_text(krb_context, problem)); + return 0; + } + + /* Find out who the principal in this cache is */ + if ((problem = krb5_cc_get_principal(krb_context, ccache, + &principal))) { + logit("krb5_cc_get_principal(): %.100s", + krb5_get_err_text(krb_context, problem)); + krb5_cc_close(krb_context, ccache); + return 0; + } + + if ((problem = krb5_unparse_name(krb_context, principal, &name))) { + logit("krb5_unparse_name(): %.100s", + krb5_get_err_text(krb_context, problem)); + krb5_free_principal(krb_context, principal); + krb5_cc_close(krb_context, ccache); + return 0; + } + + + if (strcmp(name,client->exportedname.value)!=0) { + debug("Name in local credentials cache differs. Not storing"); + krb5_free_principal(krb_context, principal); + krb5_cc_close(krb_context, ccache); + krb5_free_unparsed_name(krb_context, name); + return 0; + } + krb5_free_unparsed_name(krb_context, name); + + /* Name matches, so lets get on with it! */ + + if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) { + logit("krb5_cc_initialize(): %.100s", + krb5_get_err_text(krb_context, problem)); + krb5_free_principal(krb_context, principal); + krb5_cc_close(krb_context, ccache); + return 0; + } + + krb5_free_principal(krb_context, principal); + + if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, + ccache))) { + logit("gss_krb5_copy_ccache() failed. Sorry!"); + krb5_cc_close(krb_context, ccache); + return 0; + } + + return 1; +} #endif /* KRB5 */ diff -Naur --exclude=autom4te.cache openssh-6.6p1/gss-serv.c openssh-6.6p1-gssapi/gss-serv.c --- openssh-6.6p1/gss-serv.c 2014-02-26 17:17:50.000000000 -0600 +++ openssh-6.6p1-gssapi/gss-serv.c 2014-03-18 15:05:44.000000000 -0500 @@ -1,7 +1,7 @@ /* $OpenBSD: gss-serv.c,v 1.26 2014/02/26 20:28:44 djm Exp $ */ /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,27 +45,44 @@ #include "channels.h" #include "session.h" #include "misc.h" +#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, NULL, {NULL, NULL, NULL, NULL}}; + GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL}, 0, 0}; ssh_gssapi_mech gssapi_null_mech = - { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; + { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; #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. @@ -100,25 +117,32 @@ char lname[MAXHOSTNAMELEN]; gss_OID_set oidset; - gss_create_empty_oid_set(&status, &oidset); - gss_add_oid_set_member(&status, ctx->oid, &oidset); + if (options.gss_strict_acceptor) { + gss_create_empty_oid_set(&status, &oidset); + gss_add_oid_set_member(&status, ctx->oid, &oidset); + + if (gethostname(lname, MAXHOSTNAMELEN)) { + gss_release_oid_set(&status, &oidset); + return (-1); + } - if (gethostname(lname, MAXHOSTNAMELEN)) { - gss_release_oid_set(&status, &oidset); - return (-1); - } + if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { + gss_release_oid_set(&status, &oidset); + return (ctx->major); + } + + if ((ctx->major = gss_acquire_cred(&ctx->minor, + ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, + NULL, NULL))) + ssh_gssapi_error(ctx); - if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { gss_release_oid_set(&status, &oidset); return (ctx->major); + } else { + ctx->name = GSS_C_NO_NAME; + ctx->creds = GSS_C_NO_CREDENTIAL; } - - if ((ctx->major = gss_acquire_cred(&ctx->minor, - ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) - ssh_gssapi_error(ctx); - - gss_release_oid_set(&status, &oidset); - return (ctx->major); + return GSS_S_COMPLETE; } /* Privileged */ @@ -133,6 +157,29 @@ } /* Unprivileged */ +char * +ssh_gssapi_server_mechanisms() { + gss_OID_set supported; + + ssh_gssapi_supported_oids(&supported); + return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech, + NULL, NULL)); +} + +/* Unprivileged */ +int +ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data, + const char *dummy) { + Gssctxt *ctx = NULL; + int res; + + res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); + ssh_gssapi_delete_ctx(&ctx); + + return (res); +} + +/* Unprivileged */ void ssh_gssapi_supported_oids(gss_OID_set *oidset) { @@ -194,6 +241,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); @@ -213,6 +264,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 @@ -268,8 +330,51 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) { int i = 0; + int equal = 0; + gss_name_t new_name = GSS_C_NO_NAME; + gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; + + if (options.gss_store_rekey && client->used && ctx->client_creds) { + if (client->mech->oid.length != ctx->oid->length || + (memcmp(client->mech->oid.elements, + ctx->oid->elements, ctx->oid->length) !=0)) { + debug("Rekeyed credentials have different mechanism"); + return GSS_S_COMPLETE; + } + + /* 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); + } + + ctx->major = gss_compare_name(&ctx->minor, client->name, + new_name, &equal); - gss_buffer_desc ename; + if (GSS_ERROR(ctx->major)) { + ssh_gssapi_error(ctx); + return (ctx->major); + } + + if (!equal) { + debug("Rekeyed credentials have different name"); + return GSS_S_COMPLETE; + } + + debug("Marking rekeyed credentials for export"); + + gss_release_name(&ctx->minor, &client->name); + gss_release_cred(&ctx->minor, &client->creds); + client->name = new_name; + client->creds = ctx->client_creds; + ctx->client_creds = GSS_C_NO_CREDENTIAL; + client->updated = 1; + return GSS_S_COMPLETE; + } client->mech = NULL; @@ -284,6 +389,16 @@ 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(&ctx->minor, + ctx->client_creds, &client->name, NULL, NULL, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } + if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, &client->displayname, NULL))) { ssh_gssapi_error(ctx); @@ -301,9 +416,15 @@ return (ctx->major); } + gss_release_buffer(&ctx->minor, &ename); + /* 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); } @@ -324,6 +445,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"); @@ -347,8 +473,9 @@ } /* Privileged */ +/* gssapi_keyex arg added for Globus usage */ int -ssh_gssapi_userok(char *user) +ssh_gssapi_userok(char *user, struct passwd *pw, int gssapi_keyex) { OM_uint32 lmin; @@ -357,10 +484,18 @@ 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)) + if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { + gssapi_client.used = 1; + gssapi_client.store.owner = pw; return 1; - else { + } else { /* Destroy delegated credentials if userok fails */ gss_release_buffer(&lmin, &gssapi_client.displayname); gss_release_buffer(&lmin, &gssapi_client.exportedname); @@ -374,14 +509,133 @@ return (0); } -/* Privileged */ -OM_uint32 -ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) +/* ssh_gssapi_checkmic() moved to gss-genr.c so it can be called by + kexgss_client(). */ + +/* 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. + * + * In the child, we want to : + * *) Ask the monitor to store our credentials into the store we specify + * *) If it succeeds, maybe do a PAM update + */ + +/* Stuff for PAM */ + +#ifdef USE_PAM +static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, + struct pam_response **resp, void *data) { - ctx->major = gss_verify_mic(&ctx->minor, ctx->context, - gssbuf, gssmic, NULL); + return (PAM_CONV_ERR); +} +#endif - return (ctx->major); +void +ssh_gssapi_rekey_creds() { + int ok; +#ifdef USE_PAM + int ret; + 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 && + gssapi_client.store.envval == NULL && + gssapi_client.store.envvar == NULL) + return; + + ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); + + if (!ok) + return; + + debug("Rekeyed credentials stored successfully"); + + /* Actually managing to play with the ssh pam stack from here will + * be next to impossible. In any case, we may want different options + * for rekeying. So, use our own :) + */ +#ifdef USE_PAM + if (!use_privsep) { + debug("Not even going to try and do PAM with privsep disabled"); + return; + } + + ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, + &pamconv, &pamh); + 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); + + ret = pam_putenv(pamh, envstr); + if (!ret) + pam_setcred(pamh, PAM_REINITIALIZE_CRED); + pam_end(pamh, PAM_SUCCESS); +#endif +} + +int +ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { + int ok = 0; + + /* Check we've got credentials to store */ + if (!gssapi_client.updated) + return 0; + + gssapi_client.updated = 0; + + temporarily_use_uid(gssapi_client.store.owner); + if (gssapi_client.mech && gssapi_client.mech->updatecreds) + ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); + else + debug("No update function for this mechanism"); + + restore_uid(); + + 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 -Naur --exclude=autom4te.cache openssh-6.6p1/kex.c openssh-6.6p1-gssapi/kex.c --- openssh-6.6p1/kex.c 2014-02-03 18:20:15.000000000 -0600 +++ openssh-6.6p1-gssapi/kex.c 2014-03-18 15:05:44.000000000 -0500 @@ -51,6 +51,12 @@ #include "roaming.h" #include "digest.h" +#include "canohost.h" + +#ifdef GSSAPI +#include "ssh-gss.h" +#endif + #if OPENSSL_VERSION_NUMBER >= 0x00907000L # if defined(HAVE_EVP_SHA256) # define evp_ssh_sha256 EVP_sha256 @@ -146,7 +152,8 @@ } /* put algorithm proposal into buffer */ -static void +/* used in sshconnect.c as well as kex.c */ +void kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) { u_int i; @@ -408,6 +415,26 @@ k->name = match_list(client, server, NULL); if (k->name == NULL) fatal("Unable to negotiate a key exchange method"); +#ifdef GSSAPI /* substring matching for the GSSAPI methods */ + if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID, + sizeof(KEX_GSS_GEX_SHA1_ID) - 1) == 0) { + k->kex_type = KEX_GSS_GEX_SHA1; + k->hash_alg = SSH_DIGEST_SHA1; + return; /* gss-gex-sha1-* */ + } + if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID, + sizeof(KEX_GSS_GRP1_SHA1_ID) - 1) == 0) { + k->kex_type = KEX_GSS_GRP1_SHA1; + k->hash_alg = SSH_DIGEST_SHA1; + return; /* gss-group1-sha1-* */ + } + if (strncmp(k->name, KEX_GSS_GRP14_SHA1_ID, + sizeof(KEX_GSS_GRP14_SHA1_ID) - 1) == 0) { + k->kex_type = KEX_GSS_GRP14_SHA1; + k->hash_alg = SSH_DIGEST_SHA1; + return; /* gss-group14-sha1-* */ + } +#endif if ((kexalg = kex_alg_by_name(k->name)) == NULL) fatal("unsupported kex alg %s", k->name); k->kex_type = kexalg->type; @@ -460,6 +487,11 @@ int nenc, nmac, ncomp; u_int mode, ctos, need, dh_need, authlen; int first_kex_follows, type; + int log_flag = 0; + int auth_flag; + + auth_flag = packet_authentication_state(); + debug ("AUTH STATE IS %d", auth_flag); my = kex_buf2prop(&kex->my, NULL); peer = kex_buf2prop(&kex->peer, &first_kex_follows); @@ -497,11 +529,34 @@ if (authlen == 0) choose_mac(&newkeys->mac, cprop[nmac], sprop[nmac]); choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); + debug("REQUESTED ENC.NAME is '%s'", newkeys->enc.name); + if (strcmp(newkeys->enc.name, "none") == 0) { + debug("Requesting NONE. Authflag is %d", auth_flag); + if (auth_flag == 1) { + debug("None requested post authentication."); + } else { + fatal("Pre-authentication none cipher requests are not allowed."); + } + } debug("kex: %s %s %s %s", ctos ? "client->server" : "server->client", newkeys->enc.name, authlen == 0 ? newkeys->mac.name : "", newkeys->comp.name); + /* client starts withctos = 0 && log flag = 0 and no log*/ + /* 2nd client pass ctos=1 and flag = 1 so no log*/ + /* server starts with ctos =1 && log_flag = 0 so log */ + /* 2nd sever pass ctos = 1 && log flag = 1 so no log*/ + /* -cjr*/ + if (ctos && !log_flag) { + logit("SSH: Server;Ltype: Kex;Remote: %s-%d;Enc: %s;MAC: %s;Comp: %s", + get_remote_ipaddr(), + get_remote_port(), + newkeys->enc.name, + newkeys->mac.name, + newkeys->comp.name); + } + log_flag = 1; } choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], diff -Naur --exclude=autom4te.cache openssh-6.6p1/kex.h openssh-6.6p1-gssapi/kex.h --- openssh-6.6p1/kex.h 2014-02-03 18:02:43.000000000 -0600 +++ openssh-6.6p1-gssapi/kex.h 2014-03-18 15:05:44.000000000 -0500 @@ -75,6 +75,9 @@ KEX_DH_GEX_SHA1, KEX_DH_GEX_SHA256, KEX_ECDH_SHA2, + KEX_GSS_GRP1_SHA1, + KEX_GSS_GRP14_SHA1, + KEX_GSS_GEX_SHA1, KEX_C25519_SHA256, KEX_MAX }; @@ -133,6 +136,12 @@ Buffer peer; sig_atomic_t done; int flags; +#ifdef GSSAPI + int gss_deleg_creds; + int gss_trust_dns; + char *gss_host; + char *gss_client; +#endif int hash_alg; int ec_nid; char *client_version_string; @@ -148,6 +157,10 @@ int kex_names_valid(const char *); char *kex_alg_list(char); +void kex_prop2buf(Buffer *, char *proposal[PROPOSAL_MAX]); + +void kex_prop2buf(Buffer *, char *proposal[PROPOSAL_MAX]); + Kex *kex_setup(char *[PROPOSAL_MAX]); void kex_finish(Kex *); @@ -167,6 +180,16 @@ void kexc25519_client(Kex *); void kexc25519_server(Kex *); +#ifdef GSSAPI +void kexgss_client(Kex *); +void kexgss_server(Kex *); +#endif + +#ifdef GSSAPI +void kexgss_client(Kex *); +void kexgss_server(Kex *); +#endif + void kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); diff -Naur --exclude=autom4te.cache openssh-6.6p1/kexgssc.c openssh-6.6p1-gssapi/kexgssc.c --- openssh-6.6p1/kexgssc.c 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/kexgssc.c 2014-03-18 15:05:44.000000000 -0500 @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2001-2009 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 + +#include "includes.h" + +#include +#include + +#include + +#include "xmalloc.h" +#include "buffer.h" +#include "ssh2.h" +#include "key.h" +#include "cipher.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" + +#include "ssh-gss.h" + +void +kexgss_client(Kex *kex) { + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; + gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr; + Gssctxt *ctxt; + OM_uint32 maj_status, min_status, ret_flags; + u_int klen, kout, slen = 0, hashlen, strlen; + DH *dh; + BIGNUM *dh_server_pub = NULL; + BIGNUM *shared_secret = NULL; + BIGNUM *p = NULL; + BIGNUM *g = NULL; + u_char *kbuf, *hash; + u_char *serverhostkey = NULL; + u_char *empty = ""; + char *msg; + char *lang; + int type = 0; + int first = 1; + int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; + + /* Initialise our GSSAPI world */ + ssh_gssapi_build_ctx(&ctxt); + if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) + == GSS_C_NO_OID) + fatal("Couldn't identify host exchange"); + + if (ssh_gssapi_import_name(ctxt, kex->gss_host)) + fatal("Couldn't import hostname"); + + if (kex->gss_client && + ssh_gssapi_client_identity(ctxt, kex->gss_client)) + fatal("Couldn't acquire client credentials"); + + switch (kex->kex_type) { + case KEX_GSS_GRP1_SHA1: + dh = dh_new_group1(); + break; + case KEX_GSS_GRP14_SHA1: + dh = dh_new_group14(); + break; + case KEX_GSS_GEX_SHA1: + debug("Doing group exchange\n"); + nbits = dh_estimate(kex->we_need * 8); + packet_start(SSH2_MSG_KEXGSS_GROUPREQ); + packet_put_int(min); + packet_put_int(nbits); + packet_put_int(max); + + packet_send(); + + packet_read_expect(SSH2_MSG_KEXGSS_GROUP); + + if ((p = BN_new()) == NULL) + fatal("BN_new() failed"); + packet_get_bignum2(p); + if ((g = BN_new()) == NULL) + fatal("BN_new() failed"); + packet_get_bignum2(g); + packet_check_eom(); + + if (BN_num_bits(p) < min || BN_num_bits(p) > max) + fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", + min, BN_num_bits(p), max); + + dh = dh_new_group(g, p); + break; + default: + fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); + } + + /* Step 1 - e is dh->pub_key */ + dh_gen_key(dh, kex->we_need * 8); + + /* This is f, we initialise it now to make life easier */ + dh_server_pub = BN_new(); + if (dh_server_pub == NULL) + fatal("dh_server_pub == NULL"); + + token_ptr = GSS_C_NO_BUFFER; + + do { + debug("Calling gss_init_sec_context"); + + maj_status = ssh_gssapi_init_ctx(ctxt, + kex->gss_deleg_creds, token_ptr, &send_tok, + &ret_flags); + + if (GSS_ERROR(maj_status)) { + if (send_tok.length != 0) { + packet_start(SSH2_MSG_KEXGSS_CONTINUE); + packet_put_string(send_tok.value, + send_tok.length); + } + fatal("gss_init_context failed"); + } + + /* If we've got an old receive buffer get rid of it */ + if (token_ptr != GSS_C_NO_BUFFER) + free(recv_tok.value); + + if (maj_status == GSS_S_COMPLETE) { + /* If mutual state flag is not true, kex fails */ + if (!(ret_flags & GSS_C_MUTUAL_FLAG)) + fatal("Mutual authentication failed"); + + /* If integ avail flag is not true kex fails */ + if (!(ret_flags & GSS_C_INTEG_FLAG)) + fatal("Integrity check failed"); + } + + /* + * If we have data to send, then the last message that we + * received cannot have been a 'complete'. + */ + if (send_tok.length != 0) { + if (first) { + packet_start(SSH2_MSG_KEXGSS_INIT); + packet_put_string(send_tok.value, + send_tok.length); + packet_put_bignum2(dh->pub_key); + first = 0; + } else { + packet_start(SSH2_MSG_KEXGSS_CONTINUE); + packet_put_string(send_tok.value, + send_tok.length); + } + packet_send(); + gss_release_buffer(&min_status, &send_tok); + + /* If we've sent them data, they should reply */ + do { + type = packet_read(); + if (type == SSH2_MSG_KEXGSS_HOSTKEY) { + debug("Received KEXGSS_HOSTKEY"); + if (serverhostkey) + fatal("Server host key received more than once"); + serverhostkey = + packet_get_string(&slen); + } + } while (type == SSH2_MSG_KEXGSS_HOSTKEY); + + switch (type) { + case SSH2_MSG_KEXGSS_CONTINUE: + debug("Received GSSAPI_CONTINUE"); + if (maj_status == GSS_S_COMPLETE) + fatal("GSSAPI Continue received from server when complete"); + recv_tok.value = packet_get_string(&strlen); + recv_tok.length = strlen; + break; + case SSH2_MSG_KEXGSS_COMPLETE: + debug("Received GSSAPI_COMPLETE"); + packet_get_bignum2(dh_server_pub); + msg_tok.value = packet_get_string(&strlen); + msg_tok.length = strlen; + + /* Is there a token included? */ + if (packet_get_char()) { + recv_tok.value= + packet_get_string(&strlen); + recv_tok.length = strlen; + /* If we're already complete - protocol error */ + if (maj_status == GSS_S_COMPLETE) + packet_disconnect("Protocol error: received token when complete"); + } else { + /* No token included */ + if (maj_status != GSS_S_COMPLETE) + packet_disconnect("Protocol error: did not receive final token"); + } + break; + case SSH2_MSG_KEXGSS_ERROR: + debug("Received Error"); + maj_status = packet_get_int(); + min_status = packet_get_int(); + msg = packet_get_string(NULL); + lang = packet_get_string(NULL); + fatal("GSSAPI Error: \n%.400s",msg); + default: + packet_disconnect("Protocol error: didn't expect packet type %d", + type); + } + token_ptr = &recv_tok; + } else { + /* No data, and not complete */ + if (maj_status != GSS_S_COMPLETE) + fatal("Not complete, and no token output"); + } + } while (maj_status & GSS_S_CONTINUE_NEEDED); + + /* + * We _must_ have received a COMPLETE message in reply from the + * server, which will have set dh_server_pub and msg_tok + */ + + if (type != SSH2_MSG_KEXGSS_COMPLETE) + fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); + + /* Check f in range [1, p-1] */ + if (!dh_pub_is_valid(dh, dh_server_pub)) + packet_disconnect("bad server public DH value"); + + /* compute K=f^x mod p */ + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_server_pub, dh); + if (kout < 0) + fatal("DH_compute_key: failed"); + + shared_secret = BN_new(); + if (shared_secret == NULL) + fatal("kexgss_client: BN_new failed"); + + if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) + fatal("kexdh_client: BN_bin2bn failed"); + + memset(kbuf, 0, klen); + free(kbuf); + + switch (kex->kex_type) { + case KEX_GSS_GRP1_SHA1: + case KEX_GSS_GRP14_SHA1: + kex_dh_hash( kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->my), buffer_len(&kex->my), + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + (serverhostkey ? serverhostkey : empty), slen, + dh->pub_key, /* e */ + dh_server_pub, /* f */ + shared_secret, /* K */ + &hash, &hashlen + ); + break; + case KEX_GSS_GEX_SHA1: + kexgex_hash( + kex->hash_alg, + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->my), buffer_len(&kex->my), + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + (serverhostkey ? serverhostkey : empty), slen, + min, nbits, max, + dh->p, dh->g, + dh->pub_key, + dh_server_pub, + shared_secret, + &hash, &hashlen + ); + break; + default: + fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); + } + + gssbuf.value = hash; + gssbuf.length = hashlen; + + /* Verify that the hash matches the MIC we just got. */ + if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) + packet_disconnect("Hash's MIC didn't verify"); + + free(msg_tok.value); + + DH_free(dh); + if (serverhostkey) + free(serverhostkey); + BN_clear_free(dh_server_pub); + + /* save session id */ + if (kex->session_id == NULL) { + kex->session_id_len = hashlen; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + + if (kex->gss_deleg_creds) + ssh_gssapi_credentials_updated(ctxt); + + if (gss_kex_context == NULL) + gss_kex_context = ctxt; + else + ssh_gssapi_delete_ctx(&ctxt); + + kex_derive_keys_bn(kex, hash, hashlen, shared_secret); + BN_clear_free(shared_secret); + kex_finish(kex); +} + +#endif /* GSSAPI */ diff -Naur --exclude=autom4te.cache openssh-6.6p1/kexgsss.c openssh-6.6p1-gssapi/kexgsss.c --- openssh-6.6p1/kexgsss.c 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/kexgsss.c 2014-03-18 15:05:44.000000000 -0500 @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2001-2009 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 + +#include + +#include +#include + +#include "xmalloc.h" +#include "buffer.h" +#include "ssh2.h" +#include "key.h" +#include "cipher.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" +#include "ssh-gss.h" +#include "monitor_wrap.h" +#include "servconf.h" + +static void kex_gss_send_error(Gssctxt *ctxt); +extern ServerOptions options; + +void +kexgss_server(Kex *kex) +{ + OM_uint32 maj_status, min_status; + + /* + * Some GSSAPI implementations use the input value of ret_flags (an + * output variable) as a means of triggering mechanism specific + * features. Initializing it to zero avoids inadvertently + * activating this non-standard behaviour. + */ + + OM_uint32 ret_flags = 0; + gss_buffer_desc gssbuf, recv_tok, msg_tok; + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; + Gssctxt *ctxt = NULL; + u_int slen, klen, kout, hashlen; + u_char *kbuf, *hash; + DH *dh; + int min = -1, max = -1, nbits = -1; + BIGNUM *shared_secret = NULL; + BIGNUM *dh_client_pub = NULL; + int type = 0; + gss_OID oid; + char *mechs; + + /* Initialise GSSAPI */ + + /* If we're rekeying, privsep means that some of the private structures + * in the GSSAPI code are no longer available. This kludges them back + * into life + */ + if (!ssh_gssapi_oid_table_ok()) + if ((mechs = ssh_gssapi_server_mechanisms())) + free(mechs); + + debug2("%s: Identifying %s", __func__, kex->name); + oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); + if (oid == GSS_C_NO_OID) + fatal("Unknown gssapi mechanism"); + + debug2("%s: Acquiring credentials", __func__); + + if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) { + kex_gss_send_error(ctxt); + fatal("Unable to acquire credentials for the server"); + } + + switch (kex->kex_type) { + case KEX_GSS_GRP1_SHA1: + dh = dh_new_group1(); + break; + case KEX_GSS_GRP14_SHA1: + dh = dh_new_group14(); + break; + case KEX_GSS_GEX_SHA1: + debug("Doing group exchange"); + packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ); + min = packet_get_int(); + nbits = packet_get_int(); + max = packet_get_int(); + min = MAX(DH_GRP_MIN, min); + max = MIN(DH_GRP_MAX, max); + packet_check_eom(); + if (max < min || nbits < min || max < nbits) + fatal("GSS_GEX, bad parameters: %d !< %d !< %d", + min, nbits, max); + dh = PRIVSEP(choose_dh(min, nbits, max)); + if (dh == NULL) + packet_disconnect("Protocol error: no matching group found"); + + packet_start(SSH2_MSG_KEXGSS_GROUP); + packet_put_bignum2(dh->p); + packet_put_bignum2(dh->g); + packet_send(); + + packet_write_wait(); + break; + default: + fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); + } + + dh_gen_key(dh, kex->we_need * 8); + + do { + debug("Wait SSH2_MSG_GSSAPI_INIT"); + type = packet_read(); + switch(type) { + case SSH2_MSG_KEXGSS_INIT: + if (dh_client_pub != NULL) + fatal("Received KEXGSS_INIT after initialising"); + recv_tok.value = packet_get_string(&slen); + recv_tok.length = slen; + + if ((dh_client_pub = BN_new()) == NULL) + fatal("dh_client_pub == NULL"); + + packet_get_bignum2(dh_client_pub); + + /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ + break; + case SSH2_MSG_KEXGSS_CONTINUE: + recv_tok.value = packet_get_string(&slen); + recv_tok.length = slen; + break; + default: + packet_disconnect( + "Protocol error: didn't expect packet type %d", + type); + } + + maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, + &send_tok, &ret_flags)); + + free(recv_tok.value); + + if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) + fatal("Zero length token output when incomplete"); + + if (dh_client_pub == NULL) + fatal("No client public key"); + + if (maj_status & GSS_S_CONTINUE_NEEDED) { + debug("Sending GSSAPI_CONTINUE"); + packet_start(SSH2_MSG_KEXGSS_CONTINUE); + packet_put_string((char *)send_tok.value, send_tok.length); + packet_send(); + gss_release_buffer(&min_status, &send_tok); + } + } 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((char *)send_tok.value, send_tok.length); + packet_send(); + } + packet_disconnect("GSSAPI Key Exchange handshake failed"); + } + + if (!(ret_flags & GSS_C_MUTUAL_FLAG)) + fatal("Mutual Authentication flag wasn't set"); + + if (!(ret_flags & GSS_C_INTEG_FLAG)) + fatal("Integrity flag wasn't set"); + + if (!dh_pub_is_valid(dh, dh_client_pub)) + packet_disconnect("bad client public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_client_pub, dh); + if (kout < 0) + fatal("DH_compute_key: failed"); + + shared_secret = BN_new(); + if (shared_secret == NULL) + fatal("kexgss_server: BN_new failed"); + + if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) + fatal("kexgss_server: BN_bin2bn failed"); + + memset(kbuf, 0, klen); + free(kbuf); + + switch (kex->kex_type) { + case KEX_GSS_GRP1_SHA1: + case KEX_GSS_GRP14_SHA1: + kex_dh_hash( + kex->client_version_string, kex->server_version_string, + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + buffer_ptr(&kex->my), buffer_len(&kex->my), + NULL, 0, /* Change this if we start sending host keys */ + dh_client_pub, dh->pub_key, shared_secret, + &hash, &hashlen + ); + break; + case KEX_GSS_GEX_SHA1: + kexgex_hash( + kex->hash_alg, + kex->client_version_string, kex->server_version_string, + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + buffer_ptr(&kex->my), buffer_len(&kex->my), + NULL, 0, + min, nbits, max, + dh->p, dh->g, + dh_client_pub, + dh->pub_key, + shared_secret, + &hash, &hashlen + ); + break; + default: + fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); + } + + BN_clear_free(dh_client_pub); + + if (kex->session_id == NULL) { + kex->session_id_len = hashlen; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + + gssbuf.value = hash; + gssbuf.length = hashlen; + + if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) + fatal("Couldn't get MIC"); + + packet_start(SSH2_MSG_KEXGSS_COMPLETE); + packet_put_bignum2(dh->pub_key); + packet_put_string((char *)msg_tok.value,msg_tok.length); + + if (send_tok.length != 0) { + packet_put_char(1); /* true */ + packet_put_string((char *)send_tok.value, send_tok.length); + } else { + packet_put_char(0); /* false */ + } + packet_send(); + + gss_release_buffer(&min_status, &send_tok); + gss_release_buffer(&min_status, &msg_tok); + + if (gss_kex_context == NULL) + gss_kex_context = ctxt; + else + ssh_gssapi_delete_ctx(&ctxt); + + DH_free(dh); + + kex_derive_keys_bn(kex, hash, hashlen, shared_secret); + BN_clear_free(shared_secret); + kex_finish(kex); + + /* If this was a rekey, then save out any delegated credentials we + * just exchanged. */ + if (options.gss_store_rekey) + ssh_gssapi_rekey_creds(); +} + +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 -Naur --exclude=autom4te.cache openssh-6.6p1/key.c openssh-6.6p1-gssapi/key.c --- openssh-6.6p1/key.c 2014-02-03 18:20:15.000000000 -0600 +++ openssh-6.6p1-gssapi/key.c 2014-03-18 15:05:44.000000000 -0500 @@ -957,6 +957,9 @@ }; static const struct keytype keytypes[] = { { NULL, "RSA1", KEY_RSA1, 0, 0 }, +#ifdef GSSAPI + { "null", "null", KEY_NULL, 0, 0 }, /* 'null' host key alg for GSSAPI */ +#endif { "ssh-rsa", "RSA", KEY_RSA, 0, 0 }, { "ssh-dss", "DSA", KEY_DSA, 0, 0 }, { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0 }, diff -Naur --exclude=autom4te.cache openssh-6.6p1/key.h openssh-6.6p1-gssapi/key.h --- openssh-6.6p1/key.h 2014-01-09 17:58:53.000000000 -0600 +++ openssh-6.6p1-gssapi/key.h 2014-03-18 15:05:44.000000000 -0500 @@ -46,6 +46,9 @@ KEY_ED25519_CERT, KEY_RSA_CERT_V00, KEY_DSA_CERT_V00, +#ifdef GSSAPI + KEY_NULL, /* 'null' host key alg for GSSAPI mechs */ +#endif KEY_UNSPEC }; enum fp_type { diff -Naur --exclude=autom4te.cache openssh-6.6p1/misc.c openssh-6.6p1-gssapi/misc.c --- openssh-6.6p1/misc.c 2013-10-14 20:14:12.000000000 -0500 +++ openssh-6.6p1-gssapi/misc.c 2014-03-18 15:05:44.000000000 -0500 @@ -159,11 +159,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) @@ -171,6 +174,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); @@ -226,6 +244,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 -Naur --exclude=autom4te.cache openssh-6.6p1/misc.h openssh-6.6p1-gssapi/misc.h --- openssh-6.6p1/misc.h 2013-10-14 20:14:12.000000000 -0500 +++ openssh-6.6p1-gssapi/misc.h 2014-03-18 15:05:44.000000000 -0500 @@ -41,6 +41,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 -Naur --exclude=autom4te.cache openssh-6.6p1/modp_burl.c openssh-6.6p1-gssapi/modp_burl.c --- openssh-6.6p1/modp_burl.c 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/modp_burl.c 2014-03-18 15:05:44.000000000 -0500 @@ -0,0 +1,200 @@ +/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set expandtab shiftwidth=4 tabstop=4: */ + +/** + * \file + *
+ * BFASTURL.c High performance URL encoder/decoder
+ * http://code.google.com/p/stringencoders/
+ *
+ * Copyright © 2006,2007  Nick Galbreath -- nickg [at] modp [dot] com
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ *   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.
+ *
+ *   Neither the name of the modp.com nor the names of its
+ *   contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT
+ * OWNER OR CONTRIBUTORS 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.
+ *
+ * This is the standard "new" BSD license:
+ * http://www.opensource.org/licenses/bsd-license.php
+ * 
+ */ + +#include "includes.h" +#ifdef NERSC_MOD + +#include "modp_burl.h" +#include "modp_stdint.h" +#include "modp_burl_data.h" + +int modp_burl_encode(char* dest, const char* src, int len) +{ + + const char* deststart = dest; + const uint8_t* s = (const uint8_t*)src; + const uint8_t* srcend = s + len; + char c; + uint8_t x; + + while (s < srcend) { + x = *s++; + c = (char)gsUrlEncodeMap[x]; + if (c) { + *dest++ = c; + } else { + *dest++ = '%'; + *dest++ = (char)gsHexEncodeMap1[x]; + *dest++ = (char)gsHexEncodeMap2[x]; + /* + is the equiv of this + static const char sHexChars[] = "0123456789ABCDEF"; + *dest++ = (char)sHexChars[x >> 4]; + *dest++ = (char)sHexChars[x & 0x0F]; + */ + } + } + *dest = '\0'; + return (int)(dest - deststart); // compute "strlen" of dest. +} + +/** + * The implementation is identical except it uses a + * different array + */ +int modp_burl_min_encode(char* dest, const char* src, int len) +{ + + const char* deststart = dest; + const uint8_t* s = (const uint8_t*)src; + const uint8_t* srcend = s + len; + char c; + uint8_t x; + + while (s < srcend) { + x = *s++; + c = (char)(gsUrlEncodeMinMap[x]); /** CHANGE HERE **/ + if (c) { + *dest++ = c; + } else { + *dest++ = '%'; + *dest++ = (char) gsHexEncodeMap1[x]; + *dest++ = (char)(gsHexEncodeMap2[x]); + /* + is the equiv of this + static const char sHexChars[] = "0123456789ABCDEF"; + *dest++ = sHexChars[x >> 4]; + *dest++ = sHexChars[x & 0x0F]; + */ + } + } + *dest = '\0'; + return (int)(dest - deststart); // compute "strlen" of dest. +} + +/** + * Give exact size of encoded output string + * without doing the encoding + */ +int modp_burl_encode_strlen(const char* src, const int len) +{ + int count = 0; + const char* srcend = src + len; + while (src < srcend) { + if (gsUrlEncodeMap[ (uint8_t) *src++]) { + count++; + } else { + count += 3; + } + } + return count; +} + +/** + * Give exact size of encoded output string + * without doing the encoding + */ +int modp_burl_min_encode_strlen(const char* src, const int len) +{ + int count = 0; + const char* srcend = src + len; + while (src < srcend) { + if (gsUrlEncodeMinMap[ (uint8_t) *src++]) { + count++; + } else { + count += 3; + } + } + return count; +} + +int modp_burl_decode(char* dest, const char* s, int len) +{ + uint32_t d = 0; // used for decoding %XX + const uint8_t* src = (const uint8_t*) s; + const char* deststart = dest; + const uint8_t* srcend = (const uint8_t*)(src + len); + const uint8_t* srcendloop = (const uint8_t*)(srcend - 2); + + while (src < srcendloop) { + switch (*src) { + case '+': + *dest++ = ' '; + src++; + break; + case '%': + d = (gsHexDecodeMap[(uint32_t)(*(src + 1))] << 4) | + gsHexDecodeMap[(uint32_t)(*(src + 2))]; + if (d < 256) { // if one of the hex chars is bad, d >= 256 + *dest = (char) d; + dest++; + src += 3; + } else { + *dest++ = '%'; + src++; + } + break; + default: + *dest++ = (char) *src++; + } + } + + // handle last two chars + // dont decode "%XX" + while (src < srcend) { + switch (*src) { + case '+': + *dest++ = ' '; + src++; + break; + default: + *dest++ = (char)( *src++); + } + } + + *dest = '\0'; + return (int)(dest - deststart); // compute "strlen" of dest. +} + +#endif /* NERSC_MOD */ diff -Naur --exclude=autom4te.cache openssh-6.6p1/modp_burl.h openssh-6.6p1-gssapi/modp_burl.h --- openssh-6.6p1/modp_burl.h 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/modp_burl.h 2014-03-18 15:05:44.000000000 -0500 @@ -0,0 +1,211 @@ +/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */ +/* vi: set expandtab shiftwidth=4 tabstop=4: */ + +/** + * \file + *
+ * High Performance URL Encoder/Decoder
+ *
+ * Copyright © 2006, 2007  Nick Galbreath -- nickg [at] modp [dot] com
+ * All rights reserved.
+ *
+ * http://code.google.com/p/stringencoders/
+ *
+ * Released under bsd license.  See bfast64.c for details.
+ * 
+ */ + +#ifndef COM_MODP_STRINGENCODERS_BURL +#define COM_MODP_STRINGENCODERS_BURL + +#ifdef __cplusplus +#define BEGIN_C extern "C" { +#define END_C } +#else +#define BEGIN_C +#define END_C +#endif + +BEGIN_C + +/** + * Url encode a string. This uses a very strict definition of url + * encoding. The only characters NOT encoded are A-Z, a-z, 0-9, "-", + * "_", ".", along with the space char getting mapped to "+". + * Everything else is escaped using "%HEXHEX" format. This is + * identical to the implementation of php's urlencode and nearly + * identical to Java's UrlEncoder class (they do not escape '*' for + * some reason). + * + * \param[out] dest output string. Must + * \param[in] str The input string + * \param[in] len The length of the input string, excluding any + * final null byte. + */ +int modp_burl_encode(char* dest, const char* str, int len); + +/** + * Url encode a string. This uses a minimal definition of url + * encoding. This works similar to the previous function except '~', + * '!', '$', '\'', '(', ')', '*', ',', ';', ':', '@', '/', '?' are NOT + * escaped. This will allow decoding by standard url-decoders and + * make the encoded urls more readable. + * + * \param[out] dest output string. Must + * \param[in] str The input string + * \param[in] len The length of the input string, excluding any + * final null byte. + */ +int modp_burl_min_encode(char* dest, const char* str, int len); + +/** \brief get size of output string w/o doing actual encoding + * + * \param[in] src input string, not null + * \param[in] len length of input string + * \return length of output string NOT including any final null byte + */ +int modp_burl_min_encode_strlen(const char* src, const int len); + +/** + * Provides the maximum size for output string given + * and input size of A bytes. + */ +#define modp_burl_encode_len(A) (3*A + 1) + +/** + * Given the exact size of output string. + * + * Can be used to allocate the right amount of memory for + * modp_burl_encode. Be sure to add 1 byte for final null. + * + * This is somewhat expensive since it examines every character + * in the input string + * + * \param[in] str The input string + * \param[in] len THe length of the input string, excluding any + * final null byte (i.e. strlen(str)) + * \return the size of the output string, excluding the final + * null byte. + */ +int modp_burl_encode_strlen(const char* str, const int len); + +/** + * URL Decode a string + * + * \param[out] dest The output string. Must be at least (len + 1) + * bytes allocated. This may be the same as the input buffer. + * \param[in] str The input string that is URL encoded. + * \param[in] len The length of the input string (excluding final + * null byte) + * \return the strlen of the output string. + */ +int modp_burl_decode(char* dest, const char* str, int len); + +/** + * Returns memory required to decoded a url-encoded + * string of length A. + * + */ +#define modp_burl_decode_len(A) (A + 1) + +END_C + +#ifdef __cplusplus +#include +#include + +namespace modp { + + inline std::string url_encode(const char* s, size_t len) + { + std::string x(modp_burl_encode_len(len), '\0'); + int d = modp_burl_encode(const_cast(x.data()), s, len); + x.erase(d, std::string::npos); + return x; + } + + inline std::string url_encode(const char* s) + { + return url_encode(s, strlen(s)); + } + + inline std::string url_encode(const std::string& s) + { + return url_encode(s.data(), s.size()); + } + + /** + * Standard (maximal) url encoding. + * + * \param[in,out] s the string to be encoded + * \return a reference to the input string + */ + inline std::string& url_encode(std::string& s) + { + std::string x(url_encode(s.data(), s.size())); + s.swap(x); + return s; + } + + /** + * Minimal Url Encoding + * + * \param[in,out] s the string to be encoded + * \return a reference to the input string + */ + inline std::string& url_min_encode(std::string& s) + { + std::string x(modp_burl_encode_len(s.size()), '\0'); + int d = modp_burl_min_encode(const_cast(x.data()), s.data(), s.size()); + x.erase(d, std::string::npos); + s.swap(x); + return s; + } + + inline std::string url_min_encode(const std::string& s) + { + std::string x(modp_burl_encode_len(s.size()), '\0'); + int d = modp_burl_min_encode(const_cast(x.data()), s.data(), s.size()); + x.erase(d, std::string::npos); + return x; + } + + /** + * Url decode a string. + * This function does not allocate memory. + * + * \param[in,out] s the string to be decoded + * \return a reference to the input string. + * There is no error case, bad characters are passed through + */ + inline std::string& url_decode(std::string& s) + { + int d = modp_burl_decode(const_cast(s.data()), s.data(), s.size()); + s.erase(d, std::string::npos); + return s; + } + + inline std::string url_decode(const char* str) + { + std::string s(str); + url_decode(s); + return s; + } + + inline std::string url_decode(const char* str, size_t len) + { + std::string s(str, len); + url_decode(s); + return s; + } + + inline std::string url_decode(const std::string& s) + { + std::string x(s); + url_decode(x); + return x; + } +} +#endif + +#endif diff -Naur --exclude=autom4te.cache openssh-6.6p1/modp_burl_data.h openssh-6.6p1-gssapi/modp_burl_data.h --- openssh-6.6p1/modp_burl_data.h 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/modp_burl_data.h 2014-03-18 15:05:44.000000000 -0500 @@ -0,0 +1,141 @@ +static const unsigned char gsUrlEncodeMap[256] = { +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '+', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '-', '.', '\0', '0', '1', + '2', '3', '4', '5', '6', '7', '8', '9', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', 'A', 'B', 'C', 'D', 'E', + 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', '\0', '\0', '\0', '\0', '_', '\0', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0' +}; + +static const unsigned char gsUrlEncodeMinMap[256] = { +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '+', '!', '\0', '\0', '$', '\0', '\0', '\0', + '(', ')', '*', '\0', ',', '-', '.', '/', '0', '1', + '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', +'\0', '\0', '\0', '?', '@', 'A', 'B', 'C', 'D', 'E', + 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', '\0', '\0', '\0', '\0', '_', '\0', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', '\0', '\0', '\0', '~', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', +'\0', '\0', '\0', '\0', '\0', '\0' +}; + +static const uint32_t gsHexDecodeMap[256] = { +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256, +256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, +256, 256, 256, 256 +}; + +static const unsigned char gsHexEncodeMap1[256] = { + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', + '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', + '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', + '2', '2', '2', '2', '2', '2', '2', '2', '3', '3', + '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', + '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', + '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', + '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', + '5', '5', '5', '5', '5', '5', '6', '6', '6', '6', + '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', + '6', '6', '7', '7', '7', '7', '7', '7', '7', '7', + '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', + '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', + '8', '8', '8', '8', '9', '9', '9', '9', '9', '9', + '9', '9', '9', '9', '9', '9', '9', '9', '9', '9', + 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', + 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', + 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', + 'B', 'B', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', + 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'D', 'D', + 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', + 'D', 'D', 'D', 'D', 'E', 'E', 'E', 'E', 'E', 'E', + 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', 'E', + 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F', 'F', + 'F', 'F', 'F', 'F', 'F', 'F' +}; + +static const unsigned char gsHexEncodeMap2[256] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', + 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', + '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', + 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', + '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', + 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', + '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' +}; + diff -Naur --exclude=autom4te.cache openssh-6.6p1/modp_stdint.h openssh-6.6p1-gssapi/modp_stdint.h --- openssh-6.6p1/modp_stdint.h 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/modp_stdint.h 2014-03-18 15:05:44.000000000 -0500 @@ -0,0 +1,21 @@ +/* vi: set ft=c expandtab shiftwidth=4 tabstop=4: */ +#ifndef MODP_STDINT_H_ +#define MODP_STDINT_H_ + +#ifndef _WIN32 +# include +#else +/* win64 is llp64 so these are the same for 32/64bit + so no check for _WIN64 is required. + */ + typedef unsigned char uint8_t; + typedef signed char int8_t; + typedef unsigned short uint16_t; + typedef signed short int16_t; + typedef unsigned int uint32_t; + typedef signed int int32_t; + typedef unsigned __int64 uint64_t; + typedef signed __int64 int64_t; +#endif + +#endif /* MODP_STDINT_H_ */ diff -Naur --exclude=autom4te.cache openssh-6.6p1/monitor.c openssh-6.6p1-gssapi/monitor.c --- openssh-6.6p1/monitor.c 2014-02-03 18:20:15.000000000 -0600 +++ openssh-6.6p1-gssapi/monitor.c 2014-03-18 15:05:44.000000000 -0500 @@ -175,6 +175,11 @@ int mm_answer_gss_accept_ctx(int, Buffer *); 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 #ifdef SSH_AUDIT_EVENTS @@ -217,12 +222,12 @@ struct mon_table mon_dispatch_proto20[] = { {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, {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}, {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}, @@ -247,11 +252,23 @@ {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, {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} }; struct mon_table mon_dispatch_postauth20[] = { +#ifdef GSSAPI + {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 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, {MONITOR_REQ_SIGN, 0, mm_answer_sign}, {MONITOR_REQ_PTY, 0, mm_answer_pty}, @@ -281,8 +298,15 @@ {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, #endif +#ifdef GSSAPI + {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx}, + {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, + {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, + {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, + {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs}, +#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}, @@ -360,6 +384,12 @@ /* Permit requests for moduli and signatures */ monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); +#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; @@ -465,10 +495,21 @@ monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); + +#ifdef GSSAPI + /* and for the GSSAPI key exchange */ + monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS,1); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP,1); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR,1); +#endif + } else { mon_dispatch = mon_dispatch_postauth15; monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); } +#ifdef GSSAPI + monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1); +#endif if (!no_pty_flag) { monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1); @@ -734,14 +775,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); @@ -1833,6 +1877,13 @@ kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; kex->kex[KEX_ECDH_SHA2] = kexecdh_server; +#ifdef GSSAPI + if (options.gss_keyex) { + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; + kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; + } +#endif kex->kex[KEX_C25519_SHA256] = kexc25519_server; kex->server = 1; kex->hostkey_type = buffer_get_int(m); @@ -2041,6 +2092,9 @@ OM_uint32 major; u_int len; + if (!options.gss_authentication && !options.gss_keyex) + fatal("In GSSAPI monitor when GSSAPI is disabled"); + goid.elements = buffer_get_string(m, &len); goid.length = len; @@ -2068,6 +2122,9 @@ OM_uint32 flags = 0; /* GSI needs this */ u_int len; + if (!options.gss_authentication && !options.gss_keyex) + fatal("In GSSAPI monitor when GSSAPI is disabled"); + in.value = buffer_get_string(m, &len); in.length = len; major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); @@ -2084,7 +2141,9 @@ if (major == GSS_S_COMPLETE) { monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); } return (0); } @@ -2096,6 +2155,9 @@ OM_uint32 ret; u_int len; + if (!options.gss_authentication && !options.gss_keyex) + fatal("In GSSAPI monitor when GSSAPI is disabled"); + gssbuf.value = buffer_get_string(m, &len); gssbuf.length = len; mic.value = buffer_get_string(m, &len); @@ -2121,8 +2183,18 @@ 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); + if (!options.gss_authentication && !options.gss_keyex) + fatal("In GSSAPI monitor when GSSAPI is disabled"); + + authenticated = authctxt->valid && + ssh_gssapi_userok(authctxt->user, authctxt->pw, gssapi_keyex); buffer_clear(m); buffer_put_int(m, authenticated); @@ -2130,10 +2202,145 @@ 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); + } + +#if !defined(MECHGLUE) /* mechglue memory management bug ??? */ + gss_release_oid_set(&minor,&mech_set); +#endif + + 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) +{ + gss_buffer_desc data; + gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; + OM_uint32 major, minor; + u_int len; + + if (!options.gss_authentication && !options.gss_keyex) + fatal("In GSSAPI monitor when GSSAPI is disabled"); + + data.value = buffer_get_string(m, &len); + data.length = len; + if (data.length != 20) + fatal("%s: data length incorrect: %d", __func__, + (int) data.length); + + /* Save the session ID on the first time around */ + if (session_id2_len == 0) { + session_id2_len = data.length; + session_id2 = xmalloc(session_id2_len); + memcpy(session_id2, data.value, session_id2_len); + } + major = ssh_gssapi_sign(gsscontext, &data, &hash); + + free(data.value); + + buffer_clear(m); + buffer_put_int(m, major); + buffer_put_string(m, hash.value, hash.length); + + mm_request_send(socket, MONITOR_ANS_GSSSIGN, m); + + gss_release_buffer(&minor, &hash); + + /* Turn on getpwnam permissions */ + monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); + + /* And credential updating, for when rekeying */ + monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1); + + return (0); +} + +int +mm_answer_gss_updatecreds(int socket, Buffer *m) { + ssh_gssapi_ccache store; + int ok; + + store.filename = buffer_get_string(m, NULL); + store.envvar = buffer_get_string(m, NULL); + store.envval = buffer_get_string(m, NULL); + + ok = ssh_gssapi_update_creds(&store); + + free(store.filename); + free(store.envvar); + free(store.envval); + + buffer_clear(m); + buffer_put_int(m, ok); + + mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m); + + return(0); +} + #endif /* GSSAPI */ diff -Naur --exclude=autom4te.cache openssh-6.6p1/monitor.h openssh-6.6p1-gssapi/monitor.h --- openssh-6.6p1/monitor.h 2014-02-03 18:12:57.000000000 -0600 +++ openssh-6.6p1-gssapi/monitor.h 2014-03-18 15:05:44.000000000 -0500 @@ -65,6 +65,12 @@ MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, + MONITOR_REQ_GSSMECHS = 200, MONITOR_ANS_GSSMECHS = 201, + MONITOR_REQ_GSSLOCALNAME = 202, MONITOR_ANS_GSSLOCALNAME = 203, + MONITOR_REQ_GSSERR = 204, MONITOR_ANS_GSSERR = 205, + MONITOR_REQ_GSSSIGN = 206, MONITOR_ANS_GSSSIGN = 207, + MONITOR_REQ_GSSUPCREDS = 208, MONITOR_ANS_GSSUPCREDS = 209, + }; struct mm_master; diff -Naur --exclude=autom4te.cache openssh-6.6p1/monitor_wrap.c openssh-6.6p1-gssapi/monitor_wrap.c --- openssh-6.6p1/monitor_wrap.c 2014-02-03 18:20:15.000000000 -0600 +++ openssh-6.6p1-gssapi/monitor_wrap.c 2014-03-18 15:05:44.000000000 -0500 @@ -1271,12 +1271,13 @@ } int -mm_ssh_gssapi_userok(char *user) +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, @@ -1288,5 +1289,127 @@ debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); 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) +{ + Buffer m; + OM_uint32 major; + u_int len; + + buffer_init(&m); + buffer_put_string(&m, data->value, data->length); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m); + + major = buffer_get_int(&m); + hash->value = buffer_get_string(&m, &len); + hash->length = len; + + buffer_free(&m); + + return(major); +} + +int +mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) +{ + Buffer m; + int ok; + + buffer_init(&m); + + buffer_put_cstring(&m, store->filename ? store->filename : ""); + buffer_put_cstring(&m, store->envvar ? store->envvar : ""); + buffer_put_cstring(&m, store->envval ? store->envval : ""); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m); + + ok = buffer_get_int(&m); + + buffer_free(&m); + + return (ok); +} + #endif /* GSSAPI */ diff -Naur --exclude=autom4te.cache openssh-6.6p1/monitor_wrap.h openssh-6.6p1-gssapi/monitor_wrap.h --- openssh-6.6p1/monitor_wrap.h 2014-02-03 18:12:57.000000000 -0600 +++ openssh-6.6p1-gssapi/monitor_wrap.h 2014-03-18 15:05:44.000000000 -0500 @@ -58,8 +58,14 @@ 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); +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 #ifdef USE_PAM diff -Naur --exclude=autom4te.cache openssh-6.6p1/mux.c openssh-6.6p1-gssapi/mux.c --- openssh-6.6p1/mux.c 2013-07-18 01:12:45.000000000 -0500 +++ openssh-6.6p1-gssapi/mux.c 2014-03-18 15:05:44.000000000 -0500 @@ -439,6 +439,7 @@ set_nonblock(new_fd[2]); window = CHAN_SES_WINDOW_DEFAULT; + packetmax = CHAN_SES_PACKET_DEFAULT; if (cctx->want_tty) { window >>= 1; diff -Naur --exclude=autom4te.cache openssh-6.6p1/myproposal.h openssh-6.6p1-gssapi/myproposal.h --- openssh-6.6p1/myproposal.h 2013-12-06 18:24:02.000000000 -0600 +++ openssh-6.6p1-gssapi/myproposal.h 2014-03-18 15:05:44.000000000 -0500 @@ -110,6 +110,16 @@ "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se" +#define KEX_ENCRYPT_INCLUDE_NONE KEX_DEFAULT_ENCRYPT \ + ",none" +#ifdef HAVE_EVP_SHA256 +#define SHA2_HMAC_MODES \ + "hmac-sha2-256," \ + "hmac-sha2-512," +#else +# define SHA2_HMAC_MODES +#endif + #define KEX_DEFAULT_MAC \ "hmac-md5-etm@openssh.com," \ "hmac-sha1-etm@openssh.com," \ @@ -133,6 +143,8 @@ #define KEX_DEFAULT_COMP "none,zlib@openssh.com,zlib" #define KEX_DEFAULT_LANG "" +#define KEX_ENCRYPT_INCLUDE_NONE KEX_DEFAULT_ENCRYPT \ + ",none" static char *myproposal[PROPOSAL_MAX] = { KEX_DEFAULT_KEX, diff -Naur --exclude=autom4te.cache openssh-6.6p1/nersc.c openssh-6.6p1-gssapi/nersc.c --- openssh-6.6p1/nersc.c 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/nersc.c 2014-03-18 15:05:44.000000000 -0500 @@ -0,0 +1,583 @@ +/* + * Author: Scott Campbell, Tom Davis + * Set of functions called by the command instrumentation and logging + * + * notes as follows: + * hostname and source port of the syslog listener are hardcoded into + * the code to prevent issues with configuration - both intentional and otherwise. + * + * ------------------------------------------------------------------------------ + * Instrumented Open SSHD, Copyright (c) *2013*, The + * Regents of the University of California, through Lawrence Berkeley National + * Laboratory (subject to receipt of any required approvals from the U.S. + * Dept. of Energy). All rights reserved. + * + * If you have questions about your rights to use or distribute this software, + * please contact Berkeley Lab's Technology Transfer Department at TTD@lbl.gov + * . + * + * NOTICE. This software is owned by the U.S. Department of Energy. As such, + * the U.S. Government has been granted for itself and others acting on its + * behalf a paid-up, nonexclusive, irrevocable, worldwide license in the + * Software to reproduce, prepare derivative works, and perform publicly and + * display publicly. Beginning five (5) years after the date permission to + * assert copyright is obtained from the U.S. + * Department of Energy, and subject to any subsequent five (5) year renewals, + * the U.S. Government is granted for itself and others acting on its behalf a + * paid-up, nonexclusive, irrevocable, worldwide license in the Software to + * reproduce, prepare derivative works, distribute copies to the public, + * perform publicly and display publicly, and to permit others to do so. + * + * *** License agreement *** + * + * " Instrumented Open SSHD, Copyright (c) 2013, The Regents of the + * University of California, through Lawrence Berkeley National Laboratory + * (subject to receipt of any required approvals from the U.S. Dept. of + * Energy). This software was developed under funding from the DOE Office of + * Advanced Scientific Computing Research* *and is associated with the + * Berkeley Lab OASCR project. 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. + * + * (3) Neither the name of the University of California, Lawrence Berkeley + * National Laboratory, U.S. Dept. of Energy nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. + * + * *You are under no obligation whatsoever to provide any bug fixes, patches, + * or upgrades to the features, functionality or performance of the source + * code ("Enhancements") to anyone; however, if you choose to make your + * Enhancements available either publicly, or directly to Lawrence Berkeley + * National Laboratory, without imposing a separate written license agreement + * for such Enhancements, then you hereby grant the following license: a + * non-exclusive, royalty-free perpetual license to install, use, modify, + * prepare derivative works, incorporate into other computer software, + * distribute, and sublicense such enhancements or derivative works thereof, + * in binary and source code form.* + * + * ------------------------------------------------------------------------------ + * Additional URL encoding code taken from stringcoders-v3.10.3 source. Thanks! + * ------------------------------------------------------------------------------ + * http://code.google.com/p/stringencoders/ + * + * Copyright © 2006,2007 Nick Galbreath -- nickg [at] modp [dot] com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 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. + * + * Neither the name of the modp.com nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + * + * This is the standard "new" BSD license: + * http://www.opensource.org/licenses/bsd-license.php + */ + + +#include "includes.h" +#ifdef NERSC_MOD + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "openbsd-compat/sys-queue.h" +#include "channels.h" +#include "log.h" +#include "misc.h" +#include "xmalloc.h" +#include "version.h" +#include "nersc.h" + +/* this is for the stringencoders data */ +#include "modp_burl.h" +#include "modp_burl_data.h" + +int client_session_id; +int sis_socket = -1; /* socket test varible */ +int sis_connect = -1; /* connect test variable */ +int stun_conn_error = 0; /* track the number of connection errors to the stunnel */ +int stun_write_error = 0; /* track the number of write errors to the stunnel */ + +char n_ntop[NI_MAXHOST] = "X"; +char n_port[NI_MAXHOST] = "X"; + +extern char *__progname; + +static char server_id[128] = "X"; /* + * This is a unique value composed of: + * + * used for the lifetime of the process. + * 128 == max reasonable size expected + */ +#define NERSCMSGBUF 4096 +#define STUN_ERROR_MOD 10 /* + * Filter the number of errors down by this factor + * so that on a busy sustem the local syslog is not + * flooded with anoying and redundant messages + */ + +char interface_list[256] = "X"; /* + * Contains space delimited list of system interfaces. + * at times we may need more than the host name to + * determine the system in question. Fill up and ship + * back to the bro instance to sort out + */ + +void l_syslog(const char *fmt,...) +{ + /* + * Function filtering accidental printing of log messages to + * stderr/stdout when logging messages. + * + * NOTE: for standalong binaries like ssh, some of this code will get + * called since there are common shared objects like channels.o which + * trigger annoying errors to stderr otherwise. + */ + + if ( ! log_is_on_stderr() ) { + va_list args; + + va_start(args, fmt); + do_log(SYSLOG_LEVEL_INFO, fmt, args); + va_end(args); + } +} + + +int get_client_session_id() + { + return client_session_id; + } + +void set_server_id(int parent_pid, char* ntop, int port) + { + /* + * This is called to assert the server id from server_listen() + * in sshd.c . + */ + if ( server_id[0] == 'X' ) { + char hn[64]; + long hid; + + if ( gethostname((char*)hn, 64) == -1 ) + strncpy(hn, "unknown-hostname", sizeof(hn)); + + hid = gethostid(); + snprintf(server_id, 64,"%ld:%s:%i", hid, hn, port); + } + } + +static char* get_server_id() + { + /* + * If this is the first reference to this variable, it may be blank and + * we can try filing it in via the values set up during the sshd run. + */ + const char* env = NULL; + size_t len = 0; + char *cp = NULL; + char *p = NULL; + long hid; + + if( server_id[0] == 'X' ) { + + hid = gethostid(); + /* + * When invoking subsystems, we may have a situation where the + * server id will be incomplete. run an additional test here + * to make sure that n_top and n_port have been filled. if not, + * make a sanity guess based on: + * SSH_CONNECTION=127.0.0.1 33602 127.0.0.1 22 + */ + if ( n_port[0] == 'X' ) { + + if ((env = getenv("SSH_CONNECTION")) != NULL) { + + len = strlen(env); + cp = (char*) xmalloc(len + 1); + strcpy(cp, env); + + p = strtok(cp," "); /* src IP */ + p = strtok(NULL, " "); /* src port */ + + if ( (p = strtok(NULL, " ")) != NULL) /* dst IP */ + strncpy(n_ntop,p,NI_MAXHOST-1); + + if ( (p = strtok(NULL, " ")) != NULL) /* dst port */ + strncpy(n_port,p,NI_MAXHOST-1); + + bzero(cp, len); + free(cp); + } + else { + /* + * Have not been able to extract SSH_CONNECTION from + * the running environment. WTF? + */ + strncpy(n_port, "unknown-port", strlen(n_port)); + strncpy(n_ntop, "unknown-ip", strlen(n_ntop)); + } + } + + char hn[64]; + gethostname((char*)hn, 64); + + snprintf(server_id, 64,"%ld:%s:%s", hid, hn, n_port); + + return (server_id); + } + else + return (server_id); + } + +int set_interface_list() +{ + int iSocket; + struct if_nameindex *pIndex, *pIndex2; + + if ( strlen(interface_list) > 1 ) + return 0; + + if ((iSocket = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + + perror("socket"); + bzero(interface_list, sizeof(interface_list)); + interface_list[0] = 'S'; + return -1; + } + + bzero(interface_list, sizeof(interface_list)); + + /* + * if_nameindex() returns an array of if_nameindex structures. + * + * if_nametoindex is also defined in , and is as follows: + * + * struct if_nameindex { + * unsigned int if_index; 1, 2, ... + * char *if_name; null terminated name: "le0", ... + * }; + */ + pIndex = pIndex2 = if_nameindex(); + + /* for an error state, pIndex will be NULL */ + while ((pIndex != NULL) && (pIndex->if_name != NULL)) { + + struct ifreq req; + + strncpy(req.ifr_name, pIndex->if_name, IFNAMSIZ); + + if (ioctl(iSocket, SIOCGIFADDR, &req) < 0) { + + if (errno == EADDRNOTAVAIL) { + pIndex++; + continue; + } + + perror("ioctl"); + bzero(interface_list, sizeof(interface_list)); + interface_list[0] = 'I'; + close(iSocket); + + return -1; + } + + /* add a delimiter */ + if ( pIndex > pIndex2 ) + strncat(interface_list, "_", 2); + + size_t nl = strlen(inet_ntoa(((struct sockaddr_in*)&req.ifr_addr)->sin_addr)); + + if ( nl + strlen(interface_list) + 2 < sizeof(interface_list) ) { + + strncat( interface_list, + inet_ntoa(((struct sockaddr_in*)&req.ifr_addr)->sin_addr), + sizeof(interface_list) - nl -1); + } + + pIndex++; + + } + + if ( pIndex2 != NULL ) + if_freenameindex(pIndex2); + + close(iSocket); + + return 0; +} + +static int sis_opentcp(char *hostname, int portnum) +{ + struct sockaddr_in sa = { 0 }; + struct hostent *hp = NULL; + int s, valopt; + fd_set myset; + struct timeval tv; + socklen_t lon; + + s = -1; + sis_connect = -1; + + hp = gethostbyname(hostname); + + if (hp == NULL) { + hp = gethostbyaddr(hostname, strlen(hostname), AF_INET); + if (hp == NULL) { + l_syslog("error resolving stunnel server address, exiting open"); + return(-1); + } + } + + sa.sin_family = AF_INET; + sa.sin_port = htons(portnum); + (void) memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); + + if ((s=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + + l_syslog("error opening connection to stunnel listener, exiting open"); + return (-1); + } + + /* now make the socket non-blocking */ + if ( fcntl(s,F_SETFL,FNDELAY) == -1) { + l_syslog("Failure setting socket to no-blocking"); + } + + sis_connect = connect(s, (struct sockaddr *) & sa, sizeof(sa)); + + if ( sis_connect < 0 ) { + + /* + * We might be waiting for the connection to complete - + * quick check for that condition. + */ + if (errno == EINPROGRESS) { + /* sit for 2 seconds */ + tv.tv_sec = 2; + tv.tv_usec = 0; + FD_ZERO(&myset); + FD_SET(s, &myset); + + if (select(s+1, NULL, &myset, NULL, &tv) > 0) { + lon = sizeof(int); + getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)(&valopt), &lon); + + if (valopt) { + if ( ( stun_conn_error % STUN_ERROR_MOD ) == 0 ) { + l_syslog("connection to stunnel rejected/timeout, exiting open, error = %d, %s" , + valopt, strerror(valopt)); + + stun_conn_error++; + close(s); + sis_connect = -1; + return(-1); + } + } + else { + /* sitting around has worked, mark connect as successful */ + sis_connect = 1; + } + } + } + else { + /* some simple sanity filtering for connect errors */ + if ( ( stun_conn_error % STUN_ERROR_MOD ) == 0 ) { + l_syslog("connection to stunnel rejected, exiting open"); + + stun_conn_error++; + close(s); + return(-1); + } + } + } + + return(s); +} + +static int sis_write(char *buffer) +{ + int err = 0; + size_t sent = 0; + + if ( sis_connect != -1 && sis_socket != -1) + sent = send(sis_socket, buffer, strlen(buffer), 0); + + /* this may be a little heavy handed ... */ + if (sent != strlen(buffer) || sis_socket == -1 || sis_connect == -1) { + +#ifndef STUNNEL_PORT + #define STUNNEL_PORT 799 +#endif + +#ifndef STUNNEL_HOST + #define STUNNEL_HOST "localhost" +#endif + /* + * Close the fd since writes are failing, but only + * if there is an error on it already since that would + * close a socket that was never opened ... + */ + if ( stun_write_error > 0 ) { + + close(sis_socket); + sis_socket = -1; + sis_connect = -1; + + /* + * Some simple sanity filtering for connect errors + * this will flag every 10th error starting after #1 + */ + if ( ( stun_write_error % STUN_ERROR_MOD ) == 1 ) { + l_syslog("write to stunnel failed, reopening connection"); + } + + } + + stun_write_error++; + sis_socket = sis_opentcp(STUNNEL_HOST, STUNNEL_PORT); + + if ( sis_socket == -1 || sis_connect == -1 ) { + err = -1; + } + else { + sent = send(sis_socket, buffer, strlen(buffer), 0); + + err=1; + } + + } + + return(err); +} + + +/* + * Main auditing function called by other code + * s_audit( , , ); + */ +void s_audit(const char *_event, const char *fmt, ...) +{ + va_list args; + char msgbuf[NERSCMSGBUF] = ""; + char fmtbuf[NERSCMSGBUF] = ""; + + struct timeval tv; + gettimeofday(&tv, NULL); + + char* t1buf = encode_string( get_server_id(), strlen(get_server_id()) ); + /* get version string */ + + /* + * If --with-nerscmod has not been set in confgure there is no access to + * SSH_AUDITING so we set a token value for the define. + */ +#ifndef NERSC_MOD + #define SSH_AUDITING "XXX" +#endif + char* t2buf = encode_string( SSH_AUDITING, strlen(SSH_AUDITING) ); + /* get interface list */ + set_interface_list(); + char* t3buf = encode_string( interface_list, strlen(interface_list) ); + + /* fmt defines how data provided by args should be formatted */ + va_start(args, fmt); + /* copy the data into msgbuf */ + vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); + va_end(args); + + /* copy event and system data in front of the argument data */ + snprintf(fmtbuf, sizeof(fmtbuf), "%s time=%ld.%ld uristring=%s uristring=%s %s\n", _event, tv.tv_sec, (long int)tv.tv_usec, t2buf, t1buf, msgbuf); + + /*write(STDERR_FILENO, fmtbuf, strlen(fmtbuf)); */ + /*syslog(LOG_NOTICE, fmtbuf); */ + + /* + * If the socket open fails, sis_write() will return a -1. for the time + * being we will just let this ride since we will be reporting + * write failures anyway. + */ + sis_write(fmtbuf); + + free(t1buf); + free(t2buf); + free(t3buf); +} + + +char* encode_string(const char* src, const int len) +{ + /* take a string and return a pointer to the URI encoded version */ + int new_len = modp_burl_encode_len(len); + + char *url_enc_string; + + url_enc_string = xmalloc(new_len); + + if ( url_enc_string == NULL ) + return (char*)src; + else + /* + * We do not test the return here since it + * is done via the call itself. + */ + modp_burl_encode(url_enc_string, src, len); + + return url_enc_string; +} + +#endif /* NERSC_MOD */ diff -Naur --exclude=autom4te.cache openssh-6.6p1/nersc.h openssh-6.6p1-gssapi/nersc.h --- openssh-6.6p1/nersc.h 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/nersc.h 2014-03-18 15:05:44.000000000 -0500 @@ -0,0 +1,15 @@ +/* + * Author: Scott Campbell + * header file + * + * see nersc.c for complete copyright information + * + */ + +int get_client_session_id(); +void set_server_id(int,char*,int); +void s_audit(const char *, const char *, ...); +char* encode_string(const char *, const int len); +int set_interface_list(); + + diff -Naur --exclude=autom4te.cache openssh-6.6p1/openbsd-compat/port-aix.c openssh-6.6p1-gssapi/openbsd-compat/port-aix.c --- openssh-6.6p1/openbsd-compat/port-aix.c 2013-06-01 17:07:32.000000000 -0500 +++ openssh-6.6p1-gssapi/openbsd-compat/port-aix.c 2014-03-18 15:05:44.000000000 -0500 @@ -50,6 +50,7 @@ # include # include # if defined(HAVE_SYS_AUDIT_H) && defined(AIX_LOGINFAILED_4ARG) +# undef T_NULL # include # endif # include diff -Naur --exclude=autom4te.cache openssh-6.6p1/packet.c openssh-6.6p1-gssapi/packet.c --- openssh-6.6p1/packet.c 2014-02-03 18:20:15.000000000 -0600 +++ openssh-6.6p1-gssapi/packet.c 2014-03-18 15:05:44.000000000 -0500 @@ -848,7 +848,7 @@ /* * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) */ -static void +static int packet_send2_wrapped(void) { u_char type, *cp, *macbuf = NULL; @@ -980,11 +980,13 @@ set_newkeys(MODE_OUT); else if (type == SSH2_MSG_USERAUTH_SUCCESS && active_state->server_side) packet_enable_delayed_compress(); + return (len-4); } -static void +static int packet_send2(void) { + static int packet_length = 0; struct packet *p; u_char type, *cp; @@ -1004,7 +1006,7 @@ sizeof(Buffer)); buffer_init(&active_state->outgoing_packet); TAILQ_INSERT_TAIL(&active_state->outgoing, p, next); - return; + return(sizeof(Buffer)); } } @@ -1012,7 +1014,7 @@ if (type == SSH2_MSG_KEXINIT) active_state->rekeying = 1; - packet_send2_wrapped(); + packet_length = packet_send2_wrapped(); /* after a NEWKEYS message we can send the complete queue */ if (type == SSH2_MSG_NEWKEYS) { @@ -1026,19 +1028,22 @@ sizeof(Buffer)); TAILQ_REMOVE(&active_state->outgoing, p, next); free(p); - packet_send2_wrapped(); + packet_length += packet_send2_wrapped(); } } + return(packet_length); } -void +int packet_send(void) { + int packet_len = 0; if (compat20) - packet_send2(); + packet_len = packet_send2(); else packet_send1(); DBG(debug("packet_send done")); + return(packet_len); } /* @@ -1718,12 +1723,14 @@ /* Checks if there is any buffered output, and tries to write some of the output. */ -void +int packet_write_poll(void) { - int len = buffer_len(&active_state->output); + int len = 0; int cont; + len = buffer_len(&active_state->output); + if (len > 0) { cont = 0; len = roaming_write(active_state->connection_out, @@ -1731,13 +1738,14 @@ if (len == -1) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) - return; + return(0); fatal("Write failed: %.100s", strerror(errno)); } if (len == 0 && !cont) fatal("Write connection closed"); buffer_consume(&active_state->output, len); } + return(len); } /* @@ -1938,12 +1946,25 @@ } } +/* this supports the forced rekeying required for the NONE cipher */ +int rekey_requested = 0; +void +packet_request_rekeying(void) +{ + rekey_requested = 1; +} + #define MAX_PACKETS (1U<<31) int packet_need_rekeying(void) { if (datafellows & SSH_BUG_NOREKEY) return 0; + if (rekey_requested == 1) + { + rekey_requested = 0; + return 1; + } return (active_state->p_send.packets > MAX_PACKETS) || (active_state->p_read.packets > MAX_PACKETS) || @@ -1955,6 +1976,12 @@ active_state->rekey_interval <= monotime()); } +int +packet_authentication_state(void) +{ + return(active_state->after_authentication); +} + void packet_set_rekey_limits(u_int32_t bytes, time_t seconds) { @@ -2009,6 +2036,18 @@ return (void *)active_state->newkeys[mode]; } +void * +packet_get_receive_context(void) +{ + return (void*)&(active_state->receive_context); +} + +void * +packet_get_send_context(void) +{ + return (void*)&(active_state->send_context); +} + /* * Save the state for the real connection, and use a separate state when * resuming a suspended connection. diff -Naur --exclude=autom4te.cache openssh-6.6p1/packet.h openssh-6.6p1-gssapi/packet.h --- openssh-6.6p1/packet.h 2013-07-18 01:12:45.000000000 -0500 +++ openssh-6.6p1-gssapi/packet.h 2014-03-18 15:05:44.000000000 -0500 @@ -23,6 +23,7 @@ #include #endif +void packet_request_rekeying(void); void packet_set_connection(int, int); void packet_set_timeout(int, int); void packet_set_nonblocking(void); @@ -38,6 +39,8 @@ int packet_is_interactive(void); void packet_set_server(void); void packet_set_authenticated(void); +void* packet_get_receive_context(void); +void* packet_get_send_context(void); void packet_start(u_char); void packet_put_char(int ch); @@ -51,7 +54,7 @@ void packet_put_string(const void *buf, u_int len); void packet_put_cstring(const char *str); void packet_put_raw(const void *buf, u_int len); -void packet_send(void); +int packet_send(void); int packet_read(void); void packet_read_expect(int type); @@ -85,7 +88,7 @@ void packet_set_iv(int, u_char *); void *packet_get_newkeys(int); -void packet_write_poll(void); +int packet_write_poll(void); void packet_write_wait(void); int packet_have_data_to_write(void); int packet_not_very_much_data_to_write(void); @@ -103,6 +106,10 @@ int packet_set_maxsize(u_int); u_int packet_get_maxsize(void); +/* for forced packet rekeying post auth */ +void packet_request_rekeying(void); +int packet_authentication_state(void); + /* don't allow remaining bytes after the end of the message */ #define packet_check_eom() \ do { \ diff -Naur --exclude=autom4te.cache openssh-6.6p1/progressmeter.c openssh-6.6p1-gssapi/progressmeter.c --- openssh-6.6p1/progressmeter.c 2013-10-09 18:25:10.000000000 -0500 +++ openssh-6.6p1-gssapi/progressmeter.c 2014-03-18 15:05:44.000000000 -0500 @@ -69,6 +69,8 @@ static off_t start_pos; /* initial position of transfer */ static off_t end_pos; /* ending position of transfer */ static off_t cur_pos; /* transfer position as of last refresh */ +static off_t last_pos; +static off_t max_delta_pos = 0; static volatile off_t *counter; /* progress counter */ static long stalled; /* how long we have been stalled */ static int bytes_per_second; /* current speed in bytes per second */ @@ -129,12 +131,17 @@ int hours, minutes, seconds; int i, len; int file_len; + off_t delta_pos; transferred = *counter - (cur_pos ? cur_pos : start_pos); cur_pos = *counter; now = monotime(); bytes_left = end_pos - cur_pos; + delta_pos = cur_pos - last_pos; + if (delta_pos > max_delta_pos) + max_delta_pos = delta_pos; + if (bytes_left > 0) elapsed = now - last_update; else { @@ -159,7 +166,7 @@ /* filename */ buf[0] = '\0'; - file_len = win_size - 35; + file_len = win_size - 45; if (file_len > 0) { len = snprintf(buf, file_len + 1, "\r%s", file); if (len < 0) @@ -176,7 +183,8 @@ percent = ((float)cur_pos / end_pos) * 100; else percent = 100; - snprintf(buf + strlen(buf), win_size - strlen(buf), + + snprintf(buf + strlen(buf), win_size - strlen(buf-8), " %3d%% ", percent); /* amount transferred */ @@ -189,6 +197,15 @@ (off_t)bytes_per_second); strlcat(buf, "/s ", win_size); + /* instantaneous rate */ + if (bytes_left > 0) + format_rate(buf + strlen(buf), win_size - strlen(buf), + delta_pos); + else + format_rate(buf + strlen(buf), win_size - strlen(buf), + max_delta_pos); + strlcat(buf, "/s ", win_size); + /* ETA */ if (!transferred) stalled += elapsed; @@ -225,6 +242,7 @@ atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1); last_update = now; + last_pos = cur_pos; } /*ARGSUSED*/ diff -Naur --exclude=autom4te.cache openssh-6.6p1/readconf.c openssh-6.6p1-gssapi/readconf.c --- openssh-6.6p1/readconf.c 2014-02-23 22:57:56.000000000 -0600 +++ openssh-6.6p1-gssapi/readconf.c 2014-03-18 15:05:44.000000000 -0500 @@ -141,11 +141,15 @@ oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, + oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, + oGssServerIdentity, oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oControlPath, oControlMaster, oControlPersist, oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oVisualHostKey, oUseRoaming, + oTcpRcvBufPoll, oTcpRcvBuf, oHPNDisabled, oHPNBufferSize, + oNoneEnabled, oNoneSwitch, oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, @@ -183,10 +187,19 @@ { "afstokenpassing", oUnsupported }, #if defined(GSSAPI) { "gssapiauthentication", oGssAuthentication }, + { "gssapikeyexchange", oGssKeyEx }, { "gssapidelegatecredentials", oGssDelegateCreds }, + { "gssapitrustdns", oGssTrustDns }, + { "gssapiclientidentity", oGssClientIdentity }, + { "gssapiserveridentity", oGssServerIdentity }, + { "gssapirenewalforcesrekey", oGssRenewalRekey }, #else { "gssapiauthentication", oUnsupported }, + { "gssapikeyexchange", oUnsupported }, { "gssapidelegatecredentials", oUnsupported }, + { "gssapitrustdns", oUnsupported }, + { "gssapiclientidentity", oUnsupported }, + { "gssapirenewalforcesrekey", oUnsupported }, #endif { "fallbacktorsh", oDeprecated }, { "usersh", oDeprecated }, @@ -263,6 +276,14 @@ { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, { "ignoreunknown", oIgnoreUnknown }, + { "noneenabled", oNoneEnabled }, + { "noneswitch", oNoneSwitch }, + + { "tcprcvbufpoll", oTcpRcvBufPoll }, + { "tcprcvbuf", oTcpRcvBuf }, + { "hpndisabled", oHPNDisabled }, + { "hpnbuffersize", oHPNBufferSize }, + { NULL, oBadOption } }; @@ -841,10 +862,30 @@ intptr = &options->gss_authentication; goto parse_flag; + case oGssKeyEx: + intptr = &options->gss_keyex; + goto parse_flag; + case oGssDelegateCreds: intptr = &options->gss_deleg_creds; goto parse_flag; + case oGssTrustDns: + intptr = &options->gss_trust_dns; + goto parse_flag; + + case oGssClientIdentity: + charptr = &options->gss_client_identity; + goto parse_string; + + case oGssServerIdentity: + charptr = &options->gss_server_identity; + goto parse_string; + + case oGssRenewalRekey: + intptr = &options->gss_renewal_rekey; + goto parse_flag; + case oBatchMode: intptr = &options->batch_mode; goto parse_flag; @@ -853,6 +894,36 @@ intptr = &options->check_host_ip; goto parse_flag; + case oHPNDisabled: + intptr = &options->hpn_disabled; + goto parse_flag; + + case oHPNBufferSize: + intptr = &options->hpn_buffer_size; + goto parse_int; + + case oTcpRcvBufPoll: + intptr = &options->tcp_rcv_buf_poll; + goto parse_flag; + + case oNoneEnabled: + intptr = &options->none_enabled; + goto parse_flag; + + /* we check to see if the command comes from the */ + /* command line or not. If it does then enable it */ + /* otherwise fail. NONE should never be a default configuration */ + case oNoneSwitch: + if(strcmp(filename,"command-line") == 0) { + intptr = &options->none_switch; + goto parse_flag; + } else { + error("NoneSwitch is found in %.200s.\nYou may only use this configuration option from the command line", filename); + error("Continuing..."); + debug("NoneSwitch directive found in %.200s.", filename); + return 0; + } + case oVerifyHostKeyDNS: intptr = &options->verify_host_key_dns; multistate_ptr = multistate_yesnoask; @@ -1015,6 +1086,10 @@ intptr = &options->connection_attempts; goto parse_int; + case oTcpRcvBuf: + intptr = &options->tcp_rcv_buf; + goto parse_int; + case oCipher: intptr = &options->cipher; arg = strdelim(&s); @@ -1497,7 +1572,12 @@ options->pubkey_authentication = -1; options->challenge_response_authentication = -1; options->gss_authentication = -1; + options->gss_keyex = -1; options->gss_deleg_creds = -1; + options->gss_trust_dns = -1; + options->gss_renewal_rekey = -1; + options->gss_client_identity = NULL; + options->gss_server_identity = NULL; options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->kbd_interactive_devices = NULL; @@ -1568,6 +1648,13 @@ options->canonicalize_max_dots = -1; options->canonicalize_fallback_local = -1; options->canonicalize_hostname = -1; + + options->none_switch = -1; + options->none_enabled = -1; + options->hpn_disabled = -1; + options->hpn_buffer_size = -1; + options->tcp_rcv_buf_poll = -1; + options->tcp_rcv_buf = -1; } /* @@ -1615,9 +1702,15 @@ 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 = 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 = 1; + if (options->gss_renewal_rekey == -1) + options->gss_renewal_rekey = 0; if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) @@ -1707,6 +1800,32 @@ options->server_alive_interval = 0; if (options->server_alive_count_max == -1) options->server_alive_count_max = 3; + if (options->none_switch == -1) + options->none_switch = 0; + if (options->none_enabled == -1) + options->none_enabled = 0; + if (options->hpn_disabled == -1) + options->hpn_disabled = 0; + if (options->hpn_buffer_size > -1) + { + /* if a user tries to set the size to 0 set it to 1KB */ + if (options->hpn_buffer_size == 0) + options->hpn_buffer_size = 1; + /*limit the buffer to 64MB*/ + if (options->hpn_buffer_size > 64*1024) + { + options->hpn_buffer_size = 64*1024*1024; + debug("User requested buffer larger than 64MB. Request reverted to 64MB"); + } + else options->hpn_buffer_size *= 1024; + debug("hpn_buffer_size set to %d", options->hpn_buffer_size); + } + if (options->tcp_rcv_buf == 0) + options->tcp_rcv_buf = 1; + if (options->tcp_rcv_buf > -1) + options->tcp_rcv_buf *=1024; + if (options->tcp_rcv_buf_poll == -1) + options->tcp_rcv_buf_poll = 1; if (options->control_master == -1) options->control_master = 0; if (options->control_persist == -1) { diff -Naur --exclude=autom4te.cache openssh-6.6p1/readconf.h openssh-6.6p1-gssapi/readconf.h --- openssh-6.6p1/readconf.h 2014-02-23 22:57:56.000000000 -0600 +++ openssh-6.6p1-gssapi/readconf.h 2014-03-18 15:05:44.000000000 -0500 @@ -54,7 +54,12 @@ int challenge_response_authentication; /* Try S/Key or TIS, authentication. */ int gss_authentication; /* Try GSS authentication */ + int gss_keyex; /* Try GSS key exchange */ int gss_deleg_creds; /* Delegate GSS credentials */ + int gss_trust_dns; /* Trust DNS for GSS canonicalization */ + int gss_renewal_rekey; /* Credential renewal forces rekey */ + char *gss_client_identity; /* Principal to initiate GSSAPI with */ + char *gss_server_identity; /* GSSAPI target principal */ int password_authentication; /* Try password * authentication. */ int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ @@ -66,6 +71,10 @@ int compression_level; /* Compression level 1 (fast) to 9 * (best). */ int tcp_keep_alive; /* Set SO_KEEPALIVE. */ + int tcp_rcv_buf; /* user switch to set tcp recv buffer */ + int tcp_rcv_buf_poll; /* Option to poll recv buf every window transfer */ + int hpn_disabled; /* Switch to disable HPN buffer management */ + int hpn_buffer_size; /* User definable size for HPN buffer window */ int ip_qos_interactive; /* IP ToS/DSCP/class for interactive */ int ip_qos_bulk; /* IP ToS/DSCP/class for bulk traffic */ LogLevel log_level; /* Level for logging. */ @@ -88,6 +97,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 */ @@ -116,6 +127,8 @@ int enable_ssh_keysign; int64_t rekey_limit; int rekey_interval; + int none_switch; /* Use none cipher */ + int none_enabled; /* Allow none to be used */ int no_host_authentication_for_localhost; int identities_only; int server_alive_interval; diff -Naur --exclude=autom4te.cache openssh-6.6p1/scp.c openssh-6.6p1-gssapi/scp.c --- openssh-6.6p1/scp.c 2013-11-20 20:56:49.000000000 -0600 +++ openssh-6.6p1-gssapi/scp.c 2014-03-18 15:05:44.000000000 -0500 @@ -749,7 +749,7 @@ off_t i, statbytes; size_t amt; int fd = -1, haderr, indx; - char *last, *name, buf[2048], encname[MAXPATHLEN]; + char *last, *name, buf[16384], encname[MAXPATHLEN]; int len; for (indx = 0; indx < argc; ++indx) { @@ -914,7 +914,7 @@ off_t size, statbytes; unsigned long long ull; int setimes, targisdir, wrerrno = 0; - char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; + char ch, *cp, *np, *targ, *why, *vect[1], buf[16384]; struct timeval tv[2]; #define atime tv[0] diff -Naur --exclude=autom4te.cache openssh-6.6p1/servconf.c openssh-6.6p1-gssapi/servconf.c --- openssh-6.6p1/servconf.c 2014-02-03 18:12:57.000000000 -0600 +++ openssh-6.6p1-gssapi/servconf.c 2014-03-18 15:05:44.000000000 -0500 @@ -71,6 +71,7 @@ /* Portable-specific options */ options->use_pam = -1; + options->permit_pam_user_change = -1; /* Standard Options */ options->num_ports = 0; @@ -106,9 +107,19 @@ options->kerberos_authentication = -1; options->kerberos_or_local_passwd = -1; options->kerberos_ticket_cleanup = -1; +#ifdef SESSION_HOOKS + options->session_hooks_allow = -1; + options->session_hooks_startup_cmd = NULL; + options->session_hooks_shutdown_cmd = NULL; +#endif options->kerberos_get_afs_token = -1; - options->gss_authentication=-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->password_authentication = -1; options->kbd_interactive_authentication = -1; options->challenge_response_authentication = -1; @@ -147,9 +158,15 @@ 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; + options->none_enabled = -1; + options->tcp_rcv_buf_poll = -1; + options->hpn_disabled = -1; + options->hpn_buffer_size = -1; options->ip_qos_interactive = -1; options->ip_qos_bulk = -1; options->version_addendum = NULL; @@ -158,9 +175,16 @@ void fill_default_server_options(ServerOptions *options) { + /* needed for hpn socket tests */ + int sock; + int socksize; + int socksizelen = sizeof(int); + /* 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) @@ -240,12 +264,26 @@ options->kerberos_or_local_passwd = 1; if (options->kerberos_ticket_cleanup == -1) options->kerberos_ticket_cleanup = 1; +#ifdef SESSION_HOOKS + if (options->session_hooks_allow == -1) + options->session_hooks_allow = 0; +#endif 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 = 1; if (options->gss_cleanup_creds == -1) options->gss_cleanup_creds = 1; + if (options->gss_strict_acceptor == -1) + 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; if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) @@ -294,10 +332,86 @@ } if (options->permit_tun == -1) options->permit_tun = SSH_TUNMODE_NO; + if (options->none_enabled == -1) + options->none_enabled = 0; + if (options->hpn_disabled == -1) + options->hpn_disabled = 0; + + if (options->hpn_buffer_size == -1) { + /* option not explicitly set. Now we have to figure out */ + /* what value to use */ + if (options->hpn_disabled == 1) { + options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; + } else { + /* get the current RCV size and set it to that */ + /*create a socket but don't connect it */ + /* we use that the get the rcv socket size */ + sock = socket(AF_INET, SOCK_STREAM, 0); + getsockopt(sock, SOL_SOCKET, SO_RCVBUF, + &socksize, &socksizelen); + close(sock); + options->hpn_buffer_size = socksize; + debug ("HPN Buffer Size: %d", options->hpn_buffer_size); + + } + } else { + /* we have to do this incase the user sets both values in a contradictory */ + /* manner. hpn_disabled overrrides hpn_buffer_size*/ + if (options->hpn_disabled <= 0) { + if (options->hpn_buffer_size == 0) + options->hpn_buffer_size = 1; + /* limit the maximum buffer to 64MB */ + if (options->hpn_buffer_size > 64*1024) { + options->hpn_buffer_size = 64*1024*1024; + } else { + options->hpn_buffer_size *= 1024; + } + } else + options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT; + } + + if (options->ip_qos_interactive == -1) options->ip_qos_interactive = IPTOS_LOWDELAY; if (options->ip_qos_bulk == -1) options->ip_qos_bulk = IPTOS_THROUGHPUT; + + if (options->hpn_disabled == -1) + options->hpn_disabled = 0; + + if (options->hpn_buffer_size == -1) { + /* option not explicitly set. Now we have to figure out */ + /* what value to use */ + if (options->hpn_disabled == 1) { + options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; + } else { + /* get the current RCV size and set it to that */ + /*create a socket but don't connect it */ + /* we use that the get the rcv socket size */ + sock = socket(AF_INET, SOCK_STREAM, 0); + getsockopt(sock, SOL_SOCKET, SO_RCVBUF, + &socksize, &socksizelen); + close(sock); + options->hpn_buffer_size = socksize; + debug ("HPN Buffer Size: %d", options->hpn_buffer_size); + + } + } else { + /* we have to do this incase the user sets both values in a contradictory */ + /* manner. hpn_disabled overrrides hpn_buffer_size*/ + if (options->hpn_disabled <= 0) { + if (options->hpn_buffer_size == 0) + options->hpn_buffer_size = 1; + /* limit the maximum buffer to 64MB */ + if (options->hpn_buffer_size > 64*1024) { + options->hpn_buffer_size = 64*1024*1024; + } else { + options->hpn_buffer_size *= 1024; + } + } else + options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT; + } + if (options->version_addendum == NULL) options->version_addendum = xstrdup(""); /* Turn privilege separation on by default */ @@ -312,14 +426,13 @@ options->compression = 0; } #endif - } /* Keyword tokens. */ typedef enum { sBadOption, /* == unknown option */ /* Portable-specific options */ - sUsePAM, + sUsePAM, sPermitPAMUserChange, /* Standard Options */ sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime, sPermitRootLogin, sLogFacility, sLogLevel, @@ -327,6 +440,9 @@ sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, sKerberosGetAFSToken, sKerberosTgtPassing, sChallengeResponseAuthentication, +#ifdef SESSION_HOOKS + sAllowSessionHooks, sSessionHookStartupCmd, sSessionHookShutdownCmd, +#endif sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, sPrintMotd, sPrintLastLog, sIgnoreRhosts, @@ -340,11 +456,19 @@ sBanner, sUseDNS, sHostbasedAuthentication, sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, - sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, + sGssDelegateCreds, + sGssCredsPath, + sGsiAllowLimitedProxy, + sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, + sGssKeyEx, sGssStoreRekey, + sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, + sDisUsageStats, sUsageStatsTarg, sHostCertificate, sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, + sTcpRcvBufPoll, sHPNDisabled, sHPNBufferSize, + sNoneEnabled, sKexAlgorithms, sIPQoS, sVersionAddendum, sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, sAuthenticationMethods, sHostKeyAgent, @@ -364,8 +488,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 */ @@ -406,11 +532,36 @@ { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, #ifdef GSSAPI { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, + { "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_ALL }, { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, + { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL }, + { "gssapicredentialspath", sGssCredsPath, SSHCFG_GLOBAL }, +#ifdef GSI + { "gsiallowlimitedproxy", sGsiAllowLimitedProxy, SSHCFG_GLOBAL }, +#endif + { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, + { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, #else { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, + { "gssapidelegatecredentials", sUnsupported, SSHCFG_ALL }, { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, + { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL }, + { "gssapicredentialspath", sUnsupported, SSHCFG_GLOBAL }, +#ifdef GSI + { "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL }, #endif + { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, + { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, +#endif +#ifdef SESSION_HOOKS + { "allowsessionhooks", sAllowSessionHooks, SSHCFG_GLOBAL }, + { "sessionhookstartupcmd", sSessionHookStartupCmd, SSHCFG_GLOBAL }, + { "sessionhookshutdowncmd", sSessionHookShutdownCmd, SSHCFG_GLOBAL }, +#endif + { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, + { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, @@ -464,10 +615,16 @@ { "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 }, { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL }, + { "noneenabled", sNoneEnabled, SSHCFG_ALL }, + { "hpndisabled", sHPNDisabled, SSHCFG_ALL }, + { "hpnbuffersize", sHPNBufferSize, SSHCFG_ALL }, + { "tcprcvbufpoll", sTcpRcvBufPoll, SSHCFG_ALL }, { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL }, { "ipqos", sIPQoS, SSHCFG_ALL }, { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL }, @@ -500,6 +657,7 @@ for (i = 0; keywords[i].name; i++) if (strcasecmp(cp, keywords[i].name) == 0) { + debug ("Config token is %s", keywords[i].name); *flags = keywords[i].flags; return keywords[i].opcode; } @@ -871,6 +1029,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; @@ -1042,10 +1204,27 @@ *intptr = value; break; + + case sTcpRcvBufPoll: + intptr = &options->tcp_rcv_buf_poll; + goto parse_flag; + + case sHPNDisabled: + intptr = &options->hpn_disabled; + goto parse_flag; + + case sHPNBufferSize: + intptr = &options->hpn_buffer_size; + goto parse_int; + case sIgnoreUserKnownHosts: intptr = &options->ignore_user_known_hosts; goto parse_flag; + case sNoneEnabled: + intptr = &options->none_enabled; + goto parse_flag; + case sRhostsRSAAuthentication: intptr = &options->rhosts_rsa_authentication; goto parse_flag; @@ -1086,10 +1265,53 @@ 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; + case sGssCleanupCreds: 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; + + case sGssStoreRekey: + intptr = &options->gss_store_rekey; + goto parse_flag; + +#ifdef GSI + case sGsiAllowLimitedProxy: + intptr = &options->gsi_allow_limited_proxy; + goto parse_flag; +#endif + +#ifdef SESSION_HOOKS + case sAllowSessionHooks: + intptr = &options->session_hooks_allow; + goto parse_flag; + case sSessionHookStartupCmd: + case sSessionHookShutdownCmd: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: empty session hook command", + filename, linenum); + if (opcode==sSessionHookStartupCmd) + options->session_hooks_startup_cmd = strdup(arg); + else + options->session_hooks_shutdown_cmd = strdup(arg); + break; +#endif + case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; @@ -1542,6 +1764,39 @@ *charptr = xstrdup(arg); break; + case sDisUsageStats: + charptr = &options->chroot_directory; + + 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: + charptr = &options->chroot_directory; + + 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; @@ -1749,6 +2004,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); @@ -1995,7 +2251,10 @@ #endif #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); + dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); + dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); + dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); #endif dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); dump_cfg_fmtint(sKbdInteractiveAuthentication, diff -Naur --exclude=autom4te.cache openssh-6.6p1/servconf.h openssh-6.6p1-gssapi/servconf.h --- openssh-6.6p1/servconf.h 2014-02-03 18:12:57.000000000 -0600 +++ openssh-6.6p1-gssapi/servconf.h 2014-03-18 15:05:44.000000000 -0500 @@ -109,10 +109,21 @@ * /etc/passwd */ int kerberos_ticket_cleanup; /* If true, destroy ticket * file on logout. */ +#ifdef SESSION_HOOKS + int session_hooks_allow; /* If true, permit user hooks */ + char* session_hooks_startup_cmd; /* cmd to be executed before */ + char* session_hooks_shutdown_cmd; /* cmd to be executed after */ +#endif 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; /* If true, destroy cred cache on logout */ + int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ + int gss_store_rekey; int password_authentication; /* If true, permit password * authentication. */ int kbd_interactive_authentication; /* If true, permit */ @@ -164,12 +175,22 @@ char *adm_forced_command; int use_pam; /* Enable auth via PAM */ + int permit_pam_user_change; /* Allow PAM to change user name */ + int tcp_rcv_buf_poll; /* poll tcp rcv window in autotuning kernels*/ + int hpn_disabled; /* disable hpn functionality. false by default */ + int hpn_buffer_size; /* set the hpn buffer size - default 3MB */ + + int none_enabled; /* enable NONE cipher switch */ int permit_tun; int num_permitted_opens; char *chroot_directory; + + int disable_usage_stats; + char *usage_stats_targets; + char *revoked_keys_file; char *trusted_user_ca_keys; char *authorized_principals_file; diff -Naur --exclude=autom4te.cache openssh-6.6p1/serverloop.c openssh-6.6p1-gssapi/serverloop.c --- openssh-6.6p1/serverloop.c 2014-02-03 18:20:15.000000000 -0600 +++ openssh-6.6p1-gssapi/serverloop.c 2014-03-18 15:05:44.000000000 -0500 @@ -80,6 +80,11 @@ #include "misc.h" #include "roaming.h" +#ifdef NERSC_MOD +#include "nersc.h" +extern int client_session_id; +#endif + extern ServerOptions options; /* XXX */ @@ -94,10 +99,10 @@ static int fdout; /* Descriptor for stdout (for reading); May be same number as fdin. */ static int fderr; /* Descriptor for stderr. May be -1. */ -static long stdin_bytes = 0; /* Number of bytes written to stdin. */ -static long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ -static long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ -static long fdout_bytes = 0; /* Number of stdout bytes read from program. */ +static u_long stdin_bytes = 0; /* Number of bytes written to stdin. */ +static u_long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ +static u_long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ +static u_long fdout_bytes = 0; /* Number of stdout bytes read from program. */ static int stdin_eof = 0; /* EOF message received from client. */ static int fdout_eof = 0; /* EOF encountered reading from fdout. */ static int fderr_eof = 0; /* EOF encountered readung from fderr. */ @@ -122,6 +127,20 @@ static void server_init_dispatch(void); /* + * Returns current time in seconds from Jan 1, 1970 with the maximum + * available resolution. + */ + +static double +get_current_time(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; +} + + +/* * we write to this pipe if a SIGCHLD is caught in order to avoid * the race between select() and child_terminated */ @@ -421,6 +440,7 @@ } else { /* Buffer any received data. */ packet_process_incoming(buf, len); + fdout_bytes += len; } } if (compat20) @@ -443,6 +463,7 @@ } else { buffer_append(&stdout_buffer, buf, len); fdout_bytes += len; + debug ("FD out now: %ld", fdout_bytes); } } /* Read and buffer any available stderr data from the program. */ @@ -510,7 +531,7 @@ } /* Send any buffered packet data to the client. */ if (FD_ISSET(connection_out, writeset)) - packet_write_poll(); + stdin_bytes += packet_write_poll(); } /* @@ -571,6 +592,10 @@ debug("Entering interactive session."); +#ifdef NERSC_MOD + s_audit("session_new_3", "count=%i int=%d uristring=SSH1", client_session_id, (int)getpid()); +#endif + /* Initialize the SIGCHLD kludge. */ child_terminated = 0; mysignal(SIGCHLD, sigchld_handler); @@ -825,10 +850,12 @@ { fd_set *readset = NULL, *writeset = NULL; int rekeying = 0, max_fd; + double start_time, total_time; u_int nalloc = 0; u_int64_t rekey_timeout_ms = 0; debug("Entering interactive session for SSH2."); + start_time = get_current_time(); mysignal(SIGCHLD, sigchld_handler); child_terminated = 0; @@ -848,6 +875,10 @@ server_init_dispatch(); +#ifdef NERSC_MOD + s_audit("session_new_3", "count=%i int=%d uristring=SSH2", client_session_id, (int)getpid()); +#endif + for (;;) { process_buffered_input_packets(); @@ -893,6 +924,11 @@ /* free remaining sessions, e.g. remove wtmp entries */ session_destroy_all(NULL); + total_time = get_current_time() - start_time; + logit("SSH: Server;LType: Throughput;Remote: %s-%d;IN: %lu;OUT: %lu;Duration: %.1f;tPut_in: %.1f;tPut_out: %.1f", + get_remote_ipaddr(), get_remote_port(), + stdin_bytes, fdout_bytes, total_time, stdin_bytes / total_time, + fdout_bytes / total_time); } static void @@ -972,6 +1008,18 @@ !no_port_forwarding_flag) { c = channel_connect_to(target, target_port, "direct-tcpip", "direct-tcpip"); + +#ifdef NERSC_MOD + char* t1buf = encode_string(originator, strlen(originator)); + char* t2buf = encode_string(target, strlen(target)); + + s_audit("session_request_direct_tcpip_3", "count=%i count=%i uristring=%s port=%d/tcp string=%s port=%d/tcp count=%i", + client_session_id, c->self, t1buf, originator_port, t2buf, target_port); + + free(t1buf); + free(t2buf); +#endif + } else { logit("refused local port forward: " "originator %s port %d, target %s port %d", @@ -1015,8 +1063,16 @@ sock = tun_open(tun, mode); if (sock < 0) goto done; +#ifdef NERSC_MOD + s_audit("session_tun_init_3", "count=%i count=%i count=%i", + client_session_id, c->self, mode); +#endif + if (options.hpn_disabled) c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); + else + c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1, + options.hpn_buffer_size, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); c->datagram = 1; #if defined(SSH_TUN_FILTER) if (mode == SSH_TUNMODE_POINTOPOINT) @@ -1052,6 +1108,8 @@ c = channel_new("session", SSH_CHANNEL_LARVAL, -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT, 0, "server-session", 1); + if ((options.tcp_rcv_buf_poll) && (!options.hpn_disabled)) + c->dynamic_window = 1; if (session_open(the_authctxt, c->self) != 1) { debug("session open failed, free channel %d", c->self); channel_free(c); @@ -1096,6 +1154,15 @@ packet_put_int(c->local_window); packet_put_int(c->local_maxpacket); packet_send(); +#ifdef NERSC_MOD + char* t1buf = encode_string(ctype, strlen(ctype)); + + s_audit("session_input_channel_open_3", "count=%i count=%i uristring=%s int=%d int=%i int=%d", + client_session_id, type, t1buf, rchan, rwindow, rmaxpack); + + free(t1buf); +#endif + } } else { debug("server_input_channel_open: failure %s", ctype); diff -Naur --exclude=autom4te.cache openssh-6.6p1/session.c openssh-6.6p1-gssapi/session.c --- openssh-6.6p1/session.c 2014-03-03 16:35:17.000000000 -0600 +++ openssh-6.6p1-gssapi/session.c 2014-03-18 15:05:44.000000000 -0500 @@ -93,6 +93,12 @@ #include "monitor_wrap.h" #include "sftp.h" +#ifdef NERSC_MOD +#include "nersc.h" +#include +extern int client_session_id; +#endif + #if defined(KRB5) && defined(USE_AFS) #include #endif @@ -130,6 +136,11 @@ static int session_pty_req(Session *); +#ifdef SESSION_HOOKS +static void execute_session_hook(char* prog, Authctxt *authctxt, + int startup, int save); +#endif + /* import */ extern ServerOptions options; extern char *__progname; @@ -237,6 +248,7 @@ } /* Allocate a channel for the authentication agent socket. */ + /* this shouldn't matter if its hpn or not - cjr */ nc = channel_new("auth socket", SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, @@ -286,6 +298,21 @@ else do_authenticated1(authctxt); +#ifdef SESSION_HOOKS + if (options.session_hooks_allow && + options.session_hooks_shutdown_cmd) + { + execute_session_hook(options.session_hooks_shutdown_cmd, + authctxt, + /* startup = */ 0, /* save = */ 0); + + if (authctxt->session_env_file) + { + free(authctxt->session_env_file); + } + } +#endif + do_cleanup(authctxt); } @@ -325,15 +352,24 @@ /* Process the packet. */ switch (type) { case SSH_CMSG_REQUEST_COMPRESSION: +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 2); +#endif compression_level = packet_get_int(); packet_check_eom(); if (compression_level < 1 || compression_level > 9) { packet_send_debug("Received invalid compression level %d.", compression_level); +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 0); +#endif break; } if (options.compression == COMP_NONE) { debug2("compression disabled"); +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 0); +#endif break; } /* Enable compression after we have responded with SUCCESS. */ @@ -342,10 +378,20 @@ break; case SSH_CMSG_REQUEST_PTY: +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 2); +#endif + success = session_pty_req(s); +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, success); +#endif break; case SSH_CMSG_X11_REQUEST_FORWARDING: +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 2); +#endif s->auth_proto = packet_get_string(&proto_len); s->auth_data = packet_get_string(&data_len); @@ -369,54 +415,108 @@ s->auth_proto = NULL; s->auth_data = NULL; } +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, success); +#endif break; case SSH_CMSG_AGENT_REQUEST_FORWARDING: +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 2); +#endif if (!options.allow_agent_forwarding || no_agent_forwarding_flag || compat13) { debug("Authentication agent forwarding not permitted for this authentication."); +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 0); +#endif break; } debug("Received authentication agent forwarding request."); success = auth_input_request_forwarding(s->pw); +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, success); +#endif break; case SSH_CMSG_PORT_FORWARD_REQUEST: +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 2); +#endif if (no_port_forwarding_flag) { +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 0); +#endif debug("Port forwarding not permitted for this authentication."); break; } if (!(options.allow_tcp_forwarding & FORWARD_REMOTE)) { debug("Port forwarding not permitted."); +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 0); +#endif break; } debug("Received TCP/IP port forwarding request."); if (channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports) < 0) { debug("Port forwarding failed."); +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 0); +#endif break; } success = 1; +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 1); +#endif break; case SSH_CMSG_MAX_PACKET_SIZE: +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 2); +#endif if (packet_set_maxsize(packet_get_int()) > 0) success = 1; +#ifdef NERSC_MOD + int t_success = 0; + if ( success == 1 ) t_success = 1; + s_audit("session_do_auth_3", "count=%i count=%i", type, t_success); +#endif break; case SSH_CMSG_EXEC_SHELL: case SSH_CMSG_EXEC_CMD: +#ifdef NERSC_MOD + s_audit("session_do_auth_3", "count=%i count=%i", type, 2); + int t_success2 = 1; +#endif if (type == SSH_CMSG_EXEC_CMD) { command = packet_get_string(&dlen); debug("Exec command '%.500s'", command); if (do_exec(s, command) != 0) +#ifdef NERSC_MOD + { + t_success2 = 0; + packet_disconnect("command execution failed"); + } +#else packet_disconnect( "command execution failed"); +#endif + free(command); } else { if (do_exec(s, NULL) != 0) +#ifdef NERSC_MOD + { + t_success2 = 0; + packet_disconnect("command execution failed"); + } +#else packet_disconnect( "shell execution failed"); +#endif } packet_check_eom(); session_close(s); @@ -498,6 +598,16 @@ } #endif +#ifdef NERSC_MOD + if ( command != NULL ) { + + char* t1buf = encode_string(command, strlen(command)); + s_audit("session_remote_exec_no_pty_3", "count=%i count=%i count=%ld uristring=%s", + client_session_id, s->chanid, (long)getppid(), t1buf); + free(t1buf); + } +#endif + session_proctitle(s); /* Fork the child. */ @@ -653,6 +763,15 @@ ptyfd = s->ptyfd; ttyfd = s->ttyfd; +#ifdef NERSC_MOD + if ( command != NULL ) { + + char* t1buf = encode_string(command, strlen(command)); + s_audit("session_remote_exec_pty_3", "count=%i count=%i count=%ld uristring=%s", + client_session_id, s->chanid, (long)getppid(), t1buf); + free(t1buf); + } +#endif /* * Create another descriptor of the pty master side for use as the * standard input. We could use the original descriptor, but this @@ -797,6 +916,19 @@ const char *forced = NULL; char session_type[1024], *tty = NULL; +#ifdef NERSC_MOD + /* since the channel client/server code now takes the raw string + * data, we remove the 'clean_command' functionality + */ + if ( command != NULL ) { + + char* t1buf = encode_string(command, strlen(command)); + s_audit("session_remote_do_exec_3", "count=%i count=%i count=%ld uristring=%s", + client_session_id, s->chanid, (long)getppid(), t1buf); + free(t1buf); + } +#endif + if (options.adm_forced_command) { original_command = command; command = options.adm_forced_command; @@ -830,6 +962,26 @@ tty += 5; } +#if defined(SESSION_HOOKS) + if (options.session_hooks_allow && + (options.session_hooks_startup_cmd || + options.session_hooks_shutdown_cmd)) + { + char env_file[1000]; + struct stat st; + do + { + snprintf(env_file, + sizeof(env_file), + "/tmp/ssh_env_%d%d%d", + getuid(), + getpid(), + rand()); + } while (stat(env_file, &st)==0); + s->authctxt->session_env_file = strdup(env_file); + } +#endif + verbose("Starting session: %s%s%s for %s from %.200s port %d", session_type, tty == NULL ? "" : " on ", @@ -1071,6 +1223,117 @@ fclose(f); } +#ifdef SESSION_HOOKS +#define SSH_SESSION_ENV_FILE "SSH_SESSION_ENV_FILE" + +typedef enum { no_op, execute, clear_env, restore_env, + read_env, save_or_rm_env } session_action_t; + +static session_action_t action_order[2][5] = { + { clear_env, read_env, execute, save_or_rm_env, restore_env }, /*shutdown*/ + { execute, read_env, save_or_rm_env, no_op, no_op } /*startup */ +}; + +static +void execute_session_hook(char* prog, Authctxt *authctxt, + int startup, int save) +{ + extern char **environ; + + struct stat st; + char **saved_env, **tmpenv; + char *env_file = authctxt->session_env_file; + int i, status = 0; + + for (i=0; i<5; i++) + { + switch (action_order[startup][i]) + { + case no_op: + break; + + case execute: + { + FILE* fp; + char buf[1000]; + + snprintf(buf, + sizeof(buf), + "%s -c '%s'", + authctxt->pw->pw_shell, + prog); + + debug("executing session hook: [%s]", buf); + setenv(SSH_SESSION_ENV_FILE, env_file, /* overwrite = */ 1); + + /* flusing is recommended in the popen(3) man page, to avoid + intermingling of output */ + fflush(stdout); + fflush(stderr); + if ((fp=popen(buf, "w")) == NULL) + { + perror("Unable to run session hook"); + return; + } + status = pclose(fp); + debug2("session hook executed, status=%d", status); + unsetenv(SSH_SESSION_ENV_FILE); + } + break; + + case clear_env: + saved_env = environ; + tmpenv = (char**) malloc(sizeof(char*)); + tmpenv[0] = NULL; + environ = tmpenv; + break; + + case restore_env: + environ = saved_env; + free(tmpenv); + break; + + case read_env: + if (status==0 && stat(env_file, &st)==0) + { + int envsize = 0; + + debug("reading environment from %s", env_file); + while (environ[envsize++]) ; + read_environment_file(&environ, &envsize, env_file); + } + break; + + case save_or_rm_env: + if (status==0 && save) + { + FILE* fp; + int envcount=0; + + debug2("saving environment to %s", env_file); + if ((fp = fopen(env_file, "w")) == NULL) /* hmm: file perms? */ + { + perror("Unable to save session hook info"); + } + while (environ[envcount]) + { + fprintf(fp, "%s\n", environ[envcount++]); + } + fflush(fp); + fclose(fp); + } + else if (stat(env_file, &st)==0) + { + debug2("removing environment file %s", env_file); + remove(env_file); + } + break; + } + } + +} +#endif + #ifdef HAVE_ETC_DEFAULT_LOGIN /* * Return named variable from specified environment, or NULL if not present. @@ -1234,6 +1497,23 @@ if (getenv("TZ")) child_set_env(&env, &envsize, "TZ", getenv("TZ")); +#ifdef GSI /* GSI shared libs typically installed in non-system locations. */ + { + char *cp; + + if ((cp = getenv("LD_LIBRARY_PATH")) != NULL) + child_set_env(&env, &envsize, "LD_LIBRARY_PATH", cp); + if ((cp = getenv("LIBPATH")) != NULL) + child_set_env(&env, &envsize, "LIBPATH", cp); + if ((cp = getenv("SHLIB_PATH")) != NULL) + child_set_env(&env, &envsize, "SHLIB_PATH", cp); + if ((cp = getenv("LD_LIBRARYN32_PATH")) != NULL) + child_set_env(&env, &envsize, "LD_LIBRARYN32_PATH",cp); + if ((cp = getenv("LD_LIBRARY64_PATH")) != NULL) + child_set_env(&env, &envsize, "LD_LIBRARY64_PATH",cp); + } +#endif + /* Set custom environment options from RSA authentication. */ if (!options.use_login) { while (custom_environment) { @@ -1674,6 +1954,18 @@ struct passwd *pw = s->pw; int r = 0; +#ifdef AFS_KRB5 +/* Default place to look for aklog. */ +#ifdef AKLOG_PATH +#define KPROGDIR AKLOG_PATH +#else +#define KPROGDIR "/usr/bin/aklog" +#endif /* AKLOG_PATH */ + + struct stat st; + char *aklog_path; +#endif /* AFS_KRB5 */ + /* remove hostkey from the child's memory */ destroy_sensitive_data(); @@ -1786,6 +2078,41 @@ } #endif +#ifdef AFS_KRB5 + + /* User has authenticated, and if a ticket was going to be + * passed we would have it. KRB5CCNAME should already be set. + * Now try to get an AFS token using aklog. + */ + if (k_hasafs()) { /* Do we have AFS? */ + + aklog_path = xstrdup(KPROGDIR); + + /* + * Make sure it exists before we try to run it + */ + if (stat(aklog_path, &st) == 0) { + debug("Running %s to get afs token.",aklog_path); + system(aklog_path); + } else { + debug("%s does not exist.",aklog_path); + } + + free(aklog_path); + } +#endif /* AFS_KRB5 */ + +#ifdef SESSION_HOOKS + if (options.session_hooks_allow && + options.session_hooks_startup_cmd) + { + execute_session_hook(options.session_hooks_startup_cmd, + s->authctxt, + /* startup = */ 1, + options.session_hooks_shutdown_cmd != NULL); + } +#endif + /* Change current directory to the user's home directory. */ if (chdir(pw->pw_dir) < 0) { /* Suppress missing homedir warning for chroot case */ @@ -1866,7 +2193,7 @@ /* Execute the shell. */ argv[0] = argv0; argv[1] = NULL; - execve(shell, argv, env); + execve(shell, argv, environ); /* Executing the shell failed. */ perror(shell); @@ -1880,7 +2207,7 @@ argv[1] = "-c"; argv[2] = (char *) command; argv[3] = NULL; - execve(shell, argv, env); + execve(shell, argv, environ); perror(shell); exit(1); } @@ -2310,6 +2637,17 @@ success = session_env_req(s); } } + +#ifdef NERSC_MOD + if ((strcmp(rtype,"window-change") != 0) && (strcmp(rtype,"env") != 0)) { + + char* t1buf = encode_string(rtype, strlen(rtype)); + s_audit("session_channel_request_3", "count=%i int=%d count=%d uristring=%s", + client_session_id, getpid(), c->self, t1buf); + free(t1buf); + } +#endif + if (strcmp(rtype, "window-change") == 0) { success = session_window_change_req(s); } else if (strcmp(rtype, "break") == 0) { @@ -2331,10 +2669,16 @@ */ if (s->chanid == -1) fatal("no channel for session %d", s->self); + if (options.hpn_disabled) channel_set_fds(s->chanid, fdout, fdin, fderr, ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, 1, is_tty, CHAN_SES_WINDOW_DEFAULT); + else + channel_set_fds(s->chanid, + fdout, fdin, fderr, + ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, + 1, is_tty, options.hpn_buffer_size); } /* @@ -2483,6 +2827,10 @@ /* disconnect channel */ debug("session_exit_message: release channel %d", s->chanid); +#ifdef NERSC_MOD + s_audit("session_exit_3", "count=%i count=%d count=%ld count=%d", client_session_id, s->chanid, (long)getppid(), status); +#endif + /* * Adjust cleanup callback attachment to send close messages when * the channel gets EOF. The session will be then be closed @@ -2691,6 +3039,14 @@ s->display_number, s->screen); s->display = xstrdup(display); s->auth_display = xstrdup(auth_display); + +#ifdef NERSC_MOD + char* t1buf = encode_string(display, strlen(display)); + s_audit("session_x11fwd_3", "count=%i count=%i uristring=%s", + client_session_id, s->chanid, t1buf); + free(t1buf); +#endif + } else { #ifdef IPADDR_IN_DISPLAY struct hostent *he; diff -Naur --exclude=autom4te.cache openssh-6.6p1/sftp-server.c openssh-6.6p1-gssapi/sftp-server.c --- openssh-6.6p1/sftp-server.c 2014-01-18 22:25:35.000000000 -0600 +++ openssh-6.6p1-gssapi/sftp-server.c 2014-03-18 15:05:44.000000000 -0500 @@ -52,6 +52,11 @@ #include "sftp.h" #include "sftp-common.h" +#ifdef NERSC_MOD +#include "nersc.h" +extern int client_session_id; +#endif + /* helper */ #define get_int64() buffer_get_int64(&iqueue); #define get_int() buffer_get_int(&iqueue); @@ -628,6 +633,11 @@ buffer_put_int64(&msg, st->f_namemax); send_msg(&msg); buffer_free(&msg); + +#ifdef NERSC_MOD + s_audit("sftp_process_init_3", "count=%i int=%d int=%d", + get_client_session_id(), (int)getppid(), version); +#endif } /* parse incoming */ @@ -698,6 +708,14 @@ } if (status != SSH2_FX_OK) send_status(id, status); + +#ifdef NERSC_MOD + char* t1buf = encode_string( name, strlen(name)); + s_audit("sftp_process_open_3", "count=%i int=%d uristring=%s", + get_client_session_id(), (int)getppid(), t1buf); + free(t1buf); +#endif + free(name); } @@ -712,6 +730,11 @@ ret = handle_close(handle); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); + +#ifdef NERSC_MOD + s_audit("sftp_process_close_3", "count=%i int=%d int=%d int=%d", + get_client_session_id(), (int)getppid(), id, handle); +#endif } static void @@ -817,6 +840,13 @@ } if (status != SSH2_FX_OK) send_status(id, status); + +#ifdef NERSC_MOD + char* t1buf = encode_string(name, strlen(name)); + s_audit("sftp_process_do_stat_3", "count=%i int=%d uristring=%s", + get_client_session_id(), (int)getppid(), t1buf); + free(t1buf); +#endif free(name); } @@ -855,6 +885,11 @@ } if (status != SSH2_FX_OK) send_status(id, status); + +#ifdef NERSC_MOD + s_audit("sftp_process_fstat_3", "count=%i int=%d int=%d", + get_client_session_id(), (int)getppid(), handle); +#endif } static struct timeval * @@ -911,6 +946,13 @@ status = errno_to_portable(errno); } send_status(id, status); + +#ifdef NERSC_MOD + char* t1buf = encode_string( name, strlen(name)); + s_audit("sftp_process_setstat_3", "count=%i int=%d int=%d uristring=%s", + get_client_session_id(), (int)getppid(), id, t1buf); + free(t1buf); +#endif free(name); } @@ -975,6 +1017,13 @@ } } send_status(id, status); + +#ifdef NERSC_MOD + char* t1buf = encode_string( handle_to_name(handle), strlen(handle_to_name(handle)) ); + s_audit("sftp_process_fsetstat_3", "count=%i int=%d int=%d uristring=%s", + get_client_session_id(), (int)getppid(), id, t1buf); + free(t1buf); +#endif } static void @@ -1002,6 +1051,13 @@ } if (status != SSH2_FX_OK) send_status(id, status); + +#ifdef NERSC_MOD + char* t1buf = encode_string(path, strlen(path)); + s_audit("sftp_process_opendir_3", "count=%i int=%d uristring=%s", + get_client_session_id(), (int)getpid(), t1buf); + free(t1buf); +#endif free(path); } @@ -1055,6 +1111,12 @@ } else { send_status(id, SSH2_FX_EOF); } + +#ifdef NERSC_MOD + char* t1buf = encode_string(path, strlen(path)); + s_audit("sftp_process_readdir_3", "count=%i int=%d uristring=%s", + get_client_session_id(), (int)getppid(), t1buf); +#endif free(stats); } } @@ -1072,6 +1134,12 @@ ret = unlink(name); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); + +#ifdef NERSC_MOD + char* t1buf = encode_string(name, strlen(name)); + s_audit("sftp_process_remove_3", "count=%i int=%d uristring=%s", + get_client_session_id(), (int)getppid(), t1buf); +#endif free(name); } @@ -1091,6 +1159,13 @@ ret = mkdir(name, mode); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); + +#ifdef NERSC_MOD + char* t1buf = encode_string(name, strlen(name)); + s_audit("sftp_process_mkdir_3", "count=%i int=%d uristring=%s", + get_client_session_id(), (int)getpid(), t1buf); + free(t1buf); +#endif free(name); } @@ -1106,6 +1181,13 @@ ret = rmdir(name); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); + +#ifdef NERSC_MOD + char* t1buf = encode_string(name, strlen(name)); + s_audit("sftp_process_rmdir_3", "count=%i int=%d uristring=%s", + get_client_session_id(), (int)getppid(), t1buf); + free(t1buf); +#endif free(name); } @@ -1130,6 +1212,13 @@ s.name = s.long_name = resolvedname; send_names(id, 1, &s); } + +#ifdef NERSC_MOD + char* t1buf = encode_string(path, strlen(path)); + s_audit("sftp_process_realpath_3", "count=%i int=%d uristring=%s", + get_client_session_id(), (int)getppid(), t1buf); + free(t1buf); +#endif free(path); } @@ -1187,6 +1276,17 @@ status = SSH2_FX_OK; } send_status(id, status); + +#ifdef NERSC_MOD + char* t1buf = encode_string( oldpath, strlen(oldpath)); + char* t2buf = encode_string( newpath, strlen(newpath)); + + s_audit("sftp_process_rename_3", "count=%i int=%d uristring=%s uristring=%s", + get_client_session_id(), (int)getppid(), t1buf, t2buf); + + free(t1buf); + free(t2buf); +#endif free(oldpath); free(newpath); } @@ -1211,6 +1311,13 @@ s.name = s.long_name = buf; send_names(id, 1, &s); } + +#ifdef NERSC_MOD + char* t1buf = encode_string( path, strlen(path)); + s_audit("sftp_process_readlink_3", "count=%i int=%d uristring=%s", + get_client_session_id(), (int)getppid(), t1buf); + free(t1buf); +#endif free(path); } @@ -1228,6 +1335,18 @@ ret = symlink(oldpath, newpath); status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); + +#ifdef NERSC_MOD + char* t1buf = encode_string( oldpath, strlen(oldpath)); + char* t2buf = encode_string( newpath, strlen(newpath)); + + s_audit("sftp_process_symlink_3", "count=%i int=%d uristring=%s uristring=%s", + get_client_session_id(), (int)getppid(), t1buf, t2buf); + + free(t1buf); + free(t2buf); +#endif + free(oldpath); free(newpath); } @@ -1565,6 +1684,13 @@ } } +#ifdef NERSC_MOD + char* t1buf = encode_string(pw->pw_name, strlen(pw->pw_name)); + s_audit("sftp_process_init_3", "count=%i int=%d uristring=%s addr=%s", + get_client_session_id(), (int)getppid(), t1buf, client_addr); + free(t1buf); +#endif + for (;;) { memset(rset, 0, set_size); memset(wset, 0, set_size); diff -Naur --exclude=autom4te.cache openssh-6.6p1/sftp.1 openssh-6.6p1-gssapi/sftp.1 --- openssh-6.6p1/sftp.1 2013-10-23 00:30:00.000000000 -0500 +++ openssh-6.6p1-gssapi/sftp.1 2014-03-18 15:05:44.000000000 -0500 @@ -261,7 +261,8 @@ Specify how many requests may be outstanding at any one time. Increasing this may slightly improve file transfer speed but will increase memory usage. -The default is 64 outstanding requests. +The default is 256 outstanding requests providing for 8MB +of outstanding data with a 32KB buffer. .It Fl r Recursively copy entire directories when uploading and downloading. Note that diff -Naur --exclude=autom4te.cache openssh-6.6p1/sftp.c openssh-6.6p1-gssapi/sftp.c --- openssh-6.6p1/sftp.c 2013-11-20 20:57:15.000000000 -0600 +++ openssh-6.6p1-gssapi/sftp.c 2014-03-18 15:05:44.000000000 -0500 @@ -68,7 +68,7 @@ #include "sftp-client.h" #define DEFAULT_COPY_BUFLEN 32768 /* Size of buffer for up/download */ -#define DEFAULT_NUM_REQUESTS 64 /* # concurrent outstanding requests */ +#define DEFAULT_NUM_REQUESTS 256 /* # concurrent outstanding requests */ /* File to read commands from */ FILE* infile; diff -Naur --exclude=autom4te.cache openssh-6.6p1/ssh-globus-usage.c openssh-6.6p1-gssapi/ssh-globus-usage.c --- openssh-6.6p1/ssh-globus-usage.c 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/ssh-globus-usage.c 2014-03-18 15:05:44.000000000 -0500 @@ -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) + return GLOBUS_SUCCESS; + + result = globus_module_activate(GLOBUS_USAGE_MODULE); + if (result != GLOBUS_SUCCESS) + { + error("ERROR: couldn't activate USAGE STATS module"); + return result; + } + + if (!usage_stats_targets || + !strcasecmp(usage_stats_targets, "default")) + target_str = strdup(CILOGON_COLLECTOR); + else + 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(char *ssh_release, const char *ssl_release, + char *method, char *mechanism, const char *clientip, + char *username, 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 = 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 = method; + break; + + case SSH_GLOBUS_USAGE_MECHANISM: + key = "MECH"; + value = mechanism?:""; + break; + + case SSH_GLOBUS_USAGE_CLIENTIP: + key = "CLIENTIP"; + value = (char *) clientip?:""; + break; + + case SSH_GLOBUS_USAGE_USERNAME: + key = "USER"; + value = username?:""; + break; + + case SSH_GLOBUS_USAGE_USERDN: + key = "USERDN"; + value = 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(char *ssh_release, const char *ssl_release, + char *method, char *mechanism, const char *client_ip, + char *username, char *userdn) +{ +#ifdef HAVE_GLOBUS_USAGE + + log_usage_stats(ssh_release, ssl_release, method, mechanism, + client_ip, username, userdn); + +#endif /* HAVE_GLOBUS_USAGE */ +} diff -Naur --exclude=autom4te.cache openssh-6.6p1/ssh-globus-usage.h openssh-6.6p1-gssapi/ssh-globus-usage.h --- openssh-6.6p1/ssh-globus-usage.h 1969-12-31 18:00:00.000000000 -0600 +++ openssh-6.6p1-gssapi/ssh-globus-usage.h 2014-03-18 15:05:44.000000000 -0500 @@ -0,0 +1,46 @@ +/* + * 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" + +#define CILOGON_COLLECTOR "usage-stats.cilogon.org:4810" + +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(char *ssh_release, const char *ssl_release, + char *method, char *mechanism, const char *client_ip, + char *username, char *userdn); + +#endif /* __SSH_GLOBUS_USAGE_H */ diff -Naur --exclude=autom4te.cache openssh-6.6p1/ssh-gss.h openssh-6.6p1-gssapi/ssh-gss.h --- openssh-6.6p1/ssh-gss.h 2014-02-26 17:17:50.000000000 -0600 +++ openssh-6.6p1-gssapi/ssh-gss.h 2014-03-18 15:05:44.000000000 -0500 @@ -1,6 +1,6 @@ /* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 djm Exp $ */ /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -34,6 +34,7 @@ #include #endif +#ifndef MECHGLUE #ifdef KRB5 # ifndef HEIMDAL # ifdef HAVE_GSSAPI_GENERIC_H @@ -50,6 +51,7 @@ # endif /* !HEIMDAL */ #endif /* KRB5 */ +#endif /* !MECHGLUE */ /* draft-ietf-secsh-gsskeyex-06 */ #define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60 @@ -61,10 +63,22 @@ #define SSH_GSS_OIDTYPE 0x06 +#define SSH2_MSG_KEXGSS_INIT 30 +#define SSH2_MSG_KEXGSS_CONTINUE 31 +#define SSH2_MSG_KEXGSS_COMPLETE 32 +#define SSH2_MSG_KEXGSS_HOSTKEY 33 +#define SSH2_MSG_KEXGSS_ERROR 34 +#define SSH2_MSG_KEXGSS_GROUPREQ 40 +#define SSH2_MSG_KEXGSS_GROUP 41 +#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-" +#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" +#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" + typedef struct { char *filename; char *envvar; char *envval; + struct passwd *owner; void *data; } ssh_gssapi_ccache; @@ -72,8 +86,12 @@ gss_buffer_desc displayname; gss_buffer_desc exportedname; gss_cred_id_t creds; + 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; typedef struct ssh_gssapi_mech_struct { @@ -84,6 +102,7 @@ int (*userok) (ssh_gssapi_client *, char *); int (*localname) (ssh_gssapi_client *, char **); void (*storecreds) (ssh_gssapi_client *); + int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); } ssh_gssapi_mech; typedef struct { @@ -91,13 +110,14 @@ 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; /* server */ + gss_cred_id_t client_creds; /* both */ } Gssctxt; extern ssh_gssapi_mech *supported_mechs[]; +extern Gssctxt *gss_kex_context; int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); @@ -119,16 +139,41 @@ void ssh_gssapi_delete_ctx(Gssctxt **); OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); -int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); +int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *); +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 *); +char *ssh_gssapi_client_mechanisms(const char *, const char *); +char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *, + const char *); +gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); +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); +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); void ssh_gssapi_storecreds(void); +#ifdef MECHGLUE +gss_cred_id_t __gss_get_mechanism_cred + (gss_cred_id_t, /* union_cred */ + gss_OID /* mech_type */ + ); +#endif + +char *ssh_gssapi_server_mechanisms(void); +int ssh_gssapi_oid_table_ok(); + +int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); +void ssh_gssapi_get_client_info(char **userdn, char **mech); #endif /* GSSAPI */ #endif /* _SSH_GSS_H */ diff -Naur --exclude=autom4te.cache openssh-6.6p1/ssh.1 openssh-6.6p1-gssapi/ssh.1 --- openssh-6.6p1/ssh.1 2013-12-18 00:46:28.000000000 -0600 +++ openssh-6.6p1-gssapi/ssh.1 2014-03-18 15:05:44.000000000 -0500 @@ -1235,8 +1235,38 @@ explicitly, as that will render the X11 connection insecure (and will require the user to manually copy any required authorization cookies). +.It Ev GSSAPI_MECH_CONF +Applies to mechglue used to support both GSI and Kerberos GSSAPI mechanisms. +Used to specify the location of the mech.conf file that lists the mechanism- +specific GSSAPI libraries (both Kerberos and GSI versions). If +.Ev GSSAPI_MECH_CONF +is not set then /etc/mech.conf is used. This applies to both the clients and +the server. The NCSA GSSAPI mechglue distribution includes a sample mech.conf +file. You will need to edit the library paths in that file and install it in +an appropriate location on your system. If the mech.conf file is not found, +the GSSAPI mechglue library will not load any GSSAPI mechanisms and GSI-OpenSSH +will simply skip GSSAPI authentication. .It Ev HOME Set to the path of the user's home directory. +.It LD_LIBRARY_PATH +The ssh client is typically linked dynamically with Globus +security libraries, which must be present in the dynamic linker's +search path. This typically requires +.Cm $GLOBUS_LOCATION/lib +to be included in the list in the +.Ev LD_LIBRARY_PATH +environment variable, which is set by the +.Cm $GLOBUS_LOCATION/libexec/globus-script-initializer +script, which should be called from any +.Cm ssh +invocation script. +Alternatively, to set +.Ev LD_LIBRARY_PATH +appropriately for the Globus libraries in an interactive shell, source +.Cm $GLOBUS_LOCATION/etc/globus-user-env.sh +(for sh shells) or +.Cm $GLOBUS_LOCATION/etc/globus-user.env.csh +(for csh shells). .It Ev LOGNAME Synonym for .Ev USER ; @@ -1295,6 +1325,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 -Naur --exclude=autom4te.cache openssh-6.6p1/ssh.c openssh-6.6p1-gssapi/ssh.c --- openssh-6.6p1/ssh.c 2014-02-26 17:17:13.000000000 -0600 +++ openssh-6.6p1-gssapi/ssh.c 2014-03-18 15:05:44.000000000 -0500 @@ -393,6 +393,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, &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, &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, &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)) @@ -773,6 +799,10 @@ break; case 'T': options.request_tty = REQUEST_TTY_NO; + /* ensure that the user doesn't try to backdoor a */ + /* null cipher switch on an interactive session */ + /* so explicitly disable it no matter what */ + options.none_switch=0; break; case 'o': line = xstrdup(optarg); @@ -973,8 +1003,11 @@ seed_rng(); - 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)); @@ -1611,6 +1644,9 @@ { Channel *c; int window, packetmax, in, out, err; + int sock; + int socksize; + int socksizelen = sizeof(int); if (stdin_null_flag) { in = open(_PATH_DEVNULL, O_RDONLY); @@ -1631,9 +1667,74 @@ if (!isatty(err)) set_nonblock(err); - window = CHAN_SES_WINDOW_DEFAULT; + /* we need to check to see if what they want to do about buffer */ + /* sizes here. In a hpn to nonhpn connection we want to limit */ + /* the window size to something reasonable in case the far side */ + /* has the large window bug. In hpn to hpn connection we want to */ + /* use the max window size but allow the user to override it */ + /* lastly if they disabled hpn then use the ssh std window size */ + + /* so why don't we just do a getsockopt() here and set the */ + /* ssh window to that? In the case of a autotuning receive */ + /* window the window would get stuck at the initial buffer */ + /* size generally less than 96k. Therefore we need to set the */ + /* maximum ssh window size to the maximum hpn buffer size */ + /* unless the user has specifically set the tcprcvbufpoll */ + /* to no. In which case we *can* just set the window to the */ + /* minimum of the hpn buffer size and tcp receive buffer size */ + + if (tty_flag) + options.hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; + else + options.hpn_buffer_size = 2*1024*1024; + + if (datafellows & SSH_BUG_LARGEWINDOW) + { + debug("HPN to Non-HPN Connection"); + } + else + { + if (options.tcp_rcv_buf_poll <= 0) + { + sock = socket(AF_INET, SOCK_STREAM, 0); + getsockopt(sock, SOL_SOCKET, SO_RCVBUF, + &socksize, &socksizelen); + close(sock); + debug("socksize %d", socksize); + options.hpn_buffer_size = socksize; + debug ("HPNBufferSize set to TCP RWIN: %d", options.hpn_buffer_size); + } + else + { + if (options.tcp_rcv_buf > 0) + { + /*create a socket but don't connect it */ + /* we use that the get the rcv socket size */ + sock = socket(AF_INET, SOCK_STREAM, 0); + /* if they are using the tcp_rcv_buf option */ + /* attempt to set the buffer size to that */ + if (options.tcp_rcv_buf) + setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&options.tcp_rcv_buf, + sizeof(options.tcp_rcv_buf)); + getsockopt(sock, SOL_SOCKET, SO_RCVBUF, + &socksize, &socksizelen); + close(sock); + debug("socksize %d", socksize); + options.hpn_buffer_size = socksize; + debug ("HPNBufferSize set to user TCPRcvBuf: %d", options.hpn_buffer_size); + } + } + } + + debug("Final hpn_buffer_size = %d", options.hpn_buffer_size); + + window = options.hpn_buffer_size; + + channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); + packetmax = CHAN_SES_PACKET_DEFAULT; if (tty_flag) { + window = 4*CHAN_SES_PACKET_DEFAULT; window >>= 1; packetmax >>= 1; } @@ -1642,6 +1743,10 @@ window, packetmax, CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); + if ((options.tcp_rcv_buf_poll > 0) && (!options.hpn_disabled)) { + c->dynamic_window = 1; + debug ("Enabled Dynamic Window Scaling"); + } debug3("ssh_session2_open: channel_new: %d", c->self); channel_send_open(c->self); diff -Naur --exclude=autom4te.cache openssh-6.6p1/ssh_config openssh-6.6p1-gssapi/ssh_config --- openssh-6.6p1/ssh_config 2013-10-09 18:24:12.000000000 -0500 +++ openssh-6.6p1-gssapi/ssh_config 2014-03-18 15:05:44.000000000 -0500 @@ -24,8 +24,10 @@ # RSAAuthentication yes # PasswordAuthentication yes # HostbasedAuthentication no -# GSSAPIAuthentication no -# GSSAPIDelegateCredentials no +# GSSAPIAuthentication yes +# GSSAPIDelegateCredentials yes +# GSSAPIKeyExchange yes +# GSSAPITrustDNS yes # BatchMode no # CheckHostIP yes # AddressFamily any diff -Naur --exclude=autom4te.cache openssh-6.6p1/ssh_config.5 openssh-6.6p1-gssapi/ssh_config.5 --- openssh-6.6p1/ssh_config.5 2014-02-23 22:57:56.000000000 -0600 +++ openssh-6.6p1-gssapi/ssh_config.5 2014-03-18 15:05:44.000000000 -0500 @@ -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 @@ -680,13 +686,45 @@ .It Cm GSSAPIAuthentication Specifies whether user authentication based on GSSAPI is allowed. The default is -.Dq no . +.Dq yes . +Note that this option applies to protocol version 2 only. +.It Cm GSSAPIKeyExchange +Specifies whether key exchange based on GSSAPI may be used. When using +GSSAPI key exchange the server need not have a host key. +The default is +.Dq yes . Note that this option applies to protocol version 2 only. +.It Cm GSSAPIClientIdentity +If set, specifies the GSSAPI client identity that ssh should use when +connecting to the server. The default is unset, which means that the default +identity will be used. +.It Cm GSSAPIServerIdentity +If set, specifies the GSSAPI server identity that ssh should expect when +connecting to the server. The default is unset, which means that the +expected GSSAPI server identity will be determined from the target +hostname. .It Cm GSSAPIDelegateCredentials Forward (delegate) credentials to the server. The default is -.Dq no . -Note that this option applies to protocol version 2 only. +.Dq yes . +Note that this option applies to protocol version 2 connections using GSSAPI. +.It Cm GSSAPIRenewalForcesRekey +If set to +.Dq yes +then renewal of the client's GSSAPI credentials will force the rekeying of the +ssh connection. With a compatible server, this can delegate the renewed +credentials to a session on the server. +The default is +.Dq yes . +.It Cm GSSAPITrustDns +Set to +.Dq yes to indicate that the DNS is trusted to securely canonicalize +the name of the host being connected to. If +.Dq no, the hostname entered on the +command line will be passed untouched to the GSSAPI library. +The default is +.Dq yes . +This option only applies to protocol version 2 connections using GSSAPI. .It Cm HashKnownHosts Indicates that .Xr ssh 1 @@ -1036,7 +1074,7 @@ .Cm password ) . The default is: .Bd -literal -offset indent -gssapi-with-mic,hostbased,publickey, +gssapi-keyex,gssapi-with-mic,hostbased,publickey, keyboard-interactive,password .Ed .It Cm Protocol diff -Naur --exclude=autom4te.cache openssh-6.6p1/sshconnect.c openssh-6.6p1-gssapi/sshconnect.c --- openssh-6.6p1/sshconnect.c 2014-02-06 16:24:34.000000000 -0600 +++ openssh-6.6p1-gssapi/sshconnect.c 2014-03-18 15:05:44.000000000 -0500 @@ -263,6 +263,31 @@ } /* + * Set TCP receive buffer if requested. + * Note: tuning needs to happen after the socket is + * created but before the connection happens + * so winscale is negotiated properly -cjr + */ +static void +ssh_set_socket_recvbuf(int sock) +{ + void *buf = (void *)&options.tcp_rcv_buf; + int sz = sizeof(options.tcp_rcv_buf); + int socksize; + int socksizelen = sizeof(int); + + debug("setsockopt Attempting to set SO_RCVBUF to %d", options.tcp_rcv_buf); + if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, buf, sz) >= 0) { + getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &socksize, &socksizelen); + debug("setsockopt SO_RCVBUF: %.100s %d", strerror(errno), socksize); + } + else + error("Couldn't set socket receive buffer to %d: %.100s", + options.tcp_rcv_buf, strerror(errno)); +} + + +/* * Creates a (possibly privileged) socket for use as the ssh connection. */ static int @@ -278,6 +303,9 @@ } fcntl(sock, F_SETFD, FD_CLOEXEC); + if (options.tcp_rcv_buf > 0) + ssh_set_socket_recvbuf(sock); + /* Bind the socket to an alternative local IP address */ if (options.bind_address == NULL && !privileged) return sock; @@ -520,10 +548,10 @@ /* Send our own protocol version identification. */ if (compat20) { xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n", - PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION); + PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE); } else { xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n", - PROTOCOL_MAJOR_1, minor1, SSH_VERSION); + PROTOCOL_MAJOR_1, minor1, SSH_RELEASE); } if (roaming_atomicio(vwrite, connection_out, client_version_string, strlen(client_version_string)) != strlen(client_version_string)) diff -Naur --exclude=autom4te.cache openssh-6.6p1/sshconnect2.c openssh-6.6p1-gssapi/sshconnect2.c --- openssh-6.6p1/sshconnect2.c 2014-02-03 18:20:16.000000000 -0600 +++ openssh-6.6p1-gssapi/sshconnect2.c 2014-03-18 15:05:44.000000000 -0500 @@ -79,6 +79,12 @@ extern char *client_version_string; extern char *server_version_string; extern Options options; +extern Kex *xxx_kex; + +/* tty_flag is set in ssh.c. use this in ssh_userauth2 */ +/* if it is set then prevent the switch to the null cipher */ + +extern int tty_flag; /* * SSH2 key exchange @@ -158,9 +164,34 @@ { Kex *kex; +#ifdef GSSAPI + char *orig = NULL, *gss = NULL; + char *gss_host = NULL; +#endif + xxx_host = host; xxx_hostaddr = hostaddr; +#ifdef GSSAPI + if (options.gss_keyex) { + /* Add the GSSAPI mechanisms currently supported on this + * client to the key exchange algorithm proposal */ + orig = myproposal[PROPOSAL_KEX_ALGS]; + + if (options.gss_trust_dns) + gss_host = (char *)get_canonical_hostname(1); + else + gss_host = host; + + gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); + if (gss) { + debug("Offering GSSAPI proposal: %s", gss); + xasprintf(&myproposal[PROPOSAL_KEX_ALGS], + "%s,%s", gss, orig); + } + } +#endif + if (options.ciphers == (char *)-1) { logit("No valid ciphers for protocol version 2 given, using defaults."); options.ciphers = NULL; @@ -196,6 +227,17 @@ if (options.kex_algorithms != NULL) myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; +#ifdef GSSAPI + /* If we've got GSSAPI algorithms, then we also support the + * 'null' hostkey, as a last resort */ + if (options.gss_keyex && gss) { + orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; + xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], + "%s,null", orig); + free(gss); + } +#endif + if (options.rekey_limit || options.rekey_interval) packet_set_rekey_limits((u_int32_t)options.rekey_limit, (time_t)options.rekey_interval); @@ -207,11 +249,31 @@ kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; kex->kex[KEX_ECDH_SHA2] = kexecdh_client; +#ifdef GSSAPI + if (options.gss_keyex) { + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; + kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; + } +#endif kex->kex[KEX_C25519_SHA256] = kexc25519_client; kex->client_version_string=client_version_string; kex->server_version_string=server_version_string; kex->verify_host_key=&verify_host_key_callback; +#ifdef GSSAPI + if (options.gss_keyex) { + kex->gss_deleg_creds = options.gss_deleg_creds; + kex->gss_trust_dns = options.gss_trust_dns; + kex->gss_client = options.gss_client_identity; + if (options.gss_server_identity) { + kex->gss_host = options.gss_server_identity; + } else { + kex->gss_host = gss_host; + } + } +#endif + xxx_kex = kex; dispatch_run(DISPATCH_BLOCK, &kex->done, kex); @@ -301,6 +363,7 @@ void input_gssapi_hash(int type, u_int32_t, void *); void input_gssapi_error(int, u_int32_t, void *); void input_gssapi_errtok(int, u_int32_t, void *); +int userauth_gsskeyex(Authctxt *authctxt); #endif void userauth(Authctxt *, char *); @@ -316,6 +379,11 @@ Authmethod authmethods[] = { #ifdef GSSAPI + {"gssapi-keyex", + userauth_gsskeyex, + NULL, + &options.gss_authentication, + NULL}, {"gssapi-with-mic", userauth_gssapi, NULL, @@ -409,6 +477,29 @@ pubkey_cleanup(&authctxt); dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); + /* if the user wants to use the none cipher do it */ + /* post authentication and only if the right conditions are met */ + /* both of the NONE commands must be true and there must be no */ + /* tty allocated */ + if ((options.none_switch == 1) && (options.none_enabled == 1)) + { + if (!tty_flag) /* no null on tty sessions */ + { + debug("Requesting none rekeying..."); + myproposal[PROPOSAL_ENC_ALGS_STOC] = "none"; + myproposal[PROPOSAL_ENC_ALGS_CTOS] = "none"; + kex_prop2buf(&xxx_kex->my,myproposal); + packet_request_rekeying(); + fprintf(stderr, "WARNING: ENABLED NONE CIPHER\n"); + } + else + { + /* requested NONE cipher when in a tty */ + debug("Cannot switch to NONE cipher with tty allocated"); + fprintf(stderr, "NONE cipher switch disabled when a TTY is allocated\n"); + } + } + debug("Authentication succeeded (%s).", authctxt.method->name); } @@ -612,19 +703,36 @@ static u_int mech = 0; OM_uint32 min; int ok = 0; + char *gss_host = NULL; + + if (!options.gss_authentication) { + verbose("GSSAPI authentication disabled."); + return 0; + } + + if (options.gss_server_identity) + gss_host = (char *)options.gss_server_identity; + else if (options.gss_trust_dns) + gss_host = (char *)get_canonical_hostname(1); + else + gss_host = (char *)authctxt->host; /* Try one GSSAPI method at a time, rather than sending them all at * once. */ if (gss_supported == NULL) - gss_indicate_mechs(&min, &gss_supported); + if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { + gss_supported = NULL; + return 0; + } /* Check to see if the mechanism is usable before we offer it */ while (mech < gss_supported->count && !ok) { /* My DER encoding requires length<128 */ if (gss_supported->elements[mech].length < 128 && ssh_gssapi_check_mechanism(&gssctxt, - &gss_supported->elements[mech], authctxt->host)) { + &gss_supported->elements[mech], gss_host, + options.gss_client_identity)) { ok = 1; /* Mechanism works */ } else { mech++; @@ -688,7 +796,8 @@ if (status == GSS_S_COMPLETE) { /* send either complete or MIC, depending on mechanism */ - if (!(flags & GSS_C_INTEG_FLAG)) { + if (strcmp(authctxt->method->name,"gssapi")==0 || + (!(flags & GSS_C_INTEG_FLAG))) { packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); packet_send(); } else { @@ -721,8 +830,8 @@ { Authctxt *authctxt = ctxt; Gssctxt *gssctxt; - int oidlen; - char *oidv; + u_int oidlen; + u_char *oidv; if (authctxt == NULL) fatal("input_gssapi_response: no authentication context"); @@ -831,6 +940,73 @@ free(msg); free(lang); } + +#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) +{ + Buffer b; + gss_buffer_desc gssbuf; + gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; + OM_uint32 ms; + + static int attempt = 0; + if (attempt++ >= 1) + return (0); + + if (gss_kex_context == NULL) { + debug("No valid Key exchange context"); + 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); + + if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { + buffer_free(&b); + return (0); + } + + 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); + packet_send(); + + buffer_free(&b); + gss_release_buffer(&ms, &mic); + + return (1); +} + #endif /* GSSAPI */ int diff -Naur --exclude=autom4te.cache openssh-6.6p1/sshd.8 openssh-6.6p1-gssapi/sshd.8 --- openssh-6.6p1/sshd.8 2013-12-18 00:46:28.000000000 -0600 +++ openssh-6.6p1-gssapi/sshd.8 2014-03-18 15:05:44.000000000 -0500 @@ -765,6 +765,73 @@ # 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 GSSAPI_MECH_CONF +Applies to mechglue used to support both GSI and Kerberos GSSAPI mechanisms. +Used to specify the location of the mech.conf file that lists the mechanism- +specific GSSAPI libraries (both Kerberos and GSI versions). If +.Ev GSSAPI_MECH_CONF +is not set then /etc/mech.conf is used. This applies to both the clients and +the server. The NCSA GSSAPI mechglue distribution includes a sample mech.conf +file. You will need to edit the library paths in that file and install it in +an appropriate location on your system. If the mech.conf file is not found, +the GSSAPI mechglue library will not load any GSSAPI mechanisms and GSI-OpenSSH +will simply skip GSSAPI authentication. +.It LD_LIBRARY_PATH +The sshd server is typically linked dynamically with Globus +security libraries, which must be present in the dynamic linker's +search path. This typically requires +.Cm $GLOBUS_LOCATION/lib +to be included in the list in the +.Ev LD_LIBRARY_PATH +environment variable, which is set by the +.Cm $GLOBUS_LOCATION/libexec/globus-script-initializer +script, which should be called from any +.Cm sshd +startup script. +Alternatively, to set +.Ev LD_LIBRARY_PATH +appropriately for the Globus libraries in an interactive shell, source +.Cm $GLOBUS_LOCATION/etc/globus-user-env.sh +(for sh shells) or +.Cm $GLOBUS_LOCATION/etc/globus-user.env.csh +(for csh shells). +.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. .Sh FILES .Bl -tag -width Ds -compact .It Pa ~/.hushlogin diff -Naur --exclude=autom4te.cache openssh-6.6p1/sshd.c openssh-6.6p1-gssapi/sshd.c --- openssh-6.6p1/sshd.c 2014-02-26 17:20:08.000000000 -0600 +++ openssh-6.6p1-gssapi/sshd.c 2014-03-18 15:05:44.000000000 -0500 @@ -121,6 +121,11 @@ #include "roaming.h" #include "ssh-sandbox.h" #include "version.h" +#include "ssh-globus-usage.h" + +#ifdef USE_SECURITY_SESSION_API +#include +#endif #ifdef LIBWRAP #include @@ -139,6 +144,14 @@ #define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3) #define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4) +#ifdef NERSC_MOD +#include "nersc.h" +extern char n_ntop[NI_MAXHOST]; +extern char n_port[NI_MAXHOST]; +extern int client_session_id; +extern char interface_list[256]; +#endif + extern char *__progname; /* Server configuration options. */ @@ -314,6 +327,20 @@ static void sighup_restart(void) { + +#ifdef NERSC_MOD + + struct addrinfo *ai; + char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + + ai = options.listen_addrs; + + if ( getnameinfo(ai->ai_addr, ai->ai_addrlen,ntop, sizeof(ntop), strport, + sizeof(strport),NI_NUMERICHOST|NI_NUMERICSERV) == 0) { + s_audit("sshd_restart_3", "addr=%s port=%s/tcp", ntop, strport); + } +#endif + logit("Received SIGHUP; restarting."); platform_pre_restart(); close_listen_socks(); @@ -436,7 +463,7 @@ } xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s", - major, minor, SSH_VERSION, + major, minor, SSH_RELEASE, *options.version_addendum == '\0' ? "" : " ", options.version_addendum, newline); @@ -489,6 +516,9 @@ } debug("Client protocol version %d.%d; client software version %.100s", remote_major, remote_minor, remote_version); + logit("SSH: Server;Ltype: Version;Remote: %s-%d;Protocol: %d.%d;Client: %.100s", + get_remote_ipaddr(), get_remote_port(), + remote_major, remote_minor, remote_version); compat_datafellows(remote_version); @@ -1082,6 +1112,8 @@ int ret, listen_sock, on = 1; struct addrinfo *ai; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + int socksize; + int socksizelen = sizeof(int); for (ai = options.listen_addrs; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) @@ -1122,6 +1154,11 @@ debug("Bind to port %s on %s.", strport, ntop); + getsockopt(listen_sock, SOL_SOCKET, SO_RCVBUF, + &socksize, &socksizelen); + debug("Server TCP RWIN socket size: %d", socksize); + debug("HPN Buffer Size: %d", options.hpn_buffer_size); + /* Bind the socket to the desired port. */ if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { error("Bind to port %s on %s failed: %.200s.", @@ -1137,6 +1174,15 @@ fatal("listen on [%s]:%s: %.100s", ntop, strport, strerror(errno)); logit("Server listening on %s port %s.", ntop, strport); + +#ifdef NERSC_MOD + /* set using (pid,address,port) */ + set_server_id(getpid(),ntop,(int)options.ports[0]); + + s_audit("sshd_start_3", "addr=%s port=%s/tcp", ntop, strport); + client_session_id=0; + set_interface_list(); +#endif } freeaddrinfo(options.listen_addrs); @@ -1151,6 +1197,16 @@ static void server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) { + +#ifdef NERSC_MOD + struct addrinfo *ai; + char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + + ai = options.listen_addrs; + struct timeval l_tv; + l_tv.tv_sec = 60; + l_tv.tv_usec = 0; +#endif fd_set *fdset; int i, j, ret, maxfd; int key_used = 0, startups = 0; @@ -1190,7 +1246,27 @@ FD_SET(startup_pipes[i], fdset); /* Wait in select until there is a connection. */ + +#ifndef NERSC_MOD ret = select(maxfd+1, fdset, NULL, NULL, NULL); +#endif + +#ifdef NERSC_MOD + + /* If a connection happens, we break from the loop with some ammount of + * data flagged in the return bits of select. On error we see ret < 0. + * + * This needs to be tested wqith great enthusiasm since there might be corner + * cases of ret == 0 that I am not aware of + */ + l_tv.tv_sec = 60; + l_tv.tv_usec = 0; + + s_audit("sshd_server_heartbeat_3", "count=%i", ret); + + ret = select(maxfd+1, fdset, NULL, NULL, &l_tv); +#endif + if (ret < 0 && errno != EINTR) error("select: %.100s", strerror(errno)); if (received_sigterm) { @@ -1198,6 +1274,13 @@ (int) received_sigterm); close_listen_socks(); unlink(options.pid_file); + +#ifdef NERSC_MOD + if ( getnameinfo(ai->ai_addr, ai->ai_addrlen,ntop, sizeof(ntop), strport, + sizeof(strport),NI_NUMERICHOST|NI_NUMERICSERV) == 0) { + s_audit("sshd_exit_3", "addr=%s port=%s/tcp", ntop, strport); + } +#endif exit(received_sigterm == SIGTERM ? 0 : 255); } if (key_used && key_do_regen) { @@ -1614,6 +1697,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; @@ -1654,6 +1744,13 @@ exit(1); } +#ifdef NERSC_MOD + /* here we are setting the values for the server id which lives in nersc.c */ + getnameinfo(options.listen_addrs->ai_addr, options.listen_addrs->ai_addrlen, + n_ntop, sizeof(n_ntop), n_port,sizeof(n_port), + NI_NUMERICHOST|NI_NUMERICSERV); +#endif + debug("sshd version %s, %s", SSH_VERSION, SSLeay_version(SSLEAY_VERSION)); @@ -1728,10 +1825,13 @@ logit("Disabling protocol version 1. Could not load host key"); options.protocol &= ~SSH_PROTO_1; } +#ifndef GSSAPI + /* The GSSAPI key exchange can run without a host key */ if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { logit("Disabling protocol version 2. Could not load host key"); options.protocol &= ~SSH_PROTO_2; } +#endif if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { logit("sshd: no hostkeys available -- exiting."); exit(1); @@ -2031,6 +2131,23 @@ */ remote_ip = get_remote_ipaddr(); +#ifdef NERSC_MOD + + /* here we were setting client_session_id to the current pid + * but will now use a positive random number + * to use as a tracking id for the remainder of the + * session. c_s_i is defined in nersc.c + */ + client_session_id = abs(arc4random() ); + + char* t1buf = encode_string(interface_list, strlen(interface_list)); + + s_audit("sshd_connection_start_3", "count=%i uristring=%s addr=%s port=%i/tcp addr=%s port=%s/tcp count=%ld", + client_session_id, interface_list, remote_ip, remote_port, n_ntop, n_port); + + free(t1buf); +#endif + #ifdef SSH_AUDIT_EVENTS audit_connection_from(remote_ip, remote_port); #endif @@ -2058,6 +2175,63 @@ remote_ip, remote_port, get_local_ipaddr(sock_in), get_local_port()); +#ifdef USE_SECURITY_SESSION_API + /* + * Create a new security session for use by the new user login if + * the current session is the root session or we are not launched + * by inetd (eg: debugging mode or server mode). We do not + * necessarily need to create a session if we are launched from + * inetd because Panther xinetd will create a session for us. + * + * The only case where this logic will fail is if there is an + * inetd running in a non-root session which is not creating + * new sessions for us. Then all the users will end up in the + * same session (bad). + * + * When the client exits, the session will be destroyed for us + * automatically. + * + * We must create the session before any credentials are stored + * (including AFS pags, which happens a few lines below). + */ + { + OSStatus err = 0; + SecuritySessionId sid = 0; + SessionAttributeBits sattrs = 0; + + err = SessionGetInfo(callerSecuritySession, &sid, &sattrs); + if (err) + error("SessionGetInfo() failed with error %.8X", + (unsigned) err); + else + debug("Current Session ID is %.8X / Session Attributes are %.8X", + (unsigned) sid, (unsigned) sattrs); + + if (inetd_flag && !(sattrs & sessionIsRoot)) + debug("Running in inetd mode in a non-root session... " + "assuming inetd created the session for us."); + else { + debug("Creating new security session..."); + err = SessionCreate(0, sessionHasTTY | sessionIsRemote); + if (err) + error("SessionCreate() failed with error %.8X", + (unsigned) err); + + err = SessionGetInfo(callerSecuritySession, &sid, + &sattrs); + if (err) + error("SessionGetInfo() failed with error %.8X", + (unsigned) err); + else + debug("New Session ID is %.8X / Session Attributes are %.8X", + (unsigned) sid, (unsigned) sattrs); + } + } +#endif + + /* set the HPN options for the child */ + channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); + /* * We don't want to listen forever unless the other side * successfully authenticates itself. So we set up an alarm which is @@ -2071,6 +2245,13 @@ alarm(options.login_grace_time); sshd_exchange_identification(sock_in, sock_out); +#if defined(AFS_KRB5) + /* If machine has AFS, set process authentication group. */ + if (k_hasafs()) { + k_setpag(); + k_unlog(); + } +#endif /* AFS || AFS_KRB5 */ /* In inetd mode, generate ephemeral key only for proto 1 connections */ if (!compat20 && inetd_flag && sensitive_data.server_key == NULL) @@ -2132,7 +2313,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(); @@ -2160,8 +2341,13 @@ options.client_alive_count_max); /* Start session. */ + do_authenticated(authctxt); +#ifdef NERSC_MOD + s_audit("sshd_connection_end_3", "count=%i addr=%s port=%i/tcp addr=%s port=%s/tcp", + client_session_id, remote_ip, remote_port, n_ntop, n_port); +#endif /* The connection has been terminated. */ packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes); packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes); @@ -2442,6 +2628,10 @@ if (options.ciphers != NULL) { myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; + } else if (options.none_enabled == 1) { + debug ("WARNING: None cipher enabled"); + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_ENCRYPT_INCLUDE_NONE; } myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); @@ -2469,6 +2659,48 @@ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( list_hostkey_types()); +#ifdef GSSAPI + { + char *orig; + char *gss = NULL; + char *newstr = NULL; + orig = myproposal[PROPOSAL_KEX_ALGS]; + + /* + * If we don't have a host key, then there's no point advertising + * the other key exchange algorithms + */ + + if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) + orig = NULL; + + if (options.gss_keyex) + gss = ssh_gssapi_server_mechanisms(); + else + gss = NULL; + + if (gss && orig) + xasprintf(&newstr, "%s,%s", gss, orig); + else if (gss) + newstr = gss; + else if (orig) + newstr = orig; + + /* + * If we've got GSSAPI mechanisms, then we've got the 'null' host + * key alg, but we can't tell people about it unless its the only + * host key algorithm we support + */ + if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null"; + + if (newstr) + myproposal[PROPOSAL_KEX_ALGS] = newstr; + else + fatal("No supported key exchange algorithms"); + } +#endif + /* start key exchange */ kex = kex_setup(myproposal); kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; @@ -2476,6 +2708,13 @@ kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; kex->kex[KEX_ECDH_SHA2] = kexecdh_server; +#ifdef GSSAPI + if (options.gss_keyex) { + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; + kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; + } +#endif kex->kex[KEX_C25519_SHA256] = kexc25519_server; kex->server = 1; kex->client_version_string=client_version_string; diff -Naur --exclude=autom4te.cache openssh-6.6p1/sshd_config openssh-6.6p1-gssapi/sshd_config --- openssh-6.6p1/sshd_config 2014-01-12 02:20:47.000000000 -0600 +++ openssh-6.6p1-gssapi/sshd_config 2014-03-18 15:05:44.000000000 -0500 @@ -81,9 +81,17 @@ #KerberosTicketCleanup yes #KerberosGetAFSToken no +# Session hooks: if allowed, specify the commands to execute +#AllowSessionHooks no +#SessionHookStartupCmd /bin/true +#SessionHookShutdownCmd /bin/true + # GSSAPI options -#GSSAPIAuthentication no +#GSSAPIAuthentication yes +#GSSAPIDelegateCredentials yes #GSSAPICleanupCredentials yes +#GSSAPIStrictAcceptorCheck yes +#GSSAPIKeyExchange yes # Set this to 'yes' to enable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will @@ -96,6 +104,10 @@ # and ChallengeResponseAuthentication to 'no'. #UsePAM no +# 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 @@ -125,9 +137,27 @@ # override default of no subsystems Subsystem sftp /usr/libexec/sftp-server +# the following are HPN related configuration options +# tcp receive buffer polling. disable in non autotuning kernels +#TcpRcvBufPoll yes + +# disable hpn performance boosts +#HPNDisabled no + +# buffer size for hpn to non-hpn connections +#HPNBufferSize 2048 + +# allow the use of the none cipher +#NoneEnabled no + # Example of overriding settings on a per-user basis #Match User anoncvs # X11Forwarding no # AllowTcpForwarding no # PermitTTY no # ForceCommand cvs server + + +# Usage Metrics +#UsageStatsTargets usage-stats.cilogon.org:4810 +#DisableUsageStats No diff -Naur --exclude=autom4te.cache openssh-6.6p1/sshd_config.5 openssh-6.6p1-gssapi/sshd_config.5 --- openssh-6.6p1/sshd_config.5 2014-02-27 17:01:28.000000000 -0600 +++ openssh-6.6p1-gssapi/sshd_config.5 2014-03-18 15:05:44.000000000 -0500 @@ -449,6 +449,16 @@ 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, which is the +default. 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 ForceCommand Forces the execution of the command specified by .Cm ForceCommand , @@ -491,7 +501,17 @@ .It Cm GSSAPIAuthentication Specifies whether user authentication based on GSSAPI is allowed. The default is -.Dq no . +.Dq yes . +Note that this option applies to protocol version 2 only. +.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. +The default is +.Dq yes . Note that this option applies to protocol version 2 only. .It Cm GSSAPICleanupCredentials Specifies whether to automatically destroy the user's credentials cache @@ -499,6 +519,44 @@ The default is .Dq yes . Note that this option applies to protocol version 2 only. +.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. If +.Dq yes +then the client must authenticate against the +.Pa host +service on the current hostname. If +.Dq no +then the client may authenticate against any service key stored in the +machine's default store. This facility is provided to assist with operation +on multi homed machines. +The default is +.Dq yes . +Note that this option applies only to protocol version 2 GSSAPI connections, +and setting it to +.Dq no +may only work with recent Kerberos GSSAPI libraries. +.It Cm GSSAPIStoreCredentialsOnRekey +Controls whether the user's GSSAPI credentials should be updated following a +successful connection rekeying. This option can be used to accepted renewed +or updated credentials from a compatible client. The default is +.Dq no . .It Cm HostbasedAuthentication Specifies whether rhosts or /etc/hosts.equiv authentication together with successful public key client host authentication is allowed @@ -1155,6 +1213,121 @@ .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 +By default, Usage Metrics reporting is sent to +.Dq usage-stats.cilogon.org:4810 . +This can be made explicit by specifying +.Dq default +(all by itself) for the +target specification as in: +.Pp +.Bl -item -offset indent -compact +.It +.Cm UsageStatsTargets +.Sm off +default +.Sm on +.El +.Pp +If +.Cm UsageStatsTargets +is not specified, a comma-separated list of targets +(without any tags specified) if specified in the environment variable +.Cm GLOBUS_USAGE_TARGETS +will be used. +.Pp .It Cm TrustedUserCAKeys Specifies a file containing public keys of certificate authorities that are trusted to sign user certificates for authentication. @@ -1220,6 +1393,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 -Naur --exclude=autom4te.cache openssh-6.6p1/version.h openssh-6.6p1-gssapi/version.h --- openssh-6.6p1/version.h 2014-02-27 17:01:54.000000000 -0600 +++ openssh-6.6p1-gssapi/version.h 2014-03-18 15:05:44.000000000 -0500 @@ -1,6 +1,35 @@ /* $OpenBSD: version.h,v 1.70 2014/02/27 22:57:40 djm Exp $ */ +#ifdef GSI +#define GSI_VERSION " GSI" +#else +#define GSI_VERSION "" +#endif + +#ifdef KRB5 +#define KRB5_VERSION " KRB5" +#else +#define KRB5_VERSION "" +#endif + +#ifdef MECHGLUE +#define MGLUE_VERSION " MECHGLUE" +#else +#define MGLUE_VERSION "" +#endif + +#define NCSA_VERSION " GSI_GSSAPI_20140318" + #define SSH_VERSION "OpenSSH_6.6" +#ifdef NERSC_MOD +#define SSH_AUDITING "NMOD_3.12" +#else +#define SSH_AUDITING "" +#endif /* NERSC_MOD */ + #define SSH_PORTABLE "p1" -#define SSH_RELEASE SSH_VERSION SSH_PORTABLE +#define SSH_HPN "-hpn14" + +#define SSH_RELEASE SSH_VERSION SSH_PORTABLE SSH_AUDITING SSH_HPN \ + NCSA_VERSION GSI_VERSION KRB5_VERSION MGLUE_VERSION