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