summaryrefslogtreecommitdiff
path: root/debian/patches
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/authorized-keys-man-symlink.patch18
-rw-r--r--debian/patches/debian-banner.patch99
-rw-r--r--debian/patches/debian-config.patch146
-rw-r--r--debian/patches/dnssec-sshfp.patch82
-rw-r--r--debian/patches/doc-hash-tab-completion.patch20
-rw-r--r--debian/patches/gnome-ssh-askpass2-icon.patch18
-rw-r--r--debian/patches/gssapi-autoconf.patch29
-rw-r--r--debian/patches/gssapi.patch3045
-rw-r--r--debian/patches/helpful-wait-terminate.patch18
-rw-r--r--debian/patches/keepalive-extensions.patch124
-rw-r--r--debian/patches/lintian-symlink-pickiness.patch23
-rw-r--r--debian/patches/openbsd-docs.patch117
-rw-r--r--debian/patches/package-versioning.patch50
-rw-r--r--debian/patches/quieter-signals.patch31
-rw-r--r--debian/patches/scp-quoting.patch32
-rw-r--r--debian/patches/selinux-build-failure.patch236
-rw-r--r--debian/patches/selinux-role.patch482
-rw-r--r--debian/patches/series44
-rw-r--r--debian/patches/shell-path.patch30
-rw-r--r--debian/patches/ssh-argv0.patch21
-rw-r--r--debian/patches/ssh-vulnkey.patch1385
-rw-r--r--debian/patches/ssh1-keepalive.patch65
-rw-r--r--debian/patches/syslog-level-silent.patch37
-rw-r--r--debian/patches/user-group-modes.patch202
24 files changed, 6354 insertions, 0 deletions
diff --git a/debian/patches/authorized-keys-man-symlink.patch b/debian/patches/authorized-keys-man-symlink.patch
new file mode 100644
index 000000000..86b269659
--- /dev/null
+++ b/debian/patches/authorized-keys-man-symlink.patch
@@ -0,0 +1,18 @@
1Description: Install authorized_keys(5) as a symlink to sshd(8)
2Author: Tomas Pospisek <tpo_deb@sourcepole.ch>
3Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1720
4Bug-Debian: http://bugs.debian.org/441817
5Last-Update: 2010-03-01
6
7Index: b/Makefile.in
8===================================================================
9--- a/Makefile.in
10+++ b/Makefile.in
11@@ -288,6 +288,7 @@
12 $(INSTALL) -m 644 sshd_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/sshd_config.5
13 $(INSTALL) -m 644 ssh_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh_config.5
14 $(INSTALL) -m 644 sshd.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
15+ ln -s ../$(mansubdir)8/sshd.8 $(DESTDIR)$(mandir)/$(mansubdir)5/authorized_keys.5
16 if [ ! -z "$(INSTALL_SSH_RAND_HELPER)" ]; then \
17 $(INSTALL) -m 644 ssh-rand-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-rand-helper.8 ; \
18 fi
diff --git a/debian/patches/debian-banner.patch b/debian/patches/debian-banner.patch
new file mode 100644
index 000000000..32251397d
--- /dev/null
+++ b/debian/patches/debian-banner.patch
@@ -0,0 +1,99 @@
1Description: Add DebianBanner server configuration option
2 Setting this to "no" causes sshd to omit the Debian revision from its
3 initial protocol handshake, for those scared by package-versioning.patch.
4Author: Kees Cook <kees@debian.org>
5Bug-Debian: http://bugs.debian.org/562048
6Forwarded: not-needed
7Last-Update: 2010-02-28
8
9Index: b/servconf.c
10===================================================================
11--- a/servconf.c
12+++ b/servconf.c
13@@ -143,6 +143,7 @@
14 options->authorized_principals_file = NULL;
15 options->ip_qos_interactive = -1;
16 options->ip_qos_bulk = -1;
17+ options->debian_banner = -1;
18 }
19
20 void
21@@ -293,6 +294,8 @@
22 options->ip_qos_interactive = IPTOS_LOWDELAY;
23 if (options->ip_qos_bulk == -1)
24 options->ip_qos_bulk = IPTOS_THROUGHPUT;
25+ if (options->debian_banner == -1)
26+ options->debian_banner = 1;
27
28 /* Turn privilege separation on by default */
29 if (use_privsep == -1)
30@@ -342,6 +345,7 @@
31 sZeroKnowledgePasswordAuthentication, sHostCertificate,
32 sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
33 sKexAlgorithms, sIPQoS,
34+ sDebianBanner,
35 sDeprecated, sUnsupported
36 } ServerOpCodes;
37
38@@ -477,6 +481,7 @@
39 { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
40 { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
41 { "ipqos", sIPQoS, SSHCFG_ALL },
42+ { "debianbanner", sDebianBanner, SSHCFG_GLOBAL },
43 { NULL, sBadOption, 0 }
44 };
45
46@@ -1439,6 +1444,10 @@
47 }
48 break;
49
50+ case sDebianBanner:
51+ intptr = &options->debian_banner;
52+ goto parse_int;
53+
54 case sDeprecated:
55 logit("%s line %d: Deprecated option %s",
56 filename, linenum, arg);
57Index: b/servconf.h
58===================================================================
59--- a/servconf.h
60+++ b/servconf.h
61@@ -160,6 +160,8 @@
62
63 int num_permitted_opens;
64
65+ int debian_banner;
66+
67 char *chroot_directory;
68 char *revoked_keys_file;
69 char *trusted_user_ca_keys;
70Index: b/sshd.c
71===================================================================
72--- a/sshd.c
73+++ b/sshd.c
74@@ -422,7 +422,8 @@
75 minor = PROTOCOL_MINOR_1;
76 }
77 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s", major, minor,
78- SSH_RELEASE, newline);
79+ options.debian_banner ? SSH_RELEASE : SSH_RELEASE_MINIMUM,
80+ newline);
81 server_version_string = xstrdup(buf);
82
83 /* Send our protocol version identification. */
84Index: b/sshd_config.5
85===================================================================
86--- a/sshd_config.5
87+++ b/sshd_config.5
88@@ -339,6 +339,11 @@
89 .Dq no .
90 The default is
91 .Dq delayed .
92+.It Cm DebianBanner
93+Specifies whether the distribution-specified extra version suffix is
94+included during initial protocol handshake.
95+The default is
96+.Dq yes .
97 .It Cm DenyGroups
98 This keyword can be followed by a list of group name patterns, separated
99 by spaces.
diff --git a/debian/patches/debian-config.patch b/debian/patches/debian-config.patch
new file mode 100644
index 000000000..e804aa526
--- /dev/null
+++ b/debian/patches/debian-config.patch
@@ -0,0 +1,146 @@
1Description: Various Debian-specific configuration changes
2 ssh: Enable ForwardX11Trusted, returning to earlier semantics which cause
3 fewer problems with existing setups (http://bugs.debian.org/237021).
4 .
5 ssh: Set 'SendEnv LANG LC_*' by default (http://bugs.debian.org/264024).
6 .
7 ssh: Enable HashKnownHosts by default to try to limit the spread of ssh
8 worms.
9 .
10 ssh: Enable GSSAPIAuthentication and disable GSSAPIDelegateCredentials by
11 default.
12 .
13 sshd: Refer to /usr/share/doc/openssh-server/README.Debian.gz alongside
14 PermitRootLogin default.
15 .
16 Document all of this, along with several sshd defaults set in
17 debian/openssh-server.postinst.
18Author: Colin Watson <cjwatson@debian.org>
19Author: Russ Allbery <rra@debian.org>
20Forwarded: not-needed
21Last-Update: 2010-02-28
22
23Index: b/readconf.c
24===================================================================
25--- a/readconf.c
26+++ b/readconf.c
27@@ -1223,7 +1223,7 @@
28 if (options->forward_x11 == -1)
29 options->forward_x11 = 0;
30 if (options->forward_x11_trusted == -1)
31- options->forward_x11_trusted = 0;
32+ options->forward_x11_trusted = 1;
33 if (options->forward_x11_timeout == -1)
34 options->forward_x11_timeout = 1200;
35 if (options->exit_on_forward_failure == -1)
36Index: b/ssh_config
37===================================================================
38--- a/ssh_config
39+++ b/ssh_config
40@@ -17,9 +17,10 @@
41 # list of available options, their meanings and defaults, please see the
42 # ssh_config(5) man page.
43
44-# Host *
45+Host *
46 # ForwardAgent no
47 # ForwardX11 no
48+# ForwardX11Trusted yes
49 # RhostsRSAAuthentication no
50 # RSAAuthentication yes
51 # PasswordAuthentication yes
52@@ -47,3 +48,7 @@
53 # PermitLocalCommand no
54 # VisualHostKey no
55 # ProxyCommand ssh -q -W %h:%p gateway.example.com
56+ SendEnv LANG LC_*
57+ HashKnownHosts yes
58+ GSSAPIAuthentication yes
59+ GSSAPIDelegateCredentials no
60Index: b/ssh_config.5
61===================================================================
62--- a/ssh_config.5
63+++ b/ssh_config.5
64@@ -71,6 +71,22 @@
65 host-specific declarations should be given near the beginning of the
66 file, and general defaults at the end.
67 .Pp
68+Note that the Debian
69+.Ic openssh-client
70+package sets several options as standard in
71+.Pa /etc/ssh/ssh_config
72+which are not the default in
73+.Xr ssh 1 :
74+.Pp
75+.Bl -bullet -offset indent -compact
76+.It
77+.Cm SendEnv No LANG LC_*
78+.It
79+.Cm HashKnownHosts No yes
80+.It
81+.Cm GSSAPIAuthentication No yes
82+.El
83+.Pp
84 The configuration file has the following format:
85 .Pp
86 Empty lines and lines starting with
87@@ -482,7 +498,8 @@
88 Remote clients will be refused access after this time.
89 .Pp
90 The default is
91-.Dq no .
92+.Dq yes
93+(Debian-specific).
94 .Pp
95 See the X11 SECURITY extension specification for full details on
96 the restrictions imposed on untrusted clients.
97Index: b/sshd_config
98===================================================================
99--- a/sshd_config
100+++ b/sshd_config
101@@ -37,6 +37,7 @@
102 # Authentication:
103
104 #LoginGraceTime 2m
105+# See /usr/share/doc/openssh-server/README.Debian.gz.
106 #PermitRootLogin yes
107 #StrictModes yes
108 #MaxAuthTries 6
109Index: b/sshd_config.5
110===================================================================
111--- a/sshd_config.5
112+++ b/sshd_config.5
113@@ -57,6 +57,33 @@
114 .Pq \&"
115 in order to represent arguments containing spaces.
116 .Pp
117+Note that the Debian
118+.Ic openssh-server
119+package sets several options as standard in
120+.Pa /etc/ssh/sshd_config
121+which are not the default in
122+.Xr sshd 8 .
123+The exact list depends on whether the package was installed fresh or
124+upgraded from various possible previous versions, but includes at least the
125+following:
126+.Pp
127+.Bl -bullet -offset indent -compact
128+.It
129+.Cm Protocol No 2
130+.It
131+.Cm ChallengeResponseAuthentication No no
132+.It
133+.Cm X11Forwarding No yes
134+.It
135+.Cm PrintMotd No no
136+.It
137+.Cm AcceptEnv No LANG LC_*
138+.It
139+.Cm Subsystem No sftp /usr/lib/openssh/sftp-server
140+.It
141+.Cm UsePAM No yes
142+.El
143+.Pp
144 The possible
145 keywords and their meanings are as follows (note that
146 keywords are case-insensitive and arguments are case-sensitive):
diff --git a/debian/patches/dnssec-sshfp.patch b/debian/patches/dnssec-sshfp.patch
new file mode 100644
index 000000000..8e8285a1f
--- /dev/null
+++ b/debian/patches/dnssec-sshfp.patch
@@ -0,0 +1,82 @@
1Description: Force use of DNSSEC even if "options edns0" isn't in resolv.conf
2 This allows SSHFP DNS records to be verified if glibc 2.11 is installed.
3Origin: vendor, https://cvs.fedoraproject.org/viewvc/F-12/openssh/openssh-5.2p1-edns.patch?revision=1.1&view=markup
4Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=572049
5Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=572049
6Last-Update: 2010-04-06
7
8Index: b/dns.c
9===================================================================
10--- a/dns.c
11+++ b/dns.c
12@@ -177,6 +177,7 @@
13 {
14 u_int counter;
15 int result;
16+ unsigned int rrset_flags = 0;
17 struct rrsetinfo *fingerprints = NULL;
18
19 u_int8_t hostkey_algorithm;
20@@ -200,8 +201,19 @@
21 return -1;
22 }
23
24+ /*
25+ * Original getrrsetbyname function, found on OpenBSD for example,
26+ * doesn't accept any flag and prerequisite for obtaining AD bit in
27+ * DNS response is set by "options edns0" in resolv.conf.
28+ *
29+ * Our version is more clever and use RRSET_FORCE_EDNS0 flag.
30+ */
31+#ifndef HAVE_GETRRSETBYNAME
32+ rrset_flags |= RRSET_FORCE_EDNS0;
33+#endif
34 result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
35- DNS_RDATATYPE_SSHFP, 0, &fingerprints);
36+ DNS_RDATATYPE_SSHFP, rrset_flags, &fingerprints);
37+
38 if (result) {
39 verbose("DNS lookup error: %s", dns_result_totext(result));
40 return -1;
41Index: b/openbsd-compat/getrrsetbyname.c
42===================================================================
43--- a/openbsd-compat/getrrsetbyname.c
44+++ b/openbsd-compat/getrrsetbyname.c
45@@ -209,8 +209,8 @@
46 goto fail;
47 }
48
49- /* don't allow flags yet, unimplemented */
50- if (flags) {
51+ /* Allow RRSET_FORCE_EDNS0 flag only. */
52+ if ((flags & !RRSET_FORCE_EDNS0) != 0) {
53 result = ERRSET_INVAL;
54 goto fail;
55 }
56@@ -226,9 +226,9 @@
57 #endif /* DEBUG */
58
59 #ifdef RES_USE_DNSSEC
60- /* turn on DNSSEC if EDNS0 is configured */
61- if (_resp->options & RES_USE_EDNS0)
62- _resp->options |= RES_USE_DNSSEC;
63+ /* turn on DNSSEC if required */
64+ if (flags & RRSET_FORCE_EDNS0)
65+ _resp->options |= (RES_USE_EDNS0|RES_USE_DNSSEC);
66 #endif /* RES_USE_DNSEC */
67
68 /* make query */
69Index: b/openbsd-compat/getrrsetbyname.h
70===================================================================
71--- a/openbsd-compat/getrrsetbyname.h
72+++ b/openbsd-compat/getrrsetbyname.h
73@@ -72,6 +72,9 @@
74 #ifndef RRSET_VALIDATED
75 # define RRSET_VALIDATED 1
76 #endif
77+#ifndef RRSET_FORCE_EDNS0
78+# define RRSET_FORCE_EDNS0 0x0001
79+#endif
80
81 /*
82 * Return codes for getrrsetbyname()
diff --git a/debian/patches/doc-hash-tab-completion.patch b/debian/patches/doc-hash-tab-completion.patch
new file mode 100644
index 000000000..5cf8aa46b
--- /dev/null
+++ b/debian/patches/doc-hash-tab-completion.patch
@@ -0,0 +1,20 @@
1Description: Document that HashKnownHosts may break tab-completion
2Author: Colin Watson <cjwatson@debian.org>
3Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1727
4Bug-Debian: http://bugs.debian.org/430154
5Last-Update: 2010-03-01
6
7Index: b/ssh_config.5
8===================================================================
9--- a/ssh_config.5
10+++ b/ssh_config.5
11@@ -566,6 +566,9 @@
12 will not be converted automatically,
13 but may be manually hashed using
14 .Xr ssh-keygen 1 .
15+Use of this option may break facilities such as tab-completion that rely
16+on being able to read unhashed host names from
17+.Pa ~/.ssh/known_hosts .
18 .It Cm HostbasedAuthentication
19 Specifies whether to try rhosts based authentication with public key
20 authentication.
diff --git a/debian/patches/gnome-ssh-askpass2-icon.patch b/debian/patches/gnome-ssh-askpass2-icon.patch
new file mode 100644
index 000000000..96bbf3a09
--- /dev/null
+++ b/debian/patches/gnome-ssh-askpass2-icon.patch
@@ -0,0 +1,18 @@
1Description: Give the ssh-askpass-gnome window a default icon
2Author: Vincent Untz <vuntz@ubuntu.com>
3Bug-Ubuntu: https://bugs.launchpad.net/bugs/27152
4Last-Update: 2010-02-28
5
6Index: b/contrib/gnome-ssh-askpass2.c
7===================================================================
8--- a/contrib/gnome-ssh-askpass2.c
9+++ b/contrib/gnome-ssh-askpass2.c
10@@ -209,6 +209,8 @@
11
12 gtk_init(&argc, &argv);
13
14+ gtk_window_set_default_icon_from_file ("/usr/share/pixmaps/ssh-askpass-gnome.png", NULL);
15+
16 if (argc > 1) {
17 message = g_strjoinv(" ", argv + 1);
18 } else {
diff --git a/debian/patches/gssapi-autoconf.patch b/debian/patches/gssapi-autoconf.patch
new file mode 100644
index 000000000..51d8a8e72
--- /dev/null
+++ b/debian/patches/gssapi-autoconf.patch
@@ -0,0 +1,29 @@
1Description: Update config.h.in following GSSAPI patch
2Author: Colin Watson <cjwatson@debian.org>
3Forwarded: not-needed
4Last-Updated: 2010-02-27
5
6Index: b/config.h.in
7===================================================================
8--- a/config.h.in
9+++ b/config.h.in
10@@ -1417,6 +1417,9 @@
11 /* Use btmp to log bad logins */
12 #undef USE_BTMP
13
14+/* platform uses an in-memory credentials cache */
15+#undef USE_CCAPI
16+
17 /* Use libedit for sftp */
18 #undef USE_LIBEDIT
19
20@@ -1432,6 +1435,9 @@
21 /* Use PIPES instead of a socketpair() */
22 #undef USE_PIPES
23
24+/* platform has the Security Authorization Session API */
25+#undef USE_SECURITY_SESSION_API
26+
27 /* Define if you have Solaris process contracts */
28 #undef USE_SOLARIS_PROCESS_CONTRACTS
29
diff --git a/debian/patches/gssapi.patch b/debian/patches/gssapi.patch
new file mode 100644
index 000000000..112b31fdf
--- /dev/null
+++ b/debian/patches/gssapi.patch
@@ -0,0 +1,3045 @@
1Description: GSSAPI key exchange support
2 This patch has been rejected upstream: "None of the OpenSSH developers are
3 in favour of adding this, and this situation has not changed for several
4 years. This is not a slight on Simon's patch, which is of fine quality,
5 but just that a) we don't trust GSSAPI implementations that much and b) we
6 don't like adding new KEX since they are pre-auth attack surface. This one
7 is particularly scary, since it requires hooks out to typically root-owned
8 system resources."
9 .
10 However, quite a lot of people rely on this in Debian, and it's better to
11 have it merged into the main openssh package rather than having separate
12 -krb5 packages (as we used to have). It seems to have a generally good
13 security history.
14Author: Simon Wilkinson <simon@sxw.org.uk>
15Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242
16Last-Updated: 2010-02-27
17
18Index: b/ChangeLog.gssapi
19===================================================================
20--- /dev/null
21+++ b/ChangeLog.gssapi
22@@ -0,0 +1,113 @@
23+20110101
24+ - Finally update for OpenSSH 5.6p1
25+ - Add GSSAPIServerIdentity option from Jim Basney
26+
27+20100308
28+ - [ Makefile.in, key.c, key.h ]
29+ Updates for OpenSSH 5.4p1
30+ - [ servconf.c ]
31+ Include GSSAPI options in the sshd -T configuration dump, and flag
32+ some older configuration options as being unsupported. Thanks to Colin
33+ Watson.
34+ -
35+
36+20100124
37+ - [ sshconnect2.c ]
38+ Adapt to deal with additional element in Authmethod structure. Thanks to
39+ Colin Watson
40+
41+20090615
42+ - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c
43+ sshd.c ]
44+ Fix issues identified by Greg Hudson following a code review
45+ Check return value of gss_indicate_mechs
46+ Protect GSSAPI calls in monitor, so they can only be used if enabled
47+ Check return values of bignum functions in key exchange
48+ Use BN_clear_free to clear other side's DH value
49+ Make ssh_gssapi_id_kex more robust
50+ Only configure kex table pointers if GSSAPI is enabled
51+ Don't leak mechanism list, or gss mechanism list
52+ Cast data.length before printing
53+ If serverkey isn't provided, use an empty string, rather than NULL
54+
55+20090201
56+ - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h
57+ ssh_config.5 sshconnet2.c ]
58+ Add support for the GSSAPIClientIdentity option, which allows the user
59+ to specify which GSSAPI identity to use to contact a given server
60+
61+20080404
62+ - [ gss-serv.c ]
63+ Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow
64+ been omitted from a previous version of this patch. Reported by Borislav
65+ Stoichkov
66+
67+20070317
68+ - [ gss-serv-krb5.c ]
69+ Remove C99ism, where new_ccname was being declared in the middle of a
70+ function
71+
72+20061220
73+ - [ servconf.c ]
74+ Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and
75+ documented, behaviour. Reported by Dan Watson.
76+
77+20060910
78+ - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c
79+ ssh-gss.h ]
80+ add support for gss-group14-sha1 key exchange mechanisms
81+ - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ]
82+ Add GSSAPIStrictAcceptorCheck option to allow the disabling of
83+ acceptor principal checking on multi-homed machines.
84+ <Bugzilla #928>
85+ - [ sshd_config ssh_config ]
86+ Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample
87+ configuration files
88+ - [ kexgss.c kegsss.c sshconnect2.c sshd.c ]
89+ Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf()
90+ Limit length of error messages displayed by client
91+
92+20060909
93+ - [ gss-genr.c gss-serv.c ]
94+ move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server
95+ only, where they belong
96+ <Bugzilla #1225>
97+
98+20060829
99+ - [ gss-serv-krb5.c ]
100+ Fix CCAPI credentials cache name when creating KRB5CCNAME environment
101+ variable
102+
103+20060828
104+ - [ gss-genr.c ]
105+ Avoid Heimdal context freeing problem
106+ <Fixed upstream 20060829>
107+
108+20060818
109+ - [ gss-genr.c ssh-gss.h sshconnect2.c ]
110+ Make sure that SPENGO is disabled
111+ <Bugzilla #1218 - Fixed upstream 20060818>
112+
113+20060421
114+ - [ gssgenr.c, sshconnect2.c ]
115+ a few type changes (signed versus unsigned, int versus size_t) to
116+ fix compiler errors/warnings
117+ (from jbasney AT ncsa.uiuc.edu)
118+ - [ kexgssc.c, sshconnect2.c ]
119+ fix uninitialized variable warnings
120+ (from jbasney AT ncsa.uiuc.edu)
121+ - [ gssgenr.c ]
122+ pass oid to gss_display_status (helpful when using GSSAPI mechglue)
123+ (from jbasney AT ncsa.uiuc.edu)
124+ <Bugzilla #1220 >
125+ - [ gss-serv-krb5.c ]
126+ #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H
127+ (from jbasney AT ncsa.uiuc.edu)
128+ <Fixed upstream 20060304>
129+ - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c
130+ add client-side GssapiKeyExchange option
131+ (from jbasney AT ncsa.uiuc.edu)
132+ - [ sshconnect2.c ]
133+ add support for GssapiTrustDns option for gssapi-with-mic
134+ (from jbasney AT ncsa.uiuc.edu)
135+ <gssapi-with-mic support is Bugzilla #1008>
136Index: b/Makefile.in
137===================================================================
138--- a/Makefile.in
139+++ b/Makefile.in
140@@ -74,6 +74,7 @@
141 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
142 monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
143 kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \
144+ kexgssc.o \
145 msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o jpake.o \
146 schnorr.o ssh-pkcs11.o
147
148@@ -90,7 +91,7 @@
149 auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \
150 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
151 auth-krb5.o \
152- auth2-gss.o gss-serv.o gss-serv-krb5.o \
153+ auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
154 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
155 sftp-server.o sftp-common.o \
156 roaming_common.o roaming_serv.o
157Index: b/auth-krb5.c
158===================================================================
159--- a/auth-krb5.c
160+++ b/auth-krb5.c
161@@ -170,8 +170,13 @@
162
163 len = strlen(authctxt->krb5_ticket_file) + 6;
164 authctxt->krb5_ccname = xmalloc(len);
165+#ifdef USE_CCAPI
166+ snprintf(authctxt->krb5_ccname, len, "API:%s",
167+ authctxt->krb5_ticket_file);
168+#else
169 snprintf(authctxt->krb5_ccname, len, "FILE:%s",
170 authctxt->krb5_ticket_file);
171+#endif
172
173 #ifdef USE_PAM
174 if (options.use_pam)
175@@ -226,15 +231,22 @@
176 #ifndef HEIMDAL
177 krb5_error_code
178 ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
179- int tmpfd, ret;
180+ int ret;
181 char ccname[40];
182 mode_t old_umask;
183+#ifdef USE_CCAPI
184+ char cctemplate[] = "API:krb5cc_%d";
185+#else
186+ char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
187+ int tmpfd;
188+#endif
189
190 ret = snprintf(ccname, sizeof(ccname),
191- "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
192+ cctemplate, geteuid());
193 if (ret < 0 || (size_t)ret >= sizeof(ccname))
194 return ENOMEM;
195
196+#ifndef USE_CCAPI
197 old_umask = umask(0177);
198 tmpfd = mkstemp(ccname + strlen("FILE:"));
199 umask(old_umask);
200@@ -249,6 +261,7 @@
201 return errno;
202 }
203 close(tmpfd);
204+#endif
205
206 return (krb5_cc_resolve(ctx, ccname, ccache));
207 }
208Index: b/auth.h
209===================================================================
210--- a/auth.h
211+++ b/auth.h
212@@ -53,6 +53,7 @@
213 int valid; /* user exists and is allowed to login */
214 int attempt;
215 int failures;
216+ int server_caused_failure;
217 int force_pwchange;
218 char *user; /* username sent by the client */
219 char *service;
220Index: b/auth2-gss.c
221===================================================================
222--- a/auth2-gss.c
223+++ b/auth2-gss.c
224@@ -1,7 +1,7 @@
225 /* $OpenBSD: auth2-gss.c,v 1.16 2007/10/29 00:52:45 dtucker Exp $ */
226
227 /*
228- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
229+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
230 *
231 * Redistribution and use in source and binary forms, with or without
232 * modification, are permitted provided that the following conditions
233@@ -52,6 +52,40 @@
234 static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
235 static void input_gssapi_errtok(int, u_int32_t, void *);
236
237+/*
238+ * The 'gssapi_keyex' userauth mechanism.
239+ */
240+static int
241+userauth_gsskeyex(Authctxt *authctxt)
242+{
243+ int authenticated = 0;
244+ Buffer b;
245+ gss_buffer_desc mic, gssbuf;
246+ u_int len;
247+
248+ mic.value = packet_get_string(&len);
249+ mic.length = len;
250+
251+ packet_check_eom();
252+
253+ ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
254+ "gssapi-keyex");
255+
256+ gssbuf.value = buffer_ptr(&b);
257+ gssbuf.length = buffer_len(&b);
258+
259+ /* gss_kex_context is NULL with privsep, so we can't check it here */
260+ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
261+ &gssbuf, &mic))))
262+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
263+ authctxt->pw));
264+
265+ buffer_free(&b);
266+ xfree(mic.value);
267+
268+ return (authenticated);
269+}
270+
271 /*
272 * We only support those mechanisms that we know about (ie ones that we know
273 * how to check local user kuserok and the like)
274@@ -102,6 +136,7 @@
275
276 if (!present) {
277 xfree(doid);
278+ authctxt->server_caused_failure = 1;
279 return (0);
280 }
281
282@@ -109,6 +144,7 @@
283 if (ctxt != NULL)
284 ssh_gssapi_delete_ctx(&ctxt);
285 xfree(doid);
286+ authctxt->server_caused_failure = 1;
287 return (0);
288 }
289
290@@ -242,7 +278,8 @@
291
292 packet_check_eom();
293
294- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
295+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
296+ authctxt->pw));
297
298 authctxt->postponed = 0;
299 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
300@@ -277,7 +314,8 @@
301 gssbuf.length = buffer_len(&b);
302
303 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
304- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
305+ authenticated =
306+ PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
307 else
308 logit("GSSAPI MIC check failed");
309
310@@ -292,6 +330,12 @@
311 userauth_finish(authctxt, authenticated, "gssapi-with-mic");
312 }
313
314+Authmethod method_gsskeyex = {
315+ "gssapi-keyex",
316+ userauth_gsskeyex,
317+ &options.gss_authentication
318+};
319+
320 Authmethod method_gssapi = {
321 "gssapi-with-mic",
322 userauth_gssapi,
323Index: b/auth2.c
324===================================================================
325--- a/auth2.c
326+++ b/auth2.c
327@@ -69,6 +69,7 @@
328 extern Authmethod method_kbdint;
329 extern Authmethod method_hostbased;
330 #ifdef GSSAPI
331+extern Authmethod method_gsskeyex;
332 extern Authmethod method_gssapi;
333 #endif
334 #ifdef JPAKE
335@@ -79,6 +80,7 @@
336 &method_none,
337 &method_pubkey,
338 #ifdef GSSAPI
339+ &method_gsskeyex,
340 &method_gssapi,
341 #endif
342 #ifdef JPAKE
343@@ -274,6 +276,7 @@
344 #endif
345
346 authctxt->postponed = 0;
347+ authctxt->server_caused_failure = 0;
348
349 /* try to authenticate user */
350 m = authmethod_lookup(method);
351@@ -346,7 +349,8 @@
352 } else {
353
354 /* Allow initial try of "none" auth without failure penalty */
355- if (authctxt->attempt > 1 || strcmp(method, "none") != 0)
356+ if (!authctxt->server_caused_failure &&
357+ (authctxt->attempt > 1 || strcmp(method, "none") != 0))
358 authctxt->failures++;
359 if (authctxt->failures >= options.max_authtries) {
360 #ifdef SSH_AUDIT_EVENTS
361Index: b/clientloop.c
362===================================================================
363--- a/clientloop.c
364+++ b/clientloop.c
365@@ -111,6 +111,10 @@
366 #include "msg.h"
367 #include "roaming.h"
368
369+#ifdef GSSAPI
370+#include "ssh-gss.h"
371+#endif
372+
373 /* import options */
374 extern Options options;
375
376@@ -1483,6 +1487,15 @@
377 /* Do channel operations unless rekeying in progress. */
378 if (!rekeying) {
379 channel_after_select(readset, writeset);
380+
381+#ifdef GSSAPI
382+ if (options.gss_renewal_rekey &&
383+ ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) {
384+ debug("credentials updated - forcing rekey");
385+ need_rekeying = 1;
386+ }
387+#endif
388+
389 if (need_rekeying || packet_need_rekeying()) {
390 debug("need rekeying");
391 xxx_kex->done = 0;
392Index: b/configure.ac
393===================================================================
394--- a/configure.ac
395+++ b/configure.ac
396@@ -514,6 +514,30 @@
397 [Use tunnel device compatibility to OpenBSD])
398 AC_DEFINE(SSH_TUN_PREPEND_AF, 1,
399 [Prepend the address family to IP tunnel traffic])
400+ AC_MSG_CHECKING(if we have the Security Authorization Session API)
401+ AC_TRY_COMPILE([#include <Security/AuthSession.h>],
402+ [SessionCreate(0, 0);],
403+ [ac_cv_use_security_session_api="yes"
404+ AC_DEFINE(USE_SECURITY_SESSION_API, 1,
405+ [platform has the Security Authorization Session API])
406+ LIBS="$LIBS -framework Security"
407+ AC_MSG_RESULT(yes)],
408+ [ac_cv_use_security_session_api="no"
409+ AC_MSG_RESULT(no)])
410+ AC_MSG_CHECKING(if we have an in-memory credentials cache)
411+ AC_TRY_COMPILE(
412+ [#include <Kerberos/Kerberos.h>],
413+ [cc_context_t c;
414+ (void) cc_initialize (&c, 0, NULL, NULL);],
415+ [AC_DEFINE(USE_CCAPI, 1,
416+ [platform uses an in-memory credentials cache])
417+ LIBS="$LIBS -framework Security"
418+ AC_MSG_RESULT(yes)
419+ if test "x$ac_cv_use_security_session_api" = "xno"; then
420+ AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***)
421+ fi],
422+ [AC_MSG_RESULT(no)]
423+ )
424 m4_pattern_allow(AU_IPv)
425 AC_CHECK_DECL(AU_IPv4, [],
426 AC_DEFINE(AU_IPv4, 0, [System only supports IPv4 audit records])
427Index: b/gss-genr.c
428===================================================================
429--- a/gss-genr.c
430+++ b/gss-genr.c
431@@ -1,7 +1,7 @@
432 /* $OpenBSD: gss-genr.c,v 1.20 2009/06/22 05:39:28 dtucker Exp $ */
433
434 /*
435- * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
436+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
437 *
438 * Redistribution and use in source and binary forms, with or without
439 * modification, are permitted provided that the following conditions
440@@ -39,12 +39,167 @@
441 #include "buffer.h"
442 #include "log.h"
443 #include "ssh2.h"
444+#include "cipher.h"
445+#include "key.h"
446+#include "kex.h"
447+#include <openssl/evp.h>
448
449 #include "ssh-gss.h"
450
451 extern u_char *session_id2;
452 extern u_int session_id2_len;
453
454+typedef struct {
455+ char *encoded;
456+ gss_OID oid;
457+} ssh_gss_kex_mapping;
458+
459+/*
460+ * XXX - It would be nice to find a more elegant way of handling the
461+ * XXX passing of the key exchange context to the userauth routines
462+ */
463+
464+Gssctxt *gss_kex_context = NULL;
465+
466+static ssh_gss_kex_mapping *gss_enc2oid = NULL;
467+
468+int
469+ssh_gssapi_oid_table_ok() {
470+ return (gss_enc2oid != NULL);
471+}
472+
473+/*
474+ * Return a list of the gss-group1-sha1 mechanisms supported by this program
475+ *
476+ * We test mechanisms to ensure that we can use them, to avoid starting
477+ * a key exchange with a bad mechanism
478+ */
479+
480+char *
481+ssh_gssapi_client_mechanisms(const char *host, const char *client) {
482+ gss_OID_set gss_supported;
483+ OM_uint32 min_status;
484+
485+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
486+ return NULL;
487+
488+ return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
489+ host, client));
490+}
491+
492+char *
493+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
494+ const char *host, const char *client) {
495+ Buffer buf;
496+ size_t i;
497+ int oidpos, enclen;
498+ char *mechs, *encoded;
499+ u_char digest[EVP_MAX_MD_SIZE];
500+ char deroid[2];
501+ const EVP_MD *evp_md = EVP_md5();
502+ EVP_MD_CTX md;
503+
504+ if (gss_enc2oid != NULL) {
505+ for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
506+ xfree(gss_enc2oid[i].encoded);
507+ xfree(gss_enc2oid);
508+ }
509+
510+ gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
511+ (gss_supported->count + 1));
512+
513+ buffer_init(&buf);
514+
515+ oidpos = 0;
516+ for (i = 0; i < gss_supported->count; i++) {
517+ if (gss_supported->elements[i].length < 128 &&
518+ (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
519+
520+ deroid[0] = SSH_GSS_OIDTYPE;
521+ deroid[1] = gss_supported->elements[i].length;
522+
523+ EVP_DigestInit(&md, evp_md);
524+ EVP_DigestUpdate(&md, deroid, 2);
525+ EVP_DigestUpdate(&md,
526+ gss_supported->elements[i].elements,
527+ gss_supported->elements[i].length);
528+ EVP_DigestFinal(&md, digest, NULL);
529+
530+ encoded = xmalloc(EVP_MD_size(evp_md) * 2);
531+ enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
532+ encoded, EVP_MD_size(evp_md) * 2);
533+
534+ if (oidpos != 0)
535+ buffer_put_char(&buf, ',');
536+
537+ buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
538+ sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
539+ buffer_append(&buf, encoded, enclen);
540+ buffer_put_char(&buf, ',');
541+ buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
542+ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
543+ buffer_append(&buf, encoded, enclen);
544+ buffer_put_char(&buf, ',');
545+ buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
546+ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
547+ buffer_append(&buf, encoded, enclen);
548+
549+ gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
550+ gss_enc2oid[oidpos].encoded = encoded;
551+ oidpos++;
552+ }
553+ }
554+ gss_enc2oid[oidpos].oid = NULL;
555+ gss_enc2oid[oidpos].encoded = NULL;
556+
557+ buffer_put_char(&buf, '\0');
558+
559+ mechs = xmalloc(buffer_len(&buf));
560+ buffer_get(&buf, mechs, buffer_len(&buf));
561+ buffer_free(&buf);
562+
563+ if (strlen(mechs) == 0) {
564+ xfree(mechs);
565+ mechs = NULL;
566+ }
567+
568+ return (mechs);
569+}
570+
571+gss_OID
572+ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
573+ int i = 0;
574+
575+ switch (kex_type) {
576+ case KEX_GSS_GRP1_SHA1:
577+ if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
578+ return GSS_C_NO_OID;
579+ name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
580+ break;
581+ case KEX_GSS_GRP14_SHA1:
582+ if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
583+ return GSS_C_NO_OID;
584+ name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
585+ break;
586+ case KEX_GSS_GEX_SHA1:
587+ if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
588+ return GSS_C_NO_OID;
589+ name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
590+ break;
591+ default:
592+ return GSS_C_NO_OID;
593+ }
594+
595+ while (gss_enc2oid[i].encoded != NULL &&
596+ strcmp(name, gss_enc2oid[i].encoded) != 0)
597+ i++;
598+
599+ if (gss_enc2oid[i].oid != NULL && ctx != NULL)
600+ ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
601+
602+ return gss_enc2oid[i].oid;
603+}
604+
605 /* Check that the OID in a data stream matches that in the context */
606 int
607 ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
608@@ -197,7 +352,7 @@
609 }
610
611 ctx->major = gss_init_sec_context(&ctx->minor,
612- GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
613+ ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
614 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
615 0, NULL, recv_tok, NULL, send_tok, flags, NULL);
616
617@@ -227,8 +382,42 @@
618 }
619
620 OM_uint32
621+ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
622+{
623+ gss_buffer_desc gssbuf;
624+ gss_name_t gssname;
625+ OM_uint32 status;
626+ gss_OID_set oidset;
627+
628+ gssbuf.value = (void *) name;
629+ gssbuf.length = strlen(gssbuf.value);
630+
631+ gss_create_empty_oid_set(&status, &oidset);
632+ gss_add_oid_set_member(&status, ctx->oid, &oidset);
633+
634+ ctx->major = gss_import_name(&ctx->minor, &gssbuf,
635+ GSS_C_NT_USER_NAME, &gssname);
636+
637+ if (!ctx->major)
638+ ctx->major = gss_acquire_cred(&ctx->minor,
639+ gssname, 0, oidset, GSS_C_INITIATE,
640+ &ctx->client_creds, NULL, NULL);
641+
642+ gss_release_name(&status, &gssname);
643+ gss_release_oid_set(&status, &oidset);
644+
645+ if (ctx->major)
646+ ssh_gssapi_error(ctx);
647+
648+ return(ctx->major);
649+}
650+
651+OM_uint32
652 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
653 {
654+ if (ctx == NULL)
655+ return -1;
656+
657 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
658 GSS_C_QOP_DEFAULT, buffer, hash)))
659 ssh_gssapi_error(ctx);
660@@ -236,6 +425,19 @@
661 return (ctx->major);
662 }
663
664+/* Priviledged when used by server */
665+OM_uint32
666+ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
667+{
668+ if (ctx == NULL)
669+ return -1;
670+
671+ ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
672+ gssbuf, gssmic, NULL);
673+
674+ return (ctx->major);
675+}
676+
677 void
678 ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
679 const char *context)
680@@ -249,11 +451,16 @@
681 }
682
683 int
684-ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
685+ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
686+ const char *client)
687 {
688 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
689 OM_uint32 major, minor;
690 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
691+ Gssctxt *intctx = NULL;
692+
693+ if (ctx == NULL)
694+ ctx = &intctx;
695
696 /* RFC 4462 says we MUST NOT do SPNEGO */
697 if (oid->length == spnego_oid.length &&
698@@ -263,6 +470,10 @@
699 ssh_gssapi_build_ctx(ctx);
700 ssh_gssapi_set_oid(*ctx, oid);
701 major = ssh_gssapi_import_name(*ctx, host);
702+
703+ if (!GSS_ERROR(major) && client)
704+ major = ssh_gssapi_client_identity(*ctx, client);
705+
706 if (!GSS_ERROR(major)) {
707 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
708 NULL);
709@@ -272,10 +483,67 @@
710 GSS_C_NO_BUFFER);
711 }
712
713- if (GSS_ERROR(major))
714+ if (GSS_ERROR(major) || intctx != NULL)
715 ssh_gssapi_delete_ctx(ctx);
716
717 return (!GSS_ERROR(major));
718 }
719
720+int
721+ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
722+ static gss_name_t saved_name = GSS_C_NO_NAME;
723+ static OM_uint32 saved_lifetime = 0;
724+ static gss_OID saved_mech = GSS_C_NO_OID;
725+ static gss_name_t name;
726+ static OM_uint32 last_call = 0;
727+ OM_uint32 lifetime, now, major, minor;
728+ int equal;
729+ gss_cred_usage_t usage = GSS_C_INITIATE;
730+
731+ now = time(NULL);
732+
733+ if (ctxt) {
734+ debug("Rekey has happened - updating saved versions");
735+
736+ if (saved_name != GSS_C_NO_NAME)
737+ gss_release_name(&minor, &saved_name);
738+
739+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
740+ &saved_name, &saved_lifetime, NULL, NULL);
741+
742+ if (!GSS_ERROR(major)) {
743+ saved_mech = ctxt->oid;
744+ saved_lifetime+= now;
745+ } else {
746+ /* Handle the error */
747+ }
748+ return 0;
749+ }
750+
751+ if (now - last_call < 10)
752+ return 0;
753+
754+ last_call = now;
755+
756+ if (saved_mech == GSS_C_NO_OID)
757+ return 0;
758+
759+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
760+ &name, &lifetime, NULL, NULL);
761+ if (major == GSS_S_CREDENTIALS_EXPIRED)
762+ return 0;
763+ else if (GSS_ERROR(major))
764+ return 0;
765+
766+ major = gss_compare_name(&minor, saved_name, name, &equal);
767+ gss_release_name(&minor, &name);
768+ if (GSS_ERROR(major))
769+ return 0;
770+
771+ if (equal && (saved_lifetime < lifetime + now - 10))
772+ return 1;
773+
774+ return 0;
775+}
776+
777 #endif /* GSSAPI */
778Index: b/gss-serv-krb5.c
779===================================================================
780--- a/gss-serv-krb5.c
781+++ b/gss-serv-krb5.c
782@@ -1,7 +1,7 @@
783 /* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */
784
785 /*
786- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
787+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
788 *
789 * Redistribution and use in source and binary forms, with or without
790 * modification, are permitted provided that the following conditions
791@@ -120,6 +120,7 @@
792 krb5_principal princ;
793 OM_uint32 maj_status, min_status;
794 int len;
795+ const char *new_ccname;
796
797 if (client->creds == NULL) {
798 debug("No credentials stored");
799@@ -168,11 +169,16 @@
800 return;
801 }
802
803- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
804+ new_ccname = krb5_cc_get_name(krb_context, ccache);
805+
806 client->store.envvar = "KRB5CCNAME";
807- len = strlen(client->store.filename) + 6;
808- client->store.envval = xmalloc(len);
809- snprintf(client->store.envval, len, "FILE:%s", client->store.filename);
810+#ifdef USE_CCAPI
811+ xasprintf(&client->store.envval, "API:%s", new_ccname);
812+ client->store.filename = NULL;
813+#else
814+ xasprintf(&client->store.envval, "FILE:%s", new_ccname);
815+ client->store.filename = xstrdup(new_ccname);
816+#endif
817
818 #ifdef USE_PAM
819 if (options.use_pam)
820@@ -184,6 +190,71 @@
821 return;
822 }
823
824+int
825+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store,
826+ ssh_gssapi_client *client)
827+{
828+ krb5_ccache ccache = NULL;
829+ krb5_principal principal = NULL;
830+ char *name = NULL;
831+ krb5_error_code problem;
832+ OM_uint32 maj_status, min_status;
833+
834+ if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
835+ logit("krb5_cc_resolve(): %.100s",
836+ krb5_get_err_text(krb_context, problem));
837+ return 0;
838+ }
839+
840+ /* Find out who the principal in this cache is */
841+ if ((problem = krb5_cc_get_principal(krb_context, ccache,
842+ &principal))) {
843+ logit("krb5_cc_get_principal(): %.100s",
844+ krb5_get_err_text(krb_context, problem));
845+ krb5_cc_close(krb_context, ccache);
846+ return 0;
847+ }
848+
849+ if ((problem = krb5_unparse_name(krb_context, principal, &name))) {
850+ logit("krb5_unparse_name(): %.100s",
851+ krb5_get_err_text(krb_context, problem));
852+ krb5_free_principal(krb_context, principal);
853+ krb5_cc_close(krb_context, ccache);
854+ return 0;
855+ }
856+
857+
858+ if (strcmp(name,client->exportedname.value)!=0) {
859+ debug("Name in local credentials cache differs. Not storing");
860+ krb5_free_principal(krb_context, principal);
861+ krb5_cc_close(krb_context, ccache);
862+ krb5_free_unparsed_name(krb_context, name);
863+ return 0;
864+ }
865+ krb5_free_unparsed_name(krb_context, name);
866+
867+ /* Name matches, so lets get on with it! */
868+
869+ if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) {
870+ logit("krb5_cc_initialize(): %.100s",
871+ krb5_get_err_text(krb_context, problem));
872+ krb5_free_principal(krb_context, principal);
873+ krb5_cc_close(krb_context, ccache);
874+ return 0;
875+ }
876+
877+ krb5_free_principal(krb_context, principal);
878+
879+ if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds,
880+ ccache))) {
881+ logit("gss_krb5_copy_ccache() failed. Sorry!");
882+ krb5_cc_close(krb_context, ccache);
883+ return 0;
884+ }
885+
886+ return 1;
887+}
888+
889 ssh_gssapi_mech gssapi_kerberos_mech = {
890 "toWM5Slw5Ew8Mqkay+al2g==",
891 "Kerberos",
892@@ -191,7 +262,8 @@
893 NULL,
894 &ssh_gssapi_krb5_userok,
895 NULL,
896- &ssh_gssapi_krb5_storecreds
897+ &ssh_gssapi_krb5_storecreds,
898+ &ssh_gssapi_krb5_updatecreds
899 };
900
901 #endif /* KRB5 */
902Index: b/gss-serv.c
903===================================================================
904--- a/gss-serv.c
905+++ b/gss-serv.c
906@@ -1,7 +1,7 @@
907 /* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */
908
909 /*
910- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
911+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
912 *
913 * Redistribution and use in source and binary forms, with or without
914 * modification, are permitted provided that the following conditions
915@@ -45,15 +45,20 @@
916 #include "channels.h"
917 #include "session.h"
918 #include "misc.h"
919+#include "servconf.h"
920+#include "uidswap.h"
921
922 #include "ssh-gss.h"
923+#include "monitor_wrap.h"
924+
925+extern ServerOptions options;
926
927 static ssh_gssapi_client gssapi_client =
928 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
929- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}};
930+ GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL}, 0, 0};
931
932 ssh_gssapi_mech gssapi_null_mech =
933- { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
934+ { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
935
936 #ifdef KRB5
937 extern ssh_gssapi_mech gssapi_kerberos_mech;
938@@ -81,25 +86,32 @@
939 char lname[MAXHOSTNAMELEN];
940 gss_OID_set oidset;
941
942- gss_create_empty_oid_set(&status, &oidset);
943- gss_add_oid_set_member(&status, ctx->oid, &oidset);
944+ if (options.gss_strict_acceptor) {
945+ gss_create_empty_oid_set(&status, &oidset);
946+ gss_add_oid_set_member(&status, ctx->oid, &oidset);
947+
948+ if (gethostname(lname, MAXHOSTNAMELEN)) {
949+ gss_release_oid_set(&status, &oidset);
950+ return (-1);
951+ }
952
953- if (gethostname(lname, MAXHOSTNAMELEN)) {
954- gss_release_oid_set(&status, &oidset);
955- return (-1);
956- }
957+ if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
958+ gss_release_oid_set(&status, &oidset);
959+ return (ctx->major);
960+ }
961+
962+ if ((ctx->major = gss_acquire_cred(&ctx->minor,
963+ ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds,
964+ NULL, NULL)))
965+ ssh_gssapi_error(ctx);
966
967- if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
968 gss_release_oid_set(&status, &oidset);
969 return (ctx->major);
970+ } else {
971+ ctx->name = GSS_C_NO_NAME;
972+ ctx->creds = GSS_C_NO_CREDENTIAL;
973 }
974-
975- if ((ctx->major = gss_acquire_cred(&ctx->minor,
976- ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
977- ssh_gssapi_error(ctx);
978-
979- gss_release_oid_set(&status, &oidset);
980- return (ctx->major);
981+ return GSS_S_COMPLETE;
982 }
983
984 /* Privileged */
985@@ -114,6 +126,29 @@
986 }
987
988 /* Unprivileged */
989+char *
990+ssh_gssapi_server_mechanisms() {
991+ gss_OID_set supported;
992+
993+ ssh_gssapi_supported_oids(&supported);
994+ return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
995+ NULL, NULL));
996+}
997+
998+/* Unprivileged */
999+int
1000+ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
1001+ const char *dummy) {
1002+ Gssctxt *ctx = NULL;
1003+ int res;
1004+
1005+ res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
1006+ ssh_gssapi_delete_ctx(&ctx);
1007+
1008+ return (res);
1009+}
1010+
1011+/* Unprivileged */
1012 void
1013 ssh_gssapi_supported_oids(gss_OID_set *oidset)
1014 {
1015@@ -123,7 +158,9 @@
1016 gss_OID_set supported;
1017
1018 gss_create_empty_oid_set(&min_status, oidset);
1019- gss_indicate_mechs(&min_status, &supported);
1020+
1021+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
1022+ return;
1023
1024 while (supported_mechs[i]->name != NULL) {
1025 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
1026@@ -247,8 +284,48 @@
1027 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
1028 {
1029 int i = 0;
1030+ int equal = 0;
1031+ gss_name_t new_name = GSS_C_NO_NAME;
1032+ gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
1033+
1034+ if (options.gss_store_rekey && client->used && ctx->client_creds) {
1035+ if (client->mech->oid.length != ctx->oid->length ||
1036+ (memcmp(client->mech->oid.elements,
1037+ ctx->oid->elements, ctx->oid->length) !=0)) {
1038+ debug("Rekeyed credentials have different mechanism");
1039+ return GSS_S_COMPLETE;
1040+ }
1041+
1042+ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
1043+ ctx->client_creds, ctx->oid, &new_name,
1044+ NULL, NULL, NULL))) {
1045+ ssh_gssapi_error(ctx);
1046+ return (ctx->major);
1047+ }
1048+
1049+ ctx->major = gss_compare_name(&ctx->minor, client->name,
1050+ new_name, &equal);
1051
1052- gss_buffer_desc ename;
1053+ if (GSS_ERROR(ctx->major)) {
1054+ ssh_gssapi_error(ctx);
1055+ return (ctx->major);
1056+ }
1057+
1058+ if (!equal) {
1059+ debug("Rekeyed credentials have different name");
1060+ return GSS_S_COMPLETE;
1061+ }
1062+
1063+ debug("Marking rekeyed credentials for export");
1064+
1065+ gss_release_name(&ctx->minor, &client->name);
1066+ gss_release_cred(&ctx->minor, &client->creds);
1067+ client->name = new_name;
1068+ client->creds = ctx->client_creds;
1069+ ctx->client_creds = GSS_C_NO_CREDENTIAL;
1070+ client->updated = 1;
1071+ return GSS_S_COMPLETE;
1072+ }
1073
1074 client->mech = NULL;
1075
1076@@ -263,6 +340,13 @@
1077 if (client->mech == NULL)
1078 return GSS_S_FAILURE;
1079
1080+ if (ctx->client_creds &&
1081+ (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
1082+ ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
1083+ ssh_gssapi_error(ctx);
1084+ return (ctx->major);
1085+ }
1086+
1087 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
1088 &client->displayname, NULL))) {
1089 ssh_gssapi_error(ctx);
1090@@ -280,6 +364,8 @@
1091 return (ctx->major);
1092 }
1093
1094+ gss_release_buffer(&ctx->minor, &ename);
1095+
1096 /* We can't copy this structure, so we just move the pointer to it */
1097 client->creds = ctx->client_creds;
1098 ctx->client_creds = GSS_C_NO_CREDENTIAL;
1099@@ -327,7 +413,7 @@
1100
1101 /* Privileged */
1102 int
1103-ssh_gssapi_userok(char *user)
1104+ssh_gssapi_userok(char *user, struct passwd *pw)
1105 {
1106 OM_uint32 lmin;
1107
1108@@ -337,9 +423,11 @@
1109 return 0;
1110 }
1111 if (gssapi_client.mech && gssapi_client.mech->userok)
1112- if ((*gssapi_client.mech->userok)(&gssapi_client, user))
1113+ if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
1114+ gssapi_client.used = 1;
1115+ gssapi_client.store.owner = pw;
1116 return 1;
1117- else {
1118+ } else {
1119 /* Destroy delegated credentials if userok fails */
1120 gss_release_buffer(&lmin, &gssapi_client.displayname);
1121 gss_release_buffer(&lmin, &gssapi_client.exportedname);
1122@@ -352,14 +440,90 @@
1123 return (0);
1124 }
1125
1126-/* Privileged */
1127-OM_uint32
1128-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
1129+/* These bits are only used for rekeying. The unpriviledged child is running
1130+ * as the user, the monitor is root.
1131+ *
1132+ * In the child, we want to :
1133+ * *) Ask the monitor to store our credentials into the store we specify
1134+ * *) If it succeeds, maybe do a PAM update
1135+ */
1136+
1137+/* Stuff for PAM */
1138+
1139+#ifdef USE_PAM
1140+static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
1141+ struct pam_response **resp, void *data)
1142 {
1143- ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
1144- gssbuf, gssmic, NULL);
1145+ return (PAM_CONV_ERR);
1146+}
1147+#endif
1148
1149- return (ctx->major);
1150+void
1151+ssh_gssapi_rekey_creds() {
1152+ int ok;
1153+ int ret;
1154+#ifdef USE_PAM
1155+ pam_handle_t *pamh = NULL;
1156+ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
1157+ char *envstr;
1158+#endif
1159+
1160+ if (gssapi_client.store.filename == NULL &&
1161+ gssapi_client.store.envval == NULL &&
1162+ gssapi_client.store.envvar == NULL)
1163+ return;
1164+
1165+ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
1166+
1167+ if (!ok)
1168+ return;
1169+
1170+ debug("Rekeyed credentials stored successfully");
1171+
1172+ /* Actually managing to play with the ssh pam stack from here will
1173+ * be next to impossible. In any case, we may want different options
1174+ * for rekeying. So, use our own :)
1175+ */
1176+#ifdef USE_PAM
1177+ if (!use_privsep) {
1178+ debug("Not even going to try and do PAM with privsep disabled");
1179+ return;
1180+ }
1181+
1182+ ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
1183+ &pamconv, &pamh);
1184+ if (ret)
1185+ return;
1186+
1187+ xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
1188+ gssapi_client.store.envval);
1189+
1190+ ret = pam_putenv(pamh, envstr);
1191+ if (!ret)
1192+ pam_setcred(pamh, PAM_REINITIALIZE_CRED);
1193+ pam_end(pamh, PAM_SUCCESS);
1194+#endif
1195+}
1196+
1197+int
1198+ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
1199+ int ok = 0;
1200+
1201+ /* Check we've got credentials to store */
1202+ if (!gssapi_client.updated)
1203+ return 0;
1204+
1205+ gssapi_client.updated = 0;
1206+
1207+ temporarily_use_uid(gssapi_client.store.owner);
1208+ if (gssapi_client.mech && gssapi_client.mech->updatecreds)
1209+ ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
1210+ else
1211+ debug("No update function for this mechanism");
1212+
1213+ restore_uid();
1214+
1215+ return ok;
1216 }
1217
1218 #endif
1219Index: b/kex.c
1220===================================================================
1221--- a/kex.c
1222+++ b/kex.c
1223@@ -50,6 +50,10 @@
1224 #include "monitor.h"
1225 #include "roaming.h"
1226
1227+#ifdef GSSAPI
1228+#include "ssh-gss.h"
1229+#endif
1230+
1231 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
1232 # if defined(HAVE_EVP_SHA256)
1233 # define evp_ssh_sha256 EVP_sha256
1234@@ -358,6 +362,20 @@
1235 k->kex_type = KEX_ECDH_SHA2;
1236 k->evp_md = kex_ecdh_name_to_evpmd(k->name);
1237 #endif
1238+#ifdef GSSAPI
1239+ } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID,
1240+ sizeof(KEX_GSS_GEX_SHA1_ID) - 1) == 0) {
1241+ k->kex_type = KEX_GSS_GEX_SHA1;
1242+ k->evp_md = EVP_sha1();
1243+ } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID,
1244+ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1) == 0) {
1245+ k->kex_type = KEX_GSS_GRP1_SHA1;
1246+ k->evp_md = EVP_sha1();
1247+ } else if (strncmp(k->name, KEX_GSS_GRP14_SHA1_ID,
1248+ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1) == 0) {
1249+ k->kex_type = KEX_GSS_GRP14_SHA1;
1250+ k->evp_md = EVP_sha1();
1251+#endif
1252 } else
1253 fatal("bad kex alg %s", k->name);
1254 }
1255Index: b/kex.h
1256===================================================================
1257--- a/kex.h
1258+++ b/kex.h
1259@@ -73,6 +73,9 @@
1260 KEX_DH_GEX_SHA1,
1261 KEX_DH_GEX_SHA256,
1262 KEX_ECDH_SHA2,
1263+ KEX_GSS_GRP1_SHA1,
1264+ KEX_GSS_GRP14_SHA1,
1265+ KEX_GSS_GEX_SHA1,
1266 KEX_MAX
1267 };
1268
1269@@ -129,6 +132,12 @@
1270 sig_atomic_t done;
1271 int flags;
1272 const EVP_MD *evp_md;
1273+#ifdef GSSAPI
1274+ int gss_deleg_creds;
1275+ int gss_trust_dns;
1276+ char *gss_host;
1277+ char *gss_client;
1278+#endif
1279 char *client_version_string;
1280 char *server_version_string;
1281 int (*verify_host_key)(Key *);
1282@@ -156,6 +165,11 @@
1283 void kexecdh_client(Kex *);
1284 void kexecdh_server(Kex *);
1285
1286+#ifdef GSSAPI
1287+void kexgss_client(Kex *);
1288+void kexgss_server(Kex *);
1289+#endif
1290+
1291 void
1292 kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
1293 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
1294Index: b/kexgssc.c
1295===================================================================
1296--- /dev/null
1297+++ b/kexgssc.c
1298@@ -0,0 +1,334 @@
1299+/*
1300+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
1301+ *
1302+ * Redistribution and use in source and binary forms, with or without
1303+ * modification, are permitted provided that the following conditions
1304+ * are met:
1305+ * 1. Redistributions of source code must retain the above copyright
1306+ * notice, this list of conditions and the following disclaimer.
1307+ * 2. Redistributions in binary form must reproduce the above copyright
1308+ * notice, this list of conditions and the following disclaimer in the
1309+ * documentation and/or other materials provided with the distribution.
1310+ *
1311+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
1312+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1313+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1314+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1315+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1316+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1317+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1318+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1319+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1320+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1321+ */
1322+
1323+#include "includes.h"
1324+
1325+#ifdef GSSAPI
1326+
1327+#include "includes.h"
1328+
1329+#include <openssl/crypto.h>
1330+#include <openssl/bn.h>
1331+
1332+#include <string.h>
1333+
1334+#include "xmalloc.h"
1335+#include "buffer.h"
1336+#include "ssh2.h"
1337+#include "key.h"
1338+#include "cipher.h"
1339+#include "kex.h"
1340+#include "log.h"
1341+#include "packet.h"
1342+#include "dh.h"
1343+
1344+#include "ssh-gss.h"
1345+
1346+void
1347+kexgss_client(Kex *kex) {
1348+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
1349+ gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
1350+ Gssctxt *ctxt;
1351+ OM_uint32 maj_status, min_status, ret_flags;
1352+ u_int klen, kout, slen = 0, hashlen, strlen;
1353+ DH *dh;
1354+ BIGNUM *dh_server_pub = NULL;
1355+ BIGNUM *shared_secret = NULL;
1356+ BIGNUM *p = NULL;
1357+ BIGNUM *g = NULL;
1358+ u_char *kbuf, *hash;
1359+ u_char *serverhostkey = NULL;
1360+ u_char *empty = "";
1361+ char *msg;
1362+ char *lang;
1363+ int type = 0;
1364+ int first = 1;
1365+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
1366+
1367+ /* Initialise our GSSAPI world */
1368+ ssh_gssapi_build_ctx(&ctxt);
1369+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
1370+ == GSS_C_NO_OID)
1371+ fatal("Couldn't identify host exchange");
1372+
1373+ if (ssh_gssapi_import_name(ctxt, kex->gss_host))
1374+ fatal("Couldn't import hostname");
1375+
1376+ if (kex->gss_client &&
1377+ ssh_gssapi_client_identity(ctxt, kex->gss_client))
1378+ fatal("Couldn't acquire client credentials");
1379+
1380+ switch (kex->kex_type) {
1381+ case KEX_GSS_GRP1_SHA1:
1382+ dh = dh_new_group1();
1383+ break;
1384+ case KEX_GSS_GRP14_SHA1:
1385+ dh = dh_new_group14();
1386+ break;
1387+ case KEX_GSS_GEX_SHA1:
1388+ debug("Doing group exchange\n");
1389+ nbits = dh_estimate(kex->we_need * 8);
1390+ packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
1391+ packet_put_int(min);
1392+ packet_put_int(nbits);
1393+ packet_put_int(max);
1394+
1395+ packet_send();
1396+
1397+ packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
1398+
1399+ if ((p = BN_new()) == NULL)
1400+ fatal("BN_new() failed");
1401+ packet_get_bignum2(p);
1402+ if ((g = BN_new()) == NULL)
1403+ fatal("BN_new() failed");
1404+ packet_get_bignum2(g);
1405+ packet_check_eom();
1406+
1407+ if (BN_num_bits(p) < min || BN_num_bits(p) > max)
1408+ fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
1409+ min, BN_num_bits(p), max);
1410+
1411+ dh = dh_new_group(g, p);
1412+ break;
1413+ default:
1414+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1415+ }
1416+
1417+ /* Step 1 - e is dh->pub_key */
1418+ dh_gen_key(dh, kex->we_need * 8);
1419+
1420+ /* This is f, we initialise it now to make life easier */
1421+ dh_server_pub = BN_new();
1422+ if (dh_server_pub == NULL)
1423+ fatal("dh_server_pub == NULL");
1424+
1425+ token_ptr = GSS_C_NO_BUFFER;
1426+
1427+ do {
1428+ debug("Calling gss_init_sec_context");
1429+
1430+ maj_status = ssh_gssapi_init_ctx(ctxt,
1431+ kex->gss_deleg_creds, token_ptr, &send_tok,
1432+ &ret_flags);
1433+
1434+ if (GSS_ERROR(maj_status)) {
1435+ if (send_tok.length != 0) {
1436+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1437+ packet_put_string(send_tok.value,
1438+ send_tok.length);
1439+ }
1440+ fatal("gss_init_context failed");
1441+ }
1442+
1443+ /* If we've got an old receive buffer get rid of it */
1444+ if (token_ptr != GSS_C_NO_BUFFER)
1445+ xfree(recv_tok.value);
1446+
1447+ if (maj_status == GSS_S_COMPLETE) {
1448+ /* If mutual state flag is not true, kex fails */
1449+ if (!(ret_flags & GSS_C_MUTUAL_FLAG))
1450+ fatal("Mutual authentication failed");
1451+
1452+ /* If integ avail flag is not true kex fails */
1453+ if (!(ret_flags & GSS_C_INTEG_FLAG))
1454+ fatal("Integrity check failed");
1455+ }
1456+
1457+ /*
1458+ * If we have data to send, then the last message that we
1459+ * received cannot have been a 'complete'.
1460+ */
1461+ if (send_tok.length != 0) {
1462+ if (first) {
1463+ packet_start(SSH2_MSG_KEXGSS_INIT);
1464+ packet_put_string(send_tok.value,
1465+ send_tok.length);
1466+ packet_put_bignum2(dh->pub_key);
1467+ first = 0;
1468+ } else {
1469+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1470+ packet_put_string(send_tok.value,
1471+ send_tok.length);
1472+ }
1473+ packet_send();
1474+ gss_release_buffer(&min_status, &send_tok);
1475+
1476+ /* If we've sent them data, they should reply */
1477+ do {
1478+ type = packet_read();
1479+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
1480+ debug("Received KEXGSS_HOSTKEY");
1481+ if (serverhostkey)
1482+ fatal("Server host key received more than once");
1483+ serverhostkey =
1484+ packet_get_string(&slen);
1485+ }
1486+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
1487+
1488+ switch (type) {
1489+ case SSH2_MSG_KEXGSS_CONTINUE:
1490+ debug("Received GSSAPI_CONTINUE");
1491+ if (maj_status == GSS_S_COMPLETE)
1492+ fatal("GSSAPI Continue received from server when complete");
1493+ recv_tok.value = packet_get_string(&strlen);
1494+ recv_tok.length = strlen;
1495+ break;
1496+ case SSH2_MSG_KEXGSS_COMPLETE:
1497+ debug("Received GSSAPI_COMPLETE");
1498+ packet_get_bignum2(dh_server_pub);
1499+ msg_tok.value = packet_get_string(&strlen);
1500+ msg_tok.length = strlen;
1501+
1502+ /* Is there a token included? */
1503+ if (packet_get_char()) {
1504+ recv_tok.value=
1505+ packet_get_string(&strlen);
1506+ recv_tok.length = strlen;
1507+ /* If we're already complete - protocol error */
1508+ if (maj_status == GSS_S_COMPLETE)
1509+ packet_disconnect("Protocol error: received token when complete");
1510+ } else {
1511+ /* No token included */
1512+ if (maj_status != GSS_S_COMPLETE)
1513+ packet_disconnect("Protocol error: did not receive final token");
1514+ }
1515+ break;
1516+ case SSH2_MSG_KEXGSS_ERROR:
1517+ debug("Received Error");
1518+ maj_status = packet_get_int();
1519+ min_status = packet_get_int();
1520+ msg = packet_get_string(NULL);
1521+ lang = packet_get_string(NULL);
1522+ fatal("GSSAPI Error: \n%.400s",msg);
1523+ default:
1524+ packet_disconnect("Protocol error: didn't expect packet type %d",
1525+ type);
1526+ }
1527+ token_ptr = &recv_tok;
1528+ } else {
1529+ /* No data, and not complete */
1530+ if (maj_status != GSS_S_COMPLETE)
1531+ fatal("Not complete, and no token output");
1532+ }
1533+ } while (maj_status & GSS_S_CONTINUE_NEEDED);
1534+
1535+ /*
1536+ * We _must_ have received a COMPLETE message in reply from the
1537+ * server, which will have set dh_server_pub and msg_tok
1538+ */
1539+
1540+ if (type != SSH2_MSG_KEXGSS_COMPLETE)
1541+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
1542+
1543+ /* Check f in range [1, p-1] */
1544+ if (!dh_pub_is_valid(dh, dh_server_pub))
1545+ packet_disconnect("bad server public DH value");
1546+
1547+ /* compute K=f^x mod p */
1548+ klen = DH_size(dh);
1549+ kbuf = xmalloc(klen);
1550+ kout = DH_compute_key(kbuf, dh_server_pub, dh);
1551+ if (kout < 0)
1552+ fatal("DH_compute_key: failed");
1553+
1554+ shared_secret = BN_new();
1555+ if (shared_secret == NULL)
1556+ fatal("kexgss_client: BN_new failed");
1557+
1558+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
1559+ fatal("kexdh_client: BN_bin2bn failed");
1560+
1561+ memset(kbuf, 0, klen);
1562+ xfree(kbuf);
1563+
1564+ switch (kex->kex_type) {
1565+ case KEX_GSS_GRP1_SHA1:
1566+ case KEX_GSS_GRP14_SHA1:
1567+ kex_dh_hash( kex->client_version_string,
1568+ kex->server_version_string,
1569+ buffer_ptr(&kex->my), buffer_len(&kex->my),
1570+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
1571+ (serverhostkey ? serverhostkey : empty), slen,
1572+ dh->pub_key, /* e */
1573+ dh_server_pub, /* f */
1574+ shared_secret, /* K */
1575+ &hash, &hashlen
1576+ );
1577+ break;
1578+ case KEX_GSS_GEX_SHA1:
1579+ kexgex_hash(
1580+ kex->evp_md,
1581+ kex->client_version_string,
1582+ kex->server_version_string,
1583+ buffer_ptr(&kex->my), buffer_len(&kex->my),
1584+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
1585+ (serverhostkey ? serverhostkey : empty), slen,
1586+ min, nbits, max,
1587+ dh->p, dh->g,
1588+ dh->pub_key,
1589+ dh_server_pub,
1590+ shared_secret,
1591+ &hash, &hashlen
1592+ );
1593+ break;
1594+ default:
1595+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1596+ }
1597+
1598+ gssbuf.value = hash;
1599+ gssbuf.length = hashlen;
1600+
1601+ /* Verify that the hash matches the MIC we just got. */
1602+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
1603+ packet_disconnect("Hash's MIC didn't verify");
1604+
1605+ xfree(msg_tok.value);
1606+
1607+ DH_free(dh);
1608+ if (serverhostkey)
1609+ xfree(serverhostkey);
1610+ BN_clear_free(dh_server_pub);
1611+
1612+ /* save session id */
1613+ if (kex->session_id == NULL) {
1614+ kex->session_id_len = hashlen;
1615+ kex->session_id = xmalloc(kex->session_id_len);
1616+ memcpy(kex->session_id, hash, kex->session_id_len);
1617+ }
1618+
1619+ if (kex->gss_deleg_creds)
1620+ ssh_gssapi_credentials_updated(ctxt);
1621+
1622+ if (gss_kex_context == NULL)
1623+ gss_kex_context = ctxt;
1624+ else
1625+ ssh_gssapi_delete_ctx(&ctxt);
1626+
1627+ kex_derive_keys(kex, hash, hashlen, shared_secret);
1628+ BN_clear_free(shared_secret);
1629+ kex_finish(kex);
1630+}
1631+
1632+#endif /* GSSAPI */
1633Index: b/kexgsss.c
1634===================================================================
1635--- /dev/null
1636+++ b/kexgsss.c
1637@@ -0,0 +1,288 @@
1638+/*
1639+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
1640+ *
1641+ * Redistribution and use in source and binary forms, with or without
1642+ * modification, are permitted provided that the following conditions
1643+ * are met:
1644+ * 1. Redistributions of source code must retain the above copyright
1645+ * notice, this list of conditions and the following disclaimer.
1646+ * 2. Redistributions in binary form must reproduce the above copyright
1647+ * notice, this list of conditions and the following disclaimer in the
1648+ * documentation and/or other materials provided with the distribution.
1649+ *
1650+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
1651+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1652+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1653+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1654+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1655+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1656+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1657+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1658+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1659+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1660+ */
1661+
1662+#include "includes.h"
1663+
1664+#ifdef GSSAPI
1665+
1666+#include <string.h>
1667+
1668+#include <openssl/crypto.h>
1669+#include <openssl/bn.h>
1670+
1671+#include "xmalloc.h"
1672+#include "buffer.h"
1673+#include "ssh2.h"
1674+#include "key.h"
1675+#include "cipher.h"
1676+#include "kex.h"
1677+#include "log.h"
1678+#include "packet.h"
1679+#include "dh.h"
1680+#include "ssh-gss.h"
1681+#include "monitor_wrap.h"
1682+#include "servconf.h"
1683+
1684+extern ServerOptions options;
1685+
1686+void
1687+kexgss_server(Kex *kex)
1688+{
1689+ OM_uint32 maj_status, min_status;
1690+
1691+ /*
1692+ * Some GSSAPI implementations use the input value of ret_flags (an
1693+ * output variable) as a means of triggering mechanism specific
1694+ * features. Initializing it to zero avoids inadvertently
1695+ * activating this non-standard behaviour.
1696+ */
1697+
1698+ OM_uint32 ret_flags = 0;
1699+ gss_buffer_desc gssbuf, recv_tok, msg_tok;
1700+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
1701+ Gssctxt *ctxt = NULL;
1702+ u_int slen, klen, kout, hashlen;
1703+ u_char *kbuf, *hash;
1704+ DH *dh;
1705+ int min = -1, max = -1, nbits = -1;
1706+ BIGNUM *shared_secret = NULL;
1707+ BIGNUM *dh_client_pub = NULL;
1708+ int type = 0;
1709+ gss_OID oid;
1710+ char *mechs;
1711+
1712+ /* Initialise GSSAPI */
1713+
1714+ /* If we're rekeying, privsep means that some of the private structures
1715+ * in the GSSAPI code are no longer available. This kludges them back
1716+ * into life
1717+ */
1718+ if (!ssh_gssapi_oid_table_ok())
1719+ if ((mechs = ssh_gssapi_server_mechanisms()))
1720+ xfree(mechs);
1721+
1722+ debug2("%s: Identifying %s", __func__, kex->name);
1723+ oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
1724+ if (oid == GSS_C_NO_OID)
1725+ fatal("Unknown gssapi mechanism");
1726+
1727+ debug2("%s: Acquiring credentials", __func__);
1728+
1729+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
1730+ fatal("Unable to acquire credentials for the server");
1731+
1732+ switch (kex->kex_type) {
1733+ case KEX_GSS_GRP1_SHA1:
1734+ dh = dh_new_group1();
1735+ break;
1736+ case KEX_GSS_GRP14_SHA1:
1737+ dh = dh_new_group14();
1738+ break;
1739+ case KEX_GSS_GEX_SHA1:
1740+ debug("Doing group exchange");
1741+ packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
1742+ min = packet_get_int();
1743+ nbits = packet_get_int();
1744+ max = packet_get_int();
1745+ min = MAX(DH_GRP_MIN, min);
1746+ max = MIN(DH_GRP_MAX, max);
1747+ packet_check_eom();
1748+ if (max < min || nbits < min || max < nbits)
1749+ fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
1750+ min, nbits, max);
1751+ dh = PRIVSEP(choose_dh(min, nbits, max));
1752+ if (dh == NULL)
1753+ packet_disconnect("Protocol error: no matching group found");
1754+
1755+ packet_start(SSH2_MSG_KEXGSS_GROUP);
1756+ packet_put_bignum2(dh->p);
1757+ packet_put_bignum2(dh->g);
1758+ packet_send();
1759+
1760+ packet_write_wait();
1761+ break;
1762+ default:
1763+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1764+ }
1765+
1766+ dh_gen_key(dh, kex->we_need * 8);
1767+
1768+ do {
1769+ debug("Wait SSH2_MSG_GSSAPI_INIT");
1770+ type = packet_read();
1771+ switch(type) {
1772+ case SSH2_MSG_KEXGSS_INIT:
1773+ if (dh_client_pub != NULL)
1774+ fatal("Received KEXGSS_INIT after initialising");
1775+ recv_tok.value = packet_get_string(&slen);
1776+ recv_tok.length = slen;
1777+
1778+ if ((dh_client_pub = BN_new()) == NULL)
1779+ fatal("dh_client_pub == NULL");
1780+
1781+ packet_get_bignum2(dh_client_pub);
1782+
1783+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
1784+ break;
1785+ case SSH2_MSG_KEXGSS_CONTINUE:
1786+ recv_tok.value = packet_get_string(&slen);
1787+ recv_tok.length = slen;
1788+ break;
1789+ default:
1790+ packet_disconnect(
1791+ "Protocol error: didn't expect packet type %d",
1792+ type);
1793+ }
1794+
1795+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
1796+ &send_tok, &ret_flags));
1797+
1798+ xfree(recv_tok.value);
1799+
1800+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
1801+ fatal("Zero length token output when incomplete");
1802+
1803+ if (dh_client_pub == NULL)
1804+ fatal("No client public key");
1805+
1806+ if (maj_status & GSS_S_CONTINUE_NEEDED) {
1807+ debug("Sending GSSAPI_CONTINUE");
1808+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1809+ packet_put_string(send_tok.value, send_tok.length);
1810+ packet_send();
1811+ gss_release_buffer(&min_status, &send_tok);
1812+ }
1813+ } while (maj_status & GSS_S_CONTINUE_NEEDED);
1814+
1815+ if (GSS_ERROR(maj_status)) {
1816+ if (send_tok.length > 0) {
1817+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1818+ packet_put_string(send_tok.value, send_tok.length);
1819+ packet_send();
1820+ }
1821+ fatal("accept_ctx died");
1822+ }
1823+
1824+ if (!(ret_flags & GSS_C_MUTUAL_FLAG))
1825+ fatal("Mutual Authentication flag wasn't set");
1826+
1827+ if (!(ret_flags & GSS_C_INTEG_FLAG))
1828+ fatal("Integrity flag wasn't set");
1829+
1830+ if (!dh_pub_is_valid(dh, dh_client_pub))
1831+ packet_disconnect("bad client public DH value");
1832+
1833+ klen = DH_size(dh);
1834+ kbuf = xmalloc(klen);
1835+ kout = DH_compute_key(kbuf, dh_client_pub, dh);
1836+ if (kout < 0)
1837+ fatal("DH_compute_key: failed");
1838+
1839+ shared_secret = BN_new();
1840+ if (shared_secret == NULL)
1841+ fatal("kexgss_server: BN_new failed");
1842+
1843+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
1844+ fatal("kexgss_server: BN_bin2bn failed");
1845+
1846+ memset(kbuf, 0, klen);
1847+ xfree(kbuf);
1848+
1849+ switch (kex->kex_type) {
1850+ case KEX_GSS_GRP1_SHA1:
1851+ case KEX_GSS_GRP14_SHA1:
1852+ kex_dh_hash(
1853+ kex->client_version_string, kex->server_version_string,
1854+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
1855+ buffer_ptr(&kex->my), buffer_len(&kex->my),
1856+ NULL, 0, /* Change this if we start sending host keys */
1857+ dh_client_pub, dh->pub_key, shared_secret,
1858+ &hash, &hashlen
1859+ );
1860+ break;
1861+ case KEX_GSS_GEX_SHA1:
1862+ kexgex_hash(
1863+ kex->evp_md,
1864+ kex->client_version_string, kex->server_version_string,
1865+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
1866+ buffer_ptr(&kex->my), buffer_len(&kex->my),
1867+ NULL, 0,
1868+ min, nbits, max,
1869+ dh->p, dh->g,
1870+ dh_client_pub,
1871+ dh->pub_key,
1872+ shared_secret,
1873+ &hash, &hashlen
1874+ );
1875+ break;
1876+ default:
1877+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1878+ }
1879+
1880+ BN_clear_free(dh_client_pub);
1881+
1882+ if (kex->session_id == NULL) {
1883+ kex->session_id_len = hashlen;
1884+ kex->session_id = xmalloc(kex->session_id_len);
1885+ memcpy(kex->session_id, hash, kex->session_id_len);
1886+ }
1887+
1888+ gssbuf.value = hash;
1889+ gssbuf.length = hashlen;
1890+
1891+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
1892+ fatal("Couldn't get MIC");
1893+
1894+ packet_start(SSH2_MSG_KEXGSS_COMPLETE);
1895+ packet_put_bignum2(dh->pub_key);
1896+ packet_put_string(msg_tok.value,msg_tok.length);
1897+
1898+ if (send_tok.length != 0) {
1899+ packet_put_char(1); /* true */
1900+ packet_put_string(send_tok.value, send_tok.length);
1901+ } else {
1902+ packet_put_char(0); /* false */
1903+ }
1904+ packet_send();
1905+
1906+ gss_release_buffer(&min_status, &send_tok);
1907+ gss_release_buffer(&min_status, &msg_tok);
1908+
1909+ if (gss_kex_context == NULL)
1910+ gss_kex_context = ctxt;
1911+ else
1912+ ssh_gssapi_delete_ctx(&ctxt);
1913+
1914+ DH_free(dh);
1915+
1916+ kex_derive_keys(kex, hash, hashlen, shared_secret);
1917+ BN_clear_free(shared_secret);
1918+ kex_finish(kex);
1919+
1920+ /* If this was a rekey, then save out any delegated credentials we
1921+ * just exchanged. */
1922+ if (options.gss_store_rekey)
1923+ ssh_gssapi_rekey_creds();
1924+}
1925+#endif /* GSSAPI */
1926Index: b/key.c
1927===================================================================
1928--- a/key.c
1929+++ b/key.c
1930@@ -971,6 +971,8 @@
1931 }
1932 break;
1933 #endif /* OPENSSL_HAS_ECC */
1934+ case KEY_NULL:
1935+ return "null";
1936 }
1937 return "ssh-unknown";
1938 }
1939@@ -1276,6 +1278,8 @@
1940 strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0) {
1941 return KEY_ECDSA_CERT;
1942 #endif
1943+ } else if (strcmp(name, "null") == 0) {
1944+ return KEY_NULL;
1945 }
1946
1947 debug2("key_type_from_name: unknown key type '%s'", name);
1948Index: b/key.h
1949===================================================================
1950--- a/key.h
1951+++ b/key.h
1952@@ -44,6 +44,7 @@
1953 KEY_ECDSA_CERT,
1954 KEY_RSA_CERT_V00,
1955 KEY_DSA_CERT_V00,
1956+ KEY_NULL,
1957 KEY_UNSPEC
1958 };
1959 enum fp_type {
1960Index: b/monitor.c
1961===================================================================
1962--- a/monitor.c
1963+++ b/monitor.c
1964@@ -172,6 +172,8 @@
1965 int mm_answer_gss_accept_ctx(int, Buffer *);
1966 int mm_answer_gss_userok(int, Buffer *);
1967 int mm_answer_gss_checkmic(int, Buffer *);
1968+int mm_answer_gss_sign(int, Buffer *);
1969+int mm_answer_gss_updatecreds(int, Buffer *);
1970 #endif
1971
1972 #ifdef SSH_AUDIT_EVENTS
1973@@ -241,6 +243,7 @@
1974 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
1975 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
1976 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
1977+ {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
1978 #endif
1979 #ifdef JPAKE
1980 {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
1981@@ -253,6 +256,12 @@
1982 };
1983
1984 struct mon_table mon_dispatch_postauth20[] = {
1985+#ifdef GSSAPI
1986+ {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
1987+ {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
1988+ {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
1989+ {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
1990+#endif
1991 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
1992 {MONITOR_REQ_SIGN, 0, mm_answer_sign},
1993 {MONITOR_REQ_PTY, 0, mm_answer_pty},
1994@@ -357,6 +366,10 @@
1995 /* Permit requests for moduli and signatures */
1996 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
1997 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
1998+#ifdef GSSAPI
1999+ /* and for the GSSAPI key exchange */
2000+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
2001+#endif
2002 } else {
2003 mon_dispatch = mon_dispatch_proto15;
2004
2005@@ -443,6 +456,10 @@
2006 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
2007 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
2008 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
2009+#ifdef GSSAPI
2010+ /* and for the GSSAPI key exchange */
2011+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
2012+#endif
2013 } else {
2014 mon_dispatch = mon_dispatch_postauth15;
2015 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
2016@@ -1692,6 +1709,13 @@
2017 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
2018 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
2019 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
2020+#ifdef GSSAPI
2021+ if (options.gss_keyex) {
2022+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
2023+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
2024+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
2025+ }
2026+#endif
2027 kex->server = 1;
2028 kex->hostkey_type = buffer_get_int(m);
2029 kex->kex_type = buffer_get_int(m);
2030@@ -1898,6 +1922,9 @@
2031 OM_uint32 major;
2032 u_int len;
2033
2034+ if (!options.gss_authentication && !options.gss_keyex)
2035+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2036+
2037 goid.elements = buffer_get_string(m, &len);
2038 goid.length = len;
2039
2040@@ -1925,6 +1952,9 @@
2041 OM_uint32 flags = 0; /* GSI needs this */
2042 u_int len;
2043
2044+ if (!options.gss_authentication && !options.gss_keyex)
2045+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2046+
2047 in.value = buffer_get_string(m, &len);
2048 in.length = len;
2049 major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
2050@@ -1942,6 +1972,7 @@
2051 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
2052 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
2053 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
2054+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
2055 }
2056 return (0);
2057 }
2058@@ -1953,6 +1984,9 @@
2059 OM_uint32 ret;
2060 u_int len;
2061
2062+ if (!options.gss_authentication && !options.gss_keyex)
2063+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2064+
2065 gssbuf.value = buffer_get_string(m, &len);
2066 gssbuf.length = len;
2067 mic.value = buffer_get_string(m, &len);
2068@@ -1979,7 +2013,11 @@
2069 {
2070 int authenticated;
2071
2072- authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
2073+ if (!options.gss_authentication && !options.gss_keyex)
2074+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2075+
2076+ authenticated = authctxt->valid &&
2077+ ssh_gssapi_userok(authctxt->user, authctxt->pw);
2078
2079 buffer_clear(m);
2080 buffer_put_int(m, authenticated);
2081@@ -1992,6 +2030,74 @@
2082 /* Monitor loop will terminate if authenticated */
2083 return (authenticated);
2084 }
2085+
2086+int
2087+mm_answer_gss_sign(int socket, Buffer *m)
2088+{
2089+ gss_buffer_desc data;
2090+ gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
2091+ OM_uint32 major, minor;
2092+ u_int len;
2093+
2094+ if (!options.gss_authentication && !options.gss_keyex)
2095+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2096+
2097+ data.value = buffer_get_string(m, &len);
2098+ data.length = len;
2099+ if (data.length != 20)
2100+ fatal("%s: data length incorrect: %d", __func__,
2101+ (int) data.length);
2102+
2103+ /* Save the session ID on the first time around */
2104+ if (session_id2_len == 0) {
2105+ session_id2_len = data.length;
2106+ session_id2 = xmalloc(session_id2_len);
2107+ memcpy(session_id2, data.value, session_id2_len);
2108+ }
2109+ major = ssh_gssapi_sign(gsscontext, &data, &hash);
2110+
2111+ xfree(data.value);
2112+
2113+ buffer_clear(m);
2114+ buffer_put_int(m, major);
2115+ buffer_put_string(m, hash.value, hash.length);
2116+
2117+ mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
2118+
2119+ gss_release_buffer(&minor, &hash);
2120+
2121+ /* Turn on getpwnam permissions */
2122+ monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
2123+
2124+ /* And credential updating, for when rekeying */
2125+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
2126+
2127+ return (0);
2128+}
2129+
2130+int
2131+mm_answer_gss_updatecreds(int socket, Buffer *m) {
2132+ ssh_gssapi_ccache store;
2133+ int ok;
2134+
2135+ store.filename = buffer_get_string(m, NULL);
2136+ store.envvar = buffer_get_string(m, NULL);
2137+ store.envval = buffer_get_string(m, NULL);
2138+
2139+ ok = ssh_gssapi_update_creds(&store);
2140+
2141+ xfree(store.filename);
2142+ xfree(store.envvar);
2143+ xfree(store.envval);
2144+
2145+ buffer_clear(m);
2146+ buffer_put_int(m, ok);
2147+
2148+ mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
2149+
2150+ return(0);
2151+}
2152+
2153 #endif /* GSSAPI */
2154
2155 #ifdef JPAKE
2156Index: b/monitor.h
2157===================================================================
2158--- a/monitor.h
2159+++ b/monitor.h
2160@@ -53,6 +53,8 @@
2161 MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
2162 MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
2163 MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC,
2164+ MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN,
2165+ MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS,
2166 MONITOR_REQ_PAM_START,
2167 MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT,
2168 MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX,
2169Index: b/monitor_wrap.c
2170===================================================================
2171--- a/monitor_wrap.c
2172+++ b/monitor_wrap.c
2173@@ -1232,7 +1232,7 @@
2174 }
2175
2176 int
2177-mm_ssh_gssapi_userok(char *user)
2178+mm_ssh_gssapi_userok(char *user, struct passwd *pw)
2179 {
2180 Buffer m;
2181 int authenticated = 0;
2182@@ -1249,6 +1249,51 @@
2183 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
2184 return (authenticated);
2185 }
2186+
2187+OM_uint32
2188+mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
2189+{
2190+ Buffer m;
2191+ OM_uint32 major;
2192+ u_int len;
2193+
2194+ buffer_init(&m);
2195+ buffer_put_string(&m, data->value, data->length);
2196+
2197+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
2198+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
2199+
2200+ major = buffer_get_int(&m);
2201+ hash->value = buffer_get_string(&m, &len);
2202+ hash->length = len;
2203+
2204+ buffer_free(&m);
2205+
2206+ return(major);
2207+}
2208+
2209+int
2210+mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
2211+{
2212+ Buffer m;
2213+ int ok;
2214+
2215+ buffer_init(&m);
2216+
2217+ buffer_put_cstring(&m, store->filename ? store->filename : "");
2218+ buffer_put_cstring(&m, store->envvar ? store->envvar : "");
2219+ buffer_put_cstring(&m, store->envval ? store->envval : "");
2220+
2221+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m);
2222+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m);
2223+
2224+ ok = buffer_get_int(&m);
2225+
2226+ buffer_free(&m);
2227+
2228+ return (ok);
2229+}
2230+
2231 #endif /* GSSAPI */
2232
2233 #ifdef JPAKE
2234Index: b/monitor_wrap.h
2235===================================================================
2236--- a/monitor_wrap.h
2237+++ b/monitor_wrap.h
2238@@ -57,8 +57,10 @@
2239 OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
2240 OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
2241 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
2242-int mm_ssh_gssapi_userok(char *user);
2243+int mm_ssh_gssapi_userok(char *user, struct passwd *);
2244 OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
2245+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
2246+int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
2247 #endif
2248
2249 #ifdef USE_PAM
2250Index: b/readconf.c
2251===================================================================
2252--- a/readconf.c
2253+++ b/readconf.c
2254@@ -129,6 +129,8 @@
2255 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
2256 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
2257 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
2258+ oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
2259+ oGssServerIdentity,
2260 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
2261 oSendEnv, oControlPath, oControlMaster, oControlPersist,
2262 oHashKnownHosts,
2263@@ -169,10 +171,19 @@
2264 { "afstokenpassing", oUnsupported },
2265 #if defined(GSSAPI)
2266 { "gssapiauthentication", oGssAuthentication },
2267+ { "gssapikeyexchange", oGssKeyEx },
2268 { "gssapidelegatecredentials", oGssDelegateCreds },
2269+ { "gssapitrustdns", oGssTrustDns },
2270+ { "gssapiclientidentity", oGssClientIdentity },
2271+ { "gssapiserveridentity", oGssServerIdentity },
2272+ { "gssapirenewalforcesrekey", oGssRenewalRekey },
2273 #else
2274 { "gssapiauthentication", oUnsupported },
2275+ { "gssapikeyexchange", oUnsupported },
2276 { "gssapidelegatecredentials", oUnsupported },
2277+ { "gssapitrustdns", oUnsupported },
2278+ { "gssapiclientidentity", oUnsupported },
2279+ { "gssapirenewalforcesrekey", oUnsupported },
2280 #endif
2281 { "fallbacktorsh", oDeprecated },
2282 { "usersh", oDeprecated },
2283@@ -479,10 +490,30 @@
2284 intptr = &options->gss_authentication;
2285 goto parse_flag;
2286
2287+ case oGssKeyEx:
2288+ intptr = &options->gss_keyex;
2289+ goto parse_flag;
2290+
2291 case oGssDelegateCreds:
2292 intptr = &options->gss_deleg_creds;
2293 goto parse_flag;
2294
2295+ case oGssTrustDns:
2296+ intptr = &options->gss_trust_dns;
2297+ goto parse_flag;
2298+
2299+ case oGssClientIdentity:
2300+ charptr = &options->gss_client_identity;
2301+ goto parse_string;
2302+
2303+ case oGssServerIdentity:
2304+ charptr = &options->gss_server_identity;
2305+ goto parse_string;
2306+
2307+ case oGssRenewalRekey:
2308+ intptr = &options->gss_renewal_rekey;
2309+ goto parse_flag;
2310+
2311 case oBatchMode:
2312 intptr = &options->batch_mode;
2313 goto parse_flag;
2314@@ -1092,7 +1123,12 @@
2315 options->pubkey_authentication = -1;
2316 options->challenge_response_authentication = -1;
2317 options->gss_authentication = -1;
2318+ options->gss_keyex = -1;
2319 options->gss_deleg_creds = -1;
2320+ options->gss_trust_dns = -1;
2321+ options->gss_renewal_rekey = -1;
2322+ options->gss_client_identity = NULL;
2323+ options->gss_server_identity = NULL;
2324 options->password_authentication = -1;
2325 options->kbd_interactive_authentication = -1;
2326 options->kbd_interactive_devices = NULL;
2327@@ -1193,8 +1229,14 @@
2328 options->challenge_response_authentication = 1;
2329 if (options->gss_authentication == -1)
2330 options->gss_authentication = 0;
2331+ if (options->gss_keyex == -1)
2332+ options->gss_keyex = 0;
2333 if (options->gss_deleg_creds == -1)
2334 options->gss_deleg_creds = 0;
2335+ if (options->gss_trust_dns == -1)
2336+ options->gss_trust_dns = 0;
2337+ if (options->gss_renewal_rekey == -1)
2338+ options->gss_renewal_rekey = 0;
2339 if (options->password_authentication == -1)
2340 options->password_authentication = 1;
2341 if (options->kbd_interactive_authentication == -1)
2342Index: b/readconf.h
2343===================================================================
2344--- a/readconf.h
2345+++ b/readconf.h
2346@@ -46,7 +46,12 @@
2347 int challenge_response_authentication;
2348 /* Try S/Key or TIS, authentication. */
2349 int gss_authentication; /* Try GSS authentication */
2350+ int gss_keyex; /* Try GSS key exchange */
2351 int gss_deleg_creds; /* Delegate GSS credentials */
2352+ int gss_trust_dns; /* Trust DNS for GSS canonicalization */
2353+ int gss_renewal_rekey; /* Credential renewal forces rekey */
2354+ char *gss_client_identity; /* Principal to initiate GSSAPI with */
2355+ char *gss_server_identity; /* GSSAPI target principal */
2356 int password_authentication; /* Try password
2357 * authentication. */
2358 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
2359Index: b/servconf.c
2360===================================================================
2361--- a/servconf.c
2362+++ b/servconf.c
2363@@ -97,7 +97,10 @@
2364 options->kerberos_ticket_cleanup = -1;
2365 options->kerberos_get_afs_token = -1;
2366 options->gss_authentication=-1;
2367+ options->gss_keyex = -1;
2368 options->gss_cleanup_creds = -1;
2369+ options->gss_strict_acceptor = -1;
2370+ options->gss_store_rekey = -1;
2371 options->password_authentication = -1;
2372 options->kbd_interactive_authentication = -1;
2373 options->challenge_response_authentication = -1;
2374@@ -226,8 +229,14 @@
2375 options->kerberos_get_afs_token = 0;
2376 if (options->gss_authentication == -1)
2377 options->gss_authentication = 0;
2378+ if (options->gss_keyex == -1)
2379+ options->gss_keyex = 0;
2380 if (options->gss_cleanup_creds == -1)
2381 options->gss_cleanup_creds = 1;
2382+ if (options->gss_strict_acceptor == -1)
2383+ options->gss_strict_acceptor = 1;
2384+ if (options->gss_store_rekey == -1)
2385+ options->gss_store_rekey = 0;
2386 if (options->password_authentication == -1)
2387 options->password_authentication = 1;
2388 if (options->kbd_interactive_authentication == -1)
2389@@ -322,7 +331,9 @@
2390 sBanner, sUseDNS, sHostbasedAuthentication,
2391 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
2392 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
2393- sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
2394+ sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
2395+ sGssKeyEx, sGssStoreRekey,
2396+ sAcceptEnv, sPermitTunnel,
2397 sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
2398 sUsePrivilegeSeparation, sAllowAgentForwarding,
2399 sZeroKnowledgePasswordAuthentication, sHostCertificate,
2400@@ -386,10 +397,20 @@
2401 #ifdef GSSAPI
2402 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
2403 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
2404+ { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
2405+ { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
2406+ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
2407+ { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
2408 #else
2409 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
2410 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
2411+ { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
2412+ { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
2413+ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
2414+ { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
2415 #endif
2416+ { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
2417+ { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
2418 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
2419 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
2420 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
2421@@ -944,10 +965,22 @@
2422 intptr = &options->gss_authentication;
2423 goto parse_flag;
2424
2425+ case sGssKeyEx:
2426+ intptr = &options->gss_keyex;
2427+ goto parse_flag;
2428+
2429 case sGssCleanupCreds:
2430 intptr = &options->gss_cleanup_creds;
2431 goto parse_flag;
2432
2433+ case sGssStrictAcceptor:
2434+ intptr = &options->gss_strict_acceptor;
2435+ goto parse_flag;
2436+
2437+ case sGssStoreRekey:
2438+ intptr = &options->gss_store_rekey;
2439+ goto parse_flag;
2440+
2441 case sPasswordAuthentication:
2442 intptr = &options->password_authentication;
2443 goto parse_flag;
2444@@ -1704,7 +1737,10 @@
2445 #endif
2446 #ifdef GSSAPI
2447 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2448+ dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
2449 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2450+ dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
2451+ dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
2452 #endif
2453 #ifdef JPAKE
2454 dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication,
2455Index: b/servconf.h
2456===================================================================
2457--- a/servconf.h
2458+++ b/servconf.h
2459@@ -97,7 +97,10 @@
2460 int kerberos_get_afs_token; /* If true, try to get AFS token if
2461 * authenticated with Kerberos. */
2462 int gss_authentication; /* If true, permit GSSAPI authentication */
2463+ int gss_keyex; /* If true, permit GSSAPI key exchange */
2464 int gss_cleanup_creds; /* If true, destroy cred cache on logout */
2465+ int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */
2466+ int gss_store_rekey;
2467 int password_authentication; /* If true, permit password
2468 * authentication. */
2469 int kbd_interactive_authentication; /* If true, permit */
2470Index: b/ssh-gss.h
2471===================================================================
2472--- a/ssh-gss.h
2473+++ b/ssh-gss.h
2474@@ -1,6 +1,6 @@
2475 /* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */
2476 /*
2477- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
2478+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
2479 *
2480 * Redistribution and use in source and binary forms, with or without
2481 * modification, are permitted provided that the following conditions
2482@@ -60,10 +60,22 @@
2483
2484 #define SSH_GSS_OIDTYPE 0x06
2485
2486+#define SSH2_MSG_KEXGSS_INIT 30
2487+#define SSH2_MSG_KEXGSS_CONTINUE 31
2488+#define SSH2_MSG_KEXGSS_COMPLETE 32
2489+#define SSH2_MSG_KEXGSS_HOSTKEY 33
2490+#define SSH2_MSG_KEXGSS_ERROR 34
2491+#define SSH2_MSG_KEXGSS_GROUPREQ 40
2492+#define SSH2_MSG_KEXGSS_GROUP 41
2493+#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-"
2494+#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-"
2495+#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-"
2496+
2497 typedef struct {
2498 char *filename;
2499 char *envvar;
2500 char *envval;
2501+ struct passwd *owner;
2502 void *data;
2503 } ssh_gssapi_ccache;
2504
2505@@ -71,8 +83,11 @@
2506 gss_buffer_desc displayname;
2507 gss_buffer_desc exportedname;
2508 gss_cred_id_t creds;
2509+ gss_name_t name;
2510 struct ssh_gssapi_mech_struct *mech;
2511 ssh_gssapi_ccache store;
2512+ int used;
2513+ int updated;
2514 } ssh_gssapi_client;
2515
2516 typedef struct ssh_gssapi_mech_struct {
2517@@ -83,6 +98,7 @@
2518 int (*userok) (ssh_gssapi_client *, char *);
2519 int (*localname) (ssh_gssapi_client *, char **);
2520 void (*storecreds) (ssh_gssapi_client *);
2521+ int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
2522 } ssh_gssapi_mech;
2523
2524 typedef struct {
2525@@ -93,10 +109,11 @@
2526 gss_OID oid; /* client */
2527 gss_cred_id_t creds; /* server */
2528 gss_name_t client; /* server */
2529- gss_cred_id_t client_creds; /* server */
2530+ gss_cred_id_t client_creds; /* both */
2531 } Gssctxt;
2532
2533 extern ssh_gssapi_mech *supported_mechs[];
2534+extern Gssctxt *gss_kex_context;
2535
2536 int ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
2537 void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
2538@@ -116,16 +133,30 @@
2539 void ssh_gssapi_delete_ctx(Gssctxt **);
2540 OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
2541 void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
2542-int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *);
2543+int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *);
2544+OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
2545+int ssh_gssapi_credentials_updated(Gssctxt *);
2546
2547 /* In the server */
2548+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,
2549+ const char *);
2550+char *ssh_gssapi_client_mechanisms(const char *, const char *);
2551+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *,
2552+ const char *);
2553+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
2554+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *,
2555+ const char *);
2556 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
2557-int ssh_gssapi_userok(char *name);
2558+int ssh_gssapi_userok(char *name, struct passwd *);
2559 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
2560 void ssh_gssapi_do_child(char ***, u_int *);
2561 void ssh_gssapi_cleanup_creds(void);
2562 void ssh_gssapi_storecreds(void);
2563
2564+char *ssh_gssapi_server_mechanisms(void);
2565+int ssh_gssapi_oid_table_ok();
2566+
2567+int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
2568 #endif /* GSSAPI */
2569
2570 #endif /* _SSH_GSS_H */
2571Index: b/ssh_config
2572===================================================================
2573--- a/ssh_config
2574+++ b/ssh_config
2575@@ -26,6 +26,8 @@
2576 # HostbasedAuthentication no
2577 # GSSAPIAuthentication no
2578 # GSSAPIDelegateCredentials no
2579+# GSSAPIKeyExchange no
2580+# GSSAPITrustDNS no
2581 # BatchMode no
2582 # CheckHostIP yes
2583 # AddressFamily any
2584Index: b/ssh_config.5
2585===================================================================
2586--- a/ssh_config.5
2587+++ b/ssh_config.5
2588@@ -508,11 +508,43 @@
2589 The default is
2590 .Dq no .
2591 Note that this option applies to protocol version 2 only.
2592+.It Cm GSSAPIKeyExchange
2593+Specifies whether key exchange based on GSSAPI may be used. When using
2594+GSSAPI key exchange the server need not have a host key.
2595+The default is
2596+.Dq no .
2597+Note that this option applies to protocol version 2 only.
2598+.It Cm GSSAPIClientIdentity
2599+If set, specifies the GSSAPI client identity that ssh should use when
2600+connecting to the server. The default is unset, which means that the default
2601+identity will be used.
2602+.It Cm GSSAPIServerIdentity
2603+If set, specifies the GSSAPI server identity that ssh should expect when
2604+connecting to the server. The default is unset, which means that the
2605+expected GSSAPI server identity will be determined from the target
2606+hostname.
2607 .It Cm GSSAPIDelegateCredentials
2608 Forward (delegate) credentials to the server.
2609 The default is
2610 .Dq no .
2611-Note that this option applies to protocol version 2 only.
2612+Note that this option applies to protocol version 2 connections using GSSAPI.
2613+.It Cm GSSAPIRenewalForcesRekey
2614+If set to
2615+.Dq yes
2616+then renewal of the client's GSSAPI credentials will force the rekeying of the
2617+ssh connection. With a compatible server, this can delegate the renewed
2618+credentials to a session on the server.
2619+The default is
2620+.Dq no .
2621+.It Cm GSSAPITrustDns
2622+Set to
2623+.Dq yes to indicate that the DNS is trusted to securely canonicalize
2624+the name of the host being connected to. If
2625+.Dq no, the hostname entered on the
2626+command line will be passed untouched to the GSSAPI library.
2627+The default is
2628+.Dq no .
2629+This option only applies to protocol version 2 connections using GSSAPI.
2630 .It Cm HashKnownHosts
2631 Indicates that
2632 .Xr ssh 1
2633Index: b/sshconnect2.c
2634===================================================================
2635--- a/sshconnect2.c
2636+++ b/sshconnect2.c
2637@@ -159,9 +159,34 @@
2638 {
2639 Kex *kex;
2640
2641+#ifdef GSSAPI
2642+ char *orig = NULL, *gss = NULL;
2643+ char *gss_host = NULL;
2644+#endif
2645+
2646 xxx_host = host;
2647 xxx_hostaddr = hostaddr;
2648
2649+#ifdef GSSAPI
2650+ if (options.gss_keyex) {
2651+ /* Add the GSSAPI mechanisms currently supported on this
2652+ * client to the key exchange algorithm proposal */
2653+ orig = myproposal[PROPOSAL_KEX_ALGS];
2654+
2655+ if (options.gss_trust_dns)
2656+ gss_host = (char *)get_canonical_hostname(1);
2657+ else
2658+ gss_host = host;
2659+
2660+ gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
2661+ if (gss) {
2662+ debug("Offering GSSAPI proposal: %s", gss);
2663+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
2664+ "%s,%s", gss, orig);
2665+ }
2666+ }
2667+#endif
2668+
2669 if (options.ciphers == (char *)-1) {
2670 logit("No valid ciphers for protocol version 2 given, using defaults.");
2671 options.ciphers = NULL;
2672@@ -196,6 +221,17 @@
2673 if (options.kex_algorithms != NULL)
2674 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
2675
2676+#ifdef GSSAPI
2677+ /* If we've got GSSAPI algorithms, then we also support the
2678+ * 'null' hostkey, as a last resort */
2679+ if (options.gss_keyex && gss) {
2680+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
2681+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
2682+ "%s,null", orig);
2683+ xfree(gss);
2684+ }
2685+#endif
2686+
2687 if (options.rekey_limit)
2688 packet_set_rekey_limit((u_int32_t)options.rekey_limit);
2689
2690@@ -206,10 +242,30 @@
2691 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
2692 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
2693 kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
2694+#ifdef GSSAPI
2695+ if (options.gss_keyex) {
2696+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
2697+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
2698+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
2699+ }
2700+#endif
2701 kex->client_version_string=client_version_string;
2702 kex->server_version_string=server_version_string;
2703 kex->verify_host_key=&verify_host_key_callback;
2704
2705+#ifdef GSSAPI
2706+ if (options.gss_keyex) {
2707+ kex->gss_deleg_creds = options.gss_deleg_creds;
2708+ kex->gss_trust_dns = options.gss_trust_dns;
2709+ kex->gss_client = options.gss_client_identity;
2710+ if (options.gss_server_identity) {
2711+ kex->gss_host = options.gss_server_identity;
2712+ } else {
2713+ kex->gss_host = gss_host;
2714+ }
2715+ }
2716+#endif
2717+
2718 xxx_kex = kex;
2719
2720 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
2721@@ -304,6 +360,7 @@
2722 void input_gssapi_hash(int type, u_int32_t, void *);
2723 void input_gssapi_error(int, u_int32_t, void *);
2724 void input_gssapi_errtok(int, u_int32_t, void *);
2725+int userauth_gsskeyex(Authctxt *authctxt);
2726 #endif
2727
2728 void userauth(Authctxt *, char *);
2729@@ -319,6 +376,11 @@
2730
2731 Authmethod authmethods[] = {
2732 #ifdef GSSAPI
2733+ {"gssapi-keyex",
2734+ userauth_gsskeyex,
2735+ NULL,
2736+ &options.gss_authentication,
2737+ NULL},
2738 {"gssapi-with-mic",
2739 userauth_gssapi,
2740 NULL,
2741@@ -625,19 +687,31 @@
2742 static u_int mech = 0;
2743 OM_uint32 min;
2744 int ok = 0;
2745+ const char *gss_host;
2746+
2747+ if (options.gss_server_identity)
2748+ gss_host = options.gss_server_identity;
2749+ else if (options.gss_trust_dns)
2750+ gss_host = get_canonical_hostname(1);
2751+ else
2752+ gss_host = authctxt->host;
2753
2754 /* Try one GSSAPI method at a time, rather than sending them all at
2755 * once. */
2756
2757 if (gss_supported == NULL)
2758- gss_indicate_mechs(&min, &gss_supported);
2759+ if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
2760+ gss_supported = NULL;
2761+ return 0;
2762+ }
2763
2764 /* Check to see if the mechanism is usable before we offer it */
2765 while (mech < gss_supported->count && !ok) {
2766 /* My DER encoding requires length<128 */
2767 if (gss_supported->elements[mech].length < 128 &&
2768 ssh_gssapi_check_mechanism(&gssctxt,
2769- &gss_supported->elements[mech], authctxt->host)) {
2770+ &gss_supported->elements[mech], gss_host,
2771+ options.gss_client_identity)) {
2772 ok = 1; /* Mechanism works */
2773 } else {
2774 mech++;
2775@@ -734,8 +808,8 @@
2776 {
2777 Authctxt *authctxt = ctxt;
2778 Gssctxt *gssctxt;
2779- int oidlen;
2780- char *oidv;
2781+ u_int oidlen;
2782+ u_char *oidv;
2783
2784 if (authctxt == NULL)
2785 fatal("input_gssapi_response: no authentication context");
2786@@ -845,6 +919,48 @@
2787 xfree(msg);
2788 xfree(lang);
2789 }
2790+
2791+int
2792+userauth_gsskeyex(Authctxt *authctxt)
2793+{
2794+ Buffer b;
2795+ gss_buffer_desc gssbuf;
2796+ gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
2797+ OM_uint32 ms;
2798+
2799+ static int attempt = 0;
2800+ if (attempt++ >= 1)
2801+ return (0);
2802+
2803+ if (gss_kex_context == NULL) {
2804+ debug("No valid Key exchange context");
2805+ return (0);
2806+ }
2807+
2808+ ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
2809+ "gssapi-keyex");
2810+
2811+ gssbuf.value = buffer_ptr(&b);
2812+ gssbuf.length = buffer_len(&b);
2813+
2814+ if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
2815+ buffer_free(&b);
2816+ return (0);
2817+ }
2818+
2819+ packet_start(SSH2_MSG_USERAUTH_REQUEST);
2820+ packet_put_cstring(authctxt->server_user);
2821+ packet_put_cstring(authctxt->service);
2822+ packet_put_cstring(authctxt->method->name);
2823+ packet_put_string(mic.value, mic.length);
2824+ packet_send();
2825+
2826+ buffer_free(&b);
2827+ gss_release_buffer(&ms, &mic);
2828+
2829+ return (1);
2830+}
2831+
2832 #endif /* GSSAPI */
2833
2834 int
2835Index: b/sshd.c
2836===================================================================
2837--- a/sshd.c
2838+++ b/sshd.c
2839@@ -120,6 +120,10 @@
2840 #include "roaming.h"
2841 #include "version.h"
2842
2843+#ifdef USE_SECURITY_SESSION_API
2844+#include <Security/AuthSession.h>
2845+#endif
2846+
2847 #ifdef LIBWRAP
2848 #include <tcpd.h>
2849 #include <syslog.h>
2850@@ -1590,10 +1594,13 @@
2851 logit("Disabling protocol version 1. Could not load host key");
2852 options.protocol &= ~SSH_PROTO_1;
2853 }
2854+#ifndef GSSAPI
2855+ /* The GSSAPI key exchange can run without a host key */
2856 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
2857 logit("Disabling protocol version 2. Could not load host key");
2858 options.protocol &= ~SSH_PROTO_2;
2859 }
2860+#endif
2861 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
2862 logit("sshd: no hostkeys available -- exiting.");
2863 exit(1);
2864@@ -1922,6 +1929,60 @@
2865 /* Log the connection. */
2866 verbose("Connection from %.500s port %d", remote_ip, remote_port);
2867
2868+#ifdef USE_SECURITY_SESSION_API
2869+ /*
2870+ * Create a new security session for use by the new user login if
2871+ * the current session is the root session or we are not launched
2872+ * by inetd (eg: debugging mode or server mode). We do not
2873+ * necessarily need to create a session if we are launched from
2874+ * inetd because Panther xinetd will create a session for us.
2875+ *
2876+ * The only case where this logic will fail is if there is an
2877+ * inetd running in a non-root session which is not creating
2878+ * new sessions for us. Then all the users will end up in the
2879+ * same session (bad).
2880+ *
2881+ * When the client exits, the session will be destroyed for us
2882+ * automatically.
2883+ *
2884+ * We must create the session before any credentials are stored
2885+ * (including AFS pags, which happens a few lines below).
2886+ */
2887+ {
2888+ OSStatus err = 0;
2889+ SecuritySessionId sid = 0;
2890+ SessionAttributeBits sattrs = 0;
2891+
2892+ err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
2893+ if (err)
2894+ error("SessionGetInfo() failed with error %.8X",
2895+ (unsigned) err);
2896+ else
2897+ debug("Current Session ID is %.8X / Session Attributes are %.8X",
2898+ (unsigned) sid, (unsigned) sattrs);
2899+
2900+ if (inetd_flag && !(sattrs & sessionIsRoot))
2901+ debug("Running in inetd mode in a non-root session... "
2902+ "assuming inetd created the session for us.");
2903+ else {
2904+ debug("Creating new security session...");
2905+ err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
2906+ if (err)
2907+ error("SessionCreate() failed with error %.8X",
2908+ (unsigned) err);
2909+
2910+ err = SessionGetInfo(callerSecuritySession, &sid,
2911+ &sattrs);
2912+ if (err)
2913+ error("SessionGetInfo() failed with error %.8X",
2914+ (unsigned) err);
2915+ else
2916+ debug("New Session ID is %.8X / Session Attributes are %.8X",
2917+ (unsigned) sid, (unsigned) sattrs);
2918+ }
2919+ }
2920+#endif
2921+
2922 /*
2923 * We don't want to listen forever unless the other side
2924 * successfully authenticates itself. So we set up an alarm which is
2925@@ -2303,6 +2364,48 @@
2926
2927 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
2928
2929+#ifdef GSSAPI
2930+ {
2931+ char *orig;
2932+ char *gss = NULL;
2933+ char *newstr = NULL;
2934+ orig = myproposal[PROPOSAL_KEX_ALGS];
2935+
2936+ /*
2937+ * If we don't have a host key, then there's no point advertising
2938+ * the other key exchange algorithms
2939+ */
2940+
2941+ if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
2942+ orig = NULL;
2943+
2944+ if (options.gss_keyex)
2945+ gss = ssh_gssapi_server_mechanisms();
2946+ else
2947+ gss = NULL;
2948+
2949+ if (gss && orig)
2950+ xasprintf(&newstr, "%s,%s", gss, orig);
2951+ else if (gss)
2952+ newstr = gss;
2953+ else if (orig)
2954+ newstr = orig;
2955+
2956+ /*
2957+ * If we've got GSSAPI mechanisms, then we've got the 'null' host
2958+ * key alg, but we can't tell people about it unless its the only
2959+ * host key algorithm we support
2960+ */
2961+ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
2962+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
2963+
2964+ if (newstr)
2965+ myproposal[PROPOSAL_KEX_ALGS] = newstr;
2966+ else
2967+ fatal("No supported key exchange algorithms");
2968+ }
2969+#endif
2970+
2971 /* start key exchange */
2972 kex = kex_setup(myproposal);
2973 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
2974@@ -2310,6 +2413,13 @@
2975 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
2976 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
2977 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
2978+#ifdef GSSAPI
2979+ if (options.gss_keyex) {
2980+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
2981+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
2982+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
2983+ }
2984+#endif
2985 kex->server = 1;
2986 kex->client_version_string=client_version_string;
2987 kex->server_version_string=server_version_string;
2988Index: b/sshd_config
2989===================================================================
2990--- a/sshd_config
2991+++ b/sshd_config
2992@@ -72,6 +72,8 @@
2993 # GSSAPI options
2994 #GSSAPIAuthentication no
2995 #GSSAPICleanupCredentials yes
2996+#GSSAPIStrictAcceptorCheck yes
2997+#GSSAPIKeyExchange no
2998
2999 # Set this to 'yes' to enable PAM authentication, account processing,
3000 # and session processing. If this is enabled, PAM authentication will
3001Index: b/sshd_config.5
3002===================================================================
3003--- a/sshd_config.5
3004+++ b/sshd_config.5
3005@@ -423,12 +423,40 @@
3006 The default is
3007 .Dq no .
3008 Note that this option applies to protocol version 2 only.
3009+.It Cm GSSAPIKeyExchange
3010+Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
3011+doesn't rely on ssh keys to verify host identity.
3012+The default is
3013+.Dq no .
3014+Note that this option applies to protocol version 2 only.
3015 .It Cm GSSAPICleanupCredentials
3016 Specifies whether to automatically destroy the user's credentials cache
3017 on logout.
3018 The default is
3019 .Dq yes .
3020 Note that this option applies to protocol version 2 only.
3021+.It Cm GSSAPIStrictAcceptorCheck
3022+Determines whether to be strict about the identity of the GSSAPI acceptor
3023+a client authenticates against. If
3024+.Dq yes
3025+then the client must authenticate against the
3026+.Pa host
3027+service on the current hostname. If
3028+.Dq no
3029+then the client may authenticate against any service key stored in the
3030+machine's default store. This facility is provided to assist with operation
3031+on multi homed machines.
3032+The default is
3033+.Dq yes .
3034+Note that this option applies only to protocol version 2 GSSAPI connections,
3035+and setting it to
3036+.Dq no
3037+may only work with recent Kerberos GSSAPI libraries.
3038+.It Cm GSSAPIStoreCredentialsOnRekey
3039+Controls whether the user's GSSAPI credentials should be updated following a
3040+successful connection rekeying. This option can be used to accepted renewed
3041+or updated credentials from a compatible client. The default is
3042+.Dq no .
3043 .It Cm HostbasedAuthentication
3044 Specifies whether rhosts or /etc/hosts.equiv authentication together
3045 with successful public key client host authentication is allowed
diff --git a/debian/patches/helpful-wait-terminate.patch b/debian/patches/helpful-wait-terminate.patch
new file mode 100644
index 000000000..857f86456
--- /dev/null
+++ b/debian/patches/helpful-wait-terminate.patch
@@ -0,0 +1,18 @@
1Description: Mention ~& when waiting for forwarded connections to terminate
2Author: Matthew Vernon <matthew@debian.org>
3Bug-Debian: http://bugs.debian.org/50308
4Last-Update: 2010-02-27
5
6Index: b/serverloop.c
7===================================================================
8--- a/serverloop.c
9+++ b/serverloop.c
10@@ -680,7 +680,7 @@
11 if (!channel_still_open())
12 break;
13 if (!waiting_termination) {
14- const char *s = "Waiting for forwarded connections to terminate...\r\n";
15+ const char *s = "Waiting for forwarded connections to terminate... (press ~& to background)\r\n";
16 char *cp;
17 waiting_termination = 1;
18 buffer_append(&stderr_buffer, s, strlen(s));
diff --git a/debian/patches/keepalive-extensions.patch b/debian/patches/keepalive-extensions.patch
new file mode 100644
index 000000000..89011cfb7
--- /dev/null
+++ b/debian/patches/keepalive-extensions.patch
@@ -0,0 +1,124 @@
1Description: Various keepalive extensions
2 Add compatibility aliases for ProtocolKeepAlives and SetupTimeOut,
3 supported in previous versions of Debian's OpenSSH package but since
4 superseded by ServerAliveInterval. (We're probably stuck with this bit for
5 compatibility.)
6 .
7 In batch mode, default ServerAliveInterval to five minutes.
8 .
9 Adjust documentation to match and to give some more advice on use of
10 keepalives.
11Author: Richard Kettlewell <rjk@greenend.org.uk>
12Author: Ian Jackson <ian@chiark.greenend.org.uk>
13Author: Matthew Vernon <matthew@debian.org>
14Author: Colin Watson <cjwatson@debian.org>
15Last-Update: 2010-02-27
16
17Index: b/readconf.c
18===================================================================
19--- a/readconf.c
20+++ b/readconf.c
21@@ -138,6 +138,7 @@
22 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
23 oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
24 oKexAlgorithms, oIPQoS,
25+ oProtocolKeepAlives, oSetupTimeOut,
26 oDeprecated, oUnsupported
27 } OpCodes;
28
29@@ -258,6 +259,8 @@
30 #endif
31 { "kexalgorithms", oKexAlgorithms },
32 { "ipqos", oIPQoS },
33+ { "protocolkeepalives", oProtocolKeepAlives },
34+ { "setuptimeout", oSetupTimeOut },
35
36 { NULL, oBadOption }
37 };
38@@ -888,6 +891,8 @@
39 goto parse_flag;
40
41 case oServerAliveInterval:
42+ case oProtocolKeepAlives: /* Debian-specific compatibility alias */
43+ case oSetupTimeOut: /* Debian-specific compatibility alias */
44 intptr = &options->server_alive_interval;
45 goto parse_time;
46
47@@ -1336,8 +1341,13 @@
48 options->rekey_limit = 0;
49 if (options->verify_host_key_dns == -1)
50 options->verify_host_key_dns = 0;
51- if (options->server_alive_interval == -1)
52- options->server_alive_interval = 0;
53+ if (options->server_alive_interval == -1) {
54+ /* in batch mode, default is 5mins */
55+ if (options->batch_mode == 1)
56+ options->server_alive_interval = 300;
57+ else
58+ options->server_alive_interval = 0;
59+ }
60 if (options->server_alive_count_max == -1)
61 options->server_alive_count_max = 3;
62 if (options->control_master == -1)
63Index: b/ssh_config.5
64===================================================================
65--- a/ssh_config.5
66+++ b/ssh_config.5
67@@ -127,8 +127,12 @@
68 If set to
69 .Dq yes ,
70 passphrase/password querying will be disabled.
71+In addition, the
72+.Cm ServerAliveInterval
73+option will be set to 300 seconds by default.
74 This option is useful in scripts and other batch jobs where no user
75-is present to supply the password.
76+is present to supply the password,
77+and where it is desirable to detect a broken network swiftly.
78 The argument must be
79 .Dq yes
80 or
81@@ -1058,8 +1062,15 @@
82 will send a message through the encrypted
83 channel to request a response from the server.
84 The default
85-is 0, indicating that these messages will not be sent to the server.
86+is 0, indicating that these messages will not be sent to the server,
87+or 300 if the
88+.Cm BatchMode
89+option is set.
90 This option applies to protocol version 2 only.
91+.Cm ProtocolKeepAlives
92+and
93+.Cm SetupTimeOut
94+are Debian-specific compatibility aliases for this option.
95 .It Cm StrictHostKeyChecking
96 If this flag is set to
97 .Dq yes ,
98@@ -1098,6 +1109,12 @@
99 other side.
100 If they are sent, death of the connection or crash of one
101 of the machines will be properly noticed.
102+This option only uses TCP keepalives (as opposed to using ssh level
103+keepalives), so takes a long time to notice when the connection dies.
104+As such, you probably want
105+the
106+.Cm ServerAliveInterval
107+option as well.
108 However, this means that
109 connections will die if the route is down temporarily, and some people
110 find it annoying.
111Index: b/sshd_config.5
112===================================================================
113--- a/sshd_config.5
114+++ b/sshd_config.5
115@@ -1034,6 +1034,9 @@
116 .Pp
117 To disable TCP keepalive messages, the value should be set to
118 .Dq no .
119+.Pp
120+This option was formerly called
121+.Cm KeepAlive .
122 .It Cm TrustedUserCAKeys
123 Specifies a file containing public keys of certificate authorities that are
124 trusted to sign user certificates for authentication.
diff --git a/debian/patches/lintian-symlink-pickiness.patch b/debian/patches/lintian-symlink-pickiness.patch
new file mode 100644
index 000000000..b51377c2d
--- /dev/null
+++ b/debian/patches/lintian-symlink-pickiness.patch
@@ -0,0 +1,23 @@
1Description: Fix picky lintian errors about slogin symlinks
2 Apparently this breaks some SVR4 packaging systems, so upstream can't win
3 either way and opted to keep the status quo. We need this patch anyway.
4Author: Colin Watson <cjwatson@debian.org>
5Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1728
6Last-Update: 2010-04-10
7
8Index: b/Makefile.in
9===================================================================
10--- a/Makefile.in
11+++ b/Makefile.in
12@@ -298,9 +298,9 @@
13 $(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
14 $(INSTALL) -m 644 ssh-vulnkey.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-vulnkey.1
15 -rm -f $(DESTDIR)$(bindir)/slogin
16- ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
17+ ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
18 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
19- ln -s ./ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
20+ ln -s ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
21
22 install-sysconf:
23 if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \
diff --git a/debian/patches/openbsd-docs.patch b/debian/patches/openbsd-docs.patch
new file mode 100644
index 000000000..fc07e8861
--- /dev/null
+++ b/debian/patches/openbsd-docs.patch
@@ -0,0 +1,117 @@
1Description: Adjust various OpenBSD-specific references in manual pages
2 No single bug reference for this patch, but history includes:
3 http://bugs.debian.org/154434 (login.conf(5))
4 http://bugs.debian.org/513417 (/etc/rc)
5 http://bugs.debian.org/530692 (ssl(8))
6 https://bugs.launchpad.net/bugs/456660 (ssl(8))
7Author: Colin Watson <cjwatson@debian.org>
8Forwarded: not-needed
9Last-Update: 2010-02-28
10
11Index: b/moduli.5
12===================================================================
13--- a/moduli.5
14+++ b/moduli.5
15@@ -21,7 +21,7 @@
16 .Nd Diffie Hellman moduli
17 .Sh DESCRIPTION
18 The
19-.Pa /etc/moduli
20+.Pa /etc/ssh/moduli
21 file contains prime numbers and generators for use by
22 .Xr sshd 8
23 in the Diffie-Hellman Group Exchange key exchange method.
24@@ -111,7 +111,7 @@
25 Diffie Hellman output to sufficiently key the selected symmetric cipher.
26 .Xr sshd 8
27 then randomly selects a modulus from
28-.Fa /etc/moduli
29+.Fa /etc/ssh/moduli
30 that best meets the size requirement.
31 .Pp
32 .Sh SEE ALSO
33Index: b/ssh-keygen.1
34===================================================================
35--- a/ssh-keygen.1
36+++ b/ssh-keygen.1
37@@ -147,9 +147,7 @@
38 .Pa ~/.ssh/id_dsa
39 or
40 .Pa ~/.ssh/id_rsa .
41-Additionally, the system administrator may use this to generate host keys,
42-as seen in
43-.Pa /etc/rc .
44+Additionally, the system administrator may use this to generate host keys.
45 .Pp
46 Normally this program generates the key and asks for a file in which
47 to store the private key.
48@@ -393,9 +391,7 @@
49 .It Fl q
50 Silence
51 .Nm ssh-keygen .
52-Used by
53-.Pa /etc/rc
54-when creating a new key.
55+Used by system administration scripts when creating a new key.
56 .It Fl R Ar hostname
57 Removes all keys belonging to
58 .Ar hostname
59Index: b/ssh.1
60===================================================================
61--- a/ssh.1
62+++ b/ssh.1
63@@ -726,6 +726,10 @@
64 .Sx HISTORY
65 section of
66 .Xr ssl 8
67+(on non-OpenBSD systems, see
68+.nh
69+http://www.openbsd.org/cgi\-bin/man.cgi?query=ssl&sektion=8#HISTORY)
70+.hy
71 contains a brief discussion of the DSA and RSA algorithms.
72 .Pp
73 The file
74Index: b/sshd.8
75===================================================================
76--- a/sshd.8
77+++ b/sshd.8
78@@ -69,7 +69,7 @@
79 .Nm
80 listens for connections from clients.
81 It is normally started at boot from
82-.Pa /etc/rc .
83+.Pa /etc/init.d/ssh .
84 It forks a new
85 daemon for each incoming connection.
86 The forked daemons handle
87@@ -850,7 +850,7 @@
88 .Xr ssh 1 ) .
89 It should only be writable by root.
90 .Pp
91-.It Pa /etc/moduli
92+.It Pa /etc/ssh/moduli
93 Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange".
94 The file format is described in
95 .Xr moduli 5 .
96@@ -948,7 +948,6 @@
97 .Xr ssh-vulnkey 1 ,
98 .Xr chroot 2 ,
99 .Xr hosts_access 5 ,
100-.Xr login.conf 5 ,
101 .Xr moduli 5 ,
102 .Xr sshd_config 5 ,
103 .Xr inetd 8 ,
104Index: b/sshd_config.5
105===================================================================
106--- a/sshd_config.5
107+++ b/sshd_config.5
108@@ -221,8 +221,7 @@
109 By default, no banner is displayed.
110 .It Cm ChallengeResponseAuthentication
111 Specifies whether challenge-response authentication is allowed (e.g. via
112-PAM or though authentication styles supported in
113-.Xr login.conf 5 )
114+PAM).
115 The default is
116 .Dq yes .
117 .It Cm ChrootDirectory
diff --git a/debian/patches/package-versioning.patch b/debian/patches/package-versioning.patch
new file mode 100644
index 000000000..ffd416d98
--- /dev/null
+++ b/debian/patches/package-versioning.patch
@@ -0,0 +1,50 @@
1Description: Include the Debian version in our identification
2 This makes it easier to audit networks for versions patched against
3 security vulnerabilities. It has little detrimental effect, as attackers
4 will generally just try attacks rather than bothering to scan for
5 vulnerable-looking version strings. (However, see debian-banner.patch.)
6Author: Matthew Vernon <matthew@debian.org>
7Forwarded: not-needed
8Last-Update: 2010-02-28
9
10Index: b/sshconnect.c
11===================================================================
12--- a/sshconnect.c
13+++ b/sshconnect.c
14@@ -556,7 +556,7 @@
15 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s",
16 compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
17 compat20 ? PROTOCOL_MINOR_2 : minor1,
18- SSH_VERSION, compat20 ? "\r\n" : "\n");
19+ SSH_RELEASE, compat20 ? "\r\n" : "\n");
20 if (roaming_atomicio(vwrite, connection_out, buf, strlen(buf))
21 != strlen(buf))
22 fatal("write: %.100s", strerror(errno));
23Index: b/sshd.c
24===================================================================
25--- a/sshd.c
26+++ b/sshd.c
27@@ -422,7 +422,7 @@
28 minor = PROTOCOL_MINOR_1;
29 }
30 snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s", major, minor,
31- SSH_VERSION, newline);
32+ SSH_RELEASE, newline);
33 server_version_string = xstrdup(buf);
34
35 /* Send our protocol version identification. */
36Index: b/version.h
37===================================================================
38--- a/version.h
39+++ b/version.h
40@@ -3,4 +3,9 @@
41 #define SSH_VERSION "OpenSSH_5.7"
42
43 #define SSH_PORTABLE "p1"
44-#define SSH_RELEASE SSH_VERSION SSH_PORTABLE
45+#define SSH_RELEASE_MINIMUM SSH_VERSION SSH_PORTABLE
46+#ifdef SSH_EXTRAVERSION
47+#define SSH_RELEASE SSH_RELEASE_MINIMUM " " SSH_EXTRAVERSION
48+#else
49+#define SSH_RELEASE SSH_RELEASE_MINIMUM
50+#endif
diff --git a/debian/patches/quieter-signals.patch b/debian/patches/quieter-signals.patch
new file mode 100644
index 000000000..f8bc5fd4e
--- /dev/null
+++ b/debian/patches/quieter-signals.patch
@@ -0,0 +1,31 @@
1Description: Reduce severity of "Killed by signal %d"
2 This produces irritating messages when using ProxyCommand or other programs
3 that use ssh under the covers (e.g. Subversion). These messages are more
4 normally printed by the calling program, such as the shell.
5 .
6 According to the upstream bug, the right way to avoid this is to use the -q
7 option, so we may drop this patch after further investigation into whether
8 any software in Debian is still relying on it.
9Author: Peter Samuelson <peter@p12n.org>
10Author: Colin Watson <cjwatson@debian.org>
11Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1118
12Bug-Debian: http://bugs.debian.org/313371
13Last-Update: 2010-02-27
14
15Index: b/clientloop.c
16===================================================================
17--- a/clientloop.c
18+++ b/clientloop.c
19@@ -1594,8 +1594,10 @@
20 exit_status = 0;
21 }
22
23- if (received_signal)
24- fatal("Killed by signal %d.", (int) received_signal);
25+ if (received_signal) {
26+ debug("Killed by signal %d.", (int) received_signal);
27+ cleanup_exit((int) received_signal + 128);
28+ }
29
30 /*
31 * In interactive mode (with pseudo tty) display a message indicating
diff --git a/debian/patches/scp-quoting.patch b/debian/patches/scp-quoting.patch
new file mode 100644
index 000000000..239c1b599
--- /dev/null
+++ b/debian/patches/scp-quoting.patch
@@ -0,0 +1,32 @@
1Description: Adjust scp quoting in verbose mode
2 Tweak scp's reporting of filenames in verbose mode to be a bit less
3 confusing with spaces.
4 .
5 This should be revised to mimic real shell quoting.
6Author: Nicolas Valcárcel <nvalcarcel@ubuntu.com>
7Bug-Ubuntu: https://bugs.launchpad.net/bugs/89945
8Last-Update: 2010-02-27
9
10Index: b/scp.c
11===================================================================
12--- a/scp.c
13+++ b/scp.c
14@@ -189,8 +189,16 @@
15
16 if (verbose_mode) {
17 fprintf(stderr, "Executing:");
18- for (i = 0; i < a->num; i++)
19- fprintf(stderr, " %s", a->list[i]);
20+ for (i = 0; i < a->num; i++) {
21+ if (i == 0)
22+ fprintf(stderr, " %s", a->list[i]);
23+ else
24+ /*
25+ * TODO: misbehaves if a->list[i] contains a
26+ * single quote
27+ */
28+ fprintf(stderr, " '%s'", a->list[i]);
29+ }
30 fprintf(stderr, "\n");
31 }
32 if ((pid = fork()) == -1)
diff --git a/debian/patches/selinux-build-failure.patch b/debian/patches/selinux-build-failure.patch
new file mode 100644
index 000000000..89b91ff00
--- /dev/null
+++ b/debian/patches/selinux-build-failure.patch
@@ -0,0 +1,236 @@
1Description: Fix SELinux build failure
2Origin: backport, http://bazaar.launchpad.net/~vcs-imports/openssh/main/revision/6317
3Author: Damien Miller <djm@mindrot.org>
4Last-Update: 2011-01-25
5
6Index: b/Makefile.in
7===================================================================
8--- a/Makefile.in
9+++ b/Makefile.in
10@@ -48,6 +48,7 @@
11 CFLAGS=@CFLAGS@
12 CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@
13 LIBS=@LIBS@
14+SSHLIBS=@SSHLIBS@
15 SSHDLIBS=@SSHDLIBS@
16 LIBEDIT=@LIBEDIT@
17 AR=@AR@
18@@ -145,7 +146,7 @@
19 $(RANLIB) $@
20
21 ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS)
22- $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
23+ $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS)
24
25 sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS)
26 $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS)
27Index: b/configure.ac
28===================================================================
29--- a/configure.ac
30+++ b/configure.ac
31@@ -761,7 +761,6 @@
32 [ AC_DEFINE(USE_SOLARIS_PROCESS_CONTRACTS, 1,
33 [Define if you have Solaris process contracts])
34 SSHDLIBS="$SSHDLIBS -lcontract"
35- AC_SUBST(SSHDLIBS)
36 SPC_MSG="yes" ], )
37 ],
38 )
39@@ -772,7 +771,6 @@
40 [ AC_DEFINE(USE_SOLARIS_PROJECTS, 1,
41 [Define if you have Solaris projects])
42 SSHDLIBS="$SSHDLIBS -lproject"
43- AC_SUBST(SSHDLIBS)
44 SP_MSG="yes" ], )
45 ],
46 )
47@@ -3539,11 +3537,14 @@
48 LIBS="$LIBS -lselinux"
49 ],
50 AC_MSG_ERROR(SELinux support requires libselinux library))
51+ SSHLIBS="$SSHLIBS $LIBSELINUX"
52 SSHDLIBS="$SSHDLIBS $LIBSELINUX"
53 AC_CHECK_FUNCS(getseuserbyname get_default_context_with_level)
54 LIBS="$save_LIBS"
55 fi ]
56 )
57+AC_SUBST(SSHLIBS)
58+AC_SUBST(SSHDLIBS)
59
60 # Check whether user wants Kerberos 5 support
61 KRB5_MSG="no"
62@@ -4365,6 +4366,9 @@
63 if test ! -z "${SSHDLIBS}"; then
64 echo " +for sshd: ${SSHDLIBS}"
65 fi
66+if test ! -z "${SSHLIBS}"; then
67+echo " +for ssh: ${SSHLIBS}"
68+fi
69
70 echo ""
71
72Index: b/configure
73===================================================================
74--- a/configure
75+++ b/configure
76@@ -696,7 +696,6 @@
77 LOGIN_PROGRAM_FALLBACK
78 PATH_PASSWD_PROG
79 LD
80-SSHDLIBS
81 PKGCONFIG
82 LIBEDIT
83 TEST_SSH_SHA256
84@@ -721,6 +720,8 @@
85 PROG_IPCS
86 PROG_TAIL
87 INSTALL_SSH_PRNG_CMDS
88+SSHLIBS
89+SSHDLIBS
90 KRB5CONF
91 PRIVSEP_PATH
92 xauth_path
93@@ -9047,7 +9048,6 @@
94 _ACEOF
95
96 SSHDLIBS="$SSHDLIBS -lcontract"
97-
98 SPC_MSG="yes"
99 fi
100
101@@ -9126,7 +9126,6 @@
102 _ACEOF
103
104 SSHDLIBS="$SSHDLIBS -lproject"
105-
106 SP_MSG="yes"
107 fi
108
109@@ -27806,6 +27805,7 @@
110 { (exit 1); exit 1; }; }
111 fi
112
113+ SSHLIBS="$SSHLIBS $LIBSELINUX"
114 SSHDLIBS="$SSHDLIBS $LIBSELINUX"
115
116
117@@ -27908,6 +27908,8 @@
118 fi
119
120
121+
122+
123 # Check whether user wants Kerberos 5 support
124 KRB5_MSG="no"
125
126@@ -31416,7 +31418,6 @@
127 LOGIN_PROGRAM_FALLBACK!$LOGIN_PROGRAM_FALLBACK$ac_delim
128 PATH_PASSWD_PROG!$PATH_PASSWD_PROG$ac_delim
129 LD!$LD$ac_delim
130-SSHDLIBS!$SSHDLIBS$ac_delim
131 PKGCONFIG!$PKGCONFIG$ac_delim
132 LIBEDIT!$LIBEDIT$ac_delim
133 TEST_SSH_SHA256!$TEST_SSH_SHA256$ac_delim
134@@ -31433,6 +31434,7 @@
135 PROG_SAR!$PROG_SAR$ac_delim
136 PROG_W!$PROG_W$ac_delim
137 PROG_WHO!$PROG_WHO$ac_delim
138+PROG_LAST!$PROG_LAST$ac_delim
139 _ACEOF
140
141 if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
142@@ -31474,7 +31476,6 @@
143 ac_delim='%!_!# '
144 for ac_last_try in false false false false false :; do
145 cat >conf$$subs.sed <<_ACEOF
146-PROG_LAST!$PROG_LAST$ac_delim
147 PROG_LASTLOG!$PROG_LASTLOG$ac_delim
148 PROG_DF!$PROG_DF$ac_delim
149 PROG_VMSTAT!$PROG_VMSTAT$ac_delim
150@@ -31482,6 +31483,8 @@
151 PROG_IPCS!$PROG_IPCS$ac_delim
152 PROG_TAIL!$PROG_TAIL$ac_delim
153 INSTALL_SSH_PRNG_CMDS!$INSTALL_SSH_PRNG_CMDS$ac_delim
154+SSHLIBS!$SSHLIBS$ac_delim
155+SSHDLIBS!$SSHDLIBS$ac_delim
156 KRB5CONF!$KRB5CONF$ac_delim
157 PRIVSEP_PATH!$PRIVSEP_PATH$ac_delim
158 xauth_path!$xauth_path$ac_delim
159@@ -31496,7 +31499,7 @@
160 LTLIBOBJS!$LTLIBOBJS$ac_delim
161 _ACEOF
162
163- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 20; then
164+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 21; then
165 break
166 elif $ac_last_try; then
167 { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
168@@ -31993,6 +31996,9 @@
169 if test ! -z "${SSHDLIBS}"; then
170 echo " +for sshd: ${SSHDLIBS}"
171 fi
172+if test ! -z "${SSHLIBS}"; then
173+echo " +for ssh: ${SSHLIBS}"
174+fi
175
176 echo ""
177
178Index: b/openbsd-compat/port-linux.c
179===================================================================
180--- a/openbsd-compat/port-linux.c
181+++ b/openbsd-compat/port-linux.c
182@@ -218,6 +218,20 @@
183 xfree(oldctx);
184 xfree(newctx);
185 }
186+
187+void
188+ssh_selinux_setfscreatecon(const char *path)
189+{
190+ security_context_t context;
191+
192+ if (path == NULL) {
193+ setfscreatecon(NULL);
194+ return;
195+ }
196+ matchpathcon(path, 0700, &context);
197+ setfscreatecon(context);
198+}
199+
200 #endif /* WITH_SELINUX */
201
202 #ifdef LINUX_OOM_ADJUST
203Index: b/openbsd-compat/port-linux.h
204===================================================================
205--- a/openbsd-compat/port-linux.h
206+++ b/openbsd-compat/port-linux.h
207@@ -24,6 +24,7 @@
208 void ssh_selinux_setup_pty(char *, const char *, const char *);
209 void ssh_selinux_setup_exec_context(char *, const char *);
210 void ssh_selinux_change_context(const char *);
211+void ssh_selinux_setfscreatecon(const char *);
212 #endif
213
214 #ifdef LINUX_OOM_ADJUST
215Index: b/ssh.c
216===================================================================
217--- a/ssh.c
218+++ b/ssh.c
219@@ -852,15 +852,12 @@
220 strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
221 if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) {
222 #ifdef WITH_SELINUX
223- char *scon;
224-
225- matchpathcon(buf, 0700, &scon);
226- setfscreatecon(scon);
227+ ssh_selinux_setfscreatecon(buf);
228 #endif
229 if (mkdir(buf, 0700) < 0)
230 error("Could not create directory '%.200s'.", buf);
231 #ifdef WITH_SELINUX
232- setfscreatecon(NULL);
233+ ssh_selinux_setfscreatecon(NULL);
234 #endif
235 }
236 /* load options.identity_files */
diff --git a/debian/patches/selinux-role.patch b/debian/patches/selinux-role.patch
new file mode 100644
index 000000000..30db352dd
--- /dev/null
+++ b/debian/patches/selinux-role.patch
@@ -0,0 +1,482 @@
1Description: Handle SELinux authorisation roles
2 Rejected upstream due to discomfort with magic usernames; a better approach
3 will need an SSH protocol change. In the meantime, this came from Debian's
4 SELinux maintainer, so we'll keep it until we have something better.
5Author: Manoj Srivastava <srivasta@debian.org>
6Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1641
7Bug-Debian: http://bugs.debian.org/394795
8Last-Update: 2010-02-27
9
10Index: b/auth.h
11===================================================================
12--- a/auth.h
13+++ b/auth.h
14@@ -59,6 +59,7 @@
15 char *service;
16 struct passwd *pw; /* set if 'valid' */
17 char *style;
18+ char *role;
19 void *kbdintctxt;
20 void *jpake_ctx;
21 #ifdef BSD_AUTH
22Index: b/auth1.c
23===================================================================
24--- a/auth1.c
25+++ b/auth1.c
26@@ -383,7 +383,7 @@
27 do_authentication(Authctxt *authctxt)
28 {
29 u_int ulen;
30- char *user, *style = NULL;
31+ char *user, *style = NULL, *role = NULL;
32
33 /* Get the name of the user that we wish to log in as. */
34 packet_read_expect(SSH_CMSG_USER);
35@@ -392,11 +392,17 @@
36 user = packet_get_cstring(&ulen);
37 packet_check_eom();
38
39+ if ((role = strchr(user, '/')) != NULL)
40+ *role++ = '\0';
41+
42 if ((style = strchr(user, ':')) != NULL)
43 *style++ = '\0';
44+ else if (role && (style = strchr(role, ':')) != NULL)
45+ *style++ = '\0';
46
47 authctxt->user = user;
48 authctxt->style = style;
49+ authctxt->role = role;
50
51 /* Verify that the user is a valid user. */
52 if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
53Index: b/auth2.c
54===================================================================
55--- a/auth2.c
56+++ b/auth2.c
57@@ -217,7 +217,7 @@
58 {
59 Authctxt *authctxt = ctxt;
60 Authmethod *m = NULL;
61- char *user, *service, *method, *style = NULL;
62+ char *user, *service, *method, *style = NULL, *role = NULL;
63 int authenticated = 0;
64
65 if (authctxt == NULL)
66@@ -229,8 +229,13 @@
67 debug("userauth-request for user %s service %s method %s", user, service, method);
68 debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
69
70+ if ((role = strchr(user, '/')) != NULL)
71+ *role++ = 0;
72+
73 if ((style = strchr(user, ':')) != NULL)
74 *style++ = 0;
75+ else if (role && (style = strchr(role, ':')) != NULL)
76+ *style++ = '\0';
77
78 if (authctxt->attempt++ == 0) {
79 /* setup auth context */
80@@ -254,8 +259,9 @@
81 use_privsep ? " [net]" : "");
82 authctxt->service = xstrdup(service);
83 authctxt->style = style ? xstrdup(style) : NULL;
84+ authctxt->role = role ? xstrdup(role) : NULL;
85 if (use_privsep)
86- mm_inform_authserv(service, style);
87+ mm_inform_authserv(service, style, role);
88 userauth_banner();
89 } else if (strcmp(user, authctxt->user) != 0 ||
90 strcmp(service, authctxt->service) != 0) {
91Index: b/monitor.c
92===================================================================
93--- a/monitor.c
94+++ b/monitor.c
95@@ -137,6 +137,7 @@
96 int mm_answer_pwnamallow(int, Buffer *);
97 int mm_answer_auth2_read_banner(int, Buffer *);
98 int mm_answer_authserv(int, Buffer *);
99+int mm_answer_authrole(int, Buffer *);
100 int mm_answer_authpassword(int, Buffer *);
101 int mm_answer_bsdauthquery(int, Buffer *);
102 int mm_answer_bsdauthrespond(int, Buffer *);
103@@ -215,6 +216,7 @@
104 {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
105 {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
106 {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
107+ {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole},
108 {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
109 {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
110 #ifdef USE_PAM
111@@ -699,6 +701,7 @@
112 else {
113 /* Allow service/style information on the auth context */
114 monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
115+ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHROLE, 1);
116 monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
117 }
118
119@@ -732,14 +735,37 @@
120
121 authctxt->service = buffer_get_string(m, NULL);
122 authctxt->style = buffer_get_string(m, NULL);
123- debug3("%s: service=%s, style=%s",
124- __func__, authctxt->service, authctxt->style);
125+ authctxt->role = buffer_get_string(m, NULL);
126+ debug3("%s: service=%s, style=%s, role=%s",
127+ __func__, authctxt->service, authctxt->style, authctxt->role);
128
129 if (strlen(authctxt->style) == 0) {
130 xfree(authctxt->style);
131 authctxt->style = NULL;
132 }
133
134+ if (strlen(authctxt->role) == 0) {
135+ xfree(authctxt->role);
136+ authctxt->role = NULL;
137+ }
138+
139+ return (0);
140+}
141+
142+int
143+mm_answer_authrole(int sock, Buffer *m)
144+{
145+ monitor_permit_authentications(1);
146+
147+ authctxt->role = buffer_get_string(m, NULL);
148+ debug3("%s: role=%s",
149+ __func__, authctxt->role);
150+
151+ if (strlen(authctxt->role) == 0) {
152+ xfree(authctxt->role);
153+ authctxt->role = NULL;
154+ }
155+
156 return (0);
157 }
158
159@@ -1327,7 +1353,7 @@
160 res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
161 if (res == 0)
162 goto error;
163- pty_setowner(authctxt->pw, s->tty);
164+ pty_setowner(authctxt->pw, s->tty, authctxt->role);
165
166 buffer_put_int(m, 1);
167 buffer_put_cstring(m, s->tty);
168Index: b/monitor.h
169===================================================================
170--- a/monitor.h
171+++ b/monitor.h
172@@ -30,7 +30,7 @@
173
174 enum monitor_reqtype {
175 MONITOR_REQ_MODULI, MONITOR_ANS_MODULI,
176- MONITOR_REQ_FREE, MONITOR_REQ_AUTHSERV,
177+ MONITOR_REQ_FREE, MONITOR_REQ_AUTHSERV, MONITOR_REQ_AUTHROLE,
178 MONITOR_REQ_SIGN, MONITOR_ANS_SIGN,
179 MONITOR_REQ_PWNAM, MONITOR_ANS_PWNAM,
180 MONITOR_REQ_AUTH2_READ_BANNER, MONITOR_ANS_AUTH2_READ_BANNER,
181Index: b/monitor_wrap.c
182===================================================================
183--- a/monitor_wrap.c
184+++ b/monitor_wrap.c
185@@ -280,10 +280,10 @@
186 return (banner);
187 }
188
189-/* Inform the privileged process about service and style */
190+/* Inform the privileged process about service, style, and role */
191
192 void
193-mm_inform_authserv(char *service, char *style)
194+mm_inform_authserv(char *service, char *style, char *role)
195 {
196 Buffer m;
197
198@@ -292,11 +292,29 @@
199 buffer_init(&m);
200 buffer_put_cstring(&m, service);
201 buffer_put_cstring(&m, style ? style : "");
202+ buffer_put_cstring(&m, role ? role : "");
203
204 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHSERV, &m);
205
206 buffer_free(&m);
207 }
208+
209+/* Inform the privileged process about role */
210+
211+void
212+mm_inform_authrole(char *role)
213+{
214+ Buffer m;
215+
216+ debug3("%s entering", __func__);
217+
218+ buffer_init(&m);
219+ buffer_put_cstring(&m, role ? role : "");
220+
221+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHROLE, &m);
222+
223+ buffer_free(&m);
224+}
225
226 /* Do the password authentication */
227 int
228Index: b/monitor_wrap.h
229===================================================================
230--- a/monitor_wrap.h
231+++ b/monitor_wrap.h
232@@ -40,7 +40,8 @@
233 int mm_is_monitor(void);
234 DH *mm_choose_dh(int, int, int);
235 int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int);
236-void mm_inform_authserv(char *, char *);
237+void mm_inform_authserv(char *, char *, char *);
238+void mm_inform_authrole(char *);
239 struct passwd *mm_getpwnamallow(const char *);
240 char *mm_auth2_read_banner(void);
241 int mm_auth_password(struct Authctxt *, char *);
242Index: b/openbsd-compat/port-linux.c
243===================================================================
244--- a/openbsd-compat/port-linux.c
245+++ b/openbsd-compat/port-linux.c
246@@ -29,6 +29,12 @@
247 #include <string.h>
248 #include <stdio.h>
249
250+#ifdef WITH_SELINUX
251+#include "key.h"
252+#include "hostfile.h"
253+#include "auth.h"
254+#endif
255+
256 #include "log.h"
257 #include "xmalloc.h"
258 #include "port-linux.h"
259@@ -54,9 +60,9 @@
260
261 /* Return the default security context for the given username */
262 static security_context_t
263-ssh_selinux_getctxbyname(char *pwname)
264+ssh_selinux_getctxbyname(char *pwname, const char *role)
265 {
266- security_context_t sc;
267+ security_context_t sc = NULL;
268 char *sename = NULL, *lvl = NULL;
269 int r;
270
271@@ -69,9 +75,16 @@
272 #endif
273
274 #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
275- r = get_default_context_with_level(sename, lvl, NULL, &sc);
276+ if (role != NULL && role[0])
277+ r = get_default_context_with_rolelevel(sename, role, lvl, NULL,
278+ &sc);
279+ else
280+ r = get_default_context_with_level(sename, lvl, NULL, &sc);
281 #else
282- r = get_default_context(sename, NULL, &sc);
283+ if (role != NULL && role[0])
284+ r = get_default_context_with_role(sename, role, NULL, &sc);
285+ else
286+ r = get_default_context(sename, NULL, &sc);
287 #endif
288
289 if (r != 0) {
290@@ -102,7 +115,7 @@
291
292 /* Set the execution context to the default for the specified user */
293 void
294-ssh_selinux_setup_exec_context(char *pwname)
295+ssh_selinux_setup_exec_context(char *pwname, const char *role)
296 {
297 security_context_t user_ctx = NULL;
298
299@@ -111,7 +124,7 @@
300
301 debug3("%s: setting execution context", __func__);
302
303- user_ctx = ssh_selinux_getctxbyname(pwname);
304+ user_ctx = ssh_selinux_getctxbyname(pwname, role);
305 if (setexeccon(user_ctx) != 0) {
306 switch (security_getenforce()) {
307 case -1:
308@@ -133,7 +146,7 @@
309
310 /* Set the TTY context for the specified user */
311 void
312-ssh_selinux_setup_pty(char *pwname, const char *tty)
313+ssh_selinux_setup_pty(char *pwname, const char *tty, const char *role)
314 {
315 security_context_t new_tty_ctx = NULL;
316 security_context_t user_ctx = NULL;
317@@ -144,7 +157,7 @@
318
319 debug3("%s: setting TTY context on %s", __func__, tty);
320
321- user_ctx = ssh_selinux_getctxbyname(pwname);
322+ user_ctx = ssh_selinux_getctxbyname(pwname, role);
323
324 /* XXX: should these calls fatal() upon failure in enforcing mode? */
325
326Index: b/openbsd-compat/port-linux.h
327===================================================================
328--- a/openbsd-compat/port-linux.h
329+++ b/openbsd-compat/port-linux.h
330@@ -21,8 +21,8 @@
331
332 #ifdef WITH_SELINUX
333 int ssh_selinux_enabled(void);
334-void ssh_selinux_setup_pty(char *, const char *);
335-void ssh_selinux_setup_exec_context(char *);
336+void ssh_selinux_setup_pty(char *, const char *, const char *);
337+void ssh_selinux_setup_exec_context(char *, const char *);
338 void ssh_selinux_change_context(const char *);
339 #endif
340
341Index: b/platform.c
342===================================================================
343--- a/platform.c
344+++ b/platform.c
345@@ -134,7 +134,7 @@
346 * called if sshd is running as root.
347 */
348 void
349-platform_setusercontext_post_groups(struct passwd *pw)
350+platform_setusercontext_post_groups(struct passwd *pw, const char *role)
351 {
352 #if !defined(HAVE_LOGIN_CAP) && defined(USE_PAM)
353 /*
354@@ -181,7 +181,7 @@
355 }
356 #endif /* HAVE_SETPCRED */
357 #ifdef WITH_SELINUX
358- ssh_selinux_setup_exec_context(pw->pw_name);
359+ ssh_selinux_setup_exec_context(pw->pw_name, role);
360 #endif
361 }
362
363Index: b/platform.h
364===================================================================
365--- a/platform.h
366+++ b/platform.h
367@@ -26,7 +26,7 @@
368 void platform_post_fork_child(void);
369 int platform_privileged_uidswap(void);
370 void platform_setusercontext(struct passwd *);
371-void platform_setusercontext_post_groups(struct passwd *);
372+void platform_setusercontext_post_groups(struct passwd *, const char *);
373 char *platform_get_krb5_client(const char *);
374 char *platform_krb5_get_principal_name(const char *);
375
376Index: b/session.c
377===================================================================
378--- a/session.c
379+++ b/session.c
380@@ -1467,7 +1467,7 @@
381
382 /* Set login name, uid, gid, and groups. */
383 void
384-do_setusercontext(struct passwd *pw)
385+do_setusercontext(struct passwd *pw, const char *role)
386 {
387 char *chroot_path, *tmp;
388
389@@ -1495,7 +1495,7 @@
390 endgrent();
391 #endif
392
393- platform_setusercontext_post_groups(pw);
394+ platform_setusercontext_post_groups(pw, role);
395
396 if (options.chroot_directory != NULL &&
397 strcasecmp(options.chroot_directory, "none") != 0) {
398@@ -1618,7 +1618,7 @@
399
400 /* Force a password change */
401 if (s->authctxt->force_pwchange) {
402- do_setusercontext(pw);
403+ do_setusercontext(pw, s->authctxt->role);
404 child_close_fds();
405 do_pwchange(s);
406 exit(1);
407@@ -1645,7 +1645,7 @@
408 /* When PAM is enabled we rely on it to do the nologin check */
409 if (!options.use_pam)
410 do_nologin(pw);
411- do_setusercontext(pw);
412+ do_setusercontext(pw, s->authctxt->role);
413 /*
414 * PAM session modules in do_setusercontext may have
415 * generated messages, so if this in an interactive
416@@ -2057,7 +2057,7 @@
417 tty_parse_modes(s->ttyfd, &n_bytes);
418
419 if (!use_privsep)
420- pty_setowner(s->pw, s->tty);
421+ pty_setowner(s->pw, s->tty, s->authctxt->role);
422
423 /* Set window size from the packet. */
424 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
425Index: b/session.h
426===================================================================
427--- a/session.h
428+++ b/session.h
429@@ -76,7 +76,7 @@
430 Session *session_new(void);
431 Session *session_by_tty(char *);
432 void session_close(Session *);
433-void do_setusercontext(struct passwd *);
434+void do_setusercontext(struct passwd *, const char *);
435 void child_set_env(char ***envp, u_int *envsizep, const char *name,
436 const char *value);
437
438Index: b/sshd.c
439===================================================================
440--- a/sshd.c
441+++ b/sshd.c
442@@ -707,7 +707,7 @@
443 RAND_seed(rnd, sizeof(rnd));
444
445 /* Drop privileges */
446- do_setusercontext(authctxt->pw);
447+ do_setusercontext(authctxt->pw, authctxt->role);
448
449 skip:
450 /* It is safe now to apply the key state */
451Index: b/sshpty.c
452===================================================================
453--- a/sshpty.c
454+++ b/sshpty.c
455@@ -200,7 +200,7 @@
456 }
457
458 void
459-pty_setowner(struct passwd *pw, const char *tty)
460+pty_setowner(struct passwd *pw, const char *tty, const char *role)
461 {
462 struct group *grp;
463 gid_t gid;
464@@ -227,7 +227,7 @@
465 strerror(errno));
466
467 #ifdef WITH_SELINUX
468- ssh_selinux_setup_pty(pw->pw_name, tty);
469+ ssh_selinux_setup_pty(pw->pw_name, tty, role);
470 #endif
471
472 if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
473Index: b/sshpty.h
474===================================================================
475--- a/sshpty.h
476+++ b/sshpty.h
477@@ -24,4 +24,4 @@
478 void pty_release(const char *);
479 void pty_make_controlling_tty(int *, const char *);
480 void pty_change_window_size(int, u_int, u_int, u_int, u_int);
481-void pty_setowner(struct passwd *, const char *);
482+void pty_setowner(struct passwd *, const char *, const char *);
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 000000000..a3431201e
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,44 @@
1# GSSAPI
2gssapi.patch
3gssapi-autoconf.patch
4
5# SELinux
6selinux-role.patch
7
8# Key blacklisting
9ssh-vulnkey.patch
10
11# Keepalive handling
12ssh1-keepalive.patch
13keepalive-extensions.patch
14
15# Message adjustments
16syslog-level-silent.patch
17quieter-signals.patch
18helpful-wait-terminate.patch
19
20# Miscellaneous bug fixes
21user-group-modes.patch
22scp-quoting.patch
23shell-path.patch
24dnssec-sshfp.patch
25
26# Versioning
27package-versioning.patch
28debian-banner.patch
29
30# File system layout
31authorized-keys-man-symlink.patch
32lintian-symlink-pickiness.patch
33
34# Documentation
35openbsd-docs.patch
36ssh-argv0.patch
37doc-hash-tab-completion.patch
38
39# Upstream backports
40selinux-build-failure.patch
41
42# Debian-specific configuration
43gnome-ssh-askpass2-icon.patch
44debian-config.patch
diff --git a/debian/patches/shell-path.patch b/debian/patches/shell-path.patch
new file mode 100644
index 000000000..5100d8ec7
--- /dev/null
+++ b/debian/patches/shell-path.patch
@@ -0,0 +1,30 @@
1Description: Look for $SHELL on the path for ProxyCommand/LocalCommand
2 There's some debate on the upstream bug about whether POSIX requires this.
3 I (Colin Watson) agree with Vincent and think it does.
4Author: Colin Watson <cjwatson@debian.org>
5Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1494
6Bug-Debian: http://bugs.debian.org/492728
7Last-Update: 2010-02-27
8
9Index: b/sshconnect.c
10===================================================================
11--- a/sshconnect.c
12+++ b/sshconnect.c
13@@ -144,7 +144,7 @@
14 /* Execute the proxy command. Note that we gave up any
15 extra privileges above. */
16 signal(SIGPIPE, SIG_DFL);
17- execv(argv[0], argv);
18+ execvp(argv[0], argv);
19 perror(argv[0]);
20 exit(1);
21 }
22@@ -1274,7 +1274,7 @@
23 if (pid == 0) {
24 signal(SIGPIPE, SIG_DFL);
25 debug3("Executing %s -c \"%s\"", shell, args);
26- execl(shell, shell, "-c", args, (char *)NULL);
27+ execlp(shell, shell, "-c", args, (char *)NULL);
28 error("Couldn't execute %s -c \"%s\": %s",
29 shell, args, strerror(errno));
30 _exit(1);
diff --git a/debian/patches/ssh-argv0.patch b/debian/patches/ssh-argv0.patch
new file mode 100644
index 000000000..43d9d4d44
--- /dev/null
+++ b/debian/patches/ssh-argv0.patch
@@ -0,0 +1,21 @@
1Description: ssh(1): Refer to ssh-argv0(1)
2 Old versions of OpenSSH (up to 2.5 or thereabouts) allowed creating
3 symlinks to ssh with the name of the host you want to connect to. Debian
4 ships an ssh-argv0 script restoring this feature; this patch refers to its
5 manual page from ssh(1).
6Bug-Debian: http://bugs.debian.org/111341
7Forwarded: not-needed
8Last-Update: 2010-02-28
9
10Index: b/ssh.1
11===================================================================
12--- a/ssh.1
13+++ b/ssh.1
14@@ -1406,6 +1406,7 @@
15 .Xr sftp 1 ,
16 .Xr ssh-add 1 ,
17 .Xr ssh-agent 1 ,
18+.Xr ssh-argv0 1 ,
19 .Xr ssh-keygen 1 ,
20 .Xr ssh-keyscan 1 ,
21 .Xr ssh-vulnkey 1 ,
diff --git a/debian/patches/ssh-vulnkey.patch b/debian/patches/ssh-vulnkey.patch
new file mode 100644
index 000000000..78c9833cd
--- /dev/null
+++ b/debian/patches/ssh-vulnkey.patch
@@ -0,0 +1,1385 @@
1Description: Reject vulnerable keys to mitigate Debian OpenSSL flaw
2 In 2008, Debian (and derived distributions such as Ubuntu) shipped an
3 OpenSSL package with a flawed random number generator, causing OpenSSH to
4 generate only a very limited set of keys which were subject to private half
5 precomputation. To mitigate this, this patch checks key authentications
6 against a blacklist of known-vulnerable keys, and adds a new ssh-vulnkey
7 program which can be used to explicitly check keys against that blacklist.
8 See CVE-2008-0166.
9Author: Colin Watson <cjwatson@ubuntu.com>
10Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1469
11Last-Update: 2010-02-27
12
13Index: b/Makefile.in
14===================================================================
15--- a/Makefile.in
16+++ b/Makefile.in
17@@ -27,6 +27,7 @@
18 SSH_KEYSIGN=$(libexecdir)/ssh-keysign
19 SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
20 RAND_HELPER=$(libexecdir)/ssh-rand-helper
21+SSH_DATADIR=$(datadir)/ssh
22 PRIVSEP_PATH=@PRIVSEP_PATH@
23 SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
24 STRIP_OPT=@STRIP_OPT@
25@@ -39,7 +40,8 @@
26 -D_PATH_SSH_PKCS11_HELPER=\"$(SSH_PKCS11_HELPER)\" \
27 -D_PATH_SSH_PIDDIR=\"$(piddir)\" \
28 -D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\" \
29- -DSSH_RAND_HELPER=\"$(RAND_HELPER)\"
30+ -DSSH_RAND_HELPER=\"$(RAND_HELPER)\" \
31+ -D_PATH_SSH_DATADIR=\"$(SSH_DATADIR)\"
32
33 CC=@CC@
34 LD=@LD@
35@@ -63,7 +65,7 @@
36 INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
37 INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
38
39-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT)
40+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-vulnkey$(EXEEXT)
41
42 LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
43 canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
44@@ -96,8 +98,8 @@
45 sftp-server.o sftp-common.o \
46 roaming_common.o roaming_serv.o
47
48-MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out
49-MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5
50+MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-pkcs11-helper.8.out ssh-vulnkey.1.out sshd_config.5.out ssh_config.5.out
51+MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-vulnkey.1 sshd_config.5 ssh_config.5
52 MANTYPE = @MANTYPE@
53
54 CONFIGFILES=sshd_config.out ssh_config.out moduli.out
55@@ -178,6 +180,9 @@
56 ssh-rand-helper${EXEEXT}: $(LIBCOMPAT) libssh.a ssh-rand-helper.o
57 $(LD) -o $@ ssh-rand-helper.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
58
59+ssh-vulnkey$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-vulnkey.o
60+ $(LD) -o $@ ssh-vulnkey.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
61+
62 # test driver for the loginrec code - not built by default
63 logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o
64 $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS)
65@@ -272,6 +277,7 @@
66 $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
67 $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
68 $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
69+ $(INSTALL) -m 0755 $(STRIP_OPT) ssh-vulnkey$(EXEEXT) $(DESTDIR)$(bindir)/ssh-vulnkey$(EXEEXT)
70 $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
71 $(INSTALL) -m 644 scp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
72 $(INSTALL) -m 644 ssh-add.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
73@@ -289,6 +295,7 @@
74 $(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
75 $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
76 $(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
77+ $(INSTALL) -m 644 ssh-vulnkey.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-vulnkey.1
78 -rm -f $(DESTDIR)$(bindir)/slogin
79 ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
80 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
81@@ -378,6 +385,7 @@
82 -rm -f $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT)
83 -rm -f $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT)
84 -rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT)
85+ -rm -f $(DESTDIR)$(bindir)/ssh-vulnkey$(EXEEXT)
86 -rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT)
87 -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
88 -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
89@@ -391,6 +399,7 @@
90 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1
91 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
92 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1
93+ -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-vulnkey.1
94 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
95 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-rand-helper.8
96 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
97Index: b/auth-rh-rsa.c
98===================================================================
99--- a/auth-rh-rsa.c
100+++ b/auth-rh-rsa.c
101@@ -44,7 +44,7 @@
102 {
103 HostStatus host_status;
104
105- if (auth_key_is_revoked(client_host_key))
106+ if (auth_key_is_revoked(client_host_key, 0))
107 return 0;
108
109 /* Check if we would accept it using rhosts authentication. */
110Index: b/auth-rsa.c
111===================================================================
112--- a/auth-rsa.c
113+++ b/auth-rsa.c
114@@ -247,7 +247,7 @@
115 file, linenum, BN_num_bits(key->rsa->n), bits);
116
117 /* Never accept a revoked key */
118- if (auth_key_is_revoked(key))
119+ if (auth_key_is_revoked(key, 0))
120 break;
121
122 /* We have found the desired key. */
123Index: b/auth.c
124===================================================================
125--- a/auth.c
126+++ b/auth.c
127@@ -59,6 +59,7 @@
128 #include "servconf.h"
129 #include "key.h"
130 #include "hostfile.h"
131+#include "authfile.h"
132 #include "auth.h"
133 #include "auth-options.h"
134 #include "canohost.h"
135@@ -621,10 +622,34 @@
136
137 /* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
138 int
139-auth_key_is_revoked(Key *key)
140+auth_key_is_revoked(Key *key, int hostkey)
141 {
142 char *key_fp;
143
144+ if (blacklisted_key(key, &key_fp) == 1) {
145+ if (options.permit_blacklisted_keys) {
146+ if (hostkey)
147+ error("Host key %s blacklisted (see "
148+ "ssh-vulnkey(1)); continuing anyway",
149+ key_fp);
150+ else
151+ logit("Public key %s from %s blacklisted (see "
152+ "ssh-vulnkey(1)); continuing anyway",
153+ key_fp, get_remote_ipaddr());
154+ xfree(key_fp);
155+ } else {
156+ if (hostkey)
157+ error("Host key %s blacklisted (see "
158+ "ssh-vulnkey(1))", key_fp);
159+ else
160+ logit("Public key %s from %s blacklisted (see "
161+ "ssh-vulnkey(1))",
162+ key_fp, get_remote_ipaddr());
163+ xfree(key_fp);
164+ return 1;
165+ }
166+ }
167+
168 if (options.revoked_keys_file == NULL)
169 return 0;
170
171Index: b/auth.h
172===================================================================
173--- a/auth.h
174+++ b/auth.h
175@@ -175,7 +175,7 @@
176
177 FILE *auth_openkeyfile(const char *, struct passwd *, int);
178 FILE *auth_openprincipals(const char *, struct passwd *, int);
179-int auth_key_is_revoked(Key *);
180+int auth_key_is_revoked(Key *, int);
181
182 HostStatus
183 check_key_in_hostfiles(struct passwd *, Key *, const char *,
184Index: b/auth2-hostbased.c
185===================================================================
186--- a/auth2-hostbased.c
187+++ b/auth2-hostbased.c
188@@ -146,7 +146,7 @@
189 int len;
190 char *fp;
191
192- if (auth_key_is_revoked(key))
193+ if (auth_key_is_revoked(key, 0))
194 return 0;
195
196 resolvedname = get_canonical_hostname(options.use_dns);
197Index: b/auth2-pubkey.c
198===================================================================
199--- a/auth2-pubkey.c
200+++ b/auth2-pubkey.c
201@@ -439,9 +439,10 @@
202 int success;
203 char *file;
204
205- if (auth_key_is_revoked(key))
206+ if (auth_key_is_revoked(key, 0))
207 return 0;
208- if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
209+ if (key_is_cert(key) &&
210+ auth_key_is_revoked(key->cert->signature_key, 0))
211 return 0;
212
213 success = user_cert_trusted_ca(pw, key);
214Index: b/authfile.c
215===================================================================
216--- a/authfile.c
217+++ b/authfile.c
218@@ -68,6 +68,7 @@
219 #include "rsa.h"
220 #include "misc.h"
221 #include "atomicio.h"
222+#include "pathnames.h"
223
224 /* Version identification string for SSH v1 identity files. */
225 static const char authfile_id_string[] =
226@@ -906,3 +907,140 @@
227 return ret;
228 }
229
230+/* Scan a blacklist of known-vulnerable keys in blacklist_file. */
231+static int
232+blacklisted_key_in_file(Key *key, const char *blacklist_file, char **fp)
233+{
234+ int fd = -1;
235+ char *dgst_hex = NULL;
236+ char *dgst_packed = NULL, *p;
237+ int i;
238+ size_t line_len;
239+ struct stat st;
240+ char buf[256];
241+ off_t start, lower, upper;
242+ int ret = 0;
243+
244+ debug("Checking blacklist file %s", blacklist_file);
245+ fd = open(blacklist_file, O_RDONLY);
246+ if (fd < 0) {
247+ ret = -1;
248+ goto out;
249+ }
250+
251+ dgst_hex = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
252+ /* Remove all colons */
253+ dgst_packed = xcalloc(1, strlen(dgst_hex) + 1);
254+ for (i = 0, p = dgst_packed; dgst_hex[i]; i++)
255+ if (dgst_hex[i] != ':')
256+ *p++ = dgst_hex[i];
257+ /* Only compare least-significant 80 bits (to keep the blacklist
258+ * size down)
259+ */
260+ line_len = strlen(dgst_packed + 12);
261+ if (line_len > 32)
262+ goto out;
263+
264+ /* Skip leading comments */
265+ start = 0;
266+ for (;;) {
267+ ssize_t r;
268+ char *newline;
269+
270+ r = atomicio(read, fd, buf, sizeof(buf));
271+ if (r <= 0)
272+ goto out;
273+ if (buf[0] != '#')
274+ break;
275+
276+ newline = memchr(buf, '\n', sizeof(buf));
277+ if (!newline)
278+ goto out;
279+ start += newline + 1 - buf;
280+ if (lseek(fd, start, SEEK_SET) < 0)
281+ goto out;
282+ }
283+
284+ /* Initialise binary search record numbers */
285+ if (fstat(fd, &st) < 0)
286+ goto out;
287+ lower = 0;
288+ upper = (st.st_size - start) / (line_len + 1);
289+
290+ while (lower != upper) {
291+ off_t cur;
292+ int cmp;
293+
294+ cur = lower + (upper - lower) / 2;
295+
296+ /* Read this line and compare to digest; this is
297+ * overflow-safe since cur < max(off_t) / (line_len + 1) */
298+ if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0)
299+ break;
300+ if (atomicio(read, fd, buf, line_len) != line_len)
301+ break;
302+ cmp = memcmp(buf, dgst_packed + 12, line_len);
303+ if (cmp < 0) {
304+ if (cur == lower)
305+ break;
306+ lower = cur;
307+ } else if (cmp > 0) {
308+ if (cur == upper)
309+ break;
310+ upper = cur;
311+ } else {
312+ debug("Found %s in blacklist", dgst_hex);
313+ ret = 1;
314+ break;
315+ }
316+ }
317+
318+out:
319+ if (dgst_packed)
320+ xfree(dgst_packed);
321+ if (ret != 1 && dgst_hex) {
322+ xfree(dgst_hex);
323+ dgst_hex = NULL;
324+ }
325+ if (fp)
326+ *fp = dgst_hex;
327+ if (fd >= 0)
328+ close(fd);
329+ return ret;
330+}
331+
332+/*
333+ * Scan blacklists of known-vulnerable keys. If a vulnerable key is found,
334+ * its fingerprint is returned in *fp, unless fp is NULL.
335+ */
336+int
337+blacklisted_key(Key *key, char **fp)
338+{
339+ Key *public;
340+ char *blacklist_file;
341+ int ret, ret2;
342+
343+ public = key_demote(key);
344+ if (public->type == KEY_RSA1)
345+ public->type = KEY_RSA;
346+
347+ xasprintf(&blacklist_file, "%s.%s-%u",
348+ _PATH_BLACKLIST, key_type(public), key_size(public));
349+ ret = blacklisted_key_in_file(public, blacklist_file, fp);
350+ xfree(blacklist_file);
351+ if (ret > 0) {
352+ key_free(public);
353+ return ret;
354+ }
355+
356+ xasprintf(&blacklist_file, "%s.%s-%u",
357+ _PATH_BLACKLIST_CONFIG, key_type(public), key_size(public));
358+ ret2 = blacklisted_key_in_file(public, blacklist_file, fp);
359+ xfree(blacklist_file);
360+ if (ret2 > ret)
361+ ret = ret2;
362+
363+ key_free(public);
364+ return ret;
365+}
366+
367Index: b/authfile.h
368===================================================================
369--- a/authfile.h
370+++ b/authfile.h
371@@ -26,4 +26,6 @@
372 int key_perm_ok(int, const char *);
373 int key_in_file(Key *, const char *, int);
374
375+int blacklisted_key(Key *key, char **fp);
376+
377 #endif
378Index: b/pathnames.h
379===================================================================
380--- a/pathnames.h
381+++ b/pathnames.h
382@@ -18,6 +18,10 @@
383 #define SSHDIR ETCDIR "/ssh"
384 #endif
385
386+#ifndef _PATH_SSH_DATADIR
387+#define _PATH_SSH_DATADIR "/usr/share/ssh"
388+#endif
389+
390 #ifndef _PATH_SSH_PIDDIR
391 #define _PATH_SSH_PIDDIR "/var/run"
392 #endif
393@@ -44,6 +48,9 @@
394 /* Backwards compatibility */
395 #define _PATH_DH_PRIMES SSHDIR "/primes"
396
397+#define _PATH_BLACKLIST _PATH_SSH_DATADIR "/blacklist"
398+#define _PATH_BLACKLIST_CONFIG SSHDIR "/blacklist"
399+
400 #ifndef _PATH_SSH_PROGRAM
401 #define _PATH_SSH_PROGRAM "/usr/bin/ssh"
402 #endif
403Index: b/readconf.c
404===================================================================
405--- a/readconf.c
406+++ b/readconf.c
407@@ -125,6 +125,7 @@
408 oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
409 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
410 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
411+ oUseBlacklistedKeys,
412 oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
413 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
414 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
415@@ -158,6 +159,7 @@
416 { "passwordauthentication", oPasswordAuthentication },
417 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
418 { "kbdinteractivedevices", oKbdInteractiveDevices },
419+ { "useblacklistedkeys", oUseBlacklistedKeys },
420 { "rsaauthentication", oRSAAuthentication },
421 { "pubkeyauthentication", oPubkeyAuthentication },
422 { "dsaauthentication", oPubkeyAuthentication }, /* alias */
423@@ -486,6 +488,10 @@
424 intptr = &options->challenge_response_authentication;
425 goto parse_flag;
426
427+ case oUseBlacklistedKeys:
428+ intptr = &options->use_blacklisted_keys;
429+ goto parse_flag;
430+
431 case oGssAuthentication:
432 intptr = &options->gss_authentication;
433 goto parse_flag;
434@@ -1134,6 +1140,7 @@
435 options->kbd_interactive_devices = NULL;
436 options->rhosts_rsa_authentication = -1;
437 options->hostbased_authentication = -1;
438+ options->use_blacklisted_keys = -1;
439 options->batch_mode = -1;
440 options->check_host_ip = -1;
441 options->strict_host_key_checking = -1;
442@@ -1245,6 +1252,8 @@
443 options->rhosts_rsa_authentication = 0;
444 if (options->hostbased_authentication == -1)
445 options->hostbased_authentication = 0;
446+ if (options->use_blacklisted_keys == -1)
447+ options->use_blacklisted_keys = 0;
448 if (options->batch_mode == -1)
449 options->batch_mode = 0;
450 if (options->check_host_ip == -1)
451Index: b/readconf.h
452===================================================================
453--- a/readconf.h
454+++ b/readconf.h
455@@ -57,6 +57,7 @@
456 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
457 char *kbd_interactive_devices; /* Keyboard-interactive auth devices. */
458 int zero_knowledge_password_authentication; /* Try jpake */
459+ int use_blacklisted_keys; /* If true, send */
460 int batch_mode; /* Batch mode: do not ask for passwords. */
461 int check_host_ip; /* Also keep track of keys for IP address */
462 int strict_host_key_checking; /* Strict host key checking. */
463Index: b/servconf.c
464===================================================================
465--- a/servconf.c
466+++ b/servconf.c
467@@ -104,6 +104,7 @@
468 options->password_authentication = -1;
469 options->kbd_interactive_authentication = -1;
470 options->challenge_response_authentication = -1;
471+ options->permit_blacklisted_keys = -1;
472 options->permit_empty_passwd = -1;
473 options->permit_user_env = -1;
474 options->use_login = -1;
475@@ -243,6 +244,8 @@
476 options->kbd_interactive_authentication = 0;
477 if (options->challenge_response_authentication == -1)
478 options->challenge_response_authentication = 1;
479+ if (options->permit_blacklisted_keys == -1)
480+ options->permit_blacklisted_keys = 0;
481 if (options->permit_empty_passwd == -1)
482 options->permit_empty_passwd = 0;
483 if (options->permit_user_env == -1)
484@@ -322,7 +325,7 @@
485 sListenAddress, sAddressFamily,
486 sPrintMotd, sPrintLastLog, sIgnoreRhosts,
487 sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
488- sStrictModes, sEmptyPasswd, sTCPKeepAlive,
489+ sStrictModes, sPermitBlacklistedKeys, sEmptyPasswd, sTCPKeepAlive,
490 sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
491 sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
492 sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
493@@ -432,6 +435,7 @@
494 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
495 { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
496 { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
497+ { "permitblacklistedkeys", sPermitBlacklistedKeys, SSHCFG_GLOBAL },
498 { "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
499 { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
500 { "uselogin", sUseLogin, SSHCFG_GLOBAL },
501@@ -1029,6 +1033,10 @@
502 intptr = &options->tcp_keep_alive;
503 goto parse_flag;
504
505+ case sPermitBlacklistedKeys:
506+ intptr = &options->permit_blacklisted_keys;
507+ goto parse_flag;
508+
509 case sEmptyPasswd:
510 intptr = &options->permit_empty_passwd;
511 goto parse_flag;
512@@ -1757,6 +1765,7 @@
513 dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
514 dump_cfg_fmtint(sStrictModes, o->strict_modes);
515 dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
516+ dump_cfg_fmtint(sPermitBlacklistedKeys, o->permit_blacklisted_keys);
517 dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
518 dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
519 dump_cfg_fmtint(sUseLogin, o->use_login);
520Index: b/servconf.h
521===================================================================
522--- a/servconf.h
523+++ b/servconf.h
524@@ -107,6 +107,7 @@
525 int challenge_response_authentication;
526 int zero_knowledge_password_authentication;
527 /* If true, permit jpake auth */
528+ int permit_blacklisted_keys; /* If true, permit */
529 int permit_empty_passwd; /* If false, do not permit empty
530 * passwords. */
531 int permit_user_env; /* If true, read ~/.ssh/environment */
532Index: b/ssh-add.1
533===================================================================
534--- a/ssh-add.1
535+++ b/ssh-add.1
536@@ -81,6 +81,10 @@
537 .Nm
538 to work.
539 .Pp
540+Any keys recorded in the blacklist of known-compromised keys (see
541+.Xr ssh-vulnkey 1 )
542+will be refused.
543+.Pp
544 The options are as follows:
545 .Bl -tag -width Ds
546 .It Fl c
547@@ -183,6 +187,7 @@
548 .Xr ssh 1 ,
549 .Xr ssh-agent 1 ,
550 .Xr ssh-keygen 1 ,
551+.Xr ssh-vulnkey 1 ,
552 .Xr sshd 8
553 .Sh AUTHORS
554 OpenSSH is a derivative of the original and free
555Index: b/ssh-add.c
556===================================================================
557--- a/ssh-add.c
558+++ b/ssh-add.c
559@@ -142,7 +142,7 @@
560 add_file(AuthenticationConnection *ac, const char *filename)
561 {
562 Key *private, *cert;
563- char *comment = NULL;
564+ char *comment = NULL, *fp;
565 char msg[1024], *certpath;
566 int fd, perms_ok, ret = -1;
567
568@@ -187,6 +187,14 @@
569 "Bad passphrase, try again for %.200s: ", comment);
570 }
571 }
572+ if (blacklisted_key(private, &fp) == 1) {
573+ fprintf(stderr, "Public key %s blacklisted (see "
574+ "ssh-vulnkey(1)); refusing to add it\n", fp);
575+ xfree(fp);
576+ key_free(private);
577+ xfree(comment);
578+ return -1;
579+ }
580
581 if (ssh_add_identity_constrained(ac, private, comment, lifetime,
582 confirm)) {
583Index: b/ssh-keygen.1
584===================================================================
585--- a/ssh-keygen.1
586+++ b/ssh-keygen.1
587@@ -659,6 +659,7 @@
588 .Xr ssh 1 ,
589 .Xr ssh-add 1 ,
590 .Xr ssh-agent 1 ,
591+.Xr ssh-vulnkey 1 ,
592 .Xr moduli 5 ,
593 .Xr sshd 8
594 .Rs
595Index: b/ssh-vulnkey.1
596===================================================================
597--- /dev/null
598+++ b/ssh-vulnkey.1
599@@ -0,0 +1,242 @@
600+.\" Copyright (c) 2008 Canonical Ltd. All rights reserved.
601+.\"
602+.\" Redistribution and use in source and binary forms, with or without
603+.\" modification, are permitted provided that the following conditions
604+.\" are met:
605+.\" 1. Redistributions of source code must retain the above copyright
606+.\" notice, this list of conditions and the following disclaimer.
607+.\" 2. Redistributions in binary form must reproduce the above copyright
608+.\" notice, this list of conditions and the following disclaimer in the
609+.\" documentation and/or other materials provided with the distribution.
610+.\"
611+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
612+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
613+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
614+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
615+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
616+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
617+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
618+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
619+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
620+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
621+.\"
622+.Dd $Mdocdate: May 12 2008 $
623+.Dt SSH-VULNKEY 1
624+.Os
625+.Sh NAME
626+.Nm ssh-vulnkey
627+.Nd check blacklist of compromised keys
628+.Sh SYNOPSIS
629+.Nm
630+.Op Fl q | Fl v
631+.Ar file ...
632+.Nm
633+.Fl a
634+.Sh DESCRIPTION
635+.Nm
636+checks a key against a blacklist of compromised keys.
637+.Pp
638+A substantial number of keys are known to have been generated using a broken
639+version of OpenSSL distributed by Debian which failed to seed its random
640+number generator correctly.
641+Keys generated using these OpenSSL versions should be assumed to be
642+compromised.
643+This tool may be useful in checking for such keys.
644+.Pp
645+Keys that are compromised cannot be repaired; replacements must be generated
646+using
647+.Xr ssh-keygen 1 .
648+Make sure to update
649+.Pa authorized_keys
650+files on all systems where compromised keys were permitted to authenticate.
651+.Pp
652+The argument list will be interpreted as a list of paths to public key files
653+or
654+.Pa authorized_keys
655+files.
656+If no suitable file is found at a given path,
657+.Nm
658+will append
659+.Pa .pub
660+and retry, in case it was given a private key file.
661+If no files are given as arguments,
662+.Nm
663+will check
664+.Pa ~/.ssh/id_rsa ,
665+.Pa ~/.ssh/id_dsa ,
666+.Pa ~/.ssh/identity ,
667+.Pa ~/.ssh/authorized_keys
668+and
669+.Pa ~/.ssh/authorized_keys2 ,
670+as well as the system's host keys if readable.
671+.Pp
672+If
673+.Dq -
674+is given as an argument,
675+.Nm
676+will read from standard input.
677+This can be used to process output from
678+.Xr ssh-keyscan 1 ,
679+for example:
680+.Pp
681+.Dl $ ssh-keyscan -t rsa remote.example.org | ssh-vulnkey -
682+.Pp
683+Unless the
684+.Cm PermitBlacklistedKeys
685+option is used,
686+.Xr sshd 8
687+will reject attempts to authenticate with keys in the compromised list.
688+.Pp
689+The output from
690+.Nm
691+looks like this:
692+.Pp
693+.Bd -literal -offset indent
694+/etc/ssh/ssh_host_key:1: COMPROMISED: RSA1 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx root@host
695+/home/user/.ssh/id_dsa:1: Not blacklisted: DSA 1024 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx /home/user/.ssh/id_dsa.pub
696+/home/user/.ssh/authorized_keys:3: Unknown (blacklist file not installed): RSA 1024 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx user@host
697+.Ed
698+.Pp
699+Each line is of the following format (any lines beginning with
700+.Dq #
701+should be ignored by scripts):
702+.Pp
703+.Dl Ar filename : Ns Ar line : Ar status : Ar type Ar size Ar fingerprint Ar comment
704+.Pp
705+It is important to distinguish between the possible values of
706+.Ar status :
707+.Pp
708+.Bl -tag -width Ds
709+.It COMPROMISED
710+These keys are listed in a blacklist file, normally because their
711+corresponding private keys are well-known.
712+Replacements must be generated using
713+.Xr ssh-keygen 1 .
714+.It Not blacklisted
715+A blacklist file exists for this key type and size, but this key is not
716+listed in it.
717+Unless there is some particular reason to believe otherwise, this key
718+may be used safely.
719+(Note that DSA keys used with the broken version of OpenSSL distributed
720+by Debian may be compromised in the event that anyone captured a network
721+trace, even if they were generated with a secure version of OpenSSL.)
722+.It Unknown (blacklist file not installed)
723+No blacklist file exists for this key type and size.
724+You should find a suitable published blacklist and install it before
725+deciding whether this key is safe to use.
726+.El
727+.Pp
728+The options are as follows:
729+.Bl -tag -width Ds
730+.It Fl a
731+Check keys of all users on the system.
732+You will typically need to run
733+.Nm
734+as root to use this option.
735+For each user,
736+.Nm
737+will check
738+.Pa ~/.ssh/id_rsa ,
739+.Pa ~/.ssh/id_dsa ,
740+.Pa ~/.ssh/identity ,
741+.Pa ~/.ssh/authorized_keys
742+and
743+.Pa ~/.ssh/authorized_keys2 .
744+It will also check the system's host keys.
745+.It Fl q
746+Quiet mode.
747+Normally,
748+.Nm
749+outputs the fingerprint of each key scanned, with a description of its
750+status.
751+This option suppresses that output.
752+.It Fl v
753+Verbose mode.
754+Normally,
755+.Nm
756+does not output anything for keys that are not listed in their corresponding
757+blacklist file (although it still produces output for keys for which there
758+is no blacklist file, since their status is unknown).
759+This option causes
760+.Nm
761+to produce output for all keys.
762+.El
763+.Sh EXIT STATUS
764+.Nm
765+will exit zero if any of the given keys were in the compromised list,
766+otherwise non-zero.
767+.Sh BLACKLIST FILE FORMAT
768+The blacklist file may start with comments, on lines starting with
769+.Dq # .
770+After these initial comments, it must follow a strict format:
771+.Pp
772+.Bl -bullet -offset indent -compact
773+.It
774+All the lines must be exactly the same length (20 characters followed by a
775+newline) and must be in sorted order.
776+.It
777+Each line must consist of the lower-case hexadecimal MD5 key fingerprint,
778+without colons, and with the first 12 characters removed (that is, the least
779+significant 80 bits of the fingerprint).
780+.El
781+.Pp
782+The key fingerprint may be generated using
783+.Xr ssh-keygen 1 :
784+.Pp
785+.Dl $ ssh-keygen -l -f /path/to/key
786+.Pp
787+This strict format is necessary to allow the blacklist file to be checked
788+quickly, using a binary-search algorithm.
789+.Sh FILES
790+.Bl -tag -width Ds
791+.It Pa ~/.ssh/id_rsa
792+If present, contains the protocol version 2 RSA authentication identity of
793+the user.
794+.It Pa ~/.ssh/id_dsa
795+If present, contains the protocol version 2 DSA authentication identity of
796+the user.
797+.It Pa ~/.ssh/identity
798+If present, contains the protocol version 1 RSA authentication identity of
799+the user.
800+.It Pa ~/.ssh/authorized_keys
801+If present, lists the public keys (RSA/DSA) that can be used for logging in
802+as this user.
803+.It Pa ~/.ssh/authorized_keys2
804+Obsolete name for
805+.Pa ~/.ssh/authorized_keys .
806+This file may still be present on some old systems, but should not be
807+created if it is missing.
808+.It Pa /etc/ssh/ssh_host_rsa_key
809+If present, contains the protocol version 2 RSA identity of the system.
810+.It Pa /etc/ssh/ssh_host_dsa_key
811+If present, contains the protocol version 2 DSA identity of the system.
812+.It Pa /etc/ssh/ssh_host_key
813+If present, contains the protocol version 1 RSA identity of the system.
814+.It Pa /usr/share/ssh/blacklist. Ns Ar TYPE Ns Pa - Ns Ar LENGTH
815+If present, lists the blacklisted keys of type
816+.Ar TYPE
817+.Pf ( Dq RSA
818+or
819+.Dq DSA )
820+and bit length
821+.Ar LENGTH .
822+The format of this file is described above.
823+RSA1 keys are converted to RSA before being checked in the blacklist.
824+Note that the fingerprints of RSA1 keys are computed differently, so you
825+will not be able to find them in the blacklist by hand.
826+.It Pa /etc/ssh/blacklist. Ns Ar TYPE Ns Pa - Ns Ar LENGTH
827+Same as
828+.Pa /usr/share/ssh/blacklist. Ns Ar TYPE Ns Pa - Ns Ar LENGTH ,
829+but may be edited by the system administrator to add new blacklist entries.
830+.El
831+.Sh SEE ALSO
832+.Xr ssh-keygen 1 ,
833+.Xr sshd 8
834+.Sh AUTHORS
835+.An -nosplit
836+.An Colin Watson Aq cjwatson@ubuntu.com
837+.Pp
838+Florian Weimer suggested the option to check keys of all users, and the idea
839+of processing
840+.Xr ssh-keyscan 1
841+output.
842Index: b/ssh-vulnkey.c
843===================================================================
844--- /dev/null
845+++ b/ssh-vulnkey.c
846@@ -0,0 +1,388 @@
847+/*
848+ * Copyright (c) 2008 Canonical Ltd. All rights reserved.
849+ *
850+ * Redistribution and use in source and binary forms, with or without
851+ * modification, are permitted provided that the following conditions
852+ * are met:
853+ * 1. Redistributions of source code must retain the above copyright
854+ * notice, this list of conditions and the following disclaimer.
855+ * 2. Redistributions in binary form must reproduce the above copyright
856+ * notice, this list of conditions and the following disclaimer in the
857+ * documentation and/or other materials provided with the distribution.
858+ *
859+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
860+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
861+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
862+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
863+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
864+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
865+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
866+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
867+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
868+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
869+ */
870+
871+#include "includes.h"
872+
873+#include <sys/types.h>
874+#include <sys/stat.h>
875+
876+#include <errno.h>
877+#include <string.h>
878+#include <stdio.h>
879+#include <fcntl.h>
880+#include <unistd.h>
881+
882+#include <openssl/evp.h>
883+
884+#include "xmalloc.h"
885+#include "ssh.h"
886+#include "log.h"
887+#include "key.h"
888+#include "authfile.h"
889+#include "pathnames.h"
890+#include "uidswap.h"
891+#include "misc.h"
892+
893+extern char *__progname;
894+
895+/* Default files to check */
896+static char *default_host_files[] = {
897+ _PATH_HOST_RSA_KEY_FILE,
898+ _PATH_HOST_DSA_KEY_FILE,
899+ _PATH_HOST_KEY_FILE,
900+ NULL
901+};
902+static char *default_files[] = {
903+ _PATH_SSH_CLIENT_ID_RSA,
904+ _PATH_SSH_CLIENT_ID_DSA,
905+ _PATH_SSH_CLIENT_IDENTITY,
906+ _PATH_SSH_USER_PERMITTED_KEYS,
907+ _PATH_SSH_USER_PERMITTED_KEYS2,
908+ NULL
909+};
910+
911+static int verbosity = 0;
912+
913+static int some_keys = 0;
914+static int some_unknown = 0;
915+static int some_compromised = 0;
916+
917+static void
918+usage(void)
919+{
920+ fprintf(stderr, "usage: %s [-aqv] [file ...]\n", __progname);
921+ fprintf(stderr, "Options:\n");
922+ fprintf(stderr, " -a Check keys of all users.\n");
923+ fprintf(stderr, " -q Quiet mode.\n");
924+ fprintf(stderr, " -v Verbose mode.\n");
925+ exit(1);
926+}
927+
928+static void
929+describe_key(const char *filename, u_long linenum, const char *msg,
930+ Key *key, const char *comment, int min_verbosity)
931+{
932+ char *fp;
933+
934+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
935+ if (verbosity >= min_verbosity) {
936+ if (strchr(filename, ':'))
937+ printf("\"%s\"", filename);
938+ else
939+ printf("%s", filename);
940+ printf(":%lu: %s: %s %u %s %s\n", linenum, msg,
941+ key_type(key), key_size(key), fp, comment);
942+ }
943+ xfree(fp);
944+}
945+
946+static int
947+do_key(const char *filename, u_long linenum,
948+ Key *key, const char *comment)
949+{
950+ Key *public;
951+ int blacklist_status;
952+ int ret = 1;
953+
954+ some_keys = 1;
955+
956+ public = key_demote(key);
957+ if (public->type == KEY_RSA1)
958+ public->type = KEY_RSA;
959+
960+ blacklist_status = blacklisted_key(public, NULL);
961+ if (blacklist_status == -1) {
962+ describe_key(filename, linenum,
963+ "Unknown (blacklist file not installed)", key, comment, 0);
964+ some_unknown = 1;
965+ } else if (blacklist_status == 1) {
966+ describe_key(filename, linenum,
967+ "COMPROMISED", key, comment, 0);
968+ some_compromised = 1;
969+ ret = 0;
970+ } else
971+ describe_key(filename, linenum,
972+ "Not blacklisted", key, comment, 1);
973+
974+ key_free(public);
975+
976+ return ret;
977+}
978+
979+static int
980+do_filename(const char *filename, int quiet_open)
981+{
982+ FILE *f;
983+ char line[SSH_MAX_PUBKEY_BYTES];
984+ char *cp;
985+ u_long linenum = 0;
986+ Key *key;
987+ char *comment = NULL;
988+ int found = 0, ret = 1;
989+
990+ /* Copy much of key_load_public's logic here so that we can read
991+ * several keys from a single file (e.g. authorized_keys).
992+ */
993+
994+ if (strcmp(filename, "-") != 0) {
995+ int save_errno;
996+ f = fopen(filename, "r");
997+ save_errno = errno;
998+ if (!f) {
999+ char pubfile[MAXPATHLEN];
1000+ if (strlcpy(pubfile, filename, sizeof pubfile) <
1001+ sizeof(pubfile) &&
1002+ strlcat(pubfile, ".pub", sizeof pubfile) <
1003+ sizeof(pubfile))
1004+ f = fopen(pubfile, "r");
1005+ }
1006+ errno = save_errno; /* earlier errno is more useful */
1007+ if (!f) {
1008+ if (!quiet_open)
1009+ perror(filename);
1010+ return -1;
1011+ }
1012+ if (verbosity > 0)
1013+ printf("# %s\n", filename);
1014+ } else
1015+ f = stdin;
1016+ while (read_keyfile_line(f, filename, line, sizeof(line),
1017+ &linenum) != -1) {
1018+ int i;
1019+ char *space;
1020+ int type;
1021+ char *end;
1022+
1023+ /* Chop trailing newline. */
1024+ i = strlen(line) - 1;
1025+ if (line[i] == '\n')
1026+ line[i] = '\0';
1027+
1028+ /* Skip leading whitespace, empty and comment lines. */
1029+ for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
1030+ ;
1031+ if (!*cp || *cp == '\n' || *cp == '#')
1032+ continue;
1033+
1034+ /* Cope with ssh-keyscan output and options in
1035+ * authorized_keys files.
1036+ */
1037+ space = strchr(cp, ' ');
1038+ if (!space)
1039+ continue;
1040+ *space = '\0';
1041+ type = key_type_from_name(cp);
1042+ *space = ' ';
1043+ /* Leading number (RSA1) or valid type (RSA/DSA) indicates
1044+ * that we have no host name or options to skip.
1045+ */
1046+ if ((strtol(cp, &end, 10) == 0 || *end != ' ') &&
1047+ type == KEY_UNSPEC) {
1048+ int quoted = 0;
1049+
1050+ for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
1051+ if (*cp == '\\' && cp[1] == '"')
1052+ cp++; /* Skip both */
1053+ else if (*cp == '"')
1054+ quoted = !quoted;
1055+ }
1056+ /* Skip remaining whitespace. */
1057+ for (; *cp == ' ' || *cp == '\t'; cp++)
1058+ ;
1059+ if (!*cp)
1060+ continue;
1061+ }
1062+
1063+ /* Read and process the key itself. */
1064+ key = key_new(KEY_RSA1);
1065+ if (key_read(key, &cp) == 1) {
1066+ while (*cp == ' ' || *cp == '\t')
1067+ cp++;
1068+ if (!do_key(filename, linenum,
1069+ key, *cp ? cp : filename))
1070+ ret = 0;
1071+ found = 1;
1072+ } else {
1073+ key_free(key);
1074+ key = key_new(KEY_UNSPEC);
1075+ if (key_read(key, &cp) == 1) {
1076+ while (*cp == ' ' || *cp == '\t')
1077+ cp++;
1078+ if (!do_key(filename, linenum,
1079+ key, *cp ? cp : filename))
1080+ ret = 0;
1081+ found = 1;
1082+ }
1083+ }
1084+ key_free(key);
1085+ }
1086+ if (f != stdin)
1087+ fclose(f);
1088+
1089+ if (!found && filename) {
1090+ key = key_load_public(filename, &comment);
1091+ if (key) {
1092+ if (!do_key(filename, 1, key, comment))
1093+ ret = 0;
1094+ found = 1;
1095+ }
1096+ if (comment)
1097+ xfree(comment);
1098+ }
1099+
1100+ return ret;
1101+}
1102+
1103+static int
1104+do_host(int quiet_open)
1105+{
1106+ int i;
1107+ struct stat st;
1108+ int ret = 1;
1109+
1110+ for (i = 0; default_host_files[i]; i++) {
1111+ if (stat(default_host_files[i], &st) < 0 && errno == ENOENT)
1112+ continue;
1113+ if (!do_filename(default_host_files[i], quiet_open))
1114+ ret = 0;
1115+ }
1116+
1117+ return ret;
1118+}
1119+
1120+static int
1121+do_user(const char *dir)
1122+{
1123+ int i;
1124+ char *file;
1125+ struct stat st;
1126+ int ret = 1;
1127+
1128+ for (i = 0; default_files[i]; i++) {
1129+ xasprintf(&file, "%s/%s", dir, default_files[i]);
1130+ if (stat(file, &st) < 0 && errno == ENOENT) {
1131+ xfree(file);
1132+ continue;
1133+ }
1134+ if (!do_filename(file, 0))
1135+ ret = 0;
1136+ xfree(file);
1137+ }
1138+
1139+ return ret;
1140+}
1141+
1142+int
1143+main(int argc, char **argv)
1144+{
1145+ int opt, all_users = 0;
1146+ int ret = 1;
1147+ extern int optind;
1148+
1149+ /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1150+ sanitise_stdfd();
1151+
1152+ __progname = ssh_get_progname(argv[0]);
1153+
1154+ SSLeay_add_all_algorithms();
1155+ log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
1156+
1157+ /* We don't need the RNG ourselves, but symbol references here allow
1158+ * ld to link us properly.
1159+ */
1160+ init_rng();
1161+ seed_rng();
1162+
1163+ while ((opt = getopt(argc, argv, "ahqv")) != -1) {
1164+ switch (opt) {
1165+ case 'a':
1166+ all_users = 1;
1167+ break;
1168+ case 'q':
1169+ verbosity--;
1170+ break;
1171+ case 'v':
1172+ verbosity++;
1173+ break;
1174+ case 'h':
1175+ default:
1176+ usage();
1177+ }
1178+ }
1179+
1180+ if (all_users) {
1181+ struct passwd *pw;
1182+
1183+ if (!do_host(0))
1184+ ret = 0;
1185+
1186+ while ((pw = getpwent()) != NULL) {
1187+ if (pw->pw_dir) {
1188+ temporarily_use_uid(pw);
1189+ if (!do_user(pw->pw_dir))
1190+ ret = 0;
1191+ restore_uid();
1192+ }
1193+ }
1194+ } else if (optind == argc) {
1195+ struct passwd *pw;
1196+
1197+ if (!do_host(1))
1198+ ret = 0;
1199+
1200+ if ((pw = getpwuid(geteuid())) == NULL)
1201+ fprintf(stderr, "No user found with uid %u\n",
1202+ (u_int)geteuid());
1203+ else {
1204+ if (!do_user(pw->pw_dir))
1205+ ret = 0;
1206+ }
1207+ } else {
1208+ while (optind < argc)
1209+ if (!do_filename(argv[optind++], 0))
1210+ ret = 0;
1211+ }
1212+
1213+ if (verbosity >= 0) {
1214+ if (some_unknown) {
1215+ printf("#\n");
1216+ printf("# The status of some keys on your system is unknown.\n");
1217+ printf("# You may need to install additional blacklist files.\n");
1218+ }
1219+ if (some_compromised) {
1220+ printf("#\n");
1221+ printf("# Some keys on your system have been compromised!\n");
1222+ printf("# You must replace them using ssh-keygen(1).\n");
1223+ }
1224+ if (some_unknown || some_compromised) {
1225+ printf("#\n");
1226+ printf("# See the ssh-vulnkey(1) manual page for further advice.\n");
1227+ } else if (some_keys && verbosity > 0) {
1228+ printf("#\n");
1229+ printf("# No blacklisted keys!\n");
1230+ }
1231+ }
1232+
1233+ return ret;
1234+}
1235Index: b/ssh.1
1236===================================================================
1237--- a/ssh.1
1238+++ b/ssh.1
1239@@ -1402,6 +1402,7 @@
1240 .Xr ssh-agent 1 ,
1241 .Xr ssh-keygen 1 ,
1242 .Xr ssh-keyscan 1 ,
1243+.Xr ssh-vulnkey 1 ,
1244 .Xr tun 4 ,
1245 .Xr hosts.equiv 5 ,
1246 .Xr ssh_config 5 ,
1247Index: b/ssh.c
1248===================================================================
1249--- a/ssh.c
1250+++ b/ssh.c
1251@@ -1448,7 +1448,7 @@
1252 static void
1253 load_public_identity_files(void)
1254 {
1255- char *filename, *cp, thishost[NI_MAXHOST];
1256+ char *filename, *cp, thishost[NI_MAXHOST], *fp;
1257 char *pwdir = NULL, *pwname = NULL;
1258 int i = 0;
1259 Key *public;
1260@@ -1505,6 +1505,22 @@
1261 public = key_load_public(filename, NULL);
1262 debug("identity file %s type %d", filename,
1263 public ? public->type : -1);
1264+ if (public && blacklisted_key(public, &fp) == 1) {
1265+ if (options.use_blacklisted_keys)
1266+ logit("Public key %s blacklisted (see "
1267+ "ssh-vulnkey(1)); continuing anyway", fp);
1268+ else
1269+ logit("Public key %s blacklisted (see "
1270+ "ssh-vulnkey(1)); refusing to send it",
1271+ fp);
1272+ xfree(fp);
1273+ if (!options.use_blacklisted_keys) {
1274+ key_free(public);
1275+ xfree(filename);
1276+ filename = NULL;
1277+ public = NULL;
1278+ }
1279+ }
1280 xfree(options.identity_files[i]);
1281 identity_files[n_ids] = filename;
1282 identity_keys[n_ids] = public;
1283Index: b/ssh_config.5
1284===================================================================
1285--- a/ssh_config.5
1286+++ b/ssh_config.5
1287@@ -1146,6 +1146,23 @@
1288 .Dq any .
1289 The default is
1290 .Dq any:any .
1291+.It Cm UseBlacklistedKeys
1292+Specifies whether
1293+.Xr ssh 1
1294+should use keys recorded in its blacklist of known-compromised keys (see
1295+.Xr ssh-vulnkey 1 )
1296+for authentication.
1297+If
1298+.Dq yes ,
1299+then attempts to use compromised keys for authentication will be logged but
1300+accepted.
1301+It is strongly recommended that this be used only to install new authorized
1302+keys on the remote system, and even then only with the utmost care.
1303+If
1304+.Dq no ,
1305+then attempts to use compromised keys for authentication will be prevented.
1306+The default is
1307+.Dq no .
1308 .It Cm UsePrivilegedPort
1309 Specifies whether to use a privileged port for outgoing connections.
1310 The argument must be
1311Index: b/sshconnect2.c
1312===================================================================
1313--- a/sshconnect2.c
1314+++ b/sshconnect2.c
1315@@ -1488,6 +1488,8 @@
1316
1317 /* list of keys stored in the filesystem */
1318 for (i = 0; i < options.num_identity_files; i++) {
1319+ if (options.identity_files[i] == NULL)
1320+ continue;
1321 key = options.identity_keys[i];
1322 if (key && key->type == KEY_RSA1)
1323 continue;
1324@@ -1581,7 +1583,7 @@
1325 debug("Offering %s public key: %s", key_type(id->key),
1326 id->filename);
1327 sent = send_pubkey_test(authctxt, id);
1328- } else if (id->key == NULL) {
1329+ } else if (id->key == NULL && id->filename) {
1330 debug("Trying private key: %s", id->filename);
1331 id->key = load_identity_file(id->filename);
1332 if (id->key != NULL) {
1333Index: b/sshd.8
1334===================================================================
1335--- a/sshd.8
1336+++ b/sshd.8
1337@@ -945,6 +945,7 @@
1338 .Xr ssh-agent 1 ,
1339 .Xr ssh-keygen 1 ,
1340 .Xr ssh-keyscan 1 ,
1341+.Xr ssh-vulnkey 1 ,
1342 .Xr chroot 2 ,
1343 .Xr hosts_access 5 ,
1344 .Xr login.conf 5 ,
1345Index: b/sshd.c
1346===================================================================
1347--- a/sshd.c
1348+++ b/sshd.c
1349@@ -1576,6 +1576,11 @@
1350 sensitive_data.host_keys[i] = NULL;
1351 continue;
1352 }
1353+ if (auth_key_is_revoked(key, 1)) {
1354+ key_free(key);
1355+ sensitive_data.host_keys[i] = NULL;
1356+ continue;
1357+ }
1358 switch (key->type) {
1359 case KEY_RSA1:
1360 sensitive_data.ssh1_host_key = key;
1361Index: b/sshd_config.5
1362===================================================================
1363--- a/sshd_config.5
1364+++ b/sshd_config.5
1365@@ -792,6 +792,20 @@
1366 Specifies whether password authentication is allowed.
1367 The default is
1368 .Dq yes .
1369+.It Cm PermitBlacklistedKeys
1370+Specifies whether
1371+.Xr sshd 8
1372+should allow keys recorded in its blacklist of known-compromised keys (see
1373+.Xr ssh-vulnkey 1 ) .
1374+If
1375+.Dq yes ,
1376+then attempts to authenticate with compromised keys will be logged but
1377+accepted.
1378+If
1379+.Dq no ,
1380+then attempts to authenticate with compromised keys will be rejected.
1381+The default is
1382+.Dq no .
1383 .It Cm PermitEmptyPasswords
1384 When password authentication is allowed, it specifies whether the
1385 server allows login to accounts with empty password strings.
diff --git a/debian/patches/ssh1-keepalive.patch b/debian/patches/ssh1-keepalive.patch
new file mode 100644
index 000000000..5f1caddc9
--- /dev/null
+++ b/debian/patches/ssh1-keepalive.patch
@@ -0,0 +1,65 @@
1Description: Partial server keep-alive implementation for SSH1
2Author: Colin Watson <cjwatson@debian.org>
3Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1712
4Last-Update: 2010-02-27
5
6Index: b/clientloop.c
7===================================================================
8--- a/clientloop.c
9+++ b/clientloop.c
10@@ -547,16 +547,21 @@
11 static void
12 server_alive_check(void)
13 {
14- if (packet_inc_alive_timeouts() > options.server_alive_count_max) {
15- logit("Timeout, server %s not responding.", host);
16- cleanup_exit(255);
17+ if (compat20) {
18+ if (packet_inc_alive_timeouts() > options.server_alive_count_max) {
19+ logit("Timeout, server %s not responding.", host);
20+ cleanup_exit(255);
21+ }
22+ packet_start(SSH2_MSG_GLOBAL_REQUEST);
23+ packet_put_cstring("keepalive@openssh.com");
24+ packet_put_char(1); /* boolean: want reply */
25+ packet_send();
26+ /* Insert an empty placeholder to maintain ordering */
27+ client_register_global_confirm(NULL, NULL);
28+ } else {
29+ packet_send_ignore(0);
30+ packet_send();
31 }
32- packet_start(SSH2_MSG_GLOBAL_REQUEST);
33- packet_put_cstring("keepalive@openssh.com");
34- packet_put_char(1); /* boolean: want reply */
35- packet_send();
36- /* Insert an empty placeholder to maintain ordering */
37- client_register_global_confirm(NULL, NULL);
38 }
39
40 /*
41@@ -616,7 +621,7 @@
42 */
43
44 timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */
45- if (options.server_alive_interval > 0 && compat20)
46+ if (options.server_alive_interval > 0)
47 timeout_secs = options.server_alive_interval;
48 set_control_persist_exit_time();
49 if (control_persist_exit_time > 0) {
50Index: b/ssh_config.5
51===================================================================
52--- a/ssh_config.5
53+++ b/ssh_config.5
54@@ -1047,7 +1047,10 @@
55 .Cm ServerAliveCountMax
56 is left at the default, if the server becomes unresponsive,
57 ssh will disconnect after approximately 45 seconds.
58-This option applies to protocol version 2 only.
59+This option applies to protocol version 2 only; in protocol version
60+1 there is no mechanism to request a response from the server to the
61+server alive messages, so disconnection is the responsibility of the TCP
62+stack.
63 .It Cm ServerAliveInterval
64 Sets a timeout interval in seconds after which if no data has been received
65 from the server,
diff --git a/debian/patches/syslog-level-silent.patch b/debian/patches/syslog-level-silent.patch
new file mode 100644
index 000000000..9b560217f
--- /dev/null
+++ b/debian/patches/syslog-level-silent.patch
@@ -0,0 +1,37 @@
1Description: "LogLevel SILENT" compatibility
2 "LogLevel SILENT" (-qq) was introduced in Debian openssh 1:3.0.1p1-1 to
3 match the behaviour of non-free SSH, in which -q does not suppress fatal
4 errors. However, this was unintentionally broken in 1:4.6p1-2 and nobody
5 complained, so we've dropped most of it. The parts that remain are basic
6 configuration file compatibility, and an adjustment to "Pseudo-terminal
7 will not be allocated ..." which should be split out into a separate patch.
8Author: Jonathan David Amery <jdamery@ysolde.ucam.org>
9Author: Matthew Vernon <matthew@debian.org>
10Author: Colin Watson <cjwatson@debian.org>
11Last-Update: 2010-03-31
12
13Index: b/log.c
14===================================================================
15--- a/log.c
16+++ b/log.c
17@@ -90,6 +90,7 @@
18 LogLevel val;
19 } log_levels[] =
20 {
21+ { "SILENT", SYSLOG_LEVEL_QUIET }, /* compatibility */
22 { "QUIET", SYSLOG_LEVEL_QUIET },
23 { "FATAL", SYSLOG_LEVEL_FATAL },
24 { "ERROR", SYSLOG_LEVEL_ERROR },
25Index: b/ssh.c
26===================================================================
27--- a/ssh.c
28+++ b/ssh.c
29@@ -641,7 +641,7 @@
30 tty_flag = 0;
31 /* Do not allocate a tty if stdin is not a tty. */
32 if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) {
33- if (tty_flag)
34+ if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
35 logit("Pseudo-terminal will not be allocated because "
36 "stdin is not a terminal.");
37 tty_flag = 0;
diff --git a/debian/patches/user-group-modes.patch b/debian/patches/user-group-modes.patch
new file mode 100644
index 000000000..fe2d99be0
--- /dev/null
+++ b/debian/patches/user-group-modes.patch
@@ -0,0 +1,202 @@
1Description: Allow harmless group-writability
2 Allow secure files (~/.ssh/config, ~/.ssh/authorized_keys, etc.) to be
3 group-writable, provided that the group in question contains only the
4 file's owner. Rejected upstream for IMO incorrect reasons (e.g. a
5 misunderstanding about the contents of gr->gr_mem). Given that
6 per-user groups and umask 002 are the default setup in Debian (for good
7 reasons - this makes operating in setgid directories with other groups
8 much easier), we need to permit this by default.
9Author: Colin Watson <cjwatson@debian.org>
10Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1060
11Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=314347
12Last-Update: 2010-02-27
13
14Index: b/readconf.c
15===================================================================
16--- a/readconf.c
17+++ b/readconf.c
18@@ -30,6 +30,8 @@
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>
22+#include <pwd.h>
23+#include <grp.h>
24
25 #include "xmalloc.h"
26 #include "ssh.h"
27@@ -1085,8 +1087,7 @@
28
29 if (fstat(fileno(f), &sb) == -1)
30 fatal("fstat %s: %s", filename, strerror(errno));
31- if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
32- (sb.st_mode & 022) != 0))
33+ if (!secure_permissions(&sb, getuid()))
34 fatal("Bad owner or permissions on %s", filename);
35 }
36
37Index: b/ssh.1
38===================================================================
39--- a/ssh.1
40+++ b/ssh.1
41@@ -1293,6 +1293,8 @@
42 .Xr ssh_config 5 .
43 Because of the potential for abuse, this file must have strict permissions:
44 read/write for the user, and not accessible by others.
45+It may be group-writable provided that the group in question contains only
46+the user.
47 .Pp
48 .It Pa ~/.ssh/environment
49 Contains additional definitions for environment variables; see
50Index: b/ssh_config.5
51===================================================================
52--- a/ssh_config.5
53+++ b/ssh_config.5
54@@ -1299,6 +1299,8 @@
55 This file is used by the SSH client.
56 Because of the potential for abuse, this file must have strict permissions:
57 read/write for the user, and not accessible by others.
58+It may be group-writable provided that the group in question contains only
59+the user.
60 .It Pa /etc/ssh/ssh_config
61 Systemwide configuration file.
62 This file provides defaults for those
63Index: b/auth.c
64===================================================================
65--- a/auth.c
66+++ b/auth.c
67@@ -392,8 +392,7 @@
68 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
69 if (options.strict_modes &&
70 (stat(user_hostfile, &st) == 0) &&
71- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
72- (st.st_mode & 022) != 0)) {
73+ !secure_permissions(&st, pw->pw_uid)) {
74 logit("Authentication refused for %.100s: "
75 "bad owner or modes for %.200s",
76 pw->pw_name, user_hostfile);
77@@ -454,8 +453,7 @@
78
79 /* check the open file to avoid races */
80 if (fstat(fileno(f), &st) < 0 ||
81- (st.st_uid != 0 && st.st_uid != uid) ||
82- (st.st_mode & 022) != 0) {
83+ !secure_permissions(&st, uid)) {
84 snprintf(err, errlen, "bad ownership or modes for file %s",
85 buf);
86 return -1;
87@@ -471,8 +469,7 @@
88
89 debug3("secure_filename: checking '%s'", buf);
90 if (stat(buf, &st) < 0 ||
91- (st.st_uid != 0 && st.st_uid != uid) ||
92- (st.st_mode & 022) != 0) {
93+ !secure_permissions(&st, uid)) {
94 snprintf(err, errlen,
95 "bad ownership or modes for directory %s", buf);
96 return -1;
97Index: b/misc.c
98===================================================================
99--- a/misc.c
100+++ b/misc.c
101@@ -48,8 +48,9 @@
102 #include <netdb.h>
103 #ifdef HAVE_PATHS_H
104 # include <paths.h>
105-#include <pwd.h>
106 #endif
107+#include <pwd.h>
108+#include <grp.h>
109 #ifdef SSH_TUN_OPENBSD
110 #include <net/if.h>
111 #endif
112@@ -642,6 +643,55 @@
113 }
114
115 int
116+secure_permissions(struct stat *st, uid_t uid)
117+{
118+ if (st->st_uid != 0 && st->st_uid != uid)
119+ return 0;
120+ if ((st->st_mode & 002) != 0)
121+ return 0;
122+ if ((st->st_mode & 020) != 0) {
123+ /* If the file is group-writable, the group in question must
124+ * have exactly one member, namely the file's owner.
125+ * (Zero-member groups are typically used by setgid
126+ * binaries, and are unlikely to be suitable.)
127+ */
128+ struct passwd *pw;
129+ struct group *gr;
130+ int members = 0;
131+
132+ gr = getgrgid(st->st_gid);
133+ if (!gr)
134+ return 0;
135+
136+ /* Check primary group memberships. */
137+ while ((pw = getpwent()) != NULL) {
138+ if (pw->pw_gid == gr->gr_gid) {
139+ ++members;
140+ if (pw->pw_uid != uid)
141+ return 0;
142+ }
143+ }
144+ endpwent();
145+
146+ pw = getpwuid(st->st_uid);
147+ if (!pw)
148+ return 0;
149+
150+ /* Check supplementary group memberships. */
151+ if (gr->gr_mem[0]) {
152+ ++members;
153+ if (strcmp(pw->pw_name, gr->gr_mem[0]) ||
154+ gr->gr_mem[1])
155+ return 0;
156+ }
157+
158+ if (!members)
159+ return 0;
160+ }
161+ return 1;
162+}
163+
164+int
165 tun_open(int tun, int mode)
166 {
167 #if defined(CUSTOM_SYS_TUN_OPEN)
168Index: b/misc.h
169===================================================================
170--- a/misc.h
171+++ b/misc.h
172@@ -102,4 +102,6 @@
173 int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
174 int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *);
175
176+int secure_permissions(struct stat *st, uid_t uid);
177+
178 #endif /* _MISC_H */
179Index: b/auth-rhosts.c
180===================================================================
181--- a/auth-rhosts.c
182+++ b/auth-rhosts.c
183@@ -256,8 +256,7 @@
184 return 0;
185 }
186 if (options.strict_modes &&
187- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
188- (st.st_mode & 022) != 0)) {
189+ !secure_permissions(&st, pw->pw_uid)) {
190 logit("Rhosts authentication refused for %.100s: "
191 "bad ownership or modes for home directory.", pw->pw_name);
192 auth_debug_add("Rhosts authentication refused for %.100s: "
193@@ -283,8 +282,7 @@
194 * allowing access to their account by anyone.
195 */
196 if (options.strict_modes &&
197- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
198- (st.st_mode & 022) != 0)) {
199+ !secure_permissions(&st, pw->pw_uid)) {
200 logit("Rhosts authentication refused for %.100s: bad modes for %.200s",
201 pw->pw_name, buf);
202 auth_debug_add("Bad file modes for %.200s", buf);