diff options
Diffstat (limited to 'debian/patches')
37 files changed, 6617 insertions, 0 deletions
diff --git a/debian/patches/authorized-keys-man-symlink.patch b/debian/patches/authorized-keys-man-symlink.patch new file mode 100644 index 000000000..1e8aab147 --- /dev/null +++ b/debian/patches/authorized-keys-man-symlink.patch | |||
@@ -0,0 +1,12 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 | ||
222 | Index: 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 @@ | |||
1 | Index: 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); | ||
49 | Index: 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 | |||
62 | Index: 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. */ | ||
76 | Index: 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 @@ | |||
1 | Index: 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) | ||
14 | Index: 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 | ||
38 | Index: 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. | ||
75 | Index: 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 | ||
87 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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> | ||
109 | Index: 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 | ||
132 | Index: 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 | } | ||
183 | Index: 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; | ||
195 | Index: 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, | ||
298 | Index: 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 | ||
336 | Index: 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; | ||
367 | Index: 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]) | ||
402 | Index: 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 */ | ||
753 | Index: 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 */ | ||
877 | Index: 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 | ||
1194 | Index: 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 | } | ||
1230 | Index: 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 *); | ||
1269 | Index: 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 */ | ||
1608 | Index: 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 */ | ||
1901 | Index: 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; | ||
1914 | Index: 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 { | ||
1926 | Index: 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 | ||
2122 | Index: 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, | ||
2135 | Index: 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 | ||
2200 | Index: 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 | ||
2216 | Index: 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) | ||
2301 | Index: 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. */ | ||
2317 | Index: 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; | ||
2397 | Index: 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 */ | ||
2412 | Index: 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 */ | ||
2513 | Index: 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 | ||
2526 | Index: 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 | ||
2570 | Index: 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 | ||
2766 | Index: 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; | ||
2918 | Index: 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 | ||
2931 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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) | ||
47 | Index: 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. | ||
95 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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. | ||
18 | Index: 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 *); | ||
30 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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, | ||
36 | Index: 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 @@ | |||
1 | Index: 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 | |||
15 | Index: 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 | |||
31 | Index: 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]) | ||
43 | Index: 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 | ||
128 | Index: 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 */ | ||
142 | Index: 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 @@ | |||
1 | Index: 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 | ||
23 | Index: 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 | ||
49 | Index: 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 | ||
64 | Index: 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 , | ||
94 | Index: 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 @@ | |||
1 | Index: 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)); | ||
14 | Index: 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. */ | ||
27 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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;} | ||
14 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 | ||
13 | Index: 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) | ||
44 | Index: 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) { | ||
82 | Index: 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 | |||
150 | Index: 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, | ||
163 | Index: 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 | ||
210 | Index: 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 *); | ||
224 | Index: 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 | ||
2 | gssapi.patch | ||
3 | gssapi-autoconf.patch | ||
4 | old-gssapi.patch | ||
5 | |||
6 | # Autotools | ||
7 | config-guess-sub.patch | ||
8 | |||
9 | # SELinux | ||
10 | selinux-role.patch | ||
11 | selinux-autoconf.patch | ||
12 | selinux-fix-chroot-directory.patch | ||
13 | |||
14 | # Key blacklisting | ||
15 | ssh-vulnkey.patch | ||
16 | |||
17 | # Keepalive handling | ||
18 | ssh1-keepalive.patch | ||
19 | keepalive-extensions.patch | ||
20 | |||
21 | # Linux OOM handling | ||
22 | oom-adjust.patch | ||
23 | |||
24 | # Message adjustments | ||
25 | syslog-level-silent.patch | ||
26 | quieter-signals.patch | ||
27 | helpful-wait-terminate.patch | ||
28 | banner-noslash.patch | ||
29 | keyfile-debug.patch | ||
30 | |||
31 | # Miscellaneous bug fixes | ||
32 | gnome-ssh-askpass2-link.patch | ||
33 | user-group-modes.patch | ||
34 | epfnosupport.patch | ||
35 | scp-quoting.patch | ||
36 | shell-path.patch | ||
37 | ssh-copy-id-status-check.patch | ||
38 | ssh-copy-id-trailing-colons.patch | ||
39 | no-constraint-fallback.patch | ||
40 | sshd-ignore-sighup.patch | ||
41 | |||
42 | # Versioning | ||
43 | package-versioning.patch | ||
44 | debian-banner.patch | ||
45 | |||
46 | # File system layout | ||
47 | authorized-keys-man-symlink.patch | ||
48 | lintian-symlink-pickiness.patch | ||
49 | |||
50 | # Documentation | ||
51 | openbsd-docs.patch | ||
52 | ssh-argv0.patch | ||
53 | doc-connection-sharing.patch | ||
54 | doc-hash-tab-completion.patch | ||
55 | |||
56 | # Debian-specific configuration | ||
57 | no-openssl-version-check.patch | ||
58 | gnome-ssh-askpass2-icon.patch | ||
59 | debian-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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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 | ||
85 | Index: 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; | ||
99 | Index: 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, | ||
113 | Index: 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 | ||
164 | Index: 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); | ||
177 | Index: 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 | |||
191 | Index: 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); | ||
205 | Index: 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 | +} | ||
358 | Index: 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 | ||
369 | Index: 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 | ||
394 | Index: 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) | ||
442 | Index: 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. */ | ||
454 | Index: 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); | ||
511 | Index: 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 */ | ||
523 | Index: 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 | ||
546 | Index: 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)) { | ||
574 | Index: 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 | ||
586 | Index: 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. | ||
833 | Index: 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 | +} | ||
1226 | Index: 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 , | ||
1238 | Index: 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; | ||
1274 | Index: 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 | ||
1302 | Index: 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) { | ||
1324 | Index: 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 , | ||
1336 | Index: 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; | ||
1352 | Index: 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 @@ | |||
1 | Index: 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; | ||
45 | Index: 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 @@ | |||
1 | Index: 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 @@ | |||
1 | Index: 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)); | ||
14 | Index: 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: | ||
34 | Index: 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, | ||
46 | Index: 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]); | ||
59 | Index: 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. | ||
72 | Index: 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 | ||
88 | Index: 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; | ||
115 | Index: 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. | ||
128 | Index: 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 | ||
146 | Index: 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, | ||
164 | Index: 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 @@ | |||
1 | Index: 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 | |||
47 | Index: 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 | ||
60 | Index: 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 | ||