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