summaryrefslogtreecommitdiff
path: root/debian/patches
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/auth-log-verbosity.patch122
-rw-r--r--debian/patches/authorized-keys-man-symlink.patch18
-rw-r--r--debian/patches/consolekit.patch720
-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/doc-upstart.patch21
-rw-r--r--debian/patches/gnome-ssh-askpass2-icon.patch18
-rw-r--r--debian/patches/gssapi.patch3088
-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/mention-ssh-keygen-on-keychange.patch33
-rw-r--r--debian/patches/openbsd-docs.patch135
-rw-r--r--debian/patches/package-versioning.patch54
-rw-r--r--debian/patches/quieter-signals.patch31
-rw-r--r--debian/patches/scp-quoting.patch32
-rw-r--r--debian/patches/selinux-role.patch479
-rw-r--r--debian/patches/series48
-rw-r--r--debian/patches/shell-path.patch30
-rw-r--r--debian/patches/sigstop.patch20
-rw-r--r--debian/patches/ssh-agent-setgid.patch32
-rw-r--r--debian/patches/ssh-argv0.patch21
-rw-r--r--debian/patches/ssh-vulnkey.patch1382
-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.patch250
28 files changed, 7148 insertions, 0 deletions
diff --git a/debian/patches/auth-log-verbosity.patch b/debian/patches/auth-log-verbosity.patch
new file mode 100644
index 000000000..a6a842ecd
--- /dev/null
+++ b/debian/patches/auth-log-verbosity.patch
@@ -0,0 +1,122 @@
1Description: Quieten logs when multiple from= restrictions are used
2Author: Colin Watson <cjwatson@debian.org>
3Bug-Debian: http://bugs.debian.org/630606
4Forwarded: no
5Last-Update: 2013-09-14
6
7Index: b/auth-options.c
8===================================================================
9--- a/auth-options.c
10+++ b/auth-options.c
11@@ -58,9 +58,20 @@
12 /* "principals=" option. */
13 char *authorized_principals = NULL;
14
15+/* Throttle log messages. */
16+int logged_from_hostip = 0;
17+int logged_cert_hostip = 0;
18+
19 extern ServerOptions options;
20
21 void
22+auth_start_parse_options(void)
23+{
24+ logged_from_hostip = 0;
25+ logged_cert_hostip = 0;
26+}
27+
28+void
29 auth_clear_options(void)
30 {
31 no_agent_forwarding_flag = 0;
32@@ -288,10 +299,13 @@
33 /* FALLTHROUGH */
34 case 0:
35 free(patterns);
36- logit("Authentication tried for %.100s with "
37- "correct key but not from a permitted "
38- "host (host=%.200s, ip=%.200s).",
39- pw->pw_name, remote_host, remote_ip);
40+ if (!logged_from_hostip) {
41+ logit("Authentication tried for %.100s with "
42+ "correct key but not from a permitted "
43+ "host (host=%.200s, ip=%.200s).",
44+ pw->pw_name, remote_host, remote_ip);
45+ logged_from_hostip = 1;
46+ }
47 auth_debug_add("Your host '%.200s' is not "
48 "permitted to use this key for login.",
49 remote_host);
50@@ -513,11 +527,14 @@
51 break;
52 case 0:
53 /* no match */
54- logit("Authentication tried for %.100s "
55- "with valid certificate but not "
56- "from a permitted host "
57- "(ip=%.200s).", pw->pw_name,
58- remote_ip);
59+ if (!logged_cert_hostip) {
60+ logit("Authentication tried for %.100s "
61+ "with valid certificate but not "
62+ "from a permitted host "
63+ "(ip=%.200s).", pw->pw_name,
64+ remote_ip);
65+ logged_cert_hostip = 1;
66+ }
67 auth_debug_add("Your address '%.200s' "
68 "is not permitted to use this "
69 "certificate for login.",
70Index: b/auth-options.h
71===================================================================
72--- a/auth-options.h
73+++ b/auth-options.h
74@@ -33,6 +33,7 @@
75 extern int key_is_cert_authority;
76 extern char *authorized_principals;
77
78+void auth_start_parse_options(void);
79 int auth_parse_options(struct passwd *, char *, char *, u_long);
80 void auth_clear_options(void);
81 int auth_cert_options(Key *, struct passwd *);
82Index: b/auth-rsa.c
83===================================================================
84--- a/auth-rsa.c
85+++ b/auth-rsa.c
86@@ -174,6 +174,8 @@
87 if ((f = auth_openkeyfile(file, pw, options.strict_modes)) == NULL)
88 return 0;
89
90+ auth_start_parse_options();
91+
92 /*
93 * Go though the accepted keys, looking for the current key. If
94 * found, perform a challenge-response dialog to verify that the
95Index: b/auth2-pubkey.c
96===================================================================
97--- a/auth2-pubkey.c
98+++ b/auth2-pubkey.c
99@@ -257,6 +257,7 @@
100 restore_uid();
101 return 0;
102 }
103+ auth_start_parse_options();
104 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
105 /* Skip leading whitespace. */
106 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
107@@ -318,6 +319,7 @@
108 found_key = 0;
109
110 found = NULL;
111+ auth_start_parse_options();
112 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
113 char *cp, *key_options = NULL;
114 if (found != NULL)
115@@ -453,6 +455,7 @@
116 if (key_cert_check_authority(key, 0, 1,
117 principals_file == NULL ? pw->pw_name : NULL, &reason) != 0)
118 goto fail_reason;
119+ auth_start_parse_options();
120 if (auth_cert_options(key, pw) != 0)
121 goto out;
122
diff --git a/debian/patches/authorized-keys-man-symlink.patch b/debian/patches/authorized-keys-man-symlink.patch
new file mode 100644
index 000000000..e48a3cb3e
--- /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: 2013-09-14
6
7Index: b/Makefile.in
8===================================================================
9--- a/Makefile.in
10+++ b/Makefile.in
11@@ -289,6 +289,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 $(INSTALL) -m 644 sftp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
17 $(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
18 $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
diff --git a/debian/patches/consolekit.patch b/debian/patches/consolekit.patch
new file mode 100644
index 000000000..fd064a848
--- /dev/null
+++ b/debian/patches/consolekit.patch
@@ -0,0 +1,720 @@
1Description: Add support for registering ConsoleKit sessions on login
2Author: Colin Watson <cjwatson@ubuntu.com>
3Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1450
4Last-Updated: 2013-09-14
5
6Index: b/Makefile.in
7===================================================================
8--- a/Makefile.in
9+++ b/Makefile.in
10@@ -96,7 +96,8 @@
11 sftp-server.o sftp-common.o \
12 roaming_common.o roaming_serv.o \
13 sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
14- sandbox-seccomp-filter.o
15+ sandbox-seccomp-filter.o \
16+ consolekit.o
17
18 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-keysign.8.out ssh-pkcs11-helper.8.out ssh-vulnkey.1.out sshd_config.5.out ssh_config.5.out
19 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-keysign.8 ssh-pkcs11-helper.8 ssh-vulnkey.1 sshd_config.5 ssh_config.5
20Index: b/configure.ac
21===================================================================
22--- a/configure.ac
23+++ b/configure.ac
24@@ -3841,6 +3841,30 @@
25 AC_SUBST([GSSLIBS])
26 AC_SUBST([K5LIBS])
27
28+# Check whether user wants ConsoleKit support
29+CONSOLEKIT_MSG="no"
30+LIBCK_CONNECTOR=""
31+AC_ARG_WITH(consolekit,
32+ [ --with-consolekit Enable ConsoleKit support],
33+ [ if test "x$withval" != "xno" ; then
34+ AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no])
35+ if test "$PKGCONFIG" != "no"; then
36+ AC_MSG_CHECKING([for ck-connector])
37+ if $PKGCONFIG --exists ck-connector; then
38+ CKCON_CFLAGS=`$PKGCONFIG --cflags ck-connector`
39+ CKCON_LIBS=`$PKGCONFIG --libs ck-connector`
40+ CPPFLAGS="$CPPFLAGS $CKCON_CFLAGS"
41+ SSHDLIBS="$SSHDLIBS $CKCON_LIBS"
42+ AC_MSG_RESULT([yes])
43+ AC_DEFINE(USE_CONSOLEKIT, 1, [Define if you want ConsoleKit support.])
44+ CONSOLEKIT_MSG="yes"
45+ else
46+ AC_MSG_RESULT([no])
47+ fi
48+ fi
49+ fi ]
50+)
51+
52 # Looking for programs, paths and files
53
54 PRIVSEP_PATH=/var/empty
55@@ -4641,6 +4665,7 @@
56 echo " libedit support: $LIBEDIT_MSG"
57 echo " Solaris process contract support: $SPC_MSG"
58 echo " Solaris project support: $SP_MSG"
59+echo " ConsoleKit support: $CONSOLEKIT_MSG"
60 echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
61 echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
62 echo " BSD Auth support: $BSD_AUTH_MSG"
63Index: b/configure
64===================================================================
65--- a/configure
66+++ b/configure
67@@ -738,6 +738,7 @@
68 with_sandbox
69 with_selinux
70 with_kerberos5
71+with_consolekit
72 with_privsep_path
73 with_xauth
74 enable_strip
75@@ -1428,6 +1429,7 @@
76 --with-sandbox=style Specify privilege separation sandbox (no, darwin, rlimit, systrace, seccomp_filter)
77 --with-selinux Enable SELinux support
78 --with-kerberos5=PATH Enable Kerberos 5 support
79+ --with-consolekit Enable ConsoleKit support
80 --with-privsep-path=xxx Path for privilege separation chroot (default=/var/empty)
81 --with-xauth=PATH Specify path to xauth program
82 --with-maildir=/path/to/mail Specify your system mail directory
83@@ -16375,6 +16377,135 @@
84
85
86
87+# Check whether user wants ConsoleKit support
88+CONSOLEKIT_MSG="no"
89+LIBCK_CONNECTOR=""
90+
91+# Check whether --with-consolekit was given.
92+if test "${with_consolekit+set}" = set; then :
93+ withval=$with_consolekit; if test "x$withval" != "xno" ; then
94+ if test -n "$ac_tool_prefix"; then
95+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
96+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
97+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
98+$as_echo_n "checking for $ac_word... " >&6; }
99+if ${ac_cv_path_PKGCONFIG+:} false; then :
100+ $as_echo_n "(cached) " >&6
101+else
102+ case $PKGCONFIG in
103+ [\\/]* | ?:[\\/]*)
104+ ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path.
105+ ;;
106+ *)
107+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
108+for as_dir in $PATH
109+do
110+ IFS=$as_save_IFS
111+ test -z "$as_dir" && as_dir=.
112+ for ac_exec_ext in '' $ac_executable_extensions; do
113+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
114+ ac_cv_path_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext"
115+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
116+ break 2
117+ fi
118+done
119+ done
120+IFS=$as_save_IFS
121+
122+ ;;
123+esac
124+fi
125+PKGCONFIG=$ac_cv_path_PKGCONFIG
126+if test -n "$PKGCONFIG"; then
127+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5
128+$as_echo "$PKGCONFIG" >&6; }
129+else
130+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
131+$as_echo "no" >&6; }
132+fi
133+
134+
135+fi
136+if test -z "$ac_cv_path_PKGCONFIG"; then
137+ ac_pt_PKGCONFIG=$PKGCONFIG
138+ # Extract the first word of "pkg-config", so it can be a program name with args.
139+set dummy pkg-config; ac_word=$2
140+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
141+$as_echo_n "checking for $ac_word... " >&6; }
142+if ${ac_cv_path_ac_pt_PKGCONFIG+:} false; then :
143+ $as_echo_n "(cached) " >&6
144+else
145+ case $ac_pt_PKGCONFIG in
146+ [\\/]* | ?:[\\/]*)
147+ ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path.
148+ ;;
149+ *)
150+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
151+for as_dir in $PATH
152+do
153+ IFS=$as_save_IFS
154+ test -z "$as_dir" && as_dir=.
155+ for ac_exec_ext in '' $ac_executable_extensions; do
156+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
157+ ac_cv_path_ac_pt_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext"
158+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
159+ break 2
160+ fi
161+done
162+ done
163+IFS=$as_save_IFS
164+
165+ ;;
166+esac
167+fi
168+ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG
169+if test -n "$ac_pt_PKGCONFIG"; then
170+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5
171+$as_echo "$ac_pt_PKGCONFIG" >&6; }
172+else
173+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
174+$as_echo "no" >&6; }
175+fi
176+
177+ if test "x$ac_pt_PKGCONFIG" = x; then
178+ PKGCONFIG="no"
179+ else
180+ case $cross_compiling:$ac_tool_warned in
181+yes:)
182+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
183+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
184+ac_tool_warned=yes ;;
185+esac
186+ PKGCONFIG=$ac_pt_PKGCONFIG
187+ fi
188+else
189+ PKGCONFIG="$ac_cv_path_PKGCONFIG"
190+fi
191+
192+ if test "$PKGCONFIG" != "no"; then
193+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ck-connector" >&5
194+$as_echo_n "checking for ck-connector... " >&6; }
195+ if $PKGCONFIG --exists ck-connector; then
196+ CKCON_CFLAGS=`$PKGCONFIG --cflags ck-connector`
197+ CKCON_LIBS=`$PKGCONFIG --libs ck-connector`
198+ CPPFLAGS="$CPPFLAGS $CKCON_CFLAGS"
199+ SSHDLIBS="$SSHDLIBS $CKCON_LIBS"
200+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
201+$as_echo "yes" >&6; }
202+
203+$as_echo "#define USE_CONSOLEKIT 1" >>confdefs.h
204+
205+ CONSOLEKIT_MSG="yes"
206+ else
207+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
208+$as_echo "no" >&6; }
209+ fi
210+ fi
211+ fi
212+
213+fi
214+
215+
216 # Looking for programs, paths and files
217
218 PRIVSEP_PATH=/var/empty
219@@ -18902,6 +19033,7 @@
220 echo " libedit support: $LIBEDIT_MSG"
221 echo " Solaris process contract support: $SPC_MSG"
222 echo " Solaris project support: $SP_MSG"
223+echo " ConsoleKit support: $CONSOLEKIT_MSG"
224 echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
225 echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
226 echo " BSD Auth support: $BSD_AUTH_MSG"
227Index: b/consolekit.c
228===================================================================
229--- /dev/null
230+++ b/consolekit.c
231@@ -0,0 +1,240 @@
232+/*
233+ * Copyright (c) 2008 Colin Watson. All rights reserved.
234+ *
235+ * Permission to use, copy, modify, and distribute this software for any
236+ * purpose with or without fee is hereby granted, provided that the above
237+ * copyright notice and this permission notice appear in all copies.
238+ *
239+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
240+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
241+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
242+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
243+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
244+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
245+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
246+ */
247+/*
248+ * Loosely based on pam-ck-connector, which is:
249+ *
250+ * Copyright (c) 2007 David Zeuthen <davidz@redhat.com>
251+ *
252+ * Permission is hereby granted, free of charge, to any person
253+ * obtaining a copy of this software and associated documentation
254+ * files (the "Software"), to deal in the Software without
255+ * restriction, including without limitation the rights to use,
256+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
257+ * copies of the Software, and to permit persons to whom the
258+ * Software is furnished to do so, subject to the following
259+ * conditions:
260+ *
261+ * The above copyright notice and this permission notice shall be
262+ * included in all copies or substantial portions of the Software.
263+ *
264+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
265+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
266+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
267+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
268+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
269+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
270+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
271+ * OTHER DEALINGS IN THE SOFTWARE.
272+ */
273+
274+#include "includes.h"
275+
276+#ifdef USE_CONSOLEKIT
277+
278+#include <ck-connector.h>
279+
280+#include "openbsd-compat/sys-queue.h"
281+#include "xmalloc.h"
282+#include "channels.h"
283+#include "key.h"
284+#include "hostfile.h"
285+#include "auth.h"
286+#include "log.h"
287+#include "servconf.h"
288+#include "canohost.h"
289+#include "session.h"
290+#include "consolekit.h"
291+
292+extern ServerOptions options;
293+extern u_int utmp_len;
294+
295+void
296+set_active(const char *cookie)
297+{
298+ DBusError err;
299+ DBusConnection *connection;
300+ DBusMessage *message = NULL, *reply = NULL;
301+ char *sid;
302+ DBusMessageIter iter, subiter;
303+ const char *interface, *property;
304+ dbus_bool_t active;
305+
306+ dbus_error_init(&err);
307+ connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
308+ if (!connection) {
309+ if (dbus_error_is_set(&err)) {
310+ error("unable to open DBus connection: %s",
311+ err.message);
312+ dbus_error_free(&err);
313+ }
314+ goto out;
315+ }
316+ dbus_connection_set_exit_on_disconnect(connection, FALSE);
317+
318+ message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
319+ "/org/freedesktop/ConsoleKit/Manager",
320+ "org.freedesktop.ConsoleKit.Manager",
321+ "GetSessionForCookie");
322+ if (!message)
323+ goto out;
324+ if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &cookie,
325+ DBUS_TYPE_INVALID)) {
326+ if (dbus_error_is_set(&err)) {
327+ error("unable to get current session: %s",
328+ err.message);
329+ dbus_error_free(&err);
330+ }
331+ goto out;
332+ }
333+
334+ dbus_error_init(&err);
335+ reply = dbus_connection_send_with_reply_and_block(connection, message,
336+ -1, &err);
337+ if (!reply) {
338+ if (dbus_error_is_set(&err)) {
339+ error("unable to get current session: %s",
340+ err.message);
341+ dbus_error_free(&err);
342+ }
343+ goto out;
344+ }
345+
346+ dbus_error_init(&err);
347+ if (!dbus_message_get_args(reply, &err,
348+ DBUS_TYPE_OBJECT_PATH, &sid,
349+ DBUS_TYPE_INVALID)) {
350+ if (dbus_error_is_set(&err)) {
351+ error("unable to get current session: %s",
352+ err.message);
353+ dbus_error_free(&err);
354+ }
355+ goto out;
356+ }
357+ dbus_message_unref(reply);
358+ dbus_message_unref(message);
359+ message = reply = NULL;
360+
361+ message = dbus_message_new_method_call("org.freedesktop.ConsoleKit",
362+ sid, "org.freedesktop.DBus.Properties", "Set");
363+ if (!message)
364+ goto out;
365+ interface = "org.freedesktop.ConsoleKit.Session";
366+ property = "active";
367+ if (!dbus_message_append_args(message,
368+ DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property,
369+ DBUS_TYPE_INVALID))
370+ goto out;
371+ dbus_message_iter_init_append(message, &iter);
372+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
373+ DBUS_TYPE_BOOLEAN_AS_STRING, &subiter))
374+ goto out;
375+ active = TRUE;
376+ if (!dbus_message_iter_append_basic(&subiter, DBUS_TYPE_BOOLEAN,
377+ &active))
378+ goto out;
379+ if (!dbus_message_iter_close_container(&iter, &subiter))
380+ goto out;
381+
382+ dbus_error_init(&err);
383+ reply = dbus_connection_send_with_reply_and_block(connection, message,
384+ -1, &err);
385+ if (!reply) {
386+ if (dbus_error_is_set(&err)) {
387+ error("unable to make current session active: %s",
388+ err.message);
389+ dbus_error_free(&err);
390+ }
391+ goto out;
392+ }
393+
394+out:
395+ if (reply)
396+ dbus_message_unref(reply);
397+ if (message)
398+ dbus_message_unref(message);
399+}
400+
401+/*
402+ * We pass display separately rather than using s->display because the
403+ * latter is not available in the monitor when using privsep.
404+ */
405+
406+char *
407+consolekit_register(Session *s, const char *display)
408+{
409+ DBusError err;
410+ const char *tty = s->tty;
411+ const char *remote_host_name;
412+ dbus_bool_t is_local = FALSE;
413+ const char *cookie = NULL;
414+
415+ if (s->ckc) {
416+ debug("already registered with ConsoleKit");
417+ return xstrdup(ck_connector_get_cookie(s->ckc));
418+ }
419+
420+ s->ckc = ck_connector_new();
421+ if (!s->ckc) {
422+ error("ck_connector_new failed");
423+ return NULL;
424+ }
425+
426+ if (!tty)
427+ tty = "";
428+ if (!display)
429+ display = "";
430+ remote_host_name = get_remote_name_or_ip(utmp_len, options.use_dns);
431+ if (!remote_host_name)
432+ remote_host_name = "";
433+
434+ dbus_error_init(&err);
435+ if (!ck_connector_open_session_with_parameters(s->ckc, &err,
436+ "unix-user", &s->pw->pw_uid,
437+ "display-device", &tty,
438+ "x11-display", &display,
439+ "remote-host-name", &remote_host_name,
440+ "is-local", &is_local,
441+ NULL)) {
442+ if (dbus_error_is_set(&err)) {
443+ debug("%s", err.message);
444+ dbus_error_free(&err);
445+ } else {
446+ debug("insufficient privileges or D-Bus / ConsoleKit "
447+ "not available");
448+ }
449+ return NULL;
450+ }
451+
452+ debug("registered uid=%d on tty='%s' with ConsoleKit",
453+ s->pw->pw_uid, s->tty);
454+
455+ cookie = ck_connector_get_cookie(s->ckc);
456+ set_active(cookie);
457+ return xstrdup(cookie);
458+}
459+
460+void
461+consolekit_unregister(Session *s)
462+{
463+ if (s->ckc) {
464+ debug("unregistering ConsoleKit session %s",
465+ ck_connector_get_cookie(s->ckc));
466+ ck_connector_unref(s->ckc);
467+ s->ckc = NULL;
468+ }
469+}
470+
471+#endif /* USE_CONSOLEKIT */
472Index: b/consolekit.h
473===================================================================
474--- /dev/null
475+++ b/consolekit.h
476@@ -0,0 +1,24 @@
477+/*
478+ * Copyright (c) 2008 Colin Watson. All rights reserved.
479+ *
480+ * Permission to use, copy, modify, and distribute this software for any
481+ * purpose with or without fee is hereby granted, provided that the above
482+ * copyright notice and this permission notice appear in all copies.
483+ *
484+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
485+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
486+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
487+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
488+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
489+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
490+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
491+ */
492+
493+#ifdef USE_CONSOLEKIT
494+
495+struct Session;
496+
497+char * consolekit_register(struct Session *, const char *);
498+void consolekit_unregister(struct Session *);
499+
500+#endif /* USE_CONSOLEKIT */
501Index: b/monitor.c
502===================================================================
503--- a/monitor.c
504+++ b/monitor.c
505@@ -98,6 +98,9 @@
506 #include "jpake.h"
507 #include "roaming.h"
508 #include "authfd.h"
509+#ifdef USE_CONSOLEKIT
510+#include "consolekit.h"
511+#endif
512
513 #ifdef GSSAPI
514 static Gssctxt *gsscontext = NULL;
515@@ -193,6 +196,10 @@
516
517 static int monitor_read_log(struct monitor *);
518
519+#ifdef USE_CONSOLEKIT
520+int mm_answer_consolekit_register(int, Buffer *);
521+#endif
522+
523 static Authctxt *authctxt;
524 static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */
525
526@@ -285,6 +292,9 @@
527 {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
528 {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command},
529 #endif
530+#ifdef USE_CONSOLEKIT
531+ {MONITOR_REQ_CONSOLEKIT_REGISTER, 0, mm_answer_consolekit_register},
532+#endif
533 {0, 0, NULL}
534 };
535
536@@ -327,6 +337,9 @@
537 {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
538 {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command},
539 #endif
540+#ifdef USE_CONSOLEKIT
541+ {MONITOR_REQ_CONSOLEKIT_REGISTER, 0, mm_answer_consolekit_register},
542+#endif
543 {0, 0, NULL}
544 };
545
546@@ -514,6 +527,9 @@
547 monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
548 monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1);
549 }
550+#ifdef USE_CONSOLEKIT
551+ monitor_permit(mon_dispatch, MONITOR_REQ_CONSOLEKIT_REGISTER, 1);
552+#endif
553
554 for (;;)
555 monitor_read(pmonitor, mon_dispatch, NULL);
556@@ -2492,3 +2508,30 @@
557 }
558
559 #endif /* JPAKE */
560+
561+#ifdef USE_CONSOLEKIT
562+int
563+mm_answer_consolekit_register(int sock, Buffer *m)
564+{
565+ Session *s;
566+ char *tty, *display;
567+ char *cookie = NULL;
568+
569+ debug3("%s entering", __func__);
570+
571+ tty = buffer_get_string(m, NULL);
572+ display = buffer_get_string(m, NULL);
573+ s = session_by_tty(tty);
574+ if (s != NULL)
575+ cookie = consolekit_register(s, display);
576+ buffer_clear(m);
577+ buffer_put_cstring(m, cookie != NULL ? cookie : "");
578+ mm_request_send(sock, MONITOR_ANS_CONSOLEKIT_REGISTER, m);
579+
580+ free(cookie);
581+ free(display);
582+ free(tty);
583+
584+ return (0);
585+}
586+#endif /* USE_CONSOLEKIT */
587Index: b/monitor.h
588===================================================================
589--- a/monitor.h
590+++ b/monitor.h
591@@ -75,6 +75,8 @@
592
593 MONITOR_REQ_AUTHROLE = 154,
594
595+ MONITOR_REQ_CONSOLEKIT_REGISTER = 156, MONITOR_ANS_CONSOLEKIT_REGISTER = 157,
596+
597 };
598
599 struct mm_master;
600Index: b/monitor_wrap.c
601===================================================================
602--- a/monitor_wrap.c
603+++ b/monitor_wrap.c
604@@ -1516,3 +1516,34 @@
605 return success;
606 }
607 #endif /* JPAKE */
608+
609+#ifdef USE_CONSOLEKIT
610+char *
611+mm_consolekit_register(Session *s, const char *display)
612+{
613+ Buffer m;
614+ char *cookie;
615+
616+ debug3("%s entering", __func__);
617+
618+ if (s->ttyfd == -1)
619+ return NULL;
620+ buffer_init(&m);
621+ buffer_put_cstring(&m, s->tty);
622+ buffer_put_cstring(&m, display != NULL ? display : "");
623+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_CONSOLEKIT_REGISTER, &m);
624+ buffer_clear(&m);
625+
626+ mm_request_receive_expect(pmonitor->m_recvfd,
627+ MONITOR_ANS_CONSOLEKIT_REGISTER, &m);
628+ cookie = buffer_get_string(&m, NULL);
629+ buffer_free(&m);
630+
631+ /* treat empty cookie as missing cookie */
632+ if (strlen(cookie) == 0) {
633+ free(cookie);
634+ cookie = NULL;
635+ }
636+ return (cookie);
637+}
638+#endif /* USE_CONSOLEKIT */
639Index: b/monitor_wrap.h
640===================================================================
641--- a/monitor_wrap.h
642+++ b/monitor_wrap.h
643@@ -131,4 +131,8 @@
644 void mm_zfree(struct mm_master *, void *);
645 void mm_init_compression(struct mm_master *);
646
647+#ifdef USE_CONSOLEKIT
648+char *mm_consolekit_register(struct Session *, const char *);
649+#endif /* USE_CONSOLEKIT */
650+
651 #endif /* _MM_WRAP_H_ */
652Index: b/session.c
653===================================================================
654--- a/session.c
655+++ b/session.c
656@@ -92,6 +92,7 @@
657 #include "kex.h"
658 #include "monitor_wrap.h"
659 #include "sftp.h"
660+#include "consolekit.h"
661
662 #if defined(KRB5) && defined(USE_AFS)
663 #include <kafs.h>
664@@ -1132,6 +1133,9 @@
665 #if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
666 char *path = NULL;
667 #endif
668+#ifdef USE_CONSOLEKIT
669+ const char *ckcookie = NULL;
670+#endif /* USE_CONSOLEKIT */
671
672 /* Initialize the environment. */
673 envsize = 100;
674@@ -1276,6 +1280,11 @@
675 child_set_env(&env, &envsize, "KRB5CCNAME",
676 s->authctxt->krb5_ccname);
677 #endif
678+#ifdef USE_CONSOLEKIT
679+ ckcookie = PRIVSEP(consolekit_register(s, s->display));
680+ if (ckcookie)
681+ child_set_env(&env, &envsize, "XDG_SESSION_COOKIE", ckcookie);
682+#endif /* USE_CONSOLEKIT */
683 #ifdef USE_PAM
684 /*
685 * Pull in any environment variables that may have
686@@ -2320,6 +2329,10 @@
687
688 debug("session_pty_cleanup: session %d release %s", s->self, s->tty);
689
690+#ifdef USE_CONSOLEKIT
691+ consolekit_unregister(s);
692+#endif /* USE_CONSOLEKIT */
693+
694 /* Record that the user has logged out. */
695 if (s->pid != 0)
696 record_logout(s->pid, s->tty, s->pw->pw_name);
697Index: b/session.h
698===================================================================
699--- a/session.h
700+++ b/session.h
701@@ -26,6 +26,8 @@
702 #ifndef SESSION_H
703 #define SESSION_H
704
705+struct _CkConnector;
706+
707 #define TTYSZ 64
708 typedef struct Session Session;
709 struct Session {
710@@ -60,6 +62,10 @@
711 char *name;
712 char *val;
713 } *env;
714+
715+#ifdef USE_CONSOLEKIT
716+ struct _CkConnector *ckc;
717+#endif /* USE_CONSOLEKIT */
718 };
719
720 void do_authenticated(Authctxt *);
diff --git a/debian/patches/debian-banner.patch b/debian/patches/debian-banner.patch
new file mode 100644
index 000000000..981cdd697
--- /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: 2013-09-14
8
9Index: b/servconf.c
10===================================================================
11--- a/servconf.c
12+++ b/servconf.c
13@@ -157,6 +157,7 @@
14 options->ip_qos_interactive = -1;
15 options->ip_qos_bulk = -1;
16 options->version_addendum = NULL;
17+ options->debian_banner = -1;
18 }
19
20 void
21@@ -310,6 +311,8 @@
22 options->ip_qos_bulk = IPTOS_THROUGHPUT;
23 if (options->version_addendum == NULL)
24 options->version_addendum = xstrdup("");
25+ if (options->debian_banner == -1)
26+ options->debian_banner = 1;
27 /* Turn privilege separation on by default */
28 if (use_privsep == -1)
29 use_privsep = PRIVSEP_NOSANDBOX;
30@@ -360,6 +363,7 @@
31 sKexAlgorithms, sIPQoS, sVersionAddendum,
32 sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
33 sAuthenticationMethods, sHostKeyAgent,
34+ sDebianBanner,
35 sDeprecated, sUnsupported
36 } ServerOpCodes;
37
38@@ -501,6 +505,7 @@
39 { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
40 { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
41 { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
42+ { "debianbanner", sDebianBanner, SSHCFG_GLOBAL },
43 { NULL, sBadOption, 0 }
44 };
45
46@@ -1648,6 +1653,10 @@
47 }
48 return 0;
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@@ -188,6 +188,8 @@
62
63 u_int num_auth_methods;
64 char *auth_methods[MAX_AUTH_METHODS];
65+
66+ int debian_banner;
67 } ServerOptions;
68
69 /* Information about the incoming connection as used by Match */
70Index: b/sshd.c
71===================================================================
72--- a/sshd.c
73+++ b/sshd.c
74@@ -440,7 +440,8 @@
75 }
76
77 xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s",
78- major, minor, SSH_RELEASE,
79+ major, minor,
80+ options.debian_banner ? SSH_RELEASE : SSH_RELEASE_MINIMUM,
81 *options.version_addendum == '\0' ? "" : " ",
82 options.version_addendum, newline);
83
84Index: b/sshd_config.5
85===================================================================
86--- a/sshd_config.5
87+++ b/sshd_config.5
88@@ -404,6 +404,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..d005bdc2e
--- /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: 2013-09-14
22
23Index: b/readconf.c
24===================================================================
25--- a/readconf.c
26+++ b/readconf.c
27@@ -1298,7 +1298,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@@ -48,3 +49,7 @@
53 # VisualHostKey no
54 # ProxyCommand ssh -q -W %h:%p gateway.example.com
55 # RekeyLimit 1G 1h
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@@ -501,7 +517,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@@ -40,6 +40,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..0615de097
--- /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@@ -196,6 +196,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@@ -219,8 +220,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..4c197323c
--- /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: 2013-09-14
6
7Index: b/ssh_config.5
8===================================================================
9--- a/ssh_config.5
10+++ b/ssh_config.5
11@@ -587,6 +587,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/doc-upstart.patch b/debian/patches/doc-upstart.patch
new file mode 100644
index 000000000..a471f9c4c
--- /dev/null
+++ b/debian/patches/doc-upstart.patch
@@ -0,0 +1,21 @@
1Description: Refer to ssh's Upstart job as well as its init script
2Author: Colin Watson <cjwatson@ubuntu.com>
3Forwarded: not-needed
4Last-Update: 2013-09-14
5
6Index: b/sshd.8
7===================================================================
8--- a/sshd.8
9+++ b/sshd.8
10@@ -70,7 +70,10 @@
11 .Nm
12 listens for connections from clients.
13 It is normally started at boot from
14-.Pa /etc/init.d/ssh .
15+.Pa /etc/init.d/ssh
16+(or
17+.Pa /etc/init/ssh.conf
18+on systems using the Upstart init daemon).
19 It forks a new
20 daemon for each incoming connection.
21 The forked daemons handle
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.patch b/debian/patches/gssapi.patch
new file mode 100644
index 000000000..85c6722f0
--- /dev/null
+++ b/debian/patches/gssapi.patch
@@ -0,0 +1,3088 @@
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: 2013-09-14
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@@ -72,6 +72,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 umac128.o \
146 jpake.o schnorr.o ssh-pkcs11.o krl.o
147
148@@ -88,7 +89,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@@ -181,8 +181,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@@ -239,15 +244,22 @@
176 #ifndef HEIMDAL
177 krb5_error_code
178 ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
179- int tmpfd, ret, oerrno;
180+ int ret, oerrno;
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 oerrno = errno;
200@@ -264,6 +276,7 @@
201 return oerrno;
202 }
203 close(tmpfd);
204+#endif
205
206 return (krb5_cc_resolve(ctx, ccname, ccache));
207 }
208Index: b/auth2-gss.c
209===================================================================
210--- a/auth2-gss.c
211+++ b/auth2-gss.c
212@@ -1,7 +1,7 @@
213 /* $OpenBSD: auth2-gss.c,v 1.20 2013/05/17 00:13:13 djm Exp $ */
214
215 /*
216- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
217+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
218 *
219 * Redistribution and use in source and binary forms, with or without
220 * modification, are permitted provided that the following conditions
221@@ -52,6 +52,40 @@
222 static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
223 static void input_gssapi_errtok(int, u_int32_t, void *);
224
225+/*
226+ * The 'gssapi_keyex' userauth mechanism.
227+ */
228+static int
229+userauth_gsskeyex(Authctxt *authctxt)
230+{
231+ int authenticated = 0;
232+ Buffer b;
233+ gss_buffer_desc mic, gssbuf;
234+ u_int len;
235+
236+ mic.value = packet_get_string(&len);
237+ mic.length = len;
238+
239+ packet_check_eom();
240+
241+ ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
242+ "gssapi-keyex");
243+
244+ gssbuf.value = buffer_ptr(&b);
245+ gssbuf.length = buffer_len(&b);
246+
247+ /* gss_kex_context is NULL with privsep, so we can't check it here */
248+ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
249+ &gssbuf, &mic))))
250+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
251+ authctxt->pw));
252+
253+ buffer_free(&b);
254+ free(mic.value);
255+
256+ return (authenticated);
257+}
258+
259 /*
260 * We only support those mechanisms that we know about (ie ones that we know
261 * how to check local user kuserok and the like)
262@@ -240,7 +274,8 @@
263
264 packet_check_eom();
265
266- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
267+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
268+ authctxt->pw));
269
270 authctxt->postponed = 0;
271 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
272@@ -275,7 +310,8 @@
273 gssbuf.length = buffer_len(&b);
274
275 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
276- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
277+ authenticated =
278+ PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
279 else
280 logit("GSSAPI MIC check failed");
281
282@@ -290,6 +326,12 @@
283 userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
284 }
285
286+Authmethod method_gsskeyex = {
287+ "gssapi-keyex",
288+ userauth_gsskeyex,
289+ &options.gss_authentication
290+};
291+
292 Authmethod method_gssapi = {
293 "gssapi-with-mic",
294 userauth_gssapi,
295Index: b/auth2.c
296===================================================================
297--- a/auth2.c
298+++ b/auth2.c
299@@ -69,6 +69,7 @@
300 extern Authmethod method_kbdint;
301 extern Authmethod method_hostbased;
302 #ifdef GSSAPI
303+extern Authmethod method_gsskeyex;
304 extern Authmethod method_gssapi;
305 #endif
306 #ifdef JPAKE
307@@ -79,6 +80,7 @@
308 &method_none,
309 &method_pubkey,
310 #ifdef GSSAPI
311+ &method_gsskeyex,
312 &method_gssapi,
313 #endif
314 #ifdef JPAKE
315Index: b/clientloop.c
316===================================================================
317--- a/clientloop.c
318+++ b/clientloop.c
319@@ -111,6 +111,10 @@
320 #include "msg.h"
321 #include "roaming.h"
322
323+#ifdef GSSAPI
324+#include "ssh-gss.h"
325+#endif
326+
327 /* import options */
328 extern Options options;
329
330@@ -1608,6 +1612,15 @@
331 /* Do channel operations unless rekeying in progress. */
332 if (!rekeying) {
333 channel_after_select(readset, writeset);
334+
335+#ifdef GSSAPI
336+ if (options.gss_renewal_rekey &&
337+ ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) {
338+ debug("credentials updated - forcing rekey");
339+ need_rekeying = 1;
340+ }
341+#endif
342+
343 if (need_rekeying || packet_need_rekeying()) {
344 debug("need rekeying");
345 xxx_kex->done = 0;
346Index: b/config.h.in
347===================================================================
348--- a/config.h.in
349+++ b/config.h.in
350@@ -1546,6 +1546,9 @@
351 /* Use btmp to log bad logins */
352 #undef USE_BTMP
353
354+/* platform uses an in-memory credentials cache */
355+#undef USE_CCAPI
356+
357 /* Use libedit for sftp */
358 #undef USE_LIBEDIT
359
360@@ -1561,6 +1564,9 @@
361 /* Use PIPES instead of a socketpair() */
362 #undef USE_PIPES
363
364+/* platform has the Security Authorization Session API */
365+#undef USE_SECURITY_SESSION_API
366+
367 /* Define if you have Solaris process contracts */
368 #undef USE_SOLARIS_PROCESS_CONTRACTS
369
370Index: b/configure
371===================================================================
372--- a/configure
373+++ b/configure
374@@ -6780,6 +6780,63 @@
375
376 $as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h
377
378+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have the Security Authorization Session API" >&5
379+$as_echo_n "checking if we have the Security Authorization Session API... " >&6; }
380+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
381+/* end confdefs.h. */
382+#include <Security/AuthSession.h>
383+int
384+main ()
385+{
386+SessionCreate(0, 0);
387+ ;
388+ return 0;
389+}
390+_ACEOF
391+if ac_fn_c_try_compile "$LINENO"; then :
392+ ac_cv_use_security_session_api="yes"
393+
394+$as_echo "#define USE_SECURITY_SESSION_API 1" >>confdefs.h
395+
396+ LIBS="$LIBS -framework Security"
397+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
398+$as_echo "yes" >&6; }
399+else
400+ ac_cv_use_security_session_api="no"
401+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
402+$as_echo "no" >&6; }
403+fi
404+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
405+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have an in-memory credentials cache" >&5
406+$as_echo_n "checking if we have an in-memory credentials cache... " >&6; }
407+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
408+/* end confdefs.h. */
409+#include <Kerberos/Kerberos.h>
410+int
411+main ()
412+{
413+cc_context_t c;
414+ (void) cc_initialize (&c, 0, NULL, NULL);
415+ ;
416+ return 0;
417+}
418+_ACEOF
419+if ac_fn_c_try_compile "$LINENO"; then :
420+
421+$as_echo "#define USE_CCAPI 1" >>confdefs.h
422+
423+ LIBS="$LIBS -framework Security"
424+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
425+$as_echo "yes" >&6; }
426+ if test "x$ac_cv_use_security_session_api" = "xno"; then
427+ as_fn_error $? "*** Need a security framework to use the credentials cache API ***" "$LINENO" 5
428+ fi
429+else
430+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
431+$as_echo "no" >&6; }
432+
433+fi
434+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
435
436 ac_fn_c_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default"
437 if test "x$ac_cv_have_decl_AU_IPv4" = xyes; then :
438Index: b/configure.ac
439===================================================================
440--- a/configure.ac
441+++ b/configure.ac
442@@ -548,6 +548,30 @@
443 [Use tunnel device compatibility to OpenBSD])
444 AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
445 [Prepend the address family to IP tunnel traffic])
446+ AC_MSG_CHECKING([if we have the Security Authorization Session API])
447+ AC_TRY_COMPILE([#include <Security/AuthSession.h>],
448+ [SessionCreate(0, 0);],
449+ [ac_cv_use_security_session_api="yes"
450+ AC_DEFINE([USE_SECURITY_SESSION_API], [1],
451+ [platform has the Security Authorization Session API])
452+ LIBS="$LIBS -framework Security"
453+ AC_MSG_RESULT([yes])],
454+ [ac_cv_use_security_session_api="no"
455+ AC_MSG_RESULT([no])])
456+ AC_MSG_CHECKING([if we have an in-memory credentials cache])
457+ AC_TRY_COMPILE(
458+ [#include <Kerberos/Kerberos.h>],
459+ [cc_context_t c;
460+ (void) cc_initialize (&c, 0, NULL, NULL);],
461+ [AC_DEFINE([USE_CCAPI], [1],
462+ [platform uses an in-memory credentials cache])
463+ LIBS="$LIBS -framework Security"
464+ AC_MSG_RESULT([yes])
465+ if test "x$ac_cv_use_security_session_api" = "xno"; then
466+ AC_MSG_ERROR([*** Need a security framework to use the credentials cache API ***])
467+ fi],
468+ [AC_MSG_RESULT([no])]
469+ )
470 m4_pattern_allow([AU_IPv])
471 AC_CHECK_DECL([AU_IPv4], [],
472 AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
473Index: b/gss-genr.c
474===================================================================
475--- a/gss-genr.c
476+++ b/gss-genr.c
477@@ -1,7 +1,7 @@
478 /* $OpenBSD: gss-genr.c,v 1.21 2013/05/17 00:13:13 djm Exp $ */
479
480 /*
481- * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
482+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
483 *
484 * Redistribution and use in source and binary forms, with or without
485 * modification, are permitted provided that the following conditions
486@@ -39,12 +39,167 @@
487 #include "buffer.h"
488 #include "log.h"
489 #include "ssh2.h"
490+#include "cipher.h"
491+#include "key.h"
492+#include "kex.h"
493+#include <openssl/evp.h>
494
495 #include "ssh-gss.h"
496
497 extern u_char *session_id2;
498 extern u_int session_id2_len;
499
500+typedef struct {
501+ char *encoded;
502+ gss_OID oid;
503+} ssh_gss_kex_mapping;
504+
505+/*
506+ * XXX - It would be nice to find a more elegant way of handling the
507+ * XXX passing of the key exchange context to the userauth routines
508+ */
509+
510+Gssctxt *gss_kex_context = NULL;
511+
512+static ssh_gss_kex_mapping *gss_enc2oid = NULL;
513+
514+int
515+ssh_gssapi_oid_table_ok() {
516+ return (gss_enc2oid != NULL);
517+}
518+
519+/*
520+ * Return a list of the gss-group1-sha1 mechanisms supported by this program
521+ *
522+ * We test mechanisms to ensure that we can use them, to avoid starting
523+ * a key exchange with a bad mechanism
524+ */
525+
526+char *
527+ssh_gssapi_client_mechanisms(const char *host, const char *client) {
528+ gss_OID_set gss_supported;
529+ OM_uint32 min_status;
530+
531+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
532+ return NULL;
533+
534+ return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
535+ host, client));
536+}
537+
538+char *
539+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
540+ const char *host, const char *client) {
541+ Buffer buf;
542+ size_t i;
543+ int oidpos, enclen;
544+ char *mechs, *encoded;
545+ u_char digest[EVP_MAX_MD_SIZE];
546+ char deroid[2];
547+ const EVP_MD *evp_md = EVP_md5();
548+ EVP_MD_CTX md;
549+
550+ if (gss_enc2oid != NULL) {
551+ for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
552+ free(gss_enc2oid[i].encoded);
553+ free(gss_enc2oid);
554+ }
555+
556+ gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
557+ (gss_supported->count + 1));
558+
559+ buffer_init(&buf);
560+
561+ oidpos = 0;
562+ for (i = 0; i < gss_supported->count; i++) {
563+ if (gss_supported->elements[i].length < 128 &&
564+ (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
565+
566+ deroid[0] = SSH_GSS_OIDTYPE;
567+ deroid[1] = gss_supported->elements[i].length;
568+
569+ EVP_DigestInit(&md, evp_md);
570+ EVP_DigestUpdate(&md, deroid, 2);
571+ EVP_DigestUpdate(&md,
572+ gss_supported->elements[i].elements,
573+ gss_supported->elements[i].length);
574+ EVP_DigestFinal(&md, digest, NULL);
575+
576+ encoded = xmalloc(EVP_MD_size(evp_md) * 2);
577+ enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
578+ encoded, EVP_MD_size(evp_md) * 2);
579+
580+ if (oidpos != 0)
581+ buffer_put_char(&buf, ',');
582+
583+ buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
584+ sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
585+ buffer_append(&buf, encoded, enclen);
586+ buffer_put_char(&buf, ',');
587+ buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
588+ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
589+ buffer_append(&buf, encoded, enclen);
590+ buffer_put_char(&buf, ',');
591+ buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
592+ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
593+ buffer_append(&buf, encoded, enclen);
594+
595+ gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
596+ gss_enc2oid[oidpos].encoded = encoded;
597+ oidpos++;
598+ }
599+ }
600+ gss_enc2oid[oidpos].oid = NULL;
601+ gss_enc2oid[oidpos].encoded = NULL;
602+
603+ buffer_put_char(&buf, '\0');
604+
605+ mechs = xmalloc(buffer_len(&buf));
606+ buffer_get(&buf, mechs, buffer_len(&buf));
607+ buffer_free(&buf);
608+
609+ if (strlen(mechs) == 0) {
610+ free(mechs);
611+ mechs = NULL;
612+ }
613+
614+ return (mechs);
615+}
616+
617+gss_OID
618+ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
619+ int i = 0;
620+
621+ switch (kex_type) {
622+ case KEX_GSS_GRP1_SHA1:
623+ if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
624+ return GSS_C_NO_OID;
625+ name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
626+ break;
627+ case KEX_GSS_GRP14_SHA1:
628+ if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
629+ return GSS_C_NO_OID;
630+ name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
631+ break;
632+ case KEX_GSS_GEX_SHA1:
633+ if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
634+ return GSS_C_NO_OID;
635+ name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
636+ break;
637+ default:
638+ return GSS_C_NO_OID;
639+ }
640+
641+ while (gss_enc2oid[i].encoded != NULL &&
642+ strcmp(name, gss_enc2oid[i].encoded) != 0)
643+ i++;
644+
645+ if (gss_enc2oid[i].oid != NULL && ctx != NULL)
646+ ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
647+
648+ return gss_enc2oid[i].oid;
649+}
650+
651 /* Check that the OID in a data stream matches that in the context */
652 int
653 ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
654@@ -197,7 +352,7 @@
655 }
656
657 ctx->major = gss_init_sec_context(&ctx->minor,
658- GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
659+ ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
660 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
661 0, NULL, recv_tok, NULL, send_tok, flags, NULL);
662
663@@ -227,8 +382,42 @@
664 }
665
666 OM_uint32
667+ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
668+{
669+ gss_buffer_desc gssbuf;
670+ gss_name_t gssname;
671+ OM_uint32 status;
672+ gss_OID_set oidset;
673+
674+ gssbuf.value = (void *) name;
675+ gssbuf.length = strlen(gssbuf.value);
676+
677+ gss_create_empty_oid_set(&status, &oidset);
678+ gss_add_oid_set_member(&status, ctx->oid, &oidset);
679+
680+ ctx->major = gss_import_name(&ctx->minor, &gssbuf,
681+ GSS_C_NT_USER_NAME, &gssname);
682+
683+ if (!ctx->major)
684+ ctx->major = gss_acquire_cred(&ctx->minor,
685+ gssname, 0, oidset, GSS_C_INITIATE,
686+ &ctx->client_creds, NULL, NULL);
687+
688+ gss_release_name(&status, &gssname);
689+ gss_release_oid_set(&status, &oidset);
690+
691+ if (ctx->major)
692+ ssh_gssapi_error(ctx);
693+
694+ return(ctx->major);
695+}
696+
697+OM_uint32
698 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
699 {
700+ if (ctx == NULL)
701+ return -1;
702+
703 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
704 GSS_C_QOP_DEFAULT, buffer, hash)))
705 ssh_gssapi_error(ctx);
706@@ -236,6 +425,19 @@
707 return (ctx->major);
708 }
709
710+/* Priviledged when used by server */
711+OM_uint32
712+ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
713+{
714+ if (ctx == NULL)
715+ return -1;
716+
717+ ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
718+ gssbuf, gssmic, NULL);
719+
720+ return (ctx->major);
721+}
722+
723 void
724 ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
725 const char *context)
726@@ -249,11 +451,16 @@
727 }
728
729 int
730-ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
731+ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
732+ const char *client)
733 {
734 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
735 OM_uint32 major, minor;
736 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
737+ Gssctxt *intctx = NULL;
738+
739+ if (ctx == NULL)
740+ ctx = &intctx;
741
742 /* RFC 4462 says we MUST NOT do SPNEGO */
743 if (oid->length == spnego_oid.length &&
744@@ -263,6 +470,10 @@
745 ssh_gssapi_build_ctx(ctx);
746 ssh_gssapi_set_oid(*ctx, oid);
747 major = ssh_gssapi_import_name(*ctx, host);
748+
749+ if (!GSS_ERROR(major) && client)
750+ major = ssh_gssapi_client_identity(*ctx, client);
751+
752 if (!GSS_ERROR(major)) {
753 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
754 NULL);
755@@ -272,10 +483,67 @@
756 GSS_C_NO_BUFFER);
757 }
758
759- if (GSS_ERROR(major))
760+ if (GSS_ERROR(major) || intctx != NULL)
761 ssh_gssapi_delete_ctx(ctx);
762
763 return (!GSS_ERROR(major));
764 }
765
766+int
767+ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
768+ static gss_name_t saved_name = GSS_C_NO_NAME;
769+ static OM_uint32 saved_lifetime = 0;
770+ static gss_OID saved_mech = GSS_C_NO_OID;
771+ static gss_name_t name;
772+ static OM_uint32 last_call = 0;
773+ OM_uint32 lifetime, now, major, minor;
774+ int equal;
775+ gss_cred_usage_t usage = GSS_C_INITIATE;
776+
777+ now = time(NULL);
778+
779+ if (ctxt) {
780+ debug("Rekey has happened - updating saved versions");
781+
782+ if (saved_name != GSS_C_NO_NAME)
783+ gss_release_name(&minor, &saved_name);
784+
785+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
786+ &saved_name, &saved_lifetime, NULL, NULL);
787+
788+ if (!GSS_ERROR(major)) {
789+ saved_mech = ctxt->oid;
790+ saved_lifetime+= now;
791+ } else {
792+ /* Handle the error */
793+ }
794+ return 0;
795+ }
796+
797+ if (now - last_call < 10)
798+ return 0;
799+
800+ last_call = now;
801+
802+ if (saved_mech == GSS_C_NO_OID)
803+ return 0;
804+
805+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
806+ &name, &lifetime, NULL, NULL);
807+ if (major == GSS_S_CREDENTIALS_EXPIRED)
808+ return 0;
809+ else if (GSS_ERROR(major))
810+ return 0;
811+
812+ major = gss_compare_name(&minor, saved_name, name, &equal);
813+ gss_release_name(&minor, &name);
814+ if (GSS_ERROR(major))
815+ return 0;
816+
817+ if (equal && (saved_lifetime < lifetime + now - 10))
818+ return 1;
819+
820+ return 0;
821+}
822+
823 #endif /* GSSAPI */
824Index: b/gss-serv-krb5.c
825===================================================================
826--- a/gss-serv-krb5.c
827+++ b/gss-serv-krb5.c
828@@ -1,7 +1,7 @@
829 /* $OpenBSD: gss-serv-krb5.c,v 1.8 2013/07/20 01:55:13 djm Exp $ */
830
831 /*
832- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
833+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
834 *
835 * Redistribution and use in source and binary forms, with or without
836 * modification, are permitted provided that the following conditions
837@@ -122,6 +122,7 @@
838 OM_uint32 maj_status, min_status;
839 int len;
840 const char *errmsg;
841+ const char *new_ccname;
842
843 if (client->creds == NULL) {
844 debug("No credentials stored");
845@@ -174,11 +175,16 @@
846 return;
847 }
848
849- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
850+ new_ccname = krb5_cc_get_name(krb_context, ccache);
851+
852 client->store.envvar = "KRB5CCNAME";
853- len = strlen(client->store.filename) + 6;
854- client->store.envval = xmalloc(len);
855- snprintf(client->store.envval, len, "FILE:%s", client->store.filename);
856+#ifdef USE_CCAPI
857+ xasprintf(&client->store.envval, "API:%s", new_ccname);
858+ client->store.filename = NULL;
859+#else
860+ xasprintf(&client->store.envval, "FILE:%s", new_ccname);
861+ client->store.filename = xstrdup(new_ccname);
862+#endif
863
864 #ifdef USE_PAM
865 if (options.use_pam)
866@@ -190,6 +196,71 @@
867 return;
868 }
869
870+int
871+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store,
872+ ssh_gssapi_client *client)
873+{
874+ krb5_ccache ccache = NULL;
875+ krb5_principal principal = NULL;
876+ char *name = NULL;
877+ krb5_error_code problem;
878+ OM_uint32 maj_status, min_status;
879+
880+ if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
881+ logit("krb5_cc_resolve(): %.100s",
882+ krb5_get_err_text(krb_context, problem));
883+ return 0;
884+ }
885+
886+ /* Find out who the principal in this cache is */
887+ if ((problem = krb5_cc_get_principal(krb_context, ccache,
888+ &principal))) {
889+ logit("krb5_cc_get_principal(): %.100s",
890+ krb5_get_err_text(krb_context, problem));
891+ krb5_cc_close(krb_context, ccache);
892+ return 0;
893+ }
894+
895+ if ((problem = krb5_unparse_name(krb_context, principal, &name))) {
896+ logit("krb5_unparse_name(): %.100s",
897+ krb5_get_err_text(krb_context, problem));
898+ krb5_free_principal(krb_context, principal);
899+ krb5_cc_close(krb_context, ccache);
900+ return 0;
901+ }
902+
903+
904+ if (strcmp(name,client->exportedname.value)!=0) {
905+ debug("Name in local credentials cache differs. Not storing");
906+ krb5_free_principal(krb_context, principal);
907+ krb5_cc_close(krb_context, ccache);
908+ krb5_free_unparsed_name(krb_context, name);
909+ return 0;
910+ }
911+ krb5_free_unparsed_name(krb_context, name);
912+
913+ /* Name matches, so lets get on with it! */
914+
915+ if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) {
916+ logit("krb5_cc_initialize(): %.100s",
917+ krb5_get_err_text(krb_context, problem));
918+ krb5_free_principal(krb_context, principal);
919+ krb5_cc_close(krb_context, ccache);
920+ return 0;
921+ }
922+
923+ krb5_free_principal(krb_context, principal);
924+
925+ if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds,
926+ ccache))) {
927+ logit("gss_krb5_copy_ccache() failed. Sorry!");
928+ krb5_cc_close(krb_context, ccache);
929+ return 0;
930+ }
931+
932+ return 1;
933+}
934+
935 ssh_gssapi_mech gssapi_kerberos_mech = {
936 "toWM5Slw5Ew8Mqkay+al2g==",
937 "Kerberos",
938@@ -197,7 +268,8 @@
939 NULL,
940 &ssh_gssapi_krb5_userok,
941 NULL,
942- &ssh_gssapi_krb5_storecreds
943+ &ssh_gssapi_krb5_storecreds,
944+ &ssh_gssapi_krb5_updatecreds
945 };
946
947 #endif /* KRB5 */
948Index: b/gss-serv.c
949===================================================================
950--- a/gss-serv.c
951+++ b/gss-serv.c
952@@ -1,7 +1,7 @@
953 /* $OpenBSD: gss-serv.c,v 1.24 2013/07/20 01:55:13 djm Exp $ */
954
955 /*
956- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
957+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
958 *
959 * Redistribution and use in source and binary forms, with or without
960 * modification, are permitted provided that the following conditions
961@@ -45,15 +45,21 @@
962 #include "channels.h"
963 #include "session.h"
964 #include "misc.h"
965+#include "servconf.h"
966+#include "uidswap.h"
967
968 #include "ssh-gss.h"
969+#include "monitor_wrap.h"
970+
971+extern ServerOptions options;
972
973 static ssh_gssapi_client gssapi_client =
974 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
975- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}};
976+ GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL,
977+ {NULL, NULL, NULL, NULL, NULL}, 0, 0};
978
979 ssh_gssapi_mech gssapi_null_mech =
980- { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
981+ { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
982
983 #ifdef KRB5
984 extern ssh_gssapi_mech gssapi_kerberos_mech;
985@@ -81,25 +87,32 @@
986 char lname[MAXHOSTNAMELEN];
987 gss_OID_set oidset;
988
989- gss_create_empty_oid_set(&status, &oidset);
990- gss_add_oid_set_member(&status, ctx->oid, &oidset);
991+ if (options.gss_strict_acceptor) {
992+ gss_create_empty_oid_set(&status, &oidset);
993+ gss_add_oid_set_member(&status, ctx->oid, &oidset);
994+
995+ if (gethostname(lname, MAXHOSTNAMELEN)) {
996+ gss_release_oid_set(&status, &oidset);
997+ return (-1);
998+ }
999
1000- if (gethostname(lname, MAXHOSTNAMELEN)) {
1001- gss_release_oid_set(&status, &oidset);
1002- return (-1);
1003- }
1004+ if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
1005+ gss_release_oid_set(&status, &oidset);
1006+ return (ctx->major);
1007+ }
1008+
1009+ if ((ctx->major = gss_acquire_cred(&ctx->minor,
1010+ ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds,
1011+ NULL, NULL)))
1012+ ssh_gssapi_error(ctx);
1013
1014- if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
1015 gss_release_oid_set(&status, &oidset);
1016 return (ctx->major);
1017+ } else {
1018+ ctx->name = GSS_C_NO_NAME;
1019+ ctx->creds = GSS_C_NO_CREDENTIAL;
1020 }
1021-
1022- if ((ctx->major = gss_acquire_cred(&ctx->minor,
1023- ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
1024- ssh_gssapi_error(ctx);
1025-
1026- gss_release_oid_set(&status, &oidset);
1027- return (ctx->major);
1028+ return GSS_S_COMPLETE;
1029 }
1030
1031 /* Privileged */
1032@@ -114,6 +127,29 @@
1033 }
1034
1035 /* Unprivileged */
1036+char *
1037+ssh_gssapi_server_mechanisms() {
1038+ gss_OID_set supported;
1039+
1040+ ssh_gssapi_supported_oids(&supported);
1041+ return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
1042+ NULL, NULL));
1043+}
1044+
1045+/* Unprivileged */
1046+int
1047+ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
1048+ const char *dummy) {
1049+ Gssctxt *ctx = NULL;
1050+ int res;
1051+
1052+ res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
1053+ ssh_gssapi_delete_ctx(&ctx);
1054+
1055+ return (res);
1056+}
1057+
1058+/* Unprivileged */
1059 void
1060 ssh_gssapi_supported_oids(gss_OID_set *oidset)
1061 {
1062@@ -123,7 +159,9 @@
1063 gss_OID_set supported;
1064
1065 gss_create_empty_oid_set(&min_status, oidset);
1066- gss_indicate_mechs(&min_status, &supported);
1067+
1068+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
1069+ return;
1070
1071 while (supported_mechs[i]->name != NULL) {
1072 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
1073@@ -249,8 +287,48 @@
1074 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
1075 {
1076 int i = 0;
1077+ int equal = 0;
1078+ gss_name_t new_name = GSS_C_NO_NAME;
1079+ gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
1080+
1081+ if (options.gss_store_rekey && client->used && ctx->client_creds) {
1082+ if (client->mech->oid.length != ctx->oid->length ||
1083+ (memcmp(client->mech->oid.elements,
1084+ ctx->oid->elements, ctx->oid->length) !=0)) {
1085+ debug("Rekeyed credentials have different mechanism");
1086+ return GSS_S_COMPLETE;
1087+ }
1088+
1089+ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
1090+ ctx->client_creds, ctx->oid, &new_name,
1091+ NULL, NULL, NULL))) {
1092+ ssh_gssapi_error(ctx);
1093+ return (ctx->major);
1094+ }
1095+
1096+ ctx->major = gss_compare_name(&ctx->minor, client->name,
1097+ new_name, &equal);
1098
1099- gss_buffer_desc ename;
1100+ if (GSS_ERROR(ctx->major)) {
1101+ ssh_gssapi_error(ctx);
1102+ return (ctx->major);
1103+ }
1104+
1105+ if (!equal) {
1106+ debug("Rekeyed credentials have different name");
1107+ return GSS_S_COMPLETE;
1108+ }
1109+
1110+ debug("Marking rekeyed credentials for export");
1111+
1112+ gss_release_name(&ctx->minor, &client->name);
1113+ gss_release_cred(&ctx->minor, &client->creds);
1114+ client->name = new_name;
1115+ client->creds = ctx->client_creds;
1116+ ctx->client_creds = GSS_C_NO_CREDENTIAL;
1117+ client->updated = 1;
1118+ return GSS_S_COMPLETE;
1119+ }
1120
1121 client->mech = NULL;
1122
1123@@ -265,6 +343,13 @@
1124 if (client->mech == NULL)
1125 return GSS_S_FAILURE;
1126
1127+ if (ctx->client_creds &&
1128+ (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
1129+ ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
1130+ ssh_gssapi_error(ctx);
1131+ return (ctx->major);
1132+ }
1133+
1134 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
1135 &client->displayname, NULL))) {
1136 ssh_gssapi_error(ctx);
1137@@ -282,6 +367,8 @@
1138 return (ctx->major);
1139 }
1140
1141+ gss_release_buffer(&ctx->minor, &ename);
1142+
1143 /* We can't copy this structure, so we just move the pointer to it */
1144 client->creds = ctx->client_creds;
1145 ctx->client_creds = GSS_C_NO_CREDENTIAL;
1146@@ -329,7 +416,7 @@
1147
1148 /* Privileged */
1149 int
1150-ssh_gssapi_userok(char *user)
1151+ssh_gssapi_userok(char *user, struct passwd *pw)
1152 {
1153 OM_uint32 lmin;
1154
1155@@ -339,9 +426,11 @@
1156 return 0;
1157 }
1158 if (gssapi_client.mech && gssapi_client.mech->userok)
1159- if ((*gssapi_client.mech->userok)(&gssapi_client, user))
1160+ if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
1161+ gssapi_client.used = 1;
1162+ gssapi_client.store.owner = pw;
1163 return 1;
1164- else {
1165+ } else {
1166 /* Destroy delegated credentials if userok fails */
1167 gss_release_buffer(&lmin, &gssapi_client.displayname);
1168 gss_release_buffer(&lmin, &gssapi_client.exportedname);
1169@@ -354,14 +443,90 @@
1170 return (0);
1171 }
1172
1173-/* Privileged */
1174-OM_uint32
1175-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
1176+/* These bits are only used for rekeying. The unpriviledged child is running
1177+ * as the user, the monitor is root.
1178+ *
1179+ * In the child, we want to :
1180+ * *) Ask the monitor to store our credentials into the store we specify
1181+ * *) If it succeeds, maybe do a PAM update
1182+ */
1183+
1184+/* Stuff for PAM */
1185+
1186+#ifdef USE_PAM
1187+static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
1188+ struct pam_response **resp, void *data)
1189 {
1190- ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
1191- gssbuf, gssmic, NULL);
1192+ return (PAM_CONV_ERR);
1193+}
1194+#endif
1195
1196- return (ctx->major);
1197+void
1198+ssh_gssapi_rekey_creds() {
1199+ int ok;
1200+ int ret;
1201+#ifdef USE_PAM
1202+ pam_handle_t *pamh = NULL;
1203+ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
1204+ char *envstr;
1205+#endif
1206+
1207+ if (gssapi_client.store.filename == NULL &&
1208+ gssapi_client.store.envval == NULL &&
1209+ gssapi_client.store.envvar == NULL)
1210+ return;
1211+
1212+ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
1213+
1214+ if (!ok)
1215+ return;
1216+
1217+ debug("Rekeyed credentials stored successfully");
1218+
1219+ /* Actually managing to play with the ssh pam stack from here will
1220+ * be next to impossible. In any case, we may want different options
1221+ * for rekeying. So, use our own :)
1222+ */
1223+#ifdef USE_PAM
1224+ if (!use_privsep) {
1225+ debug("Not even going to try and do PAM with privsep disabled");
1226+ return;
1227+ }
1228+
1229+ ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
1230+ &pamconv, &pamh);
1231+ if (ret)
1232+ return;
1233+
1234+ xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
1235+ gssapi_client.store.envval);
1236+
1237+ ret = pam_putenv(pamh, envstr);
1238+ if (!ret)
1239+ pam_setcred(pamh, PAM_REINITIALIZE_CRED);
1240+ pam_end(pamh, PAM_SUCCESS);
1241+#endif
1242+}
1243+
1244+int
1245+ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
1246+ int ok = 0;
1247+
1248+ /* Check we've got credentials to store */
1249+ if (!gssapi_client.updated)
1250+ return 0;
1251+
1252+ gssapi_client.updated = 0;
1253+
1254+ temporarily_use_uid(gssapi_client.store.owner);
1255+ if (gssapi_client.mech && gssapi_client.mech->updatecreds)
1256+ ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
1257+ else
1258+ debug("No update function for this mechanism");
1259+
1260+ restore_uid();
1261+
1262+ return ok;
1263 }
1264
1265 #endif
1266Index: b/kex.c
1267===================================================================
1268--- a/kex.c
1269+++ b/kex.c
1270@@ -50,6 +50,10 @@
1271 #include "monitor.h"
1272 #include "roaming.h"
1273
1274+#ifdef GSSAPI
1275+#include "ssh-gss.h"
1276+#endif
1277+
1278 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
1279 # if defined(HAVE_EVP_SHA256)
1280 # define evp_ssh_sha256 EVP_sha256
1281@@ -82,6 +86,14 @@
1282 #endif
1283 { NULL, -1, -1, NULL},
1284 };
1285+static const struct kexalg kexalg_prefixes[] = {
1286+#ifdef GSSAPI
1287+ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, EVP_sha1 },
1288+ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, EVP_sha1 },
1289+ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, EVP_sha1 },
1290+#endif
1291+ { NULL, -1, -1, NULL },
1292+};
1293
1294 char *
1295 kex_alg_list(void)
1296@@ -110,6 +122,10 @@
1297 if (strcmp(k->name, name) == 0)
1298 return k;
1299 }
1300+ for (k = kexalg_prefixes; k->name != NULL; k++) {
1301+ if (strncmp(k->name, name, strlen(k->name)) == 0)
1302+ return k;
1303+ }
1304 return NULL;
1305 }
1306
1307Index: b/kex.h
1308===================================================================
1309--- a/kex.h
1310+++ b/kex.h
1311@@ -74,6 +74,9 @@
1312 KEX_DH_GEX_SHA1,
1313 KEX_DH_GEX_SHA256,
1314 KEX_ECDH_SHA2,
1315+ KEX_GSS_GRP1_SHA1,
1316+ KEX_GSS_GRP14_SHA1,
1317+ KEX_GSS_GEX_SHA1,
1318 KEX_MAX
1319 };
1320
1321@@ -133,6 +136,12 @@
1322 int flags;
1323 const EVP_MD *evp_md;
1324 int ec_nid;
1325+#ifdef GSSAPI
1326+ int gss_deleg_creds;
1327+ int gss_trust_dns;
1328+ char *gss_host;
1329+ char *gss_client;
1330+#endif
1331 char *client_version_string;
1332 char *server_version_string;
1333 int (*verify_host_key)(Key *);
1334@@ -162,6 +171,11 @@
1335 void kexecdh_client(Kex *);
1336 void kexecdh_server(Kex *);
1337
1338+#ifdef GSSAPI
1339+void kexgss_client(Kex *);
1340+void kexgss_server(Kex *);
1341+#endif
1342+
1343 void
1344 kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
1345 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
1346Index: b/kexgssc.c
1347===================================================================
1348--- /dev/null
1349+++ b/kexgssc.c
1350@@ -0,0 +1,333 @@
1351+/*
1352+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
1353+ *
1354+ * Redistribution and use in source and binary forms, with or without
1355+ * modification, are permitted provided that the following conditions
1356+ * are met:
1357+ * 1. Redistributions of source code must retain the above copyright
1358+ * notice, this list of conditions and the following disclaimer.
1359+ * 2. Redistributions in binary form must reproduce the above copyright
1360+ * notice, this list of conditions and the following disclaimer in the
1361+ * documentation and/or other materials provided with the distribution.
1362+ *
1363+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
1364+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1365+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1366+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1367+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1368+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1369+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1370+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1371+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1372+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1373+ */
1374+
1375+#include "includes.h"
1376+
1377+#ifdef GSSAPI
1378+
1379+#include "includes.h"
1380+
1381+#include <openssl/crypto.h>
1382+#include <openssl/bn.h>
1383+
1384+#include <string.h>
1385+
1386+#include "xmalloc.h"
1387+#include "buffer.h"
1388+#include "ssh2.h"
1389+#include "key.h"
1390+#include "cipher.h"
1391+#include "kex.h"
1392+#include "log.h"
1393+#include "packet.h"
1394+#include "dh.h"
1395+
1396+#include "ssh-gss.h"
1397+
1398+void
1399+kexgss_client(Kex *kex) {
1400+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
1401+ gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
1402+ Gssctxt *ctxt;
1403+ OM_uint32 maj_status, min_status, ret_flags;
1404+ u_int klen, kout, slen = 0, hashlen, strlen;
1405+ DH *dh;
1406+ BIGNUM *dh_server_pub = NULL;
1407+ BIGNUM *shared_secret = NULL;
1408+ BIGNUM *p = NULL;
1409+ BIGNUM *g = NULL;
1410+ u_char *kbuf, *hash;
1411+ u_char *serverhostkey = NULL;
1412+ u_char *empty = "";
1413+ char *msg;
1414+ char *lang;
1415+ int type = 0;
1416+ int first = 1;
1417+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
1418+
1419+ /* Initialise our GSSAPI world */
1420+ ssh_gssapi_build_ctx(&ctxt);
1421+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
1422+ == GSS_C_NO_OID)
1423+ fatal("Couldn't identify host exchange");
1424+
1425+ if (ssh_gssapi_import_name(ctxt, kex->gss_host))
1426+ fatal("Couldn't import hostname");
1427+
1428+ if (kex->gss_client &&
1429+ ssh_gssapi_client_identity(ctxt, kex->gss_client))
1430+ fatal("Couldn't acquire client credentials");
1431+
1432+ switch (kex->kex_type) {
1433+ case KEX_GSS_GRP1_SHA1:
1434+ dh = dh_new_group1();
1435+ break;
1436+ case KEX_GSS_GRP14_SHA1:
1437+ dh = dh_new_group14();
1438+ break;
1439+ case KEX_GSS_GEX_SHA1:
1440+ debug("Doing group exchange\n");
1441+ nbits = dh_estimate(kex->we_need * 8);
1442+ packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
1443+ packet_put_int(min);
1444+ packet_put_int(nbits);
1445+ packet_put_int(max);
1446+
1447+ packet_send();
1448+
1449+ packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
1450+
1451+ if ((p = BN_new()) == NULL)
1452+ fatal("BN_new() failed");
1453+ packet_get_bignum2(p);
1454+ if ((g = BN_new()) == NULL)
1455+ fatal("BN_new() failed");
1456+ packet_get_bignum2(g);
1457+ packet_check_eom();
1458+
1459+ if (BN_num_bits(p) < min || BN_num_bits(p) > max)
1460+ fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
1461+ min, BN_num_bits(p), max);
1462+
1463+ dh = dh_new_group(g, p);
1464+ break;
1465+ default:
1466+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1467+ }
1468+
1469+ /* Step 1 - e is dh->pub_key */
1470+ dh_gen_key(dh, kex->we_need * 8);
1471+
1472+ /* This is f, we initialise it now to make life easier */
1473+ dh_server_pub = BN_new();
1474+ if (dh_server_pub == NULL)
1475+ fatal("dh_server_pub == NULL");
1476+
1477+ token_ptr = GSS_C_NO_BUFFER;
1478+
1479+ do {
1480+ debug("Calling gss_init_sec_context");
1481+
1482+ maj_status = ssh_gssapi_init_ctx(ctxt,
1483+ kex->gss_deleg_creds, token_ptr, &send_tok,
1484+ &ret_flags);
1485+
1486+ if (GSS_ERROR(maj_status)) {
1487+ if (send_tok.length != 0) {
1488+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1489+ packet_put_string(send_tok.value,
1490+ send_tok.length);
1491+ }
1492+ fatal("gss_init_context failed");
1493+ }
1494+
1495+ /* If we've got an old receive buffer get rid of it */
1496+ if (token_ptr != GSS_C_NO_BUFFER)
1497+ free(recv_tok.value);
1498+
1499+ if (maj_status == GSS_S_COMPLETE) {
1500+ /* If mutual state flag is not true, kex fails */
1501+ if (!(ret_flags & GSS_C_MUTUAL_FLAG))
1502+ fatal("Mutual authentication failed");
1503+
1504+ /* If integ avail flag is not true kex fails */
1505+ if (!(ret_flags & GSS_C_INTEG_FLAG))
1506+ fatal("Integrity check failed");
1507+ }
1508+
1509+ /*
1510+ * If we have data to send, then the last message that we
1511+ * received cannot have been a 'complete'.
1512+ */
1513+ if (send_tok.length != 0) {
1514+ if (first) {
1515+ packet_start(SSH2_MSG_KEXGSS_INIT);
1516+ packet_put_string(send_tok.value,
1517+ send_tok.length);
1518+ packet_put_bignum2(dh->pub_key);
1519+ first = 0;
1520+ } else {
1521+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1522+ packet_put_string(send_tok.value,
1523+ send_tok.length);
1524+ }
1525+ packet_send();
1526+ gss_release_buffer(&min_status, &send_tok);
1527+
1528+ /* If we've sent them data, they should reply */
1529+ do {
1530+ type = packet_read();
1531+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
1532+ debug("Received KEXGSS_HOSTKEY");
1533+ if (serverhostkey)
1534+ fatal("Server host key received more than once");
1535+ serverhostkey =
1536+ packet_get_string(&slen);
1537+ }
1538+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
1539+
1540+ switch (type) {
1541+ case SSH2_MSG_KEXGSS_CONTINUE:
1542+ debug("Received GSSAPI_CONTINUE");
1543+ if (maj_status == GSS_S_COMPLETE)
1544+ fatal("GSSAPI Continue received from server when complete");
1545+ recv_tok.value = packet_get_string(&strlen);
1546+ recv_tok.length = strlen;
1547+ break;
1548+ case SSH2_MSG_KEXGSS_COMPLETE:
1549+ debug("Received GSSAPI_COMPLETE");
1550+ packet_get_bignum2(dh_server_pub);
1551+ msg_tok.value = packet_get_string(&strlen);
1552+ msg_tok.length = strlen;
1553+
1554+ /* Is there a token included? */
1555+ if (packet_get_char()) {
1556+ recv_tok.value=
1557+ packet_get_string(&strlen);
1558+ recv_tok.length = strlen;
1559+ /* If we're already complete - protocol error */
1560+ if (maj_status == GSS_S_COMPLETE)
1561+ packet_disconnect("Protocol error: received token when complete");
1562+ } else {
1563+ /* No token included */
1564+ if (maj_status != GSS_S_COMPLETE)
1565+ packet_disconnect("Protocol error: did not receive final token");
1566+ }
1567+ break;
1568+ case SSH2_MSG_KEXGSS_ERROR:
1569+ debug("Received Error");
1570+ maj_status = packet_get_int();
1571+ min_status = packet_get_int();
1572+ msg = packet_get_string(NULL);
1573+ lang = packet_get_string(NULL);
1574+ fatal("GSSAPI Error: \n%.400s",msg);
1575+ default:
1576+ packet_disconnect("Protocol error: didn't expect packet type %d",
1577+ type);
1578+ }
1579+ token_ptr = &recv_tok;
1580+ } else {
1581+ /* No data, and not complete */
1582+ if (maj_status != GSS_S_COMPLETE)
1583+ fatal("Not complete, and no token output");
1584+ }
1585+ } while (maj_status & GSS_S_CONTINUE_NEEDED);
1586+
1587+ /*
1588+ * We _must_ have received a COMPLETE message in reply from the
1589+ * server, which will have set dh_server_pub and msg_tok
1590+ */
1591+
1592+ if (type != SSH2_MSG_KEXGSS_COMPLETE)
1593+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
1594+
1595+ /* Check f in range [1, p-1] */
1596+ if (!dh_pub_is_valid(dh, dh_server_pub))
1597+ packet_disconnect("bad server public DH value");
1598+
1599+ /* compute K=f^x mod p */
1600+ klen = DH_size(dh);
1601+ kbuf = xmalloc(klen);
1602+ kout = DH_compute_key(kbuf, dh_server_pub, dh);
1603+ if (kout < 0)
1604+ fatal("DH_compute_key: failed");
1605+
1606+ shared_secret = BN_new();
1607+ if (shared_secret == NULL)
1608+ fatal("kexgss_client: BN_new failed");
1609+
1610+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
1611+ fatal("kexdh_client: BN_bin2bn failed");
1612+
1613+ memset(kbuf, 0, klen);
1614+ free(kbuf);
1615+
1616+ switch (kex->kex_type) {
1617+ case KEX_GSS_GRP1_SHA1:
1618+ case KEX_GSS_GRP14_SHA1:
1619+ kex_dh_hash( kex->client_version_string,
1620+ kex->server_version_string,
1621+ buffer_ptr(&kex->my), buffer_len(&kex->my),
1622+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
1623+ (serverhostkey ? serverhostkey : empty), slen,
1624+ dh->pub_key, /* e */
1625+ dh_server_pub, /* f */
1626+ shared_secret, /* K */
1627+ &hash, &hashlen
1628+ );
1629+ break;
1630+ case KEX_GSS_GEX_SHA1:
1631+ kexgex_hash(
1632+ kex->evp_md,
1633+ kex->client_version_string,
1634+ kex->server_version_string,
1635+ buffer_ptr(&kex->my), buffer_len(&kex->my),
1636+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
1637+ (serverhostkey ? serverhostkey : empty), slen,
1638+ min, nbits, max,
1639+ dh->p, dh->g,
1640+ dh->pub_key,
1641+ dh_server_pub,
1642+ shared_secret,
1643+ &hash, &hashlen
1644+ );
1645+ break;
1646+ default:
1647+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1648+ }
1649+
1650+ gssbuf.value = hash;
1651+ gssbuf.length = hashlen;
1652+
1653+ /* Verify that the hash matches the MIC we just got. */
1654+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
1655+ packet_disconnect("Hash's MIC didn't verify");
1656+
1657+ free(msg_tok.value);
1658+
1659+ DH_free(dh);
1660+ free(serverhostkey);
1661+ BN_clear_free(dh_server_pub);
1662+
1663+ /* save session id */
1664+ if (kex->session_id == NULL) {
1665+ kex->session_id_len = hashlen;
1666+ kex->session_id = xmalloc(kex->session_id_len);
1667+ memcpy(kex->session_id, hash, kex->session_id_len);
1668+ }
1669+
1670+ if (kex->gss_deleg_creds)
1671+ ssh_gssapi_credentials_updated(ctxt);
1672+
1673+ if (gss_kex_context == NULL)
1674+ gss_kex_context = ctxt;
1675+ else
1676+ ssh_gssapi_delete_ctx(&ctxt);
1677+
1678+ kex_derive_keys(kex, hash, hashlen, shared_secret);
1679+ BN_clear_free(shared_secret);
1680+ kex_finish(kex);
1681+}
1682+
1683+#endif /* GSSAPI */
1684Index: b/kexgsss.c
1685===================================================================
1686--- /dev/null
1687+++ b/kexgsss.c
1688@@ -0,0 +1,289 @@
1689+/*
1690+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
1691+ *
1692+ * Redistribution and use in source and binary forms, with or without
1693+ * modification, are permitted provided that the following conditions
1694+ * are met:
1695+ * 1. Redistributions of source code must retain the above copyright
1696+ * notice, this list of conditions and the following disclaimer.
1697+ * 2. Redistributions in binary form must reproduce the above copyright
1698+ * notice, this list of conditions and the following disclaimer in the
1699+ * documentation and/or other materials provided with the distribution.
1700+ *
1701+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
1702+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1703+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1704+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1705+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1706+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1707+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1708+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1709+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1710+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1711+ */
1712+
1713+#include "includes.h"
1714+
1715+#ifdef GSSAPI
1716+
1717+#include <string.h>
1718+
1719+#include <openssl/crypto.h>
1720+#include <openssl/bn.h>
1721+
1722+#include "xmalloc.h"
1723+#include "buffer.h"
1724+#include "ssh2.h"
1725+#include "key.h"
1726+#include "cipher.h"
1727+#include "kex.h"
1728+#include "log.h"
1729+#include "packet.h"
1730+#include "dh.h"
1731+#include "ssh-gss.h"
1732+#include "monitor_wrap.h"
1733+#include "servconf.h"
1734+
1735+extern ServerOptions options;
1736+
1737+void
1738+kexgss_server(Kex *kex)
1739+{
1740+ OM_uint32 maj_status, min_status;
1741+
1742+ /*
1743+ * Some GSSAPI implementations use the input value of ret_flags (an
1744+ * output variable) as a means of triggering mechanism specific
1745+ * features. Initializing it to zero avoids inadvertently
1746+ * activating this non-standard behaviour.
1747+ */
1748+
1749+ OM_uint32 ret_flags = 0;
1750+ gss_buffer_desc gssbuf, recv_tok, msg_tok;
1751+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
1752+ Gssctxt *ctxt = NULL;
1753+ u_int slen, klen, kout, hashlen;
1754+ u_char *kbuf, *hash;
1755+ DH *dh;
1756+ int min = -1, max = -1, nbits = -1;
1757+ BIGNUM *shared_secret = NULL;
1758+ BIGNUM *dh_client_pub = NULL;
1759+ int type = 0;
1760+ gss_OID oid;
1761+ char *mechs;
1762+
1763+ /* Initialise GSSAPI */
1764+
1765+ /* If we're rekeying, privsep means that some of the private structures
1766+ * in the GSSAPI code are no longer available. This kludges them back
1767+ * into life
1768+ */
1769+ if (!ssh_gssapi_oid_table_ok()) {
1770+ mechs = ssh_gssapi_server_mechanisms();
1771+ free(mechs);
1772+ }
1773+
1774+ debug2("%s: Identifying %s", __func__, kex->name);
1775+ oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
1776+ if (oid == GSS_C_NO_OID)
1777+ fatal("Unknown gssapi mechanism");
1778+
1779+ debug2("%s: Acquiring credentials", __func__);
1780+
1781+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
1782+ fatal("Unable to acquire credentials for the server");
1783+
1784+ switch (kex->kex_type) {
1785+ case KEX_GSS_GRP1_SHA1:
1786+ dh = dh_new_group1();
1787+ break;
1788+ case KEX_GSS_GRP14_SHA1:
1789+ dh = dh_new_group14();
1790+ break;
1791+ case KEX_GSS_GEX_SHA1:
1792+ debug("Doing group exchange");
1793+ packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
1794+ min = packet_get_int();
1795+ nbits = packet_get_int();
1796+ max = packet_get_int();
1797+ min = MAX(DH_GRP_MIN, min);
1798+ max = MIN(DH_GRP_MAX, max);
1799+ packet_check_eom();
1800+ if (max < min || nbits < min || max < nbits)
1801+ fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
1802+ min, nbits, max);
1803+ dh = PRIVSEP(choose_dh(min, nbits, max));
1804+ if (dh == NULL)
1805+ packet_disconnect("Protocol error: no matching group found");
1806+
1807+ packet_start(SSH2_MSG_KEXGSS_GROUP);
1808+ packet_put_bignum2(dh->p);
1809+ packet_put_bignum2(dh->g);
1810+ packet_send();
1811+
1812+ packet_write_wait();
1813+ break;
1814+ default:
1815+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1816+ }
1817+
1818+ dh_gen_key(dh, kex->we_need * 8);
1819+
1820+ do {
1821+ debug("Wait SSH2_MSG_GSSAPI_INIT");
1822+ type = packet_read();
1823+ switch(type) {
1824+ case SSH2_MSG_KEXGSS_INIT:
1825+ if (dh_client_pub != NULL)
1826+ fatal("Received KEXGSS_INIT after initialising");
1827+ recv_tok.value = packet_get_string(&slen);
1828+ recv_tok.length = slen;
1829+
1830+ if ((dh_client_pub = BN_new()) == NULL)
1831+ fatal("dh_client_pub == NULL");
1832+
1833+ packet_get_bignum2(dh_client_pub);
1834+
1835+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
1836+ break;
1837+ case SSH2_MSG_KEXGSS_CONTINUE:
1838+ recv_tok.value = packet_get_string(&slen);
1839+ recv_tok.length = slen;
1840+ break;
1841+ default:
1842+ packet_disconnect(
1843+ "Protocol error: didn't expect packet type %d",
1844+ type);
1845+ }
1846+
1847+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
1848+ &send_tok, &ret_flags));
1849+
1850+ free(recv_tok.value);
1851+
1852+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
1853+ fatal("Zero length token output when incomplete");
1854+
1855+ if (dh_client_pub == NULL)
1856+ fatal("No client public key");
1857+
1858+ if (maj_status & GSS_S_CONTINUE_NEEDED) {
1859+ debug("Sending GSSAPI_CONTINUE");
1860+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1861+ packet_put_string(send_tok.value, send_tok.length);
1862+ packet_send();
1863+ gss_release_buffer(&min_status, &send_tok);
1864+ }
1865+ } while (maj_status & GSS_S_CONTINUE_NEEDED);
1866+
1867+ if (GSS_ERROR(maj_status)) {
1868+ if (send_tok.length > 0) {
1869+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1870+ packet_put_string(send_tok.value, send_tok.length);
1871+ packet_send();
1872+ }
1873+ fatal("accept_ctx died");
1874+ }
1875+
1876+ if (!(ret_flags & GSS_C_MUTUAL_FLAG))
1877+ fatal("Mutual Authentication flag wasn't set");
1878+
1879+ if (!(ret_flags & GSS_C_INTEG_FLAG))
1880+ fatal("Integrity flag wasn't set");
1881+
1882+ if (!dh_pub_is_valid(dh, dh_client_pub))
1883+ packet_disconnect("bad client public DH value");
1884+
1885+ klen = DH_size(dh);
1886+ kbuf = xmalloc(klen);
1887+ kout = DH_compute_key(kbuf, dh_client_pub, dh);
1888+ if (kout < 0)
1889+ fatal("DH_compute_key: failed");
1890+
1891+ shared_secret = BN_new();
1892+ if (shared_secret == NULL)
1893+ fatal("kexgss_server: BN_new failed");
1894+
1895+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
1896+ fatal("kexgss_server: BN_bin2bn failed");
1897+
1898+ memset(kbuf, 0, klen);
1899+ free(kbuf);
1900+
1901+ switch (kex->kex_type) {
1902+ case KEX_GSS_GRP1_SHA1:
1903+ case KEX_GSS_GRP14_SHA1:
1904+ kex_dh_hash(
1905+ kex->client_version_string, kex->server_version_string,
1906+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
1907+ buffer_ptr(&kex->my), buffer_len(&kex->my),
1908+ NULL, 0, /* Change this if we start sending host keys */
1909+ dh_client_pub, dh->pub_key, shared_secret,
1910+ &hash, &hashlen
1911+ );
1912+ break;
1913+ case KEX_GSS_GEX_SHA1:
1914+ kexgex_hash(
1915+ kex->evp_md,
1916+ kex->client_version_string, kex->server_version_string,
1917+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
1918+ buffer_ptr(&kex->my), buffer_len(&kex->my),
1919+ NULL, 0,
1920+ min, nbits, max,
1921+ dh->p, dh->g,
1922+ dh_client_pub,
1923+ dh->pub_key,
1924+ shared_secret,
1925+ &hash, &hashlen
1926+ );
1927+ break;
1928+ default:
1929+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1930+ }
1931+
1932+ BN_clear_free(dh_client_pub);
1933+
1934+ if (kex->session_id == NULL) {
1935+ kex->session_id_len = hashlen;
1936+ kex->session_id = xmalloc(kex->session_id_len);
1937+ memcpy(kex->session_id, hash, kex->session_id_len);
1938+ }
1939+
1940+ gssbuf.value = hash;
1941+ gssbuf.length = hashlen;
1942+
1943+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
1944+ fatal("Couldn't get MIC");
1945+
1946+ packet_start(SSH2_MSG_KEXGSS_COMPLETE);
1947+ packet_put_bignum2(dh->pub_key);
1948+ packet_put_string(msg_tok.value,msg_tok.length);
1949+
1950+ if (send_tok.length != 0) {
1951+ packet_put_char(1); /* true */
1952+ packet_put_string(send_tok.value, send_tok.length);
1953+ } else {
1954+ packet_put_char(0); /* false */
1955+ }
1956+ packet_send();
1957+
1958+ gss_release_buffer(&min_status, &send_tok);
1959+ gss_release_buffer(&min_status, &msg_tok);
1960+
1961+ if (gss_kex_context == NULL)
1962+ gss_kex_context = ctxt;
1963+ else
1964+ ssh_gssapi_delete_ctx(&ctxt);
1965+
1966+ DH_free(dh);
1967+
1968+ kex_derive_keys(kex, hash, hashlen, shared_secret);
1969+ BN_clear_free(shared_secret);
1970+ kex_finish(kex);
1971+
1972+ /* If this was a rekey, then save out any delegated credentials we
1973+ * just exchanged. */
1974+ if (options.gss_store_rekey)
1975+ ssh_gssapi_rekey_creds();
1976+}
1977+#endif /* GSSAPI */
1978Index: b/key.c
1979===================================================================
1980--- a/key.c
1981+++ b/key.c
1982@@ -933,6 +933,7 @@
1983 KEY_RSA_CERT_V00, 0, 1 },
1984 { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00",
1985 KEY_DSA_CERT_V00, 0, 1 },
1986+ { "null", "null", KEY_NULL, 0, 0 },
1987 { NULL, NULL, -1, -1, 0 }
1988 };
1989
1990Index: b/key.h
1991===================================================================
1992--- a/key.h
1993+++ b/key.h
1994@@ -44,6 +44,7 @@
1995 KEY_ECDSA_CERT,
1996 KEY_RSA_CERT_V00,
1997 KEY_DSA_CERT_V00,
1998+ KEY_NULL,
1999 KEY_UNSPEC
2000 };
2001 enum fp_type {
2002Index: b/monitor.c
2003===================================================================
2004--- a/monitor.c
2005+++ b/monitor.c
2006@@ -181,6 +181,8 @@
2007 int mm_answer_gss_accept_ctx(int, Buffer *);
2008 int mm_answer_gss_userok(int, Buffer *);
2009 int mm_answer_gss_checkmic(int, Buffer *);
2010+int mm_answer_gss_sign(int, Buffer *);
2011+int mm_answer_gss_updatecreds(int, Buffer *);
2012 #endif
2013
2014 #ifdef SSH_AUDIT_EVENTS
2015@@ -253,6 +255,7 @@
2016 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
2017 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
2018 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
2019+ {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
2020 #endif
2021 #ifdef JPAKE
2022 {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
2023@@ -265,6 +268,12 @@
2024 };
2025
2026 struct mon_table mon_dispatch_postauth20[] = {
2027+#ifdef GSSAPI
2028+ {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
2029+ {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
2030+ {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
2031+ {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
2032+#endif
2033 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
2034 {MONITOR_REQ_SIGN, 0, mm_answer_sign},
2035 {MONITOR_REQ_PTY, 0, mm_answer_pty},
2036@@ -373,6 +382,10 @@
2037 /* Permit requests for moduli and signatures */
2038 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
2039 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
2040+#ifdef GSSAPI
2041+ /* and for the GSSAPI key exchange */
2042+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
2043+#endif
2044 } else {
2045 mon_dispatch = mon_dispatch_proto15;
2046
2047@@ -487,6 +500,10 @@
2048 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
2049 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
2050 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
2051+#ifdef GSSAPI
2052+ /* and for the GSSAPI key exchange */
2053+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
2054+#endif
2055 } else {
2056 mon_dispatch = mon_dispatch_postauth15;
2057 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
2058@@ -1855,6 +1872,13 @@
2059 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
2060 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
2061 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
2062+#ifdef GSSAPI
2063+ if (options.gss_keyex) {
2064+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
2065+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
2066+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
2067+ }
2068+#endif
2069 kex->server = 1;
2070 kex->hostkey_type = buffer_get_int(m);
2071 kex->kex_type = buffer_get_int(m);
2072@@ -2062,6 +2086,9 @@
2073 OM_uint32 major;
2074 u_int len;
2075
2076+ if (!options.gss_authentication && !options.gss_keyex)
2077+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2078+
2079 goid.elements = buffer_get_string(m, &len);
2080 goid.length = len;
2081
2082@@ -2089,6 +2116,9 @@
2083 OM_uint32 flags = 0; /* GSI needs this */
2084 u_int len;
2085
2086+ if (!options.gss_authentication && !options.gss_keyex)
2087+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2088+
2089 in.value = buffer_get_string(m, &len);
2090 in.length = len;
2091 major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
2092@@ -2106,6 +2136,7 @@
2093 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
2094 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
2095 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
2096+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
2097 }
2098 return (0);
2099 }
2100@@ -2117,6 +2148,9 @@
2101 OM_uint32 ret;
2102 u_int len;
2103
2104+ if (!options.gss_authentication && !options.gss_keyex)
2105+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2106+
2107 gssbuf.value = buffer_get_string(m, &len);
2108 gssbuf.length = len;
2109 mic.value = buffer_get_string(m, &len);
2110@@ -2143,7 +2177,11 @@
2111 {
2112 int authenticated;
2113
2114- authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
2115+ if (!options.gss_authentication && !options.gss_keyex)
2116+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2117+
2118+ authenticated = authctxt->valid &&
2119+ ssh_gssapi_userok(authctxt->user, authctxt->pw);
2120
2121 buffer_clear(m);
2122 buffer_put_int(m, authenticated);
2123@@ -2156,6 +2194,74 @@
2124 /* Monitor loop will terminate if authenticated */
2125 return (authenticated);
2126 }
2127+
2128+int
2129+mm_answer_gss_sign(int socket, Buffer *m)
2130+{
2131+ gss_buffer_desc data;
2132+ gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
2133+ OM_uint32 major, minor;
2134+ u_int len;
2135+
2136+ if (!options.gss_authentication && !options.gss_keyex)
2137+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2138+
2139+ data.value = buffer_get_string(m, &len);
2140+ data.length = len;
2141+ if (data.length != 20)
2142+ fatal("%s: data length incorrect: %d", __func__,
2143+ (int) data.length);
2144+
2145+ /* Save the session ID on the first time around */
2146+ if (session_id2_len == 0) {
2147+ session_id2_len = data.length;
2148+ session_id2 = xmalloc(session_id2_len);
2149+ memcpy(session_id2, data.value, session_id2_len);
2150+ }
2151+ major = ssh_gssapi_sign(gsscontext, &data, &hash);
2152+
2153+ free(data.value);
2154+
2155+ buffer_clear(m);
2156+ buffer_put_int(m, major);
2157+ buffer_put_string(m, hash.value, hash.length);
2158+
2159+ mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
2160+
2161+ gss_release_buffer(&minor, &hash);
2162+
2163+ /* Turn on getpwnam permissions */
2164+ monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
2165+
2166+ /* And credential updating, for when rekeying */
2167+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
2168+
2169+ return (0);
2170+}
2171+
2172+int
2173+mm_answer_gss_updatecreds(int socket, Buffer *m) {
2174+ ssh_gssapi_ccache store;
2175+ int ok;
2176+
2177+ store.filename = buffer_get_string(m, NULL);
2178+ store.envvar = buffer_get_string(m, NULL);
2179+ store.envval = buffer_get_string(m, NULL);
2180+
2181+ ok = ssh_gssapi_update_creds(&store);
2182+
2183+ free(store.filename);
2184+ free(store.envvar);
2185+ free(store.envval);
2186+
2187+ buffer_clear(m);
2188+ buffer_put_int(m, ok);
2189+
2190+ mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
2191+
2192+ return(0);
2193+}
2194+
2195 #endif /* GSSAPI */
2196
2197 #ifdef JPAKE
2198Index: b/monitor.h
2199===================================================================
2200--- a/monitor.h
2201+++ b/monitor.h
2202@@ -70,6 +70,9 @@
2203 MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
2204 MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
2205
2206+ MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
2207+ MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
2208+
2209 };
2210
2211 struct mm_master;
2212Index: b/monitor_wrap.c
2213===================================================================
2214--- a/monitor_wrap.c
2215+++ b/monitor_wrap.c
2216@@ -1273,7 +1273,7 @@
2217 }
2218
2219 int
2220-mm_ssh_gssapi_userok(char *user)
2221+mm_ssh_gssapi_userok(char *user, struct passwd *pw)
2222 {
2223 Buffer m;
2224 int authenticated = 0;
2225@@ -1290,6 +1290,51 @@
2226 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
2227 return (authenticated);
2228 }
2229+
2230+OM_uint32
2231+mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
2232+{
2233+ Buffer m;
2234+ OM_uint32 major;
2235+ u_int len;
2236+
2237+ buffer_init(&m);
2238+ buffer_put_string(&m, data->value, data->length);
2239+
2240+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
2241+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
2242+
2243+ major = buffer_get_int(&m);
2244+ hash->value = buffer_get_string(&m, &len);
2245+ hash->length = len;
2246+
2247+ buffer_free(&m);
2248+
2249+ return(major);
2250+}
2251+
2252+int
2253+mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
2254+{
2255+ Buffer m;
2256+ int ok;
2257+
2258+ buffer_init(&m);
2259+
2260+ buffer_put_cstring(&m, store->filename ? store->filename : "");
2261+ buffer_put_cstring(&m, store->envvar ? store->envvar : "");
2262+ buffer_put_cstring(&m, store->envval ? store->envval : "");
2263+
2264+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m);
2265+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m);
2266+
2267+ ok = buffer_get_int(&m);
2268+
2269+ buffer_free(&m);
2270+
2271+ return (ok);
2272+}
2273+
2274 #endif /* GSSAPI */
2275
2276 #ifdef JPAKE
2277Index: b/monitor_wrap.h
2278===================================================================
2279--- a/monitor_wrap.h
2280+++ b/monitor_wrap.h
2281@@ -58,8 +58,10 @@
2282 OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
2283 OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
2284 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
2285-int mm_ssh_gssapi_userok(char *user);
2286+int mm_ssh_gssapi_userok(char *user, struct passwd *);
2287 OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
2288+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
2289+int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
2290 #endif
2291
2292 #ifdef USE_PAM
2293Index: b/readconf.c
2294===================================================================
2295--- a/readconf.c
2296+++ b/readconf.c
2297@@ -132,6 +132,8 @@
2298 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
2299 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
2300 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
2301+ oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
2302+ oGssServerIdentity,
2303 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
2304 oSendEnv, oControlPath, oControlMaster, oControlPersist,
2305 oHashKnownHosts,
2306@@ -172,10 +174,19 @@
2307 { "afstokenpassing", oUnsupported },
2308 #if defined(GSSAPI)
2309 { "gssapiauthentication", oGssAuthentication },
2310+ { "gssapikeyexchange", oGssKeyEx },
2311 { "gssapidelegatecredentials", oGssDelegateCreds },
2312+ { "gssapitrustdns", oGssTrustDns },
2313+ { "gssapiclientidentity", oGssClientIdentity },
2314+ { "gssapiserveridentity", oGssServerIdentity },
2315+ { "gssapirenewalforcesrekey", oGssRenewalRekey },
2316 #else
2317 { "gssapiauthentication", oUnsupported },
2318+ { "gssapikeyexchange", oUnsupported },
2319 { "gssapidelegatecredentials", oUnsupported },
2320+ { "gssapitrustdns", oUnsupported },
2321+ { "gssapiclientidentity", oUnsupported },
2322+ { "gssapirenewalforcesrekey", oUnsupported },
2323 #endif
2324 { "fallbacktorsh", oDeprecated },
2325 { "usersh", oDeprecated },
2326@@ -516,10 +527,30 @@
2327 intptr = &options->gss_authentication;
2328 goto parse_flag;
2329
2330+ case oGssKeyEx:
2331+ intptr = &options->gss_keyex;
2332+ goto parse_flag;
2333+
2334 case oGssDelegateCreds:
2335 intptr = &options->gss_deleg_creds;
2336 goto parse_flag;
2337
2338+ case oGssTrustDns:
2339+ intptr = &options->gss_trust_dns;
2340+ goto parse_flag;
2341+
2342+ case oGssClientIdentity:
2343+ charptr = &options->gss_client_identity;
2344+ goto parse_string;
2345+
2346+ case oGssServerIdentity:
2347+ charptr = &options->gss_server_identity;
2348+ goto parse_string;
2349+
2350+ case oGssRenewalRekey:
2351+ intptr = &options->gss_renewal_rekey;
2352+ goto parse_flag;
2353+
2354 case oBatchMode:
2355 intptr = &options->batch_mode;
2356 goto parse_flag;
2357@@ -1168,7 +1199,12 @@
2358 options->pubkey_authentication = -1;
2359 options->challenge_response_authentication = -1;
2360 options->gss_authentication = -1;
2361+ options->gss_keyex = -1;
2362 options->gss_deleg_creds = -1;
2363+ options->gss_trust_dns = -1;
2364+ options->gss_renewal_rekey = -1;
2365+ options->gss_client_identity = NULL;
2366+ options->gss_server_identity = NULL;
2367 options->password_authentication = -1;
2368 options->kbd_interactive_authentication = -1;
2369 options->kbd_interactive_devices = NULL;
2370@@ -1268,8 +1304,14 @@
2371 options->challenge_response_authentication = 1;
2372 if (options->gss_authentication == -1)
2373 options->gss_authentication = 0;
2374+ if (options->gss_keyex == -1)
2375+ options->gss_keyex = 0;
2376 if (options->gss_deleg_creds == -1)
2377 options->gss_deleg_creds = 0;
2378+ if (options->gss_trust_dns == -1)
2379+ options->gss_trust_dns = 0;
2380+ if (options->gss_renewal_rekey == -1)
2381+ options->gss_renewal_rekey = 0;
2382 if (options->password_authentication == -1)
2383 options->password_authentication = 1;
2384 if (options->kbd_interactive_authentication == -1)
2385Index: b/readconf.h
2386===================================================================
2387--- a/readconf.h
2388+++ b/readconf.h
2389@@ -48,7 +48,12 @@
2390 int challenge_response_authentication;
2391 /* Try S/Key or TIS, authentication. */
2392 int gss_authentication; /* Try GSS authentication */
2393+ int gss_keyex; /* Try GSS key exchange */
2394 int gss_deleg_creds; /* Delegate GSS credentials */
2395+ int gss_trust_dns; /* Trust DNS for GSS canonicalization */
2396+ int gss_renewal_rekey; /* Credential renewal forces rekey */
2397+ char *gss_client_identity; /* Principal to initiate GSSAPI with */
2398+ char *gss_server_identity; /* GSSAPI target principal */
2399 int password_authentication; /* Try password
2400 * authentication. */
2401 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
2402Index: b/servconf.c
2403===================================================================
2404--- a/servconf.c
2405+++ b/servconf.c
2406@@ -107,7 +107,10 @@
2407 options->kerberos_ticket_cleanup = -1;
2408 options->kerberos_get_afs_token = -1;
2409 options->gss_authentication=-1;
2410+ options->gss_keyex = -1;
2411 options->gss_cleanup_creds = -1;
2412+ options->gss_strict_acceptor = -1;
2413+ options->gss_store_rekey = -1;
2414 options->password_authentication = -1;
2415 options->kbd_interactive_authentication = -1;
2416 options->challenge_response_authentication = -1;
2417@@ -240,8 +243,14 @@
2418 options->kerberos_get_afs_token = 0;
2419 if (options->gss_authentication == -1)
2420 options->gss_authentication = 0;
2421+ if (options->gss_keyex == -1)
2422+ options->gss_keyex = 0;
2423 if (options->gss_cleanup_creds == -1)
2424 options->gss_cleanup_creds = 1;
2425+ if (options->gss_strict_acceptor == -1)
2426+ options->gss_strict_acceptor = 1;
2427+ if (options->gss_store_rekey == -1)
2428+ options->gss_store_rekey = 0;
2429 if (options->password_authentication == -1)
2430 options->password_authentication = 1;
2431 if (options->kbd_interactive_authentication == -1)
2432@@ -338,7 +347,9 @@
2433 sBanner, sUseDNS, sHostbasedAuthentication,
2434 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
2435 sClientAliveCountMax, sAuthorizedKeysFile,
2436- sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
2437+ sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
2438+ sGssKeyEx, sGssStoreRekey,
2439+ sAcceptEnv, sPermitTunnel,
2440 sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
2441 sUsePrivilegeSeparation, sAllowAgentForwarding,
2442 sZeroKnowledgePasswordAuthentication, sHostCertificate,
2443@@ -405,10 +416,20 @@
2444 #ifdef GSSAPI
2445 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
2446 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
2447+ { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
2448+ { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
2449+ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
2450+ { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
2451 #else
2452 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
2453 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
2454+ { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
2455+ { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
2456+ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
2457+ { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
2458 #endif
2459+ { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
2460+ { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
2461 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
2462 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
2463 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
2464@@ -1073,10 +1094,22 @@
2465 intptr = &options->gss_authentication;
2466 goto parse_flag;
2467
2468+ case sGssKeyEx:
2469+ intptr = &options->gss_keyex;
2470+ goto parse_flag;
2471+
2472 case sGssCleanupCreds:
2473 intptr = &options->gss_cleanup_creds;
2474 goto parse_flag;
2475
2476+ case sGssStrictAcceptor:
2477+ intptr = &options->gss_strict_acceptor;
2478+ goto parse_flag;
2479+
2480+ case sGssStoreRekey:
2481+ intptr = &options->gss_store_rekey;
2482+ goto parse_flag;
2483+
2484 case sPasswordAuthentication:
2485 intptr = &options->password_authentication;
2486 goto parse_flag;
2487@@ -1983,7 +2016,10 @@
2488 #endif
2489 #ifdef GSSAPI
2490 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2491+ dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
2492 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2493+ dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
2494+ dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
2495 #endif
2496 #ifdef JPAKE
2497 dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication,
2498Index: b/servconf.h
2499===================================================================
2500--- a/servconf.h
2501+++ b/servconf.h
2502@@ -111,7 +111,10 @@
2503 int kerberos_get_afs_token; /* If true, try to get AFS token if
2504 * authenticated with Kerberos. */
2505 int gss_authentication; /* If true, permit GSSAPI authentication */
2506+ int gss_keyex; /* If true, permit GSSAPI key exchange */
2507 int gss_cleanup_creds; /* If true, destroy cred cache on logout */
2508+ int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */
2509+ int gss_store_rekey;
2510 int password_authentication; /* If true, permit password
2511 * authentication. */
2512 int kbd_interactive_authentication; /* If true, permit */
2513Index: b/ssh-gss.h
2514===================================================================
2515--- a/ssh-gss.h
2516+++ b/ssh-gss.h
2517@@ -1,6 +1,6 @@
2518 /* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */
2519 /*
2520- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
2521+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
2522 *
2523 * Redistribution and use in source and binary forms, with or without
2524 * modification, are permitted provided that the following conditions
2525@@ -61,10 +61,22 @@
2526
2527 #define SSH_GSS_OIDTYPE 0x06
2528
2529+#define SSH2_MSG_KEXGSS_INIT 30
2530+#define SSH2_MSG_KEXGSS_CONTINUE 31
2531+#define SSH2_MSG_KEXGSS_COMPLETE 32
2532+#define SSH2_MSG_KEXGSS_HOSTKEY 33
2533+#define SSH2_MSG_KEXGSS_ERROR 34
2534+#define SSH2_MSG_KEXGSS_GROUPREQ 40
2535+#define SSH2_MSG_KEXGSS_GROUP 41
2536+#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-"
2537+#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-"
2538+#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-"
2539+
2540 typedef struct {
2541 char *filename;
2542 char *envvar;
2543 char *envval;
2544+ struct passwd *owner;
2545 void *data;
2546 } ssh_gssapi_ccache;
2547
2548@@ -72,8 +84,11 @@
2549 gss_buffer_desc displayname;
2550 gss_buffer_desc exportedname;
2551 gss_cred_id_t creds;
2552+ gss_name_t name;
2553 struct ssh_gssapi_mech_struct *mech;
2554 ssh_gssapi_ccache store;
2555+ int used;
2556+ int updated;
2557 } ssh_gssapi_client;
2558
2559 typedef struct ssh_gssapi_mech_struct {
2560@@ -84,6 +99,7 @@
2561 int (*userok) (ssh_gssapi_client *, char *);
2562 int (*localname) (ssh_gssapi_client *, char **);
2563 void (*storecreds) (ssh_gssapi_client *);
2564+ int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
2565 } ssh_gssapi_mech;
2566
2567 typedef struct {
2568@@ -94,10 +110,11 @@
2569 gss_OID oid; /* client */
2570 gss_cred_id_t creds; /* server */
2571 gss_name_t client; /* server */
2572- gss_cred_id_t client_creds; /* server */
2573+ gss_cred_id_t client_creds; /* both */
2574 } Gssctxt;
2575
2576 extern ssh_gssapi_mech *supported_mechs[];
2577+extern Gssctxt *gss_kex_context;
2578
2579 int ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
2580 void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
2581@@ -117,16 +134,30 @@
2582 void ssh_gssapi_delete_ctx(Gssctxt **);
2583 OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
2584 void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
2585-int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *);
2586+int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *);
2587+OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
2588+int ssh_gssapi_credentials_updated(Gssctxt *);
2589
2590 /* In the server */
2591+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,
2592+ const char *);
2593+char *ssh_gssapi_client_mechanisms(const char *, const char *);
2594+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *,
2595+ const char *);
2596+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
2597+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *,
2598+ const char *);
2599 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
2600-int ssh_gssapi_userok(char *name);
2601+int ssh_gssapi_userok(char *name, struct passwd *);
2602 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
2603 void ssh_gssapi_do_child(char ***, u_int *);
2604 void ssh_gssapi_cleanup_creds(void);
2605 void ssh_gssapi_storecreds(void);
2606
2607+char *ssh_gssapi_server_mechanisms(void);
2608+int ssh_gssapi_oid_table_ok();
2609+
2610+int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
2611 #endif /* GSSAPI */
2612
2613 #endif /* _SSH_GSS_H */
2614Index: b/ssh_config
2615===================================================================
2616--- a/ssh_config
2617+++ b/ssh_config
2618@@ -26,6 +26,8 @@
2619 # HostbasedAuthentication no
2620 # GSSAPIAuthentication no
2621 # GSSAPIDelegateCredentials no
2622+# GSSAPIKeyExchange no
2623+# GSSAPITrustDNS no
2624 # BatchMode no
2625 # CheckHostIP yes
2626 # AddressFamily any
2627Index: b/ssh_config.5
2628===================================================================
2629--- a/ssh_config.5
2630+++ b/ssh_config.5
2631@@ -529,11 +529,43 @@
2632 The default is
2633 .Dq no .
2634 Note that this option applies to protocol version 2 only.
2635+.It Cm GSSAPIKeyExchange
2636+Specifies whether key exchange based on GSSAPI may be used. When using
2637+GSSAPI key exchange the server need not have a host key.
2638+The default is
2639+.Dq no .
2640+Note that this option applies to protocol version 2 only.
2641+.It Cm GSSAPIClientIdentity
2642+If set, specifies the GSSAPI client identity that ssh should use when
2643+connecting to the server. The default is unset, which means that the default
2644+identity will be used.
2645+.It Cm GSSAPIServerIdentity
2646+If set, specifies the GSSAPI server identity that ssh should expect when
2647+connecting to the server. The default is unset, which means that the
2648+expected GSSAPI server identity will be determined from the target
2649+hostname.
2650 .It Cm GSSAPIDelegateCredentials
2651 Forward (delegate) credentials to the server.
2652 The default is
2653 .Dq no .
2654-Note that this option applies to protocol version 2 only.
2655+Note that this option applies to protocol version 2 connections using GSSAPI.
2656+.It Cm GSSAPIRenewalForcesRekey
2657+If set to
2658+.Dq yes
2659+then renewal of the client's GSSAPI credentials will force the rekeying of the
2660+ssh connection. With a compatible server, this can delegate the renewed
2661+credentials to a session on the server.
2662+The default is
2663+.Dq no .
2664+.It Cm GSSAPITrustDns
2665+Set to
2666+.Dq yes to indicate that the DNS is trusted to securely canonicalize
2667+the name of the host being connected to. If
2668+.Dq no, the hostname entered on the
2669+command line will be passed untouched to the GSSAPI library.
2670+The default is
2671+.Dq no .
2672+This option only applies to protocol version 2 connections using GSSAPI.
2673 .It Cm HashKnownHosts
2674 Indicates that
2675 .Xr ssh 1
2676Index: b/sshconnect2.c
2677===================================================================
2678--- a/sshconnect2.c
2679+++ b/sshconnect2.c
2680@@ -160,9 +160,34 @@
2681 {
2682 Kex *kex;
2683
2684+#ifdef GSSAPI
2685+ char *orig = NULL, *gss = NULL;
2686+ char *gss_host = NULL;
2687+#endif
2688+
2689 xxx_host = host;
2690 xxx_hostaddr = hostaddr;
2691
2692+#ifdef GSSAPI
2693+ if (options.gss_keyex) {
2694+ /* Add the GSSAPI mechanisms currently supported on this
2695+ * client to the key exchange algorithm proposal */
2696+ orig = myproposal[PROPOSAL_KEX_ALGS];
2697+
2698+ if (options.gss_trust_dns)
2699+ gss_host = (char *)get_canonical_hostname(1);
2700+ else
2701+ gss_host = host;
2702+
2703+ gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
2704+ if (gss) {
2705+ debug("Offering GSSAPI proposal: %s", gss);
2706+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
2707+ "%s,%s", gss, orig);
2708+ }
2709+ }
2710+#endif
2711+
2712 if (options.ciphers == (char *)-1) {
2713 logit("No valid ciphers for protocol version 2 given, using defaults.");
2714 options.ciphers = NULL;
2715@@ -197,6 +222,17 @@
2716 if (options.kex_algorithms != NULL)
2717 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
2718
2719+#ifdef GSSAPI
2720+ /* If we've got GSSAPI algorithms, then we also support the
2721+ * 'null' hostkey, as a last resort */
2722+ if (options.gss_keyex && gss) {
2723+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
2724+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
2725+ "%s,null", orig);
2726+ free(gss);
2727+ }
2728+#endif
2729+
2730 if (options.rekey_limit || options.rekey_interval)
2731 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
2732 (time_t)options.rekey_interval);
2733@@ -208,10 +244,30 @@
2734 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
2735 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
2736 kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
2737+#ifdef GSSAPI
2738+ if (options.gss_keyex) {
2739+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
2740+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
2741+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
2742+ }
2743+#endif
2744 kex->client_version_string=client_version_string;
2745 kex->server_version_string=server_version_string;
2746 kex->verify_host_key=&verify_host_key_callback;
2747
2748+#ifdef GSSAPI
2749+ if (options.gss_keyex) {
2750+ kex->gss_deleg_creds = options.gss_deleg_creds;
2751+ kex->gss_trust_dns = options.gss_trust_dns;
2752+ kex->gss_client = options.gss_client_identity;
2753+ if (options.gss_server_identity) {
2754+ kex->gss_host = options.gss_server_identity;
2755+ } else {
2756+ kex->gss_host = gss_host;
2757+ }
2758+ }
2759+#endif
2760+
2761 xxx_kex = kex;
2762
2763 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
2764@@ -307,6 +363,7 @@
2765 void input_gssapi_hash(int type, u_int32_t, void *);
2766 void input_gssapi_error(int, u_int32_t, void *);
2767 void input_gssapi_errtok(int, u_int32_t, void *);
2768+int userauth_gsskeyex(Authctxt *authctxt);
2769 #endif
2770
2771 void userauth(Authctxt *, char *);
2772@@ -322,6 +379,11 @@
2773
2774 Authmethod authmethods[] = {
2775 #ifdef GSSAPI
2776+ {"gssapi-keyex",
2777+ userauth_gsskeyex,
2778+ NULL,
2779+ &options.gss_authentication,
2780+ NULL},
2781 {"gssapi-with-mic",
2782 userauth_gssapi,
2783 NULL,
2784@@ -625,19 +687,31 @@
2785 static u_int mech = 0;
2786 OM_uint32 min;
2787 int ok = 0;
2788+ const char *gss_host;
2789+
2790+ if (options.gss_server_identity)
2791+ gss_host = options.gss_server_identity;
2792+ else if (options.gss_trust_dns)
2793+ gss_host = get_canonical_hostname(1);
2794+ else
2795+ gss_host = authctxt->host;
2796
2797 /* Try one GSSAPI method at a time, rather than sending them all at
2798 * once. */
2799
2800 if (gss_supported == NULL)
2801- gss_indicate_mechs(&min, &gss_supported);
2802+ if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
2803+ gss_supported = NULL;
2804+ return 0;
2805+ }
2806
2807 /* Check to see if the mechanism is usable before we offer it */
2808 while (mech < gss_supported->count && !ok) {
2809 /* My DER encoding requires length<128 */
2810 if (gss_supported->elements[mech].length < 128 &&
2811 ssh_gssapi_check_mechanism(&gssctxt,
2812- &gss_supported->elements[mech], authctxt->host)) {
2813+ &gss_supported->elements[mech], gss_host,
2814+ options.gss_client_identity)) {
2815 ok = 1; /* Mechanism works */
2816 } else {
2817 mech++;
2818@@ -734,8 +808,8 @@
2819 {
2820 Authctxt *authctxt = ctxt;
2821 Gssctxt *gssctxt;
2822- int oidlen;
2823- char *oidv;
2824+ u_int oidlen;
2825+ u_char *oidv;
2826
2827 if (authctxt == NULL)
2828 fatal("input_gssapi_response: no authentication context");
2829@@ -844,6 +918,48 @@
2830 free(msg);
2831 free(lang);
2832 }
2833+
2834+int
2835+userauth_gsskeyex(Authctxt *authctxt)
2836+{
2837+ Buffer b;
2838+ gss_buffer_desc gssbuf;
2839+ gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
2840+ OM_uint32 ms;
2841+
2842+ static int attempt = 0;
2843+ if (attempt++ >= 1)
2844+ return (0);
2845+
2846+ if (gss_kex_context == NULL) {
2847+ debug("No valid Key exchange context");
2848+ return (0);
2849+ }
2850+
2851+ ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
2852+ "gssapi-keyex");
2853+
2854+ gssbuf.value = buffer_ptr(&b);
2855+ gssbuf.length = buffer_len(&b);
2856+
2857+ if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
2858+ buffer_free(&b);
2859+ return (0);
2860+ }
2861+
2862+ packet_start(SSH2_MSG_USERAUTH_REQUEST);
2863+ packet_put_cstring(authctxt->server_user);
2864+ packet_put_cstring(authctxt->service);
2865+ packet_put_cstring(authctxt->method->name);
2866+ packet_put_string(mic.value, mic.length);
2867+ packet_send();
2868+
2869+ buffer_free(&b);
2870+ gss_release_buffer(&ms, &mic);
2871+
2872+ return (1);
2873+}
2874+
2875 #endif /* GSSAPI */
2876
2877 int
2878Index: b/sshd.c
2879===================================================================
2880--- a/sshd.c
2881+++ b/sshd.c
2882@@ -122,6 +122,10 @@
2883 #include "ssh-sandbox.h"
2884 #include "version.h"
2885
2886+#ifdef USE_SECURITY_SESSION_API
2887+#include <Security/AuthSession.h>
2888+#endif
2889+
2890 #ifdef LIBWRAP
2891 #include <tcpd.h>
2892 #include <syslog.h>
2893@@ -1703,10 +1707,13 @@
2894 logit("Disabling protocol version 1. Could not load host key");
2895 options.protocol &= ~SSH_PROTO_1;
2896 }
2897+#ifndef GSSAPI
2898+ /* The GSSAPI key exchange can run without a host key */
2899 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
2900 logit("Disabling protocol version 2. Could not load host key");
2901 options.protocol &= ~SSH_PROTO_2;
2902 }
2903+#endif
2904 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
2905 logit("sshd: no hostkeys available -- exiting.");
2906 exit(1);
2907@@ -2035,6 +2042,60 @@
2908 /* Log the connection. */
2909 verbose("Connection from %.500s port %d", remote_ip, remote_port);
2910
2911+#ifdef USE_SECURITY_SESSION_API
2912+ /*
2913+ * Create a new security session for use by the new user login if
2914+ * the current session is the root session or we are not launched
2915+ * by inetd (eg: debugging mode or server mode). We do not
2916+ * necessarily need to create a session if we are launched from
2917+ * inetd because Panther xinetd will create a session for us.
2918+ *
2919+ * The only case where this logic will fail is if there is an
2920+ * inetd running in a non-root session which is not creating
2921+ * new sessions for us. Then all the users will end up in the
2922+ * same session (bad).
2923+ *
2924+ * When the client exits, the session will be destroyed for us
2925+ * automatically.
2926+ *
2927+ * We must create the session before any credentials are stored
2928+ * (including AFS pags, which happens a few lines below).
2929+ */
2930+ {
2931+ OSStatus err = 0;
2932+ SecuritySessionId sid = 0;
2933+ SessionAttributeBits sattrs = 0;
2934+
2935+ err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
2936+ if (err)
2937+ error("SessionGetInfo() failed with error %.8X",
2938+ (unsigned) err);
2939+ else
2940+ debug("Current Session ID is %.8X / Session Attributes are %.8X",
2941+ (unsigned) sid, (unsigned) sattrs);
2942+
2943+ if (inetd_flag && !(sattrs & sessionIsRoot))
2944+ debug("Running in inetd mode in a non-root session... "
2945+ "assuming inetd created the session for us.");
2946+ else {
2947+ debug("Creating new security session...");
2948+ err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
2949+ if (err)
2950+ error("SessionCreate() failed with error %.8X",
2951+ (unsigned) err);
2952+
2953+ err = SessionGetInfo(callerSecuritySession, &sid,
2954+ &sattrs);
2955+ if (err)
2956+ error("SessionGetInfo() failed with error %.8X",
2957+ (unsigned) err);
2958+ else
2959+ debug("New Session ID is %.8X / Session Attributes are %.8X",
2960+ (unsigned) sid, (unsigned) sattrs);
2961+ }
2962+ }
2963+#endif
2964+
2965 /*
2966 * We don't want to listen forever unless the other side
2967 * successfully authenticates itself. So we set up an alarm which is
2968@@ -2439,6 +2500,48 @@
2969
2970 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
2971
2972+#ifdef GSSAPI
2973+ {
2974+ char *orig;
2975+ char *gss = NULL;
2976+ char *newstr = NULL;
2977+ orig = myproposal[PROPOSAL_KEX_ALGS];
2978+
2979+ /*
2980+ * If we don't have a host key, then there's no point advertising
2981+ * the other key exchange algorithms
2982+ */
2983+
2984+ if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
2985+ orig = NULL;
2986+
2987+ if (options.gss_keyex)
2988+ gss = ssh_gssapi_server_mechanisms();
2989+ else
2990+ gss = NULL;
2991+
2992+ if (gss && orig)
2993+ xasprintf(&newstr, "%s,%s", gss, orig);
2994+ else if (gss)
2995+ newstr = gss;
2996+ else if (orig)
2997+ newstr = orig;
2998+
2999+ /*
3000+ * If we've got GSSAPI mechanisms, then we've got the 'null' host
3001+ * key alg, but we can't tell people about it unless its the only
3002+ * host key algorithm we support
3003+ */
3004+ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
3005+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
3006+
3007+ if (newstr)
3008+ myproposal[PROPOSAL_KEX_ALGS] = newstr;
3009+ else
3010+ fatal("No supported key exchange algorithms");
3011+ }
3012+#endif
3013+
3014 /* start key exchange */
3015 kex = kex_setup(myproposal);
3016 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
3017@@ -2446,6 +2549,13 @@
3018 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
3019 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
3020 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
3021+#ifdef GSSAPI
3022+ if (options.gss_keyex) {
3023+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
3024+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
3025+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
3026+ }
3027+#endif
3028 kex->server = 1;
3029 kex->client_version_string=client_version_string;
3030 kex->server_version_string=server_version_string;
3031Index: b/sshd_config
3032===================================================================
3033--- a/sshd_config
3034+++ b/sshd_config
3035@@ -83,6 +83,8 @@
3036 # GSSAPI options
3037 #GSSAPIAuthentication no
3038 #GSSAPICleanupCredentials yes
3039+#GSSAPIStrictAcceptorCheck yes
3040+#GSSAPIKeyExchange no
3041
3042 # Set this to 'yes' to enable PAM authentication, account processing,
3043 # and session processing. If this is enabled, PAM authentication will
3044Index: b/sshd_config.5
3045===================================================================
3046--- a/sshd_config.5
3047+++ b/sshd_config.5
3048@@ -484,12 +484,40 @@
3049 The default is
3050 .Dq no .
3051 Note that this option applies to protocol version 2 only.
3052+.It Cm GSSAPIKeyExchange
3053+Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
3054+doesn't rely on ssh keys to verify host identity.
3055+The default is
3056+.Dq no .
3057+Note that this option applies to protocol version 2 only.
3058 .It Cm GSSAPICleanupCredentials
3059 Specifies whether to automatically destroy the user's credentials cache
3060 on logout.
3061 The default is
3062 .Dq yes .
3063 Note that this option applies to protocol version 2 only.
3064+.It Cm GSSAPIStrictAcceptorCheck
3065+Determines whether to be strict about the identity of the GSSAPI acceptor
3066+a client authenticates against. If
3067+.Dq yes
3068+then the client must authenticate against the
3069+.Pa host
3070+service on the current hostname. If
3071+.Dq no
3072+then the client may authenticate against any service key stored in the
3073+machine's default store. This facility is provided to assist with operation
3074+on multi homed machines.
3075+The default is
3076+.Dq yes .
3077+Note that this option applies only to protocol version 2 GSSAPI connections,
3078+and setting it to
3079+.Dq no
3080+may only work with recent Kerberos GSSAPI libraries.
3081+.It Cm GSSAPIStoreCredentialsOnRekey
3082+Controls whether the user's GSSAPI credentials should be updated following a
3083+successful connection rekeying. This option can be used to accepted renewed
3084+or updated credentials from a compatible client. The default is
3085+.Dq no .
3086 .It Cm HostbasedAuthentication
3087 Specifies whether rhosts or /etc/hosts.equiv authentication together
3088 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..298e8e216
--- /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@@ -686,7 +686,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..a851a91bf
--- /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: 2013-09-14
16
17Index: b/readconf.c
18===================================================================
19--- a/readconf.c
20+++ b/readconf.c
21@@ -141,6 +141,7 @@
22 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
23 oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
24 oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown,
25+ oProtocolKeepAlives, oSetupTimeOut,
26 oIgnoredUnknownOption, oDeprecated, oUnsupported
27 } OpCodes;
28
29@@ -263,6 +264,8 @@
30 { "ipqos", oIPQoS },
31 { "requesttty", oRequestTTY },
32 { "ignoreunknown", oIgnoreUnknown },
33+ { "protocolkeepalives", oProtocolKeepAlives },
34+ { "setuptimeout", oSetupTimeOut },
35
36 { NULL, oBadOption }
37 };
38@@ -939,6 +942,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@@ -1404,8 +1409,13 @@
48 options->rekey_interval = 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@@ -136,8 +136,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@@ -1141,8 +1145,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@@ -1181,6 +1192,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@@ -1161,6 +1161,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..19ae33b22
--- /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: 2013-09-14
7
8Index: b/Makefile.in
9===================================================================
10--- a/Makefile.in
11+++ b/Makefile.in
12@@ -296,9 +296,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/mention-ssh-keygen-on-keychange.patch b/debian/patches/mention-ssh-keygen-on-keychange.patch
new file mode 100644
index 000000000..55c277031
--- /dev/null
+++ b/debian/patches/mention-ssh-keygen-on-keychange.patch
@@ -0,0 +1,33 @@
1Description: Mention ssh-keygen in ssh fingerprint changed warning
2Author: Scott Moser <smoser@ubuntu.com>
3Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1843
4Bug-Ubuntu: https://bugs.launchpad.net/bugs/686607
5Last-Update: 2013-09-14
6
7Index: b/sshconnect.c
8===================================================================
9--- a/sshconnect.c
10+++ b/sshconnect.c
11@@ -981,9 +981,12 @@
12 error("%s. This could either mean that", key_msg);
13 error("DNS SPOOFING is happening or the IP address for the host");
14 error("and its host key have changed at the same time.");
15- if (ip_status != HOST_NEW)
16+ if (ip_status != HOST_NEW) {
17 error("Offending key for IP in %s:%lu",
18 ip_found->file, ip_found->line);
19+ error(" remove with: ssh-keygen -f \"%s\" -R %s",
20+ ip_found->file, ip);
21+ }
22 }
23 /* The host key has changed. */
24 warn_changed_key(host_key);
25@@ -991,6 +994,8 @@
26 user_hostfiles[0]);
27 error("Offending %s key in %s:%lu", key_type(host_found->key),
28 host_found->file, host_found->line);
29+ error(" remove with: ssh-keygen -f \"%s\" -R %s",
30+ host_found->file, host);
31
32 /*
33 * If strict host key checking is in use, the user will have
diff --git a/debian/patches/openbsd-docs.patch b/debian/patches/openbsd-docs.patch
new file mode 100644
index 000000000..d4eeee6e8
--- /dev/null
+++ b/debian/patches/openbsd-docs.patch
@@ -0,0 +1,135 @@
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: 2013-09-14
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@@ -110,7 +110,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 .Sh SEE ALSO
32 .Xr ssh-keygen 1 ,
33Index: b/ssh-keygen.1
34===================================================================
35--- a/ssh-keygen.1
36+++ b/ssh-keygen.1
37@@ -171,9 +171,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@@ -219,9 +217,7 @@
49 For each of the key types (rsa1, rsa, dsa and ecdsa) for which host keys
50 do not exist, generate the host keys with the default key file path,
51 an empty passphrase, default bits for the key type, and default comment.
52-This is used by
53-.Pa /etc/rc
54-to generate new host keys.
55+This is used by system administration scripts to generate new host keys.
56 .It Fl a Ar trials
57 Specifies the number of primality tests to perform when screening DH-GEX
58 candidates using the
59@@ -605,7 +601,7 @@
60 Valid generator values are 2, 3, and 5.
61 .Pp
62 Screened DH groups may be installed in
63-.Pa /etc/moduli .
64+.Pa /etc/ssh/moduli .
65 It is important that this file contains moduli of a range of bit lengths and
66 that both ends of a connection share common moduli.
67 .Sh CERTIFICATES
68@@ -800,7 +796,7 @@
69 where the user wishes to log in using public key authentication.
70 There is no need to keep the contents of this file secret.
71 .Pp
72-.It Pa /etc/moduli
73+.It Pa /etc/ssh/moduli
74 Contains Diffie-Hellman groups used for DH-GEX.
75 The file format is described in
76 .Xr moduli 5 .
77Index: b/ssh.1
78===================================================================
79--- a/ssh.1
80+++ b/ssh.1
81@@ -756,6 +756,10 @@
82 but protocol 2 may use any.
83 The HISTORY section of
84 .Xr ssl 8
85+(on non-OpenBSD systems, see
86+.nh
87+http://www.openbsd.org/cgi\-bin/man.cgi?query=ssl&sektion=8#HISTORY)
88+.hy
89 contains a brief discussion of the DSA and RSA algorithms.
90 .Pp
91 The file
92Index: b/sshd.8
93===================================================================
94--- a/sshd.8
95+++ b/sshd.8
96@@ -70,7 +70,7 @@
97 .Nm
98 listens for connections from clients.
99 It is normally started at boot from
100-.Pa /etc/rc .
101+.Pa /etc/init.d/ssh .
102 It forks a new
103 daemon for each incoming connection.
104 The forked daemons handle
105@@ -859,7 +859,7 @@
106 .Xr ssh 1 ) .
107 It should only be writable by root.
108 .Pp
109-.It Pa /etc/moduli
110+.It Pa /etc/ssh/moduli
111 Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange".
112 The file format is described in
113 .Xr moduli 5 .
114@@ -957,7 +957,6 @@
115 .Xr ssh-vulnkey 1 ,
116 .Xr chroot 2 ,
117 .Xr hosts_access 5 ,
118-.Xr login.conf 5 ,
119 .Xr moduli 5 ,
120 .Xr sshd_config 5 ,
121 .Xr inetd 8 ,
122Index: b/sshd_config.5
123===================================================================
124--- a/sshd_config.5
125+++ b/sshd_config.5
126@@ -283,8 +283,7 @@
127 By default, no banner is displayed.
128 .It Cm ChallengeResponseAuthentication
129 Specifies whether challenge-response authentication is allowed (e.g. via
130-PAM or though authentication styles supported in
131-.Xr login.conf 5 )
132+PAM).
133 The default is
134 .Dq yes .
135 .It Cm ChrootDirectory
diff --git a/debian/patches/package-versioning.patch b/debian/patches/package-versioning.patch
new file mode 100644
index 000000000..2be45ebf8
--- /dev/null
+++ b/debian/patches/package-versioning.patch
@@ -0,0 +1,54 @@
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: 2013-09-14
9
10Index: b/sshconnect.c
11===================================================================
12--- a/sshconnect.c
13+++ b/sshconnect.c
14@@ -442,10 +442,10 @@
15 /* Send our own protocol version identification. */
16 if (compat20) {
17 xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n",
18- PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION);
19+ PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE);
20 } else {
21 xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n",
22- PROTOCOL_MAJOR_1, minor1, SSH_VERSION);
23+ PROTOCOL_MAJOR_1, minor1, SSH_RELEASE);
24 }
25 if (roaming_atomicio(vwrite, connection_out, client_version_string,
26 strlen(client_version_string)) != strlen(client_version_string))
27Index: b/sshd.c
28===================================================================
29--- a/sshd.c
30+++ b/sshd.c
31@@ -440,7 +440,7 @@
32 }
33
34 xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s",
35- major, minor, SSH_VERSION,
36+ major, minor, SSH_RELEASE,
37 *options.version_addendum == '\0' ? "" : " ",
38 options.version_addendum, newline);
39
40Index: b/version.h
41===================================================================
42--- a/version.h
43+++ b/version.h
44@@ -3,4 +3,9 @@
45 #define SSH_VERSION "OpenSSH_6.3"
46
47 #define SSH_PORTABLE "p1"
48-#define SSH_RELEASE SSH_VERSION SSH_PORTABLE
49+#define SSH_RELEASE_MINIMUM SSH_VERSION SSH_PORTABLE
50+#ifdef SSH_EXTRAVERSION
51+#define SSH_RELEASE SSH_RELEASE_MINIMUM " " SSH_EXTRAVERSION
52+#else
53+#define SSH_RELEASE SSH_RELEASE_MINIMUM
54+#endif
diff --git a/debian/patches/quieter-signals.patch b/debian/patches/quieter-signals.patch
new file mode 100644
index 000000000..32f4cfc67
--- /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: 2013-09-14
14
15Index: b/clientloop.c
16===================================================================
17--- a/clientloop.c
18+++ b/clientloop.c
19@@ -1717,8 +1717,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-role.patch b/debian/patches/selinux-role.patch
new file mode 100644
index 000000000..f3376c20a
--- /dev/null
+++ b/debian/patches/selinux-role.patch
@@ -0,0 +1,479 @@
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: 2013-09-14
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 char *info; /* Extra info for next auth_log */
21 void *jpake_ctx;
22Index: b/auth1.c
23===================================================================
24--- a/auth1.c
25+++ b/auth1.c
26@@ -380,7 +380,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@@ -389,11 +389,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@@ -222,7 +222,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@@ -234,8 +234,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@@ -259,8 +264,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 if (auth2_setup_methods_lists(authctxt) != 0)
90 packet_disconnect("no authentication methods enabled");
91Index: b/monitor.c
92===================================================================
93--- a/monitor.c
94+++ b/monitor.c
95@@ -146,6 +146,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@@ -227,6 +228,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@@ -844,6 +846,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 #ifdef USE_PAM
119@@ -874,14 +877,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 free(authctxt->style);
131 authctxt->style = NULL;
132 }
133
134+ if (strlen(authctxt->role) == 0) {
135+ free(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+ free(authctxt->role);
153+ authctxt->role = NULL;
154+ }
155+
156 return (0);
157 }
158
159@@ -1486,7 +1512,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@@ -73,6 +73,8 @@
173 MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
174 MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
175
176+ MONITOR_REQ_AUTHROLE = 154,
177+
178 };
179
180 struct mm_master;
181Index: b/monitor_wrap.c
182===================================================================
183--- a/monitor_wrap.c
184+++ b/monitor_wrap.c
185@@ -320,10 +320,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@@ -332,11 +332,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@@ -41,7 +41,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@@ -58,7 +64,7 @@
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 = NULL;
267 char *sename = NULL, *lvl = NULL;
268@@ -73,9 +79,16 @@
269 #endif
270
271 #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
272- r = get_default_context_with_level(sename, lvl, NULL, &sc);
273+ if (role != NULL && role[0])
274+ r = get_default_context_with_rolelevel(sename, role, lvl, NULL,
275+ &sc);
276+ else
277+ r = get_default_context_with_level(sename, lvl, NULL, &sc);
278 #else
279- r = get_default_context(sename, NULL, &sc);
280+ if (role != NULL && role[0])
281+ r = get_default_context_with_role(sename, role, NULL, &sc);
282+ else
283+ r = get_default_context(sename, NULL, &sc);
284 #endif
285
286 if (r != 0) {
287@@ -105,7 +118,7 @@
288
289 /* Set the execution context to the default for the specified user */
290 void
291-ssh_selinux_setup_exec_context(char *pwname)
292+ssh_selinux_setup_exec_context(char *pwname, const char *role)
293 {
294 security_context_t user_ctx = NULL;
295
296@@ -114,7 +127,7 @@
297
298 debug3("%s: setting execution context", __func__);
299
300- user_ctx = ssh_selinux_getctxbyname(pwname);
301+ user_ctx = ssh_selinux_getctxbyname(pwname, role);
302 if (setexeccon(user_ctx) != 0) {
303 switch (security_getenforce()) {
304 case -1:
305@@ -136,7 +149,7 @@
306
307 /* Set the TTY context for the specified user */
308 void
309-ssh_selinux_setup_pty(char *pwname, const char *tty)
310+ssh_selinux_setup_pty(char *pwname, const char *tty, const char *role)
311 {
312 security_context_t new_tty_ctx = NULL;
313 security_context_t user_ctx = NULL;
314@@ -147,7 +160,7 @@
315
316 debug3("%s: setting TTY context on %s", __func__, tty);
317
318- user_ctx = ssh_selinux_getctxbyname(pwname);
319+ user_ctx = ssh_selinux_getctxbyname(pwname, role);
320
321 /* XXX: should these calls fatal() upon failure in enforcing mode? */
322
323Index: b/openbsd-compat/port-linux.h
324===================================================================
325--- a/openbsd-compat/port-linux.h
326+++ b/openbsd-compat/port-linux.h
327@@ -21,8 +21,8 @@
328
329 #ifdef WITH_SELINUX
330 int ssh_selinux_enabled(void);
331-void ssh_selinux_setup_pty(char *, const char *);
332-void ssh_selinux_setup_exec_context(char *);
333+void ssh_selinux_setup_pty(char *, const char *, const char *);
334+void ssh_selinux_setup_exec_context(char *, const char *);
335 void ssh_selinux_change_context(const char *);
336 void ssh_selinux_setfscreatecon(const char *);
337 #endif
338Index: b/platform.c
339===================================================================
340--- a/platform.c
341+++ b/platform.c
342@@ -134,7 +134,7 @@
343 * called if sshd is running as root.
344 */
345 void
346-platform_setusercontext_post_groups(struct passwd *pw)
347+platform_setusercontext_post_groups(struct passwd *pw, const char *role)
348 {
349 #if !defined(HAVE_LOGIN_CAP) && defined(USE_PAM)
350 /*
351@@ -181,7 +181,7 @@
352 }
353 #endif /* HAVE_SETPCRED */
354 #ifdef WITH_SELINUX
355- ssh_selinux_setup_exec_context(pw->pw_name);
356+ ssh_selinux_setup_exec_context(pw->pw_name, role);
357 #endif
358 }
359
360Index: b/platform.h
361===================================================================
362--- a/platform.h
363+++ b/platform.h
364@@ -26,7 +26,7 @@
365 void platform_post_fork_child(void);
366 int platform_privileged_uidswap(void);
367 void platform_setusercontext(struct passwd *);
368-void platform_setusercontext_post_groups(struct passwd *);
369+void platform_setusercontext_post_groups(struct passwd *, const char *);
370 char *platform_get_krb5_client(const char *);
371 char *platform_krb5_get_principal_name(const char *);
372 int platform_sys_dir_uid(uid_t);
373Index: b/session.c
374===================================================================
375--- a/session.c
376+++ b/session.c
377@@ -1474,7 +1474,7 @@
378
379 /* Set login name, uid, gid, and groups. */
380 void
381-do_setusercontext(struct passwd *pw)
382+do_setusercontext(struct passwd *pw, const char *role)
383 {
384 char *chroot_path, *tmp;
385
386@@ -1502,7 +1502,7 @@
387 endgrent();
388 #endif
389
390- platform_setusercontext_post_groups(pw);
391+ platform_setusercontext_post_groups(pw, role);
392
393 if (options.chroot_directory != NULL &&
394 strcasecmp(options.chroot_directory, "none") != 0) {
395@@ -1646,7 +1646,7 @@
396
397 /* Force a password change */
398 if (s->authctxt->force_pwchange) {
399- do_setusercontext(pw);
400+ do_setusercontext(pw, s->authctxt->role);
401 child_close_fds();
402 do_pwchange(s);
403 exit(1);
404@@ -1673,7 +1673,7 @@
405 /* When PAM is enabled we rely on it to do the nologin check */
406 if (!options.use_pam)
407 do_nologin(pw);
408- do_setusercontext(pw);
409+ do_setusercontext(pw, s->authctxt->role);
410 /*
411 * PAM session modules in do_setusercontext may have
412 * generated messages, so if this in an interactive
413@@ -2084,7 +2084,7 @@
414 tty_parse_modes(s->ttyfd, &n_bytes);
415
416 if (!use_privsep)
417- pty_setowner(s->pw, s->tty);
418+ pty_setowner(s->pw, s->tty, s->authctxt->role);
419
420 /* Set window size from the packet. */
421 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
422Index: b/session.h
423===================================================================
424--- a/session.h
425+++ b/session.h
426@@ -76,7 +76,7 @@
427 Session *session_new(void);
428 Session *session_by_tty(char *);
429 void session_close(Session *);
430-void do_setusercontext(struct passwd *);
431+void do_setusercontext(struct passwd *, const char *);
432 void child_set_env(char ***envp, u_int *envsizep, const char *name,
433 const char *value);
434
435Index: b/sshd.c
436===================================================================
437--- a/sshd.c
438+++ b/sshd.c
439@@ -753,7 +753,7 @@
440 RAND_seed(rnd, sizeof(rnd));
441
442 /* Drop privileges */
443- do_setusercontext(authctxt->pw);
444+ do_setusercontext(authctxt->pw, authctxt->role);
445
446 skip:
447 /* It is safe now to apply the key state */
448Index: b/sshpty.c
449===================================================================
450--- a/sshpty.c
451+++ b/sshpty.c
452@@ -200,7 +200,7 @@
453 }
454
455 void
456-pty_setowner(struct passwd *pw, const char *tty)
457+pty_setowner(struct passwd *pw, const char *tty, const char *role)
458 {
459 struct group *grp;
460 gid_t gid;
461@@ -227,7 +227,7 @@
462 strerror(errno));
463
464 #ifdef WITH_SELINUX
465- ssh_selinux_setup_pty(pw->pw_name, tty);
466+ ssh_selinux_setup_pty(pw->pw_name, tty, role);
467 #endif
468
469 if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
470Index: b/sshpty.h
471===================================================================
472--- a/sshpty.h
473+++ b/sshpty.h
474@@ -24,4 +24,4 @@
475 void pty_release(const char *);
476 void pty_make_controlling_tty(int *, const char *);
477 void pty_change_window_size(int, u_int, u_int, u_int, u_int);
478-void pty_setowner(struct passwd *, const char *);
479+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..f5c2ebb52
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,48 @@
1# GSSAPI
2gssapi.patch
3
4# SELinux
5selinux-role.patch
6
7# Key blacklisting
8ssh-vulnkey.patch
9
10# Keepalive handling
11ssh1-keepalive.patch
12keepalive-extensions.patch
13
14# Message adjustments
15syslog-level-silent.patch
16quieter-signals.patch
17helpful-wait-terminate.patch
18
19# ConsoleKit
20consolekit.patch
21
22# Miscellaneous bug fixes
23user-group-modes.patch
24scp-quoting.patch
25shell-path.patch
26dnssec-sshfp.patch
27auth-log-verbosity.patch
28mention-ssh-keygen-on-keychange.patch
29
30# Versioning
31package-versioning.patch
32debian-banner.patch
33
34# File system layout
35authorized-keys-man-symlink.patch
36lintian-symlink-pickiness.patch
37
38# Documentation
39openbsd-docs.patch
40ssh-argv0.patch
41doc-hash-tab-completion.patch
42doc-upstart.patch
43ssh-agent-setgid.patch
44
45# Debian-specific configuration
46gnome-ssh-askpass2-icon.patch
47sigstop.patch
48debian-config.patch
diff --git a/debian/patches/shell-path.patch b/debian/patches/shell-path.patch
new file mode 100644
index 000000000..a1c6efc8d
--- /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: 2013-09-14
8
9Index: b/sshconnect.c
10===================================================================
11--- a/sshconnect.c
12+++ b/sshconnect.c
13@@ -151,7 +151,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@@ -1298,7 +1298,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/sigstop.patch b/debian/patches/sigstop.patch
new file mode 100644
index 000000000..3311a797c
--- /dev/null
+++ b/debian/patches/sigstop.patch
@@ -0,0 +1,20 @@
1Description: Support synchronisation with service supervisor using SIGSTOP
2Author: Colin Watson <cjwatson@debian.org>
3Forwarded: no
4Last-Update: 2013-09-14
5
6Index: b/sshd.c
7===================================================================
8--- a/sshd.c
9+++ b/sshd.c
10@@ -1914,6 +1914,10 @@
11 }
12 }
13
14+ if (getenv("SSH_SIGSTOP"))
15+ /* Tell service supervisor that we are ready. */
16+ kill(getpid(), SIGSTOP);
17+
18 /* Accept a connection and return in a forked child */
19 server_accept_loop(&sock_in, &sock_out,
20 &newsock, config_s);
diff --git a/debian/patches/ssh-agent-setgid.patch b/debian/patches/ssh-agent-setgid.patch
new file mode 100644
index 000000000..7e909a165
--- /dev/null
+++ b/debian/patches/ssh-agent-setgid.patch
@@ -0,0 +1,32 @@
1Description: Document consequences of ssh-agent being setgid in ssh-agent(1)
2Author: Colin Watson <cjwatson@debian.org>
3Bug-Debian: http://bugs.debian.org/711623
4Forwarded: no
5Last-Update: 2013-06-08
6
7Index: b/ssh-agent.1
8===================================================================
9--- a/ssh-agent.1
10+++ b/ssh-agent.1
11@@ -182,6 +182,21 @@
12 .Pp
13 The agent exits automatically when the command given on the command
14 line terminates.
15+.Pp
16+In Debian,
17+.Nm
18+is installed with the set-group-id bit set, to prevent
19+.Xr ptrace 2
20+attacks retrieving private key material.
21+This has the side-effect of causing the run-time linker to remove certain
22+environment variables which might have security implications for set-id
23+programs, including
24+.Ev LD_PRELOAD ,
25+.Ev LD_LIBRARY_PATH ,
26+and
27+.Ev TMPDIR .
28+If you need to set any of these environment variables, you will need to do
29+so in the program executed by ssh-agent.
30 .Sh FILES
31 .Bl -tag -width Ds
32 .It Pa ~/.ssh/identity
diff --git a/debian/patches/ssh-argv0.patch b/debian/patches/ssh-argv0.patch
new file mode 100644
index 000000000..28d144221
--- /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: 2013-09-14
9
10Index: b/ssh.1
11===================================================================
12--- a/ssh.1
13+++ b/ssh.1
14@@ -1451,6 +1451,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..a56911290
--- /dev/null
+++ b/debian/patches/ssh-vulnkey.patch
@@ -0,0 +1,1382 @@
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: 2013-09-14
12
13Index: b/Makefile.in
14===================================================================
15--- a/Makefile.in
16+++ b/Makefile.in
17@@ -26,6 +26,7 @@
18 SFTP_SERVER=$(libexecdir)/sftp-server
19 SSH_KEYSIGN=$(libexecdir)/ssh-keysign
20 SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
21+SSH_DATADIR=$(datadir)/ssh
22 PRIVSEP_PATH=@PRIVSEP_PATH@
23 SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
24 STRIP_OPT=@STRIP_OPT@
25@@ -37,7 +38,8 @@
26 -D_PATH_SSH_KEY_SIGN=\"$(SSH_KEYSIGN)\" \
27 -D_PATH_SSH_PKCS11_HELPER=\"$(SSH_PKCS11_HELPER)\" \
28 -D_PATH_SSH_PIDDIR=\"$(piddir)\" \
29- -D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\"
30+ -D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\" \
31+ -D_PATH_SSH_DATADIR=\"$(SSH_DATADIR)\"
32
33 CC=@CC@
34 LD=@LD@
35@@ -61,7 +63,7 @@
36 EXEEXT=@EXEEXT@
37 MANFMT=@MANFMT@
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) 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) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-vulnkey$(EXEEXT)
41
42 LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \
43 canohost.o channels.o cipher.o cipher-aes.o \
44@@ -96,8 +98,8 @@
45 sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
46 sandbox-seccomp-filter.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-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-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-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-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@@ -176,6 +178,9 @@
56 sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o
57 $(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT)
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@@ -286,6 +292,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@@ -367,6 +374,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@@ -379,6 +387,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/sftp-server.8
96 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.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@@ -237,7 +237,7 @@
115 free(fp);
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@@ -657,10 +658,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+ free(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+ free(key_fp);
164+ return 1;
165+ }
166+ }
167+
168 if (options.revoked_keys_file == NULL)
169 return 0;
170 switch (ssh_krl_file_contains_key(options.revoked_keys_file, key)) {
171Index: b/auth.h
172===================================================================
173--- a/auth.h
174+++ b/auth.h
175@@ -191,7 +191,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@@ -150,7 +150,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@@ -647,9 +647,10 @@
202 u_int success, i;
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 #define MAX_KEY_FILE_SIZE (1024 * 1024)
225
226@@ -944,3 +945,139 @@
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+ free(dgst_packed);
320+ if (ret != 1 && dgst_hex) {
321+ free(dgst_hex);
322+ dgst_hex = NULL;
323+ }
324+ if (fp)
325+ *fp = dgst_hex;
326+ if (fd >= 0)
327+ close(fd);
328+ return ret;
329+}
330+
331+/*
332+ * Scan blacklists of known-vulnerable keys. If a vulnerable key is found,
333+ * its fingerprint is returned in *fp, unless fp is NULL.
334+ */
335+int
336+blacklisted_key(Key *key, char **fp)
337+{
338+ Key *public;
339+ char *blacklist_file;
340+ int ret, ret2;
341+
342+ public = key_demote(key);
343+ if (public->type == KEY_RSA1)
344+ public->type = KEY_RSA;
345+
346+ xasprintf(&blacklist_file, "%s.%s-%u",
347+ _PATH_BLACKLIST, key_type(public), key_size(public));
348+ ret = blacklisted_key_in_file(public, blacklist_file, fp);
349+ free(blacklist_file);
350+ if (ret > 0) {
351+ key_free(public);
352+ return ret;
353+ }
354+
355+ xasprintf(&blacklist_file, "%s.%s-%u",
356+ _PATH_BLACKLIST_CONFIG, key_type(public), key_size(public));
357+ ret2 = blacklisted_key_in_file(public, blacklist_file, fp);
358+ free(blacklist_file);
359+ if (ret2 > ret)
360+ ret = ret2;
361+
362+ key_free(public);
363+ return ret;
364+}
365+
366Index: b/authfile.h
367===================================================================
368--- a/authfile.h
369+++ b/authfile.h
370@@ -28,4 +28,6 @@
371 int key_perm_ok(int, const char *);
372 int key_in_file(Key *, const char *, int);
373
374+int blacklisted_key(Key *key, char **fp);
375+
376 #endif
377Index: b/pathnames.h
378===================================================================
379--- a/pathnames.h
380+++ b/pathnames.h
381@@ -18,6 +18,10 @@
382 #define SSHDIR ETCDIR "/ssh"
383 #endif
384
385+#ifndef _PATH_SSH_DATADIR
386+#define _PATH_SSH_DATADIR "/usr/share/ssh"
387+#endif
388+
389 #ifndef _PATH_SSH_PIDDIR
390 #define _PATH_SSH_PIDDIR "/var/run"
391 #endif
392@@ -44,6 +48,9 @@
393 /* Backwards compatibility */
394 #define _PATH_DH_PRIMES SSHDIR "/primes"
395
396+#define _PATH_BLACKLIST _PATH_SSH_DATADIR "/blacklist"
397+#define _PATH_BLACKLIST_CONFIG SSHDIR "/blacklist"
398+
399 #ifndef _PATH_SSH_PROGRAM
400 #define _PATH_SSH_PROGRAM "/usr/bin/ssh"
401 #endif
402Index: b/readconf.c
403===================================================================
404--- a/readconf.c
405+++ b/readconf.c
406@@ -128,6 +128,7 @@
407 oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
408 oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
409 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
410+ oUseBlacklistedKeys,
411 oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
412 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
413 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
414@@ -161,6 +162,7 @@
415 { "passwordauthentication", oPasswordAuthentication },
416 { "kbdinteractiveauthentication", oKbdInteractiveAuthentication },
417 { "kbdinteractivedevices", oKbdInteractiveDevices },
418+ { "useblacklistedkeys", oUseBlacklistedKeys },
419 { "rsaauthentication", oRSAAuthentication },
420 { "pubkeyauthentication", oPubkeyAuthentication },
421 { "dsaauthentication", oPubkeyAuthentication }, /* alias */
422@@ -523,6 +525,10 @@
423 intptr = &options->challenge_response_authentication;
424 goto parse_flag;
425
426+ case oUseBlacklistedKeys:
427+ intptr = &options->use_blacklisted_keys;
428+ goto parse_flag;
429+
430 case oGssAuthentication:
431 intptr = &options->gss_authentication;
432 goto parse_flag;
433@@ -1210,6 +1216,7 @@
434 options->kbd_interactive_devices = NULL;
435 options->rhosts_rsa_authentication = -1;
436 options->hostbased_authentication = -1;
437+ options->use_blacklisted_keys = -1;
438 options->batch_mode = -1;
439 options->check_host_ip = -1;
440 options->strict_host_key_checking = -1;
441@@ -1320,6 +1327,8 @@
442 options->rhosts_rsa_authentication = 0;
443 if (options->hostbased_authentication == -1)
444 options->hostbased_authentication = 0;
445+ if (options->use_blacklisted_keys == -1)
446+ options->use_blacklisted_keys = 0;
447 if (options->batch_mode == -1)
448 options->batch_mode = 0;
449 if (options->check_host_ip == -1)
450Index: b/readconf.h
451===================================================================
452--- a/readconf.h
453+++ b/readconf.h
454@@ -59,6 +59,7 @@
455 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
456 char *kbd_interactive_devices; /* Keyboard-interactive auth devices. */
457 int zero_knowledge_password_authentication; /* Try jpake */
458+ int use_blacklisted_keys; /* If true, send */
459 int batch_mode; /* Batch mode: do not ask for passwords. */
460 int check_host_ip; /* Also keep track of keys for IP address */
461 int strict_host_key_checking; /* Strict host key checking. */
462Index: b/servconf.c
463===================================================================
464--- a/servconf.c
465+++ b/servconf.c
466@@ -114,6 +114,7 @@
467 options->password_authentication = -1;
468 options->kbd_interactive_authentication = -1;
469 options->challenge_response_authentication = -1;
470+ options->permit_blacklisted_keys = -1;
471 options->permit_empty_passwd = -1;
472 options->permit_user_env = -1;
473 options->use_login = -1;
474@@ -257,6 +258,8 @@
475 options->kbd_interactive_authentication = 0;
476 if (options->challenge_response_authentication == -1)
477 options->challenge_response_authentication = 1;
478+ if (options->permit_blacklisted_keys == -1)
479+ options->permit_blacklisted_keys = 0;
480 if (options->permit_empty_passwd == -1)
481 options->permit_empty_passwd = 0;
482 if (options->permit_user_env == -1)
483@@ -338,7 +341,7 @@
484 sListenAddress, sAddressFamily,
485 sPrintMotd, sPrintLastLog, sIgnoreRhosts,
486 sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
487- sStrictModes, sEmptyPasswd, sTCPKeepAlive,
488+ sStrictModes, sPermitBlacklistedKeys, sEmptyPasswd, sTCPKeepAlive,
489 sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
490 sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
491 sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
492@@ -451,6 +454,7 @@
493 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
494 { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
495 { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
496+ { "permitblacklistedkeys", sPermitBlacklistedKeys, SSHCFG_GLOBAL },
497 { "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
498 { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
499 { "uselogin", sUseLogin, SSHCFG_GLOBAL },
500@@ -1158,6 +1162,10 @@
501 intptr = &options->tcp_keep_alive;
502 goto parse_flag;
503
504+ case sPermitBlacklistedKeys:
505+ intptr = &options->permit_blacklisted_keys;
506+ goto parse_flag;
507+
508 case sEmptyPasswd:
509 intptr = &options->permit_empty_passwd;
510 goto parse_flag;
511@@ -2036,6 +2044,7 @@
512 dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
513 dump_cfg_fmtint(sStrictModes, o->strict_modes);
514 dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
515+ dump_cfg_fmtint(sPermitBlacklistedKeys, o->permit_blacklisted_keys);
516 dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
517 dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
518 dump_cfg_fmtint(sUseLogin, o->use_login);
519Index: b/servconf.h
520===================================================================
521--- a/servconf.h
522+++ b/servconf.h
523@@ -121,6 +121,7 @@
524 int challenge_response_authentication;
525 int zero_knowledge_password_authentication;
526 /* If true, permit jpake auth */
527+ int permit_blacklisted_keys; /* If true, permit */
528 int permit_empty_passwd; /* If false, do not permit empty
529 * passwords. */
530 int permit_user_env; /* If true, read ~/.ssh/environment */
531Index: b/ssh-add.1
532===================================================================
533--- a/ssh-add.1
534+++ b/ssh-add.1
535@@ -81,6 +81,10 @@
536 .Nm
537 to work.
538 .Pp
539+Any keys recorded in the blacklist of known-compromised keys (see
540+.Xr ssh-vulnkey 1 )
541+will be refused.
542+.Pp
543 The options are as follows:
544 .Bl -tag -width Ds
545 .It Fl c
546@@ -186,6 +190,7 @@
547 .Xr ssh 1 ,
548 .Xr ssh-agent 1 ,
549 .Xr ssh-keygen 1 ,
550+.Xr ssh-vulnkey 1 ,
551 .Xr sshd 8
552 .Sh AUTHORS
553 OpenSSH is a derivative of the original and free
554Index: b/ssh-add.c
555===================================================================
556--- a/ssh-add.c
557+++ b/ssh-add.c
558@@ -167,7 +167,7 @@
559 add_file(AuthenticationConnection *ac, const char *filename, int key_only)
560 {
561 Key *private, *cert;
562- char *comment = NULL;
563+ char *comment = NULL, *fp;
564 char msg[1024], *certpath = NULL;
565 int fd, perms_ok, ret = -1;
566 Buffer keyblob;
567@@ -243,6 +243,14 @@
568 } else {
569 fprintf(stderr, "Could not add identity: %s\n", filename);
570 }
571+ if (blacklisted_key(private, &fp) == 1) {
572+ fprintf(stderr, "Public key %s blacklisted (see "
573+ "ssh-vulnkey(1)); refusing to add it\n", fp);
574+ free(fp);
575+ key_free(private);
576+ free(comment);
577+ return -1;
578+ }
579
580 /* Skip trying to load the cert if requested */
581 if (key_only)
582Index: b/ssh-keygen.1
583===================================================================
584--- a/ssh-keygen.1
585+++ b/ssh-keygen.1
586@@ -809,6 +809,7 @@
587 .Xr ssh 1 ,
588 .Xr ssh-add 1 ,
589 .Xr ssh-agent 1 ,
590+.Xr ssh-vulnkey 1 ,
591 .Xr moduli 5 ,
592 .Xr sshd 8
593 .Rs
594Index: b/ssh-vulnkey.1
595===================================================================
596--- /dev/null
597+++ b/ssh-vulnkey.1
598@@ -0,0 +1,242 @@
599+.\" Copyright (c) 2008 Canonical Ltd. All rights reserved.
600+.\"
601+.\" Redistribution and use in source and binary forms, with or without
602+.\" modification, are permitted provided that the following conditions
603+.\" are met:
604+.\" 1. Redistributions of source code must retain the above copyright
605+.\" notice, this list of conditions and the following disclaimer.
606+.\" 2. Redistributions in binary form must reproduce the above copyright
607+.\" notice, this list of conditions and the following disclaimer in the
608+.\" documentation and/or other materials provided with the distribution.
609+.\"
610+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
611+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
612+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
613+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
614+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
615+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
616+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
617+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
618+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
619+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
620+.\"
621+.Dd $Mdocdate: May 12 2008 $
622+.Dt SSH-VULNKEY 1
623+.Os
624+.Sh NAME
625+.Nm ssh-vulnkey
626+.Nd check blacklist of compromised keys
627+.Sh SYNOPSIS
628+.Nm
629+.Op Fl q | Fl v
630+.Ar file ...
631+.Nm
632+.Fl a
633+.Sh DESCRIPTION
634+.Nm
635+checks a key against a blacklist of compromised keys.
636+.Pp
637+A substantial number of keys are known to have been generated using a broken
638+version of OpenSSL distributed by Debian which failed to seed its random
639+number generator correctly.
640+Keys generated using these OpenSSL versions should be assumed to be
641+compromised.
642+This tool may be useful in checking for such keys.
643+.Pp
644+Keys that are compromised cannot be repaired; replacements must be generated
645+using
646+.Xr ssh-keygen 1 .
647+Make sure to update
648+.Pa authorized_keys
649+files on all systems where compromised keys were permitted to authenticate.
650+.Pp
651+The argument list will be interpreted as a list of paths to public key files
652+or
653+.Pa authorized_keys
654+files.
655+If no suitable file is found at a given path,
656+.Nm
657+will append
658+.Pa .pub
659+and retry, in case it was given a private key file.
660+If no files are given as arguments,
661+.Nm
662+will check
663+.Pa ~/.ssh/id_rsa ,
664+.Pa ~/.ssh/id_dsa ,
665+.Pa ~/.ssh/identity ,
666+.Pa ~/.ssh/authorized_keys
667+and
668+.Pa ~/.ssh/authorized_keys2 ,
669+as well as the system's host keys if readable.
670+.Pp
671+If
672+.Dq -
673+is given as an argument,
674+.Nm
675+will read from standard input.
676+This can be used to process output from
677+.Xr ssh-keyscan 1 ,
678+for example:
679+.Pp
680+.Dl $ ssh-keyscan -t rsa remote.example.org | ssh-vulnkey -
681+.Pp
682+Unless the
683+.Cm PermitBlacklistedKeys
684+option is used,
685+.Xr sshd 8
686+will reject attempts to authenticate with keys in the compromised list.
687+.Pp
688+The output from
689+.Nm
690+looks like this:
691+.Pp
692+.Bd -literal -offset indent
693+/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
694+/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
695+/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
696+.Ed
697+.Pp
698+Each line is of the following format (any lines beginning with
699+.Dq #
700+should be ignored by scripts):
701+.Pp
702+.Dl Ar filename : Ns Ar line : Ar status : Ar type Ar size Ar fingerprint Ar comment
703+.Pp
704+It is important to distinguish between the possible values of
705+.Ar status :
706+.Pp
707+.Bl -tag -width Ds
708+.It COMPROMISED
709+These keys are listed in a blacklist file, normally because their
710+corresponding private keys are well-known.
711+Replacements must be generated using
712+.Xr ssh-keygen 1 .
713+.It Not blacklisted
714+A blacklist file exists for this key type and size, but this key is not
715+listed in it.
716+Unless there is some particular reason to believe otherwise, this key
717+may be used safely.
718+(Note that DSA keys used with the broken version of OpenSSL distributed
719+by Debian may be compromised in the event that anyone captured a network
720+trace, even if they were generated with a secure version of OpenSSL.)
721+.It Unknown (blacklist file not installed)
722+No blacklist file exists for this key type and size.
723+You should find a suitable published blacklist and install it before
724+deciding whether this key is safe to use.
725+.El
726+.Pp
727+The options are as follows:
728+.Bl -tag -width Ds
729+.It Fl a
730+Check keys of all users on the system.
731+You will typically need to run
732+.Nm
733+as root to use this option.
734+For each user,
735+.Nm
736+will check
737+.Pa ~/.ssh/id_rsa ,
738+.Pa ~/.ssh/id_dsa ,
739+.Pa ~/.ssh/identity ,
740+.Pa ~/.ssh/authorized_keys
741+and
742+.Pa ~/.ssh/authorized_keys2 .
743+It will also check the system's host keys.
744+.It Fl q
745+Quiet mode.
746+Normally,
747+.Nm
748+outputs the fingerprint of each key scanned, with a description of its
749+status.
750+This option suppresses that output.
751+.It Fl v
752+Verbose mode.
753+Normally,
754+.Nm
755+does not output anything for keys that are not listed in their corresponding
756+blacklist file (although it still produces output for keys for which there
757+is no blacklist file, since their status is unknown).
758+This option causes
759+.Nm
760+to produce output for all keys.
761+.El
762+.Sh EXIT STATUS
763+.Nm
764+will exit zero if any of the given keys were in the compromised list,
765+otherwise non-zero.
766+.Sh BLACKLIST FILE FORMAT
767+The blacklist file may start with comments, on lines starting with
768+.Dq # .
769+After these initial comments, it must follow a strict format:
770+.Pp
771+.Bl -bullet -offset indent -compact
772+.It
773+All the lines must be exactly the same length (20 characters followed by a
774+newline) and must be in sorted order.
775+.It
776+Each line must consist of the lower-case hexadecimal MD5 key fingerprint,
777+without colons, and with the first 12 characters removed (that is, the least
778+significant 80 bits of the fingerprint).
779+.El
780+.Pp
781+The key fingerprint may be generated using
782+.Xr ssh-keygen 1 :
783+.Pp
784+.Dl $ ssh-keygen -l -f /path/to/key
785+.Pp
786+This strict format is necessary to allow the blacklist file to be checked
787+quickly, using a binary-search algorithm.
788+.Sh FILES
789+.Bl -tag -width Ds
790+.It Pa ~/.ssh/id_rsa
791+If present, contains the protocol version 2 RSA authentication identity of
792+the user.
793+.It Pa ~/.ssh/id_dsa
794+If present, contains the protocol version 2 DSA authentication identity of
795+the user.
796+.It Pa ~/.ssh/identity
797+If present, contains the protocol version 1 RSA authentication identity of
798+the user.
799+.It Pa ~/.ssh/authorized_keys
800+If present, lists the public keys (RSA/DSA) that can be used for logging in
801+as this user.
802+.It Pa ~/.ssh/authorized_keys2
803+Obsolete name for
804+.Pa ~/.ssh/authorized_keys .
805+This file may still be present on some old systems, but should not be
806+created if it is missing.
807+.It Pa /etc/ssh/ssh_host_rsa_key
808+If present, contains the protocol version 2 RSA identity of the system.
809+.It Pa /etc/ssh/ssh_host_dsa_key
810+If present, contains the protocol version 2 DSA identity of the system.
811+.It Pa /etc/ssh/ssh_host_key
812+If present, contains the protocol version 1 RSA identity of the system.
813+.It Pa /usr/share/ssh/blacklist. Ns Ar TYPE Ns Pa - Ns Ar LENGTH
814+If present, lists the blacklisted keys of type
815+.Ar TYPE
816+.Pf ( Dq RSA
817+or
818+.Dq DSA )
819+and bit length
820+.Ar LENGTH .
821+The format of this file is described above.
822+RSA1 keys are converted to RSA before being checked in the blacklist.
823+Note that the fingerprints of RSA1 keys are computed differently, so you
824+will not be able to find them in the blacklist by hand.
825+.It Pa /etc/ssh/blacklist. Ns Ar TYPE Ns Pa - Ns Ar LENGTH
826+Same as
827+.Pa /usr/share/ssh/blacklist. Ns Ar TYPE Ns Pa - Ns Ar LENGTH ,
828+but may be edited by the system administrator to add new blacklist entries.
829+.El
830+.Sh SEE ALSO
831+.Xr ssh-keygen 1 ,
832+.Xr sshd 8
833+.Sh AUTHORS
834+.An -nosplit
835+.An Colin Watson Aq cjwatson@ubuntu.com
836+.Pp
837+Florian Weimer suggested the option to check keys of all users, and the idea
838+of processing
839+.Xr ssh-keyscan 1
840+output.
841Index: b/ssh-vulnkey.c
842===================================================================
843--- /dev/null
844+++ b/ssh-vulnkey.c
845@@ -0,0 +1,386 @@
846+/*
847+ * Copyright (c) 2008 Canonical Ltd. All rights reserved.
848+ *
849+ * Redistribution and use in source and binary forms, with or without
850+ * modification, are permitted provided that the following conditions
851+ * are met:
852+ * 1. Redistributions of source code must retain the above copyright
853+ * notice, this list of conditions and the following disclaimer.
854+ * 2. Redistributions in binary form must reproduce the above copyright
855+ * notice, this list of conditions and the following disclaimer in the
856+ * documentation and/or other materials provided with the distribution.
857+ *
858+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
859+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
860+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
861+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
862+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
863+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
864+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
865+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
866+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
867+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
868+ */
869+
870+#include "includes.h"
871+
872+#include <sys/types.h>
873+#include <sys/stat.h>
874+
875+#include <errno.h>
876+#include <string.h>
877+#include <stdio.h>
878+#include <fcntl.h>
879+#include <unistd.h>
880+
881+#include <openssl/evp.h>
882+
883+#include "xmalloc.h"
884+#include "ssh.h"
885+#include "log.h"
886+#include "key.h"
887+#include "authfile.h"
888+#include "pathnames.h"
889+#include "uidswap.h"
890+#include "misc.h"
891+
892+extern char *__progname;
893+
894+/* Default files to check */
895+static char *default_host_files[] = {
896+ _PATH_HOST_RSA_KEY_FILE,
897+ _PATH_HOST_DSA_KEY_FILE,
898+ _PATH_HOST_KEY_FILE,
899+ NULL
900+};
901+static char *default_files[] = {
902+ _PATH_SSH_CLIENT_ID_RSA,
903+ _PATH_SSH_CLIENT_ID_DSA,
904+ _PATH_SSH_CLIENT_IDENTITY,
905+ _PATH_SSH_USER_PERMITTED_KEYS,
906+ _PATH_SSH_USER_PERMITTED_KEYS2,
907+ NULL
908+};
909+
910+static int verbosity = 0;
911+
912+static int some_keys = 0;
913+static int some_unknown = 0;
914+static int some_compromised = 0;
915+
916+static void
917+usage(void)
918+{
919+ fprintf(stderr, "usage: %s [-aqv] [file ...]\n", __progname);
920+ fprintf(stderr, "Options:\n");
921+ fprintf(stderr, " -a Check keys of all users.\n");
922+ fprintf(stderr, " -q Quiet mode.\n");
923+ fprintf(stderr, " -v Verbose mode.\n");
924+ exit(1);
925+}
926+
927+static void
928+describe_key(const char *filename, u_long linenum, const char *msg,
929+ Key *key, const char *comment, int min_verbosity)
930+{
931+ char *fp;
932+
933+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
934+ if (verbosity >= min_verbosity) {
935+ if (strchr(filename, ':'))
936+ printf("\"%s\"", filename);
937+ else
938+ printf("%s", filename);
939+ printf(":%lu: %s: %s %u %s %s\n", linenum, msg,
940+ key_type(key), key_size(key), fp, comment);
941+ }
942+ free(fp);
943+}
944+
945+static int
946+do_key(const char *filename, u_long linenum,
947+ Key *key, const char *comment)
948+{
949+ Key *public;
950+ int blacklist_status;
951+ int ret = 1;
952+
953+ some_keys = 1;
954+
955+ public = key_demote(key);
956+ if (public->type == KEY_RSA1)
957+ public->type = KEY_RSA;
958+
959+ blacklist_status = blacklisted_key(public, NULL);
960+ if (blacklist_status == -1) {
961+ describe_key(filename, linenum,
962+ "Unknown (blacklist file not installed)", key, comment, 0);
963+ some_unknown = 1;
964+ } else if (blacklist_status == 1) {
965+ describe_key(filename, linenum,
966+ "COMPROMISED", key, comment, 0);
967+ some_compromised = 1;
968+ ret = 0;
969+ } else
970+ describe_key(filename, linenum,
971+ "Not blacklisted", key, comment, 1);
972+
973+ key_free(public);
974+
975+ return ret;
976+}
977+
978+static int
979+do_filename(const char *filename, int quiet_open)
980+{
981+ FILE *f;
982+ char line[SSH_MAX_PUBKEY_BYTES];
983+ char *cp;
984+ u_long linenum = 0;
985+ Key *key;
986+ char *comment = NULL;
987+ int found = 0, ret = 1;
988+
989+ /* Copy much of key_load_public's logic here so that we can read
990+ * several keys from a single file (e.g. authorized_keys).
991+ */
992+
993+ if (strcmp(filename, "-") != 0) {
994+ int save_errno;
995+ f = fopen(filename, "r");
996+ save_errno = errno;
997+ if (!f) {
998+ char pubfile[MAXPATHLEN];
999+ if (strlcpy(pubfile, filename, sizeof pubfile) <
1000+ sizeof(pubfile) &&
1001+ strlcat(pubfile, ".pub", sizeof pubfile) <
1002+ sizeof(pubfile))
1003+ f = fopen(pubfile, "r");
1004+ }
1005+ errno = save_errno; /* earlier errno is more useful */
1006+ if (!f) {
1007+ if (!quiet_open)
1008+ perror(filename);
1009+ return -1;
1010+ }
1011+ if (verbosity > 0)
1012+ printf("# %s\n", filename);
1013+ } else
1014+ f = stdin;
1015+ while (read_keyfile_line(f, filename, line, sizeof(line),
1016+ &linenum) != -1) {
1017+ int i;
1018+ char *space;
1019+ int type;
1020+ char *end;
1021+
1022+ /* Chop trailing newline. */
1023+ i = strlen(line) - 1;
1024+ if (line[i] == '\n')
1025+ line[i] = '\0';
1026+
1027+ /* Skip leading whitespace, empty and comment lines. */
1028+ for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
1029+ ;
1030+ if (!*cp || *cp == '\n' || *cp == '#')
1031+ continue;
1032+
1033+ /* Cope with ssh-keyscan output and options in
1034+ * authorized_keys files.
1035+ */
1036+ space = strchr(cp, ' ');
1037+ if (!space)
1038+ continue;
1039+ *space = '\0';
1040+ type = key_type_from_name(cp);
1041+ *space = ' ';
1042+ /* Leading number (RSA1) or valid type (RSA/DSA) indicates
1043+ * that we have no host name or options to skip.
1044+ */
1045+ if ((strtol(cp, &end, 10) == 0 || *end != ' ') &&
1046+ type == KEY_UNSPEC) {
1047+ int quoted = 0;
1048+
1049+ for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
1050+ if (*cp == '\\' && cp[1] == '"')
1051+ cp++; /* Skip both */
1052+ else if (*cp == '"')
1053+ quoted = !quoted;
1054+ }
1055+ /* Skip remaining whitespace. */
1056+ for (; *cp == ' ' || *cp == '\t'; cp++)
1057+ ;
1058+ if (!*cp)
1059+ continue;
1060+ }
1061+
1062+ /* Read and process the key itself. */
1063+ key = key_new(KEY_RSA1);
1064+ if (key_read(key, &cp) == 1) {
1065+ while (*cp == ' ' || *cp == '\t')
1066+ cp++;
1067+ if (!do_key(filename, linenum,
1068+ key, *cp ? cp : filename))
1069+ ret = 0;
1070+ found = 1;
1071+ } else {
1072+ key_free(key);
1073+ key = key_new(KEY_UNSPEC);
1074+ if (key_read(key, &cp) == 1) {
1075+ while (*cp == ' ' || *cp == '\t')
1076+ cp++;
1077+ if (!do_key(filename, linenum,
1078+ key, *cp ? cp : filename))
1079+ ret = 0;
1080+ found = 1;
1081+ }
1082+ }
1083+ key_free(key);
1084+ }
1085+ if (f != stdin)
1086+ fclose(f);
1087+
1088+ if (!found && filename) {
1089+ key = key_load_public(filename, &comment);
1090+ if (key) {
1091+ if (!do_key(filename, 1, key, comment))
1092+ ret = 0;
1093+ found = 1;
1094+ }
1095+ free(comment);
1096+ }
1097+
1098+ return ret;
1099+}
1100+
1101+static int
1102+do_host(int quiet_open)
1103+{
1104+ int i;
1105+ struct stat st;
1106+ int ret = 1;
1107+
1108+ for (i = 0; default_host_files[i]; i++) {
1109+ if (stat(default_host_files[i], &st) < 0 && errno == ENOENT)
1110+ continue;
1111+ if (!do_filename(default_host_files[i], quiet_open))
1112+ ret = 0;
1113+ }
1114+
1115+ return ret;
1116+}
1117+
1118+static int
1119+do_user(const char *dir)
1120+{
1121+ int i;
1122+ char *file;
1123+ struct stat st;
1124+ int ret = 1;
1125+
1126+ for (i = 0; default_files[i]; i++) {
1127+ xasprintf(&file, "%s/%s", dir, default_files[i]);
1128+ if (stat(file, &st) < 0 && errno == ENOENT) {
1129+ free(file);
1130+ continue;
1131+ }
1132+ if (!do_filename(file, 0))
1133+ ret = 0;
1134+ free(file);
1135+ }
1136+
1137+ return ret;
1138+}
1139+
1140+int
1141+main(int argc, char **argv)
1142+{
1143+ int opt, all_users = 0;
1144+ int ret = 1;
1145+ extern int optind;
1146+
1147+ /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1148+ sanitise_stdfd();
1149+
1150+ __progname = ssh_get_progname(argv[0]);
1151+
1152+ SSLeay_add_all_algorithms();
1153+ log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
1154+
1155+ /* We don't need the RNG ourselves, but symbol references here allow
1156+ * ld to link us properly.
1157+ */
1158+ seed_rng();
1159+
1160+ while ((opt = getopt(argc, argv, "ahqv")) != -1) {
1161+ switch (opt) {
1162+ case 'a':
1163+ all_users = 1;
1164+ break;
1165+ case 'q':
1166+ verbosity--;
1167+ break;
1168+ case 'v':
1169+ verbosity++;
1170+ break;
1171+ case 'h':
1172+ default:
1173+ usage();
1174+ }
1175+ }
1176+
1177+ if (all_users) {
1178+ struct passwd *pw;
1179+
1180+ if (!do_host(0))
1181+ ret = 0;
1182+
1183+ while ((pw = getpwent()) != NULL) {
1184+ if (pw->pw_dir) {
1185+ temporarily_use_uid(pw);
1186+ if (!do_user(pw->pw_dir))
1187+ ret = 0;
1188+ restore_uid();
1189+ }
1190+ }
1191+ } else if (optind == argc) {
1192+ struct passwd *pw;
1193+
1194+ if (!do_host(1))
1195+ ret = 0;
1196+
1197+ if ((pw = getpwuid(geteuid())) == NULL)
1198+ fprintf(stderr, "No user found with uid %u\n",
1199+ (u_int)geteuid());
1200+ else {
1201+ if (!do_user(pw->pw_dir))
1202+ ret = 0;
1203+ }
1204+ } else {
1205+ while (optind < argc)
1206+ if (!do_filename(argv[optind++], 0))
1207+ ret = 0;
1208+ }
1209+
1210+ if (verbosity >= 0) {
1211+ if (some_unknown) {
1212+ printf("#\n");
1213+ printf("# The status of some keys on your system is unknown.\n");
1214+ printf("# You may need to install additional blacklist files.\n");
1215+ }
1216+ if (some_compromised) {
1217+ printf("#\n");
1218+ printf("# Some keys on your system have been compromised!\n");
1219+ printf("# You must replace them using ssh-keygen(1).\n");
1220+ }
1221+ if (some_unknown || some_compromised) {
1222+ printf("#\n");
1223+ printf("# See the ssh-vulnkey(1) manual page for further advice.\n");
1224+ } else if (some_keys && verbosity > 0) {
1225+ printf("#\n");
1226+ printf("# No blacklisted keys!\n");
1227+ }
1228+ }
1229+
1230+ return ret;
1231+}
1232Index: b/ssh.1
1233===================================================================
1234--- a/ssh.1
1235+++ b/ssh.1
1236@@ -1447,6 +1447,7 @@
1237 .Xr ssh-agent 1 ,
1238 .Xr ssh-keygen 1 ,
1239 .Xr ssh-keyscan 1 ,
1240+.Xr ssh-vulnkey 1 ,
1241 .Xr tun 4 ,
1242 .Xr hosts.equiv 5 ,
1243 .Xr ssh_config 5 ,
1244Index: b/ssh.c
1245===================================================================
1246--- a/ssh.c
1247+++ b/ssh.c
1248@@ -1525,7 +1525,7 @@
1249 static void
1250 load_public_identity_files(void)
1251 {
1252- char *filename, *cp, thishost[NI_MAXHOST];
1253+ char *filename, *cp, thishost[NI_MAXHOST], *fp;
1254 char *pwdir = NULL, *pwname = NULL;
1255 int i = 0;
1256 Key *public;
1257@@ -1583,6 +1583,22 @@
1258 public = key_load_public(filename, NULL);
1259 debug("identity file %s type %d", filename,
1260 public ? public->type : -1);
1261+ if (public && blacklisted_key(public, &fp) == 1) {
1262+ if (options.use_blacklisted_keys)
1263+ logit("Public key %s blacklisted (see "
1264+ "ssh-vulnkey(1)); continuing anyway", fp);
1265+ else
1266+ logit("Public key %s blacklisted (see "
1267+ "ssh-vulnkey(1)); refusing to send it",
1268+ fp);
1269+ free(fp);
1270+ if (!options.use_blacklisted_keys) {
1271+ key_free(public);
1272+ free(filename);
1273+ filename = NULL;
1274+ public = NULL;
1275+ }
1276+ }
1277 free(options.identity_files[i]);
1278 identity_files[n_ids] = filename;
1279 identity_keys[n_ids] = public;
1280Index: b/ssh_config.5
1281===================================================================
1282--- a/ssh_config.5
1283+++ b/ssh_config.5
1284@@ -1229,6 +1229,23 @@
1285 .Dq any .
1286 The default is
1287 .Dq any:any .
1288+.It Cm UseBlacklistedKeys
1289+Specifies whether
1290+.Xr ssh 1
1291+should use keys recorded in its blacklist of known-compromised keys (see
1292+.Xr ssh-vulnkey 1 )
1293+for authentication.
1294+If
1295+.Dq yes ,
1296+then attempts to use compromised keys for authentication will be logged but
1297+accepted.
1298+It is strongly recommended that this be used only to install new authorized
1299+keys on the remote system, and even then only with the utmost care.
1300+If
1301+.Dq no ,
1302+then attempts to use compromised keys for authentication will be prevented.
1303+The default is
1304+.Dq no .
1305 .It Cm UsePrivilegedPort
1306 Specifies whether to use a privileged port for outgoing connections.
1307 The argument must be
1308Index: b/sshconnect2.c
1309===================================================================
1310--- a/sshconnect2.c
1311+++ b/sshconnect2.c
1312@@ -1491,6 +1491,8 @@
1313
1314 /* list of keys stored in the filesystem and PKCS#11 */
1315 for (i = 0; i < options.num_identity_files; i++) {
1316+ if (options.identity_files[i] == NULL)
1317+ continue;
1318 key = options.identity_keys[i];
1319 if (key && key->type == KEY_RSA1)
1320 continue;
1321@@ -1608,7 +1610,7 @@
1322 debug("Offering %s public key: %s", key_type(id->key),
1323 id->filename);
1324 sent = send_pubkey_test(authctxt, id);
1325- } else if (id->key == NULL) {
1326+ } else if (id->key == NULL && id->filename) {
1327 debug("Trying private key: %s", id->filename);
1328 id->key = load_identity_file(id->filename,
1329 id->userprovided);
1330Index: b/sshd.8
1331===================================================================
1332--- a/sshd.8
1333+++ b/sshd.8
1334@@ -954,6 +954,7 @@
1335 .Xr ssh-agent 1 ,
1336 .Xr ssh-keygen 1 ,
1337 .Xr ssh-keyscan 1 ,
1338+.Xr ssh-vulnkey 1 ,
1339 .Xr chroot 2 ,
1340 .Xr hosts_access 5 ,
1341 .Xr login.conf 5 ,
1342Index: b/sshd.c
1343===================================================================
1344--- a/sshd.c
1345+++ b/sshd.c
1346@@ -1688,6 +1688,11 @@
1347 sensitive_data.host_pubkeys[i] = NULL;
1348 continue;
1349 }
1350+ if (auth_key_is_revoked(key != NULL ? key : pubkey, 1)) {
1351+ sensitive_data.host_keys[i] = NULL;
1352+ sensitive_data.host_pubkeys[i] = NULL;
1353+ continue;
1354+ }
1355
1356 switch (keytype) {
1357 case KEY_RSA1:
1358Index: b/sshd_config.5
1359===================================================================
1360--- a/sshd_config.5
1361+++ b/sshd_config.5
1362@@ -885,6 +885,20 @@
1363 Specifies whether password authentication is allowed.
1364 The default is
1365 .Dq yes .
1366+.It Cm PermitBlacklistedKeys
1367+Specifies whether
1368+.Xr sshd 8
1369+should allow keys recorded in its blacklist of known-compromised keys (see
1370+.Xr ssh-vulnkey 1 ) .
1371+If
1372+.Dq yes ,
1373+then attempts to authenticate with compromised keys will be logged but
1374+accepted.
1375+If
1376+.Dq no ,
1377+then attempts to authenticate with compromised keys will be rejected.
1378+The default is
1379+.Dq no .
1380 .It Cm PermitEmptyPasswords
1381 When password authentication is allowed, it specifies whether the
1382 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..de61e1dd9
--- /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: 2013-09-14
5
6Index: b/clientloop.c
7===================================================================
8--- a/clientloop.c
9+++ b/clientloop.c
10@@ -563,16 +563,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@@ -634,7 +639,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 server_alive_time = now + options.server_alive_interval;
49 }
50Index: b/ssh_config.5
51===================================================================
52--- a/ssh_config.5
53+++ b/ssh_config.5
54@@ -1130,7 +1130,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..f8be76c89
--- /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: 2013-09-14
12
13Index: b/log.c
14===================================================================
15--- a/log.c
16+++ b/log.c
17@@ -94,6 +94,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@@ -740,7 +740,7 @@
30 /* Do not allocate a tty if stdin is not a tty. */
31 if ((!isatty(fileno(stdin)) || stdin_null_flag) &&
32 options.request_tty != REQUEST_TTY_FORCE) {
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..ac00edac6
--- /dev/null
+++ b/debian/patches/user-group-modes.patch
@@ -0,0 +1,250 @@
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: 2013-09-14
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 #ifdef HAVE_UTIL_H
25 #include <util.h>
26 #endif
27@@ -1160,8 +1162,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@@ -1338,6 +1338,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 writable 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@@ -1382,6 +1382,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@@ -408,8 +408,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@@ -471,8 +470,7 @@
78 snprintf(err, errlen, "%s is not a regular file", buf);
79 return -1;
80 }
81- if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
82- (stp->st_mode & 022) != 0) {
83+ if (!secure_permissions(stp, uid)) {
84 snprintf(err, errlen, "bad ownership or modes for file %s",
85 buf);
86 return -1;
87@@ -487,8 +485,7 @@
88 strlcpy(buf, cp, sizeof(buf));
89
90 if (stat(buf, &st) < 0 ||
91- (!platform_sys_dir_uid(st.st_uid) && 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@@ -58,6 +59,7 @@
113 #include "misc.h"
114 #include "log.h"
115 #include "ssh.h"
116+#include "platform.h"
117
118 /* remove newline at end of string */
119 char *
120@@ -642,6 +644,71 @@
121 return -1;
122 }
123
124+/*
125+ * return 1 if the specified uid is a uid that may own a system directory
126+ * otherwise 0.
127+ */
128+int
129+platform_sys_dir_uid(uid_t uid)
130+{
131+ if (uid == 0)
132+ return 1;
133+#ifdef PLATFORM_SYS_DIR_UID
134+ if (uid == PLATFORM_SYS_DIR_UID)
135+ return 1;
136+#endif
137+ return 0;
138+}
139+
140+int
141+secure_permissions(struct stat *st, uid_t uid)
142+{
143+ if (!platform_sys_dir_uid(st->st_uid) && st->st_uid != uid)
144+ return 0;
145+ if ((st->st_mode & 002) != 0)
146+ return 0;
147+ if ((st->st_mode & 020) != 0) {
148+ /* If the file is group-writable, the group in question must
149+ * have exactly one member, namely the file's owner.
150+ * (Zero-member groups are typically used by setgid
151+ * binaries, and are unlikely to be suitable.)
152+ */
153+ struct passwd *pw;
154+ struct group *gr;
155+ int members = 0;
156+
157+ gr = getgrgid(st->st_gid);
158+ if (!gr)
159+ return 0;
160+
161+ /* Check primary group memberships. */
162+ while ((pw = getpwent()) != NULL) {
163+ if (pw->pw_gid == gr->gr_gid) {
164+ ++members;
165+ if (pw->pw_uid != uid)
166+ return 0;
167+ }
168+ }
169+ endpwent();
170+
171+ pw = getpwuid(st->st_uid);
172+ if (!pw)
173+ return 0;
174+
175+ /* Check supplementary group memberships. */
176+ if (gr->gr_mem[0]) {
177+ ++members;
178+ if (strcmp(pw->pw_name, gr->gr_mem[0]) ||
179+ gr->gr_mem[1])
180+ return 0;
181+ }
182+
183+ if (!members)
184+ return 0;
185+ }
186+ return 1;
187+}
188+
189 int
190 tun_open(int tun, int mode)
191 {
192Index: b/misc.h
193===================================================================
194--- a/misc.h
195+++ b/misc.h
196@@ -104,4 +104,6 @@
197 int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
198 int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *);
199
200+int secure_permissions(struct stat *st, uid_t uid);
201+
202 #endif /* _MISC_H */
203Index: b/auth-rhosts.c
204===================================================================
205--- a/auth-rhosts.c
206+++ b/auth-rhosts.c
207@@ -256,8 +256,7 @@
208 return 0;
209 }
210 if (options.strict_modes &&
211- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
212- (st.st_mode & 022) != 0)) {
213+ !secure_permissions(&st, pw->pw_uid)) {
214 logit("Rhosts authentication refused for %.100s: "
215 "bad ownership or modes for home directory.", pw->pw_name);
216 auth_debug_add("Rhosts authentication refused for %.100s: "
217@@ -283,8 +282,7 @@
218 * allowing access to their account by anyone.
219 */
220 if (options.strict_modes &&
221- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
222- (st.st_mode & 022) != 0)) {
223+ !secure_permissions(&st, pw->pw_uid)) {
224 logit("Rhosts authentication refused for %.100s: bad modes for %.200s",
225 pw->pw_name, buf);
226 auth_debug_add("Bad file modes for %.200s", buf);
227Index: b/platform.c
228===================================================================
229--- a/platform.c
230+++ b/platform.c
231@@ -194,19 +194,3 @@
232 return NULL;
233 #endif
234 }
235-
236-/*
237- * return 1 if the specified uid is a uid that may own a system directory
238- * otherwise 0.
239- */
240-int
241-platform_sys_dir_uid(uid_t uid)
242-{
243- if (uid == 0)
244- return 1;
245-#ifdef PLATFORM_SYS_DIR_UID
246- if (uid == PLATFORM_SYS_DIR_UID)
247- return 1;
248-#endif
249- return 0;
250-}