diff options
Diffstat (limited to 'debian/patches')
30 files changed, 6365 insertions, 0 deletions
diff --git a/debian/patches/auth-log-verbosity.patch b/debian/patches/auth-log-verbosity.patch new file mode 100644 index 000000000..84a14cfb8 --- /dev/null +++ b/debian/patches/auth-log-verbosity.patch | |||
@@ -0,0 +1,133 @@ | |||
1 | From 1ecd5db58295874d8b9a7ce98fe1880ab08fbcaf Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:10:02 +0000 | ||
4 | Subject: Quieten logs when multiple from= restrictions are used | ||
5 | |||
6 | Bug-Debian: http://bugs.debian.org/630606 | ||
7 | Forwarded: no | ||
8 | Last-Update: 2013-09-14 | ||
9 | |||
10 | Patch-Name: auth-log-verbosity.patch | ||
11 | --- | ||
12 | auth-options.c | 35 ++++++++++++++++++++++++++--------- | ||
13 | auth-options.h | 1 + | ||
14 | auth-rsa.c | 2 ++ | ||
15 | auth2-pubkey.c | 3 +++ | ||
16 | 4 files changed, 32 insertions(+), 9 deletions(-) | ||
17 | |||
18 | diff --git a/auth-options.c b/auth-options.c | ||
19 | index f3d9c9d..d4d22d7 100644 | ||
20 | --- a/auth-options.c | ||
21 | +++ b/auth-options.c | ||
22 | @@ -54,9 +54,20 @@ int forced_tun_device = -1; | ||
23 | /* "principals=" option. */ | ||
24 | char *authorized_principals = NULL; | ||
25 | |||
26 | +/* Throttle log messages. */ | ||
27 | +int logged_from_hostip = 0; | ||
28 | +int logged_cert_hostip = 0; | ||
29 | + | ||
30 | extern ServerOptions options; | ||
31 | |||
32 | void | ||
33 | +auth_start_parse_options(void) | ||
34 | +{ | ||
35 | + logged_from_hostip = 0; | ||
36 | + logged_cert_hostip = 0; | ||
37 | +} | ||
38 | + | ||
39 | +void | ||
40 | auth_clear_options(void) | ||
41 | { | ||
42 | no_agent_forwarding_flag = 0; | ||
43 | @@ -284,10 +295,13 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) | ||
44 | /* FALLTHROUGH */ | ||
45 | case 0: | ||
46 | free(patterns); | ||
47 | - logit("Authentication tried for %.100s with " | ||
48 | - "correct key but not from a permitted " | ||
49 | - "host (host=%.200s, ip=%.200s).", | ||
50 | - pw->pw_name, remote_host, remote_ip); | ||
51 | + if (!logged_from_hostip) { | ||
52 | + logit("Authentication tried for %.100s with " | ||
53 | + "correct key but not from a permitted " | ||
54 | + "host (host=%.200s, ip=%.200s).", | ||
55 | + pw->pw_name, remote_host, remote_ip); | ||
56 | + logged_from_hostip = 1; | ||
57 | + } | ||
58 | auth_debug_add("Your host '%.200s' is not " | ||
59 | "permitted to use this key for login.", | ||
60 | remote_host); | ||
61 | @@ -511,11 +525,14 @@ parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw, | ||
62 | break; | ||
63 | case 0: | ||
64 | /* no match */ | ||
65 | - logit("Authentication tried for %.100s " | ||
66 | - "with valid certificate but not " | ||
67 | - "from a permitted host " | ||
68 | - "(ip=%.200s).", pw->pw_name, | ||
69 | - remote_ip); | ||
70 | + if (!logged_cert_hostip) { | ||
71 | + logit("Authentication tried for %.100s " | ||
72 | + "with valid certificate but not " | ||
73 | + "from a permitted host " | ||
74 | + "(ip=%.200s).", pw->pw_name, | ||
75 | + remote_ip); | ||
76 | + logged_cert_hostip = 1; | ||
77 | + } | ||
78 | auth_debug_add("Your address '%.200s' " | ||
79 | "is not permitted to use this " | ||
80 | "certificate for login.", | ||
81 | diff --git a/auth-options.h b/auth-options.h | ||
82 | index 7455c94..a3f0a02 100644 | ||
83 | --- a/auth-options.h | ||
84 | +++ b/auth-options.h | ||
85 | @@ -33,6 +33,7 @@ extern int forced_tun_device; | ||
86 | extern int key_is_cert_authority; | ||
87 | extern char *authorized_principals; | ||
88 | |||
89 | +void auth_start_parse_options(void); | ||
90 | int auth_parse_options(struct passwd *, char *, char *, u_long); | ||
91 | void auth_clear_options(void); | ||
92 | int auth_cert_options(Key *, struct passwd *); | ||
93 | diff --git a/auth-rsa.c b/auth-rsa.c | ||
94 | index e9f4ede..5d7bdcb 100644 | ||
95 | --- a/auth-rsa.c | ||
96 | +++ b/auth-rsa.c | ||
97 | @@ -179,6 +179,8 @@ rsa_key_allowed_in_file(struct passwd *pw, char *file, | ||
98 | if ((f = auth_openkeyfile(file, pw, options.strict_modes)) == NULL) | ||
99 | return 0; | ||
100 | |||
101 | + auth_start_parse_options(); | ||
102 | + | ||
103 | /* | ||
104 | * Go though the accepted keys, looking for the current key. If | ||
105 | * found, perform a challenge-response dialog to verify that the | ||
106 | diff --git a/auth2-pubkey.c b/auth2-pubkey.c | ||
107 | index f3ca965..f78b046 100644 | ||
108 | --- a/auth2-pubkey.c | ||
109 | +++ b/auth2-pubkey.c | ||
110 | @@ -263,6 +263,7 @@ match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) | ||
111 | restore_uid(); | ||
112 | return 0; | ||
113 | } | ||
114 | + auth_start_parse_options(); | ||
115 | while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { | ||
116 | /* Skip leading whitespace. */ | ||
117 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) | ||
118 | @@ -324,6 +325,7 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) | ||
119 | found_key = 0; | ||
120 | |||
121 | found = NULL; | ||
122 | + auth_start_parse_options(); | ||
123 | while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { | ||
124 | char *cp, *key_options = NULL; | ||
125 | if (found != NULL) | ||
126 | @@ -459,6 +461,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) | ||
127 | if (key_cert_check_authority(key, 0, 1, | ||
128 | principals_file == NULL ? pw->pw_name : NULL, &reason) != 0) | ||
129 | goto fail_reason; | ||
130 | + auth_start_parse_options(); | ||
131 | if (auth_cert_options(key, pw) != 0) | ||
132 | goto out; | ||
133 | |||
diff --git a/debian/patches/authorized-keys-man-symlink.patch b/debian/patches/authorized-keys-man-symlink.patch new file mode 100644 index 000000000..6afb0420b --- /dev/null +++ b/debian/patches/authorized-keys-man-symlink.patch | |||
@@ -0,0 +1,26 @@ | |||
1 | From 19b0441502c07401dd6d418f8f81cc7f1a44ccb1 Mon Sep 17 00:00:00 2001 | ||
2 | From: Tomas Pospisek <tpo_deb@sourcepole.ch> | ||
3 | Date: Sun, 9 Feb 2014 16:10:07 +0000 | ||
4 | Subject: Install authorized_keys(5) as a symlink to sshd(8) | ||
5 | |||
6 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1720 | ||
7 | Bug-Debian: http://bugs.debian.org/441817 | ||
8 | Last-Update: 2013-09-14 | ||
9 | |||
10 | Patch-Name: authorized-keys-man-symlink.patch | ||
11 | --- | ||
12 | Makefile.in | 1 + | ||
13 | 1 file changed, 1 insertion(+) | ||
14 | |||
15 | diff --git a/Makefile.in b/Makefile.in | ||
16 | index c4cb8ea..a4402e9 100644 | ||
17 | --- a/Makefile.in | ||
18 | +++ b/Makefile.in | ||
19 | @@ -309,6 +309,7 @@ install-files: | ||
20 | $(INSTALL) -m 644 sshd_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/sshd_config.5 | ||
21 | $(INSTALL) -m 644 ssh_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh_config.5 | ||
22 | $(INSTALL) -m 644 sshd.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8 | ||
23 | + ln -s ../$(mansubdir)8/sshd.8 $(DESTDIR)$(mandir)/$(mansubdir)5/authorized_keys.5 | ||
24 | $(INSTALL) -m 644 sftp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1 | ||
25 | $(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 | ||
26 | $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 | ||
diff --git a/debian/patches/consolekit.patch b/debian/patches/consolekit.patch new file mode 100644 index 000000000..e50c77f62 --- /dev/null +++ b/debian/patches/consolekit.patch | |||
@@ -0,0 +1,741 @@ | |||
1 | From f51fe0c55e54c12db952624e980d18f39c41e581 Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@ubuntu.com> | ||
3 | Date: Sun, 9 Feb 2014 16:09:57 +0000 | ||
4 | Subject: Add support for registering ConsoleKit sessions on login | ||
5 | |||
6 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1450 | ||
7 | Last-Updated: 2014-10-07 | ||
8 | |||
9 | Patch-Name: consolekit.patch | ||
10 | --- | ||
11 | Makefile.in | 3 +- | ||
12 | configure | 132 +++++++++++++++++++++++++++++++ | ||
13 | configure.ac | 25 ++++++ | ||
14 | consolekit.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | ||
15 | consolekit.h | 24 ++++++ | ||
16 | monitor.c | 42 ++++++++++ | ||
17 | monitor.h | 2 + | ||
18 | monitor_wrap.c | 30 +++++++ | ||
19 | monitor_wrap.h | 4 + | ||
20 | session.c | 13 ++++ | ||
21 | session.h | 6 ++ | ||
22 | 11 files changed, 521 insertions(+), 1 deletion(-) | ||
23 | create mode 100644 consolekit.c | ||
24 | create mode 100644 consolekit.h | ||
25 | |||
26 | diff --git a/Makefile.in b/Makefile.in | ||
27 | index 086d8dd..c4cb8ea 100644 | ||
28 | --- a/Makefile.in | ||
29 | +++ b/Makefile.in | ||
30 | @@ -107,7 +107,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ | ||
31 | sftp-server.o sftp-common.o \ | ||
32 | roaming_common.o roaming_serv.o \ | ||
33 | sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ | ||
34 | - sandbox-seccomp-filter.o sandbox-capsicum.o | ||
35 | + sandbox-seccomp-filter.o sandbox-capsicum.o \ | ||
36 | + consolekit.o | ||
37 | |||
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-keysign.8.out ssh-pkcs11-helper.8.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-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 | ||
40 | diff --git a/configure b/configure | ||
41 | index ea5f200..7be478a 100755 | ||
42 | --- a/configure | ||
43 | +++ b/configure | ||
44 | @@ -739,6 +739,7 @@ with_privsep_user | ||
45 | with_sandbox | ||
46 | with_selinux | ||
47 | with_kerberos5 | ||
48 | +with_consolekit | ||
49 | with_privsep_path | ||
50 | with_xauth | ||
51 | enable_strip | ||
52 | @@ -1430,6 +1431,7 @@ Optional Packages: | ||
53 | --with-sandbox=style Specify privilege separation sandbox (no, darwin, rlimit, systrace, seccomp_filter, capsicum) | ||
54 | --with-selinux Enable SELinux support | ||
55 | --with-kerberos5=PATH Enable Kerberos 5 support | ||
56 | + --with-consolekit Enable ConsoleKit support | ||
57 | --with-privsep-path=xxx Path for privilege separation chroot (default=/var/empty) | ||
58 | --with-xauth=PATH Specify path to xauth program | ||
59 | --with-maildir=/path/to/mail Specify your system mail directory | ||
60 | @@ -17211,6 +17213,135 @@ fi | ||
61 | |||
62 | |||
63 | |||
64 | +# Check whether user wants ConsoleKit support | ||
65 | +CONSOLEKIT_MSG="no" | ||
66 | +LIBCK_CONNECTOR="" | ||
67 | + | ||
68 | +# Check whether --with-consolekit was given. | ||
69 | +if test "${with_consolekit+set}" = set; then : | ||
70 | + withval=$with_consolekit; if test "x$withval" != "xno" ; then | ||
71 | + if test -n "$ac_tool_prefix"; then | ||
72 | + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. | ||
73 | +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 | ||
74 | +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 | ||
75 | +$as_echo_n "checking for $ac_word... " >&6; } | ||
76 | +if ${ac_cv_path_PKGCONFIG+:} false; then : | ||
77 | + $as_echo_n "(cached) " >&6 | ||
78 | +else | ||
79 | + case $PKGCONFIG in | ||
80 | + [\\/]* | ?:[\\/]*) | ||
81 | + ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path. | ||
82 | + ;; | ||
83 | + *) | ||
84 | + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR | ||
85 | +for as_dir in $PATH | ||
86 | +do | ||
87 | + IFS=$as_save_IFS | ||
88 | + test -z "$as_dir" && as_dir=. | ||
89 | + for ac_exec_ext in '' $ac_executable_extensions; do | ||
90 | + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then | ||
91 | + ac_cv_path_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext" | ||
92 | + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 | ||
93 | + break 2 | ||
94 | + fi | ||
95 | +done | ||
96 | + done | ||
97 | +IFS=$as_save_IFS | ||
98 | + | ||
99 | + ;; | ||
100 | +esac | ||
101 | +fi | ||
102 | +PKGCONFIG=$ac_cv_path_PKGCONFIG | ||
103 | +if test -n "$PKGCONFIG"; then | ||
104 | + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKGCONFIG" >&5 | ||
105 | +$as_echo "$PKGCONFIG" >&6; } | ||
106 | +else | ||
107 | + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 | ||
108 | +$as_echo "no" >&6; } | ||
109 | +fi | ||
110 | + | ||
111 | + | ||
112 | +fi | ||
113 | +if test -z "$ac_cv_path_PKGCONFIG"; then | ||
114 | + ac_pt_PKGCONFIG=$PKGCONFIG | ||
115 | + # Extract the first word of "pkg-config", so it can be a program name with args. | ||
116 | +set dummy pkg-config; ac_word=$2 | ||
117 | +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 | ||
118 | +$as_echo_n "checking for $ac_word... " >&6; } | ||
119 | +if ${ac_cv_path_ac_pt_PKGCONFIG+:} false; then : | ||
120 | + $as_echo_n "(cached) " >&6 | ||
121 | +else | ||
122 | + case $ac_pt_PKGCONFIG in | ||
123 | + [\\/]* | ?:[\\/]*) | ||
124 | + ac_cv_path_ac_pt_PKGCONFIG="$ac_pt_PKGCONFIG" # Let the user override the test with a path. | ||
125 | + ;; | ||
126 | + *) | ||
127 | + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR | ||
128 | +for as_dir in $PATH | ||
129 | +do | ||
130 | + IFS=$as_save_IFS | ||
131 | + test -z "$as_dir" && as_dir=. | ||
132 | + for ac_exec_ext in '' $ac_executable_extensions; do | ||
133 | + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then | ||
134 | + ac_cv_path_ac_pt_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext" | ||
135 | + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 | ||
136 | + break 2 | ||
137 | + fi | ||
138 | +done | ||
139 | + done | ||
140 | +IFS=$as_save_IFS | ||
141 | + | ||
142 | + ;; | ||
143 | +esac | ||
144 | +fi | ||
145 | +ac_pt_PKGCONFIG=$ac_cv_path_ac_pt_PKGCONFIG | ||
146 | +if test -n "$ac_pt_PKGCONFIG"; then | ||
147 | + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKGCONFIG" >&5 | ||
148 | +$as_echo "$ac_pt_PKGCONFIG" >&6; } | ||
149 | +else | ||
150 | + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 | ||
151 | +$as_echo "no" >&6; } | ||
152 | +fi | ||
153 | + | ||
154 | + if test "x$ac_pt_PKGCONFIG" = x; then | ||
155 | + PKGCONFIG="no" | ||
156 | + else | ||
157 | + case $cross_compiling:$ac_tool_warned in | ||
158 | +yes:) | ||
159 | +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 | ||
160 | +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} | ||
161 | +ac_tool_warned=yes ;; | ||
162 | +esac | ||
163 | + PKGCONFIG=$ac_pt_PKGCONFIG | ||
164 | + fi | ||
165 | +else | ||
166 | + PKGCONFIG="$ac_cv_path_PKGCONFIG" | ||
167 | +fi | ||
168 | + | ||
169 | + if test "$PKGCONFIG" != "no"; then | ||
170 | + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ck-connector" >&5 | ||
171 | +$as_echo_n "checking for ck-connector... " >&6; } | ||
172 | + if $PKGCONFIG --exists ck-connector; then | ||
173 | + CKCON_CFLAGS=`$PKGCONFIG --cflags ck-connector` | ||
174 | + CKCON_LIBS=`$PKGCONFIG --libs ck-connector` | ||
175 | + CPPFLAGS="$CPPFLAGS $CKCON_CFLAGS" | ||
176 | + SSHDLIBS="$SSHDLIBS $CKCON_LIBS" | ||
177 | + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 | ||
178 | +$as_echo "yes" >&6; } | ||
179 | + | ||
180 | +$as_echo "#define USE_CONSOLEKIT 1" >>confdefs.h | ||
181 | + | ||
182 | + CONSOLEKIT_MSG="yes" | ||
183 | + else | ||
184 | + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 | ||
185 | +$as_echo "no" >&6; } | ||
186 | + fi | ||
187 | + fi | ||
188 | + fi | ||
189 | + | ||
190 | +fi | ||
191 | + | ||
192 | + | ||
193 | # Looking for programs, paths and files | ||
194 | |||
195 | PRIVSEP_PATH=/var/empty | ||
196 | @@ -19739,6 +19870,7 @@ echo " MD5 password support: $MD5_MSG" | ||
197 | echo " libedit support: $LIBEDIT_MSG" | ||
198 | echo " Solaris process contract support: $SPC_MSG" | ||
199 | echo " Solaris project support: $SP_MSG" | ||
200 | +echo " ConsoleKit support: $CONSOLEKIT_MSG" | ||
201 | echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" | ||
202 | echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" | ||
203 | echo " BSD Auth support: $BSD_AUTH_MSG" | ||
204 | diff --git a/configure.ac b/configure.ac | ||
205 | index 7f160f1..f5c65c5 100644 | ||
206 | --- a/configure.ac | ||
207 | +++ b/configure.ac | ||
208 | @@ -4113,6 +4113,30 @@ AC_ARG_WITH([kerberos5], | ||
209 | AC_SUBST([GSSLIBS]) | ||
210 | AC_SUBST([K5LIBS]) | ||
211 | |||
212 | +# Check whether user wants ConsoleKit support | ||
213 | +CONSOLEKIT_MSG="no" | ||
214 | +LIBCK_CONNECTOR="" | ||
215 | +AC_ARG_WITH(consolekit, | ||
216 | + [ --with-consolekit Enable ConsoleKit support], | ||
217 | + [ if test "x$withval" != "xno" ; then | ||
218 | + AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no]) | ||
219 | + if test "$PKGCONFIG" != "no"; then | ||
220 | + AC_MSG_CHECKING([for ck-connector]) | ||
221 | + if $PKGCONFIG --exists ck-connector; then | ||
222 | + CKCON_CFLAGS=`$PKGCONFIG --cflags ck-connector` | ||
223 | + CKCON_LIBS=`$PKGCONFIG --libs ck-connector` | ||
224 | + CPPFLAGS="$CPPFLAGS $CKCON_CFLAGS" | ||
225 | + SSHDLIBS="$SSHDLIBS $CKCON_LIBS" | ||
226 | + AC_MSG_RESULT([yes]) | ||
227 | + AC_DEFINE(USE_CONSOLEKIT, 1, [Define if you want ConsoleKit support.]) | ||
228 | + CONSOLEKIT_MSG="yes" | ||
229 | + else | ||
230 | + AC_MSG_RESULT([no]) | ||
231 | + fi | ||
232 | + fi | ||
233 | + fi ] | ||
234 | +) | ||
235 | + | ||
236 | # Looking for programs, paths and files | ||
237 | |||
238 | PRIVSEP_PATH=/var/empty | ||
239 | @@ -4914,6 +4938,7 @@ echo " MD5 password support: $MD5_MSG" | ||
240 | echo " libedit support: $LIBEDIT_MSG" | ||
241 | echo " Solaris process contract support: $SPC_MSG" | ||
242 | echo " Solaris project support: $SP_MSG" | ||
243 | +echo " ConsoleKit support: $CONSOLEKIT_MSG" | ||
244 | echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" | ||
245 | echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" | ||
246 | echo " BSD Auth support: $BSD_AUTH_MSG" | ||
247 | diff --git a/consolekit.c b/consolekit.c | ||
248 | new file mode 100644 | ||
249 | index 0000000..0266f06 | ||
250 | --- /dev/null | ||
251 | +++ b/consolekit.c | ||
252 | @@ -0,0 +1,241 @@ | ||
253 | +/* | ||
254 | + * Copyright (c) 2008 Colin Watson. All rights reserved. | ||
255 | + * | ||
256 | + * Permission to use, copy, modify, and distribute this software for any | ||
257 | + * purpose with or without fee is hereby granted, provided that the above | ||
258 | + * copyright notice and this permission notice appear in all copies. | ||
259 | + * | ||
260 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
261 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
262 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
263 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
264 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
265 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
266 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
267 | + */ | ||
268 | +/* | ||
269 | + * Loosely based on pam-ck-connector, which is: | ||
270 | + * | ||
271 | + * Copyright (c) 2007 David Zeuthen <davidz@redhat.com> | ||
272 | + * | ||
273 | + * Permission is hereby granted, free of charge, to any person | ||
274 | + * obtaining a copy of this software and associated documentation | ||
275 | + * files (the "Software"), to deal in the Software without | ||
276 | + * restriction, including without limitation the rights to use, | ||
277 | + * copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
278 | + * copies of the Software, and to permit persons to whom the | ||
279 | + * Software is furnished to do so, subject to the following | ||
280 | + * conditions: | ||
281 | + * | ||
282 | + * The above copyright notice and this permission notice shall be | ||
283 | + * included in all copies or substantial portions of the Software. | ||
284 | + * | ||
285 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
286 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
287 | + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
288 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
289 | + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
290 | + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
291 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
292 | + * OTHER DEALINGS IN THE SOFTWARE. | ||
293 | + */ | ||
294 | + | ||
295 | +#include "includes.h" | ||
296 | + | ||
297 | +#ifdef USE_CONSOLEKIT | ||
298 | + | ||
299 | +#include <ck-connector.h> | ||
300 | + | ||
301 | +#include "openbsd-compat/sys-queue.h" | ||
302 | +#include "xmalloc.h" | ||
303 | +#include "channels.h" | ||
304 | +#include "key.h" | ||
305 | +#include "hostfile.h" | ||
306 | +#include "auth.h" | ||
307 | +#include "log.h" | ||
308 | +#include "misc.h" | ||
309 | +#include "servconf.h" | ||
310 | +#include "canohost.h" | ||
311 | +#include "session.h" | ||
312 | +#include "consolekit.h" | ||
313 | + | ||
314 | +extern ServerOptions options; | ||
315 | +extern u_int utmp_len; | ||
316 | + | ||
317 | +void | ||
318 | +set_active(const char *cookie) | ||
319 | +{ | ||
320 | + DBusError err; | ||
321 | + DBusConnection *connection; | ||
322 | + DBusMessage *message = NULL, *reply = NULL; | ||
323 | + char *sid; | ||
324 | + DBusMessageIter iter, subiter; | ||
325 | + const char *interface, *property; | ||
326 | + dbus_bool_t active; | ||
327 | + | ||
328 | + dbus_error_init(&err); | ||
329 | + connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err); | ||
330 | + if (!connection) { | ||
331 | + if (dbus_error_is_set(&err)) { | ||
332 | + error("unable to open DBus connection: %s", | ||
333 | + err.message); | ||
334 | + dbus_error_free(&err); | ||
335 | + } | ||
336 | + goto out; | ||
337 | + } | ||
338 | + dbus_connection_set_exit_on_disconnect(connection, FALSE); | ||
339 | + | ||
340 | + message = dbus_message_new_method_call("org.freedesktop.ConsoleKit", | ||
341 | + "/org/freedesktop/ConsoleKit/Manager", | ||
342 | + "org.freedesktop.ConsoleKit.Manager", | ||
343 | + "GetSessionForCookie"); | ||
344 | + if (!message) | ||
345 | + goto out; | ||
346 | + if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &cookie, | ||
347 | + DBUS_TYPE_INVALID)) { | ||
348 | + if (dbus_error_is_set(&err)) { | ||
349 | + error("unable to get current session: %s", | ||
350 | + err.message); | ||
351 | + dbus_error_free(&err); | ||
352 | + } | ||
353 | + goto out; | ||
354 | + } | ||
355 | + | ||
356 | + dbus_error_init(&err); | ||
357 | + reply = dbus_connection_send_with_reply_and_block(connection, message, | ||
358 | + -1, &err); | ||
359 | + if (!reply) { | ||
360 | + if (dbus_error_is_set(&err)) { | ||
361 | + error("unable to get current session: %s", | ||
362 | + err.message); | ||
363 | + dbus_error_free(&err); | ||
364 | + } | ||
365 | + goto out; | ||
366 | + } | ||
367 | + | ||
368 | + dbus_error_init(&err); | ||
369 | + if (!dbus_message_get_args(reply, &err, | ||
370 | + DBUS_TYPE_OBJECT_PATH, &sid, | ||
371 | + DBUS_TYPE_INVALID)) { | ||
372 | + if (dbus_error_is_set(&err)) { | ||
373 | + error("unable to get current session: %s", | ||
374 | + err.message); | ||
375 | + dbus_error_free(&err); | ||
376 | + } | ||
377 | + goto out; | ||
378 | + } | ||
379 | + dbus_message_unref(reply); | ||
380 | + dbus_message_unref(message); | ||
381 | + message = reply = NULL; | ||
382 | + | ||
383 | + message = dbus_message_new_method_call("org.freedesktop.ConsoleKit", | ||
384 | + sid, "org.freedesktop.DBus.Properties", "Set"); | ||
385 | + if (!message) | ||
386 | + goto out; | ||
387 | + interface = "org.freedesktop.ConsoleKit.Session"; | ||
388 | + property = "active"; | ||
389 | + if (!dbus_message_append_args(message, | ||
390 | + DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, | ||
391 | + DBUS_TYPE_INVALID)) | ||
392 | + goto out; | ||
393 | + dbus_message_iter_init_append(message, &iter); | ||
394 | + if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, | ||
395 | + DBUS_TYPE_BOOLEAN_AS_STRING, &subiter)) | ||
396 | + goto out; | ||
397 | + active = TRUE; | ||
398 | + if (!dbus_message_iter_append_basic(&subiter, DBUS_TYPE_BOOLEAN, | ||
399 | + &active)) | ||
400 | + goto out; | ||
401 | + if (!dbus_message_iter_close_container(&iter, &subiter)) | ||
402 | + goto out; | ||
403 | + | ||
404 | + dbus_error_init(&err); | ||
405 | + reply = dbus_connection_send_with_reply_and_block(connection, message, | ||
406 | + -1, &err); | ||
407 | + if (!reply) { | ||
408 | + if (dbus_error_is_set(&err)) { | ||
409 | + error("unable to make current session active: %s", | ||
410 | + err.message); | ||
411 | + dbus_error_free(&err); | ||
412 | + } | ||
413 | + goto out; | ||
414 | + } | ||
415 | + | ||
416 | +out: | ||
417 | + if (reply) | ||
418 | + dbus_message_unref(reply); | ||
419 | + if (message) | ||
420 | + dbus_message_unref(message); | ||
421 | +} | ||
422 | + | ||
423 | +/* | ||
424 | + * We pass display separately rather than using s->display because the | ||
425 | + * latter is not available in the monitor when using privsep. | ||
426 | + */ | ||
427 | + | ||
428 | +char * | ||
429 | +consolekit_register(Session *s, const char *display) | ||
430 | +{ | ||
431 | + DBusError err; | ||
432 | + const char *tty = s->tty; | ||
433 | + const char *remote_host_name; | ||
434 | + dbus_bool_t is_local = FALSE; | ||
435 | + const char *cookie = NULL; | ||
436 | + | ||
437 | + if (s->ckc) { | ||
438 | + debug("already registered with ConsoleKit"); | ||
439 | + return xstrdup(ck_connector_get_cookie(s->ckc)); | ||
440 | + } | ||
441 | + | ||
442 | + s->ckc = ck_connector_new(); | ||
443 | + if (!s->ckc) { | ||
444 | + error("ck_connector_new failed"); | ||
445 | + return NULL; | ||
446 | + } | ||
447 | + | ||
448 | + if (!tty) | ||
449 | + tty = ""; | ||
450 | + if (!display) | ||
451 | + display = ""; | ||
452 | + remote_host_name = get_remote_name_or_ip(utmp_len, options.use_dns); | ||
453 | + if (!remote_host_name) | ||
454 | + remote_host_name = ""; | ||
455 | + | ||
456 | + dbus_error_init(&err); | ||
457 | + if (!ck_connector_open_session_with_parameters(s->ckc, &err, | ||
458 | + "unix-user", &s->pw->pw_uid, | ||
459 | + "display-device", &tty, | ||
460 | + "x11-display", &display, | ||
461 | + "remote-host-name", &remote_host_name, | ||
462 | + "is-local", &is_local, | ||
463 | + NULL)) { | ||
464 | + if (dbus_error_is_set(&err)) { | ||
465 | + debug("%s", err.message); | ||
466 | + dbus_error_free(&err); | ||
467 | + } else { | ||
468 | + debug("insufficient privileges or D-Bus / ConsoleKit " | ||
469 | + "not available"); | ||
470 | + } | ||
471 | + return NULL; | ||
472 | + } | ||
473 | + | ||
474 | + debug("registered uid=%d on tty='%s' with ConsoleKit", | ||
475 | + s->pw->pw_uid, s->tty); | ||
476 | + | ||
477 | + cookie = ck_connector_get_cookie(s->ckc); | ||
478 | + set_active(cookie); | ||
479 | + return xstrdup(cookie); | ||
480 | +} | ||
481 | + | ||
482 | +void | ||
483 | +consolekit_unregister(Session *s) | ||
484 | +{ | ||
485 | + if (s->ckc) { | ||
486 | + debug("unregistering ConsoleKit session %s", | ||
487 | + ck_connector_get_cookie(s->ckc)); | ||
488 | + ck_connector_unref(s->ckc); | ||
489 | + s->ckc = NULL; | ||
490 | + } | ||
491 | +} | ||
492 | + | ||
493 | +#endif /* USE_CONSOLEKIT */ | ||
494 | diff --git a/consolekit.h b/consolekit.h | ||
495 | new file mode 100644 | ||
496 | index 0000000..8ce3716 | ||
497 | --- /dev/null | ||
498 | +++ b/consolekit.h | ||
499 | @@ -0,0 +1,24 @@ | ||
500 | +/* | ||
501 | + * Copyright (c) 2008 Colin Watson. All rights reserved. | ||
502 | + * | ||
503 | + * Permission to use, copy, modify, and distribute this software for any | ||
504 | + * purpose with or without fee is hereby granted, provided that the above | ||
505 | + * copyright notice and this permission notice appear in all copies. | ||
506 | + * | ||
507 | + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
508 | + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
509 | + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
510 | + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
511 | + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
512 | + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
513 | + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
514 | + */ | ||
515 | + | ||
516 | +#ifdef USE_CONSOLEKIT | ||
517 | + | ||
518 | +struct Session; | ||
519 | + | ||
520 | +char * consolekit_register(struct Session *, const char *); | ||
521 | +void consolekit_unregister(struct Session *); | ||
522 | + | ||
523 | +#endif /* USE_CONSOLEKIT */ | ||
524 | diff --git a/monitor.c b/monitor.c | ||
525 | index 94b194d..cc15ce4 100644 | ||
526 | --- a/monitor.c | ||
527 | +++ b/monitor.c | ||
528 | @@ -100,6 +100,9 @@ | ||
529 | #include "ssh2.h" | ||
530 | #include "roaming.h" | ||
531 | #include "authfd.h" | ||
532 | +#ifdef USE_CONSOLEKIT | ||
533 | +#include "consolekit.h" | ||
534 | +#endif | ||
535 | |||
536 | #ifdef GSSAPI | ||
537 | static Gssctxt *gsscontext = NULL; | ||
538 | @@ -190,6 +193,10 @@ int mm_answer_audit_command(int, Buffer *); | ||
539 | |||
540 | static int monitor_read_log(struct monitor *); | ||
541 | |||
542 | +#ifdef USE_CONSOLEKIT | ||
543 | +int mm_answer_consolekit_register(int, Buffer *); | ||
544 | +#endif | ||
545 | + | ||
546 | static Authctxt *authctxt; | ||
547 | |||
548 | #ifdef WITH_SSH1 | ||
549 | @@ -282,6 +289,9 @@ struct mon_table mon_dispatch_postauth20[] = { | ||
550 | {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, | ||
551 | {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, | ||
552 | #endif | ||
553 | +#ifdef USE_CONSOLEKIT | ||
554 | + {MONITOR_REQ_CONSOLEKIT_REGISTER, 0, mm_answer_consolekit_register}, | ||
555 | +#endif | ||
556 | {0, 0, NULL} | ||
557 | }; | ||
558 | |||
559 | @@ -327,6 +337,9 @@ struct mon_table mon_dispatch_postauth15[] = { | ||
560 | {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, | ||
561 | {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command}, | ||
562 | #endif | ||
563 | +#ifdef USE_CONSOLEKIT | ||
564 | + {MONITOR_REQ_CONSOLEKIT_REGISTER, 0, mm_answer_consolekit_register}, | ||
565 | +#endif | ||
566 | #endif /* WITH_SSH1 */ | ||
567 | {0, 0, NULL} | ||
568 | }; | ||
569 | @@ -509,6 +522,9 @@ monitor_child_postauth(struct monitor *pmonitor) | ||
570 | monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); | ||
571 | monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1); | ||
572 | } | ||
573 | +#ifdef USE_CONSOLEKIT | ||
574 | + monitor_permit(mon_dispatch, MONITOR_REQ_CONSOLEKIT_REGISTER, 1); | ||
575 | +#endif | ||
576 | |||
577 | for (;;) | ||
578 | monitor_read(pmonitor, mon_dispatch, NULL); | ||
579 | @@ -2296,3 +2312,29 @@ mm_answer_gss_updatecreds(int socket, Buffer *m) { | ||
580 | |||
581 | #endif /* GSSAPI */ | ||
582 | |||
583 | +#ifdef USE_CONSOLEKIT | ||
584 | +int | ||
585 | +mm_answer_consolekit_register(int sock, Buffer *m) | ||
586 | +{ | ||
587 | + Session *s; | ||
588 | + char *tty, *display; | ||
589 | + char *cookie = NULL; | ||
590 | + | ||
591 | + debug3("%s entering", __func__); | ||
592 | + | ||
593 | + tty = buffer_get_string(m, NULL); | ||
594 | + display = buffer_get_string(m, NULL); | ||
595 | + s = session_by_tty(tty); | ||
596 | + if (s != NULL) | ||
597 | + cookie = consolekit_register(s, display); | ||
598 | + buffer_clear(m); | ||
599 | + buffer_put_cstring(m, cookie != NULL ? cookie : ""); | ||
600 | + mm_request_send(sock, MONITOR_ANS_CONSOLEKIT_REGISTER, m); | ||
601 | + | ||
602 | + free(cookie); | ||
603 | + free(display); | ||
604 | + free(tty); | ||
605 | + | ||
606 | + return (0); | ||
607 | +} | ||
608 | +#endif /* USE_CONSOLEKIT */ | ||
609 | diff --git a/monitor.h b/monitor.h | ||
610 | index 4d5e8fa..10ba59e 100644 | ||
611 | --- a/monitor.h | ||
612 | +++ b/monitor.h | ||
613 | @@ -70,6 +70,8 @@ enum monitor_reqtype { | ||
614 | |||
615 | MONITOR_REQ_AUTHROLE = 154, | ||
616 | |||
617 | + MONITOR_REQ_CONSOLEKIT_REGISTER = 156, MONITOR_ANS_CONSOLEKIT_REGISTER = 157, | ||
618 | + | ||
619 | }; | ||
620 | |||
621 | struct mm_master; | ||
622 | diff --git a/monitor_wrap.c b/monitor_wrap.c | ||
623 | index 6dc890a..4c57d4d 100644 | ||
624 | --- a/monitor_wrap.c | ||
625 | +++ b/monitor_wrap.c | ||
626 | @@ -1363,3 +1363,33 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) | ||
627 | |||
628 | #endif /* GSSAPI */ | ||
629 | |||
630 | +#ifdef USE_CONSOLEKIT | ||
631 | +char * | ||
632 | +mm_consolekit_register(Session *s, const char *display) | ||
633 | +{ | ||
634 | + Buffer m; | ||
635 | + char *cookie; | ||
636 | + | ||
637 | + debug3("%s entering", __func__); | ||
638 | + | ||
639 | + if (s->ttyfd == -1) | ||
640 | + return NULL; | ||
641 | + buffer_init(&m); | ||
642 | + buffer_put_cstring(&m, s->tty); | ||
643 | + buffer_put_cstring(&m, display != NULL ? display : ""); | ||
644 | + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_CONSOLEKIT_REGISTER, &m); | ||
645 | + buffer_clear(&m); | ||
646 | + | ||
647 | + mm_request_receive_expect(pmonitor->m_recvfd, | ||
648 | + MONITOR_ANS_CONSOLEKIT_REGISTER, &m); | ||
649 | + cookie = buffer_get_string(&m, NULL); | ||
650 | + buffer_free(&m); | ||
651 | + | ||
652 | + /* treat empty cookie as missing cookie */ | ||
653 | + if (strlen(cookie) == 0) { | ||
654 | + free(cookie); | ||
655 | + cookie = NULL; | ||
656 | + } | ||
657 | + return (cookie); | ||
658 | +} | ||
659 | +#endif /* USE_CONSOLEKIT */ | ||
660 | diff --git a/monitor_wrap.h b/monitor_wrap.h | ||
661 | index 9c2ee49..00e93fe 100644 | ||
662 | --- a/monitor_wrap.h | ||
663 | +++ b/monitor_wrap.h | ||
664 | @@ -111,4 +111,8 @@ void *mm_zalloc(struct mm_master *, u_int, u_int); | ||
665 | void mm_zfree(struct mm_master *, void *); | ||
666 | void mm_init_compression(struct mm_master *); | ||
667 | |||
668 | +#ifdef USE_CONSOLEKIT | ||
669 | +char *mm_consolekit_register(struct Session *, const char *); | ||
670 | +#endif /* USE_CONSOLEKIT */ | ||
671 | + | ||
672 | #endif /* _MM_WRAP_H_ */ | ||
673 | diff --git a/session.c b/session.c | ||
674 | index 6f389ac..6250c20 100644 | ||
675 | --- a/session.c | ||
676 | +++ b/session.c | ||
677 | @@ -93,6 +93,7 @@ | ||
678 | #include "kex.h" | ||
679 | #include "monitor_wrap.h" | ||
680 | #include "sftp.h" | ||
681 | +#include "consolekit.h" | ||
682 | |||
683 | #if defined(KRB5) && defined(USE_AFS) | ||
684 | #include <kafs.h> | ||
685 | @@ -1143,6 +1144,9 @@ do_setup_env(Session *s, const char *shell) | ||
686 | #if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN) | ||
687 | char *path = NULL; | ||
688 | #endif | ||
689 | +#ifdef USE_CONSOLEKIT | ||
690 | + const char *ckcookie = NULL; | ||
691 | +#endif /* USE_CONSOLEKIT */ | ||
692 | |||
693 | /* Initialize the environment. */ | ||
694 | envsize = 100; | ||
695 | @@ -1287,6 +1291,11 @@ do_setup_env(Session *s, const char *shell) | ||
696 | child_set_env(&env, &envsize, "KRB5CCNAME", | ||
697 | s->authctxt->krb5_ccname); | ||
698 | #endif | ||
699 | +#ifdef USE_CONSOLEKIT | ||
700 | + ckcookie = PRIVSEP(consolekit_register(s, s->display)); | ||
701 | + if (ckcookie) | ||
702 | + child_set_env(&env, &envsize, "XDG_SESSION_COOKIE", ckcookie); | ||
703 | +#endif /* USE_CONSOLEKIT */ | ||
704 | #ifdef USE_PAM | ||
705 | /* | ||
706 | * Pull in any environment variables that may have | ||
707 | @@ -2350,6 +2359,10 @@ session_pty_cleanup2(Session *s) | ||
708 | |||
709 | debug("session_pty_cleanup: session %d release %s", s->self, s->tty); | ||
710 | |||
711 | +#ifdef USE_CONSOLEKIT | ||
712 | + consolekit_unregister(s); | ||
713 | +#endif /* USE_CONSOLEKIT */ | ||
714 | + | ||
715 | /* Record that the user has logged out. */ | ||
716 | if (s->pid != 0) | ||
717 | record_logout(s->pid, s->tty, s->pw->pw_name); | ||
718 | diff --git a/session.h b/session.h | ||
719 | index ef6593c..a6b6983 100644 | ||
720 | --- a/session.h | ||
721 | +++ b/session.h | ||
722 | @@ -26,6 +26,8 @@ | ||
723 | #ifndef SESSION_H | ||
724 | #define SESSION_H | ||
725 | |||
726 | +struct _CkConnector; | ||
727 | + | ||
728 | #define TTYSZ 64 | ||
729 | typedef struct Session Session; | ||
730 | struct Session { | ||
731 | @@ -61,6 +63,10 @@ struct Session { | ||
732 | char *name; | ||
733 | char *val; | ||
734 | } *env; | ||
735 | + | ||
736 | +#ifdef USE_CONSOLEKIT | ||
737 | + struct _CkConnector *ckc; | ||
738 | +#endif /* USE_CONSOLEKIT */ | ||
739 | }; | ||
740 | |||
741 | void do_authenticated(Authctxt *); | ||
diff --git a/debian/patches/debian-banner.patch b/debian/patches/debian-banner.patch new file mode 100644 index 000000000..ab64cbed5 --- /dev/null +++ b/debian/patches/debian-banner.patch | |||
@@ -0,0 +1,111 @@ | |||
1 | From 114c8a8fb488cbe39507edb75c51198a4b9e8b24 Mon Sep 17 00:00:00 2001 | ||
2 | From: Kees Cook <kees@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:10:06 +0000 | ||
4 | Subject: Add DebianBanner server configuration option | ||
5 | |||
6 | Setting this to "no" causes sshd to omit the Debian revision from its | ||
7 | initial protocol handshake, for those scared by package-versioning.patch. | ||
8 | |||
9 | Bug-Debian: http://bugs.debian.org/562048 | ||
10 | Forwarded: not-needed | ||
11 | Last-Update: 2014-10-07 | ||
12 | |||
13 | Patch-Name: debian-banner.patch | ||
14 | --- | ||
15 | servconf.c | 9 +++++++++ | ||
16 | servconf.h | 2 ++ | ||
17 | sshd.c | 3 ++- | ||
18 | sshd_config.5 | 5 +++++ | ||
19 | 4 files changed, 18 insertions(+), 1 deletion(-) | ||
20 | |||
21 | diff --git a/servconf.c b/servconf.c | ||
22 | index a252487..6c7741a 100644 | ||
23 | --- a/servconf.c | ||
24 | +++ b/servconf.c | ||
25 | @@ -160,6 +160,7 @@ initialize_server_options(ServerOptions *options) | ||
26 | options->ip_qos_interactive = -1; | ||
27 | options->ip_qos_bulk = -1; | ||
28 | options->version_addendum = NULL; | ||
29 | + options->debian_banner = -1; | ||
30 | } | ||
31 | |||
32 | void | ||
33 | @@ -321,6 +322,8 @@ fill_default_server_options(ServerOptions *options) | ||
34 | options->fwd_opts.streamlocal_bind_mask = 0177; | ||
35 | if (options->fwd_opts.streamlocal_bind_unlink == -1) | ||
36 | options->fwd_opts.streamlocal_bind_unlink = 0; | ||
37 | + if (options->debian_banner == -1) | ||
38 | + options->debian_banner = 1; | ||
39 | /* Turn privilege separation on by default */ | ||
40 | if (use_privsep == -1) | ||
41 | use_privsep = PRIVSEP_NOSANDBOX; | ||
42 | @@ -373,6 +376,7 @@ typedef enum { | ||
43 | sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, | ||
44 | sStreamLocalBindMask, sStreamLocalBindUnlink, | ||
45 | sAllowStreamLocalForwarding, | ||
46 | + sDebianBanner, | ||
47 | sDeprecated, sUnsupported | ||
48 | } ServerOpCodes; | ||
49 | |||
50 | @@ -514,6 +518,7 @@ static struct { | ||
51 | { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL }, | ||
52 | { "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL }, | ||
53 | { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL }, | ||
54 | + { "debianbanner", sDebianBanner, SSHCFG_GLOBAL }, | ||
55 | { NULL, sBadOption, 0 } | ||
56 | }; | ||
57 | |||
58 | @@ -1697,6 +1702,10 @@ process_server_config_line(ServerOptions *options, char *line, | ||
59 | intptr = &options->fwd_opts.streamlocal_bind_unlink; | ||
60 | goto parse_flag; | ||
61 | |||
62 | + case sDebianBanner: | ||
63 | + intptr = &options->debian_banner; | ||
64 | + goto parse_int; | ||
65 | + | ||
66 | case sDeprecated: | ||
67 | logit("%s line %d: Deprecated option %s", | ||
68 | filename, linenum, arg); | ||
69 | diff --git a/servconf.h b/servconf.h | ||
70 | index f8265a8..fa48804 100644 | ||
71 | --- a/servconf.h | ||
72 | +++ b/servconf.h | ||
73 | @@ -188,6 +188,8 @@ typedef struct { | ||
74 | |||
75 | u_int num_auth_methods; | ||
76 | char *auth_methods[MAX_AUTH_METHODS]; | ||
77 | + | ||
78 | + int debian_banner; | ||
79 | } ServerOptions; | ||
80 | |||
81 | /* Information about the incoming connection as used by Match */ | ||
82 | diff --git a/sshd.c b/sshd.c | ||
83 | index 1710e71..87331c1 100644 | ||
84 | --- a/sshd.c | ||
85 | +++ b/sshd.c | ||
86 | @@ -443,7 +443,8 @@ sshd_exchange_identification(int sock_in, int sock_out) | ||
87 | } | ||
88 | |||
89 | xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s", | ||
90 | - major, minor, SSH_RELEASE, | ||
91 | + major, minor, | ||
92 | + options.debian_banner ? SSH_RELEASE : SSH_RELEASE_MINIMUM, | ||
93 | *options.version_addendum == '\0' ? "" : " ", | ||
94 | options.version_addendum, newline); | ||
95 | |||
96 | diff --git a/sshd_config.5 b/sshd_config.5 | ||
97 | index 2843048..58997d3 100644 | ||
98 | --- a/sshd_config.5 | ||
99 | +++ b/sshd_config.5 | ||
100 | @@ -447,6 +447,11 @@ or | ||
101 | .Dq no . | ||
102 | The default is | ||
103 | .Dq delayed . | ||
104 | +.It Cm DebianBanner | ||
105 | +Specifies whether the distribution-specified extra version suffix is | ||
106 | +included during initial protocol handshake. | ||
107 | +The default is | ||
108 | +.Dq yes . | ||
109 | .It Cm DenyGroups | ||
110 | This keyword can be followed by a list of group name patterns, separated | ||
111 | by spaces. | ||
diff --git a/debian/patches/debian-config.patch b/debian/patches/debian-config.patch new file mode 100644 index 000000000..f81d731f1 --- /dev/null +++ b/debian/patches/debian-config.patch | |||
@@ -0,0 +1,165 @@ | |||
1 | From 44f0937b56758f662ff388d474213107e3290863 Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:10:18 +0000 | ||
4 | Subject: Various Debian-specific configuration changes | ||
5 | |||
6 | ssh: Enable ForwardX11Trusted, returning to earlier semantics which cause | ||
7 | fewer problems with existing setups (http://bugs.debian.org/237021). | ||
8 | |||
9 | ssh: Set 'SendEnv LANG LC_*' by default (http://bugs.debian.org/264024). | ||
10 | |||
11 | ssh: Enable HashKnownHosts by default to try to limit the spread of ssh | ||
12 | worms. | ||
13 | |||
14 | ssh: Enable GSSAPIAuthentication and disable GSSAPIDelegateCredentials by | ||
15 | default. | ||
16 | |||
17 | sshd: Refer to /usr/share/doc/openssh-server/README.Debian.gz alongside | ||
18 | PermitRootLogin default. | ||
19 | |||
20 | Document all of this, along with several sshd defaults set in | ||
21 | debian/openssh-server.postinst. | ||
22 | |||
23 | Author: Russ Allbery <rra@debian.org> | ||
24 | Forwarded: not-needed | ||
25 | Last-Update: 2014-11-06 | ||
26 | |||
27 | Patch-Name: debian-config.patch | ||
28 | --- | ||
29 | readconf.c | 2 +- | ||
30 | ssh_config | 7 ++++++- | ||
31 | ssh_config.5 | 23 ++++++++++++++++++++++- | ||
32 | sshd_config | 1 + | ||
33 | sshd_config.5 | 29 +++++++++++++++++++++++++++++ | ||
34 | 5 files changed, 59 insertions(+), 3 deletions(-) | ||
35 | |||
36 | diff --git a/readconf.c b/readconf.c | ||
37 | index 0648867..29338b6 100644 | ||
38 | --- a/readconf.c | ||
39 | +++ b/readconf.c | ||
40 | @@ -1681,7 +1681,7 @@ fill_default_options(Options * options) | ||
41 | if (options->forward_x11 == -1) | ||
42 | options->forward_x11 = 0; | ||
43 | if (options->forward_x11_trusted == -1) | ||
44 | - options->forward_x11_trusted = 0; | ||
45 | + options->forward_x11_trusted = 1; | ||
46 | if (options->forward_x11_timeout == -1) | ||
47 | options->forward_x11_timeout = 1200; | ||
48 | if (options->exit_on_forward_failure == -1) | ||
49 | diff --git a/ssh_config b/ssh_config | ||
50 | index 228e5ab..91be1e7 100644 | ||
51 | --- a/ssh_config | ||
52 | +++ b/ssh_config | ||
53 | @@ -17,9 +17,10 @@ | ||
54 | # list of available options, their meanings and defaults, please see the | ||
55 | # ssh_config(5) man page. | ||
56 | |||
57 | -# Host * | ||
58 | +Host * | ||
59 | # ForwardAgent no | ||
60 | # ForwardX11 no | ||
61 | +# ForwardX11Trusted yes | ||
62 | # RhostsRSAAuthentication no | ||
63 | # RSAAuthentication yes | ||
64 | # PasswordAuthentication yes | ||
65 | @@ -48,3 +49,7 @@ | ||
66 | # VisualHostKey no | ||
67 | # ProxyCommand ssh -q -W %h:%p gateway.example.com | ||
68 | # RekeyLimit 1G 1h | ||
69 | + SendEnv LANG LC_ADDRESS LC_COLLATE LC_CTYPE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE LC_TIME LC_ALL | ||
70 | + HashKnownHosts yes | ||
71 | + GSSAPIAuthentication yes | ||
72 | + GSSAPIDelegateCredentials no | ||
73 | diff --git a/ssh_config.5 b/ssh_config.5 | ||
74 | index a1005ba..5985769 100644 | ||
75 | --- a/ssh_config.5 | ||
76 | +++ b/ssh_config.5 | ||
77 | @@ -71,6 +71,26 @@ Since the first obtained value for each parameter is used, more | ||
78 | host-specific declarations should be given near the beginning of the | ||
79 | file, and general defaults at the end. | ||
80 | .Pp | ||
81 | +Note that the Debian | ||
82 | +.Ic openssh-client | ||
83 | +package sets several options as standard in | ||
84 | +.Pa /etc/ssh/ssh_config | ||
85 | +which are not the default in | ||
86 | +.Xr ssh 1 : | ||
87 | +.Pp | ||
88 | +.Bl -bullet -offset indent -compact | ||
89 | +.It | ||
90 | +.Cm SendEnv No LANG Xo | ||
91 | +.No LC_ADDRESS LC_COLLATE LC_CTYPE LC_IDENTIFICATION LC_MEASUREMENT | ||
92 | +.No LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE LC_TIME | ||
93 | +.No LC_ALL | ||
94 | +.Xc | ||
95 | +.It | ||
96 | +.Cm HashKnownHosts No yes | ||
97 | +.It | ||
98 | +.Cm GSSAPIAuthentication No yes | ||
99 | +.El | ||
100 | +.Pp | ||
101 | The configuration file has the following format: | ||
102 | .Pp | ||
103 | Empty lines and lines starting with | ||
104 | @@ -673,7 +693,8 @@ token used for the session will be set to expire after 20 minutes. | ||
105 | Remote clients will be refused access after this time. | ||
106 | .Pp | ||
107 | The default is | ||
108 | -.Dq no . | ||
109 | +.Dq yes | ||
110 | +(Debian-specific). | ||
111 | .Pp | ||
112 | See the X11 SECURITY extension specification for full details on | ||
113 | the restrictions imposed on untrusted clients. | ||
114 | diff --git a/sshd_config b/sshd_config | ||
115 | index d9b8594..4db32f5 100644 | ||
116 | --- a/sshd_config | ||
117 | +++ b/sshd_config | ||
118 | @@ -41,6 +41,7 @@ | ||
119 | # Authentication: | ||
120 | |||
121 | #LoginGraceTime 2m | ||
122 | +# See /usr/share/doc/openssh-server/README.Debian.gz. | ||
123 | #PermitRootLogin yes | ||
124 | #StrictModes yes | ||
125 | #MaxAuthTries 6 | ||
126 | diff --git a/sshd_config.5 b/sshd_config.5 | ||
127 | index 7396b23..09bb5fe 100644 | ||
128 | --- a/sshd_config.5 | ||
129 | +++ b/sshd_config.5 | ||
130 | @@ -57,6 +57,35 @@ Arguments may optionally be enclosed in double quotes | ||
131 | .Pq \&" | ||
132 | in order to represent arguments containing spaces. | ||
133 | .Pp | ||
134 | +Note that the Debian | ||
135 | +.Ic openssh-server | ||
136 | +package sets several options as standard in | ||
137 | +.Pa /etc/ssh/sshd_config | ||
138 | +which are not the default in | ||
139 | +.Xr sshd 8 . | ||
140 | +The exact list depends on whether the package was installed fresh or | ||
141 | +upgraded from various possible previous versions, but includes at least the | ||
142 | +following: | ||
143 | +.Pp | ||
144 | +.Bl -bullet -offset indent -compact | ||
145 | +.It | ||
146 | +.Cm ChallengeResponseAuthentication No no | ||
147 | +.It | ||
148 | +.Cm X11Forwarding No yes | ||
149 | +.It | ||
150 | +.Cm PrintMotd No no | ||
151 | +.It | ||
152 | +.Cm AcceptEnv No LANG Xo | ||
153 | +.No LC_ADDRESS LC_COLLATE LC_CTYPE LC_IDENTIFICATION LC_MEASUREMENT | ||
154 | +.No LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE LC_TIME | ||
155 | +.No LC_ALL | ||
156 | +.Xc | ||
157 | +.It | ||
158 | +.Cm Subsystem No sftp /usr/lib/openssh/sftp-server | ||
159 | +.It | ||
160 | +.Cm UsePAM No yes | ||
161 | +.El | ||
162 | +.Pp | ||
163 | The possible | ||
164 | keywords and their meanings are as follows (note that | ||
165 | keywords are case-insensitive and arguments are case-sensitive): | ||
diff --git a/debian/patches/dnssec-sshfp.patch b/debian/patches/dnssec-sshfp.patch new file mode 100644 index 000000000..0212ea841 --- /dev/null +++ b/debian/patches/dnssec-sshfp.patch | |||
@@ -0,0 +1,94 @@ | |||
1 | From 4ac9937c1d9f1901ab0694114d76e59a138aae96 Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:10:01 +0000 | ||
4 | Subject: Force use of DNSSEC even if "options edns0" isn't in resolv.conf | ||
5 | |||
6 | This allows SSHFP DNS records to be verified if glibc 2.11 is installed. | ||
7 | |||
8 | Origin: vendor, https://cvs.fedoraproject.org/viewvc/F-12/openssh/openssh-5.2p1-edns.patch?revision=1.1&view=markup | ||
9 | Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=572049 | ||
10 | Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=572049 | ||
11 | Last-Update: 2010-04-06 | ||
12 | |||
13 | Patch-Name: dnssec-sshfp.patch | ||
14 | --- | ||
15 | dns.c | 14 +++++++++++++- | ||
16 | openbsd-compat/getrrsetbyname.c | 10 +++++----- | ||
17 | openbsd-compat/getrrsetbyname.h | 3 +++ | ||
18 | 3 files changed, 21 insertions(+), 6 deletions(-) | ||
19 | |||
20 | diff --git a/dns.c b/dns.c | ||
21 | index c4d073c..e5872c1 100644 | ||
22 | --- a/dns.c | ||
23 | +++ b/dns.c | ||
24 | @@ -203,6 +203,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, | ||
25 | { | ||
26 | u_int counter; | ||
27 | int result; | ||
28 | + unsigned int rrset_flags = 0; | ||
29 | struct rrsetinfo *fingerprints = NULL; | ||
30 | |||
31 | u_int8_t hostkey_algorithm; | ||
32 | @@ -226,8 +227,19 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, | ||
33 | return -1; | ||
34 | } | ||
35 | |||
36 | + /* | ||
37 | + * Original getrrsetbyname function, found on OpenBSD for example, | ||
38 | + * doesn't accept any flag and prerequisite for obtaining AD bit in | ||
39 | + * DNS response is set by "options edns0" in resolv.conf. | ||
40 | + * | ||
41 | + * Our version is more clever and use RRSET_FORCE_EDNS0 flag. | ||
42 | + */ | ||
43 | +#ifndef HAVE_GETRRSETBYNAME | ||
44 | + rrset_flags |= RRSET_FORCE_EDNS0; | ||
45 | +#endif | ||
46 | result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, | ||
47 | - DNS_RDATATYPE_SSHFP, 0, &fingerprints); | ||
48 | + DNS_RDATATYPE_SSHFP, rrset_flags, &fingerprints); | ||
49 | + | ||
50 | if (result) { | ||
51 | verbose("DNS lookup error: %s", dns_result_totext(result)); | ||
52 | return -1; | ||
53 | diff --git a/openbsd-compat/getrrsetbyname.c b/openbsd-compat/getrrsetbyname.c | ||
54 | index dc6fe05..e061a29 100644 | ||
55 | --- a/openbsd-compat/getrrsetbyname.c | ||
56 | +++ b/openbsd-compat/getrrsetbyname.c | ||
57 | @@ -209,8 +209,8 @@ getrrsetbyname(const char *hostname, unsigned int rdclass, | ||
58 | goto fail; | ||
59 | } | ||
60 | |||
61 | - /* don't allow flags yet, unimplemented */ | ||
62 | - if (flags) { | ||
63 | + /* Allow RRSET_FORCE_EDNS0 flag only. */ | ||
64 | + if ((flags & !RRSET_FORCE_EDNS0) != 0) { | ||
65 | result = ERRSET_INVAL; | ||
66 | goto fail; | ||
67 | } | ||
68 | @@ -226,9 +226,9 @@ getrrsetbyname(const char *hostname, unsigned int rdclass, | ||
69 | #endif /* DEBUG */ | ||
70 | |||
71 | #ifdef RES_USE_DNSSEC | ||
72 | - /* turn on DNSSEC if EDNS0 is configured */ | ||
73 | - if (_resp->options & RES_USE_EDNS0) | ||
74 | - _resp->options |= RES_USE_DNSSEC; | ||
75 | + /* turn on DNSSEC if required */ | ||
76 | + if (flags & RRSET_FORCE_EDNS0) | ||
77 | + _resp->options |= (RES_USE_EDNS0|RES_USE_DNSSEC); | ||
78 | #endif /* RES_USE_DNSEC */ | ||
79 | |||
80 | /* make query */ | ||
81 | diff --git a/openbsd-compat/getrrsetbyname.h b/openbsd-compat/getrrsetbyname.h | ||
82 | index 1283f55..dbbc85a 100644 | ||
83 | --- a/openbsd-compat/getrrsetbyname.h | ||
84 | +++ b/openbsd-compat/getrrsetbyname.h | ||
85 | @@ -72,6 +72,9 @@ | ||
86 | #ifndef RRSET_VALIDATED | ||
87 | # define RRSET_VALIDATED 1 | ||
88 | #endif | ||
89 | +#ifndef RRSET_FORCE_EDNS0 | ||
90 | +# define RRSET_FORCE_EDNS0 0x0001 | ||
91 | +#endif | ||
92 | |||
93 | /* | ||
94 | * Return codes for getrrsetbyname() | ||
diff --git a/debian/patches/doc-hash-tab-completion.patch b/debian/patches/doc-hash-tab-completion.patch new file mode 100644 index 000000000..8e6cfa575 --- /dev/null +++ b/debian/patches/doc-hash-tab-completion.patch | |||
@@ -0,0 +1,28 @@ | |||
1 | From 2fd0b3814e27d584efa6df92845a7354e7c2de6c Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:10:11 +0000 | ||
4 | Subject: Document that HashKnownHosts may break tab-completion | ||
5 | |||
6 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1727 | ||
7 | Bug-Debian: http://bugs.debian.org/430154 | ||
8 | Last-Update: 2013-09-14 | ||
9 | |||
10 | Patch-Name: doc-hash-tab-completion.patch | ||
11 | --- | ||
12 | ssh_config.5 | 3 +++ | ||
13 | 1 file changed, 3 insertions(+) | ||
14 | |||
15 | diff --git a/ssh_config.5 b/ssh_config.5 | ||
16 | index d68b45a..a1005ba 100644 | ||
17 | --- a/ssh_config.5 | ||
18 | +++ b/ssh_config.5 | ||
19 | @@ -759,6 +759,9 @@ Note that existing names and addresses in known hosts files | ||
20 | will not be converted automatically, | ||
21 | but may be manually hashed using | ||
22 | .Xr ssh-keygen 1 . | ||
23 | +Use of this option may break facilities such as tab-completion that rely | ||
24 | +on being able to read unhashed host names from | ||
25 | +.Pa ~/.ssh/known_hosts . | ||
26 | .It Cm HostbasedAuthentication | ||
27 | Specifies whether to try rhosts based authentication with public key | ||
28 | authentication. | ||
diff --git a/debian/patches/doc-upstart.patch b/debian/patches/doc-upstart.patch new file mode 100644 index 000000000..c1ce1bcae --- /dev/null +++ b/debian/patches/doc-upstart.patch | |||
@@ -0,0 +1,29 @@ | |||
1 | From 252e76b3ad6e83a798e479a2beba5be7000ff85e Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@ubuntu.com> | ||
3 | Date: Sun, 9 Feb 2014 16:10:12 +0000 | ||
4 | Subject: Refer to ssh's Upstart job as well as its init script | ||
5 | |||
6 | Forwarded: not-needed | ||
7 | Last-Update: 2013-09-14 | ||
8 | |||
9 | Patch-Name: doc-upstart.patch | ||
10 | --- | ||
11 | sshd.8 | 5 ++++- | ||
12 | 1 file changed, 4 insertions(+), 1 deletion(-) | ||
13 | |||
14 | diff --git a/sshd.8 b/sshd.8 | ||
15 | index 3538208..f8f9eac 100644 | ||
16 | --- a/sshd.8 | ||
17 | +++ b/sshd.8 | ||
18 | @@ -67,7 +67,10 @@ over an insecure network. | ||
19 | .Nm | ||
20 | listens for connections from clients. | ||
21 | It is normally started at boot from | ||
22 | -.Pa /etc/init.d/ssh . | ||
23 | +.Pa /etc/init.d/ssh | ||
24 | +(or | ||
25 | +.Pa /etc/init/ssh.conf | ||
26 | +on systems using the Upstart init daemon). | ||
27 | It forks a new | ||
28 | daemon for each incoming connection. | ||
29 | The forked daemons handle | ||
diff --git a/debian/patches/gnome-ssh-askpass2-icon.patch b/debian/patches/gnome-ssh-askpass2-icon.patch new file mode 100644 index 000000000..84fe03acc --- /dev/null +++ b/debian/patches/gnome-ssh-askpass2-icon.patch | |||
@@ -0,0 +1,26 @@ | |||
1 | From 1195b028cb9f402633cfdcae6ec34bf63b4ab771 Mon Sep 17 00:00:00 2001 | ||
2 | From: Vincent Untz <vuntz@ubuntu.com> | ||
3 | Date: Sun, 9 Feb 2014 16:10:16 +0000 | ||
4 | Subject: Give the ssh-askpass-gnome window a default icon | ||
5 | |||
6 | Bug-Ubuntu: https://bugs.launchpad.net/bugs/27152 | ||
7 | Last-Update: 2010-02-28 | ||
8 | |||
9 | Patch-Name: gnome-ssh-askpass2-icon.patch | ||
10 | --- | ||
11 | contrib/gnome-ssh-askpass2.c | 2 ++ | ||
12 | 1 file changed, 2 insertions(+) | ||
13 | |||
14 | diff --git a/contrib/gnome-ssh-askpass2.c b/contrib/gnome-ssh-askpass2.c | ||
15 | index 9d97c30..04b3a11 100644 | ||
16 | --- a/contrib/gnome-ssh-askpass2.c | ||
17 | +++ b/contrib/gnome-ssh-askpass2.c | ||
18 | @@ -209,6 +209,8 @@ main(int argc, char **argv) | ||
19 | |||
20 | gtk_init(&argc, &argv); | ||
21 | |||
22 | + gtk_window_set_default_icon_from_file ("/usr/share/pixmaps/ssh-askpass-gnome.png", NULL); | ||
23 | + | ||
24 | if (argc > 1) { | ||
25 | message = g_strjoinv(" ", argv + 1); | ||
26 | } else { | ||
diff --git a/debian/patches/gssapi.patch b/debian/patches/gssapi.patch new file mode 100644 index 000000000..e8cbc1083 --- /dev/null +++ b/debian/patches/gssapi.patch | |||
@@ -0,0 +1,3143 @@ | |||
1 | From 1c1b6fa17982eb622e2c4e8f4a279f2113f57413 Mon Sep 17 00:00:00 2001 | ||
2 | From: Simon Wilkinson <simon@sxw.org.uk> | ||
3 | Date: Sun, 9 Feb 2014 16:09:48 +0000 | ||
4 | Subject: GSSAPI key exchange support | ||
5 | |||
6 | This patch has been rejected upstream: "None of the OpenSSH developers are | ||
7 | in favour of adding this, and this situation has not changed for several | ||
8 | years. This is not a slight on Simon's patch, which is of fine quality, but | ||
9 | just that a) we don't trust GSSAPI implementations that much and b) we don't | ||
10 | like adding new KEX since they are pre-auth attack surface. This one is | ||
11 | particularly scary, since it requires hooks out to typically root-owned | ||
12 | system resources." | ||
13 | |||
14 | However, quite a lot of people rely on this in Debian, and it's better to | ||
15 | have it merged into the main openssh package rather than having separate | ||
16 | -krb5 packages (as we used to have). It seems to have a generally good | ||
17 | security history. | ||
18 | |||
19 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242 | ||
20 | Last-Updated: 2014-10-07 | ||
21 | |||
22 | Patch-Name: gssapi.patch | ||
23 | --- | ||
24 | ChangeLog.gssapi | 113 +++++++++++++++++++ | ||
25 | Makefile.in | 3 +- | ||
26 | auth-krb5.c | 17 ++- | ||
27 | auth2-gss.c | 48 +++++++- | ||
28 | auth2.c | 2 + | ||
29 | clientloop.c | 13 +++ | ||
30 | config.h.in | 6 + | ||
31 | configure | 57 ++++++++++ | ||
32 | configure.ac | 24 ++++ | ||
33 | gss-genr.c | 275 ++++++++++++++++++++++++++++++++++++++++++++- | ||
34 | gss-serv-krb5.c | 85 ++++++++++++-- | ||
35 | gss-serv.c | 221 +++++++++++++++++++++++++++++++----- | ||
36 | kex.c | 16 +++ | ||
37 | kex.h | 14 +++ | ||
38 | kexgssc.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ | ||
39 | kexgsss.c | 290 ++++++++++++++++++++++++++++++++++++++++++++++++ | ||
40 | monitor.c | 108 +++++++++++++++++- | ||
41 | monitor.h | 3 + | ||
42 | monitor_wrap.c | 47 +++++++- | ||
43 | monitor_wrap.h | 4 +- | ||
44 | readconf.c | 42 +++++++ | ||
45 | readconf.h | 5 + | ||
46 | servconf.c | 38 ++++++- | ||
47 | servconf.h | 3 + | ||
48 | ssh-gss.h | 41 ++++++- | ||
49 | ssh_config | 2 + | ||
50 | ssh_config.5 | 34 +++++- | ||
51 | sshconnect2.c | 124 ++++++++++++++++++++- | ||
52 | sshd.c | 110 ++++++++++++++++++ | ||
53 | sshd_config | 2 + | ||
54 | sshd_config.5 | 28 +++++ | ||
55 | sshkey.c | 3 +- | ||
56 | sshkey.h | 1 + | ||
57 | 33 files changed, 2052 insertions(+), 59 deletions(-) | ||
58 | create mode 100644 ChangeLog.gssapi | ||
59 | create mode 100644 kexgssc.c | ||
60 | create mode 100644 kexgsss.c | ||
61 | |||
62 | diff --git a/ChangeLog.gssapi b/ChangeLog.gssapi | ||
63 | new file mode 100644 | ||
64 | index 0000000..f117a33 | ||
65 | --- /dev/null | ||
66 | +++ b/ChangeLog.gssapi | ||
67 | @@ -0,0 +1,113 @@ | ||
68 | +20110101 | ||
69 | + - Finally update for OpenSSH 5.6p1 | ||
70 | + - Add GSSAPIServerIdentity option from Jim Basney | ||
71 | + | ||
72 | +20100308 | ||
73 | + - [ Makefile.in, key.c, key.h ] | ||
74 | + Updates for OpenSSH 5.4p1 | ||
75 | + - [ servconf.c ] | ||
76 | + Include GSSAPI options in the sshd -T configuration dump, and flag | ||
77 | + some older configuration options as being unsupported. Thanks to Colin | ||
78 | + Watson. | ||
79 | + - | ||
80 | + | ||
81 | +20100124 | ||
82 | + - [ sshconnect2.c ] | ||
83 | + Adapt to deal with additional element in Authmethod structure. Thanks to | ||
84 | + Colin Watson | ||
85 | + | ||
86 | +20090615 | ||
87 | + - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c | ||
88 | + sshd.c ] | ||
89 | + Fix issues identified by Greg Hudson following a code review | ||
90 | + Check return value of gss_indicate_mechs | ||
91 | + Protect GSSAPI calls in monitor, so they can only be used if enabled | ||
92 | + Check return values of bignum functions in key exchange | ||
93 | + Use BN_clear_free to clear other side's DH value | ||
94 | + Make ssh_gssapi_id_kex more robust | ||
95 | + Only configure kex table pointers if GSSAPI is enabled | ||
96 | + Don't leak mechanism list, or gss mechanism list | ||
97 | + Cast data.length before printing | ||
98 | + If serverkey isn't provided, use an empty string, rather than NULL | ||
99 | + | ||
100 | +20090201 | ||
101 | + - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h | ||
102 | + ssh_config.5 sshconnet2.c ] | ||
103 | + Add support for the GSSAPIClientIdentity option, which allows the user | ||
104 | + to specify which GSSAPI identity to use to contact a given server | ||
105 | + | ||
106 | +20080404 | ||
107 | + - [ gss-serv.c ] | ||
108 | + Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow | ||
109 | + been omitted from a previous version of this patch. Reported by Borislav | ||
110 | + Stoichkov | ||
111 | + | ||
112 | +20070317 | ||
113 | + - [ gss-serv-krb5.c ] | ||
114 | + Remove C99ism, where new_ccname was being declared in the middle of a | ||
115 | + function | ||
116 | + | ||
117 | +20061220 | ||
118 | + - [ servconf.c ] | ||
119 | + Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and | ||
120 | + documented, behaviour. Reported by Dan Watson. | ||
121 | + | ||
122 | +20060910 | ||
123 | + - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c | ||
124 | + ssh-gss.h ] | ||
125 | + add support for gss-group14-sha1 key exchange mechanisms | ||
126 | + - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ] | ||
127 | + Add GSSAPIStrictAcceptorCheck option to allow the disabling of | ||
128 | + acceptor principal checking on multi-homed machines. | ||
129 | + <Bugzilla #928> | ||
130 | + - [ sshd_config ssh_config ] | ||
131 | + Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample | ||
132 | + configuration files | ||
133 | + - [ kexgss.c kegsss.c sshconnect2.c sshd.c ] | ||
134 | + Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf() | ||
135 | + Limit length of error messages displayed by client | ||
136 | + | ||
137 | +20060909 | ||
138 | + - [ gss-genr.c gss-serv.c ] | ||
139 | + move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server | ||
140 | + only, where they belong | ||
141 | + <Bugzilla #1225> | ||
142 | + | ||
143 | +20060829 | ||
144 | + - [ gss-serv-krb5.c ] | ||
145 | + Fix CCAPI credentials cache name when creating KRB5CCNAME environment | ||
146 | + variable | ||
147 | + | ||
148 | +20060828 | ||
149 | + - [ gss-genr.c ] | ||
150 | + Avoid Heimdal context freeing problem | ||
151 | + <Fixed upstream 20060829> | ||
152 | + | ||
153 | +20060818 | ||
154 | + - [ gss-genr.c ssh-gss.h sshconnect2.c ] | ||
155 | + Make sure that SPENGO is disabled | ||
156 | + <Bugzilla #1218 - Fixed upstream 20060818> | ||
157 | + | ||
158 | +20060421 | ||
159 | + - [ gssgenr.c, sshconnect2.c ] | ||
160 | + a few type changes (signed versus unsigned, int versus size_t) to | ||
161 | + fix compiler errors/warnings | ||
162 | + (from jbasney AT ncsa.uiuc.edu) | ||
163 | + - [ kexgssc.c, sshconnect2.c ] | ||
164 | + fix uninitialized variable warnings | ||
165 | + (from jbasney AT ncsa.uiuc.edu) | ||
166 | + - [ gssgenr.c ] | ||
167 | + pass oid to gss_display_status (helpful when using GSSAPI mechglue) | ||
168 | + (from jbasney AT ncsa.uiuc.edu) | ||
169 | + <Bugzilla #1220 > | ||
170 | + - [ gss-serv-krb5.c ] | ||
171 | + #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H | ||
172 | + (from jbasney AT ncsa.uiuc.edu) | ||
173 | + <Fixed upstream 20060304> | ||
174 | + - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c | ||
175 | + add client-side GssapiKeyExchange option | ||
176 | + (from jbasney AT ncsa.uiuc.edu) | ||
177 | + - [ sshconnect2.c ] | ||
178 | + add support for GssapiTrustDns option for gssapi-with-mic | ||
179 | + (from jbasney AT ncsa.uiuc.edu) | ||
180 | + <gssapi-with-mic support is Bugzilla #1008> | ||
181 | diff --git a/Makefile.in b/Makefile.in | ||
182 | index 06be3d5..086d8dd 100644 | ||
183 | --- a/Makefile.in | ||
184 | +++ b/Makefile.in | ||
185 | @@ -82,6 +82,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ | ||
186 | atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ | ||
187 | monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ | ||
188 | kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ | ||
189 | + kexgssc.o \ | ||
190 | msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ | ||
191 | ssh-pkcs11.o krl.o smult_curve25519_ref.o \ | ||
192 | kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ | ||
193 | @@ -101,7 +102,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ | ||
194 | auth2-none.o auth2-passwd.o auth2-pubkey.o \ | ||
195 | monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \ | ||
196 | kexc25519s.o auth-krb5.o \ | ||
197 | - auth2-gss.o gss-serv.o gss-serv-krb5.o \ | ||
198 | + auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ | ||
199 | loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ | ||
200 | sftp-server.o sftp-common.o \ | ||
201 | roaming_common.o roaming_serv.o \ | ||
202 | diff --git a/auth-krb5.c b/auth-krb5.c | ||
203 | index 0089b18..ec47869 100644 | ||
204 | --- a/auth-krb5.c | ||
205 | +++ b/auth-krb5.c | ||
206 | @@ -183,8 +183,13 @@ auth_krb5_password(Authctxt *authctxt, const char *password) | ||
207 | |||
208 | len = strlen(authctxt->krb5_ticket_file) + 6; | ||
209 | authctxt->krb5_ccname = xmalloc(len); | ||
210 | +#ifdef USE_CCAPI | ||
211 | + snprintf(authctxt->krb5_ccname, len, "API:%s", | ||
212 | + authctxt->krb5_ticket_file); | ||
213 | +#else | ||
214 | snprintf(authctxt->krb5_ccname, len, "FILE:%s", | ||
215 | authctxt->krb5_ticket_file); | ||
216 | +#endif | ||
217 | |||
218 | #ifdef USE_PAM | ||
219 | if (options.use_pam) | ||
220 | @@ -241,15 +246,22 @@ krb5_cleanup_proc(Authctxt *authctxt) | ||
221 | #ifndef HEIMDAL | ||
222 | krb5_error_code | ||
223 | ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { | ||
224 | - int tmpfd, ret, oerrno; | ||
225 | + int ret, oerrno; | ||
226 | char ccname[40]; | ||
227 | mode_t old_umask; | ||
228 | +#ifdef USE_CCAPI | ||
229 | + char cctemplate[] = "API:krb5cc_%d"; | ||
230 | +#else | ||
231 | + char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX"; | ||
232 | + int tmpfd; | ||
233 | +#endif | ||
234 | |||
235 | ret = snprintf(ccname, sizeof(ccname), | ||
236 | - "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); | ||
237 | + cctemplate, geteuid()); | ||
238 | if (ret < 0 || (size_t)ret >= sizeof(ccname)) | ||
239 | return ENOMEM; | ||
240 | |||
241 | +#ifndef USE_CCAPI | ||
242 | old_umask = umask(0177); | ||
243 | tmpfd = mkstemp(ccname + strlen("FILE:")); | ||
244 | oerrno = errno; | ||
245 | @@ -266,6 +278,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { | ||
246 | return oerrno; | ||
247 | } | ||
248 | close(tmpfd); | ||
249 | +#endif | ||
250 | |||
251 | return (krb5_cc_resolve(ctx, ccname, ccache)); | ||
252 | } | ||
253 | diff --git a/auth2-gss.c b/auth2-gss.c | ||
254 | index 447f896..284f364 100644 | ||
255 | --- a/auth2-gss.c | ||
256 | +++ b/auth2-gss.c | ||
257 | @@ -1,7 +1,7 @@ | ||
258 | /* $OpenBSD: auth2-gss.c,v 1.21 2014/02/26 20:28:44 djm Exp $ */ | ||
259 | |||
260 | /* | ||
261 | - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | ||
262 | + * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. | ||
263 | * | ||
264 | * Redistribution and use in source and binary forms, with or without | ||
265 | * modification, are permitted provided that the following conditions | ||
266 | @@ -53,6 +53,40 @@ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); | ||
267 | static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); | ||
268 | static void input_gssapi_errtok(int, u_int32_t, void *); | ||
269 | |||
270 | +/* | ||
271 | + * The 'gssapi_keyex' userauth mechanism. | ||
272 | + */ | ||
273 | +static int | ||
274 | +userauth_gsskeyex(Authctxt *authctxt) | ||
275 | +{ | ||
276 | + int authenticated = 0; | ||
277 | + Buffer b; | ||
278 | + gss_buffer_desc mic, gssbuf; | ||
279 | + u_int len; | ||
280 | + | ||
281 | + mic.value = packet_get_string(&len); | ||
282 | + mic.length = len; | ||
283 | + | ||
284 | + packet_check_eom(); | ||
285 | + | ||
286 | + ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service, | ||
287 | + "gssapi-keyex"); | ||
288 | + | ||
289 | + gssbuf.value = buffer_ptr(&b); | ||
290 | + gssbuf.length = buffer_len(&b); | ||
291 | + | ||
292 | + /* gss_kex_context is NULL with privsep, so we can't check it here */ | ||
293 | + if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, | ||
294 | + &gssbuf, &mic)))) | ||
295 | + authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, | ||
296 | + authctxt->pw)); | ||
297 | + | ||
298 | + buffer_free(&b); | ||
299 | + free(mic.value); | ||
300 | + | ||
301 | + return (authenticated); | ||
302 | +} | ||
303 | + | ||
304 | /* | ||
305 | * We only support those mechanisms that we know about (ie ones that we know | ||
306 | * how to check local user kuserok and the like) | ||
307 | @@ -236,7 +270,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) | ||
308 | |||
309 | packet_check_eom(); | ||
310 | |||
311 | - authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); | ||
312 | + authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, | ||
313 | + authctxt->pw)); | ||
314 | |||
315 | authctxt->postponed = 0; | ||
316 | dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); | ||
317 | @@ -271,7 +306,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) | ||
318 | gssbuf.length = buffer_len(&b); | ||
319 | |||
320 | if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) | ||
321 | - authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); | ||
322 | + authenticated = | ||
323 | + PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw)); | ||
324 | else | ||
325 | logit("GSSAPI MIC check failed"); | ||
326 | |||
327 | @@ -286,6 +322,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) | ||
328 | userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL); | ||
329 | } | ||
330 | |||
331 | +Authmethod method_gsskeyex = { | ||
332 | + "gssapi-keyex", | ||
333 | + userauth_gsskeyex, | ||
334 | + &options.gss_authentication | ||
335 | +}; | ||
336 | + | ||
337 | Authmethod method_gssapi = { | ||
338 | "gssapi-with-mic", | ||
339 | userauth_gssapi, | ||
340 | diff --git a/auth2.c b/auth2.c | ||
341 | index d9b440a..2f0d565 100644 | ||
342 | --- a/auth2.c | ||
343 | +++ b/auth2.c | ||
344 | @@ -70,6 +70,7 @@ extern Authmethod method_passwd; | ||
345 | extern Authmethod method_kbdint; | ||
346 | extern Authmethod method_hostbased; | ||
347 | #ifdef GSSAPI | ||
348 | +extern Authmethod method_gsskeyex; | ||
349 | extern Authmethod method_gssapi; | ||
350 | #endif | ||
351 | |||
352 | @@ -77,6 +78,7 @@ Authmethod *authmethods[] = { | ||
353 | &method_none, | ||
354 | &method_pubkey, | ||
355 | #ifdef GSSAPI | ||
356 | + &method_gsskeyex, | ||
357 | &method_gssapi, | ||
358 | #endif | ||
359 | &method_passwd, | ||
360 | diff --git a/clientloop.c b/clientloop.c | ||
361 | index 397c965..f9175e3 100644 | ||
362 | --- a/clientloop.c | ||
363 | +++ b/clientloop.c | ||
364 | @@ -111,6 +111,10 @@ | ||
365 | #include "msg.h" | ||
366 | #include "roaming.h" | ||
367 | |||
368 | +#ifdef GSSAPI | ||
369 | +#include "ssh-gss.h" | ||
370 | +#endif | ||
371 | + | ||
372 | /* import options */ | ||
373 | extern Options options; | ||
374 | |||
375 | @@ -1596,6 +1600,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | ||
376 | /* Do channel operations unless rekeying in progress. */ | ||
377 | if (!rekeying) { | ||
378 | channel_after_select(readset, writeset); | ||
379 | + | ||
380 | +#ifdef GSSAPI | ||
381 | + if (options.gss_renewal_rekey && | ||
382 | + ssh_gssapi_credentials_updated(NULL)) { | ||
383 | + debug("credentials updated - forcing rekey"); | ||
384 | + need_rekeying = 1; | ||
385 | + } | ||
386 | +#endif | ||
387 | + | ||
388 | if (need_rekeying || packet_need_rekeying()) { | ||
389 | debug("need rekeying"); | ||
390 | xxx_kex->done = 0; | ||
391 | diff --git a/config.h.in b/config.h.in | ||
392 | index 16d6206..a9a8b7a 100644 | ||
393 | --- a/config.h.in | ||
394 | +++ b/config.h.in | ||
395 | @@ -1622,6 +1622,9 @@ | ||
396 | /* Use btmp to log bad logins */ | ||
397 | #undef USE_BTMP | ||
398 | |||
399 | +/* platform uses an in-memory credentials cache */ | ||
400 | +#undef USE_CCAPI | ||
401 | + | ||
402 | /* Use libedit for sftp */ | ||
403 | #undef USE_LIBEDIT | ||
404 | |||
405 | @@ -1637,6 +1640,9 @@ | ||
406 | /* Use PIPES instead of a socketpair() */ | ||
407 | #undef USE_PIPES | ||
408 | |||
409 | +/* platform has the Security Authorization Session API */ | ||
410 | +#undef USE_SECURITY_SESSION_API | ||
411 | + | ||
412 | /* Define if you have Solaris process contracts */ | ||
413 | #undef USE_SOLARIS_PROCESS_CONTRACTS | ||
414 | |||
415 | diff --git a/configure b/configure | ||
416 | index 6815388..ea5f200 100755 | ||
417 | --- a/configure | ||
418 | +++ b/configure | ||
419 | @@ -7168,6 +7168,63 @@ $as_echo "#define SSH_TUN_COMPAT_AF 1" >>confdefs.h | ||
420 | |||
421 | $as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h | ||
422 | |||
423 | + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have the Security Authorization Session API" >&5 | ||
424 | +$as_echo_n "checking if we have the Security Authorization Session API... " >&6; } | ||
425 | + cat confdefs.h - <<_ACEOF >conftest.$ac_ext | ||
426 | +/* end confdefs.h. */ | ||
427 | +#include <Security/AuthSession.h> | ||
428 | +int | ||
429 | +main () | ||
430 | +{ | ||
431 | +SessionCreate(0, 0); | ||
432 | + ; | ||
433 | + return 0; | ||
434 | +} | ||
435 | +_ACEOF | ||
436 | +if ac_fn_c_try_compile "$LINENO"; then : | ||
437 | + ac_cv_use_security_session_api="yes" | ||
438 | + | ||
439 | +$as_echo "#define USE_SECURITY_SESSION_API 1" >>confdefs.h | ||
440 | + | ||
441 | + LIBS="$LIBS -framework Security" | ||
442 | + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 | ||
443 | +$as_echo "yes" >&6; } | ||
444 | +else | ||
445 | + ac_cv_use_security_session_api="no" | ||
446 | + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 | ||
447 | +$as_echo "no" >&6; } | ||
448 | +fi | ||
449 | +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext | ||
450 | + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have an in-memory credentials cache" >&5 | ||
451 | +$as_echo_n "checking if we have an in-memory credentials cache... " >&6; } | ||
452 | + cat confdefs.h - <<_ACEOF >conftest.$ac_ext | ||
453 | +/* end confdefs.h. */ | ||
454 | +#include <Kerberos/Kerberos.h> | ||
455 | +int | ||
456 | +main () | ||
457 | +{ | ||
458 | +cc_context_t c; | ||
459 | + (void) cc_initialize (&c, 0, NULL, NULL); | ||
460 | + ; | ||
461 | + return 0; | ||
462 | +} | ||
463 | +_ACEOF | ||
464 | +if ac_fn_c_try_compile "$LINENO"; then : | ||
465 | + | ||
466 | +$as_echo "#define USE_CCAPI 1" >>confdefs.h | ||
467 | + | ||
468 | + LIBS="$LIBS -framework Security" | ||
469 | + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 | ||
470 | +$as_echo "yes" >&6; } | ||
471 | + if test "x$ac_cv_use_security_session_api" = "xno"; then | ||
472 | + as_fn_error $? "*** Need a security framework to use the credentials cache API ***" "$LINENO" 5 | ||
473 | + fi | ||
474 | +else | ||
475 | + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 | ||
476 | +$as_echo "no" >&6; } | ||
477 | + | ||
478 | +fi | ||
479 | +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext | ||
480 | |||
481 | ac_fn_c_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default" | ||
482 | if test "x$ac_cv_have_decl_AU_IPv4" = xyes; then : | ||
483 | diff --git a/configure.ac b/configure.ac | ||
484 | index 67c4486..90e81e1 100644 | ||
485 | --- a/configure.ac | ||
486 | +++ b/configure.ac | ||
487 | @@ -584,6 +584,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) | ||
488 | [Use tunnel device compatibility to OpenBSD]) | ||
489 | AC_DEFINE([SSH_TUN_PREPEND_AF], [1], | ||
490 | [Prepend the address family to IP tunnel traffic]) | ||
491 | + AC_MSG_CHECKING([if we have the Security Authorization Session API]) | ||
492 | + AC_TRY_COMPILE([#include <Security/AuthSession.h>], | ||
493 | + [SessionCreate(0, 0);], | ||
494 | + [ac_cv_use_security_session_api="yes" | ||
495 | + AC_DEFINE([USE_SECURITY_SESSION_API], [1], | ||
496 | + [platform has the Security Authorization Session API]) | ||
497 | + LIBS="$LIBS -framework Security" | ||
498 | + AC_MSG_RESULT([yes])], | ||
499 | + [ac_cv_use_security_session_api="no" | ||
500 | + AC_MSG_RESULT([no])]) | ||
501 | + AC_MSG_CHECKING([if we have an in-memory credentials cache]) | ||
502 | + AC_TRY_COMPILE( | ||
503 | + [#include <Kerberos/Kerberos.h>], | ||
504 | + [cc_context_t c; | ||
505 | + (void) cc_initialize (&c, 0, NULL, NULL);], | ||
506 | + [AC_DEFINE([USE_CCAPI], [1], | ||
507 | + [platform uses an in-memory credentials cache]) | ||
508 | + LIBS="$LIBS -framework Security" | ||
509 | + AC_MSG_RESULT([yes]) | ||
510 | + if test "x$ac_cv_use_security_session_api" = "xno"; then | ||
511 | + AC_MSG_ERROR([*** Need a security framework to use the credentials cache API ***]) | ||
512 | + fi], | ||
513 | + [AC_MSG_RESULT([no])] | ||
514 | + ) | ||
515 | m4_pattern_allow([AU_IPv]) | ||
516 | AC_CHECK_DECL([AU_IPv4], [], | ||
517 | AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records]) | ||
518 | diff --git a/gss-genr.c b/gss-genr.c | ||
519 | index b39281b..1e569ad 100644 | ||
520 | --- a/gss-genr.c | ||
521 | +++ b/gss-genr.c | ||
522 | @@ -1,7 +1,7 @@ | ||
523 | /* $OpenBSD: gss-genr.c,v 1.22 2013/11/08 00:39:15 djm Exp $ */ | ||
524 | |||
525 | /* | ||
526 | - * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. | ||
527 | + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. | ||
528 | * | ||
529 | * Redistribution and use in source and binary forms, with or without | ||
530 | * modification, are permitted provided that the following conditions | ||
531 | @@ -39,12 +39,167 @@ | ||
532 | #include "buffer.h" | ||
533 | #include "log.h" | ||
534 | #include "ssh2.h" | ||
535 | +#include "cipher.h" | ||
536 | +#include "key.h" | ||
537 | +#include "kex.h" | ||
538 | +#include <openssl/evp.h> | ||
539 | |||
540 | #include "ssh-gss.h" | ||
541 | |||
542 | extern u_char *session_id2; | ||
543 | extern u_int session_id2_len; | ||
544 | |||
545 | +typedef struct { | ||
546 | + char *encoded; | ||
547 | + gss_OID oid; | ||
548 | +} ssh_gss_kex_mapping; | ||
549 | + | ||
550 | +/* | ||
551 | + * XXX - It would be nice to find a more elegant way of handling the | ||
552 | + * XXX passing of the key exchange context to the userauth routines | ||
553 | + */ | ||
554 | + | ||
555 | +Gssctxt *gss_kex_context = NULL; | ||
556 | + | ||
557 | +static ssh_gss_kex_mapping *gss_enc2oid = NULL; | ||
558 | + | ||
559 | +int | ||
560 | +ssh_gssapi_oid_table_ok(void) { | ||
561 | + return (gss_enc2oid != NULL); | ||
562 | +} | ||
563 | + | ||
564 | +/* | ||
565 | + * Return a list of the gss-group1-sha1 mechanisms supported by this program | ||
566 | + * | ||
567 | + * We test mechanisms to ensure that we can use them, to avoid starting | ||
568 | + * a key exchange with a bad mechanism | ||
569 | + */ | ||
570 | + | ||
571 | +char * | ||
572 | +ssh_gssapi_client_mechanisms(const char *host, const char *client) { | ||
573 | + gss_OID_set gss_supported; | ||
574 | + OM_uint32 min_status; | ||
575 | + | ||
576 | + if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported))) | ||
577 | + return NULL; | ||
578 | + | ||
579 | + return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, | ||
580 | + host, client)); | ||
581 | +} | ||
582 | + | ||
583 | +char * | ||
584 | +ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, | ||
585 | + const char *host, const char *client) { | ||
586 | + Buffer buf; | ||
587 | + size_t i; | ||
588 | + int oidpos, enclen; | ||
589 | + char *mechs, *encoded; | ||
590 | + u_char digest[EVP_MAX_MD_SIZE]; | ||
591 | + char deroid[2]; | ||
592 | + const EVP_MD *evp_md = EVP_md5(); | ||
593 | + EVP_MD_CTX md; | ||
594 | + | ||
595 | + if (gss_enc2oid != NULL) { | ||
596 | + for (i = 0; gss_enc2oid[i].encoded != NULL; i++) | ||
597 | + free(gss_enc2oid[i].encoded); | ||
598 | + free(gss_enc2oid); | ||
599 | + } | ||
600 | + | ||
601 | + gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) * | ||
602 | + (gss_supported->count + 1)); | ||
603 | + | ||
604 | + buffer_init(&buf); | ||
605 | + | ||
606 | + oidpos = 0; | ||
607 | + for (i = 0; i < gss_supported->count; i++) { | ||
608 | + if (gss_supported->elements[i].length < 128 && | ||
609 | + (*check)(NULL, &(gss_supported->elements[i]), host, client)) { | ||
610 | + | ||
611 | + deroid[0] = SSH_GSS_OIDTYPE; | ||
612 | + deroid[1] = gss_supported->elements[i].length; | ||
613 | + | ||
614 | + EVP_DigestInit(&md, evp_md); | ||
615 | + EVP_DigestUpdate(&md, deroid, 2); | ||
616 | + EVP_DigestUpdate(&md, | ||
617 | + gss_supported->elements[i].elements, | ||
618 | + gss_supported->elements[i].length); | ||
619 | + EVP_DigestFinal(&md, digest, NULL); | ||
620 | + | ||
621 | + encoded = xmalloc(EVP_MD_size(evp_md) * 2); | ||
622 | + enclen = __b64_ntop(digest, EVP_MD_size(evp_md), | ||
623 | + encoded, EVP_MD_size(evp_md) * 2); | ||
624 | + | ||
625 | + if (oidpos != 0) | ||
626 | + buffer_put_char(&buf, ','); | ||
627 | + | ||
628 | + buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, | ||
629 | + sizeof(KEX_GSS_GEX_SHA1_ID) - 1); | ||
630 | + buffer_append(&buf, encoded, enclen); | ||
631 | + buffer_put_char(&buf, ','); | ||
632 | + buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, | ||
633 | + sizeof(KEX_GSS_GRP1_SHA1_ID) - 1); | ||
634 | + buffer_append(&buf, encoded, enclen); | ||
635 | + buffer_put_char(&buf, ','); | ||
636 | + buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID, | ||
637 | + sizeof(KEX_GSS_GRP14_SHA1_ID) - 1); | ||
638 | + buffer_append(&buf, encoded, enclen); | ||
639 | + | ||
640 | + gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); | ||
641 | + gss_enc2oid[oidpos].encoded = encoded; | ||
642 | + oidpos++; | ||
643 | + } | ||
644 | + } | ||
645 | + gss_enc2oid[oidpos].oid = NULL; | ||
646 | + gss_enc2oid[oidpos].encoded = NULL; | ||
647 | + | ||
648 | + buffer_put_char(&buf, '\0'); | ||
649 | + | ||
650 | + mechs = xmalloc(buffer_len(&buf)); | ||
651 | + buffer_get(&buf, mechs, buffer_len(&buf)); | ||
652 | + buffer_free(&buf); | ||
653 | + | ||
654 | + if (strlen(mechs) == 0) { | ||
655 | + free(mechs); | ||
656 | + mechs = NULL; | ||
657 | + } | ||
658 | + | ||
659 | + return (mechs); | ||
660 | +} | ||
661 | + | ||
662 | +gss_OID | ||
663 | +ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) { | ||
664 | + int i = 0; | ||
665 | + | ||
666 | + switch (kex_type) { | ||
667 | + case KEX_GSS_GRP1_SHA1: | ||
668 | + if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID)) | ||
669 | + return GSS_C_NO_OID; | ||
670 | + name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1; | ||
671 | + break; | ||
672 | + case KEX_GSS_GRP14_SHA1: | ||
673 | + if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID)) | ||
674 | + return GSS_C_NO_OID; | ||
675 | + name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1; | ||
676 | + break; | ||
677 | + case KEX_GSS_GEX_SHA1: | ||
678 | + if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID)) | ||
679 | + return GSS_C_NO_OID; | ||
680 | + name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1; | ||
681 | + break; | ||
682 | + default: | ||
683 | + return GSS_C_NO_OID; | ||
684 | + } | ||
685 | + | ||
686 | + while (gss_enc2oid[i].encoded != NULL && | ||
687 | + strcmp(name, gss_enc2oid[i].encoded) != 0) | ||
688 | + i++; | ||
689 | + | ||
690 | + if (gss_enc2oid[i].oid != NULL && ctx != NULL) | ||
691 | + ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid); | ||
692 | + | ||
693 | + return gss_enc2oid[i].oid; | ||
694 | +} | ||
695 | + | ||
696 | /* Check that the OID in a data stream matches that in the context */ | ||
697 | int | ||
698 | ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) | ||
699 | @@ -197,7 +352,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, | ||
700 | } | ||
701 | |||
702 | ctx->major = gss_init_sec_context(&ctx->minor, | ||
703 | - GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, | ||
704 | + ctx->client_creds, &ctx->context, ctx->name, ctx->oid, | ||
705 | GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, | ||
706 | 0, NULL, recv_tok, NULL, send_tok, flags, NULL); | ||
707 | |||
708 | @@ -227,8 +382,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) | ||
709 | } | ||
710 | |||
711 | OM_uint32 | ||
712 | +ssh_gssapi_client_identity(Gssctxt *ctx, const char *name) | ||
713 | +{ | ||
714 | + gss_buffer_desc gssbuf; | ||
715 | + gss_name_t gssname; | ||
716 | + OM_uint32 status; | ||
717 | + gss_OID_set oidset; | ||
718 | + | ||
719 | + gssbuf.value = (void *) name; | ||
720 | + gssbuf.length = strlen(gssbuf.value); | ||
721 | + | ||
722 | + gss_create_empty_oid_set(&status, &oidset); | ||
723 | + gss_add_oid_set_member(&status, ctx->oid, &oidset); | ||
724 | + | ||
725 | + ctx->major = gss_import_name(&ctx->minor, &gssbuf, | ||
726 | + GSS_C_NT_USER_NAME, &gssname); | ||
727 | + | ||
728 | + if (!ctx->major) | ||
729 | + ctx->major = gss_acquire_cred(&ctx->minor, | ||
730 | + gssname, 0, oidset, GSS_C_INITIATE, | ||
731 | + &ctx->client_creds, NULL, NULL); | ||
732 | + | ||
733 | + gss_release_name(&status, &gssname); | ||
734 | + gss_release_oid_set(&status, &oidset); | ||
735 | + | ||
736 | + if (ctx->major) | ||
737 | + ssh_gssapi_error(ctx); | ||
738 | + | ||
739 | + return(ctx->major); | ||
740 | +} | ||
741 | + | ||
742 | +OM_uint32 | ||
743 | ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) | ||
744 | { | ||
745 | + if (ctx == NULL) | ||
746 | + return -1; | ||
747 | + | ||
748 | if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, | ||
749 | GSS_C_QOP_DEFAULT, buffer, hash))) | ||
750 | ssh_gssapi_error(ctx); | ||
751 | @@ -236,6 +425,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) | ||
752 | return (ctx->major); | ||
753 | } | ||
754 | |||
755 | +/* Priviledged when used by server */ | ||
756 | +OM_uint32 | ||
757 | +ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) | ||
758 | +{ | ||
759 | + if (ctx == NULL) | ||
760 | + return -1; | ||
761 | + | ||
762 | + ctx->major = gss_verify_mic(&ctx->minor, ctx->context, | ||
763 | + gssbuf, gssmic, NULL); | ||
764 | + | ||
765 | + return (ctx->major); | ||
766 | +} | ||
767 | + | ||
768 | void | ||
769 | ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, | ||
770 | const char *context) | ||
771 | @@ -249,11 +451,16 @@ ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, | ||
772 | } | ||
773 | |||
774 | int | ||
775 | -ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) | ||
776 | +ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host, | ||
777 | + const char *client) | ||
778 | { | ||
779 | gss_buffer_desc token = GSS_C_EMPTY_BUFFER; | ||
780 | OM_uint32 major, minor; | ||
781 | gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; | ||
782 | + Gssctxt *intctx = NULL; | ||
783 | + | ||
784 | + if (ctx == NULL) | ||
785 | + ctx = &intctx; | ||
786 | |||
787 | /* RFC 4462 says we MUST NOT do SPNEGO */ | ||
788 | if (oid->length == spnego_oid.length && | ||
789 | @@ -263,6 +470,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) | ||
790 | ssh_gssapi_build_ctx(ctx); | ||
791 | ssh_gssapi_set_oid(*ctx, oid); | ||
792 | major = ssh_gssapi_import_name(*ctx, host); | ||
793 | + | ||
794 | + if (!GSS_ERROR(major) && client) | ||
795 | + major = ssh_gssapi_client_identity(*ctx, client); | ||
796 | + | ||
797 | if (!GSS_ERROR(major)) { | ||
798 | major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, | ||
799 | NULL); | ||
800 | @@ -272,10 +483,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) | ||
801 | GSS_C_NO_BUFFER); | ||
802 | } | ||
803 | |||
804 | - if (GSS_ERROR(major)) | ||
805 | + if (GSS_ERROR(major) || intctx != NULL) | ||
806 | ssh_gssapi_delete_ctx(ctx); | ||
807 | |||
808 | return (!GSS_ERROR(major)); | ||
809 | } | ||
810 | |||
811 | +int | ||
812 | +ssh_gssapi_credentials_updated(Gssctxt *ctxt) { | ||
813 | + static gss_name_t saved_name = GSS_C_NO_NAME; | ||
814 | + static OM_uint32 saved_lifetime = 0; | ||
815 | + static gss_OID saved_mech = GSS_C_NO_OID; | ||
816 | + static gss_name_t name; | ||
817 | + static OM_uint32 last_call = 0; | ||
818 | + OM_uint32 lifetime, now, major, minor; | ||
819 | + int equal; | ||
820 | + | ||
821 | + now = time(NULL); | ||
822 | + | ||
823 | + if (ctxt) { | ||
824 | + debug("Rekey has happened - updating saved versions"); | ||
825 | + | ||
826 | + if (saved_name != GSS_C_NO_NAME) | ||
827 | + gss_release_name(&minor, &saved_name); | ||
828 | + | ||
829 | + major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, | ||
830 | + &saved_name, &saved_lifetime, NULL, NULL); | ||
831 | + | ||
832 | + if (!GSS_ERROR(major)) { | ||
833 | + saved_mech = ctxt->oid; | ||
834 | + saved_lifetime+= now; | ||
835 | + } else { | ||
836 | + /* Handle the error */ | ||
837 | + } | ||
838 | + return 0; | ||
839 | + } | ||
840 | + | ||
841 | + if (now - last_call < 10) | ||
842 | + return 0; | ||
843 | + | ||
844 | + last_call = now; | ||
845 | + | ||
846 | + if (saved_mech == GSS_C_NO_OID) | ||
847 | + return 0; | ||
848 | + | ||
849 | + major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, | ||
850 | + &name, &lifetime, NULL, NULL); | ||
851 | + if (major == GSS_S_CREDENTIALS_EXPIRED) | ||
852 | + return 0; | ||
853 | + else if (GSS_ERROR(major)) | ||
854 | + return 0; | ||
855 | + | ||
856 | + major = gss_compare_name(&minor, saved_name, name, &equal); | ||
857 | + gss_release_name(&minor, &name); | ||
858 | + if (GSS_ERROR(major)) | ||
859 | + return 0; | ||
860 | + | ||
861 | + if (equal && (saved_lifetime < lifetime + now - 10)) | ||
862 | + return 1; | ||
863 | + | ||
864 | + return 0; | ||
865 | +} | ||
866 | + | ||
867 | #endif /* GSSAPI */ | ||
868 | diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c | ||
869 | index 795992d..fd8b371 100644 | ||
870 | --- a/gss-serv-krb5.c | ||
871 | +++ b/gss-serv-krb5.c | ||
872 | @@ -1,7 +1,7 @@ | ||
873 | /* $OpenBSD: gss-serv-krb5.c,v 1.8 2013/07/20 01:55:13 djm Exp $ */ | ||
874 | |||
875 | /* | ||
876 | - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | ||
877 | + * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. | ||
878 | * | ||
879 | * Redistribution and use in source and binary forms, with or without | ||
880 | * modification, are permitted provided that the following conditions | ||
881 | @@ -121,8 +121,8 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) | ||
882 | krb5_error_code problem; | ||
883 | krb5_principal princ; | ||
884 | OM_uint32 maj_status, min_status; | ||
885 | - int len; | ||
886 | const char *errmsg; | ||
887 | + const char *new_ccname; | ||
888 | |||
889 | if (client->creds == NULL) { | ||
890 | debug("No credentials stored"); | ||
891 | @@ -181,11 +181,16 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) | ||
892 | return; | ||
893 | } | ||
894 | |||
895 | - client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); | ||
896 | + new_ccname = krb5_cc_get_name(krb_context, ccache); | ||
897 | + | ||
898 | client->store.envvar = "KRB5CCNAME"; | ||
899 | - len = strlen(client->store.filename) + 6; | ||
900 | - client->store.envval = xmalloc(len); | ||
901 | - snprintf(client->store.envval, len, "FILE:%s", client->store.filename); | ||
902 | +#ifdef USE_CCAPI | ||
903 | + xasprintf(&client->store.envval, "API:%s", new_ccname); | ||
904 | + client->store.filename = NULL; | ||
905 | +#else | ||
906 | + xasprintf(&client->store.envval, "FILE:%s", new_ccname); | ||
907 | + client->store.filename = xstrdup(new_ccname); | ||
908 | +#endif | ||
909 | |||
910 | #ifdef USE_PAM | ||
911 | if (options.use_pam) | ||
912 | @@ -197,6 +202,71 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) | ||
913 | return; | ||
914 | } | ||
915 | |||
916 | +int | ||
917 | +ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, | ||
918 | + ssh_gssapi_client *client) | ||
919 | +{ | ||
920 | + krb5_ccache ccache = NULL; | ||
921 | + krb5_principal principal = NULL; | ||
922 | + char *name = NULL; | ||
923 | + krb5_error_code problem; | ||
924 | + OM_uint32 maj_status, min_status; | ||
925 | + | ||
926 | + if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { | ||
927 | + logit("krb5_cc_resolve(): %.100s", | ||
928 | + krb5_get_err_text(krb_context, problem)); | ||
929 | + return 0; | ||
930 | + } | ||
931 | + | ||
932 | + /* Find out who the principal in this cache is */ | ||
933 | + if ((problem = krb5_cc_get_principal(krb_context, ccache, | ||
934 | + &principal))) { | ||
935 | + logit("krb5_cc_get_principal(): %.100s", | ||
936 | + krb5_get_err_text(krb_context, problem)); | ||
937 | + krb5_cc_close(krb_context, ccache); | ||
938 | + return 0; | ||
939 | + } | ||
940 | + | ||
941 | + if ((problem = krb5_unparse_name(krb_context, principal, &name))) { | ||
942 | + logit("krb5_unparse_name(): %.100s", | ||
943 | + krb5_get_err_text(krb_context, problem)); | ||
944 | + krb5_free_principal(krb_context, principal); | ||
945 | + krb5_cc_close(krb_context, ccache); | ||
946 | + return 0; | ||
947 | + } | ||
948 | + | ||
949 | + | ||
950 | + if (strcmp(name,client->exportedname.value)!=0) { | ||
951 | + debug("Name in local credentials cache differs. Not storing"); | ||
952 | + krb5_free_principal(krb_context, principal); | ||
953 | + krb5_cc_close(krb_context, ccache); | ||
954 | + krb5_free_unparsed_name(krb_context, name); | ||
955 | + return 0; | ||
956 | + } | ||
957 | + krb5_free_unparsed_name(krb_context, name); | ||
958 | + | ||
959 | + /* Name matches, so lets get on with it! */ | ||
960 | + | ||
961 | + if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) { | ||
962 | + logit("krb5_cc_initialize(): %.100s", | ||
963 | + krb5_get_err_text(krb_context, problem)); | ||
964 | + krb5_free_principal(krb_context, principal); | ||
965 | + krb5_cc_close(krb_context, ccache); | ||
966 | + return 0; | ||
967 | + } | ||
968 | + | ||
969 | + krb5_free_principal(krb_context, principal); | ||
970 | + | ||
971 | + if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, | ||
972 | + ccache))) { | ||
973 | + logit("gss_krb5_copy_ccache() failed. Sorry!"); | ||
974 | + krb5_cc_close(krb_context, ccache); | ||
975 | + return 0; | ||
976 | + } | ||
977 | + | ||
978 | + return 1; | ||
979 | +} | ||
980 | + | ||
981 | ssh_gssapi_mech gssapi_kerberos_mech = { | ||
982 | "toWM5Slw5Ew8Mqkay+al2g==", | ||
983 | "Kerberos", | ||
984 | @@ -204,7 +274,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = { | ||
985 | NULL, | ||
986 | &ssh_gssapi_krb5_userok, | ||
987 | NULL, | ||
988 | - &ssh_gssapi_krb5_storecreds | ||
989 | + &ssh_gssapi_krb5_storecreds, | ||
990 | + &ssh_gssapi_krb5_updatecreds | ||
991 | }; | ||
992 | |||
993 | #endif /* KRB5 */ | ||
994 | diff --git a/gss-serv.c b/gss-serv.c | ||
995 | index 5c59924..50fa438 100644 | ||
996 | --- a/gss-serv.c | ||
997 | +++ b/gss-serv.c | ||
998 | @@ -1,7 +1,7 @@ | ||
999 | /* $OpenBSD: gss-serv.c,v 1.27 2014/07/03 03:34:09 djm Exp $ */ | ||
1000 | |||
1001 | /* | ||
1002 | - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | ||
1003 | + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. | ||
1004 | * | ||
1005 | * Redistribution and use in source and binary forms, with or without | ||
1006 | * modification, are permitted provided that the following conditions | ||
1007 | @@ -45,15 +45,21 @@ | ||
1008 | #include "channels.h" | ||
1009 | #include "session.h" | ||
1010 | #include "misc.h" | ||
1011 | +#include "servconf.h" | ||
1012 | +#include "uidswap.h" | ||
1013 | |||
1014 | #include "ssh-gss.h" | ||
1015 | +#include "monitor_wrap.h" | ||
1016 | + | ||
1017 | +extern ServerOptions options; | ||
1018 | |||
1019 | static ssh_gssapi_client gssapi_client = | ||
1020 | { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, | ||
1021 | - GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}}; | ||
1022 | + GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, | ||
1023 | + {NULL, NULL, NULL, NULL, NULL}, 0, 0}; | ||
1024 | |||
1025 | ssh_gssapi_mech gssapi_null_mech = | ||
1026 | - { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; | ||
1027 | + { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; | ||
1028 | |||
1029 | #ifdef KRB5 | ||
1030 | extern ssh_gssapi_mech gssapi_kerberos_mech; | ||
1031 | @@ -100,25 +106,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx) | ||
1032 | char lname[NI_MAXHOST]; | ||
1033 | gss_OID_set oidset; | ||
1034 | |||
1035 | - gss_create_empty_oid_set(&status, &oidset); | ||
1036 | - gss_add_oid_set_member(&status, ctx->oid, &oidset); | ||
1037 | + if (options.gss_strict_acceptor) { | ||
1038 | + gss_create_empty_oid_set(&status, &oidset); | ||
1039 | + gss_add_oid_set_member(&status, ctx->oid, &oidset); | ||
1040 | |||
1041 | - if (gethostname(lname, sizeof(lname))) { | ||
1042 | - gss_release_oid_set(&status, &oidset); | ||
1043 | - return (-1); | ||
1044 | - } | ||
1045 | + if (gethostname(lname, sizeof(lname))) { | ||
1046 | + gss_release_oid_set(&status, &oidset); | ||
1047 | + return (-1); | ||
1048 | + } | ||
1049 | + | ||
1050 | + if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { | ||
1051 | + gss_release_oid_set(&status, &oidset); | ||
1052 | + return (ctx->major); | ||
1053 | + } | ||
1054 | + | ||
1055 | + if ((ctx->major = gss_acquire_cred(&ctx->minor, | ||
1056 | + ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, | ||
1057 | + NULL, NULL))) | ||
1058 | + ssh_gssapi_error(ctx); | ||
1059 | |||
1060 | - if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { | ||
1061 | gss_release_oid_set(&status, &oidset); | ||
1062 | return (ctx->major); | ||
1063 | + } else { | ||
1064 | + ctx->name = GSS_C_NO_NAME; | ||
1065 | + ctx->creds = GSS_C_NO_CREDENTIAL; | ||
1066 | } | ||
1067 | - | ||
1068 | - if ((ctx->major = gss_acquire_cred(&ctx->minor, | ||
1069 | - ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) | ||
1070 | - ssh_gssapi_error(ctx); | ||
1071 | - | ||
1072 | - gss_release_oid_set(&status, &oidset); | ||
1073 | - return (ctx->major); | ||
1074 | + return GSS_S_COMPLETE; | ||
1075 | } | ||
1076 | |||
1077 | /* Privileged */ | ||
1078 | @@ -133,6 +146,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) | ||
1079 | } | ||
1080 | |||
1081 | /* Unprivileged */ | ||
1082 | +char * | ||
1083 | +ssh_gssapi_server_mechanisms(void) { | ||
1084 | + gss_OID_set supported; | ||
1085 | + | ||
1086 | + ssh_gssapi_supported_oids(&supported); | ||
1087 | + return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech, | ||
1088 | + NULL, NULL)); | ||
1089 | +} | ||
1090 | + | ||
1091 | +/* Unprivileged */ | ||
1092 | +int | ||
1093 | +ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data, | ||
1094 | + const char *dummy) { | ||
1095 | + Gssctxt *ctx = NULL; | ||
1096 | + int res; | ||
1097 | + | ||
1098 | + res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); | ||
1099 | + ssh_gssapi_delete_ctx(&ctx); | ||
1100 | + | ||
1101 | + return (res); | ||
1102 | +} | ||
1103 | + | ||
1104 | +/* Unprivileged */ | ||
1105 | void | ||
1106 | ssh_gssapi_supported_oids(gss_OID_set *oidset) | ||
1107 | { | ||
1108 | @@ -142,7 +178,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset) | ||
1109 | gss_OID_set supported; | ||
1110 | |||
1111 | gss_create_empty_oid_set(&min_status, oidset); | ||
1112 | - gss_indicate_mechs(&min_status, &supported); | ||
1113 | + | ||
1114 | + if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported))) | ||
1115 | + return; | ||
1116 | |||
1117 | while (supported_mechs[i]->name != NULL) { | ||
1118 | if (GSS_ERROR(gss_test_oid_set_member(&min_status, | ||
1119 | @@ -268,8 +306,48 @@ OM_uint32 | ||
1120 | ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) | ||
1121 | { | ||
1122 | int i = 0; | ||
1123 | + int equal = 0; | ||
1124 | + gss_name_t new_name = GSS_C_NO_NAME; | ||
1125 | + gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; | ||
1126 | + | ||
1127 | + if (options.gss_store_rekey && client->used && ctx->client_creds) { | ||
1128 | + if (client->mech->oid.length != ctx->oid->length || | ||
1129 | + (memcmp(client->mech->oid.elements, | ||
1130 | + ctx->oid->elements, ctx->oid->length) !=0)) { | ||
1131 | + debug("Rekeyed credentials have different mechanism"); | ||
1132 | + return GSS_S_COMPLETE; | ||
1133 | + } | ||
1134 | + | ||
1135 | + if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, | ||
1136 | + ctx->client_creds, ctx->oid, &new_name, | ||
1137 | + NULL, NULL, NULL))) { | ||
1138 | + ssh_gssapi_error(ctx); | ||
1139 | + return (ctx->major); | ||
1140 | + } | ||
1141 | + | ||
1142 | + ctx->major = gss_compare_name(&ctx->minor, client->name, | ||
1143 | + new_name, &equal); | ||
1144 | |||
1145 | - gss_buffer_desc ename; | ||
1146 | + if (GSS_ERROR(ctx->major)) { | ||
1147 | + ssh_gssapi_error(ctx); | ||
1148 | + return (ctx->major); | ||
1149 | + } | ||
1150 | + | ||
1151 | + if (!equal) { | ||
1152 | + debug("Rekeyed credentials have different name"); | ||
1153 | + return GSS_S_COMPLETE; | ||
1154 | + } | ||
1155 | + | ||
1156 | + debug("Marking rekeyed credentials for export"); | ||
1157 | + | ||
1158 | + gss_release_name(&ctx->minor, &client->name); | ||
1159 | + gss_release_cred(&ctx->minor, &client->creds); | ||
1160 | + client->name = new_name; | ||
1161 | + client->creds = ctx->client_creds; | ||
1162 | + ctx->client_creds = GSS_C_NO_CREDENTIAL; | ||
1163 | + client->updated = 1; | ||
1164 | + return GSS_S_COMPLETE; | ||
1165 | + } | ||
1166 | |||
1167 | client->mech = NULL; | ||
1168 | |||
1169 | @@ -284,6 +362,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) | ||
1170 | if (client->mech == NULL) | ||
1171 | return GSS_S_FAILURE; | ||
1172 | |||
1173 | + if (ctx->client_creds && | ||
1174 | + (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, | ||
1175 | + ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { | ||
1176 | + ssh_gssapi_error(ctx); | ||
1177 | + return (ctx->major); | ||
1178 | + } | ||
1179 | + | ||
1180 | if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, | ||
1181 | &client->displayname, NULL))) { | ||
1182 | ssh_gssapi_error(ctx); | ||
1183 | @@ -301,6 +386,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) | ||
1184 | return (ctx->major); | ||
1185 | } | ||
1186 | |||
1187 | + gss_release_buffer(&ctx->minor, &ename); | ||
1188 | + | ||
1189 | /* We can't copy this structure, so we just move the pointer to it */ | ||
1190 | client->creds = ctx->client_creds; | ||
1191 | ctx->client_creds = GSS_C_NO_CREDENTIAL; | ||
1192 | @@ -348,7 +435,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) | ||
1193 | |||
1194 | /* Privileged */ | ||
1195 | int | ||
1196 | -ssh_gssapi_userok(char *user) | ||
1197 | +ssh_gssapi_userok(char *user, struct passwd *pw) | ||
1198 | { | ||
1199 | OM_uint32 lmin; | ||
1200 | |||
1201 | @@ -358,9 +445,11 @@ ssh_gssapi_userok(char *user) | ||
1202 | return 0; | ||
1203 | } | ||
1204 | if (gssapi_client.mech && gssapi_client.mech->userok) | ||
1205 | - if ((*gssapi_client.mech->userok)(&gssapi_client, user)) | ||
1206 | + if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { | ||
1207 | + gssapi_client.used = 1; | ||
1208 | + gssapi_client.store.owner = pw; | ||
1209 | return 1; | ||
1210 | - else { | ||
1211 | + } else { | ||
1212 | /* Destroy delegated credentials if userok fails */ | ||
1213 | gss_release_buffer(&lmin, &gssapi_client.displayname); | ||
1214 | gss_release_buffer(&lmin, &gssapi_client.exportedname); | ||
1215 | @@ -374,14 +463,90 @@ ssh_gssapi_userok(char *user) | ||
1216 | return (0); | ||
1217 | } | ||
1218 | |||
1219 | -/* Privileged */ | ||
1220 | -OM_uint32 | ||
1221 | -ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) | ||
1222 | +/* These bits are only used for rekeying. The unpriviledged child is running | ||
1223 | + * as the user, the monitor is root. | ||
1224 | + * | ||
1225 | + * In the child, we want to : | ||
1226 | + * *) Ask the monitor to store our credentials into the store we specify | ||
1227 | + * *) If it succeeds, maybe do a PAM update | ||
1228 | + */ | ||
1229 | + | ||
1230 | +/* Stuff for PAM */ | ||
1231 | + | ||
1232 | +#ifdef USE_PAM | ||
1233 | +static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, | ||
1234 | + struct pam_response **resp, void *data) | ||
1235 | { | ||
1236 | - ctx->major = gss_verify_mic(&ctx->minor, ctx->context, | ||
1237 | - gssbuf, gssmic, NULL); | ||
1238 | + return (PAM_CONV_ERR); | ||
1239 | +} | ||
1240 | +#endif | ||
1241 | |||
1242 | - return (ctx->major); | ||
1243 | +void | ||
1244 | +ssh_gssapi_rekey_creds(void) { | ||
1245 | + int ok; | ||
1246 | + int ret; | ||
1247 | +#ifdef USE_PAM | ||
1248 | + pam_handle_t *pamh = NULL; | ||
1249 | + struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; | ||
1250 | + char *envstr; | ||
1251 | +#endif | ||
1252 | + | ||
1253 | + if (gssapi_client.store.filename == NULL && | ||
1254 | + gssapi_client.store.envval == NULL && | ||
1255 | + gssapi_client.store.envvar == NULL) | ||
1256 | + return; | ||
1257 | + | ||
1258 | + ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); | ||
1259 | + | ||
1260 | + if (!ok) | ||
1261 | + return; | ||
1262 | + | ||
1263 | + debug("Rekeyed credentials stored successfully"); | ||
1264 | + | ||
1265 | + /* Actually managing to play with the ssh pam stack from here will | ||
1266 | + * be next to impossible. In any case, we may want different options | ||
1267 | + * for rekeying. So, use our own :) | ||
1268 | + */ | ||
1269 | +#ifdef USE_PAM | ||
1270 | + if (!use_privsep) { | ||
1271 | + debug("Not even going to try and do PAM with privsep disabled"); | ||
1272 | + return; | ||
1273 | + } | ||
1274 | + | ||
1275 | + ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, | ||
1276 | + &pamconv, &pamh); | ||
1277 | + if (ret) | ||
1278 | + return; | ||
1279 | + | ||
1280 | + xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, | ||
1281 | + gssapi_client.store.envval); | ||
1282 | + | ||
1283 | + ret = pam_putenv(pamh, envstr); | ||
1284 | + if (!ret) | ||
1285 | + pam_setcred(pamh, PAM_REINITIALIZE_CRED); | ||
1286 | + pam_end(pamh, PAM_SUCCESS); | ||
1287 | +#endif | ||
1288 | +} | ||
1289 | + | ||
1290 | +int | ||
1291 | +ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { | ||
1292 | + int ok = 0; | ||
1293 | + | ||
1294 | + /* Check we've got credentials to store */ | ||
1295 | + if (!gssapi_client.updated) | ||
1296 | + return 0; | ||
1297 | + | ||
1298 | + gssapi_client.updated = 0; | ||
1299 | + | ||
1300 | + temporarily_use_uid(gssapi_client.store.owner); | ||
1301 | + if (gssapi_client.mech && gssapi_client.mech->updatecreds) | ||
1302 | + ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); | ||
1303 | + else | ||
1304 | + debug("No update function for this mechanism"); | ||
1305 | + | ||
1306 | + restore_uid(); | ||
1307 | + | ||
1308 | + return ok; | ||
1309 | } | ||
1310 | |||
1311 | #endif | ||
1312 | diff --git a/kex.c b/kex.c | ||
1313 | index a173e70..891852b 100644 | ||
1314 | --- a/kex.c | ||
1315 | +++ b/kex.c | ||
1316 | @@ -53,6 +53,10 @@ | ||
1317 | #include "roaming.h" | ||
1318 | #include "digest.h" | ||
1319 | |||
1320 | +#ifdef GSSAPI | ||
1321 | +#include "ssh-gss.h" | ||
1322 | +#endif | ||
1323 | + | ||
1324 | #if OPENSSL_VERSION_NUMBER >= 0x00907000L | ||
1325 | # if defined(HAVE_EVP_SHA256) | ||
1326 | # define evp_ssh_sha256 EVP_sha256 | ||
1327 | @@ -96,6 +100,14 @@ static const struct kexalg kexalgs[] = { | ||
1328 | #endif /* HAVE_EVP_SHA256 */ | ||
1329 | { NULL, -1, -1, -1}, | ||
1330 | }; | ||
1331 | +static const struct kexalg kexalg_prefixes[] = { | ||
1332 | +#ifdef GSSAPI | ||
1333 | + { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, | ||
1334 | + { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, | ||
1335 | + { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, | ||
1336 | +#endif | ||
1337 | + { NULL, -1, -1, -1 }, | ||
1338 | +}; | ||
1339 | |||
1340 | char * | ||
1341 | kex_alg_list(char sep) | ||
1342 | @@ -124,6 +136,10 @@ kex_alg_by_name(const char *name) | ||
1343 | if (strcmp(k->name, name) == 0) | ||
1344 | return k; | ||
1345 | } | ||
1346 | + for (k = kexalg_prefixes; k->name != NULL; k++) { | ||
1347 | + if (strncmp(k->name, name, strlen(k->name)) == 0) | ||
1348 | + return k; | ||
1349 | + } | ||
1350 | return NULL; | ||
1351 | } | ||
1352 | |||
1353 | diff --git a/kex.h b/kex.h | ||
1354 | index 4c40ec8..c179a4d 100644 | ||
1355 | --- a/kex.h | ||
1356 | +++ b/kex.h | ||
1357 | @@ -76,6 +76,9 @@ enum kex_exchange { | ||
1358 | KEX_DH_GEX_SHA256, | ||
1359 | KEX_ECDH_SHA2, | ||
1360 | KEX_C25519_SHA256, | ||
1361 | + KEX_GSS_GRP1_SHA1, | ||
1362 | + KEX_GSS_GRP14_SHA1, | ||
1363 | + KEX_GSS_GEX_SHA1, | ||
1364 | KEX_MAX | ||
1365 | }; | ||
1366 | |||
1367 | @@ -135,6 +138,12 @@ struct Kex { | ||
1368 | int flags; | ||
1369 | int hash_alg; | ||
1370 | int ec_nid; | ||
1371 | +#ifdef GSSAPI | ||
1372 | + int gss_deleg_creds; | ||
1373 | + int gss_trust_dns; | ||
1374 | + char *gss_host; | ||
1375 | + char *gss_client; | ||
1376 | +#endif | ||
1377 | char *client_version_string; | ||
1378 | char *server_version_string; | ||
1379 | int (*verify_host_key)(Key *); | ||
1380 | @@ -167,6 +176,11 @@ void kexecdh_server(Kex *); | ||
1381 | void kexc25519_client(Kex *); | ||
1382 | void kexc25519_server(Kex *); | ||
1383 | |||
1384 | +#ifdef GSSAPI | ||
1385 | +void kexgss_client(Kex *); | ||
1386 | +void kexgss_server(Kex *); | ||
1387 | +#endif | ||
1388 | + | ||
1389 | void | ||
1390 | kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, | ||
1391 | BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); | ||
1392 | diff --git a/kexgssc.c b/kexgssc.c | ||
1393 | new file mode 100644 | ||
1394 | index 0000000..92a31c5 | ||
1395 | --- /dev/null | ||
1396 | +++ b/kexgssc.c | ||
1397 | @@ -0,0 +1,332 @@ | ||
1398 | +/* | ||
1399 | + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. | ||
1400 | + * | ||
1401 | + * Redistribution and use in source and binary forms, with or without | ||
1402 | + * modification, are permitted provided that the following conditions | ||
1403 | + * are met: | ||
1404 | + * 1. Redistributions of source code must retain the above copyright | ||
1405 | + * notice, this list of conditions and the following disclaimer. | ||
1406 | + * 2. Redistributions in binary form must reproduce the above copyright | ||
1407 | + * notice, this list of conditions and the following disclaimer in the | ||
1408 | + * documentation and/or other materials provided with the distribution. | ||
1409 | + * | ||
1410 | + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR | ||
1411 | + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
1412 | + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
1413 | + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
1414 | + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
1415 | + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
1416 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
1417 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
1418 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
1419 | + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
1420 | + */ | ||
1421 | + | ||
1422 | +#include "includes.h" | ||
1423 | + | ||
1424 | +#ifdef GSSAPI | ||
1425 | + | ||
1426 | +#include "includes.h" | ||
1427 | + | ||
1428 | +#include <openssl/crypto.h> | ||
1429 | +#include <openssl/bn.h> | ||
1430 | + | ||
1431 | +#include <string.h> | ||
1432 | + | ||
1433 | +#include "xmalloc.h" | ||
1434 | +#include "buffer.h" | ||
1435 | +#include "ssh2.h" | ||
1436 | +#include "key.h" | ||
1437 | +#include "cipher.h" | ||
1438 | +#include "kex.h" | ||
1439 | +#include "log.h" | ||
1440 | +#include "packet.h" | ||
1441 | +#include "dh.h" | ||
1442 | + | ||
1443 | +#include "ssh-gss.h" | ||
1444 | + | ||
1445 | +void | ||
1446 | +kexgss_client(Kex *kex) { | ||
1447 | + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
1448 | + gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr; | ||
1449 | + Gssctxt *ctxt; | ||
1450 | + OM_uint32 maj_status, min_status, ret_flags; | ||
1451 | + u_int klen, kout, slen = 0, hashlen, strlen; | ||
1452 | + DH *dh; | ||
1453 | + BIGNUM *dh_server_pub = NULL; | ||
1454 | + BIGNUM *shared_secret = NULL; | ||
1455 | + BIGNUM *p = NULL; | ||
1456 | + BIGNUM *g = NULL; | ||
1457 | + u_char *kbuf, *hash; | ||
1458 | + u_char *serverhostkey = NULL; | ||
1459 | + u_char *empty = ""; | ||
1460 | + char *msg; | ||
1461 | + int type = 0; | ||
1462 | + int first = 1; | ||
1463 | + int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; | ||
1464 | + | ||
1465 | + /* Initialise our GSSAPI world */ | ||
1466 | + ssh_gssapi_build_ctx(&ctxt); | ||
1467 | + if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) | ||
1468 | + == GSS_C_NO_OID) | ||
1469 | + fatal("Couldn't identify host exchange"); | ||
1470 | + | ||
1471 | + if (ssh_gssapi_import_name(ctxt, kex->gss_host)) | ||
1472 | + fatal("Couldn't import hostname"); | ||
1473 | + | ||
1474 | + if (kex->gss_client && | ||
1475 | + ssh_gssapi_client_identity(ctxt, kex->gss_client)) | ||
1476 | + fatal("Couldn't acquire client credentials"); | ||
1477 | + | ||
1478 | + switch (kex->kex_type) { | ||
1479 | + case KEX_GSS_GRP1_SHA1: | ||
1480 | + dh = dh_new_group1(); | ||
1481 | + break; | ||
1482 | + case KEX_GSS_GRP14_SHA1: | ||
1483 | + dh = dh_new_group14(); | ||
1484 | + break; | ||
1485 | + case KEX_GSS_GEX_SHA1: | ||
1486 | + debug("Doing group exchange\n"); | ||
1487 | + nbits = dh_estimate(kex->we_need * 8); | ||
1488 | + packet_start(SSH2_MSG_KEXGSS_GROUPREQ); | ||
1489 | + packet_put_int(min); | ||
1490 | + packet_put_int(nbits); | ||
1491 | + packet_put_int(max); | ||
1492 | + | ||
1493 | + packet_send(); | ||
1494 | + | ||
1495 | + packet_read_expect(SSH2_MSG_KEXGSS_GROUP); | ||
1496 | + | ||
1497 | + if ((p = BN_new()) == NULL) | ||
1498 | + fatal("BN_new() failed"); | ||
1499 | + packet_get_bignum2(p); | ||
1500 | + if ((g = BN_new()) == NULL) | ||
1501 | + fatal("BN_new() failed"); | ||
1502 | + packet_get_bignum2(g); | ||
1503 | + packet_check_eom(); | ||
1504 | + | ||
1505 | + if (BN_num_bits(p) < min || BN_num_bits(p) > max) | ||
1506 | + fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", | ||
1507 | + min, BN_num_bits(p), max); | ||
1508 | + | ||
1509 | + dh = dh_new_group(g, p); | ||
1510 | + break; | ||
1511 | + default: | ||
1512 | + fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); | ||
1513 | + } | ||
1514 | + | ||
1515 | + /* Step 1 - e is dh->pub_key */ | ||
1516 | + dh_gen_key(dh, kex->we_need * 8); | ||
1517 | + | ||
1518 | + /* This is f, we initialise it now to make life easier */ | ||
1519 | + dh_server_pub = BN_new(); | ||
1520 | + if (dh_server_pub == NULL) | ||
1521 | + fatal("dh_server_pub == NULL"); | ||
1522 | + | ||
1523 | + token_ptr = GSS_C_NO_BUFFER; | ||
1524 | + | ||
1525 | + do { | ||
1526 | + debug("Calling gss_init_sec_context"); | ||
1527 | + | ||
1528 | + maj_status = ssh_gssapi_init_ctx(ctxt, | ||
1529 | + kex->gss_deleg_creds, token_ptr, &send_tok, | ||
1530 | + &ret_flags); | ||
1531 | + | ||
1532 | + if (GSS_ERROR(maj_status)) { | ||
1533 | + if (send_tok.length != 0) { | ||
1534 | + packet_start(SSH2_MSG_KEXGSS_CONTINUE); | ||
1535 | + packet_put_string(send_tok.value, | ||
1536 | + send_tok.length); | ||
1537 | + } | ||
1538 | + fatal("gss_init_context failed"); | ||
1539 | + } | ||
1540 | + | ||
1541 | + /* If we've got an old receive buffer get rid of it */ | ||
1542 | + if (token_ptr != GSS_C_NO_BUFFER) | ||
1543 | + free(recv_tok.value); | ||
1544 | + | ||
1545 | + if (maj_status == GSS_S_COMPLETE) { | ||
1546 | + /* If mutual state flag is not true, kex fails */ | ||
1547 | + if (!(ret_flags & GSS_C_MUTUAL_FLAG)) | ||
1548 | + fatal("Mutual authentication failed"); | ||
1549 | + | ||
1550 | + /* If integ avail flag is not true kex fails */ | ||
1551 | + if (!(ret_flags & GSS_C_INTEG_FLAG)) | ||
1552 | + fatal("Integrity check failed"); | ||
1553 | + } | ||
1554 | + | ||
1555 | + /* | ||
1556 | + * If we have data to send, then the last message that we | ||
1557 | + * received cannot have been a 'complete'. | ||
1558 | + */ | ||
1559 | + if (send_tok.length != 0) { | ||
1560 | + if (first) { | ||
1561 | + packet_start(SSH2_MSG_KEXGSS_INIT); | ||
1562 | + packet_put_string(send_tok.value, | ||
1563 | + send_tok.length); | ||
1564 | + packet_put_bignum2(dh->pub_key); | ||
1565 | + first = 0; | ||
1566 | + } else { | ||
1567 | + packet_start(SSH2_MSG_KEXGSS_CONTINUE); | ||
1568 | + packet_put_string(send_tok.value, | ||
1569 | + send_tok.length); | ||
1570 | + } | ||
1571 | + packet_send(); | ||
1572 | + gss_release_buffer(&min_status, &send_tok); | ||
1573 | + | ||
1574 | + /* If we've sent them data, they should reply */ | ||
1575 | + do { | ||
1576 | + type = packet_read(); | ||
1577 | + if (type == SSH2_MSG_KEXGSS_HOSTKEY) { | ||
1578 | + debug("Received KEXGSS_HOSTKEY"); | ||
1579 | + if (serverhostkey) | ||
1580 | + fatal("Server host key received more than once"); | ||
1581 | + serverhostkey = | ||
1582 | + packet_get_string(&slen); | ||
1583 | + } | ||
1584 | + } while (type == SSH2_MSG_KEXGSS_HOSTKEY); | ||
1585 | + | ||
1586 | + switch (type) { | ||
1587 | + case SSH2_MSG_KEXGSS_CONTINUE: | ||
1588 | + debug("Received GSSAPI_CONTINUE"); | ||
1589 | + if (maj_status == GSS_S_COMPLETE) | ||
1590 | + fatal("GSSAPI Continue received from server when complete"); | ||
1591 | + recv_tok.value = packet_get_string(&strlen); | ||
1592 | + recv_tok.length = strlen; | ||
1593 | + break; | ||
1594 | + case SSH2_MSG_KEXGSS_COMPLETE: | ||
1595 | + debug("Received GSSAPI_COMPLETE"); | ||
1596 | + packet_get_bignum2(dh_server_pub); | ||
1597 | + msg_tok.value = packet_get_string(&strlen); | ||
1598 | + msg_tok.length = strlen; | ||
1599 | + | ||
1600 | + /* Is there a token included? */ | ||
1601 | + if (packet_get_char()) { | ||
1602 | + recv_tok.value= | ||
1603 | + packet_get_string(&strlen); | ||
1604 | + recv_tok.length = strlen; | ||
1605 | + /* If we're already complete - protocol error */ | ||
1606 | + if (maj_status == GSS_S_COMPLETE) | ||
1607 | + packet_disconnect("Protocol error: received token when complete"); | ||
1608 | + } else { | ||
1609 | + /* No token included */ | ||
1610 | + if (maj_status != GSS_S_COMPLETE) | ||
1611 | + packet_disconnect("Protocol error: did not receive final token"); | ||
1612 | + } | ||
1613 | + break; | ||
1614 | + case SSH2_MSG_KEXGSS_ERROR: | ||
1615 | + debug("Received Error"); | ||
1616 | + maj_status = packet_get_int(); | ||
1617 | + min_status = packet_get_int(); | ||
1618 | + msg = packet_get_string(NULL); | ||
1619 | + (void) packet_get_string_ptr(NULL); | ||
1620 | + fatal("GSSAPI Error: \n%.400s",msg); | ||
1621 | + default: | ||
1622 | + packet_disconnect("Protocol error: didn't expect packet type %d", | ||
1623 | + type); | ||
1624 | + } | ||
1625 | + token_ptr = &recv_tok; | ||
1626 | + } else { | ||
1627 | + /* No data, and not complete */ | ||
1628 | + if (maj_status != GSS_S_COMPLETE) | ||
1629 | + fatal("Not complete, and no token output"); | ||
1630 | + } | ||
1631 | + } while (maj_status & GSS_S_CONTINUE_NEEDED); | ||
1632 | + | ||
1633 | + /* | ||
1634 | + * We _must_ have received a COMPLETE message in reply from the | ||
1635 | + * server, which will have set dh_server_pub and msg_tok | ||
1636 | + */ | ||
1637 | + | ||
1638 | + if (type != SSH2_MSG_KEXGSS_COMPLETE) | ||
1639 | + fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); | ||
1640 | + | ||
1641 | + /* Check f in range [1, p-1] */ | ||
1642 | + if (!dh_pub_is_valid(dh, dh_server_pub)) | ||
1643 | + packet_disconnect("bad server public DH value"); | ||
1644 | + | ||
1645 | + /* compute K=f^x mod p */ | ||
1646 | + klen = DH_size(dh); | ||
1647 | + kbuf = xmalloc(klen); | ||
1648 | + kout = DH_compute_key(kbuf, dh_server_pub, dh); | ||
1649 | + if (kout < 0) | ||
1650 | + fatal("DH_compute_key: failed"); | ||
1651 | + | ||
1652 | + shared_secret = BN_new(); | ||
1653 | + if (shared_secret == NULL) | ||
1654 | + fatal("kexgss_client: BN_new failed"); | ||
1655 | + | ||
1656 | + if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) | ||
1657 | + fatal("kexdh_client: BN_bin2bn failed"); | ||
1658 | + | ||
1659 | + memset(kbuf, 0, klen); | ||
1660 | + free(kbuf); | ||
1661 | + | ||
1662 | + switch (kex->kex_type) { | ||
1663 | + case KEX_GSS_GRP1_SHA1: | ||
1664 | + case KEX_GSS_GRP14_SHA1: | ||
1665 | + kex_dh_hash( kex->client_version_string, | ||
1666 | + kex->server_version_string, | ||
1667 | + buffer_ptr(&kex->my), buffer_len(&kex->my), | ||
1668 | + buffer_ptr(&kex->peer), buffer_len(&kex->peer), | ||
1669 | + (serverhostkey ? serverhostkey : empty), slen, | ||
1670 | + dh->pub_key, /* e */ | ||
1671 | + dh_server_pub, /* f */ | ||
1672 | + shared_secret, /* K */ | ||
1673 | + &hash, &hashlen | ||
1674 | + ); | ||
1675 | + break; | ||
1676 | + case KEX_GSS_GEX_SHA1: | ||
1677 | + kexgex_hash( | ||
1678 | + kex->hash_alg, | ||
1679 | + kex->client_version_string, | ||
1680 | + kex->server_version_string, | ||
1681 | + buffer_ptr(&kex->my), buffer_len(&kex->my), | ||
1682 | + buffer_ptr(&kex->peer), buffer_len(&kex->peer), | ||
1683 | + (serverhostkey ? serverhostkey : empty), slen, | ||
1684 | + min, nbits, max, | ||
1685 | + dh->p, dh->g, | ||
1686 | + dh->pub_key, | ||
1687 | + dh_server_pub, | ||
1688 | + shared_secret, | ||
1689 | + &hash, &hashlen | ||
1690 | + ); | ||
1691 | + break; | ||
1692 | + default: | ||
1693 | + fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); | ||
1694 | + } | ||
1695 | + | ||
1696 | + gssbuf.value = hash; | ||
1697 | + gssbuf.length = hashlen; | ||
1698 | + | ||
1699 | + /* Verify that the hash matches the MIC we just got. */ | ||
1700 | + if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) | ||
1701 | + packet_disconnect("Hash's MIC didn't verify"); | ||
1702 | + | ||
1703 | + free(msg_tok.value); | ||
1704 | + | ||
1705 | + DH_free(dh); | ||
1706 | + free(serverhostkey); | ||
1707 | + BN_clear_free(dh_server_pub); | ||
1708 | + | ||
1709 | + /* save session id */ | ||
1710 | + if (kex->session_id == NULL) { | ||
1711 | + kex->session_id_len = hashlen; | ||
1712 | + kex->session_id = xmalloc(kex->session_id_len); | ||
1713 | + memcpy(kex->session_id, hash, kex->session_id_len); | ||
1714 | + } | ||
1715 | + | ||
1716 | + if (kex->gss_deleg_creds) | ||
1717 | + ssh_gssapi_credentials_updated(ctxt); | ||
1718 | + | ||
1719 | + if (gss_kex_context == NULL) | ||
1720 | + gss_kex_context = ctxt; | ||
1721 | + else | ||
1722 | + ssh_gssapi_delete_ctx(&ctxt); | ||
1723 | + | ||
1724 | + kex_derive_keys_bn(kex, hash, hashlen, shared_secret); | ||
1725 | + BN_clear_free(shared_secret); | ||
1726 | + kex_finish(kex); | ||
1727 | +} | ||
1728 | + | ||
1729 | +#endif /* GSSAPI */ | ||
1730 | diff --git a/kexgsss.c b/kexgsss.c | ||
1731 | new file mode 100644 | ||
1732 | index 0000000..6a0ece8 | ||
1733 | --- /dev/null | ||
1734 | +++ b/kexgsss.c | ||
1735 | @@ -0,0 +1,290 @@ | ||
1736 | +/* | ||
1737 | + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. | ||
1738 | + * | ||
1739 | + * Redistribution and use in source and binary forms, with or without | ||
1740 | + * modification, are permitted provided that the following conditions | ||
1741 | + * are met: | ||
1742 | + * 1. Redistributions of source code must retain the above copyright | ||
1743 | + * notice, this list of conditions and the following disclaimer. | ||
1744 | + * 2. Redistributions in binary form must reproduce the above copyright | ||
1745 | + * notice, this list of conditions and the following disclaimer in the | ||
1746 | + * documentation and/or other materials provided with the distribution. | ||
1747 | + * | ||
1748 | + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR | ||
1749 | + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
1750 | + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
1751 | + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
1752 | + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
1753 | + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
1754 | + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
1755 | + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
1756 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
1757 | + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
1758 | + */ | ||
1759 | + | ||
1760 | +#include "includes.h" | ||
1761 | + | ||
1762 | +#ifdef GSSAPI | ||
1763 | + | ||
1764 | +#include <string.h> | ||
1765 | + | ||
1766 | +#include <openssl/crypto.h> | ||
1767 | +#include <openssl/bn.h> | ||
1768 | + | ||
1769 | +#include "xmalloc.h" | ||
1770 | +#include "buffer.h" | ||
1771 | +#include "ssh2.h" | ||
1772 | +#include "key.h" | ||
1773 | +#include "cipher.h" | ||
1774 | +#include "kex.h" | ||
1775 | +#include "log.h" | ||
1776 | +#include "packet.h" | ||
1777 | +#include "dh.h" | ||
1778 | +#include "ssh-gss.h" | ||
1779 | +#include "monitor_wrap.h" | ||
1780 | +#include "misc.h" | ||
1781 | +#include "servconf.h" | ||
1782 | + | ||
1783 | +extern ServerOptions options; | ||
1784 | + | ||
1785 | +void | ||
1786 | +kexgss_server(Kex *kex) | ||
1787 | +{ | ||
1788 | + OM_uint32 maj_status, min_status; | ||
1789 | + | ||
1790 | + /* | ||
1791 | + * Some GSSAPI implementations use the input value of ret_flags (an | ||
1792 | + * output variable) as a means of triggering mechanism specific | ||
1793 | + * features. Initializing it to zero avoids inadvertently | ||
1794 | + * activating this non-standard behaviour. | ||
1795 | + */ | ||
1796 | + | ||
1797 | + OM_uint32 ret_flags = 0; | ||
1798 | + gss_buffer_desc gssbuf, recv_tok, msg_tok; | ||
1799 | + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; | ||
1800 | + Gssctxt *ctxt = NULL; | ||
1801 | + u_int slen, klen, kout, hashlen; | ||
1802 | + u_char *kbuf, *hash; | ||
1803 | + DH *dh; | ||
1804 | + int min = -1, max = -1, nbits = -1; | ||
1805 | + BIGNUM *shared_secret = NULL; | ||
1806 | + BIGNUM *dh_client_pub = NULL; | ||
1807 | + int type = 0; | ||
1808 | + gss_OID oid; | ||
1809 | + char *mechs; | ||
1810 | + | ||
1811 | + /* Initialise GSSAPI */ | ||
1812 | + | ||
1813 | + /* If we're rekeying, privsep means that some of the private structures | ||
1814 | + * in the GSSAPI code are no longer available. This kludges them back | ||
1815 | + * into life | ||
1816 | + */ | ||
1817 | + if (!ssh_gssapi_oid_table_ok()) { | ||
1818 | + mechs = ssh_gssapi_server_mechanisms(); | ||
1819 | + free(mechs); | ||
1820 | + } | ||
1821 | + | ||
1822 | + debug2("%s: Identifying %s", __func__, kex->name); | ||
1823 | + oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); | ||
1824 | + if (oid == GSS_C_NO_OID) | ||
1825 | + fatal("Unknown gssapi mechanism"); | ||
1826 | + | ||
1827 | + debug2("%s: Acquiring credentials", __func__); | ||
1828 | + | ||
1829 | + if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) | ||
1830 | + fatal("Unable to acquire credentials for the server"); | ||
1831 | + | ||
1832 | + switch (kex->kex_type) { | ||
1833 | + case KEX_GSS_GRP1_SHA1: | ||
1834 | + dh = dh_new_group1(); | ||
1835 | + break; | ||
1836 | + case KEX_GSS_GRP14_SHA1: | ||
1837 | + dh = dh_new_group14(); | ||
1838 | + break; | ||
1839 | + case KEX_GSS_GEX_SHA1: | ||
1840 | + debug("Doing group exchange"); | ||
1841 | + packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ); | ||
1842 | + min = packet_get_int(); | ||
1843 | + nbits = packet_get_int(); | ||
1844 | + max = packet_get_int(); | ||
1845 | + min = MAX(DH_GRP_MIN, min); | ||
1846 | + max = MIN(DH_GRP_MAX, max); | ||
1847 | + packet_check_eom(); | ||
1848 | + if (max < min || nbits < min || max < nbits) | ||
1849 | + fatal("GSS_GEX, bad parameters: %d !< %d !< %d", | ||
1850 | + min, nbits, max); | ||
1851 | + dh = PRIVSEP(choose_dh(min, nbits, max)); | ||
1852 | + if (dh == NULL) | ||
1853 | + packet_disconnect("Protocol error: no matching group found"); | ||
1854 | + | ||
1855 | + packet_start(SSH2_MSG_KEXGSS_GROUP); | ||
1856 | + packet_put_bignum2(dh->p); | ||
1857 | + packet_put_bignum2(dh->g); | ||
1858 | + packet_send(); | ||
1859 | + | ||
1860 | + packet_write_wait(); | ||
1861 | + break; | ||
1862 | + default: | ||
1863 | + fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); | ||
1864 | + } | ||
1865 | + | ||
1866 | + dh_gen_key(dh, kex->we_need * 8); | ||
1867 | + | ||
1868 | + do { | ||
1869 | + debug("Wait SSH2_MSG_GSSAPI_INIT"); | ||
1870 | + type = packet_read(); | ||
1871 | + switch(type) { | ||
1872 | + case SSH2_MSG_KEXGSS_INIT: | ||
1873 | + if (dh_client_pub != NULL) | ||
1874 | + fatal("Received KEXGSS_INIT after initialising"); | ||
1875 | + recv_tok.value = packet_get_string(&slen); | ||
1876 | + recv_tok.length = slen; | ||
1877 | + | ||
1878 | + if ((dh_client_pub = BN_new()) == NULL) | ||
1879 | + fatal("dh_client_pub == NULL"); | ||
1880 | + | ||
1881 | + packet_get_bignum2(dh_client_pub); | ||
1882 | + | ||
1883 | + /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ | ||
1884 | + break; | ||
1885 | + case SSH2_MSG_KEXGSS_CONTINUE: | ||
1886 | + recv_tok.value = packet_get_string(&slen); | ||
1887 | + recv_tok.length = slen; | ||
1888 | + break; | ||
1889 | + default: | ||
1890 | + packet_disconnect( | ||
1891 | + "Protocol error: didn't expect packet type %d", | ||
1892 | + type); | ||
1893 | + } | ||
1894 | + | ||
1895 | + maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, | ||
1896 | + &send_tok, &ret_flags)); | ||
1897 | + | ||
1898 | + free(recv_tok.value); | ||
1899 | + | ||
1900 | + if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) | ||
1901 | + fatal("Zero length token output when incomplete"); | ||
1902 | + | ||
1903 | + if (dh_client_pub == NULL) | ||
1904 | + fatal("No client public key"); | ||
1905 | + | ||
1906 | + if (maj_status & GSS_S_CONTINUE_NEEDED) { | ||
1907 | + debug("Sending GSSAPI_CONTINUE"); | ||
1908 | + packet_start(SSH2_MSG_KEXGSS_CONTINUE); | ||
1909 | + packet_put_string(send_tok.value, send_tok.length); | ||
1910 | + packet_send(); | ||
1911 | + gss_release_buffer(&min_status, &send_tok); | ||
1912 | + } | ||
1913 | + } while (maj_status & GSS_S_CONTINUE_NEEDED); | ||
1914 | + | ||
1915 | + if (GSS_ERROR(maj_status)) { | ||
1916 | + if (send_tok.length > 0) { | ||
1917 | + packet_start(SSH2_MSG_KEXGSS_CONTINUE); | ||
1918 | + packet_put_string(send_tok.value, send_tok.length); | ||
1919 | + packet_send(); | ||
1920 | + } | ||
1921 | + fatal("accept_ctx died"); | ||
1922 | + } | ||
1923 | + | ||
1924 | + if (!(ret_flags & GSS_C_MUTUAL_FLAG)) | ||
1925 | + fatal("Mutual Authentication flag wasn't set"); | ||
1926 | + | ||
1927 | + if (!(ret_flags & GSS_C_INTEG_FLAG)) | ||
1928 | + fatal("Integrity flag wasn't set"); | ||
1929 | + | ||
1930 | + if (!dh_pub_is_valid(dh, dh_client_pub)) | ||
1931 | + packet_disconnect("bad client public DH value"); | ||
1932 | + | ||
1933 | + klen = DH_size(dh); | ||
1934 | + kbuf = xmalloc(klen); | ||
1935 | + kout = DH_compute_key(kbuf, dh_client_pub, dh); | ||
1936 | + if (kout < 0) | ||
1937 | + fatal("DH_compute_key: failed"); | ||
1938 | + | ||
1939 | + shared_secret = BN_new(); | ||
1940 | + if (shared_secret == NULL) | ||
1941 | + fatal("kexgss_server: BN_new failed"); | ||
1942 | + | ||
1943 | + if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) | ||
1944 | + fatal("kexgss_server: BN_bin2bn failed"); | ||
1945 | + | ||
1946 | + memset(kbuf, 0, klen); | ||
1947 | + free(kbuf); | ||
1948 | + | ||
1949 | + switch (kex->kex_type) { | ||
1950 | + case KEX_GSS_GRP1_SHA1: | ||
1951 | + case KEX_GSS_GRP14_SHA1: | ||
1952 | + kex_dh_hash( | ||
1953 | + kex->client_version_string, kex->server_version_string, | ||
1954 | + buffer_ptr(&kex->peer), buffer_len(&kex->peer), | ||
1955 | + buffer_ptr(&kex->my), buffer_len(&kex->my), | ||
1956 | + NULL, 0, /* Change this if we start sending host keys */ | ||
1957 | + dh_client_pub, dh->pub_key, shared_secret, | ||
1958 | + &hash, &hashlen | ||
1959 | + ); | ||
1960 | + break; | ||
1961 | + case KEX_GSS_GEX_SHA1: | ||
1962 | + kexgex_hash( | ||
1963 | + kex->hash_alg, | ||
1964 | + kex->client_version_string, kex->server_version_string, | ||
1965 | + buffer_ptr(&kex->peer), buffer_len(&kex->peer), | ||
1966 | + buffer_ptr(&kex->my), buffer_len(&kex->my), | ||
1967 | + NULL, 0, | ||
1968 | + min, nbits, max, | ||
1969 | + dh->p, dh->g, | ||
1970 | + dh_client_pub, | ||
1971 | + dh->pub_key, | ||
1972 | + shared_secret, | ||
1973 | + &hash, &hashlen | ||
1974 | + ); | ||
1975 | + break; | ||
1976 | + default: | ||
1977 | + fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); | ||
1978 | + } | ||
1979 | + | ||
1980 | + BN_clear_free(dh_client_pub); | ||
1981 | + | ||
1982 | + if (kex->session_id == NULL) { | ||
1983 | + kex->session_id_len = hashlen; | ||
1984 | + kex->session_id = xmalloc(kex->session_id_len); | ||
1985 | + memcpy(kex->session_id, hash, kex->session_id_len); | ||
1986 | + } | ||
1987 | + | ||
1988 | + gssbuf.value = hash; | ||
1989 | + gssbuf.length = hashlen; | ||
1990 | + | ||
1991 | + if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) | ||
1992 | + fatal("Couldn't get MIC"); | ||
1993 | + | ||
1994 | + packet_start(SSH2_MSG_KEXGSS_COMPLETE); | ||
1995 | + packet_put_bignum2(dh->pub_key); | ||
1996 | + packet_put_string(msg_tok.value,msg_tok.length); | ||
1997 | + | ||
1998 | + if (send_tok.length != 0) { | ||
1999 | + packet_put_char(1); /* true */ | ||
2000 | + packet_put_string(send_tok.value, send_tok.length); | ||
2001 | + } else { | ||
2002 | + packet_put_char(0); /* false */ | ||
2003 | + } | ||
2004 | + packet_send(); | ||
2005 | + | ||
2006 | + gss_release_buffer(&min_status, &send_tok); | ||
2007 | + gss_release_buffer(&min_status, &msg_tok); | ||
2008 | + | ||
2009 | + if (gss_kex_context == NULL) | ||
2010 | + gss_kex_context = ctxt; | ||
2011 | + else | ||
2012 | + ssh_gssapi_delete_ctx(&ctxt); | ||
2013 | + | ||
2014 | + DH_free(dh); | ||
2015 | + | ||
2016 | + kex_derive_keys_bn(kex, hash, hashlen, shared_secret); | ||
2017 | + BN_clear_free(shared_secret); | ||
2018 | + kex_finish(kex); | ||
2019 | + | ||
2020 | + /* If this was a rekey, then save out any delegated credentials we | ||
2021 | + * just exchanged. */ | ||
2022 | + if (options.gss_store_rekey) | ||
2023 | + ssh_gssapi_rekey_creds(); | ||
2024 | +} | ||
2025 | +#endif /* GSSAPI */ | ||
2026 | diff --git a/monitor.c b/monitor.c | ||
2027 | index dbe29f1..b0896ef 100644 | ||
2028 | --- a/monitor.c | ||
2029 | +++ b/monitor.c | ||
2030 | @@ -178,6 +178,8 @@ int mm_answer_gss_setup_ctx(int, Buffer *); | ||
2031 | int mm_answer_gss_accept_ctx(int, Buffer *); | ||
2032 | int mm_answer_gss_userok(int, Buffer *); | ||
2033 | int mm_answer_gss_checkmic(int, Buffer *); | ||
2034 | +int mm_answer_gss_sign(int, Buffer *); | ||
2035 | +int mm_answer_gss_updatecreds(int, Buffer *); | ||
2036 | #endif | ||
2037 | |||
2038 | #ifdef SSH_AUDIT_EVENTS | ||
2039 | @@ -255,11 +257,18 @@ struct mon_table mon_dispatch_proto20[] = { | ||
2040 | {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, | ||
2041 | {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, | ||
2042 | {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, | ||
2043 | + {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, | ||
2044 | #endif | ||
2045 | {0, 0, NULL} | ||
2046 | }; | ||
2047 | |||
2048 | struct mon_table mon_dispatch_postauth20[] = { | ||
2049 | +#ifdef GSSAPI | ||
2050 | + {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, | ||
2051 | + {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, | ||
2052 | + {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, | ||
2053 | + {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, | ||
2054 | +#endif | ||
2055 | #ifdef WITH_OPENSSL | ||
2056 | {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, | ||
2057 | #endif | ||
2058 | @@ -374,6 +383,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) | ||
2059 | /* Permit requests for moduli and signatures */ | ||
2060 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); | ||
2061 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); | ||
2062 | +#ifdef GSSAPI | ||
2063 | + /* and for the GSSAPI key exchange */ | ||
2064 | + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); | ||
2065 | +#endif | ||
2066 | } else { | ||
2067 | mon_dispatch = mon_dispatch_proto15; | ||
2068 | |||
2069 | @@ -482,6 +495,10 @@ monitor_child_postauth(struct monitor *pmonitor) | ||
2070 | monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); | ||
2071 | monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); | ||
2072 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); | ||
2073 | +#ifdef GSSAPI | ||
2074 | + /* and for the GSSAPI key exchange */ | ||
2075 | + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); | ||
2076 | +#endif | ||
2077 | } else { | ||
2078 | mon_dispatch = mon_dispatch_postauth15; | ||
2079 | monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); | ||
2080 | @@ -1861,6 +1878,13 @@ mm_get_kex(Buffer *m) | ||
2081 | kex->kex[KEX_ECDH_SHA2] = kexecdh_server; | ||
2082 | #endif | ||
2083 | kex->kex[KEX_C25519_SHA256] = kexc25519_server; | ||
2084 | +#ifdef GSSAPI | ||
2085 | + if (options.gss_keyex) { | ||
2086 | + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; | ||
2087 | + kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; | ||
2088 | + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; | ||
2089 | + } | ||
2090 | +#endif | ||
2091 | kex->server = 1; | ||
2092 | kex->hostkey_type = buffer_get_int(m); | ||
2093 | kex->kex_type = buffer_get_int(m); | ||
2094 | @@ -2068,6 +2092,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m) | ||
2095 | OM_uint32 major; | ||
2096 | u_int len; | ||
2097 | |||
2098 | + if (!options.gss_authentication && !options.gss_keyex) | ||
2099 | + fatal("In GSSAPI monitor when GSSAPI is disabled"); | ||
2100 | + | ||
2101 | goid.elements = buffer_get_string(m, &len); | ||
2102 | goid.length = len; | ||
2103 | |||
2104 | @@ -2095,6 +2122,9 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m) | ||
2105 | OM_uint32 flags = 0; /* GSI needs this */ | ||
2106 | u_int len; | ||
2107 | |||
2108 | + if (!options.gss_authentication && !options.gss_keyex) | ||
2109 | + fatal("In GSSAPI monitor when GSSAPI is disabled"); | ||
2110 | + | ||
2111 | in.value = buffer_get_string(m, &len); | ||
2112 | in.length = len; | ||
2113 | major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); | ||
2114 | @@ -2112,6 +2142,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m) | ||
2115 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); | ||
2116 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); | ||
2117 | monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); | ||
2118 | + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); | ||
2119 | } | ||
2120 | return (0); | ||
2121 | } | ||
2122 | @@ -2123,6 +2154,9 @@ mm_answer_gss_checkmic(int sock, Buffer *m) | ||
2123 | OM_uint32 ret; | ||
2124 | u_int len; | ||
2125 | |||
2126 | + if (!options.gss_authentication && !options.gss_keyex) | ||
2127 | + fatal("In GSSAPI monitor when GSSAPI is disabled"); | ||
2128 | + | ||
2129 | gssbuf.value = buffer_get_string(m, &len); | ||
2130 | gssbuf.length = len; | ||
2131 | mic.value = buffer_get_string(m, &len); | ||
2132 | @@ -2149,7 +2183,11 @@ mm_answer_gss_userok(int sock, Buffer *m) | ||
2133 | { | ||
2134 | int authenticated; | ||
2135 | |||
2136 | - authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); | ||
2137 | + if (!options.gss_authentication && !options.gss_keyex) | ||
2138 | + fatal("In GSSAPI monitor when GSSAPI is disabled"); | ||
2139 | + | ||
2140 | + authenticated = authctxt->valid && | ||
2141 | + ssh_gssapi_userok(authctxt->user, authctxt->pw); | ||
2142 | |||
2143 | buffer_clear(m); | ||
2144 | buffer_put_int(m, authenticated); | ||
2145 | @@ -2162,5 +2200,73 @@ mm_answer_gss_userok(int sock, Buffer *m) | ||
2146 | /* Monitor loop will terminate if authenticated */ | ||
2147 | return (authenticated); | ||
2148 | } | ||
2149 | + | ||
2150 | +int | ||
2151 | +mm_answer_gss_sign(int socket, Buffer *m) | ||
2152 | +{ | ||
2153 | + gss_buffer_desc data; | ||
2154 | + gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; | ||
2155 | + OM_uint32 major, minor; | ||
2156 | + u_int len; | ||
2157 | + | ||
2158 | + if (!options.gss_authentication && !options.gss_keyex) | ||
2159 | + fatal("In GSSAPI monitor when GSSAPI is disabled"); | ||
2160 | + | ||
2161 | + data.value = buffer_get_string(m, &len); | ||
2162 | + data.length = len; | ||
2163 | + if (data.length != 20) | ||
2164 | + fatal("%s: data length incorrect: %d", __func__, | ||
2165 | + (int) data.length); | ||
2166 | + | ||
2167 | + /* Save the session ID on the first time around */ | ||
2168 | + if (session_id2_len == 0) { | ||
2169 | + session_id2_len = data.length; | ||
2170 | + session_id2 = xmalloc(session_id2_len); | ||
2171 | + memcpy(session_id2, data.value, session_id2_len); | ||
2172 | + } | ||
2173 | + major = ssh_gssapi_sign(gsscontext, &data, &hash); | ||
2174 | + | ||
2175 | + free(data.value); | ||
2176 | + | ||
2177 | + buffer_clear(m); | ||
2178 | + buffer_put_int(m, major); | ||
2179 | + buffer_put_string(m, hash.value, hash.length); | ||
2180 | + | ||
2181 | + mm_request_send(socket, MONITOR_ANS_GSSSIGN, m); | ||
2182 | + | ||
2183 | + gss_release_buffer(&minor, &hash); | ||
2184 | + | ||
2185 | + /* Turn on getpwnam permissions */ | ||
2186 | + monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); | ||
2187 | + | ||
2188 | + /* And credential updating, for when rekeying */ | ||
2189 | + monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1); | ||
2190 | + | ||
2191 | + return (0); | ||
2192 | +} | ||
2193 | + | ||
2194 | +int | ||
2195 | +mm_answer_gss_updatecreds(int socket, Buffer *m) { | ||
2196 | + ssh_gssapi_ccache store; | ||
2197 | + int ok; | ||
2198 | + | ||
2199 | + store.filename = buffer_get_string(m, NULL); | ||
2200 | + store.envvar = buffer_get_string(m, NULL); | ||
2201 | + store.envval = buffer_get_string(m, NULL); | ||
2202 | + | ||
2203 | + ok = ssh_gssapi_update_creds(&store); | ||
2204 | + | ||
2205 | + free(store.filename); | ||
2206 | + free(store.envvar); | ||
2207 | + free(store.envval); | ||
2208 | + | ||
2209 | + buffer_clear(m); | ||
2210 | + buffer_put_int(m, ok); | ||
2211 | + | ||
2212 | + mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m); | ||
2213 | + | ||
2214 | + return(0); | ||
2215 | +} | ||
2216 | + | ||
2217 | #endif /* GSSAPI */ | ||
2218 | |||
2219 | diff --git a/monitor.h b/monitor.h | ||
2220 | index 5bc41b5..7f32b0c 100644 | ||
2221 | --- a/monitor.h | ||
2222 | +++ b/monitor.h | ||
2223 | @@ -65,6 +65,9 @@ enum monitor_reqtype { | ||
2224 | MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, | ||
2225 | MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, | ||
2226 | |||
2227 | + MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, | ||
2228 | + MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, | ||
2229 | + | ||
2230 | }; | ||
2231 | |||
2232 | struct mm_master; | ||
2233 | diff --git a/monitor_wrap.c b/monitor_wrap.c | ||
2234 | index 45dc169..e476f0d 100644 | ||
2235 | --- a/monitor_wrap.c | ||
2236 | +++ b/monitor_wrap.c | ||
2237 | @@ -1281,7 +1281,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) | ||
2238 | } | ||
2239 | |||
2240 | int | ||
2241 | -mm_ssh_gssapi_userok(char *user) | ||
2242 | +mm_ssh_gssapi_userok(char *user, struct passwd *pw) | ||
2243 | { | ||
2244 | Buffer m; | ||
2245 | int authenticated = 0; | ||
2246 | @@ -1298,5 +1298,50 @@ mm_ssh_gssapi_userok(char *user) | ||
2247 | debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); | ||
2248 | return (authenticated); | ||
2249 | } | ||
2250 | + | ||
2251 | +OM_uint32 | ||
2252 | +mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) | ||
2253 | +{ | ||
2254 | + Buffer m; | ||
2255 | + OM_uint32 major; | ||
2256 | + u_int len; | ||
2257 | + | ||
2258 | + buffer_init(&m); | ||
2259 | + buffer_put_string(&m, data->value, data->length); | ||
2260 | + | ||
2261 | + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m); | ||
2262 | + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m); | ||
2263 | + | ||
2264 | + major = buffer_get_int(&m); | ||
2265 | + hash->value = buffer_get_string(&m, &len); | ||
2266 | + hash->length = len; | ||
2267 | + | ||
2268 | + buffer_free(&m); | ||
2269 | + | ||
2270 | + return(major); | ||
2271 | +} | ||
2272 | + | ||
2273 | +int | ||
2274 | +mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) | ||
2275 | +{ | ||
2276 | + Buffer m; | ||
2277 | + int ok; | ||
2278 | + | ||
2279 | + buffer_init(&m); | ||
2280 | + | ||
2281 | + buffer_put_cstring(&m, store->filename ? store->filename : ""); | ||
2282 | + buffer_put_cstring(&m, store->envvar ? store->envvar : ""); | ||
2283 | + buffer_put_cstring(&m, store->envval ? store->envval : ""); | ||
2284 | + | ||
2285 | + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m); | ||
2286 | + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m); | ||
2287 | + | ||
2288 | + ok = buffer_get_int(&m); | ||
2289 | + | ||
2290 | + buffer_free(&m); | ||
2291 | + | ||
2292 | + return (ok); | ||
2293 | +} | ||
2294 | + | ||
2295 | #endif /* GSSAPI */ | ||
2296 | |||
2297 | diff --git a/monitor_wrap.h b/monitor_wrap.h | ||
2298 | index 18c2501..a4e9d24 100644 | ||
2299 | --- a/monitor_wrap.h | ||
2300 | +++ b/monitor_wrap.h | ||
2301 | @@ -58,8 +58,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(Key *); | ||
2302 | OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); | ||
2303 | OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, | ||
2304 | gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); | ||
2305 | -int mm_ssh_gssapi_userok(char *user); | ||
2306 | +int mm_ssh_gssapi_userok(char *user, struct passwd *); | ||
2307 | OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); | ||
2308 | +OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); | ||
2309 | +int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *); | ||
2310 | #endif | ||
2311 | |||
2312 | #ifdef USE_PAM | ||
2313 | diff --git a/readconf.c b/readconf.c | ||
2314 | index 7948ce1..9127e93 100644 | ||
2315 | --- a/readconf.c | ||
2316 | +++ b/readconf.c | ||
2317 | @@ -142,6 +142,8 @@ typedef enum { | ||
2318 | oClearAllForwardings, oNoHostAuthenticationForLocalhost, | ||
2319 | oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, | ||
2320 | oAddressFamily, oGssAuthentication, oGssDelegateCreds, | ||
2321 | + oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, | ||
2322 | + oGssServerIdentity, | ||
2323 | oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, | ||
2324 | oSendEnv, oControlPath, oControlMaster, oControlPersist, | ||
2325 | oHashKnownHosts, | ||
2326 | @@ -185,10 +187,19 @@ static struct { | ||
2327 | { "afstokenpassing", oUnsupported }, | ||
2328 | #if defined(GSSAPI) | ||
2329 | { "gssapiauthentication", oGssAuthentication }, | ||
2330 | + { "gssapikeyexchange", oGssKeyEx }, | ||
2331 | { "gssapidelegatecredentials", oGssDelegateCreds }, | ||
2332 | + { "gssapitrustdns", oGssTrustDns }, | ||
2333 | + { "gssapiclientidentity", oGssClientIdentity }, | ||
2334 | + { "gssapiserveridentity", oGssServerIdentity }, | ||
2335 | + { "gssapirenewalforcesrekey", oGssRenewalRekey }, | ||
2336 | #else | ||
2337 | { "gssapiauthentication", oUnsupported }, | ||
2338 | + { "gssapikeyexchange", oUnsupported }, | ||
2339 | { "gssapidelegatecredentials", oUnsupported }, | ||
2340 | + { "gssapitrustdns", oUnsupported }, | ||
2341 | + { "gssapiclientidentity", oUnsupported }, | ||
2342 | + { "gssapirenewalforcesrekey", oUnsupported }, | ||
2343 | #endif | ||
2344 | { "fallbacktorsh", oDeprecated }, | ||
2345 | { "usersh", oDeprecated }, | ||
2346 | @@ -865,10 +876,30 @@ parse_time: | ||
2347 | intptr = &options->gss_authentication; | ||
2348 | goto parse_flag; | ||
2349 | |||
2350 | + case oGssKeyEx: | ||
2351 | + intptr = &options->gss_keyex; | ||
2352 | + goto parse_flag; | ||
2353 | + | ||
2354 | case oGssDelegateCreds: | ||
2355 | intptr = &options->gss_deleg_creds; | ||
2356 | goto parse_flag; | ||
2357 | |||
2358 | + case oGssTrustDns: | ||
2359 | + intptr = &options->gss_trust_dns; | ||
2360 | + goto parse_flag; | ||
2361 | + | ||
2362 | + case oGssClientIdentity: | ||
2363 | + charptr = &options->gss_client_identity; | ||
2364 | + goto parse_string; | ||
2365 | + | ||
2366 | + case oGssServerIdentity: | ||
2367 | + charptr = &options->gss_server_identity; | ||
2368 | + goto parse_string; | ||
2369 | + | ||
2370 | + case oGssRenewalRekey: | ||
2371 | + intptr = &options->gss_renewal_rekey; | ||
2372 | + goto parse_flag; | ||
2373 | + | ||
2374 | case oBatchMode: | ||
2375 | intptr = &options->batch_mode; | ||
2376 | goto parse_flag; | ||
2377 | @@ -1538,7 +1569,12 @@ initialize_options(Options * options) | ||
2378 | options->pubkey_authentication = -1; | ||
2379 | options->challenge_response_authentication = -1; | ||
2380 | options->gss_authentication = -1; | ||
2381 | + options->gss_keyex = -1; | ||
2382 | options->gss_deleg_creds = -1; | ||
2383 | + options->gss_trust_dns = -1; | ||
2384 | + options->gss_renewal_rekey = -1; | ||
2385 | + options->gss_client_identity = NULL; | ||
2386 | + options->gss_server_identity = NULL; | ||
2387 | options->password_authentication = -1; | ||
2388 | options->kbd_interactive_authentication = -1; | ||
2389 | options->kbd_interactive_devices = NULL; | ||
2390 | @@ -1661,8 +1697,14 @@ fill_default_options(Options * options) | ||
2391 | options->challenge_response_authentication = 1; | ||
2392 | if (options->gss_authentication == -1) | ||
2393 | options->gss_authentication = 0; | ||
2394 | + if (options->gss_keyex == -1) | ||
2395 | + options->gss_keyex = 0; | ||
2396 | if (options->gss_deleg_creds == -1) | ||
2397 | options->gss_deleg_creds = 0; | ||
2398 | + if (options->gss_trust_dns == -1) | ||
2399 | + options->gss_trust_dns = 0; | ||
2400 | + if (options->gss_renewal_rekey == -1) | ||
2401 | + options->gss_renewal_rekey = 0; | ||
2402 | if (options->password_authentication == -1) | ||
2403 | options->password_authentication = 1; | ||
2404 | if (options->kbd_interactive_authentication == -1) | ||
2405 | diff --git a/readconf.h b/readconf.h | ||
2406 | index 0b9cb77..0e29889 100644 | ||
2407 | --- a/readconf.h | ||
2408 | +++ b/readconf.h | ||
2409 | @@ -45,7 +45,12 @@ typedef struct { | ||
2410 | int challenge_response_authentication; | ||
2411 | /* Try S/Key or TIS, authentication. */ | ||
2412 | int gss_authentication; /* Try GSS authentication */ | ||
2413 | + int gss_keyex; /* Try GSS key exchange */ | ||
2414 | int gss_deleg_creds; /* Delegate GSS credentials */ | ||
2415 | + int gss_trust_dns; /* Trust DNS for GSS canonicalization */ | ||
2416 | + int gss_renewal_rekey; /* Credential renewal forces rekey */ | ||
2417 | + char *gss_client_identity; /* Principal to initiate GSSAPI with */ | ||
2418 | + char *gss_server_identity; /* GSSAPI target principal */ | ||
2419 | int password_authentication; /* Try password | ||
2420 | * authentication. */ | ||
2421 | int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ | ||
2422 | diff --git a/servconf.c b/servconf.c | ||
2423 | index b7f3294..cb3c831 100644 | ||
2424 | --- a/servconf.c | ||
2425 | +++ b/servconf.c | ||
2426 | @@ -109,7 +109,10 @@ initialize_server_options(ServerOptions *options) | ||
2427 | options->kerberos_ticket_cleanup = -1; | ||
2428 | options->kerberos_get_afs_token = -1; | ||
2429 | options->gss_authentication=-1; | ||
2430 | + options->gss_keyex = -1; | ||
2431 | options->gss_cleanup_creds = -1; | ||
2432 | + options->gss_strict_acceptor = -1; | ||
2433 | + options->gss_store_rekey = -1; | ||
2434 | options->password_authentication = -1; | ||
2435 | options->kbd_interactive_authentication = -1; | ||
2436 | options->challenge_response_authentication = -1; | ||
2437 | @@ -250,8 +253,14 @@ fill_default_server_options(ServerOptions *options) | ||
2438 | options->kerberos_get_afs_token = 0; | ||
2439 | if (options->gss_authentication == -1) | ||
2440 | options->gss_authentication = 0; | ||
2441 | + if (options->gss_keyex == -1) | ||
2442 | + options->gss_keyex = 0; | ||
2443 | if (options->gss_cleanup_creds == -1) | ||
2444 | options->gss_cleanup_creds = 1; | ||
2445 | + if (options->gss_strict_acceptor == -1) | ||
2446 | + options->gss_strict_acceptor = 1; | ||
2447 | + if (options->gss_store_rekey == -1) | ||
2448 | + options->gss_store_rekey = 0; | ||
2449 | if (options->password_authentication == -1) | ||
2450 | options->password_authentication = 1; | ||
2451 | if (options->kbd_interactive_authentication == -1) | ||
2452 | @@ -352,7 +361,9 @@ typedef enum { | ||
2453 | sBanner, sUseDNS, sHostbasedAuthentication, | ||
2454 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, | ||
2455 | sClientAliveCountMax, sAuthorizedKeysFile, | ||
2456 | - sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, | ||
2457 | + sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, | ||
2458 | + sGssKeyEx, sGssStoreRekey, | ||
2459 | + sAcceptEnv, sPermitTunnel, | ||
2460 | sMatch, sPermitOpen, sForceCommand, sChrootDirectory, | ||
2461 | sUsePrivilegeSeparation, sAllowAgentForwarding, | ||
2462 | sHostCertificate, | ||
2463 | @@ -421,10 +432,20 @@ static struct { | ||
2464 | #ifdef GSSAPI | ||
2465 | { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, | ||
2466 | { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, | ||
2467 | + { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL }, | ||
2468 | + { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, | ||
2469 | + { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, | ||
2470 | + { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, | ||
2471 | #else | ||
2472 | { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, | ||
2473 | { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, | ||
2474 | + { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL }, | ||
2475 | + { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, | ||
2476 | + { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, | ||
2477 | + { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, | ||
2478 | #endif | ||
2479 | + { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, | ||
2480 | + { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, | ||
2481 | { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, | ||
2482 | { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, | ||
2483 | { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, | ||
2484 | @@ -1104,10 +1125,22 @@ process_server_config_line(ServerOptions *options, char *line, | ||
2485 | intptr = &options->gss_authentication; | ||
2486 | goto parse_flag; | ||
2487 | |||
2488 | + case sGssKeyEx: | ||
2489 | + intptr = &options->gss_keyex; | ||
2490 | + goto parse_flag; | ||
2491 | + | ||
2492 | case sGssCleanupCreds: | ||
2493 | intptr = &options->gss_cleanup_creds; | ||
2494 | goto parse_flag; | ||
2495 | |||
2496 | + case sGssStrictAcceptor: | ||
2497 | + intptr = &options->gss_strict_acceptor; | ||
2498 | + goto parse_flag; | ||
2499 | + | ||
2500 | + case sGssStoreRekey: | ||
2501 | + intptr = &options->gss_store_rekey; | ||
2502 | + goto parse_flag; | ||
2503 | + | ||
2504 | case sPasswordAuthentication: | ||
2505 | intptr = &options->password_authentication; | ||
2506 | goto parse_flag; | ||
2507 | @@ -2042,7 +2075,10 @@ dump_config(ServerOptions *o) | ||
2508 | #endif | ||
2509 | #ifdef GSSAPI | ||
2510 | dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); | ||
2511 | + dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); | ||
2512 | dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); | ||
2513 | + dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); | ||
2514 | + dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); | ||
2515 | #endif | ||
2516 | dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); | ||
2517 | dump_cfg_fmtint(sKbdInteractiveAuthentication, | ||
2518 | diff --git a/servconf.h b/servconf.h | ||
2519 | index 766db3a..f8265a8 100644 | ||
2520 | --- a/servconf.h | ||
2521 | +++ b/servconf.h | ||
2522 | @@ -113,7 +113,10 @@ typedef struct { | ||
2523 | int kerberos_get_afs_token; /* If true, try to get AFS token if | ||
2524 | * authenticated with Kerberos. */ | ||
2525 | int gss_authentication; /* If true, permit GSSAPI authentication */ | ||
2526 | + int gss_keyex; /* If true, permit GSSAPI key exchange */ | ||
2527 | int gss_cleanup_creds; /* If true, destroy cred cache on logout */ | ||
2528 | + int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ | ||
2529 | + int gss_store_rekey; | ||
2530 | int password_authentication; /* If true, permit password | ||
2531 | * authentication. */ | ||
2532 | int kbd_interactive_authentication; /* If true, permit */ | ||
2533 | diff --git a/ssh-gss.h b/ssh-gss.h | ||
2534 | index a99d7f0..914701b 100644 | ||
2535 | --- a/ssh-gss.h | ||
2536 | +++ b/ssh-gss.h | ||
2537 | @@ -1,6 +1,6 @@ | ||
2538 | /* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 djm Exp $ */ | ||
2539 | /* | ||
2540 | - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. | ||
2541 | + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. | ||
2542 | * | ||
2543 | * Redistribution and use in source and binary forms, with or without | ||
2544 | * modification, are permitted provided that the following conditions | ||
2545 | @@ -61,10 +61,22 @@ | ||
2546 | |||
2547 | #define SSH_GSS_OIDTYPE 0x06 | ||
2548 | |||
2549 | +#define SSH2_MSG_KEXGSS_INIT 30 | ||
2550 | +#define SSH2_MSG_KEXGSS_CONTINUE 31 | ||
2551 | +#define SSH2_MSG_KEXGSS_COMPLETE 32 | ||
2552 | +#define SSH2_MSG_KEXGSS_HOSTKEY 33 | ||
2553 | +#define SSH2_MSG_KEXGSS_ERROR 34 | ||
2554 | +#define SSH2_MSG_KEXGSS_GROUPREQ 40 | ||
2555 | +#define SSH2_MSG_KEXGSS_GROUP 41 | ||
2556 | +#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-" | ||
2557 | +#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" | ||
2558 | +#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" | ||
2559 | + | ||
2560 | typedef struct { | ||
2561 | char *filename; | ||
2562 | char *envvar; | ||
2563 | char *envval; | ||
2564 | + struct passwd *owner; | ||
2565 | void *data; | ||
2566 | } ssh_gssapi_ccache; | ||
2567 | |||
2568 | @@ -72,8 +84,11 @@ typedef struct { | ||
2569 | gss_buffer_desc displayname; | ||
2570 | gss_buffer_desc exportedname; | ||
2571 | gss_cred_id_t creds; | ||
2572 | + gss_name_t name; | ||
2573 | struct ssh_gssapi_mech_struct *mech; | ||
2574 | ssh_gssapi_ccache store; | ||
2575 | + int used; | ||
2576 | + int updated; | ||
2577 | } ssh_gssapi_client; | ||
2578 | |||
2579 | typedef struct ssh_gssapi_mech_struct { | ||
2580 | @@ -84,6 +99,7 @@ typedef struct ssh_gssapi_mech_struct { | ||
2581 | int (*userok) (ssh_gssapi_client *, char *); | ||
2582 | int (*localname) (ssh_gssapi_client *, char **); | ||
2583 | void (*storecreds) (ssh_gssapi_client *); | ||
2584 | + int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); | ||
2585 | } ssh_gssapi_mech; | ||
2586 | |||
2587 | typedef struct { | ||
2588 | @@ -94,10 +110,11 @@ typedef struct { | ||
2589 | gss_OID oid; /* client */ | ||
2590 | gss_cred_id_t creds; /* server */ | ||
2591 | gss_name_t client; /* server */ | ||
2592 | - gss_cred_id_t client_creds; /* server */ | ||
2593 | + gss_cred_id_t client_creds; /* both */ | ||
2594 | } Gssctxt; | ||
2595 | |||
2596 | extern ssh_gssapi_mech *supported_mechs[]; | ||
2597 | +extern Gssctxt *gss_kex_context; | ||
2598 | |||
2599 | int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); | ||
2600 | void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); | ||
2601 | @@ -119,16 +136,32 @@ void ssh_gssapi_build_ctx(Gssctxt **); | ||
2602 | void ssh_gssapi_delete_ctx(Gssctxt **); | ||
2603 | OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); | ||
2604 | void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); | ||
2605 | -int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); | ||
2606 | +int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *); | ||
2607 | +OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); | ||
2608 | +int ssh_gssapi_credentials_updated(Gssctxt *); | ||
2609 | |||
2610 | /* In the server */ | ||
2611 | +typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, | ||
2612 | + const char *); | ||
2613 | +char *ssh_gssapi_client_mechanisms(const char *, const char *); | ||
2614 | +char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *, | ||
2615 | + const char *); | ||
2616 | +gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); | ||
2617 | +int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, | ||
2618 | + const char *); | ||
2619 | OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); | ||
2620 | -int ssh_gssapi_userok(char *name); | ||
2621 | +int ssh_gssapi_userok(char *name, struct passwd *); | ||
2622 | OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); | ||
2623 | void ssh_gssapi_do_child(char ***, u_int *); | ||
2624 | void ssh_gssapi_cleanup_creds(void); | ||
2625 | void ssh_gssapi_storecreds(void); | ||
2626 | |||
2627 | +char *ssh_gssapi_server_mechanisms(void); | ||
2628 | +int ssh_gssapi_oid_table_ok(void); | ||
2629 | + | ||
2630 | +int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); | ||
2631 | +void ssh_gssapi_rekey_creds(void); | ||
2632 | + | ||
2633 | #endif /* GSSAPI */ | ||
2634 | |||
2635 | #endif /* _SSH_GSS_H */ | ||
2636 | diff --git a/ssh_config b/ssh_config | ||
2637 | index 03a228f..228e5ab 100644 | ||
2638 | --- a/ssh_config | ||
2639 | +++ b/ssh_config | ||
2640 | @@ -26,6 +26,8 @@ | ||
2641 | # HostbasedAuthentication no | ||
2642 | # GSSAPIAuthentication no | ||
2643 | # GSSAPIDelegateCredentials no | ||
2644 | +# GSSAPIKeyExchange no | ||
2645 | +# GSSAPITrustDNS no | ||
2646 | # BatchMode no | ||
2647 | # CheckHostIP yes | ||
2648 | # AddressFamily any | ||
2649 | diff --git a/ssh_config.5 b/ssh_config.5 | ||
2650 | index f9ede7a..e6649ac 100644 | ||
2651 | --- a/ssh_config.5 | ||
2652 | +++ b/ssh_config.5 | ||
2653 | @@ -701,11 +701,43 @@ Specifies whether user authentication based on GSSAPI is allowed. | ||
2654 | The default is | ||
2655 | .Dq no . | ||
2656 | Note that this option applies to protocol version 2 only. | ||
2657 | +.It Cm GSSAPIKeyExchange | ||
2658 | +Specifies whether key exchange based on GSSAPI may be used. When using | ||
2659 | +GSSAPI key exchange the server need not have a host key. | ||
2660 | +The default is | ||
2661 | +.Dq no . | ||
2662 | +Note that this option applies to protocol version 2 only. | ||
2663 | +.It Cm GSSAPIClientIdentity | ||
2664 | +If set, specifies the GSSAPI client identity that ssh should use when | ||
2665 | +connecting to the server. The default is unset, which means that the default | ||
2666 | +identity will be used. | ||
2667 | +.It Cm GSSAPIServerIdentity | ||
2668 | +If set, specifies the GSSAPI server identity that ssh should expect when | ||
2669 | +connecting to the server. The default is unset, which means that the | ||
2670 | +expected GSSAPI server identity will be determined from the target | ||
2671 | +hostname. | ||
2672 | .It Cm GSSAPIDelegateCredentials | ||
2673 | Forward (delegate) credentials to the server. | ||
2674 | The default is | ||
2675 | .Dq no . | ||
2676 | -Note that this option applies to protocol version 2 only. | ||
2677 | +Note that this option applies to protocol version 2 connections using GSSAPI. | ||
2678 | +.It Cm GSSAPIRenewalForcesRekey | ||
2679 | +If set to | ||
2680 | +.Dq yes | ||
2681 | +then renewal of the client's GSSAPI credentials will force the rekeying of the | ||
2682 | +ssh connection. With a compatible server, this can delegate the renewed | ||
2683 | +credentials to a session on the server. | ||
2684 | +The default is | ||
2685 | +.Dq no . | ||
2686 | +.It Cm GSSAPITrustDns | ||
2687 | +Set to | ||
2688 | +.Dq yes to indicate that the DNS is trusted to securely canonicalize | ||
2689 | +the name of the host being connected to. If | ||
2690 | +.Dq no, the hostname entered on the | ||
2691 | +command line will be passed untouched to the GSSAPI library. | ||
2692 | +The default is | ||
2693 | +.Dq no . | ||
2694 | +This option only applies to protocol version 2 connections using GSSAPI. | ||
2695 | .It Cm HashKnownHosts | ||
2696 | Indicates that | ||
2697 | .Xr ssh 1 | ||
2698 | diff --git a/sshconnect2.c b/sshconnect2.c | ||
2699 | index 68f7f4f..7b478f1 100644 | ||
2700 | --- a/sshconnect2.c | ||
2701 | +++ b/sshconnect2.c | ||
2702 | @@ -159,9 +159,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | ||
2703 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; | ||
2704 | Kex *kex; | ||
2705 | |||
2706 | +#ifdef GSSAPI | ||
2707 | + char *orig = NULL, *gss = NULL; | ||
2708 | + char *gss_host = NULL; | ||
2709 | +#endif | ||
2710 | + | ||
2711 | xxx_host = host; | ||
2712 | xxx_hostaddr = hostaddr; | ||
2713 | |||
2714 | +#ifdef GSSAPI | ||
2715 | + if (options.gss_keyex) { | ||
2716 | + /* Add the GSSAPI mechanisms currently supported on this | ||
2717 | + * client to the key exchange algorithm proposal */ | ||
2718 | + orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
2719 | + | ||
2720 | + if (options.gss_trust_dns) | ||
2721 | + gss_host = (char *)get_canonical_hostname(1); | ||
2722 | + else | ||
2723 | + gss_host = host; | ||
2724 | + | ||
2725 | + gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); | ||
2726 | + if (gss) { | ||
2727 | + debug("Offering GSSAPI proposal: %s", gss); | ||
2728 | + xasprintf(&myproposal[PROPOSAL_KEX_ALGS], | ||
2729 | + "%s,%s", gss, orig); | ||
2730 | + } | ||
2731 | + } | ||
2732 | +#endif | ||
2733 | + | ||
2734 | if (options.ciphers == (char *)-1) { | ||
2735 | logit("No valid ciphers for protocol version 2 given, using defaults."); | ||
2736 | options.ciphers = NULL; | ||
2737 | @@ -199,6 +224,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | ||
2738 | myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( | ||
2739 | myproposal[PROPOSAL_KEX_ALGS]); | ||
2740 | |||
2741 | +#ifdef GSSAPI | ||
2742 | + /* If we've got GSSAPI algorithms, then we also support the | ||
2743 | + * 'null' hostkey, as a last resort */ | ||
2744 | + if (options.gss_keyex && gss) { | ||
2745 | + orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; | ||
2746 | + xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], | ||
2747 | + "%s,null", orig); | ||
2748 | + free(gss); | ||
2749 | + } | ||
2750 | +#endif | ||
2751 | + | ||
2752 | if (options.rekey_limit || options.rekey_interval) | ||
2753 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, | ||
2754 | (time_t)options.rekey_interval); | ||
2755 | @@ -213,10 +249,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | ||
2756 | kex->kex[KEX_ECDH_SHA2] = kexecdh_client; | ||
2757 | #endif | ||
2758 | kex->kex[KEX_C25519_SHA256] = kexc25519_client; | ||
2759 | +#ifdef GSSAPI | ||
2760 | + if (options.gss_keyex) { | ||
2761 | + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; | ||
2762 | + kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; | ||
2763 | + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; | ||
2764 | + } | ||
2765 | +#endif | ||
2766 | kex->client_version_string=client_version_string; | ||
2767 | kex->server_version_string=server_version_string; | ||
2768 | kex->verify_host_key=&verify_host_key_callback; | ||
2769 | |||
2770 | +#ifdef GSSAPI | ||
2771 | + if (options.gss_keyex) { | ||
2772 | + kex->gss_deleg_creds = options.gss_deleg_creds; | ||
2773 | + kex->gss_trust_dns = options.gss_trust_dns; | ||
2774 | + kex->gss_client = options.gss_client_identity; | ||
2775 | + if (options.gss_server_identity) { | ||
2776 | + kex->gss_host = options.gss_server_identity; | ||
2777 | + } else { | ||
2778 | + kex->gss_host = gss_host; | ||
2779 | + } | ||
2780 | + } | ||
2781 | +#endif | ||
2782 | + | ||
2783 | xxx_kex = kex; | ||
2784 | |||
2785 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); | ||
2786 | @@ -306,6 +362,7 @@ void input_gssapi_token(int type, u_int32_t, void *); | ||
2787 | void input_gssapi_hash(int type, u_int32_t, void *); | ||
2788 | void input_gssapi_error(int, u_int32_t, void *); | ||
2789 | void input_gssapi_errtok(int, u_int32_t, void *); | ||
2790 | +int userauth_gsskeyex(Authctxt *authctxt); | ||
2791 | #endif | ||
2792 | |||
2793 | void userauth(Authctxt *, char *); | ||
2794 | @@ -321,6 +378,11 @@ static char *authmethods_get(void); | ||
2795 | |||
2796 | Authmethod authmethods[] = { | ||
2797 | #ifdef GSSAPI | ||
2798 | + {"gssapi-keyex", | ||
2799 | + userauth_gsskeyex, | ||
2800 | + NULL, | ||
2801 | + &options.gss_authentication, | ||
2802 | + NULL}, | ||
2803 | {"gssapi-with-mic", | ||
2804 | userauth_gssapi, | ||
2805 | NULL, | ||
2806 | @@ -617,19 +679,31 @@ userauth_gssapi(Authctxt *authctxt) | ||
2807 | static u_int mech = 0; | ||
2808 | OM_uint32 min; | ||
2809 | int ok = 0; | ||
2810 | + const char *gss_host; | ||
2811 | + | ||
2812 | + if (options.gss_server_identity) | ||
2813 | + gss_host = options.gss_server_identity; | ||
2814 | + else if (options.gss_trust_dns) | ||
2815 | + gss_host = get_canonical_hostname(1); | ||
2816 | + else | ||
2817 | + gss_host = authctxt->host; | ||
2818 | |||
2819 | /* Try one GSSAPI method at a time, rather than sending them all at | ||
2820 | * once. */ | ||
2821 | |||
2822 | if (gss_supported == NULL) | ||
2823 | - gss_indicate_mechs(&min, &gss_supported); | ||
2824 | + if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { | ||
2825 | + gss_supported = NULL; | ||
2826 | + return 0; | ||
2827 | + } | ||
2828 | |||
2829 | /* Check to see if the mechanism is usable before we offer it */ | ||
2830 | while (mech < gss_supported->count && !ok) { | ||
2831 | /* My DER encoding requires length<128 */ | ||
2832 | if (gss_supported->elements[mech].length < 128 && | ||
2833 | ssh_gssapi_check_mechanism(&gssctxt, | ||
2834 | - &gss_supported->elements[mech], authctxt->host)) { | ||
2835 | + &gss_supported->elements[mech], gss_host, | ||
2836 | + options.gss_client_identity)) { | ||
2837 | ok = 1; /* Mechanism works */ | ||
2838 | } else { | ||
2839 | mech++; | ||
2840 | @@ -726,8 +800,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) | ||
2841 | { | ||
2842 | Authctxt *authctxt = ctxt; | ||
2843 | Gssctxt *gssctxt; | ||
2844 | - int oidlen; | ||
2845 | - char *oidv; | ||
2846 | + u_int oidlen; | ||
2847 | + u_char *oidv; | ||
2848 | |||
2849 | if (authctxt == NULL) | ||
2850 | fatal("input_gssapi_response: no authentication context"); | ||
2851 | @@ -836,6 +910,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) | ||
2852 | free(msg); | ||
2853 | free(lang); | ||
2854 | } | ||
2855 | + | ||
2856 | +int | ||
2857 | +userauth_gsskeyex(Authctxt *authctxt) | ||
2858 | +{ | ||
2859 | + Buffer b; | ||
2860 | + gss_buffer_desc gssbuf; | ||
2861 | + gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; | ||
2862 | + OM_uint32 ms; | ||
2863 | + | ||
2864 | + static int attempt = 0; | ||
2865 | + if (attempt++ >= 1) | ||
2866 | + return (0); | ||
2867 | + | ||
2868 | + if (gss_kex_context == NULL) { | ||
2869 | + debug("No valid Key exchange context"); | ||
2870 | + return (0); | ||
2871 | + } | ||
2872 | + | ||
2873 | + ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, | ||
2874 | + "gssapi-keyex"); | ||
2875 | + | ||
2876 | + gssbuf.value = buffer_ptr(&b); | ||
2877 | + gssbuf.length = buffer_len(&b); | ||
2878 | + | ||
2879 | + if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { | ||
2880 | + buffer_free(&b); | ||
2881 | + return (0); | ||
2882 | + } | ||
2883 | + | ||
2884 | + packet_start(SSH2_MSG_USERAUTH_REQUEST); | ||
2885 | + packet_put_cstring(authctxt->server_user); | ||
2886 | + packet_put_cstring(authctxt->service); | ||
2887 | + packet_put_cstring(authctxt->method->name); | ||
2888 | + packet_put_string(mic.value, mic.length); | ||
2889 | + packet_send(); | ||
2890 | + | ||
2891 | + buffer_free(&b); | ||
2892 | + gss_release_buffer(&ms, &mic); | ||
2893 | + | ||
2894 | + return (1); | ||
2895 | +} | ||
2896 | + | ||
2897 | #endif /* GSSAPI */ | ||
2898 | |||
2899 | int | ||
2900 | diff --git a/sshd.c b/sshd.c | ||
2901 | index 481d001..e6706a8 100644 | ||
2902 | --- a/sshd.c | ||
2903 | +++ b/sshd.c | ||
2904 | @@ -123,6 +123,10 @@ | ||
2905 | #include "ssh-sandbox.h" | ||
2906 | #include "version.h" | ||
2907 | |||
2908 | +#ifdef USE_SECURITY_SESSION_API | ||
2909 | +#include <Security/AuthSession.h> | ||
2910 | +#endif | ||
2911 | + | ||
2912 | #ifndef O_NOCTTY | ||
2913 | #define O_NOCTTY 0 | ||
2914 | #endif | ||
2915 | @@ -1745,10 +1749,13 @@ main(int ac, char **av) | ||
2916 | logit("Disabling protocol version 1. Could not load host key"); | ||
2917 | options.protocol &= ~SSH_PROTO_1; | ||
2918 | } | ||
2919 | +#ifndef GSSAPI | ||
2920 | + /* The GSSAPI key exchange can run without a host key */ | ||
2921 | if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { | ||
2922 | logit("Disabling protocol version 2. Could not load host key"); | ||
2923 | options.protocol &= ~SSH_PROTO_2; | ||
2924 | } | ||
2925 | +#endif | ||
2926 | if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { | ||
2927 | logit("sshd: no hostkeys available -- exiting."); | ||
2928 | exit(1); | ||
2929 | @@ -2060,6 +2067,60 @@ main(int ac, char **av) | ||
2930 | remote_ip, remote_port, | ||
2931 | get_local_ipaddr(sock_in), get_local_port()); | ||
2932 | |||
2933 | +#ifdef USE_SECURITY_SESSION_API | ||
2934 | + /* | ||
2935 | + * Create a new security session for use by the new user login if | ||
2936 | + * the current session is the root session or we are not launched | ||
2937 | + * by inetd (eg: debugging mode or server mode). We do not | ||
2938 | + * necessarily need to create a session if we are launched from | ||
2939 | + * inetd because Panther xinetd will create a session for us. | ||
2940 | + * | ||
2941 | + * The only case where this logic will fail is if there is an | ||
2942 | + * inetd running in a non-root session which is not creating | ||
2943 | + * new sessions for us. Then all the users will end up in the | ||
2944 | + * same session (bad). | ||
2945 | + * | ||
2946 | + * When the client exits, the session will be destroyed for us | ||
2947 | + * automatically. | ||
2948 | + * | ||
2949 | + * We must create the session before any credentials are stored | ||
2950 | + * (including AFS pags, which happens a few lines below). | ||
2951 | + */ | ||
2952 | + { | ||
2953 | + OSStatus err = 0; | ||
2954 | + SecuritySessionId sid = 0; | ||
2955 | + SessionAttributeBits sattrs = 0; | ||
2956 | + | ||
2957 | + err = SessionGetInfo(callerSecuritySession, &sid, &sattrs); | ||
2958 | + if (err) | ||
2959 | + error("SessionGetInfo() failed with error %.8X", | ||
2960 | + (unsigned) err); | ||
2961 | + else | ||
2962 | + debug("Current Session ID is %.8X / Session Attributes are %.8X", | ||
2963 | + (unsigned) sid, (unsigned) sattrs); | ||
2964 | + | ||
2965 | + if (inetd_flag && !(sattrs & sessionIsRoot)) | ||
2966 | + debug("Running in inetd mode in a non-root session... " | ||
2967 | + "assuming inetd created the session for us."); | ||
2968 | + else { | ||
2969 | + debug("Creating new security session..."); | ||
2970 | + err = SessionCreate(0, sessionHasTTY | sessionIsRemote); | ||
2971 | + if (err) | ||
2972 | + error("SessionCreate() failed with error %.8X", | ||
2973 | + (unsigned) err); | ||
2974 | + | ||
2975 | + err = SessionGetInfo(callerSecuritySession, &sid, | ||
2976 | + &sattrs); | ||
2977 | + if (err) | ||
2978 | + error("SessionGetInfo() failed with error %.8X", | ||
2979 | + (unsigned) err); | ||
2980 | + else | ||
2981 | + debug("New Session ID is %.8X / Session Attributes are %.8X", | ||
2982 | + (unsigned) sid, (unsigned) sattrs); | ||
2983 | + } | ||
2984 | + } | ||
2985 | +#endif | ||
2986 | + | ||
2987 | /* | ||
2988 | * We don't want to listen forever unless the other side | ||
2989 | * successfully authenticates itself. So we set up an alarm which is | ||
2990 | @@ -2482,6 +2543,48 @@ do_ssh2_kex(void) | ||
2991 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( | ||
2992 | list_hostkey_types()); | ||
2993 | |||
2994 | +#ifdef GSSAPI | ||
2995 | + { | ||
2996 | + char *orig; | ||
2997 | + char *gss = NULL; | ||
2998 | + char *newstr = NULL; | ||
2999 | + orig = myproposal[PROPOSAL_KEX_ALGS]; | ||
3000 | + | ||
3001 | + /* | ||
3002 | + * If we don't have a host key, then there's no point advertising | ||
3003 | + * the other key exchange algorithms | ||
3004 | + */ | ||
3005 | + | ||
3006 | + if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) | ||
3007 | + orig = NULL; | ||
3008 | + | ||
3009 | + if (options.gss_keyex) | ||
3010 | + gss = ssh_gssapi_server_mechanisms(); | ||
3011 | + else | ||
3012 | + gss = NULL; | ||
3013 | + | ||
3014 | + if (gss && orig) | ||
3015 | + xasprintf(&newstr, "%s,%s", gss, orig); | ||
3016 | + else if (gss) | ||
3017 | + newstr = gss; | ||
3018 | + else if (orig) | ||
3019 | + newstr = orig; | ||
3020 | + | ||
3021 | + /* | ||
3022 | + * If we've got GSSAPI mechanisms, then we've got the 'null' host | ||
3023 | + * key alg, but we can't tell people about it unless its the only | ||
3024 | + * host key algorithm we support | ||
3025 | + */ | ||
3026 | + if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) | ||
3027 | + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null"; | ||
3028 | + | ||
3029 | + if (newstr) | ||
3030 | + myproposal[PROPOSAL_KEX_ALGS] = newstr; | ||
3031 | + else | ||
3032 | + fatal("No supported key exchange algorithms"); | ||
3033 | + } | ||
3034 | +#endif | ||
3035 | + | ||
3036 | /* start key exchange */ | ||
3037 | kex = kex_setup(myproposal); | ||
3038 | #ifdef WITH_OPENSSL | ||
3039 | @@ -2492,6 +2595,13 @@ do_ssh2_kex(void) | ||
3040 | kex->kex[KEX_ECDH_SHA2] = kexecdh_server; | ||
3041 | #endif | ||
3042 | kex->kex[KEX_C25519_SHA256] = kexc25519_server; | ||
3043 | +#ifdef GSSAPI | ||
3044 | + if (options.gss_keyex) { | ||
3045 | + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; | ||
3046 | + kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; | ||
3047 | + kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; | ||
3048 | + } | ||
3049 | +#endif | ||
3050 | kex->server = 1; | ||
3051 | kex->client_version_string=client_version_string; | ||
3052 | kex->server_version_string=server_version_string; | ||
3053 | diff --git a/sshd_config b/sshd_config | ||
3054 | index e9045bc..d9b8594 100644 | ||
3055 | --- a/sshd_config | ||
3056 | +++ b/sshd_config | ||
3057 | @@ -84,6 +84,8 @@ AuthorizedKeysFile .ssh/authorized_keys | ||
3058 | # GSSAPI options | ||
3059 | #GSSAPIAuthentication no | ||
3060 | #GSSAPICleanupCredentials yes | ||
3061 | +#GSSAPIStrictAcceptorCheck yes | ||
3062 | +#GSSAPIKeyExchange no | ||
3063 | |||
3064 | # Set this to 'yes' to enable PAM authentication, account processing, | ||
3065 | # and session processing. If this is enabled, PAM authentication will | ||
3066 | diff --git a/sshd_config.5 b/sshd_config.5 | ||
3067 | index fd44abe..c8b43da 100644 | ||
3068 | --- a/sshd_config.5 | ||
3069 | +++ b/sshd_config.5 | ||
3070 | @@ -527,12 +527,40 @@ Specifies whether user authentication based on GSSAPI is allowed. | ||
3071 | The default is | ||
3072 | .Dq no . | ||
3073 | Note that this option applies to protocol version 2 only. | ||
3074 | +.It Cm GSSAPIKeyExchange | ||
3075 | +Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange | ||
3076 | +doesn't rely on ssh keys to verify host identity. | ||
3077 | +The default is | ||
3078 | +.Dq no . | ||
3079 | +Note that this option applies to protocol version 2 only. | ||
3080 | .It Cm GSSAPICleanupCredentials | ||
3081 | Specifies whether to automatically destroy the user's credentials cache | ||
3082 | on logout. | ||
3083 | The default is | ||
3084 | .Dq yes . | ||
3085 | Note that this option applies to protocol version 2 only. | ||
3086 | +.It Cm GSSAPIStrictAcceptorCheck | ||
3087 | +Determines whether to be strict about the identity of the GSSAPI acceptor | ||
3088 | +a client authenticates against. If | ||
3089 | +.Dq yes | ||
3090 | +then the client must authenticate against the | ||
3091 | +.Pa host | ||
3092 | +service on the current hostname. If | ||
3093 | +.Dq no | ||
3094 | +then the client may authenticate against any service key stored in the | ||
3095 | +machine's default store. This facility is provided to assist with operation | ||
3096 | +on multi homed machines. | ||
3097 | +The default is | ||
3098 | +.Dq yes . | ||
3099 | +Note that this option applies only to protocol version 2 GSSAPI connections, | ||
3100 | +and setting it to | ||
3101 | +.Dq no | ||
3102 | +may only work with recent Kerberos GSSAPI libraries. | ||
3103 | +.It Cm GSSAPIStoreCredentialsOnRekey | ||
3104 | +Controls whether the user's GSSAPI credentials should be updated following a | ||
3105 | +successful connection rekeying. This option can be used to accepted renewed | ||
3106 | +or updated credentials from a compatible client. The default is | ||
3107 | +.Dq no . | ||
3108 | .It Cm HostbasedAuthentication | ||
3109 | Specifies whether rhosts or /etc/hosts.equiv authentication together | ||
3110 | with successful public key client host authentication is allowed | ||
3111 | diff --git a/sshkey.c b/sshkey.c | ||
3112 | index fdd0c8a..1a96eae 100644 | ||
3113 | --- a/sshkey.c | ||
3114 | +++ b/sshkey.c | ||
3115 | @@ -110,6 +110,7 @@ static const struct keytype keytypes[] = { | ||
3116 | { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00", | ||
3117 | KEY_DSA_CERT_V00, 0, 1 }, | ||
3118 | #endif /* WITH_OPENSSL */ | ||
3119 | + { "null", "null", KEY_NULL, 0, 0 }, | ||
3120 | { NULL, NULL, -1, -1, 0 } | ||
3121 | }; | ||
3122 | |||
3123 | @@ -198,7 +199,7 @@ key_alg_list(int certs_only, int plain_only) | ||
3124 | const struct keytype *kt; | ||
3125 | |||
3126 | for (kt = keytypes; kt->type != -1; kt++) { | ||
3127 | - if (kt->name == NULL) | ||
3128 | + if (kt->name == NULL || kt->type == KEY_NULL) | ||
3129 | continue; | ||
3130 | if ((certs_only && !kt->cert) || (plain_only && kt->cert)) | ||
3131 | continue; | ||
3132 | diff --git a/sshkey.h b/sshkey.h | ||
3133 | index 450b30c..b573e7f 100644 | ||
3134 | --- a/sshkey.h | ||
3135 | +++ b/sshkey.h | ||
3136 | @@ -64,6 +64,7 @@ enum sshkey_types { | ||
3137 | KEY_ED25519_CERT, | ||
3138 | KEY_RSA_CERT_V00, | ||
3139 | KEY_DSA_CERT_V00, | ||
3140 | + KEY_NULL, | ||
3141 | KEY_UNSPEC | ||
3142 | }; | ||
3143 | |||
diff --git a/debian/patches/helpful-wait-terminate.patch b/debian/patches/helpful-wait-terminate.patch new file mode 100644 index 000000000..de43f2a80 --- /dev/null +++ b/debian/patches/helpful-wait-terminate.patch | |||
@@ -0,0 +1,26 @@ | |||
1 | From aca34215fc0e85d6b49e04f0a3cd0db79732125e Mon Sep 17 00:00:00 2001 | ||
2 | From: Matthew Vernon <matthew@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:09:56 +0000 | ||
4 | Subject: Mention ~& when waiting for forwarded connections to terminate | ||
5 | |||
6 | Bug-Debian: http://bugs.debian.org/50308 | ||
7 | Last-Update: 2010-02-27 | ||
8 | |||
9 | Patch-Name: helpful-wait-terminate.patch | ||
10 | --- | ||
11 | serverloop.c | 2 +- | ||
12 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
13 | |||
14 | diff --git a/serverloop.c b/serverloop.c | ||
15 | index e92f9e2..813e5bf 100644 | ||
16 | --- a/serverloop.c | ||
17 | +++ b/serverloop.c | ||
18 | @@ -687,7 +687,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) | ||
19 | if (!channel_still_open()) | ||
20 | break; | ||
21 | if (!waiting_termination) { | ||
22 | - const char *s = "Waiting for forwarded connections to terminate...\r\n"; | ||
23 | + const char *s = "Waiting for forwarded connections to terminate... (press ~& to background)\r\n"; | ||
24 | char *cp; | ||
25 | waiting_termination = 1; | ||
26 | 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..15acabc0e --- /dev/null +++ b/debian/patches/keepalive-extensions.patch | |||
@@ -0,0 +1,135 @@ | |||
1 | From bd3abc2f732da3a61e4158b915480808957a4357 Mon Sep 17 00:00:00 2001 | ||
2 | From: Richard Kettlewell <rjk@greenend.org.uk> | ||
3 | Date: Sun, 9 Feb 2014 16:09:52 +0000 | ||
4 | Subject: Various keepalive extensions | ||
5 | |||
6 | Add compatibility aliases for ProtocolKeepAlives and SetupTimeOut, supported | ||
7 | in previous versions of Debian's OpenSSH package but since superseded by | ||
8 | ServerAliveInterval. (We're probably stuck with this bit for | ||
9 | compatibility.) | ||
10 | |||
11 | In batch mode, default ServerAliveInterval to five minutes. | ||
12 | |||
13 | Adjust documentation to match and to give some more advice on use of | ||
14 | keepalives. | ||
15 | |||
16 | Author: Ian Jackson <ian@chiark.greenend.org.uk> | ||
17 | Author: Matthew Vernon <matthew@debian.org> | ||
18 | Author: Colin Watson <cjwatson@debian.org> | ||
19 | Last-Update: 2014-10-07 | ||
20 | |||
21 | Patch-Name: keepalive-extensions.patch | ||
22 | --- | ||
23 | readconf.c | 14 ++++++++++++-- | ||
24 | ssh_config.5 | 21 +++++++++++++++++++-- | ||
25 | sshd_config.5 | 3 +++ | ||
26 | 3 files changed, 34 insertions(+), 4 deletions(-) | ||
27 | |||
28 | diff --git a/readconf.c b/readconf.c | ||
29 | index bc879eb..337818c 100644 | ||
30 | --- a/readconf.c | ||
31 | +++ b/readconf.c | ||
32 | @@ -153,6 +153,7 @@ typedef enum { | ||
33 | oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, | ||
34 | oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, | ||
35 | oStreamLocalBindMask, oStreamLocalBindUnlink, | ||
36 | + oProtocolKeepAlives, oSetupTimeOut, | ||
37 | oIgnoredUnknownOption, oDeprecated, oUnsupported | ||
38 | } OpCodes; | ||
39 | |||
40 | @@ -278,6 +279,8 @@ static struct { | ||
41 | { "streamlocalbindmask", oStreamLocalBindMask }, | ||
42 | { "streamlocalbindunlink", oStreamLocalBindUnlink }, | ||
43 | { "ignoreunknown", oIgnoreUnknown }, | ||
44 | + { "protocolkeepalives", oProtocolKeepAlives }, | ||
45 | + { "setuptimeout", oSetupTimeOut }, | ||
46 | |||
47 | { NULL, oBadOption } | ||
48 | }; | ||
49 | @@ -1271,6 +1274,8 @@ parse_int: | ||
50 | goto parse_flag; | ||
51 | |||
52 | case oServerAliveInterval: | ||
53 | + case oProtocolKeepAlives: /* Debian-specific compatibility alias */ | ||
54 | + case oSetupTimeOut: /* Debian-specific compatibility alias */ | ||
55 | intptr = &options->server_alive_interval; | ||
56 | goto parse_time; | ||
57 | |||
58 | @@ -1791,8 +1796,13 @@ fill_default_options(Options * options) | ||
59 | options->rekey_interval = 0; | ||
60 | if (options->verify_host_key_dns == -1) | ||
61 | options->verify_host_key_dns = 0; | ||
62 | - if (options->server_alive_interval == -1) | ||
63 | - options->server_alive_interval = 0; | ||
64 | + if (options->server_alive_interval == -1) { | ||
65 | + /* in batch mode, default is 5mins */ | ||
66 | + if (options->batch_mode == 1) | ||
67 | + options->server_alive_interval = 300; | ||
68 | + else | ||
69 | + options->server_alive_interval = 0; | ||
70 | + } | ||
71 | if (options->server_alive_count_max == -1) | ||
72 | options->server_alive_count_max = 3; | ||
73 | if (options->control_master == -1) | ||
74 | diff --git a/ssh_config.5 b/ssh_config.5 | ||
75 | index 01f1f7f..ea92ea8 100644 | ||
76 | --- a/ssh_config.5 | ||
77 | +++ b/ssh_config.5 | ||
78 | @@ -205,8 +205,12 @@ Valid arguments are | ||
79 | If set to | ||
80 | .Dq yes , | ||
81 | passphrase/password querying will be disabled. | ||
82 | +In addition, the | ||
83 | +.Cm ServerAliveInterval | ||
84 | +option will be set to 300 seconds by default. | ||
85 | This option is useful in scripts and other batch jobs where no user | ||
86 | -is present to supply the password. | ||
87 | +is present to supply the password, | ||
88 | +and where it is desirable to detect a broken network swiftly. | ||
89 | The argument must be | ||
90 | .Dq yes | ||
91 | or | ||
92 | @@ -1336,8 +1340,15 @@ from the server, | ||
93 | will send a message through the encrypted | ||
94 | channel to request a response from the server. | ||
95 | The default | ||
96 | -is 0, indicating that these messages will not be sent to the server. | ||
97 | +is 0, indicating that these messages will not be sent to the server, | ||
98 | +or 300 if the | ||
99 | +.Cm BatchMode | ||
100 | +option is set. | ||
101 | This option applies to protocol version 2 only. | ||
102 | +.Cm ProtocolKeepAlives | ||
103 | +and | ||
104 | +.Cm SetupTimeOut | ||
105 | +are Debian-specific compatibility aliases for this option. | ||
106 | .It Cm StreamLocalBindMask | ||
107 | Sets the octal file creation mode mask | ||
108 | .Pq umask | ||
109 | @@ -1403,6 +1414,12 @@ Specifies whether the system should send TCP keepalive messages to the | ||
110 | other side. | ||
111 | If they are sent, death of the connection or crash of one | ||
112 | of the machines will be properly noticed. | ||
113 | +This option only uses TCP keepalives (as opposed to using ssh level | ||
114 | +keepalives), so takes a long time to notice when the connection dies. | ||
115 | +As such, you probably want | ||
116 | +the | ||
117 | +.Cm ServerAliveInterval | ||
118 | +option as well. | ||
119 | However, this means that | ||
120 | connections will die if the route is down temporarily, and some people | ||
121 | find it annoying. | ||
122 | diff --git a/sshd_config.5 b/sshd_config.5 | ||
123 | index c8b43da..2843048 100644 | ||
124 | --- a/sshd_config.5 | ||
125 | +++ b/sshd_config.5 | ||
126 | @@ -1307,6 +1307,9 @@ This avoids infinitely hanging sessions. | ||
127 | .Pp | ||
128 | To disable TCP keepalive messages, the value should be set to | ||
129 | .Dq no . | ||
130 | +.Pp | ||
131 | +This option was formerly called | ||
132 | +.Cm KeepAlive . | ||
133 | .It Cm TrustedUserCAKeys | ||
134 | Specifies a file containing public keys of certificate authorities that are | ||
135 | trusted to sign user certificates for authentication. | ||
diff --git a/debian/patches/lintian-symlink-pickiness.patch b/debian/patches/lintian-symlink-pickiness.patch new file mode 100644 index 000000000..81b924e35 --- /dev/null +++ b/debian/patches/lintian-symlink-pickiness.patch | |||
@@ -0,0 +1,32 @@ | |||
1 | From 248d3bb8de371b55aaf3a8f544c15f3a25eb7339 Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:10:08 +0000 | ||
4 | Subject: Fix picky lintian errors about slogin symlinks | ||
5 | |||
6 | Apparently this breaks some SVR4 packaging systems, so upstream can't win | ||
7 | either way and opted to keep the status quo. We need this patch anyway. | ||
8 | |||
9 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1728 | ||
10 | Last-Update: 2013-09-14 | ||
11 | |||
12 | Patch-Name: lintian-symlink-pickiness.patch | ||
13 | --- | ||
14 | Makefile.in | 4 ++-- | ||
15 | 1 file changed, 2 insertions(+), 2 deletions(-) | ||
16 | |||
17 | diff --git a/Makefile.in b/Makefile.in | ||
18 | index a4402e9..4eab574 100644 | ||
19 | --- a/Makefile.in | ||
20 | +++ b/Makefile.in | ||
21 | @@ -315,9 +315,9 @@ install-files: | ||
22 | $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 | ||
23 | $(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8 | ||
24 | -rm -f $(DESTDIR)$(bindir)/slogin | ||
25 | - ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin | ||
26 | + ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin | ||
27 | -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 | ||
28 | - ln -s ./ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 | ||
29 | + ln -s ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 | ||
30 | |||
31 | install-sysconf: | ||
32 | if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \ | ||
diff --git a/debian/patches/mention-ssh-keygen-on-keychange.patch b/debian/patches/mention-ssh-keygen-on-keychange.patch new file mode 100644 index 000000000..f90c7e2b1 --- /dev/null +++ b/debian/patches/mention-ssh-keygen-on-keychange.patch | |||
@@ -0,0 +1,41 @@ | |||
1 | From 064453886f4c3d8ac0b0c8d015ad614c8bce3b42 Mon Sep 17 00:00:00 2001 | ||
2 | From: Scott Moser <smoser@ubuntu.com> | ||
3 | Date: Sun, 9 Feb 2014 16:10:03 +0000 | ||
4 | Subject: Mention ssh-keygen in ssh fingerprint changed warning | ||
5 | |||
6 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1843 | ||
7 | Bug-Ubuntu: https://bugs.launchpad.net/bugs/686607 | ||
8 | Last-Update: 2013-09-14 | ||
9 | |||
10 | Patch-Name: mention-ssh-keygen-on-keychange.patch | ||
11 | --- | ||
12 | sshconnect.c | 7 ++++++- | ||
13 | 1 file changed, 6 insertions(+), 1 deletion(-) | ||
14 | |||
15 | diff --git a/sshconnect.c b/sshconnect.c | ||
16 | index 26116d2..ab83d0c 100644 | ||
17 | --- a/sshconnect.c | ||
18 | +++ b/sshconnect.c | ||
19 | @@ -1066,9 +1066,12 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | ||
20 | error("%s. This could either mean that", key_msg); | ||
21 | error("DNS SPOOFING is happening or the IP address for the host"); | ||
22 | error("and its host key have changed at the same time."); | ||
23 | - if (ip_status != HOST_NEW) | ||
24 | + if (ip_status != HOST_NEW) { | ||
25 | error("Offending key for IP in %s:%lu", | ||
26 | ip_found->file, ip_found->line); | ||
27 | + error(" remove with: ssh-keygen -f \"%s\" -R %s", | ||
28 | + ip_found->file, ip); | ||
29 | + } | ||
30 | } | ||
31 | /* The host key has changed. */ | ||
32 | warn_changed_key(host_key); | ||
33 | @@ -1076,6 +1079,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, | ||
34 | user_hostfiles[0]); | ||
35 | error("Offending %s key in %s:%lu", key_type(host_found->key), | ||
36 | host_found->file, host_found->line); | ||
37 | + error(" remove with: ssh-keygen -f \"%s\" -R %s", | ||
38 | + host_found->file, host); | ||
39 | |||
40 | /* | ||
41 | * If strict host key checking is in use, the user will have | ||
diff --git a/debian/patches/no-openssl-version-status.patch b/debian/patches/no-openssl-version-status.patch new file mode 100644 index 000000000..dfcef83b0 --- /dev/null +++ b/debian/patches/no-openssl-version-status.patch | |||
@@ -0,0 +1,62 @@ | |||
1 | From 37fd625165d0df302e441d9cad9bcc742378eef5 Mon Sep 17 00:00:00 2001 | ||
2 | From: Kurt Roeckx <kurt@roeckx.be> | ||
3 | Date: Sun, 9 Feb 2014 16:10:14 +0000 | ||
4 | Subject: Don't check the status field of the OpenSSL version | ||
5 | |||
6 | There is no reason to check the version of OpenSSL (in Debian). If it's | ||
7 | not compatible the soname will change. OpenSSH seems to want to do a | ||
8 | check for the soname based on the version number, but wants to keep the | ||
9 | status of the release the same. Remove that check on the status since | ||
10 | it doesn't tell you anything about how compatible that version is. | ||
11 | |||
12 | Author: Colin Watson <cjwatson@debian.org> | ||
13 | Bug-Debian: https://bugs.debian.org/93581 | ||
14 | Bug-Debian: https://bugs.debian.org/664383 | ||
15 | Bug-Debian: https://bugs.debian.org/732940 | ||
16 | Forwarded: not-needed | ||
17 | Last-Update: 2014-10-07 | ||
18 | |||
19 | Patch-Name: no-openssl-version-status.patch | ||
20 | --- | ||
21 | openbsd-compat/openssl-compat.c | 6 +++--- | ||
22 | openbsd-compat/regress/opensslvertest.c | 1 + | ||
23 | 2 files changed, 4 insertions(+), 3 deletions(-) | ||
24 | |||
25 | diff --git a/openbsd-compat/openssl-compat.c b/openbsd-compat/openssl-compat.c | ||
26 | index 36570e4..defd5fb 100644 | ||
27 | --- a/openbsd-compat/openssl-compat.c | ||
28 | +++ b/openbsd-compat/openssl-compat.c | ||
29 | @@ -34,7 +34,7 @@ | ||
30 | /* | ||
31 | * OpenSSL version numbers: MNNFFPPS: major minor fix patch status | ||
32 | * We match major, minor, fix and status (not patch) for <1.0.0. | ||
33 | - * After that, we acceptable compatible fix versions (so we | ||
34 | + * After that, we accept compatible fix and status versions (so we | ||
35 | * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed | ||
36 | * within a patch series. | ||
37 | */ | ||
38 | @@ -55,10 +55,10 @@ ssh_compatible_openssl(long headerver, long libver) | ||
39 | } | ||
40 | |||
41 | /* | ||
42 | - * For versions >= 1.0.0, major,minor,status must match and library | ||
43 | + * For versions >= 1.0.0, major,minor must match and library | ||
44 | * fix version must be equal to or newer than the header. | ||
45 | */ | ||
46 | - mask = 0xfff0000fL; /* major,minor,status */ | ||
47 | + mask = 0xfff00000L; /* major,minor */ | ||
48 | hfix = (headerver & 0x000ff000) >> 12; | ||
49 | lfix = (libver & 0x000ff000) >> 12; | ||
50 | if ( (headerver & mask) == (libver & mask) && lfix >= hfix) | ||
51 | diff --git a/openbsd-compat/regress/opensslvertest.c b/openbsd-compat/regress/opensslvertest.c | ||
52 | index 5d019b5..5847487 100644 | ||
53 | --- a/openbsd-compat/regress/opensslvertest.c | ||
54 | +++ b/openbsd-compat/regress/opensslvertest.c | ||
55 | @@ -35,6 +35,7 @@ struct version_test { | ||
56 | |||
57 | /* built with 1.0.1b release headers */ | ||
58 | { 0x1000101fL, 0x1000101fL, 1},/* exact match */ | ||
59 | + { 0x1000101fL, 0x10001010L, 1}, /* different status: ok */ | ||
60 | { 0x1000101fL, 0x1000102fL, 1}, /* newer library patch version: ok */ | ||
61 | { 0x1000101fL, 0x1000100fL, 1}, /* older library patch version: ok */ | ||
62 | { 0x1000101fL, 0x1000201fL, 1}, /* newer library fix version: ok */ | ||
diff --git a/debian/patches/openbsd-docs.patch b/debian/patches/openbsd-docs.patch new file mode 100644 index 000000000..37ad675d4 --- /dev/null +++ b/debian/patches/openbsd-docs.patch | |||
@@ -0,0 +1,148 @@ | |||
1 | From 0b9407d3023938b02bccf7dd1874a871d0cc8eb5 Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:10:09 +0000 | ||
4 | Subject: Adjust various OpenBSD-specific references in manual pages | ||
5 | |||
6 | No single bug reference for this patch, but history includes: | ||
7 | http://bugs.debian.org/154434 (login.conf(5)) | ||
8 | http://bugs.debian.org/513417 (/etc/rc) | ||
9 | http://bugs.debian.org/530692 (ssl(8)) | ||
10 | https://bugs.launchpad.net/bugs/456660 (ssl(8)) | ||
11 | |||
12 | Forwarded: not-needed | ||
13 | Last-Update: 2014-10-07 | ||
14 | |||
15 | Patch-Name: openbsd-docs.patch | ||
16 | --- | ||
17 | moduli.5 | 4 ++-- | ||
18 | ssh-keygen.1 | 12 ++++-------- | ||
19 | ssh.1 | 4 ++++ | ||
20 | sshd.8 | 5 ++--- | ||
21 | sshd_config.5 | 3 +-- | ||
22 | 5 files changed, 13 insertions(+), 15 deletions(-) | ||
23 | |||
24 | diff --git a/moduli.5 b/moduli.5 | ||
25 | index ef0de08..149846c 100644 | ||
26 | --- a/moduli.5 | ||
27 | +++ b/moduli.5 | ||
28 | @@ -21,7 +21,7 @@ | ||
29 | .Nd Diffie-Hellman moduli | ||
30 | .Sh DESCRIPTION | ||
31 | The | ||
32 | -.Pa /etc/moduli | ||
33 | +.Pa /etc/ssh/moduli | ||
34 | file contains prime numbers and generators for use by | ||
35 | .Xr sshd 8 | ||
36 | in the Diffie-Hellman Group Exchange key exchange method. | ||
37 | @@ -110,7 +110,7 @@ first estimates the size of the modulus required to produce enough | ||
38 | Diffie-Hellman output to sufficiently key the selected symmetric cipher. | ||
39 | .Xr sshd 8 | ||
40 | then randomly selects a modulus from | ||
41 | -.Fa /etc/moduli | ||
42 | +.Fa /etc/ssh/moduli | ||
43 | that best meets the size requirement. | ||
44 | .Sh SEE ALSO | ||
45 | .Xr ssh-keygen 1 , | ||
46 | diff --git a/ssh-keygen.1 b/ssh-keygen.1 | ||
47 | index 723a016..79b948c 100644 | ||
48 | --- a/ssh-keygen.1 | ||
49 | +++ b/ssh-keygen.1 | ||
50 | @@ -172,9 +172,7 @@ key in | ||
51 | .Pa ~/.ssh/id_ed25519 | ||
52 | or | ||
53 | .Pa ~/.ssh/id_rsa . | ||
54 | -Additionally, the system administrator may use this to generate host keys, | ||
55 | -as seen in | ||
56 | -.Pa /etc/rc . | ||
57 | +Additionally, the system administrator may use this to generate host keys. | ||
58 | .Pp | ||
59 | Normally this program generates the key and asks for a file in which | ||
60 | to store the private key. | ||
61 | @@ -221,9 +219,7 @@ For each of the key types (rsa1, rsa, dsa, ecdsa and ed25519) | ||
62 | for which host keys | ||
63 | do not exist, generate the host keys with the default key file path, | ||
64 | an empty passphrase, default bits for the key type, and default comment. | ||
65 | -This is used by | ||
66 | -.Pa /etc/rc | ||
67 | -to generate new host keys. | ||
68 | +This is used by system administration scripts to generate new host keys. | ||
69 | .It Fl a Ar rounds | ||
70 | When saving a new-format private key (i.e. an ed25519 key or any SSH protocol | ||
71 | 2 key when the | ||
72 | @@ -628,7 +624,7 @@ option. | ||
73 | Valid generator values are 2, 3, and 5. | ||
74 | .Pp | ||
75 | Screened DH groups may be installed in | ||
76 | -.Pa /etc/moduli . | ||
77 | +.Pa /etc/ssh/moduli . | ||
78 | It is important that this file contains moduli of a range of bit lengths and | ||
79 | that both ends of a connection share common moduli. | ||
80 | .Sh CERTIFICATES | ||
81 | @@ -827,7 +823,7 @@ on all machines | ||
82 | where the user wishes to log in using public key authentication. | ||
83 | There is no need to keep the contents of this file secret. | ||
84 | .Pp | ||
85 | -.It Pa /etc/moduli | ||
86 | +.It Pa /etc/ssh/moduli | ||
87 | Contains Diffie-Hellman groups used for DH-GEX. | ||
88 | The file format is described in | ||
89 | .Xr moduli 5 . | ||
90 | diff --git a/ssh.1 b/ssh.1 | ||
91 | index 7f6ab77..de178cd 100644 | ||
92 | --- a/ssh.1 | ||
93 | +++ b/ssh.1 | ||
94 | @@ -753,6 +753,10 @@ Protocol 1 is restricted to using only RSA keys, | ||
95 | but protocol 2 may use any. | ||
96 | The HISTORY section of | ||
97 | .Xr ssl 8 | ||
98 | +(on non-OpenBSD systems, see | ||
99 | +.nh | ||
100 | +http://www.openbsd.org/cgi\-bin/man.cgi?query=ssl&sektion=8#HISTORY) | ||
101 | +.hy | ||
102 | contains a brief discussion of the DSA and RSA algorithms. | ||
103 | .Pp | ||
104 | The file | ||
105 | diff --git a/sshd.8 b/sshd.8 | ||
106 | index eaeac45..3538208 100644 | ||
107 | --- a/sshd.8 | ||
108 | +++ b/sshd.8 | ||
109 | @@ -67,7 +67,7 @@ over an insecure network. | ||
110 | .Nm | ||
111 | listens for connections from clients. | ||
112 | It is normally started at boot from | ||
113 | -.Pa /etc/rc . | ||
114 | +.Pa /etc/init.d/ssh . | ||
115 | It forks a new | ||
116 | daemon for each incoming connection. | ||
117 | The forked daemons handle | ||
118 | @@ -862,7 +862,7 @@ This file is for host-based authentication (see | ||
119 | .Xr ssh 1 ) . | ||
120 | It should only be writable by root. | ||
121 | .Pp | ||
122 | -.It Pa /etc/moduli | ||
123 | +.It Pa /etc/ssh/moduli | ||
124 | Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange". | ||
125 | The file format is described in | ||
126 | .Xr moduli 5 . | ||
127 | @@ -961,7 +961,6 @@ The content of this file is not sensitive; it can be world-readable. | ||
128 | .Xr ssh-keyscan 1 , | ||
129 | .Xr chroot 2 , | ||
130 | .Xr hosts_access 5 , | ||
131 | -.Xr login.conf 5 , | ||
132 | .Xr moduli 5 , | ||
133 | .Xr sshd_config 5 , | ||
134 | .Xr inetd 8 , | ||
135 | diff --git a/sshd_config.5 b/sshd_config.5 | ||
136 | index 58997d3..7396b23 100644 | ||
137 | --- a/sshd_config.5 | ||
138 | +++ b/sshd_config.5 | ||
139 | @@ -303,8 +303,7 @@ This option is only available for protocol version 2. | ||
140 | By default, no banner is displayed. | ||
141 | .It Cm ChallengeResponseAuthentication | ||
142 | Specifies whether challenge-response authentication is allowed (e.g. via | ||
143 | -PAM or through authentication styles supported in | ||
144 | -.Xr login.conf 5 ) | ||
145 | +PAM). | ||
146 | The default is | ||
147 | .Dq yes . | ||
148 | .It Cm ChrootDirectory | ||
diff --git a/debian/patches/package-versioning.patch b/debian/patches/package-versioning.patch new file mode 100644 index 000000000..07a28af9a --- /dev/null +++ b/debian/patches/package-versioning.patch | |||
@@ -0,0 +1,65 @@ | |||
1 | From 8679c96f74ee7dbea6c15c764b036fbab7372740 Mon Sep 17 00:00:00 2001 | ||
2 | From: Matthew Vernon <matthew@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:10:05 +0000 | ||
4 | Subject: Include the Debian version in our identification | ||
5 | |||
6 | This makes it easier to audit networks for versions patched against security | ||
7 | vulnerabilities. It has little detrimental effect, as attackers will | ||
8 | generally just try attacks rather than bothering to scan for | ||
9 | vulnerable-looking version strings. (However, see debian-banner.patch.) | ||
10 | |||
11 | Forwarded: not-needed | ||
12 | Last-Update: 2013-09-14 | ||
13 | |||
14 | Patch-Name: package-versioning.patch | ||
15 | --- | ||
16 | sshconnect.c | 4 ++-- | ||
17 | sshd.c | 2 +- | ||
18 | version.h | 7 ++++++- | ||
19 | 3 files changed, 9 insertions(+), 4 deletions(-) | ||
20 | |||
21 | diff --git a/sshconnect.c b/sshconnect.c | ||
22 | index ab83d0c..563405e 100644 | ||
23 | --- a/sshconnect.c | ||
24 | +++ b/sshconnect.c | ||
25 | @@ -521,10 +521,10 @@ send_client_banner(int connection_out, int minor1) | ||
26 | /* Send our own protocol version identification. */ | ||
27 | if (compat20) { | ||
28 | xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n", | ||
29 | - PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION); | ||
30 | + PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE); | ||
31 | } else { | ||
32 | xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n", | ||
33 | - PROTOCOL_MAJOR_1, minor1, SSH_VERSION); | ||
34 | + PROTOCOL_MAJOR_1, minor1, SSH_RELEASE); | ||
35 | } | ||
36 | if (roaming_atomicio(vwrite, connection_out, client_version_string, | ||
37 | strlen(client_version_string)) != strlen(client_version_string)) | ||
38 | diff --git a/sshd.c b/sshd.c | ||
39 | index 48a14dd..1710e71 100644 | ||
40 | --- a/sshd.c | ||
41 | +++ b/sshd.c | ||
42 | @@ -443,7 +443,7 @@ sshd_exchange_identification(int sock_in, int sock_out) | ||
43 | } | ||
44 | |||
45 | xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s", | ||
46 | - major, minor, SSH_VERSION, | ||
47 | + major, minor, SSH_RELEASE, | ||
48 | *options.version_addendum == '\0' ? "" : " ", | ||
49 | options.version_addendum, newline); | ||
50 | |||
51 | diff --git a/version.h b/version.h | ||
52 | index cc8a079..0fee7c3 100644 | ||
53 | --- a/version.h | ||
54 | +++ b/version.h | ||
55 | @@ -3,4 +3,9 @@ | ||
56 | #define SSH_VERSION "OpenSSH_6.7" | ||
57 | |||
58 | #define SSH_PORTABLE "p1" | ||
59 | -#define SSH_RELEASE SSH_VERSION SSH_PORTABLE | ||
60 | +#define SSH_RELEASE_MINIMUM SSH_VERSION SSH_PORTABLE | ||
61 | +#ifdef SSH_EXTRAVERSION | ||
62 | +#define SSH_RELEASE SSH_RELEASE_MINIMUM " " SSH_EXTRAVERSION | ||
63 | +#else | ||
64 | +#define SSH_RELEASE SSH_RELEASE_MINIMUM | ||
65 | +#endif | ||
diff --git a/debian/patches/quieter-signals.patch b/debian/patches/quieter-signals.patch new file mode 100644 index 000000000..6d9a2f9c0 --- /dev/null +++ b/debian/patches/quieter-signals.patch | |||
@@ -0,0 +1,40 @@ | |||
1 | From dc028c5992b4b14cca380b6ad2115fcc6907a8b7 Mon Sep 17 00:00:00 2001 | ||
2 | From: Peter Samuelson <peter@p12n.org> | ||
3 | Date: Sun, 9 Feb 2014 16:09:55 +0000 | ||
4 | Subject: Reduce severity of "Killed by signal %d" | ||
5 | |||
6 | This produces irritating messages when using ProxyCommand or other programs | ||
7 | that use ssh under the covers (e.g. Subversion). These messages are more | ||
8 | normally printed by the calling program, such as the shell. | ||
9 | |||
10 | According to the upstream bug, the right way to avoid this is to use the -q | ||
11 | option, so we may drop this patch after further investigation into whether | ||
12 | any software in Debian is still relying on it. | ||
13 | |||
14 | Author: Colin Watson <cjwatson@debian.org> | ||
15 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1118 | ||
16 | Bug-Debian: http://bugs.debian.org/313371 | ||
17 | Last-Update: 2013-09-14 | ||
18 | |||
19 | Patch-Name: quieter-signals.patch | ||
20 | --- | ||
21 | clientloop.c | 6 ++++-- | ||
22 | 1 file changed, 4 insertions(+), 2 deletions(-) | ||
23 | |||
24 | diff --git a/clientloop.c b/clientloop.c | ||
25 | index 046ca8b..0180774 100644 | ||
26 | --- a/clientloop.c | ||
27 | +++ b/clientloop.c | ||
28 | @@ -1705,8 +1705,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | ||
29 | exit_status = 0; | ||
30 | } | ||
31 | |||
32 | - if (received_signal) | ||
33 | - fatal("Killed by signal %d.", (int) received_signal); | ||
34 | + if (received_signal) { | ||
35 | + debug("Killed by signal %d.", (int) received_signal); | ||
36 | + cleanup_exit((int) received_signal + 128); | ||
37 | + } | ||
38 | |||
39 | /* | ||
40 | * In interactive mode (with pseudo tty) display a message indicating | ||
diff --git a/debian/patches/restore-tcp-wrappers.patch b/debian/patches/restore-tcp-wrappers.patch new file mode 100644 index 000000000..c590f52ce --- /dev/null +++ b/debian/patches/restore-tcp-wrappers.patch | |||
@@ -0,0 +1,172 @@ | |||
1 | From b25d6dd3b6b5a2cb93723586c56d6fa0277ea56a Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Tue, 7 Oct 2014 13:22:41 +0100 | ||
4 | Subject: Restore TCP wrappers support | ||
5 | |||
6 | Support for TCP wrappers was dropped in OpenSSH 6.7. See this message | ||
7 | and thread: | ||
8 | |||
9 | https://lists.mindrot.org/pipermail/openssh-unix-dev/2014-April/032497.html | ||
10 | |||
11 | It is true that this reduces preauth attack surface in sshd. On the | ||
12 | other hand, this support seems to be quite widely used, and abruptly | ||
13 | dropping it (from the perspective of users who don't read | ||
14 | openssh-unix-dev) could easily cause more serious problems in practice. | ||
15 | |||
16 | It's not entirely clear what the right long-term answer for Debian is, | ||
17 | but it at least probably doesn't involve dropping this feature shortly | ||
18 | before a freeze. | ||
19 | |||
20 | Forwarded: not-needed | ||
21 | Last-Update: 2014-10-07 | ||
22 | |||
23 | Patch-Name: restore-tcp-wrappers.patch | ||
24 | --- | ||
25 | configure.ac | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | ||
26 | sshd.8 | 7 +++++++ | ||
27 | sshd.c | 25 +++++++++++++++++++++++++ | ||
28 | 3 files changed, 89 insertions(+) | ||
29 | |||
30 | diff --git a/configure.ac b/configure.ac | ||
31 | index 90e81e1..7f160f1 100644 | ||
32 | --- a/configure.ac | ||
33 | +++ b/configure.ac | ||
34 | @@ -1404,6 +1404,62 @@ AC_ARG_WITH([skey], | ||
35 | ] | ||
36 | ) | ||
37 | |||
38 | +# Check whether user wants TCP wrappers support | ||
39 | +TCPW_MSG="no" | ||
40 | +AC_ARG_WITH([tcp-wrappers], | ||
41 | + [ --with-tcp-wrappers[[=PATH]] Enable tcpwrappers support (optionally in PATH)], | ||
42 | + [ | ||
43 | + if test "x$withval" != "xno" ; then | ||
44 | + saved_LIBS="$LIBS" | ||
45 | + saved_LDFLAGS="$LDFLAGS" | ||
46 | + saved_CPPFLAGS="$CPPFLAGS" | ||
47 | + if test -n "${withval}" && \ | ||
48 | + test "x${withval}" != "xyes"; then | ||
49 | + if test -d "${withval}/lib"; then | ||
50 | + if test -n "${need_dash_r}"; then | ||
51 | + LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" | ||
52 | + else | ||
53 | + LDFLAGS="-L${withval}/lib ${LDFLAGS}" | ||
54 | + fi | ||
55 | + else | ||
56 | + if test -n "${need_dash_r}"; then | ||
57 | + LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" | ||
58 | + else | ||
59 | + LDFLAGS="-L${withval} ${LDFLAGS}" | ||
60 | + fi | ||
61 | + fi | ||
62 | + if test -d "${withval}/include"; then | ||
63 | + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" | ||
64 | + else | ||
65 | + CPPFLAGS="-I${withval} ${CPPFLAGS}" | ||
66 | + fi | ||
67 | + fi | ||
68 | + LIBS="-lwrap $LIBS" | ||
69 | + AC_MSG_CHECKING([for libwrap]) | ||
70 | + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ | ||
71 | +#include <sys/types.h> | ||
72 | +#include <sys/socket.h> | ||
73 | +#include <netinet/in.h> | ||
74 | +#include <tcpd.h> | ||
75 | +int deny_severity = 0, allow_severity = 0; | ||
76 | + ]], [[ | ||
77 | + hosts_access(0); | ||
78 | + ]])], [ | ||
79 | + AC_MSG_RESULT([yes]) | ||
80 | + AC_DEFINE([LIBWRAP], [1], | ||
81 | + [Define if you want | ||
82 | + TCP Wrappers support]) | ||
83 | + SSHDLIBS="$SSHDLIBS -lwrap" | ||
84 | + TCPW_MSG="yes" | ||
85 | + ], [ | ||
86 | + AC_MSG_ERROR([*** libwrap missing]) | ||
87 | + | ||
88 | + ]) | ||
89 | + LIBS="$saved_LIBS" | ||
90 | + fi | ||
91 | + ] | ||
92 | +) | ||
93 | + | ||
94 | # Check whether user wants to use ldns | ||
95 | LDNS_MSG="no" | ||
96 | AC_ARG_WITH(ldns, | ||
97 | @@ -4853,6 +4909,7 @@ echo " KerberosV support: $KRB5_MSG" | ||
98 | echo " SELinux support: $SELINUX_MSG" | ||
99 | echo " Smartcard support: $SCARD_MSG" | ||
100 | echo " S/KEY support: $SKEY_MSG" | ||
101 | +echo " TCP Wrappers support: $TCPW_MSG" | ||
102 | echo " MD5 password support: $MD5_MSG" | ||
103 | echo " libedit support: $LIBEDIT_MSG" | ||
104 | echo " Solaris process contract support: $SPC_MSG" | ||
105 | diff --git a/sshd.8 b/sshd.8 | ||
106 | index 01459d6..eaeac45 100644 | ||
107 | --- a/sshd.8 | ||
108 | +++ b/sshd.8 | ||
109 | @@ -851,6 +851,12 @@ the user's home directory becomes accessible. | ||
110 | This file should be writable only by the user, and need not be | ||
111 | readable by anyone else. | ||
112 | .Pp | ||
113 | +.It Pa /etc/hosts.allow | ||
114 | +.It Pa /etc/hosts.deny | ||
115 | +Access controls that should be enforced by tcp-wrappers are defined here. | ||
116 | +Further details are described in | ||
117 | +.Xr hosts_access 5 . | ||
118 | +.Pp | ||
119 | .It Pa /etc/hosts.equiv | ||
120 | This file is for host-based authentication (see | ||
121 | .Xr ssh 1 ) . | ||
122 | @@ -954,6 +960,7 @@ The content of this file is not sensitive; it can be world-readable. | ||
123 | .Xr ssh-keygen 1 , | ||
124 | .Xr ssh-keyscan 1 , | ||
125 | .Xr chroot 2 , | ||
126 | +.Xr hosts_access 5 , | ||
127 | .Xr login.conf 5 , | ||
128 | .Xr moduli 5 , | ||
129 | .Xr sshd_config 5 , | ||
130 | diff --git a/sshd.c b/sshd.c | ||
131 | index e6706a8..3a6be65 100644 | ||
132 | --- a/sshd.c | ||
133 | +++ b/sshd.c | ||
134 | @@ -127,6 +127,13 @@ | ||
135 | #include <Security/AuthSession.h> | ||
136 | #endif | ||
137 | |||
138 | +#ifdef LIBWRAP | ||
139 | +#include <tcpd.h> | ||
140 | +#include <syslog.h> | ||
141 | +int allow_severity; | ||
142 | +int deny_severity; | ||
143 | +#endif /* LIBWRAP */ | ||
144 | + | ||
145 | #ifndef O_NOCTTY | ||
146 | #define O_NOCTTY 0 | ||
147 | #endif | ||
148 | @@ -2061,6 +2068,24 @@ main(int ac, char **av) | ||
149 | #ifdef SSH_AUDIT_EVENTS | ||
150 | audit_connection_from(remote_ip, remote_port); | ||
151 | #endif | ||
152 | +#ifdef LIBWRAP | ||
153 | + allow_severity = options.log_facility|LOG_INFO; | ||
154 | + deny_severity = options.log_facility|LOG_WARNING; | ||
155 | + /* Check whether logins are denied from this host. */ | ||
156 | + if (packet_connection_is_on_socket()) { | ||
157 | + struct request_info req; | ||
158 | + | ||
159 | + request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0); | ||
160 | + fromhost(&req); | ||
161 | + | ||
162 | + if (!hosts_access(&req)) { | ||
163 | + debug("Connection refused by tcp wrapper"); | ||
164 | + refuse(&req); | ||
165 | + /* NOTREACHED */ | ||
166 | + fatal("libwrap refuse returns"); | ||
167 | + } | ||
168 | + } | ||
169 | +#endif /* LIBWRAP */ | ||
170 | |||
171 | /* Log the connection. */ | ||
172 | verbose("Connection from %s port %d on %s port %d", | ||
diff --git a/debian/patches/scp-quoting.patch b/debian/patches/scp-quoting.patch new file mode 100644 index 000000000..ee006da93 --- /dev/null +++ b/debian/patches/scp-quoting.patch | |||
@@ -0,0 +1,41 @@ | |||
1 | From fd174c13c46191abdb33c0a45545573a8e06b061 Mon Sep 17 00:00:00 2001 | ||
2 | From: =?UTF-8?q?Nicolas=20Valc=C3=A1rcel?= <nvalcarcel@ubuntu.com> | ||
3 | Date: Sun, 9 Feb 2014 16:09:59 +0000 | ||
4 | Subject: Adjust scp quoting in verbose mode | ||
5 | |||
6 | Tweak scp's reporting of filenames in verbose mode to be a bit less | ||
7 | confusing with spaces. | ||
8 | |||
9 | This should be revised to mimic real shell quoting. | ||
10 | |||
11 | Bug-Ubuntu: https://bugs.launchpad.net/bugs/89945 | ||
12 | Last-Update: 2010-02-27 | ||
13 | |||
14 | Patch-Name: scp-quoting.patch | ||
15 | --- | ||
16 | scp.c | 12 ++++++++++-- | ||
17 | 1 file changed, 10 insertions(+), 2 deletions(-) | ||
18 | |||
19 | diff --git a/scp.c b/scp.c | ||
20 | index 1ec3b70..a1b318b 100644 | ||
21 | --- a/scp.c | ||
22 | +++ b/scp.c | ||
23 | @@ -189,8 +189,16 @@ do_local_cmd(arglist *a) | ||
24 | |||
25 | if (verbose_mode) { | ||
26 | fprintf(stderr, "Executing:"); | ||
27 | - for (i = 0; i < a->num; i++) | ||
28 | - fprintf(stderr, " %s", a->list[i]); | ||
29 | + for (i = 0; i < a->num; i++) { | ||
30 | + if (i == 0) | ||
31 | + fprintf(stderr, " %s", a->list[i]); | ||
32 | + else | ||
33 | + /* | ||
34 | + * TODO: misbehaves if a->list[i] contains a | ||
35 | + * single quote | ||
36 | + */ | ||
37 | + fprintf(stderr, " '%s'", a->list[i]); | ||
38 | + } | ||
39 | fprintf(stderr, "\n"); | ||
40 | } | ||
41 | if ((pid = fork()) == -1) | ||
diff --git a/debian/patches/selinux-role.patch b/debian/patches/selinux-role.patch new file mode 100644 index 000000000..1fa0bf928 --- /dev/null +++ b/debian/patches/selinux-role.patch | |||
@@ -0,0 +1,504 @@ | |||
1 | From c9638aa44d787849cea1ae273f0908c6313fd19b Mon Sep 17 00:00:00 2001 | ||
2 | From: Manoj Srivastava <srivasta@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:09:49 +0000 | ||
4 | Subject: Handle SELinux authorisation roles | ||
5 | |||
6 | Rejected upstream due to discomfort with magic usernames; a better approach | ||
7 | will need an SSH protocol change. In the meantime, this came from Debian's | ||
8 | SELinux maintainer, so we'll keep it until we have something better. | ||
9 | |||
10 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1641 | ||
11 | Bug-Debian: http://bugs.debian.org/394795 | ||
12 | Last-Update: 2013-09-14 | ||
13 | |||
14 | Patch-Name: selinux-role.patch | ||
15 | --- | ||
16 | auth.h | 1 + | ||
17 | auth1.c | 8 +++++++- | ||
18 | auth2.c | 10 ++++++++-- | ||
19 | monitor.c | 32 +++++++++++++++++++++++++++++--- | ||
20 | monitor.h | 2 ++ | ||
21 | monitor_wrap.c | 22 ++++++++++++++++++++-- | ||
22 | monitor_wrap.h | 3 ++- | ||
23 | openbsd-compat/port-linux.c | 27 ++++++++++++++++++++------- | ||
24 | openbsd-compat/port-linux.h | 4 ++-- | ||
25 | platform.c | 4 ++-- | ||
26 | platform.h | 2 +- | ||
27 | session.c | 10 +++++----- | ||
28 | session.h | 2 +- | ||
29 | sshd.c | 2 +- | ||
30 | sshpty.c | 4 ++-- | ||
31 | sshpty.h | 2 +- | ||
32 | 16 files changed, 104 insertions(+), 31 deletions(-) | ||
33 | |||
34 | diff --git a/auth.h b/auth.h | ||
35 | index d081c94..f099e98 100644 | ||
36 | --- a/auth.h | ||
37 | +++ b/auth.h | ||
38 | @@ -59,6 +59,7 @@ struct Authctxt { | ||
39 | char *service; | ||
40 | struct passwd *pw; /* set if 'valid' */ | ||
41 | char *style; | ||
42 | + char *role; | ||
43 | void *kbdintctxt; | ||
44 | char *info; /* Extra info for next auth_log */ | ||
45 | #ifdef BSD_AUTH | ||
46 | diff --git a/auth1.c b/auth1.c | ||
47 | index 5038828..52b17db 100644 | ||
48 | --- a/auth1.c | ||
49 | +++ b/auth1.c | ||
50 | @@ -381,7 +381,7 @@ void | ||
51 | do_authentication(Authctxt *authctxt) | ||
52 | { | ||
53 | u_int ulen; | ||
54 | - char *user, *style = NULL; | ||
55 | + char *user, *style = NULL, *role = NULL; | ||
56 | |||
57 | /* Get the name of the user that we wish to log in as. */ | ||
58 | packet_read_expect(SSH_CMSG_USER); | ||
59 | @@ -390,11 +390,17 @@ do_authentication(Authctxt *authctxt) | ||
60 | user = packet_get_cstring(&ulen); | ||
61 | packet_check_eom(); | ||
62 | |||
63 | + if ((role = strchr(user, '/')) != NULL) | ||
64 | + *role++ = '\0'; | ||
65 | + | ||
66 | if ((style = strchr(user, ':')) != NULL) | ||
67 | *style++ = '\0'; | ||
68 | + else if (role && (style = strchr(role, ':')) != NULL) | ||
69 | + *style++ = '\0'; | ||
70 | |||
71 | authctxt->user = user; | ||
72 | authctxt->style = style; | ||
73 | + authctxt->role = role; | ||
74 | |||
75 | /* Verify that the user is a valid user. */ | ||
76 | if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL) | ||
77 | diff --git a/auth2.c b/auth2.c | ||
78 | index 2f0d565..fa1a588 100644 | ||
79 | --- a/auth2.c | ||
80 | +++ b/auth2.c | ||
81 | @@ -217,7 +217,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) | ||
82 | { | ||
83 | Authctxt *authctxt = ctxt; | ||
84 | Authmethod *m = NULL; | ||
85 | - char *user, *service, *method, *style = NULL; | ||
86 | + char *user, *service, *method, *style = NULL, *role = NULL; | ||
87 | int authenticated = 0; | ||
88 | |||
89 | if (authctxt == NULL) | ||
90 | @@ -229,8 +229,13 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) | ||
91 | debug("userauth-request for user %s service %s method %s", user, service, method); | ||
92 | debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); | ||
93 | |||
94 | + if ((role = strchr(user, '/')) != NULL) | ||
95 | + *role++ = 0; | ||
96 | + | ||
97 | if ((style = strchr(user, ':')) != NULL) | ||
98 | *style++ = 0; | ||
99 | + else if (role && (style = strchr(role, ':')) != NULL) | ||
100 | + *style++ = '\0'; | ||
101 | |||
102 | if (authctxt->attempt++ == 0) { | ||
103 | /* setup auth context */ | ||
104 | @@ -254,8 +259,9 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) | ||
105 | use_privsep ? " [net]" : ""); | ||
106 | authctxt->service = xstrdup(service); | ||
107 | authctxt->style = style ? xstrdup(style) : NULL; | ||
108 | + authctxt->role = role ? xstrdup(role) : NULL; | ||
109 | if (use_privsep) | ||
110 | - mm_inform_authserv(service, style); | ||
111 | + mm_inform_authserv(service, style, role); | ||
112 | userauth_banner(); | ||
113 | if (auth2_setup_methods_lists(authctxt) != 0) | ||
114 | packet_disconnect("no authentication methods enabled"); | ||
115 | diff --git a/monitor.c b/monitor.c | ||
116 | index b0896ef..94b194d 100644 | ||
117 | --- a/monitor.c | ||
118 | +++ b/monitor.c | ||
119 | @@ -148,6 +148,7 @@ int mm_answer_sign(int, Buffer *); | ||
120 | int mm_answer_pwnamallow(int, Buffer *); | ||
121 | int mm_answer_auth2_read_banner(int, Buffer *); | ||
122 | int mm_answer_authserv(int, Buffer *); | ||
123 | +int mm_answer_authrole(int, Buffer *); | ||
124 | int mm_answer_authpassword(int, Buffer *); | ||
125 | int mm_answer_bsdauthquery(int, Buffer *); | ||
126 | int mm_answer_bsdauthrespond(int, Buffer *); | ||
127 | @@ -229,6 +230,7 @@ struct mon_table mon_dispatch_proto20[] = { | ||
128 | {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, | ||
129 | {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, | ||
130 | {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, | ||
131 | + {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole}, | ||
132 | {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, | ||
133 | {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, | ||
134 | #ifdef USE_PAM | ||
135 | @@ -841,6 +843,7 @@ mm_answer_pwnamallow(int sock, Buffer *m) | ||
136 | else { | ||
137 | /* Allow service/style information on the auth context */ | ||
138 | monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); | ||
139 | + monitor_permit(mon_dispatch, MONITOR_REQ_AUTHROLE, 1); | ||
140 | monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); | ||
141 | } | ||
142 | #ifdef USE_PAM | ||
143 | @@ -871,14 +874,37 @@ mm_answer_authserv(int sock, Buffer *m) | ||
144 | |||
145 | authctxt->service = buffer_get_string(m, NULL); | ||
146 | authctxt->style = buffer_get_string(m, NULL); | ||
147 | - debug3("%s: service=%s, style=%s", | ||
148 | - __func__, authctxt->service, authctxt->style); | ||
149 | + authctxt->role = buffer_get_string(m, NULL); | ||
150 | + debug3("%s: service=%s, style=%s, role=%s", | ||
151 | + __func__, authctxt->service, authctxt->style, authctxt->role); | ||
152 | |||
153 | if (strlen(authctxt->style) == 0) { | ||
154 | free(authctxt->style); | ||
155 | authctxt->style = NULL; | ||
156 | } | ||
157 | |||
158 | + if (strlen(authctxt->role) == 0) { | ||
159 | + free(authctxt->role); | ||
160 | + authctxt->role = NULL; | ||
161 | + } | ||
162 | + | ||
163 | + return (0); | ||
164 | +} | ||
165 | + | ||
166 | +int | ||
167 | +mm_answer_authrole(int sock, Buffer *m) | ||
168 | +{ | ||
169 | + monitor_permit_authentications(1); | ||
170 | + | ||
171 | + authctxt->role = buffer_get_string(m, NULL); | ||
172 | + debug3("%s: role=%s", | ||
173 | + __func__, authctxt->role); | ||
174 | + | ||
175 | + if (strlen(authctxt->role) == 0) { | ||
176 | + free(authctxt->role); | ||
177 | + authctxt->role = NULL; | ||
178 | + } | ||
179 | + | ||
180 | return (0); | ||
181 | } | ||
182 | |||
183 | @@ -1485,7 +1511,7 @@ mm_answer_pty(int sock, Buffer *m) | ||
184 | res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)); | ||
185 | if (res == 0) | ||
186 | goto error; | ||
187 | - pty_setowner(authctxt->pw, s->tty); | ||
188 | + pty_setowner(authctxt->pw, s->tty, authctxt->role); | ||
189 | |||
190 | buffer_put_int(m, 1); | ||
191 | buffer_put_cstring(m, s->tty); | ||
192 | diff --git a/monitor.h b/monitor.h | ||
193 | index 7f32b0c..4d5e8fa 100644 | ||
194 | --- a/monitor.h | ||
195 | +++ b/monitor.h | ||
196 | @@ -68,6 +68,8 @@ enum monitor_reqtype { | ||
197 | MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, | ||
198 | MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, | ||
199 | |||
200 | + MONITOR_REQ_AUTHROLE = 154, | ||
201 | + | ||
202 | }; | ||
203 | |||
204 | struct mm_master; | ||
205 | diff --git a/monitor_wrap.c b/monitor_wrap.c | ||
206 | index e476f0d..6dc890a 100644 | ||
207 | --- a/monitor_wrap.c | ||
208 | +++ b/monitor_wrap.c | ||
209 | @@ -324,10 +324,10 @@ mm_auth2_read_banner(void) | ||
210 | return (banner); | ||
211 | } | ||
212 | |||
213 | -/* Inform the privileged process about service and style */ | ||
214 | +/* Inform the privileged process about service, style, and role */ | ||
215 | |||
216 | void | ||
217 | -mm_inform_authserv(char *service, char *style) | ||
218 | +mm_inform_authserv(char *service, char *style, char *role) | ||
219 | { | ||
220 | Buffer m; | ||
221 | |||
222 | @@ -336,12 +336,30 @@ mm_inform_authserv(char *service, char *style) | ||
223 | buffer_init(&m); | ||
224 | buffer_put_cstring(&m, service); | ||
225 | buffer_put_cstring(&m, style ? style : ""); | ||
226 | + buffer_put_cstring(&m, role ? role : ""); | ||
227 | |||
228 | mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHSERV, &m); | ||
229 | |||
230 | buffer_free(&m); | ||
231 | } | ||
232 | |||
233 | +/* Inform the privileged process about role */ | ||
234 | + | ||
235 | +void | ||
236 | +mm_inform_authrole(char *role) | ||
237 | +{ | ||
238 | + Buffer m; | ||
239 | + | ||
240 | + debug3("%s entering", __func__); | ||
241 | + | ||
242 | + buffer_init(&m); | ||
243 | + buffer_put_cstring(&m, role ? role : ""); | ||
244 | + | ||
245 | + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHROLE, &m); | ||
246 | + | ||
247 | + buffer_free(&m); | ||
248 | +} | ||
249 | + | ||
250 | /* Do the password authentication */ | ||
251 | int | ||
252 | mm_auth_password(Authctxt *authctxt, char *password) | ||
253 | diff --git a/monitor_wrap.h b/monitor_wrap.h | ||
254 | index a4e9d24..9c2ee49 100644 | ||
255 | --- a/monitor_wrap.h | ||
256 | +++ b/monitor_wrap.h | ||
257 | @@ -41,7 +41,8 @@ void mm_log_handler(LogLevel, const char *, void *); | ||
258 | int mm_is_monitor(void); | ||
259 | DH *mm_choose_dh(int, int, int); | ||
260 | int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int); | ||
261 | -void mm_inform_authserv(char *, char *); | ||
262 | +void mm_inform_authserv(char *, char *, char *); | ||
263 | +void mm_inform_authrole(char *); | ||
264 | struct passwd *mm_getpwnamallow(const char *); | ||
265 | char *mm_auth2_read_banner(void); | ||
266 | int mm_auth_password(struct Authctxt *, char *); | ||
267 | diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c | ||
268 | index 4637a7a..de6ad3f 100644 | ||
269 | --- a/openbsd-compat/port-linux.c | ||
270 | +++ b/openbsd-compat/port-linux.c | ||
271 | @@ -29,6 +29,12 @@ | ||
272 | #include <string.h> | ||
273 | #include <stdio.h> | ||
274 | |||
275 | +#ifdef WITH_SELINUX | ||
276 | +#include "key.h" | ||
277 | +#include "hostfile.h" | ||
278 | +#include "auth.h" | ||
279 | +#endif | ||
280 | + | ||
281 | #include "log.h" | ||
282 | #include "xmalloc.h" | ||
283 | #include "port-linux.h" | ||
284 | @@ -58,7 +64,7 @@ ssh_selinux_enabled(void) | ||
285 | |||
286 | /* Return the default security context for the given username */ | ||
287 | static security_context_t | ||
288 | -ssh_selinux_getctxbyname(char *pwname) | ||
289 | +ssh_selinux_getctxbyname(char *pwname, const char *role) | ||
290 | { | ||
291 | security_context_t sc = NULL; | ||
292 | char *sename = NULL, *lvl = NULL; | ||
293 | @@ -73,9 +79,16 @@ ssh_selinux_getctxbyname(char *pwname) | ||
294 | #endif | ||
295 | |||
296 | #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL | ||
297 | - r = get_default_context_with_level(sename, lvl, NULL, &sc); | ||
298 | + if (role != NULL && role[0]) | ||
299 | + r = get_default_context_with_rolelevel(sename, role, lvl, NULL, | ||
300 | + &sc); | ||
301 | + else | ||
302 | + r = get_default_context_with_level(sename, lvl, NULL, &sc); | ||
303 | #else | ||
304 | - r = get_default_context(sename, NULL, &sc); | ||
305 | + if (role != NULL && role[0]) | ||
306 | + r = get_default_context_with_role(sename, role, NULL, &sc); | ||
307 | + else | ||
308 | + r = get_default_context(sename, NULL, &sc); | ||
309 | #endif | ||
310 | |||
311 | if (r != 0) { | ||
312 | @@ -105,7 +118,7 @@ ssh_selinux_getctxbyname(char *pwname) | ||
313 | |||
314 | /* Set the execution context to the default for the specified user */ | ||
315 | void | ||
316 | -ssh_selinux_setup_exec_context(char *pwname) | ||
317 | +ssh_selinux_setup_exec_context(char *pwname, const char *role) | ||
318 | { | ||
319 | security_context_t user_ctx = NULL; | ||
320 | |||
321 | @@ -114,7 +127,7 @@ ssh_selinux_setup_exec_context(char *pwname) | ||
322 | |||
323 | debug3("%s: setting execution context", __func__); | ||
324 | |||
325 | - user_ctx = ssh_selinux_getctxbyname(pwname); | ||
326 | + user_ctx = ssh_selinux_getctxbyname(pwname, role); | ||
327 | if (setexeccon(user_ctx) != 0) { | ||
328 | switch (security_getenforce()) { | ||
329 | case -1: | ||
330 | @@ -136,7 +149,7 @@ ssh_selinux_setup_exec_context(char *pwname) | ||
331 | |||
332 | /* Set the TTY context for the specified user */ | ||
333 | void | ||
334 | -ssh_selinux_setup_pty(char *pwname, const char *tty) | ||
335 | +ssh_selinux_setup_pty(char *pwname, const char *tty, const char *role) | ||
336 | { | ||
337 | security_context_t new_tty_ctx = NULL; | ||
338 | security_context_t user_ctx = NULL; | ||
339 | @@ -147,7 +160,7 @@ ssh_selinux_setup_pty(char *pwname, const char *tty) | ||
340 | |||
341 | debug3("%s: setting TTY context on %s", __func__, tty); | ||
342 | |||
343 | - user_ctx = ssh_selinux_getctxbyname(pwname); | ||
344 | + user_ctx = ssh_selinux_getctxbyname(pwname, role); | ||
345 | |||
346 | /* XXX: should these calls fatal() upon failure in enforcing mode? */ | ||
347 | |||
348 | diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h | ||
349 | index e3d1004..80ce13a 100644 | ||
350 | --- a/openbsd-compat/port-linux.h | ||
351 | +++ b/openbsd-compat/port-linux.h | ||
352 | @@ -21,8 +21,8 @@ | ||
353 | |||
354 | #ifdef WITH_SELINUX | ||
355 | int ssh_selinux_enabled(void); | ||
356 | -void ssh_selinux_setup_pty(char *, const char *); | ||
357 | -void ssh_selinux_setup_exec_context(char *); | ||
358 | +void ssh_selinux_setup_pty(char *, const char *, const char *); | ||
359 | +void ssh_selinux_setup_exec_context(char *, const char *); | ||
360 | void ssh_selinux_change_context(const char *); | ||
361 | void ssh_selinux_setfscreatecon(const char *); | ||
362 | #endif | ||
363 | diff --git a/platform.c b/platform.c | ||
364 | index ee313da..f35ec39 100644 | ||
365 | --- a/platform.c | ||
366 | +++ b/platform.c | ||
367 | @@ -143,7 +143,7 @@ platform_setusercontext(struct passwd *pw) | ||
368 | * called if sshd is running as root. | ||
369 | */ | ||
370 | void | ||
371 | -platform_setusercontext_post_groups(struct passwd *pw) | ||
372 | +platform_setusercontext_post_groups(struct passwd *pw, const char *role) | ||
373 | { | ||
374 | #if !defined(HAVE_LOGIN_CAP) && defined(USE_PAM) | ||
375 | /* | ||
376 | @@ -184,7 +184,7 @@ platform_setusercontext_post_groups(struct passwd *pw) | ||
377 | } | ||
378 | #endif /* HAVE_SETPCRED */ | ||
379 | #ifdef WITH_SELINUX | ||
380 | - ssh_selinux_setup_exec_context(pw->pw_name); | ||
381 | + ssh_selinux_setup_exec_context(pw->pw_name, role); | ||
382 | #endif | ||
383 | } | ||
384 | |||
385 | diff --git a/platform.h b/platform.h | ||
386 | index 1c7a45d..436ae7c 100644 | ||
387 | --- a/platform.h | ||
388 | +++ b/platform.h | ||
389 | @@ -27,7 +27,7 @@ void platform_post_fork_parent(pid_t child_pid); | ||
390 | void platform_post_fork_child(void); | ||
391 | int platform_privileged_uidswap(void); | ||
392 | void platform_setusercontext(struct passwd *); | ||
393 | -void platform_setusercontext_post_groups(struct passwd *); | ||
394 | +void platform_setusercontext_post_groups(struct passwd *, const char *); | ||
395 | char *platform_get_krb5_client(const char *); | ||
396 | char *platform_krb5_get_principal_name(const char *); | ||
397 | int platform_sys_dir_uid(uid_t); | ||
398 | diff --git a/session.c b/session.c | ||
399 | index 3e96557..6f389ac 100644 | ||
400 | --- a/session.c | ||
401 | +++ b/session.c | ||
402 | @@ -1486,7 +1486,7 @@ safely_chroot(const char *path, uid_t uid) | ||
403 | |||
404 | /* Set login name, uid, gid, and groups. */ | ||
405 | void | ||
406 | -do_setusercontext(struct passwd *pw) | ||
407 | +do_setusercontext(struct passwd *pw, const char *role) | ||
408 | { | ||
409 | char *chroot_path, *tmp; | ||
410 | #ifdef USE_LIBIAF | ||
411 | @@ -1517,7 +1517,7 @@ do_setusercontext(struct passwd *pw) | ||
412 | endgrent(); | ||
413 | #endif | ||
414 | |||
415 | - platform_setusercontext_post_groups(pw); | ||
416 | + platform_setusercontext_post_groups(pw, role); | ||
417 | |||
418 | if (options.chroot_directory != NULL && | ||
419 | strcasecmp(options.chroot_directory, "none") != 0) { | ||
420 | @@ -1676,7 +1676,7 @@ do_child(Session *s, const char *command) | ||
421 | |||
422 | /* Force a password change */ | ||
423 | if (s->authctxt->force_pwchange) { | ||
424 | - do_setusercontext(pw); | ||
425 | + do_setusercontext(pw, s->authctxt->role); | ||
426 | child_close_fds(); | ||
427 | do_pwchange(s); | ||
428 | exit(1); | ||
429 | @@ -1703,7 +1703,7 @@ do_child(Session *s, const char *command) | ||
430 | /* When PAM is enabled we rely on it to do the nologin check */ | ||
431 | if (!options.use_pam) | ||
432 | do_nologin(pw); | ||
433 | - do_setusercontext(pw); | ||
434 | + do_setusercontext(pw, s->authctxt->role); | ||
435 | /* | ||
436 | * PAM session modules in do_setusercontext may have | ||
437 | * generated messages, so if this in an interactive | ||
438 | @@ -2114,7 +2114,7 @@ session_pty_req(Session *s) | ||
439 | tty_parse_modes(s->ttyfd, &n_bytes); | ||
440 | |||
441 | if (!use_privsep) | ||
442 | - pty_setowner(s->pw, s->tty); | ||
443 | + pty_setowner(s->pw, s->tty, s->authctxt->role); | ||
444 | |||
445 | /* Set window size from the packet. */ | ||
446 | pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); | ||
447 | diff --git a/session.h b/session.h | ||
448 | index 6a2f35e..ef6593c 100644 | ||
449 | --- a/session.h | ||
450 | +++ b/session.h | ||
451 | @@ -77,7 +77,7 @@ void session_pty_cleanup2(Session *); | ||
452 | Session *session_new(void); | ||
453 | Session *session_by_tty(char *); | ||
454 | void session_close(Session *); | ||
455 | -void do_setusercontext(struct passwd *); | ||
456 | +void do_setusercontext(struct passwd *, const char *); | ||
457 | void child_set_env(char ***envp, u_int *envsizep, const char *name, | ||
458 | const char *value); | ||
459 | |||
460 | diff --git a/sshd.c b/sshd.c | ||
461 | index 3a6be65..48a14dd 100644 | ||
462 | --- a/sshd.c | ||
463 | +++ b/sshd.c | ||
464 | @@ -772,7 +772,7 @@ privsep_postauth(Authctxt *authctxt) | ||
465 | explicit_bzero(rnd, sizeof(rnd)); | ||
466 | |||
467 | /* Drop privileges */ | ||
468 | - do_setusercontext(authctxt->pw); | ||
469 | + do_setusercontext(authctxt->pw, authctxt->role); | ||
470 | |||
471 | skip: | ||
472 | /* It is safe now to apply the key state */ | ||
473 | diff --git a/sshpty.c b/sshpty.c | ||
474 | index a2059b7..3512ec8 100644 | ||
475 | --- a/sshpty.c | ||
476 | +++ b/sshpty.c | ||
477 | @@ -187,7 +187,7 @@ pty_change_window_size(int ptyfd, u_int row, u_int col, | ||
478 | } | ||
479 | |||
480 | void | ||
481 | -pty_setowner(struct passwd *pw, const char *tty) | ||
482 | +pty_setowner(struct passwd *pw, const char *tty, const char *role) | ||
483 | { | ||
484 | struct group *grp; | ||
485 | gid_t gid; | ||
486 | @@ -214,7 +214,7 @@ pty_setowner(struct passwd *pw, const char *tty) | ||
487 | strerror(errno)); | ||
488 | |||
489 | #ifdef WITH_SELINUX | ||
490 | - ssh_selinux_setup_pty(pw->pw_name, tty); | ||
491 | + ssh_selinux_setup_pty(pw->pw_name, tty, role); | ||
492 | #endif | ||
493 | |||
494 | if (st.st_uid != pw->pw_uid || st.st_gid != gid) { | ||
495 | diff --git a/sshpty.h b/sshpty.h | ||
496 | index cfa3224..edf2436 100644 | ||
497 | --- a/sshpty.h | ||
498 | +++ b/sshpty.h | ||
499 | @@ -24,4 +24,4 @@ int pty_allocate(int *, int *, char *, size_t); | ||
500 | void pty_release(const char *); | ||
501 | void pty_make_controlling_tty(int *, const char *); | ||
502 | void pty_change_window_size(int, u_int, u_int, u_int, u_int); | ||
503 | -void pty_setowner(struct passwd *, const char *); | ||
504 | +void pty_setowner(struct passwd *, const char *, const char *); | ||
diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 000000000..bbc7a5fb4 --- /dev/null +++ b/debian/patches/series | |||
@@ -0,0 +1,29 @@ | |||
1 | gssapi.patch | ||
2 | restore-tcp-wrappers.patch | ||
3 | selinux-role.patch | ||
4 | ssh-vulnkey-compat.patch | ||
5 | ssh1-keepalive.patch | ||
6 | keepalive-extensions.patch | ||
7 | syslog-level-silent.patch | ||
8 | quieter-signals.patch | ||
9 | helpful-wait-terminate.patch | ||
10 | consolekit.patch | ||
11 | user-group-modes.patch | ||
12 | scp-quoting.patch | ||
13 | shell-path.patch | ||
14 | dnssec-sshfp.patch | ||
15 | auth-log-verbosity.patch | ||
16 | mention-ssh-keygen-on-keychange.patch | ||
17 | package-versioning.patch | ||
18 | debian-banner.patch | ||
19 | authorized-keys-man-symlink.patch | ||
20 | lintian-symlink-pickiness.patch | ||
21 | openbsd-docs.patch | ||
22 | ssh-argv0.patch | ||
23 | doc-hash-tab-completion.patch | ||
24 | doc-upstart.patch | ||
25 | ssh-agent-setgid.patch | ||
26 | no-openssl-version-status.patch | ||
27 | gnome-ssh-askpass2-icon.patch | ||
28 | sigstop.patch | ||
29 | debian-config.patch | ||
diff --git a/debian/patches/shell-path.patch b/debian/patches/shell-path.patch new file mode 100644 index 000000000..07e20f03d --- /dev/null +++ b/debian/patches/shell-path.patch | |||
@@ -0,0 +1,39 @@ | |||
1 | From 66377fbb52584b41bd7f6f19116107fbbad41058 Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:10:00 +0000 | ||
4 | Subject: Look for $SHELL on the path for ProxyCommand/LocalCommand | ||
5 | |||
6 | There's some debate on the upstream bug about whether POSIX requires this. | ||
7 | I (Colin Watson) agree with Vincent and think it does. | ||
8 | |||
9 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1494 | ||
10 | Bug-Debian: http://bugs.debian.org/492728 | ||
11 | Last-Update: 2013-09-14 | ||
12 | |||
13 | Patch-Name: shell-path.patch | ||
14 | --- | ||
15 | sshconnect.c | 4 ++-- | ||
16 | 1 file changed, 2 insertions(+), 2 deletions(-) | ||
17 | |||
18 | diff --git a/sshconnect.c b/sshconnect.c | ||
19 | index ac09eae..26116d2 100644 | ||
20 | --- a/sshconnect.c | ||
21 | +++ b/sshconnect.c | ||
22 | @@ -228,7 +228,7 @@ ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) | ||
23 | /* Execute the proxy command. Note that we gave up any | ||
24 | extra privileges above. */ | ||
25 | signal(SIGPIPE, SIG_DFL); | ||
26 | - execv(argv[0], argv); | ||
27 | + execvp(argv[0], argv); | ||
28 | perror(argv[0]); | ||
29 | exit(1); | ||
30 | } | ||
31 | @@ -1416,7 +1416,7 @@ ssh_local_cmd(const char *args) | ||
32 | if (pid == 0) { | ||
33 | signal(SIGPIPE, SIG_DFL); | ||
34 | debug3("Executing %s -c \"%s\"", shell, args); | ||
35 | - execl(shell, shell, "-c", args, (char *)NULL); | ||
36 | + execlp(shell, shell, "-c", args, (char *)NULL); | ||
37 | error("Couldn't execute %s -c \"%s\": %s", | ||
38 | shell, args, strerror(errno)); | ||
39 | _exit(1); | ||
diff --git a/debian/patches/sigstop.patch b/debian/patches/sigstop.patch new file mode 100644 index 000000000..1eaa7758b --- /dev/null +++ b/debian/patches/sigstop.patch | |||
@@ -0,0 +1,35 @@ | |||
1 | From 689f465c66059e527974c6d4ea8e95f04d5abab7 Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:10:17 +0000 | ||
4 | Subject: Support synchronisation with service supervisor using SIGSTOP | ||
5 | |||
6 | Author: Robie Basak <robie.basak@ubuntu.com> | ||
7 | Forwarded: no | ||
8 | Last-Update: 2014-04-14 | ||
9 | |||
10 | Patch-Name: sigstop.patch | ||
11 | --- | ||
12 | sshd.c | 10 ++++++++++ | ||
13 | 1 file changed, 10 insertions(+) | ||
14 | |||
15 | diff --git a/sshd.c b/sshd.c | ||
16 | index 87331c1..23d5a64 100644 | ||
17 | --- a/sshd.c | ||
18 | +++ b/sshd.c | ||
19 | @@ -1958,6 +1958,16 @@ main(int ac, char **av) | ||
20 | } | ||
21 | } | ||
22 | |||
23 | + if (getenv("SSH_SIGSTOP")) { | ||
24 | + /* Tell service supervisor that we are ready. */ | ||
25 | + kill(getpid(), SIGSTOP); | ||
26 | + /* The service supervisor only ever expects a single | ||
27 | + * STOP signal, so do not ever signal it again, even | ||
28 | + * in the case of a re-exec or future children. | ||
29 | + */ | ||
30 | + unsetenv("SSH_SIGSTOP"); | ||
31 | + } | ||
32 | + | ||
33 | /* Accept a connection and return in a forked child */ | ||
34 | server_accept_loop(&sock_in, &sock_out, | ||
35 | &newsock, config_s); | ||
diff --git a/debian/patches/ssh-agent-setgid.patch b/debian/patches/ssh-agent-setgid.patch new file mode 100644 index 000000000..9c3ddc86e --- /dev/null +++ b/debian/patches/ssh-agent-setgid.patch | |||
@@ -0,0 +1,40 @@ | |||
1 | From 78dd041bb6ad29ceb35f05b539b09ccf761eaee2 Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:10:13 +0000 | ||
4 | Subject: Document consequences of ssh-agent being setgid in ssh-agent(1) | ||
5 | |||
6 | Bug-Debian: http://bugs.debian.org/711623 | ||
7 | Forwarded: no | ||
8 | Last-Update: 2013-06-08 | ||
9 | |||
10 | Patch-Name: ssh-agent-setgid.patch | ||
11 | --- | ||
12 | ssh-agent.1 | 15 +++++++++++++++ | ||
13 | 1 file changed, 15 insertions(+) | ||
14 | |||
15 | diff --git a/ssh-agent.1 b/ssh-agent.1 | ||
16 | index a1e634f..f2c4080 100644 | ||
17 | --- a/ssh-agent.1 | ||
18 | +++ b/ssh-agent.1 | ||
19 | @@ -172,6 +172,21 @@ environment variable holds the agent's process ID. | ||
20 | .Pp | ||
21 | The agent exits automatically when the command given on the command | ||
22 | line terminates. | ||
23 | +.Pp | ||
24 | +In Debian, | ||
25 | +.Nm | ||
26 | +is installed with the set-group-id bit set, to prevent | ||
27 | +.Xr ptrace 2 | ||
28 | +attacks retrieving private key material. | ||
29 | +This has the side-effect of causing the run-time linker to remove certain | ||
30 | +environment variables which might have security implications for set-id | ||
31 | +programs, including | ||
32 | +.Ev LD_PRELOAD , | ||
33 | +.Ev LD_LIBRARY_PATH , | ||
34 | +and | ||
35 | +.Ev TMPDIR . | ||
36 | +If you need to set any of these environment variables, you will need to do | ||
37 | +so in the program executed by ssh-agent. | ||
38 | .Sh FILES | ||
39 | .Bl -tag -width Ds | ||
40 | .It Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt | ||
diff --git a/debian/patches/ssh-argv0.patch b/debian/patches/ssh-argv0.patch new file mode 100644 index 000000000..0ccf7c42b --- /dev/null +++ b/debian/patches/ssh-argv0.patch | |||
@@ -0,0 +1,31 @@ | |||
1 | From cbd5cb03866f6df50c82d26588b73135d05bf245 Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:10:10 +0000 | ||
4 | Subject: ssh(1): Refer to ssh-argv0(1) | ||
5 | |||
6 | Old versions of OpenSSH (up to 2.5 or thereabouts) allowed creating symlinks | ||
7 | to ssh with the name of the host you want to connect to. Debian ships an | ||
8 | ssh-argv0 script restoring this feature; this patch refers to its manual | ||
9 | page from ssh(1). | ||
10 | |||
11 | Bug-Debian: http://bugs.debian.org/111341 | ||
12 | Forwarded: not-needed | ||
13 | Last-Update: 2013-09-14 | ||
14 | |||
15 | Patch-Name: ssh-argv0.patch | ||
16 | --- | ||
17 | ssh.1 | 1 + | ||
18 | 1 file changed, 1 insertion(+) | ||
19 | |||
20 | diff --git a/ssh.1 b/ssh.1 | ||
21 | index de178cd..2606b15 100644 | ||
22 | --- a/ssh.1 | ||
23 | +++ b/ssh.1 | ||
24 | @@ -1458,6 +1458,7 @@ if an error occurred. | ||
25 | .Xr sftp 1 , | ||
26 | .Xr ssh-add 1 , | ||
27 | .Xr ssh-agent 1 , | ||
28 | +.Xr ssh-argv0 1 , | ||
29 | .Xr ssh-keygen 1 , | ||
30 | .Xr ssh-keyscan 1 , | ||
31 | .Xr tun 4 , | ||
diff --git a/debian/patches/ssh-vulnkey-compat.patch b/debian/patches/ssh-vulnkey-compat.patch new file mode 100644 index 000000000..427ee6be1 --- /dev/null +++ b/debian/patches/ssh-vulnkey-compat.patch | |||
@@ -0,0 +1,42 @@ | |||
1 | From e6836d7c98c75d3252de56c2f3ea07e12c817e00 Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@ubuntu.com> | ||
3 | Date: Sun, 9 Feb 2014 16:09:50 +0000 | ||
4 | Subject: Accept obsolete ssh-vulnkey configuration options | ||
5 | |||
6 | These options were used as part of Debian's response to CVE-2008-0166. | ||
7 | Nearly six years later, we no longer need to continue carrying the bulk | ||
8 | of that patch, but we do need to avoid failing when the associated | ||
9 | configuration options are still present. | ||
10 | |||
11 | Last-Update: 2014-02-09 | ||
12 | |||
13 | Patch-Name: ssh-vulnkey-compat.patch | ||
14 | --- | ||
15 | readconf.c | 1 + | ||
16 | servconf.c | 1 + | ||
17 | 2 files changed, 2 insertions(+) | ||
18 | |||
19 | diff --git a/readconf.c b/readconf.c | ||
20 | index 9127e93..bc879eb 100644 | ||
21 | --- a/readconf.c | ||
22 | +++ b/readconf.c | ||
23 | @@ -174,6 +174,7 @@ static struct { | ||
24 | { "passwordauthentication", oPasswordAuthentication }, | ||
25 | { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, | ||
26 | { "kbdinteractivedevices", oKbdInteractiveDevices }, | ||
27 | + { "useblacklistedkeys", oDeprecated }, | ||
28 | { "rsaauthentication", oRSAAuthentication }, | ||
29 | { "pubkeyauthentication", oPubkeyAuthentication }, | ||
30 | { "dsaauthentication", oPubkeyAuthentication }, /* alias */ | ||
31 | diff --git a/servconf.c b/servconf.c | ||
32 | index cb3c831..a252487 100644 | ||
33 | --- a/servconf.c | ||
34 | +++ b/servconf.c | ||
35 | @@ -462,6 +462,7 @@ static struct { | ||
36 | { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL }, | ||
37 | { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL }, | ||
38 | { "strictmodes", sStrictModes, SSHCFG_GLOBAL }, | ||
39 | + { "permitblacklistedkeys", sDeprecated, SSHCFG_GLOBAL }, | ||
40 | { "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL }, | ||
41 | { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL }, | ||
42 | { "uselogin", sUseLogin, SSHCFG_GLOBAL }, | ||
diff --git a/debian/patches/ssh1-keepalive.patch b/debian/patches/ssh1-keepalive.patch new file mode 100644 index 000000000..2e5fa306d --- /dev/null +++ b/debian/patches/ssh1-keepalive.patch | |||
@@ -0,0 +1,74 @@ | |||
1 | From cbbc8577950b93090171c7394bcdeb68b7c3cd0c Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:09:51 +0000 | ||
4 | Subject: Partial server keep-alive implementation for SSH1 | ||
5 | |||
6 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1712 | ||
7 | Last-Update: 2013-09-14 | ||
8 | |||
9 | Patch-Name: ssh1-keepalive.patch | ||
10 | --- | ||
11 | clientloop.c | 25 +++++++++++++++---------- | ||
12 | ssh_config.5 | 5 ++++- | ||
13 | 2 files changed, 19 insertions(+), 11 deletions(-) | ||
14 | |||
15 | diff --git a/clientloop.c b/clientloop.c | ||
16 | index f9175e3..046ca8b 100644 | ||
17 | --- a/clientloop.c | ||
18 | +++ b/clientloop.c | ||
19 | @@ -563,16 +563,21 @@ client_global_request_reply(int type, u_int32_t seq, void *ctxt) | ||
20 | static void | ||
21 | server_alive_check(void) | ||
22 | { | ||
23 | - if (packet_inc_alive_timeouts() > options.server_alive_count_max) { | ||
24 | - logit("Timeout, server %s not responding.", host); | ||
25 | - cleanup_exit(255); | ||
26 | + if (compat20) { | ||
27 | + if (packet_inc_alive_timeouts() > options.server_alive_count_max) { | ||
28 | + logit("Timeout, server %s not responding.", host); | ||
29 | + cleanup_exit(255); | ||
30 | + } | ||
31 | + packet_start(SSH2_MSG_GLOBAL_REQUEST); | ||
32 | + packet_put_cstring("keepalive@openssh.com"); | ||
33 | + packet_put_char(1); /* boolean: want reply */ | ||
34 | + packet_send(); | ||
35 | + /* Insert an empty placeholder to maintain ordering */ | ||
36 | + client_register_global_confirm(NULL, NULL); | ||
37 | + } else { | ||
38 | + packet_send_ignore(0); | ||
39 | + packet_send(); | ||
40 | } | ||
41 | - packet_start(SSH2_MSG_GLOBAL_REQUEST); | ||
42 | - packet_put_cstring("keepalive@openssh.com"); | ||
43 | - packet_put_char(1); /* boolean: want reply */ | ||
44 | - packet_send(); | ||
45 | - /* Insert an empty placeholder to maintain ordering */ | ||
46 | - client_register_global_confirm(NULL, NULL); | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | @@ -634,7 +639,7 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | ||
51 | */ | ||
52 | |||
53 | timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */ | ||
54 | - if (options.server_alive_interval > 0 && compat20) { | ||
55 | + if (options.server_alive_interval > 0) { | ||
56 | timeout_secs = options.server_alive_interval; | ||
57 | server_alive_time = now + options.server_alive_interval; | ||
58 | } | ||
59 | diff --git a/ssh_config.5 b/ssh_config.5 | ||
60 | index e6649ac..01f1f7f 100644 | ||
61 | --- a/ssh_config.5 | ||
62 | +++ b/ssh_config.5 | ||
63 | @@ -1325,7 +1325,10 @@ If, for example, | ||
64 | .Cm ServerAliveCountMax | ||
65 | is left at the default, if the server becomes unresponsive, | ||
66 | ssh will disconnect after approximately 45 seconds. | ||
67 | -This option applies to protocol version 2 only. | ||
68 | +This option applies to protocol version 2 only; in protocol version | ||
69 | +1 there is no mechanism to request a response from the server to the | ||
70 | +server alive messages, so disconnection is the responsibility of the TCP | ||
71 | +stack. | ||
72 | .It Cm ServerAliveInterval | ||
73 | Sets a timeout interval in seconds after which if no data has been received | ||
74 | from the server, | ||
diff --git a/debian/patches/syslog-level-silent.patch b/debian/patches/syslog-level-silent.patch new file mode 100644 index 000000000..bfc236927 --- /dev/null +++ b/debian/patches/syslog-level-silent.patch | |||
@@ -0,0 +1,47 @@ | |||
1 | From 69f7c00e04d1baa01a9038eeb764cfed0830fb19 Mon Sep 17 00:00:00 2001 | ||
2 | From: Jonathan David Amery <jdamery@ysolde.ucam.org> | ||
3 | Date: Sun, 9 Feb 2014 16:09:54 +0000 | ||
4 | Subject: "LogLevel SILENT" compatibility | ||
5 | |||
6 | "LogLevel SILENT" (-qq) was introduced in Debian openssh 1:3.0.1p1-1 to | ||
7 | match the behaviour of non-free SSH, in which -q does not suppress fatal | ||
8 | errors. However, this was unintentionally broken in 1:4.6p1-2 and nobody | ||
9 | complained, so we've dropped most of it. The parts that remain are basic | ||
10 | configuration file compatibility, and an adjustment to "Pseudo-terminal will | ||
11 | not be allocated ..." which should be split out into a separate patch. | ||
12 | |||
13 | Author: Matthew Vernon <matthew@debian.org> | ||
14 | Author: Colin Watson <cjwatson@debian.org> | ||
15 | Last-Update: 2013-09-14 | ||
16 | |||
17 | Patch-Name: syslog-level-silent.patch | ||
18 | --- | ||
19 | log.c | 1 + | ||
20 | ssh.c | 2 +- | ||
21 | 2 files changed, 2 insertions(+), 1 deletion(-) | ||
22 | |||
23 | diff --git a/log.c b/log.c | ||
24 | index 32e1d2e..53e7b65 100644 | ||
25 | --- a/log.c | ||
26 | +++ b/log.c | ||
27 | @@ -94,6 +94,7 @@ static struct { | ||
28 | LogLevel val; | ||
29 | } log_levels[] = | ||
30 | { | ||
31 | + { "SILENT", SYSLOG_LEVEL_QUIET }, /* compatibility */ | ||
32 | { "QUIET", SYSLOG_LEVEL_QUIET }, | ||
33 | { "FATAL", SYSLOG_LEVEL_FATAL }, | ||
34 | { "ERROR", SYSLOG_LEVEL_ERROR }, | ||
35 | diff --git a/ssh.c b/ssh.c | ||
36 | index 26e9681..5bce695 100644 | ||
37 | --- a/ssh.c | ||
38 | +++ b/ssh.c | ||
39 | @@ -989,7 +989,7 @@ main(int ac, char **av) | ||
40 | /* Do not allocate a tty if stdin is not a tty. */ | ||
41 | if ((!isatty(fileno(stdin)) || stdin_null_flag) && | ||
42 | options.request_tty != REQUEST_TTY_FORCE) { | ||
43 | - if (tty_flag) | ||
44 | + if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) | ||
45 | logit("Pseudo-terminal will not be allocated because " | ||
46 | "stdin is not a terminal."); | ||
47 | tty_flag = 0; | ||
diff --git a/debian/patches/user-group-modes.patch b/debian/patches/user-group-modes.patch new file mode 100644 index 000000000..e4e4657f3 --- /dev/null +++ b/debian/patches/user-group-modes.patch | |||
@@ -0,0 +1,266 @@ | |||
1 | From 28ea747089f695e58a476a2849133402d4f86b92 Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:09:58 +0000 | ||
4 | Subject: Allow harmless group-writability | ||
5 | |||
6 | Allow secure files (~/.ssh/config, ~/.ssh/authorized_keys, etc.) to be | ||
7 | group-writable, provided that the group in question contains only the file's | ||
8 | owner. Rejected upstream for IMO incorrect reasons (e.g. a misunderstanding | ||
9 | about the contents of gr->gr_mem). Given that per-user groups and umask 002 | ||
10 | are the default setup in Debian (for good reasons - this makes operating in | ||
11 | setgid directories with other groups much easier), we need to permit this by | ||
12 | default. | ||
13 | |||
14 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1060 | ||
15 | Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=314347 | ||
16 | Last-Update: 2013-09-14 | ||
17 | |||
18 | Patch-Name: user-group-modes.patch | ||
19 | --- | ||
20 | auth-rhosts.c | 6 ++---- | ||
21 | auth.c | 9 +++----- | ||
22 | misc.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- | ||
23 | misc.h | 2 ++ | ||
24 | platform.c | 16 -------------- | ||
25 | readconf.c | 5 +++-- | ||
26 | ssh.1 | 2 ++ | ||
27 | ssh_config.5 | 2 ++ | ||
28 | 8 files changed, 82 insertions(+), 29 deletions(-) | ||
29 | |||
30 | diff --git a/auth-rhosts.c b/auth-rhosts.c | ||
31 | index b5bedee..11fcca6 100644 | ||
32 | --- a/auth-rhosts.c | ||
33 | +++ b/auth-rhosts.c | ||
34 | @@ -256,8 +256,7 @@ auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostnam | ||
35 | return 0; | ||
36 | } | ||
37 | if (options.strict_modes && | ||
38 | - ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || | ||
39 | - (st.st_mode & 022) != 0)) { | ||
40 | + !secure_permissions(&st, pw->pw_uid)) { | ||
41 | logit("Rhosts authentication refused for %.100s: " | ||
42 | "bad ownership or modes for home directory.", pw->pw_name); | ||
43 | auth_debug_add("Rhosts authentication refused for %.100s: " | ||
44 | @@ -283,8 +282,7 @@ auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostnam | ||
45 | * allowing access to their account by anyone. | ||
46 | */ | ||
47 | if (options.strict_modes && | ||
48 | - ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || | ||
49 | - (st.st_mode & 022) != 0)) { | ||
50 | + !secure_permissions(&st, pw->pw_uid)) { | ||
51 | logit("Rhosts authentication refused for %.100s: bad modes for %.200s", | ||
52 | pw->pw_name, buf); | ||
53 | auth_debug_add("Bad file modes for %.200s", buf); | ||
54 | diff --git a/auth.c b/auth.c | ||
55 | index 5e60682..18de51a 100644 | ||
56 | --- a/auth.c | ||
57 | +++ b/auth.c | ||
58 | @@ -421,8 +421,7 @@ check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, | ||
59 | user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); | ||
60 | if (options.strict_modes && | ||
61 | (stat(user_hostfile, &st) == 0) && | ||
62 | - ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || | ||
63 | - (st.st_mode & 022) != 0)) { | ||
64 | + !secure_permissions(&st, pw->pw_uid)) { | ||
65 | logit("Authentication refused for %.100s: " | ||
66 | "bad owner or modes for %.200s", | ||
67 | pw->pw_name, user_hostfile); | ||
68 | @@ -484,8 +483,7 @@ auth_secure_path(const char *name, struct stat *stp, const char *pw_dir, | ||
69 | snprintf(err, errlen, "%s is not a regular file", buf); | ||
70 | return -1; | ||
71 | } | ||
72 | - if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || | ||
73 | - (stp->st_mode & 022) != 0) { | ||
74 | + if (!secure_permissions(stp, uid)) { | ||
75 | snprintf(err, errlen, "bad ownership or modes for file %s", | ||
76 | buf); | ||
77 | return -1; | ||
78 | @@ -500,8 +498,7 @@ auth_secure_path(const char *name, struct stat *stp, const char *pw_dir, | ||
79 | strlcpy(buf, cp, sizeof(buf)); | ||
80 | |||
81 | if (stat(buf, &st) < 0 || | ||
82 | - (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || | ||
83 | - (st.st_mode & 022) != 0) { | ||
84 | + !secure_permissions(&st, uid)) { | ||
85 | snprintf(err, errlen, | ||
86 | "bad ownership or modes for directory %s", buf); | ||
87 | return -1; | ||
88 | diff --git a/misc.c b/misc.c | ||
89 | index 94b05b0..c25ccd8 100644 | ||
90 | --- a/misc.c | ||
91 | +++ b/misc.c | ||
92 | @@ -50,8 +50,9 @@ | ||
93 | #include <netdb.h> | ||
94 | #ifdef HAVE_PATHS_H | ||
95 | # include <paths.h> | ||
96 | -#include <pwd.h> | ||
97 | #endif | ||
98 | +#include <pwd.h> | ||
99 | +#include <grp.h> | ||
100 | #ifdef SSH_TUN_OPENBSD | ||
101 | #include <net/if.h> | ||
102 | #endif | ||
103 | @@ -60,6 +61,7 @@ | ||
104 | #include "misc.h" | ||
105 | #include "log.h" | ||
106 | #include "ssh.h" | ||
107 | +#include "platform.h" | ||
108 | |||
109 | /* remove newline at end of string */ | ||
110 | char * | ||
111 | @@ -644,6 +646,71 @@ read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz, | ||
112 | return -1; | ||
113 | } | ||
114 | |||
115 | +/* | ||
116 | + * return 1 if the specified uid is a uid that may own a system directory | ||
117 | + * otherwise 0. | ||
118 | + */ | ||
119 | +int | ||
120 | +platform_sys_dir_uid(uid_t uid) | ||
121 | +{ | ||
122 | + if (uid == 0) | ||
123 | + return 1; | ||
124 | +#ifdef PLATFORM_SYS_DIR_UID | ||
125 | + if (uid == PLATFORM_SYS_DIR_UID) | ||
126 | + return 1; | ||
127 | +#endif | ||
128 | + return 0; | ||
129 | +} | ||
130 | + | ||
131 | +int | ||
132 | +secure_permissions(struct stat *st, uid_t uid) | ||
133 | +{ | ||
134 | + if (!platform_sys_dir_uid(st->st_uid) && st->st_uid != uid) | ||
135 | + return 0; | ||
136 | + if ((st->st_mode & 002) != 0) | ||
137 | + return 0; | ||
138 | + if ((st->st_mode & 020) != 0) { | ||
139 | + /* If the file is group-writable, the group in question must | ||
140 | + * have exactly one member, namely the file's owner. | ||
141 | + * (Zero-member groups are typically used by setgid | ||
142 | + * binaries, and are unlikely to be suitable.) | ||
143 | + */ | ||
144 | + struct passwd *pw; | ||
145 | + struct group *gr; | ||
146 | + int members = 0; | ||
147 | + | ||
148 | + gr = getgrgid(st->st_gid); | ||
149 | + if (!gr) | ||
150 | + return 0; | ||
151 | + | ||
152 | + /* Check primary group memberships. */ | ||
153 | + while ((pw = getpwent()) != NULL) { | ||
154 | + if (pw->pw_gid == gr->gr_gid) { | ||
155 | + ++members; | ||
156 | + if (pw->pw_uid != uid) | ||
157 | + return 0; | ||
158 | + } | ||
159 | + } | ||
160 | + endpwent(); | ||
161 | + | ||
162 | + pw = getpwuid(st->st_uid); | ||
163 | + if (!pw) | ||
164 | + return 0; | ||
165 | + | ||
166 | + /* Check supplementary group memberships. */ | ||
167 | + if (gr->gr_mem[0]) { | ||
168 | + ++members; | ||
169 | + if (strcmp(pw->pw_name, gr->gr_mem[0]) || | ||
170 | + gr->gr_mem[1]) | ||
171 | + return 0; | ||
172 | + } | ||
173 | + | ||
174 | + if (!members) | ||
175 | + return 0; | ||
176 | + } | ||
177 | + return 1; | ||
178 | +} | ||
179 | + | ||
180 | int | ||
181 | tun_open(int tun, int mode) | ||
182 | { | ||
183 | diff --git a/misc.h b/misc.h | ||
184 | index 374c33c..89e1f75 100644 | ||
185 | --- a/misc.h | ||
186 | +++ b/misc.h | ||
187 | @@ -135,4 +135,6 @@ char *read_passphrase(const char *, int); | ||
188 | int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2))); | ||
189 | int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *); | ||
190 | |||
191 | +int secure_permissions(struct stat *st, uid_t uid); | ||
192 | + | ||
193 | #endif /* _MISC_H */ | ||
194 | diff --git a/platform.c b/platform.c | ||
195 | index f35ec39..9a23e6e 100644 | ||
196 | --- a/platform.c | ||
197 | +++ b/platform.c | ||
198 | @@ -197,19 +197,3 @@ platform_krb5_get_principal_name(const char *pw_name) | ||
199 | return NULL; | ||
200 | #endif | ||
201 | } | ||
202 | - | ||
203 | -/* | ||
204 | - * return 1 if the specified uid is a uid that may own a system directory | ||
205 | - * otherwise 0. | ||
206 | - */ | ||
207 | -int | ||
208 | -platform_sys_dir_uid(uid_t uid) | ||
209 | -{ | ||
210 | - if (uid == 0) | ||
211 | - return 1; | ||
212 | -#ifdef PLATFORM_SYS_DIR_UID | ||
213 | - if (uid == PLATFORM_SYS_DIR_UID) | ||
214 | - return 1; | ||
215 | -#endif | ||
216 | - return 0; | ||
217 | -} | ||
218 | diff --git a/readconf.c b/readconf.c | ||
219 | index 337818c..0648867 100644 | ||
220 | --- a/readconf.c | ||
221 | +++ b/readconf.c | ||
222 | @@ -38,6 +38,8 @@ | ||
223 | #include <stdio.h> | ||
224 | #include <string.h> | ||
225 | #include <unistd.h> | ||
226 | +#include <pwd.h> | ||
227 | +#include <grp.h> | ||
228 | #ifdef HAVE_UTIL_H | ||
229 | #include <util.h> | ||
230 | #endif | ||
231 | @@ -1516,8 +1518,7 @@ read_config_file(const char *filename, struct passwd *pw, const char *host, | ||
232 | |||
233 | if (fstat(fileno(f), &sb) == -1) | ||
234 | fatal("fstat %s: %s", filename, strerror(errno)); | ||
235 | - if (((sb.st_uid != 0 && sb.st_uid != getuid()) || | ||
236 | - (sb.st_mode & 022) != 0)) | ||
237 | + if (!secure_permissions(&sb, getuid())) | ||
238 | fatal("Bad owner or permissions on %s", filename); | ||
239 | } | ||
240 | |||
241 | diff --git a/ssh.1 b/ssh.1 | ||
242 | index fa5cfb2..7f6ab77 100644 | ||
243 | --- a/ssh.1 | ||
244 | +++ b/ssh.1 | ||
245 | @@ -1342,6 +1342,8 @@ The file format and configuration options are described in | ||
246 | .Xr ssh_config 5 . | ||
247 | Because of the potential for abuse, this file must have strict permissions: | ||
248 | read/write for the user, and not writable by others. | ||
249 | +It may be group-writable provided that the group in question contains only | ||
250 | +the user. | ||
251 | .Pp | ||
252 | .It Pa ~/.ssh/environment | ||
253 | Contains additional definitions for environment variables; see | ||
254 | diff --git a/ssh_config.5 b/ssh_config.5 | ||
255 | index ea92ea8..d68b45a 100644 | ||
256 | --- a/ssh_config.5 | ||
257 | +++ b/ssh_config.5 | ||
258 | @@ -1587,6 +1587,8 @@ The format of this file is described above. | ||
259 | This file is used by the SSH client. | ||
260 | Because of the potential for abuse, this file must have strict permissions: | ||
261 | read/write for the user, and not accessible by others. | ||
262 | +It may be group-writable provided that the group in question contains only | ||
263 | +the user. | ||
264 | .It Pa /etc/ssh/ssh_config | ||
265 | Systemwide configuration file. | ||
266 | This file provides defaults for those | ||