diff --git a/openssh-3.8.1p1-krb5-config.patch b/openssh-3.8.1p1-krb5-config.patch deleted file mode 100644 index f284632..0000000 --- a/openssh-3.8.1p1-krb5-config.patch +++ /dev/null @@ -1,16 +0,0 @@ -Search the path for krb5-config if the prefix wasn't specified. ---- openssh-3.8p1/configure.ac 2004-02-26 21:17:12.000000000 -0500 -+++ openssh-3.8p1/configure.ac 2004-02-26 21:17:06.000000000 -0500 -@@ -2077,8 +2077,10 @@ - KRB5_MSG="yes" - - AC_MSG_CHECKING(for krb5-config) -- if test -x $KRB5ROOT/bin/krb5-config ; then -- KRB5CONF=$KRB5ROOT/bin/krb5-config -+ AC_PATH_PROG([KRB5CONF],[krb5-config], -+ [$KRB5ROOT/bin/krb5-config], -+ [$KRB5ROOT/bin:$PATH]) -+ if test -x $KRB5CONF ; then - AC_MSG_RESULT($KRB5CONF) - - AC_MSG_CHECKING(for gssapi support) diff --git a/openssh-5.1p1-skip-initial.patch b/openssh-5.1p1-skip-initial.patch deleted file mode 100644 index be3204e..0000000 --- a/openssh-5.1p1-skip-initial.patch +++ /dev/null @@ -1,28 +0,0 @@ -Skip the initial empty-password check if permit_empty_passwd is disabled. This -doesn't change the timing profiles of the host because the additional condition -check which can short-circuit the call to pam_authenticate() has no dependency -on the identity of the user who is being authenticated. -diff -up openssh-5.1p1/auth1.c.skip-initial openssh-5.1p1/auth1.c ---- openssh-5.1p1/auth1.c.skip-initial 2008-07-09 12:54:05.000000000 +0200 -+++ openssh-5.1p1/auth1.c 2008-07-23 18:26:01.000000000 +0200 -@@ -244,7 +244,7 @@ do_authloop(Authctxt *authctxt) - authctxt->valid ? "" : "invalid user ", authctxt->user); - - /* If the user has no password, accept authentication immediately. */ -- if (options.password_authentication && -+ if (options.permit_empty_passwd && options.password_authentication && - #ifdef KRB5 - (!options.kerberos_authentication || options.kerberos_or_local_passwd) && - #endif -diff -up openssh-5.1p1/auth2-none.c.skip-initial openssh-5.1p1/auth2-none.c ---- openssh-5.1p1/auth2-none.c.skip-initial 2008-07-02 14:56:09.000000000 +0200 -+++ openssh-5.1p1/auth2-none.c 2008-07-23 18:26:01.000000000 +0200 -@@ -65,7 +65,7 @@ userauth_none(Authctxt *authctxt) - if (check_nt_auth(1, authctxt->pw) == 0) - return (0); - #endif -- if (options.password_authentication) -+ if (options.permit_empty_passwd && options.password_authentication) - return (PRIVSEP(auth_password(authctxt, ""))); - return (0); - } diff --git a/openssh-5.2p1-pathmax.patch b/openssh-5.2p1-pathmax.patch deleted file mode 100644 index 5411589..0000000 --- a/openssh-5.2p1-pathmax.patch +++ /dev/null @@ -1,47 +0,0 @@ -diff -up openssh-5.2p1/ssh.c.pathmax openssh-5.2p1/ssh.c ---- openssh-5.2p1/ssh.c.pathmax 2009-07-08 14:23:19.000000000 +0200 -+++ openssh-5.2p1/ssh.c 2009-07-08 14:26:26.000000000 +0200 -@@ -49,6 +49,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -208,8 +209,8 @@ void muxserver_listen(void); - int - main(int ac, char **av) - { -- int i, opt, exit_status, use_syslog; -- char *p, *cp, *line, buf[256]; -+ int i, r, opt, exit_status, use_syslog; -+ char *p, *cp, *line, buf[MAXPATHLEN]; - struct stat st; - struct passwd *pw; - int dummy, timeout_ms; -@@ -624,9 +625,10 @@ main(int ac, char **av) - fatal("Can't open user config file %.100s: " - "%.100s", config, strerror(errno)); - } else { -- snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, -+ r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, - _PATH_SSH_USER_CONFFILE); -- (void)read_config_file(buf, host, &options, 1); -+ if (r > 0 && (size_t)r < sizeof(buf)) -+ (void)read_config_file(buf, host, &options, 1); - - /* Read systemwide configuration file after use config. */ - (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, -@@ -787,9 +789,9 @@ main(int ac, char **av) - * Now that we are back to our own permissions, create ~/.ssh - * directory if it doesn't already exist. - */ -- snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, -+ r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir, - strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); -- if (stat(buf, &st) < 0) -+ if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) - if (mkdir(buf, 0700) < 0) - error("Could not create directory '%.200s'.", buf); - diff --git a/openssh-4.7p1-audit.patch b/openssh-5.3p1-audit.patch similarity index 74% rename from openssh-4.7p1-audit.patch rename to openssh-5.3p1-audit.patch index d561be0..7606e49 100644 --- a/openssh-4.7p1-audit.patch +++ b/openssh-5.3p1-audit.patch @@ -1,6 +1,6 @@ -diff -up openssh-5.2p1/auth.c.audit openssh-5.2p1/auth.c ---- openssh-5.2p1/auth.c.audit 2008-11-05 06:12:54.000000000 +0100 -+++ openssh-5.2p1/auth.c 2009-08-09 09:22:23.634850536 +0200 +diff -up openssh-5.3p1/auth.c.audit openssh-5.3p1/auth.c +--- openssh-5.3p1/auth.c.audit 2008-11-05 06:12:54.000000000 +0100 ++++ openssh-5.3p1/auth.c 2009-10-11 13:02:47.000000000 +0200 @@ -287,6 +287,12 @@ auth_log(Authctxt *authctxt, int authent get_canonical_hostname(options.use_dns), "ssh", &loginmsg); # endif @@ -25,19 +25,10 @@ diff -up openssh-5.2p1/auth.c.audit openssh-5.2p1/auth.c #ifdef SSH_AUDIT_EVENTS audit_event(SSH_INVALID_USER); #endif /* SSH_AUDIT_EVENTS */ -diff -up openssh-5.2p1/config.h.in.audit openssh-5.2p1/config.h.in ---- openssh-5.2p1/config.h.in.audit 2009-02-23 01:18:12.000000000 +0100 -+++ openssh-5.2p1/config.h.in 2009-08-09 09:22:28.825939998 +0200 -@@ -1,5 +1,8 @@ - /* config.h.in. Generated from configure.ac by autoheader. */ - -+/* Define if building universal (internal helper macro) */ -+#undef AC_APPLE_UNIVERSAL_BUILD -+ - /* Define if you have a getaddrinfo that fails for the all-zeros IPv6 address - */ - #undef AIX_GETNAMEINFO_HACK -@@ -521,6 +524,9 @@ +diff -up openssh-5.3p1/config.h.in.audit openssh-5.3p1/config.h.in +--- openssh-5.3p1/config.h.in.audit 2009-09-26 08:31:14.000000000 +0200 ++++ openssh-5.3p1/config.h.in 2009-10-11 13:09:41.000000000 +0200 +@@ -533,6 +533,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LASTLOG_H @@ -47,7 +38,7 @@ diff -up openssh-5.2p1/config.h.in.audit openssh-5.2p1/config.h.in /* Define to 1 if you have the `bsm' library (-lbsm). */ #undef HAVE_LIBBSM -@@ -560,6 +566,9 @@ +@@ -572,6 +575,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H @@ -57,7 +48,7 @@ diff -up openssh-5.2p1/config.h.in.audit openssh-5.2p1/config.h.in /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_IF_TUN_H -@@ -756,6 +765,9 @@ +@@ -768,6 +774,9 @@ /* Define to 1 if you have the `setgroups' function. */ #undef HAVE_SETGROUPS @@ -67,7 +58,7 @@ diff -up openssh-5.2p1/config.h.in.audit openssh-5.2p1/config.h.in /* Define to 1 if you have the `setlogin' function. */ #undef HAVE_SETLOGIN -@@ -1330,6 +1342,10 @@ +@@ -1348,6 +1357,10 @@ /* Prepend the address family to IP tunnel traffic */ #undef SSH_TUN_PREPEND_AF @@ -78,31 +69,10 @@ diff -up openssh-5.2p1/config.h.in.audit openssh-5.2p1/config.h.in /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS -@@ -1397,9 +1413,17 @@ - /* Define if you want SELinux support. */ - #undef WITH_SELINUX - --/* Define to 1 if your processor stores words with the most significant byte -- first (like Motorola and SPARC, unlike Intel and VAX). */ --#undef WORDS_BIGENDIAN -+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most -+ significant byte first (like Motorola and SPARC, unlike Intel). */ -+#if defined AC_APPLE_UNIVERSAL_BUILD -+# if defined __BIG_ENDIAN__ -+# define WORDS_BIGENDIAN 1 -+# endif -+#else -+# ifndef WORDS_BIGENDIAN -+# undef WORDS_BIGENDIAN -+# endif -+#endif - - /* Define if xauth is found in your path */ - #undef XAUTH_PATH -diff -up openssh-5.2p1/configure.ac.audit openssh-5.2p1/configure.ac ---- openssh-5.2p1/configure.ac.audit 2009-08-09 09:22:23.608877833 +0200 -+++ openssh-5.2p1/configure.ac 2009-08-09 09:22:23.646244409 +0200 -@@ -3342,6 +3342,18 @@ AC_ARG_WITH(selinux, +diff -up openssh-5.3p1/configure.ac.audit openssh-5.3p1/configure.ac +--- openssh-5.3p1/configure.ac.audit 2009-09-11 06:56:08.000000000 +0200 ++++ openssh-5.3p1/configure.ac 2009-10-11 13:08:03.000000000 +0200 +@@ -3407,6 +3407,18 @@ AC_ARG_WITH(selinux, fi ] ) @@ -121,7 +91,7 @@ diff -up openssh-5.2p1/configure.ac.audit openssh-5.2p1/configure.ac # Check whether user wants Kerberos 5 support KRB5_MSG="no" AC_ARG_WITH(kerberos5, -@@ -4170,6 +4182,7 @@ echo " PAM support +@@ -4226,6 +4238,7 @@ echo " PAM support echo " OSF SIA support: $SIA_MSG" echo " KerberosV support: $KRB5_MSG" echo " SELinux support: $SELINUX_MSG" @@ -129,9 +99,9 @@ diff -up openssh-5.2p1/configure.ac.audit openssh-5.2p1/configure.ac echo " Smartcard support: $SCARD_MSG" echo " S/KEY support: $SKEY_MSG" echo " TCP Wrappers support: $TCPW_MSG" -diff -up openssh-5.2p1/loginrec.c.audit openssh-5.2p1/loginrec.c ---- openssh-5.2p1/loginrec.c.audit 2009-02-12 03:12:22.000000000 +0100 -+++ openssh-5.2p1/loginrec.c 2009-08-09 09:22:23.667199702 +0200 +diff -up openssh-5.3p1/loginrec.c.audit openssh-5.3p1/loginrec.c +--- openssh-5.3p1/loginrec.c.audit 2009-02-12 03:12:22.000000000 +0100 ++++ openssh-5.3p1/loginrec.c 2009-10-11 13:06:16.000000000 +0200 @@ -176,6 +176,10 @@ #include "auth.h" #include "buffer.h" @@ -252,9 +222,9 @@ diff -up openssh-5.2p1/loginrec.c.audit openssh-5.2p1/loginrec.c /** ** Low-level libutil login() functions **/ -diff -up openssh-5.2p1/loginrec.h.audit openssh-5.2p1/loginrec.h ---- openssh-5.2p1/loginrec.h.audit 2006-08-05 04:39:40.000000000 +0200 -+++ openssh-5.2p1/loginrec.h 2009-08-09 09:22:23.641175349 +0200 +diff -up openssh-5.3p1/loginrec.h.audit openssh-5.3p1/loginrec.h +--- openssh-5.3p1/loginrec.h.audit 2006-08-05 04:39:40.000000000 +0200 ++++ openssh-5.3p1/loginrec.h 2009-10-11 13:04:28.000000000 +0200 @@ -127,5 +127,9 @@ char *line_stripname(char *dst, const ch char *line_abbrevname(char *dst, const char *src, int dstsize); diff --git a/openssh-5.2p1-fips.patch b/openssh-5.3p1-fips.patch similarity index 78% rename from openssh-5.2p1-fips.patch rename to openssh-5.3p1-fips.patch index 6e5b88c..01a715c 100644 --- a/openssh-5.2p1-fips.patch +++ b/openssh-5.3p1-fips.patch @@ -1,6 +1,6 @@ -diff -up openssh-5.2p1/auth2-pubkey.c.fips openssh-5.2p1/auth2-pubkey.c ---- openssh-5.2p1/auth2-pubkey.c.fips 2009-05-15 15:51:01.000000000 +0200 -+++ openssh-5.2p1/auth2-pubkey.c 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/auth2-pubkey.c.fips openssh-5.3p1/auth2-pubkey.c +--- openssh-5.3p1/auth2-pubkey.c.fips 2009-10-02 14:12:00.000000000 +0200 ++++ openssh-5.3p1/auth2-pubkey.c 2009-10-02 14:12:00.000000000 +0200 @@ -33,6 +33,7 @@ #include #include @@ -9,7 +9,7 @@ diff -up openssh-5.2p1/auth2-pubkey.c.fips openssh-5.2p1/auth2-pubkey.c #include "xmalloc.h" #include "ssh.h" -@@ -243,7 +244,7 @@ user_key_allowed2(struct passwd *pw, Key +@@ -240,7 +241,7 @@ user_key_allowed2(struct passwd *pw, Key found_key = 1; debug("matching key found: file %s, line %lu", file, linenum); @@ -18,9 +18,9 @@ diff -up openssh-5.2p1/auth2-pubkey.c.fips openssh-5.2p1/auth2-pubkey.c verbose("Found matching %s key: %s", key_type(found), fp); xfree(fp); -diff -up openssh-5.2p1/authfile.c.fips openssh-5.2p1/authfile.c ---- openssh-5.2p1/authfile.c.fips 2006-09-01 07:38:36.000000000 +0200 -+++ openssh-5.2p1/authfile.c 2009-05-15 16:08:34.000000000 +0200 +diff -up openssh-5.3p1/authfile.c.fips openssh-5.3p1/authfile.c +--- openssh-5.3p1/authfile.c.fips 2006-09-01 07:38:36.000000000 +0200 ++++ openssh-5.3p1/authfile.c 2009-10-02 14:12:00.000000000 +0200 @@ -143,8 +143,14 @@ key_save_private_rsa1(Key *key, const ch /* Allocate space for the private part of the key in the buffer. */ cp = buffer_append_space(&encrypted, buffer_len(&buffer)); @@ -55,9 +55,9 @@ diff -up openssh-5.2p1/authfile.c.fips openssh-5.2p1/authfile.c cipher_crypt(&ciphercontext, cp, buffer_ptr(&buffer), buffer_len(&buffer)); cipher_cleanup(&ciphercontext); -diff -up openssh-5.2p1/cipher.c.fips openssh-5.2p1/cipher.c ---- openssh-5.2p1/cipher.c.fips 2009-03-06 18:23:21.000000000 +0100 -+++ openssh-5.2p1/cipher.c 2009-05-15 16:14:16.000000000 +0200 +diff -up openssh-5.3p1/cipher.c.fips openssh-5.3p1/cipher.c +--- openssh-5.3p1/cipher.c.fips 2009-10-02 13:44:03.000000000 +0200 ++++ openssh-5.3p1/cipher.c 2009-10-02 14:12:00.000000000 +0200 @@ -40,6 +40,7 @@ #include @@ -142,9 +142,9 @@ diff -up openssh-5.2p1/cipher.c.fips openssh-5.2p1/cipher.c } /* -diff -up openssh-5.2p1/cipher-ctr.c.fips openssh-5.2p1/cipher-ctr.c ---- openssh-5.2p1/cipher-ctr.c.fips 2007-06-14 15:21:33.000000000 +0200 -+++ openssh-5.2p1/cipher-ctr.c 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/cipher-ctr.c.fips openssh-5.3p1/cipher-ctr.c +--- openssh-5.3p1/cipher-ctr.c.fips 2007-06-14 15:21:33.000000000 +0200 ++++ openssh-5.3p1/cipher-ctr.c 2009-10-02 14:12:00.000000000 +0200 @@ -140,7 +140,8 @@ evp_aes_128_ctr(void) aes_ctr.do_cipher = ssh_aes_ctr; #ifndef SSH_OLD_EVP @@ -155,9 +155,9 @@ diff -up openssh-5.2p1/cipher-ctr.c.fips openssh-5.2p1/cipher-ctr.c #endif return (&aes_ctr); } -diff -up openssh-5.2p1/cipher.h.fips openssh-5.2p1/cipher.h ---- openssh-5.2p1/cipher.h.fips 2009-01-28 06:38:41.000000000 +0100 -+++ openssh-5.2p1/cipher.h 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/cipher.h.fips openssh-5.3p1/cipher.h +--- openssh-5.3p1/cipher.h.fips 2009-01-28 06:38:41.000000000 +0100 ++++ openssh-5.3p1/cipher.h 2009-10-02 14:12:00.000000000 +0200 @@ -78,7 +78,7 @@ void cipher_init(CipherContext *, Ciphe const u_char *, u_int, int); void cipher_crypt(CipherContext *, u_char *, const u_char *, u_int); @@ -167,9 +167,9 @@ diff -up openssh-5.2p1/cipher.h.fips openssh-5.2p1/cipher.h u_int cipher_blocksize(const Cipher *); u_int cipher_keylen(const Cipher *); u_int cipher_is_cbc(const Cipher *); -diff -up openssh-5.2p1/mac.c.fips openssh-5.2p1/mac.c ---- openssh-5.2p1/mac.c.fips 2008-06-13 02:58:50.000000000 +0200 -+++ openssh-5.2p1/mac.c 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/mac.c.fips openssh-5.3p1/mac.c +--- openssh-5.3p1/mac.c.fips 2008-06-13 02:58:50.000000000 +0200 ++++ openssh-5.3p1/mac.c 2009-10-02 14:12:00.000000000 +0200 @@ -28,6 +28,7 @@ #include @@ -219,10 +219,10 @@ diff -up openssh-5.2p1/mac.c.fips openssh-5.2p1/mac.c for (i = 0; macs[i].name; i++) { if (strcmp(name, macs[i].name) == 0) { -diff -up openssh-5.2p1/Makefile.in.fips openssh-5.2p1/Makefile.in ---- openssh-5.2p1/Makefile.in.fips 2009-05-15 15:51:01.000000000 +0200 -+++ openssh-5.2p1/Makefile.in 2009-05-15 15:51:01.000000000 +0200 -@@ -134,28 +134,28 @@ libssh.a: $(LIBSSH_OBJS) +diff -up openssh-5.3p1/Makefile.in.fips openssh-5.3p1/Makefile.in +--- openssh-5.3p1/Makefile.in.fips 2009-10-02 14:12:00.000000000 +0200 ++++ openssh-5.3p1/Makefile.in 2009-10-02 14:20:18.000000000 +0200 +@@ -136,28 +136,28 @@ libssh.a: $(LIBSSH_OBJS) $(RANLIB) $@ ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) @@ -231,7 +231,7 @@ diff -up openssh-5.2p1/Makefile.in.fips openssh-5.2p1/Makefile.in sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) - $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) -+ $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) -lfipscheck $(LIBS) ++ $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(LIBS) scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o $(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) @@ -248,19 +248,19 @@ diff -up openssh-5.2p1/Makefile.in.fips openssh-5.2p1/Makefile.in - $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) + $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o -- $(LD) -o $@ ssh-keysign.o readconf.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-keysign.o readconf.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) + ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o +- $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o -- $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) -+ $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o +- $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) ++ $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -diff -up openssh-5.2p1/myproposal.h.fips openssh-5.2p1/myproposal.h ---- openssh-5.2p1/myproposal.h.fips 2009-01-28 06:33:31.000000000 +0100 -+++ openssh-5.2p1/myproposal.h 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/myproposal.h.fips openssh-5.3p1/myproposal.h +--- openssh-5.3p1/myproposal.h.fips 2009-01-28 06:33:31.000000000 +0100 ++++ openssh-5.3p1/myproposal.h 2009-10-02 14:12:00.000000000 +0200 @@ -53,7 +53,12 @@ "hmac-sha1-96,hmac-md5-96" #define KEX_DEFAULT_COMP "none,zlib@openssh.com,zlib" @@ -275,9 +275,9 @@ diff -up openssh-5.2p1/myproposal.h.fips openssh-5.2p1/myproposal.h static char *myproposal[PROPOSAL_MAX] = { KEX_DEFAULT_KEX, -diff -up openssh-5.2p1/nsskeys.c.fips openssh-5.2p1/nsskeys.c ---- openssh-5.2p1/nsskeys.c.fips 2009-05-15 15:51:01.000000000 +0200 -+++ openssh-5.2p1/nsskeys.c 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/nsskeys.c.fips openssh-5.3p1/nsskeys.c +--- openssh-5.3p1/nsskeys.c.fips 2009-10-02 14:12:00.000000000 +0200 ++++ openssh-5.3p1/nsskeys.c 2009-10-02 14:12:00.000000000 +0200 @@ -183,8 +183,8 @@ nss_convert_pubkey(Key *k) break; } @@ -289,9 +289,9 @@ diff -up openssh-5.2p1/nsskeys.c.fips openssh-5.2p1/nsskeys.c xfree(p); return 0; -diff -up openssh-5.2p1/openbsd-compat/bsd-arc4random.c.fips openssh-5.2p1/openbsd-compat/bsd-arc4random.c ---- openssh-5.2p1/openbsd-compat/bsd-arc4random.c.fips 2008-06-04 02:54:00.000000000 +0200 -+++ openssh-5.2p1/openbsd-compat/bsd-arc4random.c 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/openbsd-compat/bsd-arc4random.c.fips openssh-5.3p1/openbsd-compat/bsd-arc4random.c +--- openssh-5.3p1/openbsd-compat/bsd-arc4random.c.fips 2008-06-04 02:54:00.000000000 +0200 ++++ openssh-5.3p1/openbsd-compat/bsd-arc4random.c 2009-10-02 14:12:00.000000000 +0200 @@ -39,6 +39,7 @@ static int rc4_ready = 0; static RC4_KEY rc4; @@ -333,9 +333,9 @@ diff -up openssh-5.2p1/openbsd-compat/bsd-arc4random.c.fips openssh-5.2p1/openbs #endif /* !HAVE_ARC4RANDOM */ #ifndef ARC4RANDOM_BUF -diff -up openssh-5.2p1/ssh-add.c.fips openssh-5.2p1/ssh-add.c ---- openssh-5.2p1/ssh-add.c.fips 2009-05-15 15:51:01.000000000 +0200 -+++ openssh-5.2p1/ssh-add.c 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/ssh-add.c.fips openssh-5.3p1/ssh-add.c +--- openssh-5.3p1/ssh-add.c.fips 2009-10-02 14:12:00.000000000 +0200 ++++ openssh-5.3p1/ssh-add.c 2009-10-02 14:12:00.000000000 +0200 @@ -42,6 +42,7 @@ #include @@ -353,9 +353,9 @@ diff -up openssh-5.2p1/ssh-add.c.fips openssh-5.2p1/ssh-add.c SSH_FP_HEX); printf("%d %s %s (%s)\n", key_size(key), fp, comment, key_type(key)); -diff -up openssh-5.2p1/ssh-agent.c.fips openssh-5.2p1/ssh-agent.c ---- openssh-5.2p1/ssh-agent.c.fips 2009-05-15 15:51:01.000000000 +0200 -+++ openssh-5.2p1/ssh-agent.c 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/ssh-agent.c.fips openssh-5.3p1/ssh-agent.c +--- openssh-5.3p1/ssh-agent.c.fips 2009-10-02 14:12:00.000000000 +0200 ++++ openssh-5.3p1/ssh-agent.c 2009-10-02 14:12:00.000000000 +0200 @@ -51,6 +51,7 @@ #include @@ -377,10 +377,10 @@ diff -up openssh-5.2p1/ssh-agent.c.fips openssh-5.2p1/ssh-agent.c ret = 0; xfree(p); -diff -up openssh-5.2p1/ssh.c.fips openssh-5.2p1/ssh.c ---- openssh-5.2p1/ssh.c.fips 2009-05-15 15:51:01.000000000 +0200 -+++ openssh-5.2p1/ssh.c 2009-05-15 15:51:01.000000000 +0200 -@@ -71,6 +71,8 @@ +diff -up openssh-5.3p1/ssh.c.fips openssh-5.3p1/ssh.c +--- openssh-5.3p1/ssh.c.fips 2009-10-02 14:12:00.000000000 +0200 ++++ openssh-5.3p1/ssh.c 2009-10-02 14:12:00.000000000 +0200 +@@ -72,6 +72,8 @@ #include #include @@ -389,7 +389,7 @@ diff -up openssh-5.2p1/ssh.c.fips openssh-5.2p1/ssh.c #include "openbsd-compat/openssl-compat.h" #include "openbsd-compat/sys-queue.h" -@@ -220,6 +222,10 @@ main(int ac, char **av) +@@ -221,6 +223,10 @@ main(int ac, char **av) sanitise_stdfd(); __progname = ssh_get_progname(av[0]); @@ -400,7 +400,7 @@ diff -up openssh-5.2p1/ssh.c.fips openssh-5.2p1/ssh.c init_rng(); /* -@@ -279,6 +285,9 @@ main(int ac, char **av) +@@ -281,6 +287,9 @@ main(int ac, char **av) "ACD:F:I:KL:MNO:PR:S:TVw:XYy")) != -1) { switch (opt) { case '1': @@ -410,7 +410,7 @@ diff -up openssh-5.2p1/ssh.c.fips openssh-5.2p1/ssh.c options.protocol = SSH_PROTO_1; break; case '2': -@@ -550,7 +559,6 @@ main(int ac, char **av) +@@ -552,7 +561,6 @@ main(int ac, char **av) if (!host) usage(); @@ -418,7 +418,7 @@ diff -up openssh-5.2p1/ssh.c.fips openssh-5.2p1/ssh.c ERR_load_crypto_strings(); /* Initialize the command to execute on remote host. */ -@@ -635,6 +643,10 @@ main(int ac, char **av) +@@ -638,6 +646,10 @@ main(int ac, char **av) seed_rng(); @@ -429,7 +429,7 @@ diff -up openssh-5.2p1/ssh.c.fips openssh-5.2p1/ssh.c if (options.user == NULL) options.user = xstrdup(pw->pw_name); -@@ -701,6 +713,12 @@ main(int ac, char **av) +@@ -704,6 +716,12 @@ main(int ac, char **av) timeout_ms = options.connection_timeout * 1000; @@ -442,9 +442,9 @@ diff -up openssh-5.2p1/ssh.c.fips openssh-5.2p1/ssh.c /* Open a connection to the remote host. */ if (ssh_connect(host, &hostaddr, options.port, options.address_family, options.connection_attempts, &timeout_ms, -diff -up openssh-5.2p1/sshconnect2.c.fips openssh-5.2p1/sshconnect2.c ---- openssh-5.2p1/sshconnect2.c.fips 2009-05-15 15:51:01.000000000 +0200 -+++ openssh-5.2p1/sshconnect2.c 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/sshconnect2.c.fips openssh-5.3p1/sshconnect2.c +--- openssh-5.3p1/sshconnect2.c.fips 2009-10-02 14:12:00.000000000 +0200 ++++ openssh-5.3p1/sshconnect2.c 2009-10-02 14:12:00.000000000 +0200 @@ -44,6 +44,8 @@ #include #endif @@ -454,7 +454,7 @@ diff -up openssh-5.2p1/sshconnect2.c.fips openssh-5.2p1/sshconnect2.c #include "openbsd-compat/sys-queue.h" #include "xmalloc.h" -@@ -115,6 +117,10 @@ ssh_kex2(char *host, struct sockaddr *ho +@@ -116,6 +118,10 @@ ssh_kex2(char *host, struct sockaddr *ho if (options.ciphers != NULL) { myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; @@ -465,7 +465,7 @@ diff -up openssh-5.2p1/sshconnect2.c.fips openssh-5.2p1/sshconnect2.c } myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); -@@ -130,7 +136,11 @@ ssh_kex2(char *host, struct sockaddr *ho +@@ -131,7 +137,11 @@ ssh_kex2(char *host, struct sockaddr *ho if (options.macs != NULL) { myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; @@ -477,7 +477,7 @@ diff -up openssh-5.2p1/sshconnect2.c.fips openssh-5.2p1/sshconnect2.c if (options.hostkeyalgorithms != NULL) myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = options.hostkeyalgorithms; -@@ -507,8 +517,8 @@ input_userauth_pk_ok(int type, u_int32_t +@@ -508,8 +518,8 @@ input_userauth_pk_ok(int type, u_int32_t key->type, pktype); goto done; } @@ -488,9 +488,9 @@ diff -up openssh-5.2p1/sshconnect2.c.fips openssh-5.2p1/sshconnect2.c xfree(fp); /* -diff -up openssh-5.2p1/sshconnect.c.fips openssh-5.2p1/sshconnect.c ---- openssh-5.2p1/sshconnect.c.fips 2009-05-15 15:51:01.000000000 +0200 -+++ openssh-5.2p1/sshconnect.c 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/sshconnect.c.fips openssh-5.3p1/sshconnect.c +--- openssh-5.3p1/sshconnect.c.fips 2009-10-02 14:12:00.000000000 +0200 ++++ openssh-5.3p1/sshconnect.c 2009-10-02 14:12:00.000000000 +0200 @@ -40,6 +40,8 @@ #include #include @@ -500,7 +500,7 @@ diff -up openssh-5.2p1/sshconnect.c.fips openssh-5.2p1/sshconnect.c #include "xmalloc.h" #include "key.h" #include "hostfile.h" -@@ -761,6 +763,7 @@ check_host_key(char *hostname, struct so +@@ -763,6 +765,7 @@ check_host_key(char *hostname, struct so goto fail; } else if (options.strict_host_key_checking == 2) { char msg1[1024], msg2[1024]; @@ -508,7 +508,7 @@ diff -up openssh-5.2p1/sshconnect.c.fips openssh-5.2p1/sshconnect.c if (show_other_keys(host, host_key)) snprintf(msg1, sizeof(msg1), -@@ -769,8 +772,8 @@ check_host_key(char *hostname, struct so +@@ -771,8 +774,8 @@ check_host_key(char *hostname, struct so else snprintf(msg1, sizeof(msg1), "."); /* The default */ @@ -519,7 +519,7 @@ diff -up openssh-5.2p1/sshconnect.c.fips openssh-5.2p1/sshconnect.c SSH_FP_RANDOMART); msg2[0] = '\0'; if (options.verify_host_key_dns) { -@@ -786,10 +789,10 @@ check_host_key(char *hostname, struct so +@@ -788,10 +791,10 @@ check_host_key(char *hostname, struct so snprintf(msg, sizeof(msg), "The authenticity of host '%.200s (%s)' can't be " "established%s\n" @@ -532,7 +532,7 @@ diff -up openssh-5.2p1/sshconnect.c.fips openssh-5.2p1/sshconnect.c options.visual_host_key ? "\n" : "", options.visual_host_key ? ra : "", msg2); -@@ -1077,17 +1080,18 @@ show_key_from_file(const char *file, con +@@ -1079,17 +1082,18 @@ show_key_from_file(const char *file, con Key *found; char *fp, *ra; int line, ret; @@ -555,7 +555,7 @@ diff -up openssh-5.2p1/sshconnect.c.fips openssh-5.2p1/sshconnect.c xfree(ra); xfree(fp); } -@@ -1133,8 +1137,9 @@ warn_changed_key(Key *host_key) +@@ -1135,8 +1139,9 @@ warn_changed_key(Key *host_key) { char *fp; const char *type = key_type(host_key); @@ -566,7 +566,7 @@ diff -up openssh-5.2p1/sshconnect.c.fips openssh-5.2p1/sshconnect.c error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); -@@ -1142,8 +1147,8 @@ warn_changed_key(Key *host_key) +@@ -1144,8 +1149,8 @@ warn_changed_key(Key *host_key) error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); error("It is also possible that the %s host key has just been changed.", type); @@ -577,9 +577,9 @@ diff -up openssh-5.2p1/sshconnect.c.fips openssh-5.2p1/sshconnect.c error("Please contact your system administrator."); xfree(fp); -diff -up openssh-5.2p1/sshd.c.fips openssh-5.2p1/sshd.c ---- openssh-5.2p1/sshd.c.fips 2009-05-15 15:51:01.000000000 +0200 -+++ openssh-5.2p1/sshd.c 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/sshd.c.fips openssh-5.3p1/sshd.c +--- openssh-5.3p1/sshd.c.fips 2009-10-02 14:12:00.000000000 +0200 ++++ openssh-5.3p1/sshd.c 2009-10-02 14:12:00.000000000 +0200 @@ -76,6 +76,8 @@ #include #include @@ -589,7 +589,7 @@ diff -up openssh-5.2p1/sshd.c.fips openssh-5.2p1/sshd.c #include "openbsd-compat/openssl-compat.h" #ifdef HAVE_SECUREWARE -@@ -1260,6 +1262,12 @@ main(int ac, char **av) +@@ -1261,6 +1263,12 @@ main(int ac, char **av) (void)set_auth_parameters(ac, av); #endif __progname = ssh_get_progname(av[0]); @@ -602,7 +602,7 @@ diff -up openssh-5.2p1/sshd.c.fips openssh-5.2p1/sshd.c init_rng(); /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ -@@ -1412,8 +1420,6 @@ main(int ac, char **av) +@@ -1413,8 +1421,6 @@ main(int ac, char **av) else closefrom(REEXEC_DEVCRYPTO_RESERVED_FD); @@ -611,7 +611,7 @@ diff -up openssh-5.2p1/sshd.c.fips openssh-5.2p1/sshd.c /* * Force logging to stderr until we have loaded the private host * key (unless started from inetd) -@@ -1531,6 +1537,10 @@ main(int ac, char **av) +@@ -1532,6 +1538,10 @@ main(int ac, char **av) debug("private host key: #%d type %d %s", i, key->type, key_type(key)); } @@ -622,7 +622,7 @@ diff -up openssh-5.2p1/sshd.c.fips openssh-5.2p1/sshd.c if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) { logit("Disabling protocol version 1. Could not load host key"); options.protocol &= ~SSH_PROTO_1; -@@ -1655,6 +1665,10 @@ main(int ac, char **av) +@@ -1656,6 +1666,10 @@ main(int ac, char **av) /* Initialize the random number generator. */ arc4random_stir(); @@ -633,7 +633,7 @@ diff -up openssh-5.2p1/sshd.c.fips openssh-5.2p1/sshd.c /* Chdir to the root directory so that the current disk can be unmounted if desired. */ chdir("/"); -@@ -2182,6 +2196,9 @@ do_ssh2_kex(void) +@@ -2183,6 +2197,9 @@ do_ssh2_kex(void) if (options.ciphers != NULL) { myproposal[PROPOSAL_ENC_ALGS_CTOS] = myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; @@ -643,7 +643,7 @@ diff -up openssh-5.2p1/sshd.c.fips openssh-5.2p1/sshd.c } myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); -@@ -2191,6 +2208,9 @@ do_ssh2_kex(void) +@@ -2192,6 +2209,9 @@ do_ssh2_kex(void) if (options.macs != NULL) { myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; @@ -653,9 +653,9 @@ diff -up openssh-5.2p1/sshd.c.fips openssh-5.2p1/sshd.c } if (options.compression == COMP_NONE) { myproposal[PROPOSAL_COMP_ALGS_CTOS] = -diff -up openssh-5.2p1/ssh-keygen.c.fips openssh-5.2p1/ssh-keygen.c ---- openssh-5.2p1/ssh-keygen.c.fips 2009-05-15 15:51:01.000000000 +0200 -+++ openssh-5.2p1/ssh-keygen.c 2009-05-15 15:51:01.000000000 +0200 +diff -up openssh-5.3p1/ssh-keygen.c.fips openssh-5.3p1/ssh-keygen.c +--- openssh-5.3p1/ssh-keygen.c.fips 2009-10-02 14:12:00.000000000 +0200 ++++ openssh-5.3p1/ssh-keygen.c 2009-10-02 14:12:00.000000000 +0200 @@ -21,6 +21,7 @@ #include diff --git a/openssh-5.3p1-gsskex.patch b/openssh-5.3p1-gsskex.patch new file mode 100644 index 0000000..0ff0d54 --- /dev/null +++ b/openssh-5.3p1-gsskex.patch @@ -0,0 +1,2929 @@ +diff -up openssh-5.3p1/auth2.c.gsskex openssh-5.3p1/auth2.c +--- openssh-5.3p1/auth2.c.gsskex 2009-11-20 14:38:55.000000000 +0100 ++++ openssh-5.3p1/auth2.c 2009-11-20 14:39:04.000000000 +0100 +@@ -69,6 +69,7 @@ extern Authmethod method_passwd; + extern Authmethod method_kbdint; + extern Authmethod method_hostbased; + #ifdef GSSAPI ++extern Authmethod method_gsskeyex; + extern Authmethod method_gssapi; + #endif + #ifdef JPAKE +@@ -79,6 +80,7 @@ Authmethod *authmethods[] = { + &method_none, + &method_pubkey, + #ifdef GSSAPI ++ &method_gsskeyex, + &method_gssapi, + #endif + #ifdef JPAKE +@@ -289,6 +291,7 @@ input_userauth_request(int type, u_int32 + #endif + + authctxt->postponed = 0; ++ authctxt->server_caused_failure = 0; + + /* try to authenticate user */ + m = authmethod_lookup(method); +@@ -361,7 +364,8 @@ userauth_finish(Authctxt *authctxt, int + } else { + + /* Allow initial try of "none" auth without failure penalty */ +- if (authctxt->attempt > 1 || strcmp(method, "none") != 0) ++ if (!authctxt->server_caused_failure && ++ (authctxt->attempt > 1 || strcmp(method, "none") != 0)) + authctxt->failures++; + if (authctxt->failures >= options.max_authtries) { + #ifdef SSH_AUDIT_EVENTS +diff -up openssh-5.3p1/auth2-gss.c.gsskex openssh-5.3p1/auth2-gss.c +--- openssh-5.3p1/auth2-gss.c.gsskex 2009-11-20 14:38:55.000000000 +0100 ++++ openssh-5.3p1/auth2-gss.c 2009-11-20 14:39:04.000000000 +0100 +@@ -1,7 +1,7 @@ + /* $OpenBSD: auth2-gss.c,v 1.16 2007/10/29 00:52:45 dtucker 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 +@@ -52,6 +52,40 @@ static void input_gssapi_mic(int type, u + 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; ++ gss_buffer_desc mic, gssbuf; ++ 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); ++ ++ /* gss_kex_context is NULL with privsep, so we can't check it here */ ++ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, ++ &gssbuf, &mic)))) ++ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, ++ authctxt->pw)); ++ ++ buffer_free(&b); ++ xfree(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) +@@ -102,6 +136,7 @@ userauth_gssapi(Authctxt *authctxt) + + if (!present) { + xfree(doid); ++ authctxt->server_caused_failure = 1; + return (0); + } + +@@ -109,6 +144,7 @@ userauth_gssapi(Authctxt *authctxt) + if (ctxt != NULL) + ssh_gssapi_delete_ctx(&ctxt); + xfree(doid); ++ authctxt->server_caused_failure = 1; + return (0); + } + +@@ -242,7 +278,8 @@ input_gssapi_exchange_complete(int type, + + packet_check_eom(); + +- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); ++ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, ++ authctxt->pw)); + + authctxt->postponed = 0; + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); +@@ -284,7 +321,8 @@ input_gssapi_mic(int type, u_int32_t ple + gssbuf.length = buffer_len(&b); + + if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) +- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); ++ authenticated = ++ PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw)); + else + logit("GSSAPI MIC check failed"); + +@@ -301,6 +339,12 @@ input_gssapi_mic(int type, u_int32_t ple + userauth_finish(authctxt, authenticated, "gssapi-with-mic"); + } + ++Authmethod method_gsskeyex = { ++ "gssapi-keyex", ++ userauth_gsskeyex, ++ &options.gss_authentication ++}; ++ + Authmethod method_gssapi = { + "gssapi-with-mic", + userauth_gssapi, +diff -up openssh-5.3p1/auth.h.gsskex openssh-5.3p1/auth.h +--- openssh-5.3p1/auth.h.gsskex 2009-11-20 14:38:55.000000000 +0100 ++++ openssh-5.3p1/auth.h 2009-11-20 14:39:04.000000000 +0100 +@@ -53,6 +53,7 @@ struct Authctxt { + int valid; /* user exists and is allowed to login */ + int attempt; + int failures; ++ int server_caused_failure; + int force_pwchange; + char *user; /* username sent by the client */ + char *service; +diff -up openssh-5.3p1/auth-krb5.c.gsskex openssh-5.3p1/auth-krb5.c +--- openssh-5.3p1/auth-krb5.c.gsskex 2006-08-05 04:39:39.000000000 +0200 ++++ openssh-5.3p1/auth-krb5.c 2009-11-20 14:39:04.000000000 +0100 +@@ -166,8 +166,13 @@ auth_krb5_password(Authctxt *authctxt, c + + 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) +@@ -219,15 +224,22 @@ krb5_cleanup_proc(Authctxt *authctxt) + #ifndef HEIMDAL + krb5_error_code + ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { +- int tmpfd, ret; ++ 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; ++#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:")); + umask(old_umask); +@@ -242,6 +254,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_c + return errno; + } + close(tmpfd); ++#endif + + return (krb5_cc_resolve(ctx, ccname, ccache)); + } +diff -up /dev/null openssh-5.3p1/ChangeLog.gssapi +--- /dev/null 2009-11-13 11:29:57.672908570 +0100 ++++ openssh-5.3p1/ChangeLog.gssapi 2009-11-20 14:39:04.000000000 +0100 +@@ -0,0 +1,95 @@ ++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 -up openssh-5.3p1/clientloop.c.gsskex openssh-5.3p1/clientloop.c +--- openssh-5.3p1/clientloop.c.gsskex 2009-08-28 03:21:07.000000000 +0200 ++++ openssh-5.3p1/clientloop.c 2009-11-20 14:48:53.000000000 +0100 +@@ -111,6 +111,10 @@ + #include "msg.h" + #include "roaming.h" + ++#ifdef GSSAPI ++#include "ssh-gss.h" ++#endif ++ + /* import options */ + extern Options options; + +@@ -1430,6 +1434,13 @@ client_loop(int have_pty, int escape_cha + /* Do channel operations unless rekeying in progress. */ + if (!rekeying) { + channel_after_select(readset, writeset); ++ ++ if (options.gss_renewal_rekey && ++ ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) { ++ debug("credentials updated - forcing rekey"); ++ need_rekeying = 1; ++ } ++ + if (need_rekeying || packet_need_rekeying()) { + debug("need rekeying"); + xxx_kex->done = 0; +diff -up openssh-5.3p1/configure.ac.gsskex openssh-5.3p1/configure.ac +--- openssh-5.3p1/configure.ac.gsskex 2009-11-20 14:39:02.000000000 +0100 ++++ openssh-5.3p1/configure.ac 2009-11-20 14:39:04.000000000 +0100 +@@ -477,6 +477,30 @@ main() { if (NSVersionOfRunTimeLibrary(" + [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]) +diff -up openssh-5.3p1/gss-genr.c.gsskex openssh-5.3p1/gss-genr.c +--- openssh-5.3p1/gss-genr.c.gsskex 2009-06-22 08:11:07.000000000 +0200 ++++ openssh-5.3p1/gss-genr.c 2009-11-20 14:39:04.000000000 +0100 +@@ -39,12 +39,167 @@ + #include "buffer.h" + #include "log.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++) ++ xfree(gss_enc2oid[i].encoded); ++ xfree(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) { ++ xfree(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) +@@ -197,7 +352,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de + } + + 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); + +@@ -227,8 +382,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, con + } + + 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 +425,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer + 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 +451,16 @@ ssh_gssapi_buildmic(Buffer *b, const cha + } + + 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 +470,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx + 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 +483,67 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx + 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; ++ gss_cred_usage_t usage = GSS_C_INITIATE; ++ ++ 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 -up openssh-5.3p1/gss-serv.c.gsskex openssh-5.3p1/gss-serv.c +--- openssh-5.3p1/gss-serv.c.gsskex 2008-05-19 07:05:07.000000000 +0200 ++++ openssh-5.3p1/gss-serv.c 2009-11-20 14:39:05.000000000 +0100 +@@ -1,7 +1,7 @@ + /* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 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,15 +45,20 @@ + #include "channels.h" + #include "session.h" + #include "misc.h" ++#include "servconf.h" ++#include "uidswap.h" + + #include "ssh-gss.h" ++#include "monitor_wrap.h" ++ ++extern ServerOptions options; + + static ssh_gssapi_client gssapi_client = + { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, +- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}}; ++ GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, 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; +@@ -81,25 +86,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx) + 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 */ +@@ -114,6 +126,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss + } + + /* 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) + { +@@ -123,7 +158,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o + gss_OID_set supported; + + gss_create_empty_oid_set(&min_status, oidset); +- gss_indicate_mechs(&min_status, &supported); ++ ++ if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported))) ++ return; + + while (supported_mechs[i]->name != NULL) { + if (GSS_ERROR(gss_test_oid_set_member(&min_status, +@@ -247,8 +284,48 @@ OM_uint32 + 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; ++ } ++ ++ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, ++ ctx->client_creds, ctx->oid, &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; + +@@ -263,6 +340,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g + if (client->mech == NULL) + return GSS_S_FAILURE; + ++ if (ctx->client_creds && ++ (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, ++ ctx->client_creds, ctx->oid, &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); +@@ -280,6 +364,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g + 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; +@@ -327,7 +413,7 @@ ssh_gssapi_do_child(char ***envp, u_int + + /* Privileged */ + int +-ssh_gssapi_userok(char *user) ++ssh_gssapi_userok(char *user, struct passwd *pw) + { + OM_uint32 lmin; + +@@ -337,9 +423,11 @@ ssh_gssapi_userok(char *user) + return 0; + } + 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); +@@ -352,14 +440,90 @@ ssh_gssapi_userok(char *user) + return (0); + } + +-/* Privileged */ +-OM_uint32 +-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) ++/* 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; ++ int ret; ++#ifdef USE_PAM ++ pam_handle_t *pamh = NULL; ++ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; ++ char *envstr; ++#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; ++ ++ 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; + } + + #endif +diff -up openssh-5.3p1/gss-serv-krb5.c.gsskex openssh-5.3p1/gss-serv-krb5.c +--- openssh-5.3p1/gss-serv-krb5.c.gsskex 2006-09-01 07:38:36.000000000 +0200 ++++ openssh-5.3p1/gss-serv-krb5.c 2009-11-20 14:39:04.000000000 +0100 +@@ -1,7 +1,7 @@ + /* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt 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 +@@ -120,6 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl + krb5_principal princ; + OM_uint32 maj_status, min_status; + int len; ++ const char *new_ccname; + + if (client->creds == NULL) { + debug("No credentials stored"); +@@ -168,11 +169,16 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl + 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) +@@ -184,6 +190,71 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl + return; + } + ++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; ++} ++ + ssh_gssapi_mech gssapi_kerberos_mech = { + "toWM5Slw5Ew8Mqkay+al2g==", + "Kerberos", +@@ -191,7 +262,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = { + NULL, + &ssh_gssapi_krb5_userok, + NULL, +- &ssh_gssapi_krb5_storecreds ++ &ssh_gssapi_krb5_storecreds, ++ &ssh_gssapi_krb5_updatecreds + }; + + #endif /* KRB5 */ +diff -up openssh-5.3p1/kex.c.gsskex openssh-5.3p1/kex.c +--- openssh-5.3p1/kex.c.gsskex 2009-06-21 10:15:25.000000000 +0200 ++++ openssh-5.3p1/kex.c 2009-11-20 14:50:11.000000000 +0100 +@@ -49,6 +49,10 @@ + #include "dispatch.h" + #include "monitor.h" + ++#ifdef GSSAPI ++#include "ssh-gss.h" ++#endif ++ + #if OPENSSL_VERSION_NUMBER >= 0x00907000L + # if defined(HAVE_EVP_SHA256) + # define evp_ssh_sha256 EVP_sha256 +@@ -325,6 +329,20 @@ choose_kex(Kex *k, char *client, char *s + k->kex_type = KEX_DH_GEX_SHA256; + k->evp_md = evp_ssh_sha256(); + #endif ++#ifdef GSSAPI ++ } else 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->evp_md = EVP_sha1(); ++ } else 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->evp_md = EVP_sha1(); ++ } else 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->evp_md = EVP_sha1(); ++#endif + } else + fatal("bad kex alg %s", k->name); + } +diff -up /dev/null openssh-5.3p1/kexgssc.c +--- /dev/null 2009-11-13 11:29:57.672908570 +0100 ++++ openssh-5.3p1/kexgssc.c 2009-11-20 14:39:05.000000000 +0100 +@@ -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) ++ xfree(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); ++ xfree(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->evp_md, ++ 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"); ++ ++ xfree(msg_tok.value); ++ ++ DH_free(dh); ++ if (serverhostkey) ++ xfree(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(kex, hash, hashlen, shared_secret); ++ BN_clear_free(shared_secret); ++ kex_finish(kex); ++} ++ ++#endif /* GSSAPI */ +diff -up /dev/null openssh-5.3p1/kexgsss.c +--- /dev/null 2009-11-13 11:29:57.672908570 +0100 ++++ openssh-5.3p1/kexgsss.c 2009-11-20 14:39:05.000000000 +0100 +@@ -0,0 +1,288 @@ ++/* ++ * 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" ++ ++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())) ++ xfree(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)))) ++ 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)); ++ ++ xfree(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(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)) { ++ if (send_tok.length > 0) { ++ packet_start(SSH2_MSG_KEXGSS_CONTINUE); ++ packet_put_string(send_tok.value, send_tok.length); ++ packet_send(); ++ } ++ fatal("accept_ctx died"); ++ } ++ ++ 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); ++ xfree(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->evp_md, ++ 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(msg_tok.value,msg_tok.length); ++ ++ if (send_tok.length != 0) { ++ packet_put_char(1); /* true */ ++ packet_put_string(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(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(); ++} ++#endif /* GSSAPI */ +diff -up openssh-5.3p1/kex.h.gsskex openssh-5.3p1/kex.h +--- openssh-5.3p1/kex.h.gsskex 2009-06-21 10:15:25.000000000 +0200 ++++ openssh-5.3p1/kex.h 2009-11-20 14:39:05.000000000 +0100 +@@ -66,6 +66,9 @@ enum kex_exchange { + KEX_DH_GRP14_SHA1, + KEX_DH_GEX_SHA1, + KEX_DH_GEX_SHA256, ++ KEX_GSS_GRP1_SHA1, ++ KEX_GSS_GRP14_SHA1, ++ KEX_GSS_GEX_SHA1, + KEX_MAX + }; + +@@ -121,6 +124,12 @@ struct Kex { + sig_atomic_t done; + int flags; + const EVP_MD *evp_md; ++#ifdef GSSAPI ++ int gss_deleg_creds; ++ int gss_trust_dns; ++ char *gss_host; ++ char *gss_client; ++#endif + char *client_version_string; + char *server_version_string; + int (*verify_host_key)(Key *); +@@ -143,6 +152,11 @@ void kexdh_server(Kex *); + void kexgex_client(Kex *); + void kexgex_server(Kex *); + ++#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 -up openssh-5.3p1/key.c.gsskex openssh-5.3p1/key.c +--- openssh-5.3p1/key.c.gsskex 2009-11-20 14:38:59.000000000 +0100 ++++ openssh-5.3p1/key.c 2009-11-20 14:39:05.000000000 +0100 +@@ -825,6 +825,8 @@ key_type_from_name(char *name) + return KEY_RSA; + } else if (strcmp(name, "ssh-dss") == 0) { + return KEY_DSA; ++ } else if (strcmp(name, "null") == 0) { ++ return KEY_NULL; + } + debug2("key_type_from_name: unknown key type '%s'", name); + return KEY_UNSPEC; +diff -up openssh-5.3p1/key.h.gsskex openssh-5.3p1/key.h +--- openssh-5.3p1/key.h.gsskex 2009-11-20 14:38:59.000000000 +0100 ++++ openssh-5.3p1/key.h 2009-11-20 14:50:59.000000000 +0100 +@@ -40,6 +40,7 @@ enum types { + KEY_RSA, + KEY_DSA, + KEY_NSS, ++ KEY_NULL, + KEY_UNSPEC + }; + enum fp_type { +diff -up openssh-5.3p1/Makefile.in.gsskex openssh-5.3p1/Makefile.in +--- openssh-5.3p1/Makefile.in.gsskex 2009-11-20 14:39:02.000000000 +0100 ++++ openssh-5.3p1/Makefile.in 2009-11-20 15:06:44.000000000 +0100 +@@ -71,7 +71,8 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o b + 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-rsa.o dh.o kexdh.o \ + kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \ +- entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o nsskeys.o ++ entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o nsskeys.o \ ++ kexgssc.o + + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ + sshconnect.o sshconnect1.o sshconnect2.o mux.o \ +@@ -85,7 +86,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw + auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \ + monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \ + auth-krb5.o \ +- auth2-gss.o gss-serv.o gss-serv-krb5.o \ ++ auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\ + loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ + audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \ + roaming_common.o +diff -up openssh-5.3p1/monitor.c.gsskex openssh-5.3p1/monitor.c +--- openssh-5.3p1/monitor.c.gsskex 2009-11-20 14:38:55.000000000 +0100 ++++ openssh-5.3p1/monitor.c 2009-11-20 14:39:05.000000000 +0100 +@@ -175,6 +175,8 @@ int mm_answer_gss_setup_ctx(int, Buffer + 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_updatecreds(int, Buffer *); + #endif + + #ifdef SSH_AUDIT_EVENTS +@@ -247,6 +249,7 @@ struct mon_table mon_dispatch_proto20[] + {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}, + #endif + #ifdef JPAKE + {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata}, +@@ -259,6 +262,12 @@ struct mon_table mon_dispatch_proto20[] + }; + + 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_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}, +@@ -363,6 +372,10 @@ monitor_child_preauth(Authctxt *_authctx + /* 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); ++#endif + } else { + mon_dispatch = mon_dispatch_proto15; + +@@ -449,6 +462,10 @@ monitor_child_postauth(struct monitor *p + 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_GSSSETUP, 1); ++#endif + } else { + mon_dispatch = mon_dispatch_postauth15; + monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); +@@ -1738,6 +1755,13 @@ mm_get_kex(Buffer *m) + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; + kex->kex[KEX_DH_GEX_SHA256] = kexgex_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->server = 1; + kex->hostkey_type = buffer_get_int(m); + kex->kex_type = buffer_get_int(m); +@@ -1943,6 +1967,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer + 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; + +@@ -1970,6 +1997,9 @@ mm_answer_gss_accept_ctx(int sock, Buffe + 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); +@@ -1987,6 +2017,7 @@ mm_answer_gss_accept_ctx(int sock, Buffe + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); + } + return (0); + } +@@ -1998,6 +2029,9 @@ mm_answer_gss_checkmic(int sock, Buffer + 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); +@@ -2024,7 +2058,11 @@ mm_answer_gss_userok(int sock, Buffer *m + { + int authenticated; + +- 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); + + buffer_clear(m); + buffer_put_int(m, authenticated); +@@ -2037,6 +2075,74 @@ mm_answer_gss_userok(int sock, Buffer *m + /* Monitor loop will terminate if authenticated */ + return (authenticated); + } ++ ++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); ++ ++ xfree(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); ++ ++ xfree(store.filename); ++ xfree(store.envvar); ++ xfree(store.envval); ++ ++ buffer_clear(m); ++ buffer_put_int(m, ok); ++ ++ mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m); ++ ++ return(0); ++} ++ + #endif /* GSSAPI */ + + #ifdef JPAKE +diff -up openssh-5.3p1/monitor.h.gsskex openssh-5.3p1/monitor.h +--- openssh-5.3p1/monitor.h.gsskex 2009-11-20 14:38:55.000000000 +0100 ++++ openssh-5.3p1/monitor.h 2009-11-20 14:39:05.000000000 +0100 +@@ -56,6 +56,8 @@ enum monitor_reqtype { + MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP, + MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, + MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, ++ MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN, ++ MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS, + MONITOR_REQ_PAM_START, + MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, + MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, +diff -up openssh-5.3p1/monitor_wrap.c.gsskex openssh-5.3p1/monitor_wrap.c +--- openssh-5.3p1/monitor_wrap.c.gsskex 2009-11-20 14:38:55.000000000 +0100 ++++ openssh-5.3p1/monitor_wrap.c 2009-11-20 14:39:05.000000000 +0100 +@@ -1267,7 +1267,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss + } + + int +-mm_ssh_gssapi_userok(char *user) ++mm_ssh_gssapi_userok(char *user, struct passwd *pw) + { + Buffer m; + int authenticated = 0; +@@ -1284,6 +1284,51 @@ mm_ssh_gssapi_userok(char *user) + debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); + return (authenticated); + } ++ ++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 */ + + #ifdef JPAKE +diff -up openssh-5.3p1/monitor_wrap.h.gsskex openssh-5.3p1/monitor_wrap.h +--- openssh-5.3p1/monitor_wrap.h.gsskex 2009-11-20 14:38:55.000000000 +0100 ++++ openssh-5.3p1/monitor_wrap.h 2009-11-20 14:39:05.000000000 +0100 +@@ -60,8 +60,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(K + 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 *); + 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_update_creds(ssh_gssapi_ccache *); + #endif + + #ifdef USE_PAM +diff -up openssh-5.3p1/readconf.c.gsskex openssh-5.3p1/readconf.c +--- openssh-5.3p1/readconf.c.gsskex 2009-11-20 14:38:59.000000000 +0100 ++++ openssh-5.3p1/readconf.c 2009-11-20 14:39:06.000000000 +0100 +@@ -128,6 +128,7 @@ typedef enum { + oClearAllForwardings, oNoHostAuthenticationForLocalhost, + oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, + oAddressFamily, oGssAuthentication, oGssDelegateCreds, ++ oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, + oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, + oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, + oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, +@@ -165,10 +166,18 @@ static struct { + { "afstokenpassing", oUnsupported }, + #if defined(GSSAPI) + { "gssapiauthentication", oGssAuthentication }, ++ { "gssapikeyexchange", oGssKeyEx }, + { "gssapidelegatecredentials", oGssDelegateCreds }, ++ { "gssapitrustdns", oGssTrustDns }, ++ { "gssapiclientidentity", oGssClientIdentity }, ++ { "gssapirenewalforcesrekey", oGssRenewalRekey }, + #else + { "gssapiauthentication", oUnsupported }, ++ { "gssapikeyexchange", oUnsupported }, + { "gssapidelegatecredentials", oUnsupported }, ++ { "gssapitrustdns", oUnsupported }, ++ { "gssapiclientidentity", oUnsupported }, ++ { "gssapirenewalforcesrekey", oUnsupported }, + #endif + { "fallbacktorsh", oDeprecated }, + { "usersh", oDeprecated }, +@@ -462,10 +471,26 @@ parse_flag: + 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 oGssRenewalRekey: ++ intptr = &options->gss_renewal_rekey; ++ goto parse_flag; ++ + case oBatchMode: + intptr = &options->batch_mode; + goto parse_flag; +@@ -1029,7 +1054,11 @@ initialize_options(Options * options) + 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->password_authentication = -1; + options->kbd_interactive_authentication = -1; + options->kbd_interactive_devices = NULL; +@@ -1123,8 +1152,14 @@ fill_default_options(Options * options) + options->challenge_response_authentication = 1; + if (options->gss_authentication == -1) + options->gss_authentication = 0; ++ if (options->gss_keyex == -1) ++ options->gss_keyex = 0; + if (options->gss_deleg_creds == -1) + options->gss_deleg_creds = 0; ++ if (options->gss_trust_dns == -1) ++ options->gss_trust_dns = 0; ++ 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) +diff -up openssh-5.3p1/readconf.h.gsskex openssh-5.3p1/readconf.h +--- openssh-5.3p1/readconf.h.gsskex 2009-11-20 14:38:59.000000000 +0100 ++++ openssh-5.3p1/readconf.h 2009-11-20 14:39:06.000000000 +0100 +@@ -44,7 +44,11 @@ typedef struct { + 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 */ + int password_authentication; /* Try password + * authentication. */ + int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ +diff -up openssh-5.3p1/servconf.c.gsskex openssh-5.3p1/servconf.c +--- openssh-5.3p1/servconf.c.gsskex 2009-11-20 14:39:03.000000000 +0100 ++++ openssh-5.3p1/servconf.c 2009-11-20 14:52:27.000000000 +0100 +@@ -92,7 +92,10 @@ initialize_server_options(ServerOptions + options->kerberos_ticket_cleanup = -1; + options->kerberos_get_afs_token = -1; + options->gss_authentication=-1; ++ options->gss_keyex = -1; + options->gss_cleanup_creds = -1; ++ options->gss_strict_acceptor = -1; ++ options->gss_store_rekey = -1; + options->password_authentication = -1; + options->kbd_interactive_authentication = -1; + options->challenge_response_authentication = -1; +@@ -213,8 +216,14 @@ fill_default_server_options(ServerOption + options->kerberos_get_afs_token = 0; + if (options->gss_authentication == -1) + options->gss_authentication = 0; ++ if (options->gss_keyex == -1) ++ options->gss_keyex = 0; + if (options->gss_cleanup_creds == -1) + options->gss_cleanup_creds = 1; ++ if (options->gss_strict_acceptor == -1) ++ options->gss_strict_acceptor = 1; ++ 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) +@@ -308,7 +317,9 @@ typedef enum { + sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication, + sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, + sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, +- sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, ++ sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, ++ sGssKeyEx, sGssStoreRekey, ++ sAcceptEnv, sPermitTunnel, + sMatch, sPermitOpen, sForceCommand, sChrootDirectory, + sUsePrivilegeSeparation, sAllowAgentForwarding, + sZeroKnowledgePasswordAuthentication, +@@ -371,9 +382,15 @@ static struct { + #ifdef GSSAPI + { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, + { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, ++ { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, ++ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, ++ { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, + #else + { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, + { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, ++ { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, ++ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, ++ { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, + #endif + { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, + { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, +@@ -906,10 +923,22 @@ process_server_config_line(ServerOptions + intptr = &options->gss_authentication; + goto parse_flag; + ++ case sGssKeyEx: ++ intptr = &options->gss_keyex; ++ goto parse_flag; ++ + case sGssCleanupCreds: + intptr = &options->gss_cleanup_creds; + goto parse_flag; + ++ case sGssStrictAcceptor: ++ intptr = &options->gss_strict_acceptor; ++ goto parse_flag; ++ ++ case sGssStoreRekey: ++ intptr = &options->gss_store_rekey; ++ goto parse_flag; ++ + case sPasswordAuthentication: + intptr = &options->password_authentication; + goto parse_flag; +diff -up openssh-5.3p1/servconf.h.gsskex openssh-5.3p1/servconf.h +--- openssh-5.3p1/servconf.h.gsskex 2009-11-20 14:39:03.000000000 +0100 ++++ openssh-5.3p1/servconf.h 2009-11-20 14:39:06.000000000 +0100 +@@ -91,7 +91,10 @@ typedef struct { + int kerberos_get_afs_token; /* If true, try to get AFS token if + * authenticated with Kerberos. */ + int gss_authentication; /* If true, permit GSSAPI authentication */ ++ int gss_keyex; /* If true, permit GSSAPI key exchange */ + int gss_cleanup_creds; /* 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 */ +diff -up openssh-5.3p1/ssh_config.5.gsskex openssh-5.3p1/ssh_config.5 +--- openssh-5.3p1/ssh_config.5.gsskex 2009-02-23 00:53:58.000000000 +0100 ++++ openssh-5.3p1/ssh_config.5 2009-11-20 14:39:06.000000000 +0100 +@@ -478,11 +478,38 @@ Specifies whether user authentication ba + The default is + .Dq no . + 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 no . ++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 GSSAPIDelegateCredentials + Forward (delegate) credentials to the server. + The default is + .Dq no . +-Note that this option applies to protocol version 2 only. ++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 no . ++.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 no . ++This option only applies to protocol version 2 connections using GSSAPI. + .It Cm HashKnownHosts + Indicates that + .Xr ssh 1 +diff -up openssh-5.3p1/ssh_config.gsskex openssh-5.3p1/ssh_config +--- openssh-5.3p1/ssh_config.gsskex 2009-11-20 14:38:53.000000000 +0100 ++++ openssh-5.3p1/ssh_config 2009-11-20 14:39:06.000000000 +0100 +@@ -26,6 +26,8 @@ + # HostbasedAuthentication no + # GSSAPIAuthentication no + # GSSAPIDelegateCredentials no ++# GSSAPIKeyExchange no ++# GSSAPITrustDNS no + # BatchMode no + # CheckHostIP yes + # AddressFamily any +diff -up openssh-5.3p1/sshconnect2.c.gsskex openssh-5.3p1/sshconnect2.c +--- openssh-5.3p1/sshconnect2.c.gsskex 2009-11-20 14:39:01.000000000 +0100 ++++ openssh-5.3p1/sshconnect2.c 2009-11-20 15:05:03.000000000 +0100 +@@ -108,9 +108,34 @@ ssh_kex2(char *host, struct sockaddr *ho + { + 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; +@@ -146,6 +171,17 @@ ssh_kex2(char *host, struct sockaddr *ho + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = + options.hostkeyalgorithms; + ++#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); ++ xfree(gss); ++ } ++#endif ++ + if (options.rekey_limit) + packet_set_rekey_limit((u_int32_t)options.rekey_limit); + +@@ -155,10 +191,26 @@ ssh_kex2(char *host, struct sockaddr *ho + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; + kex->kex[KEX_DH_GEX_SHA256] = kexgex_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->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; ++ kex->gss_host = gss_host; ++ } ++#endif ++ + xxx_kex = kex; + + dispatch_run(DISPATCH_BLOCK, &kex->done, kex); +@@ -247,6 +299,7 @@ void input_gssapi_token(int type, u_int3 + 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 *); +@@ -262,6 +315,10 @@ static char *authmethods_get(void); + + Authmethod authmethods[] = { + #ifdef GSSAPI ++ {"gssapi-keyex", ++ userauth_gsskeyex, ++ &options.gss_authentication, ++ NULL}, + {"gssapi-with-mic", + userauth_gssapi, + NULL, +@@ -555,23 +612,35 @@ userauth_gssapi(Authctxt *authctxt) + int ok = 0; + char* remotehost = NULL; + const char* canonicalhost = get_canonical_hostname(1); ++ const char *gss_host; ++ + if ( strcmp( canonicalhost, "UNKNOWN" ) == 0 ) + remotehost = authctxt->host; + else + remotehost = canonicalhost; + ++ if (options.gss_trust_dns) ++// gss_host = get_canonical_hostname(1); ++ gss_host = remotehost; ++ else ++ gss_host = 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], remotehost)) { ++ &gss_supported->elements[mech], gss_host, ++ options.gss_client_identity)) { + ok = 1; /* Mechanism works */ + } else { + mech++; +@@ -668,8 +737,8 @@ input_gssapi_response(int type, u_int32_ + { + 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"); +@@ -779,6 +848,48 @@ input_gssapi_error(int type, u_int32_t p + xfree(msg); + xfree(lang); + } ++ ++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); ++ } ++ ++ ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, ++ "gssapi-keyex"); ++ ++ 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); ++ packet_put_cstring(authctxt->server_user); ++ 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 -up openssh-5.3p1/sshd.c.gsskex openssh-5.3p1/sshd.c +--- openssh-5.3p1/sshd.c.gsskex 2009-11-20 14:39:01.000000000 +0100 ++++ openssh-5.3p1/sshd.c 2009-11-20 14:53:31.000000000 +0100 +@@ -129,6 +129,10 @@ int allow_severity; + int deny_severity; + #endif /* LIBWRAP */ + ++#ifdef USE_SECURITY_SESSION_API ++#include ++#endif ++ + #ifndef O_NOCTTY + #define O_NOCTTY 0 + #endif +@@ -1546,10 +1550,13 @@ main(int ac, char **av) + 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); +@@ -1837,6 +1844,60 @@ main(int ac, char **av) + /* Log the connection. */ + verbose("Connection from %.500s port %d", remote_ip, remote_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 ++ + /* + * We don't want to listen forever unless the other side + * successfully authenticates itself. So we set up an alarm which is +@@ -2223,12 +2284,61 @@ do_ssh2_kex(void) + + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 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; + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; + kex->kex[KEX_DH_GEX_SHA256] = kexgex_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->server = 1; + kex->client_version_string=client_version_string; + kex->server_version_string=server_version_string; +diff -up openssh-5.3p1/sshd_config.5.gsskex openssh-5.3p1/sshd_config.5 +--- openssh-5.3p1/sshd_config.5.gsskex 2009-11-20 14:39:03.000000000 +0100 ++++ openssh-5.3p1/sshd_config.5 2009-11-20 14:39:06.000000000 +0100 +@@ -379,12 +379,40 @@ Specifies whether user authentication ba + The default is + .Dq no . + Note that this option applies to protocol version 2 only. ++.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 no . ++Note that this option applies to protocol version 2 only. + .It Cm GSSAPICleanupCredentials + Specifies whether to automatically destroy the user's credentials cache + on logout. + The default is + .Dq yes . + Note that this option applies to protocol version 2 only. ++.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 +diff -up openssh-5.3p1/sshd_config.gsskex openssh-5.3p1/sshd_config +--- openssh-5.3p1/sshd_config.gsskex 2009-11-20 14:39:04.000000000 +0100 ++++ openssh-5.3p1/sshd_config 2009-11-20 14:54:30.000000000 +0100 +@@ -80,6 +80,8 @@ ChallengeResponseAuthentication no + GSSAPIAuthentication yes + #GSSAPICleanupCredentials yes + GSSAPICleanupCredentials yes ++#GSSAPIStrictAcceptorCheck yes ++#GSSAPIKeyExchange no + + # Set this to 'yes' to enable PAM authentication, account processing, + # and session processing. If this is enabled, PAM authentication will +diff -up openssh-5.3p1/ssh-gss.h.gsskex openssh-5.3p1/ssh-gss.h +--- openssh-5.3p1/ssh-gss.h.gsskex 2007-06-12 15:40:39.000000000 +0200 ++++ openssh-5.3p1/ssh-gss.h 2009-11-20 14:39:06.000000000 +0100 +@@ -1,6 +1,6 @@ + /* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 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 +@@ -60,10 +60,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; + +@@ -71,8 +83,11 @@ typedef struct { + 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; ++ int used; ++ int updated; + } ssh_gssapi_client; + + typedef struct ssh_gssapi_mech_struct { +@@ -83,6 +98,7 @@ typedef struct ssh_gssapi_mech_struct { + 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 { +@@ -93,10 +109,11 @@ typedef struct { + gss_OID oid; /* client */ + 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); +@@ -116,16 +133,30 @@ void ssh_gssapi_build_ctx(Gssctxt **); + 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 *); + + /* 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 *); + 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); + ++char *ssh_gssapi_server_mechanisms(void); ++int ssh_gssapi_oid_table_ok(); ++ ++int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); + #endif /* GSSAPI */ + + #endif /* _SSH_GSS_H */ diff --git a/openssh-5.1p1-mls.patch b/openssh-5.3p1-mls.patch similarity index 91% rename from openssh-5.1p1-mls.patch rename to openssh-5.3p1-mls.patch index baf34ad..451b7e8 100644 --- a/openssh-5.1p1-mls.patch +++ b/openssh-5.3p1-mls.patch @@ -1,7 +1,18 @@ -diff -up openssh-5.1p1/misc.c.mls openssh-5.1p1/misc.c ---- openssh-5.1p1/misc.c.mls 2008-06-13 06:48:59.000000000 +0200 -+++ openssh-5.1p1/misc.c 2008-07-23 18:53:37.000000000 +0200 -@@ -427,6 +427,7 @@ char * +diff -up openssh-5.3p1/configure.ac.mls openssh-5.3p1/configure.ac +--- openssh-5.3p1/configure.ac.mls 2009-10-02 14:04:31.000000000 +0200 ++++ openssh-5.3p1/configure.ac 2009-10-02 14:04:31.000000000 +0200 +@@ -3404,6 +3404,7 @@ AC_ARG_WITH(selinux, + SSHDLIBS="$SSHDLIBS $LIBSELINUX" + LIBS="$LIBS $LIBSELINUX" + AC_CHECK_FUNCS(getseuserbyname get_default_context_with_level) ++ AC_CHECK_FUNCS(setkeycreatecon) + LIBS="$save_LIBS" + fi ] + ) +diff -up openssh-5.3p1/misc.c.mls openssh-5.3p1/misc.c +--- openssh-5.3p1/misc.c.mls 2009-02-21 22:47:02.000000000 +0100 ++++ openssh-5.3p1/misc.c 2009-10-02 14:04:31.000000000 +0200 +@@ -423,6 +423,7 @@ char * colon(char *cp) { int flag = 0; @@ -9,7 +20,7 @@ diff -up openssh-5.1p1/misc.c.mls openssh-5.1p1/misc.c if (*cp == ':') /* Leading colon is part of file name. */ return (0); -@@ -440,8 +441,13 @@ colon(char *cp) +@@ -436,8 +437,13 @@ colon(char *cp) return (cp+1); if (*cp == ':' && !flag) return (cp); @@ -25,23 +36,9 @@ diff -up openssh-5.1p1/misc.c.mls openssh-5.1p1/misc.c } return (0); } -diff -up openssh-5.1p1/session.c.mls openssh-5.1p1/session.c ---- openssh-5.1p1/session.c.mls 2008-06-16 15:29:18.000000000 +0200 -+++ openssh-5.1p1/session.c 2008-07-23 18:53:37.000000000 +0200 -@@ -1550,10 +1550,6 @@ do_setusercontext(struct passwd *pw) - #endif - if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) - fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); -- --#ifdef WITH_SELINUX -- ssh_selinux_setup_exec_context(pw->pw_name); --#endif - } - - static void -diff -up openssh-5.1p1/openbsd-compat/port-linux.c.mls openssh-5.1p1/openbsd-compat/port-linux.c ---- openssh-5.1p1/openbsd-compat/port-linux.c.mls 2008-07-23 18:53:37.000000000 +0200 -+++ openssh-5.1p1/openbsd-compat/port-linux.c 2008-07-23 18:53:37.000000000 +0200 +diff -up openssh-5.3p1/openbsd-compat/port-linux.c.mls openssh-5.3p1/openbsd-compat/port-linux.c +--- openssh-5.3p1/openbsd-compat/port-linux.c.mls 2009-10-02 14:04:31.000000000 +0200 ++++ openssh-5.3p1/openbsd-compat/port-linux.c 2009-10-02 14:04:31.000000000 +0200 @@ -33,12 +33,23 @@ #include "key.h" #include "hostfile.h" @@ -419,20 +416,23 @@ diff -up openssh-5.1p1/openbsd-compat/port-linux.c.mls openssh-5.1p1/openbsd-com /* XXX: should these calls fatal() upon failure in enforcing mode? */ -diff -up openssh-5.1p1/configure.ac.mls openssh-5.1p1/configure.ac ---- openssh-5.1p1/configure.ac.mls 2008-07-23 18:53:37.000000000 +0200 -+++ openssh-5.1p1/configure.ac 2008-07-23 18:53:37.000000000 +0200 -@@ -3311,6 +3311,7 @@ AC_ARG_WITH(selinux, - SSHDLIBS="$SSHDLIBS $LIBSELINUX" - LIBS="$LIBS $LIBSELINUX" - AC_CHECK_FUNCS(getseuserbyname get_default_context_with_level) -+ AC_CHECK_FUNCS(setkeycreatecon) - LIBS="$save_LIBS" - fi ] - ) -diff -up openssh-5.1p1/sshd.c.mls openssh-5.1p1/sshd.c ---- openssh-5.1p1/sshd.c.mls 2008-07-23 18:53:37.000000000 +0200 -+++ openssh-5.1p1/sshd.c 2008-07-23 18:53:37.000000000 +0200 +diff -up openssh-5.3p1/session.c.mls openssh-5.3p1/session.c +--- openssh-5.3p1/session.c.mls 2009-08-20 08:20:50.000000000 +0200 ++++ openssh-5.3p1/session.c 2009-10-02 14:06:12.000000000 +0200 +@@ -1550,10 +1550,6 @@ do_setusercontext(struct passwd *pw) + + if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) + fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); +- +-#ifdef WITH_SELINUX +- ssh_selinux_setup_exec_context(pw->pw_name); +-#endif + } + + static void +diff -up openssh-5.3p1/sshd.c.mls openssh-5.3p1/sshd.c +--- openssh-5.3p1/sshd.c.mls 2009-10-02 14:04:31.000000000 +0200 ++++ openssh-5.3p1/sshd.c 2009-10-02 14:04:31.000000000 +0200 @@ -1896,6 +1896,9 @@ main(int ac, char **av) restore_uid(); } diff --git a/openssh-5.2p1-nss-keys.patch b/openssh-5.3p1-nss-keys.patch similarity index 99% rename from openssh-5.2p1-nss-keys.patch rename to openssh-5.3p1-nss-keys.patch index 24d6a59..dbf34cb 100644 --- a/openssh-5.2p1-nss-keys.patch +++ b/openssh-5.3p1-nss-keys.patch @@ -245,7 +245,7 @@ diff -up openssh-5.3p1/Makefile.in.nss-keys openssh-5.3p1/Makefile.in + entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o nsskeys.o SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ - sshconnect.o sshconnect1.o sshconnect2.o mux.o + sshconnect.o sshconnect1.o sshconnect2.o mux.o \ diff -up /dev/null openssh-5.3p1/nsskeys.c --- /dev/null 2009-09-11 09:35:58.778798825 +0200 +++ openssh-5.3p1/nsskeys.c 2009-10-02 14:09:01.000000000 +0200 diff --git a/openssh-5.3p1-pka.patch b/openssh-5.3p1-pka.patch new file mode 100644 index 0000000..be22083 --- /dev/null +++ b/openssh-5.3p1-pka.patch @@ -0,0 +1,440 @@ +diff -up openssh-5.3p1/auth2-pubkey.c.pka openssh-5.3p1/auth2-pubkey.c +--- openssh-5.3p1/auth2-pubkey.c.pka 2009-10-15 06:26:25.000000000 +0200 ++++ openssh-5.3p1/auth2-pubkey.c 2009-10-15 06:44:32.000000000 +0200 +@@ -184,26 +184,14 @@ done: + + /* return 1 if user allows given key */ + static int +-user_key_allowed2(struct passwd *pw, Key *key, char *file) ++user_search_key_in_file(FILE *f, char *file, Key* key, struct passwd *pw) + { + char line[SSH_MAX_PUBKEY_BYTES]; + int found_key = 0; +- FILE *f; + u_long linenum = 0; + Key *found; + char *fp; + +- /* Temporarily use the user's uid. */ +- temporarily_use_uid(pw); +- +- debug("trying public key file %s", file); +- f = auth_openkeyfile(file, pw, options.strict_modes); +- +- if (!f) { +- restore_uid(); +- return 0; +- } +- + found_key = 0; + found = key_new(key->type); + +@@ -248,21 +236,160 @@ user_key_allowed2(struct passwd *pw, Key + break; + } + } +- restore_uid(); +- fclose(f); + key_free(found); + if (!found_key) + debug2("key not found"); + return found_key; + } + +-/* check whether given key is in .ssh/authorized_keys* */ ++ ++/* return 1 if user allows given key */ ++static int ++user_key_allowed2(struct passwd *pw, Key *key, char *file) ++{ ++ FILE *f; ++ int found_key = 0; ++ ++ /* Temporarily use the user's uid. */ ++ temporarily_use_uid(pw); ++ ++ debug("trying public key file %s", file); ++ f = auth_openkeyfile(file, pw, options.strict_modes); ++ ++ if (f) { ++ found_key = user_search_key_in_file (f, file, key, pw); ++ fclose(f); ++ } ++ ++ restore_uid(); ++ return found_key; ++} ++ ++#ifdef WITH_PUBKEY_AGENT ++ ++#define WHITESPACE " \t\r\n" ++ ++/* return 1 if user allows given key */ ++static int ++user_key_via_agent_allowed2(struct passwd *pw, Key *key) ++{ ++ FILE *f; ++ int found_key = 0; ++ char *pubkey_agent_string = NULL; ++ char *tmp_pubkey_agent_string = NULL; ++ char *progname; ++ char *cp; ++ struct passwd *runas_pw; ++ struct stat st; ++ ++ if (options.pubkey_agent == NULL || options.pubkey_agent[0] != '/') ++ return -1; ++ ++ /* get the run as identity from config */ ++ runas_pw = (options.pubkey_agent_runas == NULL)? pw ++ : getpwnam (options.pubkey_agent_runas); ++ if (!runas_pw) { ++ error("%s: getpwnam(\"%s\"): %s", __func__, ++ options.pubkey_agent_runas, strerror(errno)); ++ return 0; ++ } ++ ++ /* Temporarily use the specified uid. */ ++ if (runas_pw->pw_uid != 0) ++ temporarily_use_uid(runas_pw); ++ ++ pubkey_agent_string = percent_expand(options.pubkey_agent, ++ "h", pw->pw_dir, "u", pw->pw_name, (char *)NULL); ++ ++ /* Test whether agent can be modified by non root user */ ++ tmp_pubkey_agent_string = xstrdup (pubkey_agent_string); ++ progname = strtok (tmp_pubkey_agent_string, WHITESPACE); ++ ++ debug3("%s: checking program '%s'", __func__, progname); ++ ++ if (stat (progname, &st) < 0) { ++ error("%s: stat(\"%s\"): %s", __func__, ++ progname, strerror(errno)); ++ goto go_away; ++ } ++ ++ if (st.st_uid != 0 || (st.st_mode & 022) != 0) { ++ error("bad ownership or modes for pubkey agent \"%s\"", ++ progname); ++ goto go_away; ++ } ++ ++ if (!S_ISREG(st.st_mode)) { ++ error("pubkey agent \"%s\" is not a regular file", ++ progname); ++ goto go_away; ++ } ++ ++ /* ++ * Descend the path, checking that each component is a ++ * root-owned directory with strict permissions. ++ */ ++ do { ++ if ((cp = strrchr(progname, '/')) == NULL) ++ break; ++ else ++ *cp = '\0'; ++ ++ debug3("%s: checking component '%s'", __func__, progname); ++ ++ if (stat(progname, &st) != 0) { ++ error("%s: stat(\"%s\"): %s", __func__, ++ progname, strerror(errno)); ++ goto go_away; ++ } ++ if (st.st_uid != 0 || (st.st_mode & 022) != 0) { ++ error("bad ownership or modes for pubkey agent path component \"%s\"", ++ progname); ++ goto go_away; ++ } ++ if (!S_ISDIR(st.st_mode)) { ++ error("pubkey agent path component \"%s\" is not a directory", ++ progname); ++ goto go_away; ++ } ++ } while (0); ++ ++ /* open the pipe and read the keys */ ++ f = popen (pubkey_agent_string, "r"); ++ if (!f) { ++ error("%s: popen (\"%s\", \"r\"): %s", __func__, ++ pubkey_agent_string, strerror (errno)); ++ goto go_away; ++ } ++ ++ found_key = user_search_key_in_file (f, options.pubkey_agent, key, pw); ++ pclose (f); ++ ++go_away: ++ if (tmp_pubkey_agent_string) ++ xfree (tmp_pubkey_agent_string); ++ if (pubkey_agent_string) ++ xfree (pubkey_agent_string); ++ ++ if (runas_pw->pw_uid != 0) ++ restore_uid(); ++ return found_key; ++} ++#endif ++ ++/* check whether given key is in = 0) ++ return success; ++#endif ++ + file = authorized_keys_file(pw); + success = user_key_allowed2(pw, key, file); + xfree(file); +diff -up openssh-5.3p1/configure.ac.pka openssh-5.3p1/configure.ac +--- openssh-5.3p1/configure.ac.pka 2009-10-15 06:26:25.000000000 +0200 ++++ openssh-5.3p1/configure.ac 2009-10-15 06:26:26.000000000 +0200 +@@ -1319,6 +1319,18 @@ AC_ARG_WITH(audit, + esac ] + ) + ++# Check whether user wants pubkey agent support ++PKA_MSG="no" ++AC_ARG_WITH(pka, ++ [ --with-pka Enable pubkey agent support], ++ [ ++ if test "x$withval" != "xno" ; then ++ AC_DEFINE([WITH_PUBKEY_AGENT], 1, [Enable pubkey agent support]) ++ PKA_MSG="yes" ++ fi ++ ] ++) ++ + dnl Checks for library functions. Please keep in alphabetical order + AC_CHECK_FUNCS( \ + arc4random \ +@@ -4264,6 +4276,7 @@ echo " Linux audit support + echo " Smartcard support: $SCARD_MSG" + echo " S/KEY support: $SKEY_MSG" + echo " TCP Wrappers support: $TCPW_MSG" ++echo " PKA support: $PKA_MSG" + echo " MD5 password support: $MD5_MSG" + echo " libedit support: $LIBEDIT_MSG" + echo " Solaris process contract support: $SPC_MSG" +diff -up openssh-5.3p1/configure.pka openssh-5.3p1/configure +--- openssh-5.3p1/configure.pka 2009-10-13 19:27:51.000000000 +0200 ++++ openssh-5.3p1/configure 2009-10-15 06:26:33.000000000 +0200 +@@ -769,6 +769,7 @@ with_skey + with_tcp_wrappers + with_libedit + with_audit ++with_pka + with_ssl_dir + with_openssl_header_check + with_ssl_engine +@@ -1473,6 +1474,7 @@ Optional Packages: + --with-tcp-wrappers[=PATH] Enable tcpwrappers support (optionally in PATH) + --with-libedit[=PATH] Enable libedit support for sftp + --with-audit=module Enable EXPERIMENTAL audit support (modules=debug,bsm) ++ --with-pka Enable pubkey agent support + --with-ssl-dir=PATH Specify path to OpenSSL installation + --without-openssl-header-check Disable OpenSSL version consistency check + --with-ssl-engine Enable OpenSSL (hardware) ENGINE support +@@ -13443,6 +13445,25 @@ $as_echo "$as_me: error: Unknown audit m + fi + + ++# Check whether user wants pubkey agent support ++PKA_MSG="no" ++ ++# Check whether --with-pka was given. ++if test "${with_pka+set}" = set; then ++ withval=$with_pka; ++ if test "x$withval" != "xno" ; then ++ ++cat >>confdefs.h <<\_ACEOF ++#define WITH_PUBKEY_AGENT 1 ++_ACEOF ++ ++ PKA_MSG="yes" ++ fi ++ ++ ++fi ++ ++ + + + +@@ -32772,6 +32793,7 @@ echo " Linux audit support + echo " Smartcard support: $SCARD_MSG" + echo " S/KEY support: $SKEY_MSG" + echo " TCP Wrappers support: $TCPW_MSG" ++echo " PKA support: $PKA_MSG" + echo " MD5 password support: $MD5_MSG" + echo " libedit support: $LIBEDIT_MSG" + echo " Solaris process contract support: $SPC_MSG" +diff -up openssh-5.3p1/servconf.c.pka openssh-5.3p1/servconf.c +--- openssh-5.3p1/servconf.c.pka 2009-10-15 06:26:24.000000000 +0200 ++++ openssh-5.3p1/servconf.c 2009-10-15 06:26:26.000000000 +0200 +@@ -128,6 +128,8 @@ initialize_server_options(ServerOptions + options->num_permitted_opens = -1; + options->adm_forced_command = NULL; + options->chroot_directory = NULL; ++ options->pubkey_agent = NULL; ++ options->pubkey_agent_runas = NULL; + options->zero_knowledge_password_authentication = -1; + } + +@@ -310,6 +312,7 @@ typedef enum { + sMatch, sPermitOpen, sForceCommand, sChrootDirectory, + sUsePrivilegeSeparation, sAllowAgentForwarding, + sZeroKnowledgePasswordAuthentication, ++ sPubkeyAgent, sPubkeyAgentRunAs, + sDeprecated, sUnsupported + } ServerOpCodes; + +@@ -429,6 +432,13 @@ static struct { + { "permitopen", sPermitOpen, SSHCFG_ALL }, + { "forcecommand", sForceCommand, SSHCFG_ALL }, + { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, ++#ifdef WITH_PUBKEY_AGENT ++ { "pubkeyagent", sPubkeyAgent, SSHCFG_ALL }, ++ { "pubkeyagentrunas", sPubkeyAgentRunAs, SSHCFG_ALL }, ++#else ++ { "pubkeyagent", sUnsupported, SSHCFG_ALL }, ++ { "pubkeyagentrunas", sUnsupported, SSHCFG_ALL }, ++#endif + { NULL, sBadOption, 0 } + }; + +@@ -1303,6 +1313,16 @@ process_server_config_line(ServerOptions + *charptr = xstrdup(arg); + break; + ++ case sPubkeyAgent: ++ len = strspn(cp, WHITESPACE); ++ if (*activep && options->pubkey_agent == NULL) ++ options->pubkey_agent = xstrdup(cp + len); ++ return 0; ++ ++ case sPubkeyAgentRunAs: ++ charptr = &options->pubkey_agent_runas; ++ break; ++ + case sDeprecated: + logit("%s line %d: Deprecated option %s", + filename, linenum, arg); +@@ -1396,6 +1416,8 @@ copy_set_server_options(ServerOptions *d + M_CP_INTOPT(gss_authentication); + M_CP_INTOPT(rsa_authentication); + M_CP_INTOPT(pubkey_authentication); ++ M_CP_STROPT(pubkey_agent); ++ M_CP_STROPT(pubkey_agent_runas); + M_CP_INTOPT(kerberos_authentication); + M_CP_INTOPT(hostbased_authentication); + M_CP_INTOPT(kbd_interactive_authentication); +@@ -1636,6 +1658,10 @@ dump_config(ServerOptions *o) + dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file); + dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2); + dump_cfg_string(sForceCommand, o->adm_forced_command); ++#ifdef WITH_PUBKEY_AGENT ++ dump_cfg_string(sPubkeyAgent, o->pubkey_agent); ++ dump_cfg_string(sPubkeyAgentRunAs, o->pubkey_agent_runas); ++#endif + + /* string arguments requiring a lookup */ + dump_cfg_string(sLogLevel, log_level_name(o->log_level)); +diff -up openssh-5.3p1/servconf.h.pka openssh-5.3p1/servconf.h +--- openssh-5.3p1/servconf.h.pka 2009-10-15 06:26:24.000000000 +0200 ++++ openssh-5.3p1/servconf.h 2009-10-15 06:26:26.000000000 +0200 +@@ -152,6 +152,8 @@ typedef struct { + int num_permitted_opens; + + char *chroot_directory; ++ char *pubkey_agent; ++ char *pubkey_agent_runas; + } ServerOptions; + + void initialize_server_options(ServerOptions *); +diff -up openssh-5.3p1/sshd_config.0.pka openssh-5.3p1/sshd_config.0 +--- openssh-5.3p1/sshd_config.0.pka 2009-10-15 06:26:24.000000000 +0200 ++++ openssh-5.3p1/sshd_config.0 2009-10-15 06:26:26.000000000 +0200 +@@ -344,10 +344,11 @@ DESCRIPTION + AllowTcpForwarding, Banner, ChrootDirectory, ForceCommand, + GatewayPorts, GSSAPIAuthentication, HostbasedAuthentication, + KbdInteractiveAuthentication, KerberosAuthentication, +- MaxAuthTries, MaxSessions, PasswordAuthentication, +- PermitEmptyPasswords, PermitOpen, PermitRootLogin, +- RhostsRSAAuthentication, RSAAuthentication, X11DisplayOffset, +- X11Forwarding and X11UseLocalHost. ++ MaxAuthTries, MaxSessions, PubkeyAuthentication, PubkeyAgent, ++ PubkeyAgentRunAs, PasswordAuthentication, PermitEmptyPasswords, ++ PermitOpen, PermitRootLogin, RhostsRSAAuthentication, ++ RSAAuthentication, X11DisplayOffset, X11Forwarding and ++ X11UseLocalHost. + + MaxAuthTries + Specifies the maximum number of authentication attempts permitted +@@ -455,6 +456,17 @@ DESCRIPTION + fault is ``yes''. Note that this option applies to protocol ver- + sion 2 only. + ++ PubkeyAgent ++ Specifies which agent is used for lookup of the user's public ++ keys. Empty string means to use the authorized_keys file. By ++ default there is no PubkeyAgent set. Note that this option has ++ an effect only with PubkeyAuthentication switched on. ++ ++ PubkeyAgentRunAs ++ Specifies the user under whose account the PubkeyAgent is run. ++ Empty string (the default value) means the user being authorized ++ is used. ++ + RhostsRSAAuthentication + Specifies whether rhosts or /etc/hosts.equiv authentication to- + gether with successful RSA host authentication is allowed. The +diff -up openssh-5.3p1/sshd_config.5.pka openssh-5.3p1/sshd_config.5 +--- openssh-5.3p1/sshd_config.5.pka 2009-10-15 06:26:24.000000000 +0200 ++++ openssh-5.3p1/sshd_config.5 2009-10-15 06:26:26.000000000 +0200 +@@ -610,6 +610,9 @@ Available keywords are + .Cm KerberosAuthentication , + .Cm MaxAuthTries , + .Cm MaxSessions , ++.Cm PubkeyAuthentication , ++.Cm PubkeyAgent , ++.Cm PubkeyAgentRunAs , + .Cm PasswordAuthentication , + .Cm PermitEmptyPasswords , + .Cm PermitOpen , +@@ -805,6 +808,16 @@ Specifies whether public key authenticat + The default is + .Dq yes . + Note that this option applies to protocol version 2 only. ++.It Cm PubkeyAgent ++Specifies which agent is used for lookup of the user's public ++keys. Empty string means to use the authorized_keys file. ++By default there is no PubkeyAgent set. ++Note that this option has an effect only with PubkeyAuthentication ++switched on. ++.It Cm PubkeyAgentRunAs ++Specifies the user under whose account the PubkeyAgent is run. Empty ++string (the default value) means the user being authorized is used. ++.Dq + .It Cm RhostsRSAAuthentication + Specifies whether rhosts or /etc/hosts.equiv authentication together + with successful RSA host authentication is allowed. +diff -up openssh-5.3p1/sshd_config.pka openssh-5.3p1/sshd_config +--- openssh-5.3p1/sshd_config.pka 2009-10-15 06:26:24.000000000 +0200 ++++ openssh-5.3p1/sshd_config 2009-10-15 06:26:26.000000000 +0200 +@@ -47,6 +47,8 @@ SyslogFacility AUTHPRIV + #RSAAuthentication yes + #PubkeyAuthentication yes + #AuthorizedKeysFile .ssh/authorized_keys ++#PubkeyAgent none ++#PubkeyAgentRunAs nobody + + # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts + #RhostsRSAAuthentication no diff --git a/openssh-5.2p1-selabel.patch b/openssh-5.3p1-selabel.patch similarity index 67% rename from openssh-5.2p1-selabel.patch rename to openssh-5.3p1-selabel.patch index 06ccffe..6e5d6bd 100644 --- a/openssh-5.2p1-selabel.patch +++ b/openssh-5.3p1-selabel.patch @@ -1,6 +1,6 @@ -diff -up openssh-5.2p1/contrib/ssh-copy-id.selabel openssh-5.2p1/contrib/ssh-copy-id ---- openssh-5.2p1/contrib/ssh-copy-id.selabel 2009-01-21 10:29:21.000000000 +0100 -+++ openssh-5.2p1/contrib/ssh-copy-id 2009-07-08 14:28:27.000000000 +0200 +diff -up openssh-5.3p1/contrib/ssh-copy-id.selabel openssh-5.3p1/contrib/ssh-copy-id +--- openssh-5.3p1/contrib/ssh-copy-id.selabel 2009-01-21 10:29:21.000000000 +0100 ++++ openssh-5.3p1/contrib/ssh-copy-id 2009-10-02 14:21:54.000000000 +0200 @@ -38,7 +38,7 @@ if [ "$#" -lt 1 ] || [ "$1" = "-h" ] || exit 1 fi @@ -10,10 +10,10 @@ diff -up openssh-5.2p1/contrib/ssh-copy-id.selabel openssh-5.2p1/contrib/ssh-cop cat < #include @@ -33,7 +33,7 @@ diff -up openssh-5.2p1/ssh.c.selabel openssh-5.2p1/ssh.c #include "openbsd-compat/openssl-compat.h" #include "openbsd-compat/sys-queue.h" -@@ -791,10 +792,15 @@ main(int ac, char **av) +@@ -792,10 +793,15 @@ main(int ac, char **av) */ r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); diff --git a/openssh-5.3p1-skip-initial.patch b/openssh-5.3p1-skip-initial.patch new file mode 100644 index 0000000..d52962e --- /dev/null +++ b/openssh-5.3p1-skip-initial.patch @@ -0,0 +1,24 @@ +diff -up openssh-5.3p1/auth1.c.skip-initial openssh-5.3p1/auth1.c +--- openssh-5.3p1/auth1.c.skip-initial 2009-03-08 01:40:28.000000000 +0100 ++++ openssh-5.3p1/auth1.c 2009-10-02 13:55:00.000000000 +0200 +@@ -244,7 +244,7 @@ do_authloop(Authctxt *authctxt) + authctxt->valid ? "" : "invalid user ", authctxt->user); + + /* If the user has no password, accept authentication immediately. */ +- if (options.password_authentication && ++ if (options.permit_empty_passwd && options.password_authentication && + #ifdef KRB5 + (!options.kerberos_authentication || options.kerberos_or_local_passwd) && + #endif +diff -up openssh-5.3p1/auth2-none.c.skip-initial openssh-5.3p1/auth2-none.c +--- openssh-5.3p1/auth2-none.c.skip-initial 2009-03-08 01:40:28.000000000 +0100 ++++ openssh-5.3p1/auth2-none.c 2009-10-02 13:56:21.000000000 +0200 +@@ -61,7 +61,7 @@ userauth_none(Authctxt *authctxt) + { + none_enabled = 0; + packet_check_eom(); +- if (options.password_authentication) ++ if (options.permit_empty_passwd && options.password_authentication) + return (PRIVSEP(auth_password(authctxt, ""))); + return (0); + } diff --git a/openssh.spec b/openssh.spec index 0ccf858..ed72c0a 100644 --- a/openssh.spec +++ b/openssh.spec @@ -32,6 +32,9 @@ # Whether or not /sbin/nologin exists. %define nologin 1 +# Whether to build pam_ssh_agent_auth +%define pam_ssh_agent 1 + # Reserve options to override askpass settings with: # rpm -ba|--rebuild --define 'skip_xxx 1' %{?skip_gnome_askpass:%define no_gnome_askpass 1} @@ -58,13 +61,17 @@ %if %{rescue} %define kerberos5 0 %define libedit 0 +%define pam_ssh_agent 0 %endif +%define pam_ssh_agent_ver 0.9 + Summary: An open source implementation of SSH protocol versions 1 and 2 Name: openssh -Version: 5.2p1 -Release: 31%{?dist}%{?rescue_rel} +Version: 5.3p1 +Release: 9%{?dist}%{?rescue_rel} URL: http://www.openssh.com/portable.html +#URL1: http://pamsshauth.sourceforge.net #Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz #Source1: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz.asc # This package differs from the upstream OpenSSH tarball in that @@ -74,13 +81,15 @@ Source0: openssh-%{version}-noacss.tar.bz2 Source1: openssh-nukeacss.sh Source2: sshd.pam Source3: sshd.init +Source4: http://prdownloads.sourceforge.net/pamsshagentauth/pam_ssh_agent_auth/pam_ssh_agent_auth-%{pam_ssh_agent_ver}.tar.bz2 +Source5: pam_ssh_agent-rmheaders Patch0: openssh-5.2p1-redhat.patch -Patch2: openssh-5.1p1-skip-initial.patch -Patch3: openssh-3.8.1p1-krb5-config.patch +Patch2: openssh-5.3p1-skip-initial.patch Patch4: openssh-5.2p1-vendor.patch +Patch10: pam_ssh_agent_auth-0.9-build.patch Patch12: openssh-5.2p1-selinux.patch -Patch13: openssh-5.1p1-mls.patch -Patch16: openssh-4.7p1-audit.patch +Patch13: openssh-5.3p1-mls.patch +Patch16: openssh-5.3p1-audit.patch Patch18: openssh-5.0p1-pam_selinux.patch Patch19: openssh-5.2p1-sesftp.patch Patch22: openssh-3.9p1-askpass-keep-above.patch @@ -92,13 +101,14 @@ Patch38: openssh-4.3p2-askpass-grab-info.patch Patch39: openssh-4.3p2-no-v6only.patch Patch44: openssh-5.2p1-allow-ip-opts.patch Patch49: openssh-4.3p2-gssapi-canohost.patch -Patch51: openssh-5.2p1-nss-keys.patch +Patch51: openssh-5.3p1-nss-keys.patch Patch55: openssh-5.1p1-cloexec.patch Patch62: openssh-5.1p1-scp-manpage.patch -Patch65: openssh-5.2p1-fips.patch -Patch68: openssh-5.2p1-pathmax.patch -Patch69: openssh-5.2p1-selabel.patch +Patch65: openssh-5.3p1-fips.patch +Patch69: openssh-5.3p1-selabel.patch Patch71: openssh-5.2p1-edns.patch +Patch72: openssh-5.3p1-pka.patch +Patch73: openssh-5.3p1-gsskex.patch License: BSD Group: Applications/Internet @@ -170,6 +180,14 @@ Requires: openssh = %{version}-%{release} Obsoletes: openssh-askpass-gnome Provides: openssh-askpass-gnome +%package -n pam_ssh_agent_auth +Summary: PAM module for authentication with ssh-agent +Group: System Environment/Base +Version: %{pam_ssh_agent_ver} +# There is special exception added to the GPLv3+ license to +# permit linking with OpenSSL licensed code +License: GPLv3+ and OpenSSL and BSD + %description SSH (Secure SHell) is a program for logging into and executing commands on a remote machine. SSH is intended to replace rlogin and @@ -200,13 +218,28 @@ OpenSSH is a free version of SSH (Secure SHell), a program for logging into and executing commands on a remote machine. This package contains an X11 passphrase dialog for OpenSSH. +%description -n pam_ssh_agent_auth +This package contains a PAM module which can be used to authenticate +users using ssh keys stored in a ssh-agent. Through the use of the +forwarding of ssh-agent connection it also allows to authenticate with +remote ssh-agent instance. + +The module is most useful for su and sudo service stacks. + %prep -%setup -q +%setup -q -a 4 %patch0 -p1 -b .redhat %patch2 -p1 -b .skip-initial -%patch3 -p1 -b .krb5-config %patch4 -p1 -b .vendor +%if %{pam_ssh_agent} +pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver} +%patch10 -p1 -b .psaa-build +# Remove duplicate headers +rm -f $(cat %{SOURCE5}) +popd +%endif + %if %{WITH_SELINUX} #SELinux %patch12 -p1 -b .selinux @@ -229,9 +262,10 @@ an X11 passphrase dialog for OpenSSH. %patch55 -p1 -b .cloexec %patch62 -p1 -b .manpage %patch65 -p1 -b .fips -%patch68 -p1 -b .pathmax %patch69 -p1 -b .selabel %patch71 -p1 -b .edns +%patch72 -p1 -b .pka +%patch73 -p1 -b .gsskex autoreconf @@ -242,11 +276,12 @@ CFLAGS="$CFLAGS -Os" %endif %if %{pie} %ifarch s390 s390x sparc sparcv9 sparc64 -CFLAGS="$CFLAGS -fPIE" +CFLAGS="$CFLAGS -fPIC" %else -CFLAGS="$CFLAGS -fpie" +CFLAGS="$CFLAGS -fpic" %endif export CFLAGS +SAVE_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -pie"; export LDFLAGS %endif %if %{kerberos5} @@ -326,6 +361,14 @@ fi popd %endif +%if %{pam_ssh_agent} +pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver} +LDFLAGS="$SAVE_LDFLAGS" +%configure --with-selinux --libexecdir=/%{_lib}/security +make +popd +%endif + # Add generation of HMAC checksums of the final stripped binaries %define __spec_install_post \ %{?__debug_package:%{__debug_install_post}} \ @@ -375,6 +418,12 @@ rm -f README.nss.nss-keys %if ! %{nss} rm -f README.nss %endif + +%if %{pam_ssh_agent} +pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver} +make install DESTDIR=$RPM_BUILD_ROOT +popd +%endif %clean rm -rf $RPM_BUILD_ROOT @@ -465,14 +514,42 @@ fi %attr(0755,root,root) %{_libexecdir}/openssh/ssh-askpass %endif +%if %{pam_ssh_agent} +%files -n pam_ssh_agent_auth +%defattr(-,root,root) +%doc pam_ssh_agent_auth-%{pam_ssh_agent_ver}/GPL_LICENSE +%doc pam_ssh_agent_auth-%{pam_ssh_agent_ver}/OPENSSH_LICENSE +%doc pam_ssh_agent_auth-%{pam_ssh_agent_ver}/LICENSE.OpenSSL +%attr(0755,root,root) /%{_lib}/security/pam_ssh_agent_auth.so +%attr(0644,root,root) %{_mandir}/man8/pam_ssh_agent_auth.8* +%endif + %changelog -* Mon Nov 2 2009 Jan F. Chadima - 5.2p1-31 +* Fri Nov 20 2009 Jan F. Chadima - 5.3p1-8 +- Add gssapi key exchange patch (#455351) + +* Fri Nov 20 2009 Jan F. Chadima - 5.3p1-8 +- Add public key agent patch (#455350) + +* Mon Nov 2 2009 Jan F. Chadima - 5.3p1-7 - Repair canohost patch to allow gssapi to work when host is acessed via pipe proxy (#531849) -* Thu Oct 29 2009 Jan F. Chadima - 5.2p1-30 +* Thu Oct 29 2009 Jan F. Chadima - 5.3p1-6 - Modify the init script to prevent it to hang during generating the keys (#515145) -* Tue Oct 27 2009 Jan F. Chadima - 5.2p1-29 +* Tue Oct 27 2009 Jan F. Chadima - 5.3p1-5 +- Add README.nss + +* Mon Oct 19 2009 Tomas Mraz - 5.3p1-4 +- Add pam_ssh_agent_auth module to a subpackage. + +* Fri Oct 16 2009 Jan F. Chadima - 5.3p1-3 +- Reenable audit. + +* Fri Oct 2 2009 Jan F. Chadima - 5.3p1-2 +- Upgrade to new wersion 5.3p1 + +* Tue Sep 29 2009 Jan F. Chadima - 5.2p1-29 - Resolve locking in ssh-add (#491312) * Thu Sep 24 2009 Jan F. Chadima - 5.2p1-28 diff --git a/pam_ssh_agent-rmheaders b/pam_ssh_agent-rmheaders new file mode 100644 index 0000000..5f036cc --- /dev/null +++ b/pam_ssh_agent-rmheaders @@ -0,0 +1,20 @@ +atomicio.h +authfd.h +buffer.h +cipher.h +compat.h +defines.h +entropy.h +includes.h +kex.h +key.h +log.h +match.h +misc.h +pathnames.h +platform.h +rsa.h +ssh.h +ssh2.h +uuencode.h +xmalloc.h diff --git a/pam_ssh_agent_auth-0.9-build.patch b/pam_ssh_agent_auth-0.9-build.patch new file mode 100644 index 0000000..ddacff6 --- /dev/null +++ b/pam_ssh_agent_auth-0.9-build.patch @@ -0,0 +1,190 @@ +diff -up pam_ssh_agent_auth-0.9/iterate_ssh_agent_keys.c.psaa-build pam_ssh_agent_auth-0.9/iterate_ssh_agent_keys.c +--- pam_ssh_agent_auth-0.9/iterate_ssh_agent_keys.c.psaa-build 2009-08-08 11:51:04.000000000 +0200 ++++ pam_ssh_agent_auth-0.9/iterate_ssh_agent_keys.c 2009-10-16 15:20:55.000000000 +0200 +@@ -41,7 +41,16 @@ + #include "buffer.h" + #include "key.h" + #include "authfd.h" ++#include "ssh.h" + #include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + #include + + #include "userauth_pubkey_from_id.h" +@@ -73,6 +82,96 @@ session_id2_gen() + return cookie; + } + ++/* ++ * Added by Jamie Beverly, ensure socket fd points to a socket owned by the user ++ * A cursory check is done, but to avoid race conditions, it is necessary ++ * to drop effective UID when connecting to the socket. ++ * ++ * If the cause of error is EACCES, because we verified we would not have that ++ * problem initially, we can safely assume that somebody is attempting to find a ++ * race condition; so a more "direct" log message is generated. ++ */ ++ ++int ++ssh_get_authentication_socket_for_uid(uid_t uid) ++{ ++ const char *authsocket; ++ int sock; ++ struct sockaddr_un sunaddr; ++ struct stat sock_st; ++ ++ authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); ++ if (!authsocket) ++ return -1; ++ ++ /* Advisory only; seteuid ensures no race condition; but will only log if we see EACCES */ ++ if( stat(authsocket,&sock_st) == 0) { ++ if(uid != 0 && sock_st.st_uid != uid) { ++ fatal("uid %lu attempted to open an agent socket owned by uid %lu", (unsigned long) uid, (unsigned long) sock_st.st_uid); ++ return -1; ++ } ++ } ++ ++ /* ++ * Ensures that the EACCES tested for below can _only_ happen if somebody ++ * is attempting to race the stat above to bypass authentication. ++ */ ++ if( (sock_st.st_mode & S_IWUSR) != S_IWUSR || (sock_st.st_mode & S_IRUSR) != S_IRUSR) { ++ error("ssh-agent socket has incorrect permissions for owner"); ++ return -1; ++ } ++ ++ sunaddr.sun_family = AF_UNIX; ++ strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); ++ ++ sock = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (sock < 0) ++ return -1; ++ ++ /* close on exec */ ++ if (fcntl(sock, F_SETFD, 1) == -1) { ++ close(sock); ++ return -1; ++ } ++ ++ errno = 0; ++ seteuid(uid); /* To ensure a race condition is not used to circumvent the stat ++ above, we will temporarily drop UID to the caller */ ++ if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { ++ close(sock); ++ if(errno == EACCES) ++ fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); ++ return -1; ++ } ++ ++ seteuid(0); /* we now continue the regularly scheduled programming */ ++ ++ return sock; ++} ++ ++AuthenticationConnection * ++ssh_get_authentication_connection_for_uid(uid_t uid) ++{ ++ AuthenticationConnection *auth; ++ int sock; ++ ++ sock = ssh_get_authentication_socket_for_uid(uid); ++ ++ /* ++ * Fail if we couldn't obtain a connection. This happens if we ++ * exited due to a timeout. ++ */ ++ if (sock < 0) ++ return NULL; ++ ++ auth = xmalloc(sizeof(*auth)); ++ auth->fd = sock; ++ buffer_init(&auth->identities); ++ auth->howmany = 0; ++ ++ return auth; ++} ++ + int + find_authorized_keys(uid_t uid) + { +@@ -85,7 +184,7 @@ find_authorized_keys(uid_t uid) + OpenSSL_add_all_digests(); + session_id2 = session_id2_gen(); + +- if ((ac = ssh_get_authentication_connection(uid))) { ++ if ((ac = ssh_get_authentication_connection_for_uid(uid))) { + verbose("Contacted ssh-agent of user %s (%u)", getpwuid(uid)->pw_name, uid); + for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) + { +@@ -113,3 +212,4 @@ find_authorized_keys(uid_t uid) + EVP_cleanup(); + return retval; + } ++ +diff -up pam_ssh_agent_auth-0.9/Makefile.in.psaa-build pam_ssh_agent_auth-0.9/Makefile.in +--- pam_ssh_agent_auth-0.9/Makefile.in.psaa-build 2009-08-06 07:40:16.000000000 +0200 ++++ pam_ssh_agent_auth-0.9/Makefile.in 2009-10-16 15:20:55.000000000 +0200 +@@ -28,7 +28,7 @@ PATHS= + CC=@CC@ + LD=@LD@ + CFLAGS=@CFLAGS@ +-CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ ++CPPFLAGS=-I.. -I$(srcdir) -I/usr/include/nss3 -I/usr/include/nspr4 @CPPFLAGS@ $(PATHS) @DEFS@ + LIBS=@LIBS@ + AR=@AR@ + AWK=@AWK@ +@@ -37,7 +37,7 @@ INSTALL=@INSTALL@ + PERL=@PERL@ + SED=@SED@ + ENT=@ENT@ +-LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ ++LDFLAGS=-L.. -L../openbsd-compat/ @LDFLAGS@ + LDFLAGS_SHARED = @LDFLAGS_SHARED@ + EXEEXT=@EXEEXT@ + +@@ -48,7 +48,7 @@ PAM_MODULES=pam_ssh_agent_auth.so + + SSHOBJS=xmalloc.o atomicio.o authfd.o bufaux.o bufbn.o buffer.o cleanup.o entropy.o fatal.o key.o log.o misc.o secure_filename.o ssh-dss.o ssh-rsa.o uuencode.o compat.o + +-PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o ++PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o secure_filename.o + + + MANPAGES_IN = pam_ssh_agent_auth.pod +@@ -67,13 +67,13 @@ $(PAM_MODULES): Makefile.in config.h + .c.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< + +-LIBCOMPAT=openbsd-compat/libopenbsd-compat.a ++LIBCOMPAT=../openbsd-compat/libopenbsd-compat.a + $(LIBCOMPAT): always + (cd openbsd-compat && $(MAKE)) + always: + +-pam_ssh_agent_auth.so: $(LIBCOMPAT) $(SSHOBJS) $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o +- $(LD) $(LDFLAGS_SHARED) -o $@ $(SSHOBJS) $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lopenbsd-compat $(LIBS) -lpam pam_ssh_agent_auth.o ++pam_ssh_agent_auth.so: $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o ++ $(LD) $(LDFLAGS_SHARED) -o $@ $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -lpam -lnss3 pam_ssh_agent_auth.o + + $(MANPAGES): $(MANPAGES_IN) + pod2man --section=8 --release=v0.8 --name=pam_ssh_agent_auth --official --center "PAM" pam_ssh_agent_auth.pod > pam_ssh_agent_auth.8 +diff -up pam_ssh_agent_auth-0.9/pam_user_authorized_keys.c.psaa-build pam_ssh_agent_auth-0.9/pam_user_authorized_keys.c +--- pam_ssh_agent_auth-0.9/pam_user_authorized_keys.c.psaa-build 2009-07-29 02:46:38.000000000 +0200 ++++ pam_ssh_agent_auth-0.9/pam_user_authorized_keys.c 2009-10-16 15:50:36.000000000 +0200 +@@ -94,7 +94,7 @@ parse_authorized_key_file(const char *us + /* + * temporary copy, so that both tilde expansion and percent expansion both get to apply to the path + */ +- strncat(auth_keys_file_buf, authorized_keys_file_input, 4096); ++ strncat(auth_keys_file_buf, authorized_keys_file_input, sizeof(auth_keys_file_buf)-1); + + if(allow_user_owned_authorized_keys_file) + authorized_keys_file_allowed_owner_uid = getpwnam(user)->pw_uid; diff --git a/sources b/sources index 128c867..add7e47 100644 --- a/sources +++ b/sources @@ -1 +1,2 @@ -41c61b5e2c2cddfd53897582b114ffe1 openssh-5.2p1-noacss.tar.bz2 +89f85c1da83c24ca0b10c05344f7c93c openssh-5.3p1-noacss.tar.bz2 +1868cb825393678489b1d48c97819f76 pam_ssh_agent_auth-0.9.tar.bz2