summaryrefslogtreecommitdiff
path: root/debian/patches/gssapi.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/gssapi.patch')
-rw-r--r--debian/patches/gssapi.patch3088
1 files changed, 3088 insertions, 0 deletions
diff --git a/debian/patches/gssapi.patch b/debian/patches/gssapi.patch
new file mode 100644
index 000000000..85c6722f0
--- /dev/null
+++ b/debian/patches/gssapi.patch
@@ -0,0 +1,3088 @@
1Description: GSSAPI key exchange support
2 This patch has been rejected upstream: "None of the OpenSSH developers are
3 in favour of adding this, and this situation has not changed for several
4 years. This is not a slight on Simon's patch, which is of fine quality,
5 but just that a) we don't trust GSSAPI implementations that much and b) we
6 don't like adding new KEX since they are pre-auth attack surface. This one
7 is particularly scary, since it requires hooks out to typically root-owned
8 system resources."
9 .
10 However, quite a lot of people rely on this in Debian, and it's better to
11 have it merged into the main openssh package rather than having separate
12 -krb5 packages (as we used to have). It seems to have a generally good
13 security history.
14Author: Simon Wilkinson <simon@sxw.org.uk>
15Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242
16Last-Updated: 2013-09-14
17
18Index: b/ChangeLog.gssapi
19===================================================================
20--- /dev/null
21+++ b/ChangeLog.gssapi
22@@ -0,0 +1,113 @@
23+20110101
24+ - Finally update for OpenSSH 5.6p1
25+ - Add GSSAPIServerIdentity option from Jim Basney
26+
27+20100308
28+ - [ Makefile.in, key.c, key.h ]
29+ Updates for OpenSSH 5.4p1
30+ - [ servconf.c ]
31+ Include GSSAPI options in the sshd -T configuration dump, and flag
32+ some older configuration options as being unsupported. Thanks to Colin
33+ Watson.
34+ -
35+
36+20100124
37+ - [ sshconnect2.c ]
38+ Adapt to deal with additional element in Authmethod structure. Thanks to
39+ Colin Watson
40+
41+20090615
42+ - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c
43+ sshd.c ]
44+ Fix issues identified by Greg Hudson following a code review
45+ Check return value of gss_indicate_mechs
46+ Protect GSSAPI calls in monitor, so they can only be used if enabled
47+ Check return values of bignum functions in key exchange
48+ Use BN_clear_free to clear other side's DH value
49+ Make ssh_gssapi_id_kex more robust
50+ Only configure kex table pointers if GSSAPI is enabled
51+ Don't leak mechanism list, or gss mechanism list
52+ Cast data.length before printing
53+ If serverkey isn't provided, use an empty string, rather than NULL
54+
55+20090201
56+ - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h
57+ ssh_config.5 sshconnet2.c ]
58+ Add support for the GSSAPIClientIdentity option, which allows the user
59+ to specify which GSSAPI identity to use to contact a given server
60+
61+20080404
62+ - [ gss-serv.c ]
63+ Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow
64+ been omitted from a previous version of this patch. Reported by Borislav
65+ Stoichkov
66+
67+20070317
68+ - [ gss-serv-krb5.c ]
69+ Remove C99ism, where new_ccname was being declared in the middle of a
70+ function
71+
72+20061220
73+ - [ servconf.c ]
74+ Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and
75+ documented, behaviour. Reported by Dan Watson.
76+
77+20060910
78+ - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c
79+ ssh-gss.h ]
80+ add support for gss-group14-sha1 key exchange mechanisms
81+ - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ]
82+ Add GSSAPIStrictAcceptorCheck option to allow the disabling of
83+ acceptor principal checking on multi-homed machines.
84+ <Bugzilla #928>
85+ - [ sshd_config ssh_config ]
86+ Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample
87+ configuration files
88+ - [ kexgss.c kegsss.c sshconnect2.c sshd.c ]
89+ Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf()
90+ Limit length of error messages displayed by client
91+
92+20060909
93+ - [ gss-genr.c gss-serv.c ]
94+ move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server
95+ only, where they belong
96+ <Bugzilla #1225>
97+
98+20060829
99+ - [ gss-serv-krb5.c ]
100+ Fix CCAPI credentials cache name when creating KRB5CCNAME environment
101+ variable
102+
103+20060828
104+ - [ gss-genr.c ]
105+ Avoid Heimdal context freeing problem
106+ <Fixed upstream 20060829>
107+
108+20060818
109+ - [ gss-genr.c ssh-gss.h sshconnect2.c ]
110+ Make sure that SPENGO is disabled
111+ <Bugzilla #1218 - Fixed upstream 20060818>
112+
113+20060421
114+ - [ gssgenr.c, sshconnect2.c ]
115+ a few type changes (signed versus unsigned, int versus size_t) to
116+ fix compiler errors/warnings
117+ (from jbasney AT ncsa.uiuc.edu)
118+ - [ kexgssc.c, sshconnect2.c ]
119+ fix uninitialized variable warnings
120+ (from jbasney AT ncsa.uiuc.edu)
121+ - [ gssgenr.c ]
122+ pass oid to gss_display_status (helpful when using GSSAPI mechglue)
123+ (from jbasney AT ncsa.uiuc.edu)
124+ <Bugzilla #1220 >
125+ - [ gss-serv-krb5.c ]
126+ #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H
127+ (from jbasney AT ncsa.uiuc.edu)
128+ <Fixed upstream 20060304>
129+ - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c
130+ add client-side GssapiKeyExchange option
131+ (from jbasney AT ncsa.uiuc.edu)
132+ - [ sshconnect2.c ]
133+ add support for GssapiTrustDns option for gssapi-with-mic
134+ (from jbasney AT ncsa.uiuc.edu)
135+ <gssapi-with-mic support is Bugzilla #1008>
136Index: b/Makefile.in
137===================================================================
138--- a/Makefile.in
139+++ b/Makefile.in
140@@ -72,6 +72,7 @@
141 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
142 monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
143 kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \
144+ kexgssc.o \
145 msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
146 jpake.o schnorr.o ssh-pkcs11.o krl.o
147
148@@ -88,7 +89,7 @@
149 auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \
150 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
151 auth-krb5.o \
152- auth2-gss.o gss-serv.o gss-serv-krb5.o \
153+ auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
154 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
155 sftp-server.o sftp-common.o \
156 roaming_common.o roaming_serv.o \
157Index: b/auth-krb5.c
158===================================================================
159--- a/auth-krb5.c
160+++ b/auth-krb5.c
161@@ -181,8 +181,13 @@
162
163 len = strlen(authctxt->krb5_ticket_file) + 6;
164 authctxt->krb5_ccname = xmalloc(len);
165+#ifdef USE_CCAPI
166+ snprintf(authctxt->krb5_ccname, len, "API:%s",
167+ authctxt->krb5_ticket_file);
168+#else
169 snprintf(authctxt->krb5_ccname, len, "FILE:%s",
170 authctxt->krb5_ticket_file);
171+#endif
172
173 #ifdef USE_PAM
174 if (options.use_pam)
175@@ -239,15 +244,22 @@
176 #ifndef HEIMDAL
177 krb5_error_code
178 ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
179- int tmpfd, ret, oerrno;
180+ int ret, oerrno;
181 char ccname[40];
182 mode_t old_umask;
183+#ifdef USE_CCAPI
184+ char cctemplate[] = "API:krb5cc_%d";
185+#else
186+ char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
187+ int tmpfd;
188+#endif
189
190 ret = snprintf(ccname, sizeof(ccname),
191- "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
192+ cctemplate, geteuid());
193 if (ret < 0 || (size_t)ret >= sizeof(ccname))
194 return ENOMEM;
195
196+#ifndef USE_CCAPI
197 old_umask = umask(0177);
198 tmpfd = mkstemp(ccname + strlen("FILE:"));
199 oerrno = errno;
200@@ -264,6 +276,7 @@
201 return oerrno;
202 }
203 close(tmpfd);
204+#endif
205
206 return (krb5_cc_resolve(ctx, ccname, ccache));
207 }
208Index: b/auth2-gss.c
209===================================================================
210--- a/auth2-gss.c
211+++ b/auth2-gss.c
212@@ -1,7 +1,7 @@
213 /* $OpenBSD: auth2-gss.c,v 1.20 2013/05/17 00:13:13 djm Exp $ */
214
215 /*
216- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
217+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
218 *
219 * Redistribution and use in source and binary forms, with or without
220 * modification, are permitted provided that the following conditions
221@@ -52,6 +52,40 @@
222 static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
223 static void input_gssapi_errtok(int, u_int32_t, void *);
224
225+/*
226+ * The 'gssapi_keyex' userauth mechanism.
227+ */
228+static int
229+userauth_gsskeyex(Authctxt *authctxt)
230+{
231+ int authenticated = 0;
232+ Buffer b;
233+ gss_buffer_desc mic, gssbuf;
234+ u_int len;
235+
236+ mic.value = packet_get_string(&len);
237+ mic.length = len;
238+
239+ packet_check_eom();
240+
241+ ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
242+ "gssapi-keyex");
243+
244+ gssbuf.value = buffer_ptr(&b);
245+ gssbuf.length = buffer_len(&b);
246+
247+ /* gss_kex_context is NULL with privsep, so we can't check it here */
248+ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
249+ &gssbuf, &mic))))
250+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
251+ authctxt->pw));
252+
253+ buffer_free(&b);
254+ free(mic.value);
255+
256+ return (authenticated);
257+}
258+
259 /*
260 * We only support those mechanisms that we know about (ie ones that we know
261 * how to check local user kuserok and the like)
262@@ -240,7 +274,8 @@
263
264 packet_check_eom();
265
266- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
267+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
268+ authctxt->pw));
269
270 authctxt->postponed = 0;
271 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
272@@ -275,7 +310,8 @@
273 gssbuf.length = buffer_len(&b);
274
275 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
276- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
277+ authenticated =
278+ PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
279 else
280 logit("GSSAPI MIC check failed");
281
282@@ -290,6 +326,12 @@
283 userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
284 }
285
286+Authmethod method_gsskeyex = {
287+ "gssapi-keyex",
288+ userauth_gsskeyex,
289+ &options.gss_authentication
290+};
291+
292 Authmethod method_gssapi = {
293 "gssapi-with-mic",
294 userauth_gssapi,
295Index: b/auth2.c
296===================================================================
297--- a/auth2.c
298+++ b/auth2.c
299@@ -69,6 +69,7 @@
300 extern Authmethod method_kbdint;
301 extern Authmethod method_hostbased;
302 #ifdef GSSAPI
303+extern Authmethod method_gsskeyex;
304 extern Authmethod method_gssapi;
305 #endif
306 #ifdef JPAKE
307@@ -79,6 +80,7 @@
308 &method_none,
309 &method_pubkey,
310 #ifdef GSSAPI
311+ &method_gsskeyex,
312 &method_gssapi,
313 #endif
314 #ifdef JPAKE
315Index: b/clientloop.c
316===================================================================
317--- a/clientloop.c
318+++ b/clientloop.c
319@@ -111,6 +111,10 @@
320 #include "msg.h"
321 #include "roaming.h"
322
323+#ifdef GSSAPI
324+#include "ssh-gss.h"
325+#endif
326+
327 /* import options */
328 extern Options options;
329
330@@ -1608,6 +1612,15 @@
331 /* Do channel operations unless rekeying in progress. */
332 if (!rekeying) {
333 channel_after_select(readset, writeset);
334+
335+#ifdef GSSAPI
336+ if (options.gss_renewal_rekey &&
337+ ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) {
338+ debug("credentials updated - forcing rekey");
339+ need_rekeying = 1;
340+ }
341+#endif
342+
343 if (need_rekeying || packet_need_rekeying()) {
344 debug("need rekeying");
345 xxx_kex->done = 0;
346Index: b/config.h.in
347===================================================================
348--- a/config.h.in
349+++ b/config.h.in
350@@ -1546,6 +1546,9 @@
351 /* Use btmp to log bad logins */
352 #undef USE_BTMP
353
354+/* platform uses an in-memory credentials cache */
355+#undef USE_CCAPI
356+
357 /* Use libedit for sftp */
358 #undef USE_LIBEDIT
359
360@@ -1561,6 +1564,9 @@
361 /* Use PIPES instead of a socketpair() */
362 #undef USE_PIPES
363
364+/* platform has the Security Authorization Session API */
365+#undef USE_SECURITY_SESSION_API
366+
367 /* Define if you have Solaris process contracts */
368 #undef USE_SOLARIS_PROCESS_CONTRACTS
369
370Index: b/configure
371===================================================================
372--- a/configure
373+++ b/configure
374@@ -6780,6 +6780,63 @@
375
376 $as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h
377
378+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have the Security Authorization Session API" >&5
379+$as_echo_n "checking if we have the Security Authorization Session API... " >&6; }
380+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
381+/* end confdefs.h. */
382+#include <Security/AuthSession.h>
383+int
384+main ()
385+{
386+SessionCreate(0, 0);
387+ ;
388+ return 0;
389+}
390+_ACEOF
391+if ac_fn_c_try_compile "$LINENO"; then :
392+ ac_cv_use_security_session_api="yes"
393+
394+$as_echo "#define USE_SECURITY_SESSION_API 1" >>confdefs.h
395+
396+ LIBS="$LIBS -framework Security"
397+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
398+$as_echo "yes" >&6; }
399+else
400+ ac_cv_use_security_session_api="no"
401+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
402+$as_echo "no" >&6; }
403+fi
404+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
405+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have an in-memory credentials cache" >&5
406+$as_echo_n "checking if we have an in-memory credentials cache... " >&6; }
407+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
408+/* end confdefs.h. */
409+#include <Kerberos/Kerberos.h>
410+int
411+main ()
412+{
413+cc_context_t c;
414+ (void) cc_initialize (&c, 0, NULL, NULL);
415+ ;
416+ return 0;
417+}
418+_ACEOF
419+if ac_fn_c_try_compile "$LINENO"; then :
420+
421+$as_echo "#define USE_CCAPI 1" >>confdefs.h
422+
423+ LIBS="$LIBS -framework Security"
424+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
425+$as_echo "yes" >&6; }
426+ if test "x$ac_cv_use_security_session_api" = "xno"; then
427+ as_fn_error $? "*** Need a security framework to use the credentials cache API ***" "$LINENO" 5
428+ fi
429+else
430+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
431+$as_echo "no" >&6; }
432+
433+fi
434+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
435
436 ac_fn_c_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default"
437 if test "x$ac_cv_have_decl_AU_IPv4" = xyes; then :
438Index: b/configure.ac
439===================================================================
440--- a/configure.ac
441+++ b/configure.ac
442@@ -548,6 +548,30 @@
443 [Use tunnel device compatibility to OpenBSD])
444 AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
445 [Prepend the address family to IP tunnel traffic])
446+ AC_MSG_CHECKING([if we have the Security Authorization Session API])
447+ AC_TRY_COMPILE([#include <Security/AuthSession.h>],
448+ [SessionCreate(0, 0);],
449+ [ac_cv_use_security_session_api="yes"
450+ AC_DEFINE([USE_SECURITY_SESSION_API], [1],
451+ [platform has the Security Authorization Session API])
452+ LIBS="$LIBS -framework Security"
453+ AC_MSG_RESULT([yes])],
454+ [ac_cv_use_security_session_api="no"
455+ AC_MSG_RESULT([no])])
456+ AC_MSG_CHECKING([if we have an in-memory credentials cache])
457+ AC_TRY_COMPILE(
458+ [#include <Kerberos/Kerberos.h>],
459+ [cc_context_t c;
460+ (void) cc_initialize (&c, 0, NULL, NULL);],
461+ [AC_DEFINE([USE_CCAPI], [1],
462+ [platform uses an in-memory credentials cache])
463+ LIBS="$LIBS -framework Security"
464+ AC_MSG_RESULT([yes])
465+ if test "x$ac_cv_use_security_session_api" = "xno"; then
466+ AC_MSG_ERROR([*** Need a security framework to use the credentials cache API ***])
467+ fi],
468+ [AC_MSG_RESULT([no])]
469+ )
470 m4_pattern_allow([AU_IPv])
471 AC_CHECK_DECL([AU_IPv4], [],
472 AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
473Index: b/gss-genr.c
474===================================================================
475--- a/gss-genr.c
476+++ b/gss-genr.c
477@@ -1,7 +1,7 @@
478 /* $OpenBSD: gss-genr.c,v 1.21 2013/05/17 00:13:13 djm Exp $ */
479
480 /*
481- * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
482+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
483 *
484 * Redistribution and use in source and binary forms, with or without
485 * modification, are permitted provided that the following conditions
486@@ -39,12 +39,167 @@
487 #include "buffer.h"
488 #include "log.h"
489 #include "ssh2.h"
490+#include "cipher.h"
491+#include "key.h"
492+#include "kex.h"
493+#include <openssl/evp.h>
494
495 #include "ssh-gss.h"
496
497 extern u_char *session_id2;
498 extern u_int session_id2_len;
499
500+typedef struct {
501+ char *encoded;
502+ gss_OID oid;
503+} ssh_gss_kex_mapping;
504+
505+/*
506+ * XXX - It would be nice to find a more elegant way of handling the
507+ * XXX passing of the key exchange context to the userauth routines
508+ */
509+
510+Gssctxt *gss_kex_context = NULL;
511+
512+static ssh_gss_kex_mapping *gss_enc2oid = NULL;
513+
514+int
515+ssh_gssapi_oid_table_ok() {
516+ return (gss_enc2oid != NULL);
517+}
518+
519+/*
520+ * Return a list of the gss-group1-sha1 mechanisms supported by this program
521+ *
522+ * We test mechanisms to ensure that we can use them, to avoid starting
523+ * a key exchange with a bad mechanism
524+ */
525+
526+char *
527+ssh_gssapi_client_mechanisms(const char *host, const char *client) {
528+ gss_OID_set gss_supported;
529+ OM_uint32 min_status;
530+
531+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
532+ return NULL;
533+
534+ return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
535+ host, client));
536+}
537+
538+char *
539+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
540+ const char *host, const char *client) {
541+ Buffer buf;
542+ size_t i;
543+ int oidpos, enclen;
544+ char *mechs, *encoded;
545+ u_char digest[EVP_MAX_MD_SIZE];
546+ char deroid[2];
547+ const EVP_MD *evp_md = EVP_md5();
548+ EVP_MD_CTX md;
549+
550+ if (gss_enc2oid != NULL) {
551+ for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
552+ free(gss_enc2oid[i].encoded);
553+ free(gss_enc2oid);
554+ }
555+
556+ gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
557+ (gss_supported->count + 1));
558+
559+ buffer_init(&buf);
560+
561+ oidpos = 0;
562+ for (i = 0; i < gss_supported->count; i++) {
563+ if (gss_supported->elements[i].length < 128 &&
564+ (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
565+
566+ deroid[0] = SSH_GSS_OIDTYPE;
567+ deroid[1] = gss_supported->elements[i].length;
568+
569+ EVP_DigestInit(&md, evp_md);
570+ EVP_DigestUpdate(&md, deroid, 2);
571+ EVP_DigestUpdate(&md,
572+ gss_supported->elements[i].elements,
573+ gss_supported->elements[i].length);
574+ EVP_DigestFinal(&md, digest, NULL);
575+
576+ encoded = xmalloc(EVP_MD_size(evp_md) * 2);
577+ enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
578+ encoded, EVP_MD_size(evp_md) * 2);
579+
580+ if (oidpos != 0)
581+ buffer_put_char(&buf, ',');
582+
583+ buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
584+ sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
585+ buffer_append(&buf, encoded, enclen);
586+ buffer_put_char(&buf, ',');
587+ buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
588+ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
589+ buffer_append(&buf, encoded, enclen);
590+ buffer_put_char(&buf, ',');
591+ buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
592+ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
593+ buffer_append(&buf, encoded, enclen);
594+
595+ gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
596+ gss_enc2oid[oidpos].encoded = encoded;
597+ oidpos++;
598+ }
599+ }
600+ gss_enc2oid[oidpos].oid = NULL;
601+ gss_enc2oid[oidpos].encoded = NULL;
602+
603+ buffer_put_char(&buf, '\0');
604+
605+ mechs = xmalloc(buffer_len(&buf));
606+ buffer_get(&buf, mechs, buffer_len(&buf));
607+ buffer_free(&buf);
608+
609+ if (strlen(mechs) == 0) {
610+ free(mechs);
611+ mechs = NULL;
612+ }
613+
614+ return (mechs);
615+}
616+
617+gss_OID
618+ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
619+ int i = 0;
620+
621+ switch (kex_type) {
622+ case KEX_GSS_GRP1_SHA1:
623+ if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
624+ return GSS_C_NO_OID;
625+ name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
626+ break;
627+ case KEX_GSS_GRP14_SHA1:
628+ if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
629+ return GSS_C_NO_OID;
630+ name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
631+ break;
632+ case KEX_GSS_GEX_SHA1:
633+ if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
634+ return GSS_C_NO_OID;
635+ name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
636+ break;
637+ default:
638+ return GSS_C_NO_OID;
639+ }
640+
641+ while (gss_enc2oid[i].encoded != NULL &&
642+ strcmp(name, gss_enc2oid[i].encoded) != 0)
643+ i++;
644+
645+ if (gss_enc2oid[i].oid != NULL && ctx != NULL)
646+ ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
647+
648+ return gss_enc2oid[i].oid;
649+}
650+
651 /* Check that the OID in a data stream matches that in the context */
652 int
653 ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
654@@ -197,7 +352,7 @@
655 }
656
657 ctx->major = gss_init_sec_context(&ctx->minor,
658- GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
659+ ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
660 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
661 0, NULL, recv_tok, NULL, send_tok, flags, NULL);
662
663@@ -227,8 +382,42 @@
664 }
665
666 OM_uint32
667+ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
668+{
669+ gss_buffer_desc gssbuf;
670+ gss_name_t gssname;
671+ OM_uint32 status;
672+ gss_OID_set oidset;
673+
674+ gssbuf.value = (void *) name;
675+ gssbuf.length = strlen(gssbuf.value);
676+
677+ gss_create_empty_oid_set(&status, &oidset);
678+ gss_add_oid_set_member(&status, ctx->oid, &oidset);
679+
680+ ctx->major = gss_import_name(&ctx->minor, &gssbuf,
681+ GSS_C_NT_USER_NAME, &gssname);
682+
683+ if (!ctx->major)
684+ ctx->major = gss_acquire_cred(&ctx->minor,
685+ gssname, 0, oidset, GSS_C_INITIATE,
686+ &ctx->client_creds, NULL, NULL);
687+
688+ gss_release_name(&status, &gssname);
689+ gss_release_oid_set(&status, &oidset);
690+
691+ if (ctx->major)
692+ ssh_gssapi_error(ctx);
693+
694+ return(ctx->major);
695+}
696+
697+OM_uint32
698 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
699 {
700+ if (ctx == NULL)
701+ return -1;
702+
703 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
704 GSS_C_QOP_DEFAULT, buffer, hash)))
705 ssh_gssapi_error(ctx);
706@@ -236,6 +425,19 @@
707 return (ctx->major);
708 }
709
710+/* Priviledged when used by server */
711+OM_uint32
712+ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
713+{
714+ if (ctx == NULL)
715+ return -1;
716+
717+ ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
718+ gssbuf, gssmic, NULL);
719+
720+ return (ctx->major);
721+}
722+
723 void
724 ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
725 const char *context)
726@@ -249,11 +451,16 @@
727 }
728
729 int
730-ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
731+ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
732+ const char *client)
733 {
734 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
735 OM_uint32 major, minor;
736 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
737+ Gssctxt *intctx = NULL;
738+
739+ if (ctx == NULL)
740+ ctx = &intctx;
741
742 /* RFC 4462 says we MUST NOT do SPNEGO */
743 if (oid->length == spnego_oid.length &&
744@@ -263,6 +470,10 @@
745 ssh_gssapi_build_ctx(ctx);
746 ssh_gssapi_set_oid(*ctx, oid);
747 major = ssh_gssapi_import_name(*ctx, host);
748+
749+ if (!GSS_ERROR(major) && client)
750+ major = ssh_gssapi_client_identity(*ctx, client);
751+
752 if (!GSS_ERROR(major)) {
753 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
754 NULL);
755@@ -272,10 +483,67 @@
756 GSS_C_NO_BUFFER);
757 }
758
759- if (GSS_ERROR(major))
760+ if (GSS_ERROR(major) || intctx != NULL)
761 ssh_gssapi_delete_ctx(ctx);
762
763 return (!GSS_ERROR(major));
764 }
765
766+int
767+ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
768+ static gss_name_t saved_name = GSS_C_NO_NAME;
769+ static OM_uint32 saved_lifetime = 0;
770+ static gss_OID saved_mech = GSS_C_NO_OID;
771+ static gss_name_t name;
772+ static OM_uint32 last_call = 0;
773+ OM_uint32 lifetime, now, major, minor;
774+ int equal;
775+ gss_cred_usage_t usage = GSS_C_INITIATE;
776+
777+ now = time(NULL);
778+
779+ if (ctxt) {
780+ debug("Rekey has happened - updating saved versions");
781+
782+ if (saved_name != GSS_C_NO_NAME)
783+ gss_release_name(&minor, &saved_name);
784+
785+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
786+ &saved_name, &saved_lifetime, NULL, NULL);
787+
788+ if (!GSS_ERROR(major)) {
789+ saved_mech = ctxt->oid;
790+ saved_lifetime+= now;
791+ } else {
792+ /* Handle the error */
793+ }
794+ return 0;
795+ }
796+
797+ if (now - last_call < 10)
798+ return 0;
799+
800+ last_call = now;
801+
802+ if (saved_mech == GSS_C_NO_OID)
803+ return 0;
804+
805+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
806+ &name, &lifetime, NULL, NULL);
807+ if (major == GSS_S_CREDENTIALS_EXPIRED)
808+ return 0;
809+ else if (GSS_ERROR(major))
810+ return 0;
811+
812+ major = gss_compare_name(&minor, saved_name, name, &equal);
813+ gss_release_name(&minor, &name);
814+ if (GSS_ERROR(major))
815+ return 0;
816+
817+ if (equal && (saved_lifetime < lifetime + now - 10))
818+ return 1;
819+
820+ return 0;
821+}
822+
823 #endif /* GSSAPI */
824Index: b/gss-serv-krb5.c
825===================================================================
826--- a/gss-serv-krb5.c
827+++ b/gss-serv-krb5.c
828@@ -1,7 +1,7 @@
829 /* $OpenBSD: gss-serv-krb5.c,v 1.8 2013/07/20 01:55:13 djm Exp $ */
830
831 /*
832- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
833+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
834 *
835 * Redistribution and use in source and binary forms, with or without
836 * modification, are permitted provided that the following conditions
837@@ -122,6 +122,7 @@
838 OM_uint32 maj_status, min_status;
839 int len;
840 const char *errmsg;
841+ const char *new_ccname;
842
843 if (client->creds == NULL) {
844 debug("No credentials stored");
845@@ -174,11 +175,16 @@
846 return;
847 }
848
849- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
850+ new_ccname = krb5_cc_get_name(krb_context, ccache);
851+
852 client->store.envvar = "KRB5CCNAME";
853- len = strlen(client->store.filename) + 6;
854- client->store.envval = xmalloc(len);
855- snprintf(client->store.envval, len, "FILE:%s", client->store.filename);
856+#ifdef USE_CCAPI
857+ xasprintf(&client->store.envval, "API:%s", new_ccname);
858+ client->store.filename = NULL;
859+#else
860+ xasprintf(&client->store.envval, "FILE:%s", new_ccname);
861+ client->store.filename = xstrdup(new_ccname);
862+#endif
863
864 #ifdef USE_PAM
865 if (options.use_pam)
866@@ -190,6 +196,71 @@
867 return;
868 }
869
870+int
871+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store,
872+ ssh_gssapi_client *client)
873+{
874+ krb5_ccache ccache = NULL;
875+ krb5_principal principal = NULL;
876+ char *name = NULL;
877+ krb5_error_code problem;
878+ OM_uint32 maj_status, min_status;
879+
880+ if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
881+ logit("krb5_cc_resolve(): %.100s",
882+ krb5_get_err_text(krb_context, problem));
883+ return 0;
884+ }
885+
886+ /* Find out who the principal in this cache is */
887+ if ((problem = krb5_cc_get_principal(krb_context, ccache,
888+ &principal))) {
889+ logit("krb5_cc_get_principal(): %.100s",
890+ krb5_get_err_text(krb_context, problem));
891+ krb5_cc_close(krb_context, ccache);
892+ return 0;
893+ }
894+
895+ if ((problem = krb5_unparse_name(krb_context, principal, &name))) {
896+ logit("krb5_unparse_name(): %.100s",
897+ krb5_get_err_text(krb_context, problem));
898+ krb5_free_principal(krb_context, principal);
899+ krb5_cc_close(krb_context, ccache);
900+ return 0;
901+ }
902+
903+
904+ if (strcmp(name,client->exportedname.value)!=0) {
905+ debug("Name in local credentials cache differs. Not storing");
906+ krb5_free_principal(krb_context, principal);
907+ krb5_cc_close(krb_context, ccache);
908+ krb5_free_unparsed_name(krb_context, name);
909+ return 0;
910+ }
911+ krb5_free_unparsed_name(krb_context, name);
912+
913+ /* Name matches, so lets get on with it! */
914+
915+ if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) {
916+ logit("krb5_cc_initialize(): %.100s",
917+ krb5_get_err_text(krb_context, problem));
918+ krb5_free_principal(krb_context, principal);
919+ krb5_cc_close(krb_context, ccache);
920+ return 0;
921+ }
922+
923+ krb5_free_principal(krb_context, principal);
924+
925+ if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds,
926+ ccache))) {
927+ logit("gss_krb5_copy_ccache() failed. Sorry!");
928+ krb5_cc_close(krb_context, ccache);
929+ return 0;
930+ }
931+
932+ return 1;
933+}
934+
935 ssh_gssapi_mech gssapi_kerberos_mech = {
936 "toWM5Slw5Ew8Mqkay+al2g==",
937 "Kerberos",
938@@ -197,7 +268,8 @@
939 NULL,
940 &ssh_gssapi_krb5_userok,
941 NULL,
942- &ssh_gssapi_krb5_storecreds
943+ &ssh_gssapi_krb5_storecreds,
944+ &ssh_gssapi_krb5_updatecreds
945 };
946
947 #endif /* KRB5 */
948Index: b/gss-serv.c
949===================================================================
950--- a/gss-serv.c
951+++ b/gss-serv.c
952@@ -1,7 +1,7 @@
953 /* $OpenBSD: gss-serv.c,v 1.24 2013/07/20 01:55:13 djm Exp $ */
954
955 /*
956- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
957+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
958 *
959 * Redistribution and use in source and binary forms, with or without
960 * modification, are permitted provided that the following conditions
961@@ -45,15 +45,21 @@
962 #include "channels.h"
963 #include "session.h"
964 #include "misc.h"
965+#include "servconf.h"
966+#include "uidswap.h"
967
968 #include "ssh-gss.h"
969+#include "monitor_wrap.h"
970+
971+extern ServerOptions options;
972
973 static ssh_gssapi_client gssapi_client =
974 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
975- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}};
976+ GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL,
977+ {NULL, NULL, NULL, NULL, NULL}, 0, 0};
978
979 ssh_gssapi_mech gssapi_null_mech =
980- { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
981+ { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
982
983 #ifdef KRB5
984 extern ssh_gssapi_mech gssapi_kerberos_mech;
985@@ -81,25 +87,32 @@
986 char lname[MAXHOSTNAMELEN];
987 gss_OID_set oidset;
988
989- gss_create_empty_oid_set(&status, &oidset);
990- gss_add_oid_set_member(&status, ctx->oid, &oidset);
991+ if (options.gss_strict_acceptor) {
992+ gss_create_empty_oid_set(&status, &oidset);
993+ gss_add_oid_set_member(&status, ctx->oid, &oidset);
994+
995+ if (gethostname(lname, MAXHOSTNAMELEN)) {
996+ gss_release_oid_set(&status, &oidset);
997+ return (-1);
998+ }
999
1000- if (gethostname(lname, MAXHOSTNAMELEN)) {
1001- gss_release_oid_set(&status, &oidset);
1002- return (-1);
1003- }
1004+ if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
1005+ gss_release_oid_set(&status, &oidset);
1006+ return (ctx->major);
1007+ }
1008+
1009+ if ((ctx->major = gss_acquire_cred(&ctx->minor,
1010+ ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds,
1011+ NULL, NULL)))
1012+ ssh_gssapi_error(ctx);
1013
1014- if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
1015 gss_release_oid_set(&status, &oidset);
1016 return (ctx->major);
1017+ } else {
1018+ ctx->name = GSS_C_NO_NAME;
1019+ ctx->creds = GSS_C_NO_CREDENTIAL;
1020 }
1021-
1022- if ((ctx->major = gss_acquire_cred(&ctx->minor,
1023- ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
1024- ssh_gssapi_error(ctx);
1025-
1026- gss_release_oid_set(&status, &oidset);
1027- return (ctx->major);
1028+ return GSS_S_COMPLETE;
1029 }
1030
1031 /* Privileged */
1032@@ -114,6 +127,29 @@
1033 }
1034
1035 /* Unprivileged */
1036+char *
1037+ssh_gssapi_server_mechanisms() {
1038+ gss_OID_set supported;
1039+
1040+ ssh_gssapi_supported_oids(&supported);
1041+ return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
1042+ NULL, NULL));
1043+}
1044+
1045+/* Unprivileged */
1046+int
1047+ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
1048+ const char *dummy) {
1049+ Gssctxt *ctx = NULL;
1050+ int res;
1051+
1052+ res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
1053+ ssh_gssapi_delete_ctx(&ctx);
1054+
1055+ return (res);
1056+}
1057+
1058+/* Unprivileged */
1059 void
1060 ssh_gssapi_supported_oids(gss_OID_set *oidset)
1061 {
1062@@ -123,7 +159,9 @@
1063 gss_OID_set supported;
1064
1065 gss_create_empty_oid_set(&min_status, oidset);
1066- gss_indicate_mechs(&min_status, &supported);
1067+
1068+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
1069+ return;
1070
1071 while (supported_mechs[i]->name != NULL) {
1072 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
1073@@ -249,8 +287,48 @@
1074 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
1075 {
1076 int i = 0;
1077+ int equal = 0;
1078+ gss_name_t new_name = GSS_C_NO_NAME;
1079+ gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
1080+
1081+ if (options.gss_store_rekey && client->used && ctx->client_creds) {
1082+ if (client->mech->oid.length != ctx->oid->length ||
1083+ (memcmp(client->mech->oid.elements,
1084+ ctx->oid->elements, ctx->oid->length) !=0)) {
1085+ debug("Rekeyed credentials have different mechanism");
1086+ return GSS_S_COMPLETE;
1087+ }
1088+
1089+ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
1090+ ctx->client_creds, ctx->oid, &new_name,
1091+ NULL, NULL, NULL))) {
1092+ ssh_gssapi_error(ctx);
1093+ return (ctx->major);
1094+ }
1095+
1096+ ctx->major = gss_compare_name(&ctx->minor, client->name,
1097+ new_name, &equal);
1098
1099- gss_buffer_desc ename;
1100+ if (GSS_ERROR(ctx->major)) {
1101+ ssh_gssapi_error(ctx);
1102+ return (ctx->major);
1103+ }
1104+
1105+ if (!equal) {
1106+ debug("Rekeyed credentials have different name");
1107+ return GSS_S_COMPLETE;
1108+ }
1109+
1110+ debug("Marking rekeyed credentials for export");
1111+
1112+ gss_release_name(&ctx->minor, &client->name);
1113+ gss_release_cred(&ctx->minor, &client->creds);
1114+ client->name = new_name;
1115+ client->creds = ctx->client_creds;
1116+ ctx->client_creds = GSS_C_NO_CREDENTIAL;
1117+ client->updated = 1;
1118+ return GSS_S_COMPLETE;
1119+ }
1120
1121 client->mech = NULL;
1122
1123@@ -265,6 +343,13 @@
1124 if (client->mech == NULL)
1125 return GSS_S_FAILURE;
1126
1127+ if (ctx->client_creds &&
1128+ (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
1129+ ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
1130+ ssh_gssapi_error(ctx);
1131+ return (ctx->major);
1132+ }
1133+
1134 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
1135 &client->displayname, NULL))) {
1136 ssh_gssapi_error(ctx);
1137@@ -282,6 +367,8 @@
1138 return (ctx->major);
1139 }
1140
1141+ gss_release_buffer(&ctx->minor, &ename);
1142+
1143 /* We can't copy this structure, so we just move the pointer to it */
1144 client->creds = ctx->client_creds;
1145 ctx->client_creds = GSS_C_NO_CREDENTIAL;
1146@@ -329,7 +416,7 @@
1147
1148 /* Privileged */
1149 int
1150-ssh_gssapi_userok(char *user)
1151+ssh_gssapi_userok(char *user, struct passwd *pw)
1152 {
1153 OM_uint32 lmin;
1154
1155@@ -339,9 +426,11 @@
1156 return 0;
1157 }
1158 if (gssapi_client.mech && gssapi_client.mech->userok)
1159- if ((*gssapi_client.mech->userok)(&gssapi_client, user))
1160+ if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
1161+ gssapi_client.used = 1;
1162+ gssapi_client.store.owner = pw;
1163 return 1;
1164- else {
1165+ } else {
1166 /* Destroy delegated credentials if userok fails */
1167 gss_release_buffer(&lmin, &gssapi_client.displayname);
1168 gss_release_buffer(&lmin, &gssapi_client.exportedname);
1169@@ -354,14 +443,90 @@
1170 return (0);
1171 }
1172
1173-/* Privileged */
1174-OM_uint32
1175-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
1176+/* These bits are only used for rekeying. The unpriviledged child is running
1177+ * as the user, the monitor is root.
1178+ *
1179+ * In the child, we want to :
1180+ * *) Ask the monitor to store our credentials into the store we specify
1181+ * *) If it succeeds, maybe do a PAM update
1182+ */
1183+
1184+/* Stuff for PAM */
1185+
1186+#ifdef USE_PAM
1187+static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
1188+ struct pam_response **resp, void *data)
1189 {
1190- ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
1191- gssbuf, gssmic, NULL);
1192+ return (PAM_CONV_ERR);
1193+}
1194+#endif
1195
1196- return (ctx->major);
1197+void
1198+ssh_gssapi_rekey_creds() {
1199+ int ok;
1200+ int ret;
1201+#ifdef USE_PAM
1202+ pam_handle_t *pamh = NULL;
1203+ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
1204+ char *envstr;
1205+#endif
1206+
1207+ if (gssapi_client.store.filename == NULL &&
1208+ gssapi_client.store.envval == NULL &&
1209+ gssapi_client.store.envvar == NULL)
1210+ return;
1211+
1212+ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
1213+
1214+ if (!ok)
1215+ return;
1216+
1217+ debug("Rekeyed credentials stored successfully");
1218+
1219+ /* Actually managing to play with the ssh pam stack from here will
1220+ * be next to impossible. In any case, we may want different options
1221+ * for rekeying. So, use our own :)
1222+ */
1223+#ifdef USE_PAM
1224+ if (!use_privsep) {
1225+ debug("Not even going to try and do PAM with privsep disabled");
1226+ return;
1227+ }
1228+
1229+ ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
1230+ &pamconv, &pamh);
1231+ if (ret)
1232+ return;
1233+
1234+ xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
1235+ gssapi_client.store.envval);
1236+
1237+ ret = pam_putenv(pamh, envstr);
1238+ if (!ret)
1239+ pam_setcred(pamh, PAM_REINITIALIZE_CRED);
1240+ pam_end(pamh, PAM_SUCCESS);
1241+#endif
1242+}
1243+
1244+int
1245+ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
1246+ int ok = 0;
1247+
1248+ /* Check we've got credentials to store */
1249+ if (!gssapi_client.updated)
1250+ return 0;
1251+
1252+ gssapi_client.updated = 0;
1253+
1254+ temporarily_use_uid(gssapi_client.store.owner);
1255+ if (gssapi_client.mech && gssapi_client.mech->updatecreds)
1256+ ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
1257+ else
1258+ debug("No update function for this mechanism");
1259+
1260+ restore_uid();
1261+
1262+ return ok;
1263 }
1264
1265 #endif
1266Index: b/kex.c
1267===================================================================
1268--- a/kex.c
1269+++ b/kex.c
1270@@ -50,6 +50,10 @@
1271 #include "monitor.h"
1272 #include "roaming.h"
1273
1274+#ifdef GSSAPI
1275+#include "ssh-gss.h"
1276+#endif
1277+
1278 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
1279 # if defined(HAVE_EVP_SHA256)
1280 # define evp_ssh_sha256 EVP_sha256
1281@@ -82,6 +86,14 @@
1282 #endif
1283 { NULL, -1, -1, NULL},
1284 };
1285+static const struct kexalg kexalg_prefixes[] = {
1286+#ifdef GSSAPI
1287+ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, EVP_sha1 },
1288+ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, EVP_sha1 },
1289+ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, EVP_sha1 },
1290+#endif
1291+ { NULL, -1, -1, NULL },
1292+};
1293
1294 char *
1295 kex_alg_list(void)
1296@@ -110,6 +122,10 @@
1297 if (strcmp(k->name, name) == 0)
1298 return k;
1299 }
1300+ for (k = kexalg_prefixes; k->name != NULL; k++) {
1301+ if (strncmp(k->name, name, strlen(k->name)) == 0)
1302+ return k;
1303+ }
1304 return NULL;
1305 }
1306
1307Index: b/kex.h
1308===================================================================
1309--- a/kex.h
1310+++ b/kex.h
1311@@ -74,6 +74,9 @@
1312 KEX_DH_GEX_SHA1,
1313 KEX_DH_GEX_SHA256,
1314 KEX_ECDH_SHA2,
1315+ KEX_GSS_GRP1_SHA1,
1316+ KEX_GSS_GRP14_SHA1,
1317+ KEX_GSS_GEX_SHA1,
1318 KEX_MAX
1319 };
1320
1321@@ -133,6 +136,12 @@
1322 int flags;
1323 const EVP_MD *evp_md;
1324 int ec_nid;
1325+#ifdef GSSAPI
1326+ int gss_deleg_creds;
1327+ int gss_trust_dns;
1328+ char *gss_host;
1329+ char *gss_client;
1330+#endif
1331 char *client_version_string;
1332 char *server_version_string;
1333 int (*verify_host_key)(Key *);
1334@@ -162,6 +171,11 @@
1335 void kexecdh_client(Kex *);
1336 void kexecdh_server(Kex *);
1337
1338+#ifdef GSSAPI
1339+void kexgss_client(Kex *);
1340+void kexgss_server(Kex *);
1341+#endif
1342+
1343 void
1344 kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
1345 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
1346Index: b/kexgssc.c
1347===================================================================
1348--- /dev/null
1349+++ b/kexgssc.c
1350@@ -0,0 +1,333 @@
1351+/*
1352+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
1353+ *
1354+ * Redistribution and use in source and binary forms, with or without
1355+ * modification, are permitted provided that the following conditions
1356+ * are met:
1357+ * 1. Redistributions of source code must retain the above copyright
1358+ * notice, this list of conditions and the following disclaimer.
1359+ * 2. Redistributions in binary form must reproduce the above copyright
1360+ * notice, this list of conditions and the following disclaimer in the
1361+ * documentation and/or other materials provided with the distribution.
1362+ *
1363+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
1364+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1365+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1366+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1367+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1368+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1369+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1370+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1371+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1372+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1373+ */
1374+
1375+#include "includes.h"
1376+
1377+#ifdef GSSAPI
1378+
1379+#include "includes.h"
1380+
1381+#include <openssl/crypto.h>
1382+#include <openssl/bn.h>
1383+
1384+#include <string.h>
1385+
1386+#include "xmalloc.h"
1387+#include "buffer.h"
1388+#include "ssh2.h"
1389+#include "key.h"
1390+#include "cipher.h"
1391+#include "kex.h"
1392+#include "log.h"
1393+#include "packet.h"
1394+#include "dh.h"
1395+
1396+#include "ssh-gss.h"
1397+
1398+void
1399+kexgss_client(Kex *kex) {
1400+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
1401+ gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
1402+ Gssctxt *ctxt;
1403+ OM_uint32 maj_status, min_status, ret_flags;
1404+ u_int klen, kout, slen = 0, hashlen, strlen;
1405+ DH *dh;
1406+ BIGNUM *dh_server_pub = NULL;
1407+ BIGNUM *shared_secret = NULL;
1408+ BIGNUM *p = NULL;
1409+ BIGNUM *g = NULL;
1410+ u_char *kbuf, *hash;
1411+ u_char *serverhostkey = NULL;
1412+ u_char *empty = "";
1413+ char *msg;
1414+ char *lang;
1415+ int type = 0;
1416+ int first = 1;
1417+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
1418+
1419+ /* Initialise our GSSAPI world */
1420+ ssh_gssapi_build_ctx(&ctxt);
1421+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
1422+ == GSS_C_NO_OID)
1423+ fatal("Couldn't identify host exchange");
1424+
1425+ if (ssh_gssapi_import_name(ctxt, kex->gss_host))
1426+ fatal("Couldn't import hostname");
1427+
1428+ if (kex->gss_client &&
1429+ ssh_gssapi_client_identity(ctxt, kex->gss_client))
1430+ fatal("Couldn't acquire client credentials");
1431+
1432+ switch (kex->kex_type) {
1433+ case KEX_GSS_GRP1_SHA1:
1434+ dh = dh_new_group1();
1435+ break;
1436+ case KEX_GSS_GRP14_SHA1:
1437+ dh = dh_new_group14();
1438+ break;
1439+ case KEX_GSS_GEX_SHA1:
1440+ debug("Doing group exchange\n");
1441+ nbits = dh_estimate(kex->we_need * 8);
1442+ packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
1443+ packet_put_int(min);
1444+ packet_put_int(nbits);
1445+ packet_put_int(max);
1446+
1447+ packet_send();
1448+
1449+ packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
1450+
1451+ if ((p = BN_new()) == NULL)
1452+ fatal("BN_new() failed");
1453+ packet_get_bignum2(p);
1454+ if ((g = BN_new()) == NULL)
1455+ fatal("BN_new() failed");
1456+ packet_get_bignum2(g);
1457+ packet_check_eom();
1458+
1459+ if (BN_num_bits(p) < min || BN_num_bits(p) > max)
1460+ fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
1461+ min, BN_num_bits(p), max);
1462+
1463+ dh = dh_new_group(g, p);
1464+ break;
1465+ default:
1466+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1467+ }
1468+
1469+ /* Step 1 - e is dh->pub_key */
1470+ dh_gen_key(dh, kex->we_need * 8);
1471+
1472+ /* This is f, we initialise it now to make life easier */
1473+ dh_server_pub = BN_new();
1474+ if (dh_server_pub == NULL)
1475+ fatal("dh_server_pub == NULL");
1476+
1477+ token_ptr = GSS_C_NO_BUFFER;
1478+
1479+ do {
1480+ debug("Calling gss_init_sec_context");
1481+
1482+ maj_status = ssh_gssapi_init_ctx(ctxt,
1483+ kex->gss_deleg_creds, token_ptr, &send_tok,
1484+ &ret_flags);
1485+
1486+ if (GSS_ERROR(maj_status)) {
1487+ if (send_tok.length != 0) {
1488+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1489+ packet_put_string(send_tok.value,
1490+ send_tok.length);
1491+ }
1492+ fatal("gss_init_context failed");
1493+ }
1494+
1495+ /* If we've got an old receive buffer get rid of it */
1496+ if (token_ptr != GSS_C_NO_BUFFER)
1497+ free(recv_tok.value);
1498+
1499+ if (maj_status == GSS_S_COMPLETE) {
1500+ /* If mutual state flag is not true, kex fails */
1501+ if (!(ret_flags & GSS_C_MUTUAL_FLAG))
1502+ fatal("Mutual authentication failed");
1503+
1504+ /* If integ avail flag is not true kex fails */
1505+ if (!(ret_flags & GSS_C_INTEG_FLAG))
1506+ fatal("Integrity check failed");
1507+ }
1508+
1509+ /*
1510+ * If we have data to send, then the last message that we
1511+ * received cannot have been a 'complete'.
1512+ */
1513+ if (send_tok.length != 0) {
1514+ if (first) {
1515+ packet_start(SSH2_MSG_KEXGSS_INIT);
1516+ packet_put_string(send_tok.value,
1517+ send_tok.length);
1518+ packet_put_bignum2(dh->pub_key);
1519+ first = 0;
1520+ } else {
1521+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1522+ packet_put_string(send_tok.value,
1523+ send_tok.length);
1524+ }
1525+ packet_send();
1526+ gss_release_buffer(&min_status, &send_tok);
1527+
1528+ /* If we've sent them data, they should reply */
1529+ do {
1530+ type = packet_read();
1531+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
1532+ debug("Received KEXGSS_HOSTKEY");
1533+ if (serverhostkey)
1534+ fatal("Server host key received more than once");
1535+ serverhostkey =
1536+ packet_get_string(&slen);
1537+ }
1538+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
1539+
1540+ switch (type) {
1541+ case SSH2_MSG_KEXGSS_CONTINUE:
1542+ debug("Received GSSAPI_CONTINUE");
1543+ if (maj_status == GSS_S_COMPLETE)
1544+ fatal("GSSAPI Continue received from server when complete");
1545+ recv_tok.value = packet_get_string(&strlen);
1546+ recv_tok.length = strlen;
1547+ break;
1548+ case SSH2_MSG_KEXGSS_COMPLETE:
1549+ debug("Received GSSAPI_COMPLETE");
1550+ packet_get_bignum2(dh_server_pub);
1551+ msg_tok.value = packet_get_string(&strlen);
1552+ msg_tok.length = strlen;
1553+
1554+ /* Is there a token included? */
1555+ if (packet_get_char()) {
1556+ recv_tok.value=
1557+ packet_get_string(&strlen);
1558+ recv_tok.length = strlen;
1559+ /* If we're already complete - protocol error */
1560+ if (maj_status == GSS_S_COMPLETE)
1561+ packet_disconnect("Protocol error: received token when complete");
1562+ } else {
1563+ /* No token included */
1564+ if (maj_status != GSS_S_COMPLETE)
1565+ packet_disconnect("Protocol error: did not receive final token");
1566+ }
1567+ break;
1568+ case SSH2_MSG_KEXGSS_ERROR:
1569+ debug("Received Error");
1570+ maj_status = packet_get_int();
1571+ min_status = packet_get_int();
1572+ msg = packet_get_string(NULL);
1573+ lang = packet_get_string(NULL);
1574+ fatal("GSSAPI Error: \n%.400s",msg);
1575+ default:
1576+ packet_disconnect("Protocol error: didn't expect packet type %d",
1577+ type);
1578+ }
1579+ token_ptr = &recv_tok;
1580+ } else {
1581+ /* No data, and not complete */
1582+ if (maj_status != GSS_S_COMPLETE)
1583+ fatal("Not complete, and no token output");
1584+ }
1585+ } while (maj_status & GSS_S_CONTINUE_NEEDED);
1586+
1587+ /*
1588+ * We _must_ have received a COMPLETE message in reply from the
1589+ * server, which will have set dh_server_pub and msg_tok
1590+ */
1591+
1592+ if (type != SSH2_MSG_KEXGSS_COMPLETE)
1593+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
1594+
1595+ /* Check f in range [1, p-1] */
1596+ if (!dh_pub_is_valid(dh, dh_server_pub))
1597+ packet_disconnect("bad server public DH value");
1598+
1599+ /* compute K=f^x mod p */
1600+ klen = DH_size(dh);
1601+ kbuf = xmalloc(klen);
1602+ kout = DH_compute_key(kbuf, dh_server_pub, dh);
1603+ if (kout < 0)
1604+ fatal("DH_compute_key: failed");
1605+
1606+ shared_secret = BN_new();
1607+ if (shared_secret == NULL)
1608+ fatal("kexgss_client: BN_new failed");
1609+
1610+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
1611+ fatal("kexdh_client: BN_bin2bn failed");
1612+
1613+ memset(kbuf, 0, klen);
1614+ free(kbuf);
1615+
1616+ switch (kex->kex_type) {
1617+ case KEX_GSS_GRP1_SHA1:
1618+ case KEX_GSS_GRP14_SHA1:
1619+ kex_dh_hash( kex->client_version_string,
1620+ kex->server_version_string,
1621+ buffer_ptr(&kex->my), buffer_len(&kex->my),
1622+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
1623+ (serverhostkey ? serverhostkey : empty), slen,
1624+ dh->pub_key, /* e */
1625+ dh_server_pub, /* f */
1626+ shared_secret, /* K */
1627+ &hash, &hashlen
1628+ );
1629+ break;
1630+ case KEX_GSS_GEX_SHA1:
1631+ kexgex_hash(
1632+ kex->evp_md,
1633+ kex->client_version_string,
1634+ kex->server_version_string,
1635+ buffer_ptr(&kex->my), buffer_len(&kex->my),
1636+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
1637+ (serverhostkey ? serverhostkey : empty), slen,
1638+ min, nbits, max,
1639+ dh->p, dh->g,
1640+ dh->pub_key,
1641+ dh_server_pub,
1642+ shared_secret,
1643+ &hash, &hashlen
1644+ );
1645+ break;
1646+ default:
1647+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1648+ }
1649+
1650+ gssbuf.value = hash;
1651+ gssbuf.length = hashlen;
1652+
1653+ /* Verify that the hash matches the MIC we just got. */
1654+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
1655+ packet_disconnect("Hash's MIC didn't verify");
1656+
1657+ free(msg_tok.value);
1658+
1659+ DH_free(dh);
1660+ free(serverhostkey);
1661+ BN_clear_free(dh_server_pub);
1662+
1663+ /* save session id */
1664+ if (kex->session_id == NULL) {
1665+ kex->session_id_len = hashlen;
1666+ kex->session_id = xmalloc(kex->session_id_len);
1667+ memcpy(kex->session_id, hash, kex->session_id_len);
1668+ }
1669+
1670+ if (kex->gss_deleg_creds)
1671+ ssh_gssapi_credentials_updated(ctxt);
1672+
1673+ if (gss_kex_context == NULL)
1674+ gss_kex_context = ctxt;
1675+ else
1676+ ssh_gssapi_delete_ctx(&ctxt);
1677+
1678+ kex_derive_keys(kex, hash, hashlen, shared_secret);
1679+ BN_clear_free(shared_secret);
1680+ kex_finish(kex);
1681+}
1682+
1683+#endif /* GSSAPI */
1684Index: b/kexgsss.c
1685===================================================================
1686--- /dev/null
1687+++ b/kexgsss.c
1688@@ -0,0 +1,289 @@
1689+/*
1690+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
1691+ *
1692+ * Redistribution and use in source and binary forms, with or without
1693+ * modification, are permitted provided that the following conditions
1694+ * are met:
1695+ * 1. Redistributions of source code must retain the above copyright
1696+ * notice, this list of conditions and the following disclaimer.
1697+ * 2. Redistributions in binary form must reproduce the above copyright
1698+ * notice, this list of conditions and the following disclaimer in the
1699+ * documentation and/or other materials provided with the distribution.
1700+ *
1701+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
1702+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1703+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1704+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1705+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1706+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1707+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1708+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1709+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1710+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1711+ */
1712+
1713+#include "includes.h"
1714+
1715+#ifdef GSSAPI
1716+
1717+#include <string.h>
1718+
1719+#include <openssl/crypto.h>
1720+#include <openssl/bn.h>
1721+
1722+#include "xmalloc.h"
1723+#include "buffer.h"
1724+#include "ssh2.h"
1725+#include "key.h"
1726+#include "cipher.h"
1727+#include "kex.h"
1728+#include "log.h"
1729+#include "packet.h"
1730+#include "dh.h"
1731+#include "ssh-gss.h"
1732+#include "monitor_wrap.h"
1733+#include "servconf.h"
1734+
1735+extern ServerOptions options;
1736+
1737+void
1738+kexgss_server(Kex *kex)
1739+{
1740+ OM_uint32 maj_status, min_status;
1741+
1742+ /*
1743+ * Some GSSAPI implementations use the input value of ret_flags (an
1744+ * output variable) as a means of triggering mechanism specific
1745+ * features. Initializing it to zero avoids inadvertently
1746+ * activating this non-standard behaviour.
1747+ */
1748+
1749+ OM_uint32 ret_flags = 0;
1750+ gss_buffer_desc gssbuf, recv_tok, msg_tok;
1751+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
1752+ Gssctxt *ctxt = NULL;
1753+ u_int slen, klen, kout, hashlen;
1754+ u_char *kbuf, *hash;
1755+ DH *dh;
1756+ int min = -1, max = -1, nbits = -1;
1757+ BIGNUM *shared_secret = NULL;
1758+ BIGNUM *dh_client_pub = NULL;
1759+ int type = 0;
1760+ gss_OID oid;
1761+ char *mechs;
1762+
1763+ /* Initialise GSSAPI */
1764+
1765+ /* If we're rekeying, privsep means that some of the private structures
1766+ * in the GSSAPI code are no longer available. This kludges them back
1767+ * into life
1768+ */
1769+ if (!ssh_gssapi_oid_table_ok()) {
1770+ mechs = ssh_gssapi_server_mechanisms();
1771+ free(mechs);
1772+ }
1773+
1774+ debug2("%s: Identifying %s", __func__, kex->name);
1775+ oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
1776+ if (oid == GSS_C_NO_OID)
1777+ fatal("Unknown gssapi mechanism");
1778+
1779+ debug2("%s: Acquiring credentials", __func__);
1780+
1781+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
1782+ fatal("Unable to acquire credentials for the server");
1783+
1784+ switch (kex->kex_type) {
1785+ case KEX_GSS_GRP1_SHA1:
1786+ dh = dh_new_group1();
1787+ break;
1788+ case KEX_GSS_GRP14_SHA1:
1789+ dh = dh_new_group14();
1790+ break;
1791+ case KEX_GSS_GEX_SHA1:
1792+ debug("Doing group exchange");
1793+ packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
1794+ min = packet_get_int();
1795+ nbits = packet_get_int();
1796+ max = packet_get_int();
1797+ min = MAX(DH_GRP_MIN, min);
1798+ max = MIN(DH_GRP_MAX, max);
1799+ packet_check_eom();
1800+ if (max < min || nbits < min || max < nbits)
1801+ fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
1802+ min, nbits, max);
1803+ dh = PRIVSEP(choose_dh(min, nbits, max));
1804+ if (dh == NULL)
1805+ packet_disconnect("Protocol error: no matching group found");
1806+
1807+ packet_start(SSH2_MSG_KEXGSS_GROUP);
1808+ packet_put_bignum2(dh->p);
1809+ packet_put_bignum2(dh->g);
1810+ packet_send();
1811+
1812+ packet_write_wait();
1813+ break;
1814+ default:
1815+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1816+ }
1817+
1818+ dh_gen_key(dh, kex->we_need * 8);
1819+
1820+ do {
1821+ debug("Wait SSH2_MSG_GSSAPI_INIT");
1822+ type = packet_read();
1823+ switch(type) {
1824+ case SSH2_MSG_KEXGSS_INIT:
1825+ if (dh_client_pub != NULL)
1826+ fatal("Received KEXGSS_INIT after initialising");
1827+ recv_tok.value = packet_get_string(&slen);
1828+ recv_tok.length = slen;
1829+
1830+ if ((dh_client_pub = BN_new()) == NULL)
1831+ fatal("dh_client_pub == NULL");
1832+
1833+ packet_get_bignum2(dh_client_pub);
1834+
1835+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
1836+ break;
1837+ case SSH2_MSG_KEXGSS_CONTINUE:
1838+ recv_tok.value = packet_get_string(&slen);
1839+ recv_tok.length = slen;
1840+ break;
1841+ default:
1842+ packet_disconnect(
1843+ "Protocol error: didn't expect packet type %d",
1844+ type);
1845+ }
1846+
1847+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
1848+ &send_tok, &ret_flags));
1849+
1850+ free(recv_tok.value);
1851+
1852+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
1853+ fatal("Zero length token output when incomplete");
1854+
1855+ if (dh_client_pub == NULL)
1856+ fatal("No client public key");
1857+
1858+ if (maj_status & GSS_S_CONTINUE_NEEDED) {
1859+ debug("Sending GSSAPI_CONTINUE");
1860+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1861+ packet_put_string(send_tok.value, send_tok.length);
1862+ packet_send();
1863+ gss_release_buffer(&min_status, &send_tok);
1864+ }
1865+ } while (maj_status & GSS_S_CONTINUE_NEEDED);
1866+
1867+ if (GSS_ERROR(maj_status)) {
1868+ if (send_tok.length > 0) {
1869+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
1870+ packet_put_string(send_tok.value, send_tok.length);
1871+ packet_send();
1872+ }
1873+ fatal("accept_ctx died");
1874+ }
1875+
1876+ if (!(ret_flags & GSS_C_MUTUAL_FLAG))
1877+ fatal("Mutual Authentication flag wasn't set");
1878+
1879+ if (!(ret_flags & GSS_C_INTEG_FLAG))
1880+ fatal("Integrity flag wasn't set");
1881+
1882+ if (!dh_pub_is_valid(dh, dh_client_pub))
1883+ packet_disconnect("bad client public DH value");
1884+
1885+ klen = DH_size(dh);
1886+ kbuf = xmalloc(klen);
1887+ kout = DH_compute_key(kbuf, dh_client_pub, dh);
1888+ if (kout < 0)
1889+ fatal("DH_compute_key: failed");
1890+
1891+ shared_secret = BN_new();
1892+ if (shared_secret == NULL)
1893+ fatal("kexgss_server: BN_new failed");
1894+
1895+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
1896+ fatal("kexgss_server: BN_bin2bn failed");
1897+
1898+ memset(kbuf, 0, klen);
1899+ free(kbuf);
1900+
1901+ switch (kex->kex_type) {
1902+ case KEX_GSS_GRP1_SHA1:
1903+ case KEX_GSS_GRP14_SHA1:
1904+ kex_dh_hash(
1905+ kex->client_version_string, kex->server_version_string,
1906+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
1907+ buffer_ptr(&kex->my), buffer_len(&kex->my),
1908+ NULL, 0, /* Change this if we start sending host keys */
1909+ dh_client_pub, dh->pub_key, shared_secret,
1910+ &hash, &hashlen
1911+ );
1912+ break;
1913+ case KEX_GSS_GEX_SHA1:
1914+ kexgex_hash(
1915+ kex->evp_md,
1916+ kex->client_version_string, kex->server_version_string,
1917+ buffer_ptr(&kex->peer), buffer_len(&kex->peer),
1918+ buffer_ptr(&kex->my), buffer_len(&kex->my),
1919+ NULL, 0,
1920+ min, nbits, max,
1921+ dh->p, dh->g,
1922+ dh_client_pub,
1923+ dh->pub_key,
1924+ shared_secret,
1925+ &hash, &hashlen
1926+ );
1927+ break;
1928+ default:
1929+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
1930+ }
1931+
1932+ BN_clear_free(dh_client_pub);
1933+
1934+ if (kex->session_id == NULL) {
1935+ kex->session_id_len = hashlen;
1936+ kex->session_id = xmalloc(kex->session_id_len);
1937+ memcpy(kex->session_id, hash, kex->session_id_len);
1938+ }
1939+
1940+ gssbuf.value = hash;
1941+ gssbuf.length = hashlen;
1942+
1943+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
1944+ fatal("Couldn't get MIC");
1945+
1946+ packet_start(SSH2_MSG_KEXGSS_COMPLETE);
1947+ packet_put_bignum2(dh->pub_key);
1948+ packet_put_string(msg_tok.value,msg_tok.length);
1949+
1950+ if (send_tok.length != 0) {
1951+ packet_put_char(1); /* true */
1952+ packet_put_string(send_tok.value, send_tok.length);
1953+ } else {
1954+ packet_put_char(0); /* false */
1955+ }
1956+ packet_send();
1957+
1958+ gss_release_buffer(&min_status, &send_tok);
1959+ gss_release_buffer(&min_status, &msg_tok);
1960+
1961+ if (gss_kex_context == NULL)
1962+ gss_kex_context = ctxt;
1963+ else
1964+ ssh_gssapi_delete_ctx(&ctxt);
1965+
1966+ DH_free(dh);
1967+
1968+ kex_derive_keys(kex, hash, hashlen, shared_secret);
1969+ BN_clear_free(shared_secret);
1970+ kex_finish(kex);
1971+
1972+ /* If this was a rekey, then save out any delegated credentials we
1973+ * just exchanged. */
1974+ if (options.gss_store_rekey)
1975+ ssh_gssapi_rekey_creds();
1976+}
1977+#endif /* GSSAPI */
1978Index: b/key.c
1979===================================================================
1980--- a/key.c
1981+++ b/key.c
1982@@ -933,6 +933,7 @@
1983 KEY_RSA_CERT_V00, 0, 1 },
1984 { "ssh-dss-cert-v00@openssh.com", "DSA-CERT-V00",
1985 KEY_DSA_CERT_V00, 0, 1 },
1986+ { "null", "null", KEY_NULL, 0, 0 },
1987 { NULL, NULL, -1, -1, 0 }
1988 };
1989
1990Index: b/key.h
1991===================================================================
1992--- a/key.h
1993+++ b/key.h
1994@@ -44,6 +44,7 @@
1995 KEY_ECDSA_CERT,
1996 KEY_RSA_CERT_V00,
1997 KEY_DSA_CERT_V00,
1998+ KEY_NULL,
1999 KEY_UNSPEC
2000 };
2001 enum fp_type {
2002Index: b/monitor.c
2003===================================================================
2004--- a/monitor.c
2005+++ b/monitor.c
2006@@ -181,6 +181,8 @@
2007 int mm_answer_gss_accept_ctx(int, Buffer *);
2008 int mm_answer_gss_userok(int, Buffer *);
2009 int mm_answer_gss_checkmic(int, Buffer *);
2010+int mm_answer_gss_sign(int, Buffer *);
2011+int mm_answer_gss_updatecreds(int, Buffer *);
2012 #endif
2013
2014 #ifdef SSH_AUDIT_EVENTS
2015@@ -253,6 +255,7 @@
2016 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
2017 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
2018 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
2019+ {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
2020 #endif
2021 #ifdef JPAKE
2022 {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
2023@@ -265,6 +268,12 @@
2024 };
2025
2026 struct mon_table mon_dispatch_postauth20[] = {
2027+#ifdef GSSAPI
2028+ {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
2029+ {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
2030+ {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
2031+ {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
2032+#endif
2033 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
2034 {MONITOR_REQ_SIGN, 0, mm_answer_sign},
2035 {MONITOR_REQ_PTY, 0, mm_answer_pty},
2036@@ -373,6 +382,10 @@
2037 /* Permit requests for moduli and signatures */
2038 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
2039 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
2040+#ifdef GSSAPI
2041+ /* and for the GSSAPI key exchange */
2042+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
2043+#endif
2044 } else {
2045 mon_dispatch = mon_dispatch_proto15;
2046
2047@@ -487,6 +500,10 @@
2048 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
2049 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
2050 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
2051+#ifdef GSSAPI
2052+ /* and for the GSSAPI key exchange */
2053+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
2054+#endif
2055 } else {
2056 mon_dispatch = mon_dispatch_postauth15;
2057 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
2058@@ -1855,6 +1872,13 @@
2059 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
2060 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
2061 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
2062+#ifdef GSSAPI
2063+ if (options.gss_keyex) {
2064+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
2065+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
2066+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
2067+ }
2068+#endif
2069 kex->server = 1;
2070 kex->hostkey_type = buffer_get_int(m);
2071 kex->kex_type = buffer_get_int(m);
2072@@ -2062,6 +2086,9 @@
2073 OM_uint32 major;
2074 u_int len;
2075
2076+ if (!options.gss_authentication && !options.gss_keyex)
2077+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2078+
2079 goid.elements = buffer_get_string(m, &len);
2080 goid.length = len;
2081
2082@@ -2089,6 +2116,9 @@
2083 OM_uint32 flags = 0; /* GSI needs this */
2084 u_int len;
2085
2086+ if (!options.gss_authentication && !options.gss_keyex)
2087+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2088+
2089 in.value = buffer_get_string(m, &len);
2090 in.length = len;
2091 major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
2092@@ -2106,6 +2136,7 @@
2093 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
2094 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
2095 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
2096+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
2097 }
2098 return (0);
2099 }
2100@@ -2117,6 +2148,9 @@
2101 OM_uint32 ret;
2102 u_int len;
2103
2104+ if (!options.gss_authentication && !options.gss_keyex)
2105+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2106+
2107 gssbuf.value = buffer_get_string(m, &len);
2108 gssbuf.length = len;
2109 mic.value = buffer_get_string(m, &len);
2110@@ -2143,7 +2177,11 @@
2111 {
2112 int authenticated;
2113
2114- authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
2115+ if (!options.gss_authentication && !options.gss_keyex)
2116+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2117+
2118+ authenticated = authctxt->valid &&
2119+ ssh_gssapi_userok(authctxt->user, authctxt->pw);
2120
2121 buffer_clear(m);
2122 buffer_put_int(m, authenticated);
2123@@ -2156,6 +2194,74 @@
2124 /* Monitor loop will terminate if authenticated */
2125 return (authenticated);
2126 }
2127+
2128+int
2129+mm_answer_gss_sign(int socket, Buffer *m)
2130+{
2131+ gss_buffer_desc data;
2132+ gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
2133+ OM_uint32 major, minor;
2134+ u_int len;
2135+
2136+ if (!options.gss_authentication && !options.gss_keyex)
2137+ fatal("In GSSAPI monitor when GSSAPI is disabled");
2138+
2139+ data.value = buffer_get_string(m, &len);
2140+ data.length = len;
2141+ if (data.length != 20)
2142+ fatal("%s: data length incorrect: %d", __func__,
2143+ (int) data.length);
2144+
2145+ /* Save the session ID on the first time around */
2146+ if (session_id2_len == 0) {
2147+ session_id2_len = data.length;
2148+ session_id2 = xmalloc(session_id2_len);
2149+ memcpy(session_id2, data.value, session_id2_len);
2150+ }
2151+ major = ssh_gssapi_sign(gsscontext, &data, &hash);
2152+
2153+ free(data.value);
2154+
2155+ buffer_clear(m);
2156+ buffer_put_int(m, major);
2157+ buffer_put_string(m, hash.value, hash.length);
2158+
2159+ mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
2160+
2161+ gss_release_buffer(&minor, &hash);
2162+
2163+ /* Turn on getpwnam permissions */
2164+ monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
2165+
2166+ /* And credential updating, for when rekeying */
2167+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
2168+
2169+ return (0);
2170+}
2171+
2172+int
2173+mm_answer_gss_updatecreds(int socket, Buffer *m) {
2174+ ssh_gssapi_ccache store;
2175+ int ok;
2176+
2177+ store.filename = buffer_get_string(m, NULL);
2178+ store.envvar = buffer_get_string(m, NULL);
2179+ store.envval = buffer_get_string(m, NULL);
2180+
2181+ ok = ssh_gssapi_update_creds(&store);
2182+
2183+ free(store.filename);
2184+ free(store.envvar);
2185+ free(store.envval);
2186+
2187+ buffer_clear(m);
2188+ buffer_put_int(m, ok);
2189+
2190+ mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
2191+
2192+ return(0);
2193+}
2194+
2195 #endif /* GSSAPI */
2196
2197 #ifdef JPAKE
2198Index: b/monitor.h
2199===================================================================
2200--- a/monitor.h
2201+++ b/monitor.h
2202@@ -70,6 +70,9 @@
2203 MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
2204 MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
2205
2206+ MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
2207+ MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
2208+
2209 };
2210
2211 struct mm_master;
2212Index: b/monitor_wrap.c
2213===================================================================
2214--- a/monitor_wrap.c
2215+++ b/monitor_wrap.c
2216@@ -1273,7 +1273,7 @@
2217 }
2218
2219 int
2220-mm_ssh_gssapi_userok(char *user)
2221+mm_ssh_gssapi_userok(char *user, struct passwd *pw)
2222 {
2223 Buffer m;
2224 int authenticated = 0;
2225@@ -1290,6 +1290,51 @@
2226 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
2227 return (authenticated);
2228 }
2229+
2230+OM_uint32
2231+mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
2232+{
2233+ Buffer m;
2234+ OM_uint32 major;
2235+ u_int len;
2236+
2237+ buffer_init(&m);
2238+ buffer_put_string(&m, data->value, data->length);
2239+
2240+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
2241+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
2242+
2243+ major = buffer_get_int(&m);
2244+ hash->value = buffer_get_string(&m, &len);
2245+ hash->length = len;
2246+
2247+ buffer_free(&m);
2248+
2249+ return(major);
2250+}
2251+
2252+int
2253+mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
2254+{
2255+ Buffer m;
2256+ int ok;
2257+
2258+ buffer_init(&m);
2259+
2260+ buffer_put_cstring(&m, store->filename ? store->filename : "");
2261+ buffer_put_cstring(&m, store->envvar ? store->envvar : "");
2262+ buffer_put_cstring(&m, store->envval ? store->envval : "");
2263+
2264+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m);
2265+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m);
2266+
2267+ ok = buffer_get_int(&m);
2268+
2269+ buffer_free(&m);
2270+
2271+ return (ok);
2272+}
2273+
2274 #endif /* GSSAPI */
2275
2276 #ifdef JPAKE
2277Index: b/monitor_wrap.h
2278===================================================================
2279--- a/monitor_wrap.h
2280+++ b/monitor_wrap.h
2281@@ -58,8 +58,10 @@
2282 OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
2283 OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
2284 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
2285-int mm_ssh_gssapi_userok(char *user);
2286+int mm_ssh_gssapi_userok(char *user, struct passwd *);
2287 OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
2288+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
2289+int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
2290 #endif
2291
2292 #ifdef USE_PAM
2293Index: b/readconf.c
2294===================================================================
2295--- a/readconf.c
2296+++ b/readconf.c
2297@@ -132,6 +132,8 @@
2298 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
2299 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
2300 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
2301+ oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
2302+ oGssServerIdentity,
2303 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
2304 oSendEnv, oControlPath, oControlMaster, oControlPersist,
2305 oHashKnownHosts,
2306@@ -172,10 +174,19 @@
2307 { "afstokenpassing", oUnsupported },
2308 #if defined(GSSAPI)
2309 { "gssapiauthentication", oGssAuthentication },
2310+ { "gssapikeyexchange", oGssKeyEx },
2311 { "gssapidelegatecredentials", oGssDelegateCreds },
2312+ { "gssapitrustdns", oGssTrustDns },
2313+ { "gssapiclientidentity", oGssClientIdentity },
2314+ { "gssapiserveridentity", oGssServerIdentity },
2315+ { "gssapirenewalforcesrekey", oGssRenewalRekey },
2316 #else
2317 { "gssapiauthentication", oUnsupported },
2318+ { "gssapikeyexchange", oUnsupported },
2319 { "gssapidelegatecredentials", oUnsupported },
2320+ { "gssapitrustdns", oUnsupported },
2321+ { "gssapiclientidentity", oUnsupported },
2322+ { "gssapirenewalforcesrekey", oUnsupported },
2323 #endif
2324 { "fallbacktorsh", oDeprecated },
2325 { "usersh", oDeprecated },
2326@@ -516,10 +527,30 @@
2327 intptr = &options->gss_authentication;
2328 goto parse_flag;
2329
2330+ case oGssKeyEx:
2331+ intptr = &options->gss_keyex;
2332+ goto parse_flag;
2333+
2334 case oGssDelegateCreds:
2335 intptr = &options->gss_deleg_creds;
2336 goto parse_flag;
2337
2338+ case oGssTrustDns:
2339+ intptr = &options->gss_trust_dns;
2340+ goto parse_flag;
2341+
2342+ case oGssClientIdentity:
2343+ charptr = &options->gss_client_identity;
2344+ goto parse_string;
2345+
2346+ case oGssServerIdentity:
2347+ charptr = &options->gss_server_identity;
2348+ goto parse_string;
2349+
2350+ case oGssRenewalRekey:
2351+ intptr = &options->gss_renewal_rekey;
2352+ goto parse_flag;
2353+
2354 case oBatchMode:
2355 intptr = &options->batch_mode;
2356 goto parse_flag;
2357@@ -1168,7 +1199,12 @@
2358 options->pubkey_authentication = -1;
2359 options->challenge_response_authentication = -1;
2360 options->gss_authentication = -1;
2361+ options->gss_keyex = -1;
2362 options->gss_deleg_creds = -1;
2363+ options->gss_trust_dns = -1;
2364+ options->gss_renewal_rekey = -1;
2365+ options->gss_client_identity = NULL;
2366+ options->gss_server_identity = NULL;
2367 options->password_authentication = -1;
2368 options->kbd_interactive_authentication = -1;
2369 options->kbd_interactive_devices = NULL;
2370@@ -1268,8 +1304,14 @@
2371 options->challenge_response_authentication = 1;
2372 if (options->gss_authentication == -1)
2373 options->gss_authentication = 0;
2374+ if (options->gss_keyex == -1)
2375+ options->gss_keyex = 0;
2376 if (options->gss_deleg_creds == -1)
2377 options->gss_deleg_creds = 0;
2378+ if (options->gss_trust_dns == -1)
2379+ options->gss_trust_dns = 0;
2380+ if (options->gss_renewal_rekey == -1)
2381+ options->gss_renewal_rekey = 0;
2382 if (options->password_authentication == -1)
2383 options->password_authentication = 1;
2384 if (options->kbd_interactive_authentication == -1)
2385Index: b/readconf.h
2386===================================================================
2387--- a/readconf.h
2388+++ b/readconf.h
2389@@ -48,7 +48,12 @@
2390 int challenge_response_authentication;
2391 /* Try S/Key or TIS, authentication. */
2392 int gss_authentication; /* Try GSS authentication */
2393+ int gss_keyex; /* Try GSS key exchange */
2394 int gss_deleg_creds; /* Delegate GSS credentials */
2395+ int gss_trust_dns; /* Trust DNS for GSS canonicalization */
2396+ int gss_renewal_rekey; /* Credential renewal forces rekey */
2397+ char *gss_client_identity; /* Principal to initiate GSSAPI with */
2398+ char *gss_server_identity; /* GSSAPI target principal */
2399 int password_authentication; /* Try password
2400 * authentication. */
2401 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
2402Index: b/servconf.c
2403===================================================================
2404--- a/servconf.c
2405+++ b/servconf.c
2406@@ -107,7 +107,10 @@
2407 options->kerberos_ticket_cleanup = -1;
2408 options->kerberos_get_afs_token = -1;
2409 options->gss_authentication=-1;
2410+ options->gss_keyex = -1;
2411 options->gss_cleanup_creds = -1;
2412+ options->gss_strict_acceptor = -1;
2413+ options->gss_store_rekey = -1;
2414 options->password_authentication = -1;
2415 options->kbd_interactive_authentication = -1;
2416 options->challenge_response_authentication = -1;
2417@@ -240,8 +243,14 @@
2418 options->kerberos_get_afs_token = 0;
2419 if (options->gss_authentication == -1)
2420 options->gss_authentication = 0;
2421+ if (options->gss_keyex == -1)
2422+ options->gss_keyex = 0;
2423 if (options->gss_cleanup_creds == -1)
2424 options->gss_cleanup_creds = 1;
2425+ if (options->gss_strict_acceptor == -1)
2426+ options->gss_strict_acceptor = 1;
2427+ if (options->gss_store_rekey == -1)
2428+ options->gss_store_rekey = 0;
2429 if (options->password_authentication == -1)
2430 options->password_authentication = 1;
2431 if (options->kbd_interactive_authentication == -1)
2432@@ -338,7 +347,9 @@
2433 sBanner, sUseDNS, sHostbasedAuthentication,
2434 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
2435 sClientAliveCountMax, sAuthorizedKeysFile,
2436- sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
2437+ sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
2438+ sGssKeyEx, sGssStoreRekey,
2439+ sAcceptEnv, sPermitTunnel,
2440 sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
2441 sUsePrivilegeSeparation, sAllowAgentForwarding,
2442 sZeroKnowledgePasswordAuthentication, sHostCertificate,
2443@@ -405,10 +416,20 @@
2444 #ifdef GSSAPI
2445 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
2446 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
2447+ { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL },
2448+ { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
2449+ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
2450+ { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
2451 #else
2452 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
2453 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
2454+ { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL },
2455+ { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
2456+ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
2457+ { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
2458 #endif
2459+ { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL },
2460+ { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL },
2461 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
2462 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
2463 { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
2464@@ -1073,10 +1094,22 @@
2465 intptr = &options->gss_authentication;
2466 goto parse_flag;
2467
2468+ case sGssKeyEx:
2469+ intptr = &options->gss_keyex;
2470+ goto parse_flag;
2471+
2472 case sGssCleanupCreds:
2473 intptr = &options->gss_cleanup_creds;
2474 goto parse_flag;
2475
2476+ case sGssStrictAcceptor:
2477+ intptr = &options->gss_strict_acceptor;
2478+ goto parse_flag;
2479+
2480+ case sGssStoreRekey:
2481+ intptr = &options->gss_store_rekey;
2482+ goto parse_flag;
2483+
2484 case sPasswordAuthentication:
2485 intptr = &options->password_authentication;
2486 goto parse_flag;
2487@@ -1983,7 +2016,10 @@
2488 #endif
2489 #ifdef GSSAPI
2490 dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
2491+ dump_cfg_fmtint(sGssKeyEx, o->gss_keyex);
2492 dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
2493+ dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor);
2494+ dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey);
2495 #endif
2496 #ifdef JPAKE
2497 dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication,
2498Index: b/servconf.h
2499===================================================================
2500--- a/servconf.h
2501+++ b/servconf.h
2502@@ -111,7 +111,10 @@
2503 int kerberos_get_afs_token; /* If true, try to get AFS token if
2504 * authenticated with Kerberos. */
2505 int gss_authentication; /* If true, permit GSSAPI authentication */
2506+ int gss_keyex; /* If true, permit GSSAPI key exchange */
2507 int gss_cleanup_creds; /* If true, destroy cred cache on logout */
2508+ int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */
2509+ int gss_store_rekey;
2510 int password_authentication; /* If true, permit password
2511 * authentication. */
2512 int kbd_interactive_authentication; /* If true, permit */
2513Index: b/ssh-gss.h
2514===================================================================
2515--- a/ssh-gss.h
2516+++ b/ssh-gss.h
2517@@ -1,6 +1,6 @@
2518 /* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */
2519 /*
2520- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
2521+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
2522 *
2523 * Redistribution and use in source and binary forms, with or without
2524 * modification, are permitted provided that the following conditions
2525@@ -61,10 +61,22 @@
2526
2527 #define SSH_GSS_OIDTYPE 0x06
2528
2529+#define SSH2_MSG_KEXGSS_INIT 30
2530+#define SSH2_MSG_KEXGSS_CONTINUE 31
2531+#define SSH2_MSG_KEXGSS_COMPLETE 32
2532+#define SSH2_MSG_KEXGSS_HOSTKEY 33
2533+#define SSH2_MSG_KEXGSS_ERROR 34
2534+#define SSH2_MSG_KEXGSS_GROUPREQ 40
2535+#define SSH2_MSG_KEXGSS_GROUP 41
2536+#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-"
2537+#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-"
2538+#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-"
2539+
2540 typedef struct {
2541 char *filename;
2542 char *envvar;
2543 char *envval;
2544+ struct passwd *owner;
2545 void *data;
2546 } ssh_gssapi_ccache;
2547
2548@@ -72,8 +84,11 @@
2549 gss_buffer_desc displayname;
2550 gss_buffer_desc exportedname;
2551 gss_cred_id_t creds;
2552+ gss_name_t name;
2553 struct ssh_gssapi_mech_struct *mech;
2554 ssh_gssapi_ccache store;
2555+ int used;
2556+ int updated;
2557 } ssh_gssapi_client;
2558
2559 typedef struct ssh_gssapi_mech_struct {
2560@@ -84,6 +99,7 @@
2561 int (*userok) (ssh_gssapi_client *, char *);
2562 int (*localname) (ssh_gssapi_client *, char **);
2563 void (*storecreds) (ssh_gssapi_client *);
2564+ int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
2565 } ssh_gssapi_mech;
2566
2567 typedef struct {
2568@@ -94,10 +110,11 @@
2569 gss_OID oid; /* client */
2570 gss_cred_id_t creds; /* server */
2571 gss_name_t client; /* server */
2572- gss_cred_id_t client_creds; /* server */
2573+ gss_cred_id_t client_creds; /* both */
2574 } Gssctxt;
2575
2576 extern ssh_gssapi_mech *supported_mechs[];
2577+extern Gssctxt *gss_kex_context;
2578
2579 int ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
2580 void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
2581@@ -117,16 +134,30 @@
2582 void ssh_gssapi_delete_ctx(Gssctxt **);
2583 OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
2584 void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
2585-int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *);
2586+int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *);
2587+OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
2588+int ssh_gssapi_credentials_updated(Gssctxt *);
2589
2590 /* In the server */
2591+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,
2592+ const char *);
2593+char *ssh_gssapi_client_mechanisms(const char *, const char *);
2594+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *,
2595+ const char *);
2596+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
2597+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *,
2598+ const char *);
2599 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
2600-int ssh_gssapi_userok(char *name);
2601+int ssh_gssapi_userok(char *name, struct passwd *);
2602 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
2603 void ssh_gssapi_do_child(char ***, u_int *);
2604 void ssh_gssapi_cleanup_creds(void);
2605 void ssh_gssapi_storecreds(void);
2606
2607+char *ssh_gssapi_server_mechanisms(void);
2608+int ssh_gssapi_oid_table_ok();
2609+
2610+int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
2611 #endif /* GSSAPI */
2612
2613 #endif /* _SSH_GSS_H */
2614Index: b/ssh_config
2615===================================================================
2616--- a/ssh_config
2617+++ b/ssh_config
2618@@ -26,6 +26,8 @@
2619 # HostbasedAuthentication no
2620 # GSSAPIAuthentication no
2621 # GSSAPIDelegateCredentials no
2622+# GSSAPIKeyExchange no
2623+# GSSAPITrustDNS no
2624 # BatchMode no
2625 # CheckHostIP yes
2626 # AddressFamily any
2627Index: b/ssh_config.5
2628===================================================================
2629--- a/ssh_config.5
2630+++ b/ssh_config.5
2631@@ -529,11 +529,43 @@
2632 The default is
2633 .Dq no .
2634 Note that this option applies to protocol version 2 only.
2635+.It Cm GSSAPIKeyExchange
2636+Specifies whether key exchange based on GSSAPI may be used. When using
2637+GSSAPI key exchange the server need not have a host key.
2638+The default is
2639+.Dq no .
2640+Note that this option applies to protocol version 2 only.
2641+.It Cm GSSAPIClientIdentity
2642+If set, specifies the GSSAPI client identity that ssh should use when
2643+connecting to the server. The default is unset, which means that the default
2644+identity will be used.
2645+.It Cm GSSAPIServerIdentity
2646+If set, specifies the GSSAPI server identity that ssh should expect when
2647+connecting to the server. The default is unset, which means that the
2648+expected GSSAPI server identity will be determined from the target
2649+hostname.
2650 .It Cm GSSAPIDelegateCredentials
2651 Forward (delegate) credentials to the server.
2652 The default is
2653 .Dq no .
2654-Note that this option applies to protocol version 2 only.
2655+Note that this option applies to protocol version 2 connections using GSSAPI.
2656+.It Cm GSSAPIRenewalForcesRekey
2657+If set to
2658+.Dq yes
2659+then renewal of the client's GSSAPI credentials will force the rekeying of the
2660+ssh connection. With a compatible server, this can delegate the renewed
2661+credentials to a session on the server.
2662+The default is
2663+.Dq no .
2664+.It Cm GSSAPITrustDns
2665+Set to
2666+.Dq yes to indicate that the DNS is trusted to securely canonicalize
2667+the name of the host being connected to. If
2668+.Dq no, the hostname entered on the
2669+command line will be passed untouched to the GSSAPI library.
2670+The default is
2671+.Dq no .
2672+This option only applies to protocol version 2 connections using GSSAPI.
2673 .It Cm HashKnownHosts
2674 Indicates that
2675 .Xr ssh 1
2676Index: b/sshconnect2.c
2677===================================================================
2678--- a/sshconnect2.c
2679+++ b/sshconnect2.c
2680@@ -160,9 +160,34 @@
2681 {
2682 Kex *kex;
2683
2684+#ifdef GSSAPI
2685+ char *orig = NULL, *gss = NULL;
2686+ char *gss_host = NULL;
2687+#endif
2688+
2689 xxx_host = host;
2690 xxx_hostaddr = hostaddr;
2691
2692+#ifdef GSSAPI
2693+ if (options.gss_keyex) {
2694+ /* Add the GSSAPI mechanisms currently supported on this
2695+ * client to the key exchange algorithm proposal */
2696+ orig = myproposal[PROPOSAL_KEX_ALGS];
2697+
2698+ if (options.gss_trust_dns)
2699+ gss_host = (char *)get_canonical_hostname(1);
2700+ else
2701+ gss_host = host;
2702+
2703+ gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
2704+ if (gss) {
2705+ debug("Offering GSSAPI proposal: %s", gss);
2706+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
2707+ "%s,%s", gss, orig);
2708+ }
2709+ }
2710+#endif
2711+
2712 if (options.ciphers == (char *)-1) {
2713 logit("No valid ciphers for protocol version 2 given, using defaults.");
2714 options.ciphers = NULL;
2715@@ -197,6 +222,17 @@
2716 if (options.kex_algorithms != NULL)
2717 myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
2718
2719+#ifdef GSSAPI
2720+ /* If we've got GSSAPI algorithms, then we also support the
2721+ * 'null' hostkey, as a last resort */
2722+ if (options.gss_keyex && gss) {
2723+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
2724+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
2725+ "%s,null", orig);
2726+ free(gss);
2727+ }
2728+#endif
2729+
2730 if (options.rekey_limit || options.rekey_interval)
2731 packet_set_rekey_limits((u_int32_t)options.rekey_limit,
2732 (time_t)options.rekey_interval);
2733@@ -208,10 +244,30 @@
2734 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
2735 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
2736 kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
2737+#ifdef GSSAPI
2738+ if (options.gss_keyex) {
2739+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
2740+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
2741+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
2742+ }
2743+#endif
2744 kex->client_version_string=client_version_string;
2745 kex->server_version_string=server_version_string;
2746 kex->verify_host_key=&verify_host_key_callback;
2747
2748+#ifdef GSSAPI
2749+ if (options.gss_keyex) {
2750+ kex->gss_deleg_creds = options.gss_deleg_creds;
2751+ kex->gss_trust_dns = options.gss_trust_dns;
2752+ kex->gss_client = options.gss_client_identity;
2753+ if (options.gss_server_identity) {
2754+ kex->gss_host = options.gss_server_identity;
2755+ } else {
2756+ kex->gss_host = gss_host;
2757+ }
2758+ }
2759+#endif
2760+
2761 xxx_kex = kex;
2762
2763 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
2764@@ -307,6 +363,7 @@
2765 void input_gssapi_hash(int type, u_int32_t, void *);
2766 void input_gssapi_error(int, u_int32_t, void *);
2767 void input_gssapi_errtok(int, u_int32_t, void *);
2768+int userauth_gsskeyex(Authctxt *authctxt);
2769 #endif
2770
2771 void userauth(Authctxt *, char *);
2772@@ -322,6 +379,11 @@
2773
2774 Authmethod authmethods[] = {
2775 #ifdef GSSAPI
2776+ {"gssapi-keyex",
2777+ userauth_gsskeyex,
2778+ NULL,
2779+ &options.gss_authentication,
2780+ NULL},
2781 {"gssapi-with-mic",
2782 userauth_gssapi,
2783 NULL,
2784@@ -625,19 +687,31 @@
2785 static u_int mech = 0;
2786 OM_uint32 min;
2787 int ok = 0;
2788+ const char *gss_host;
2789+
2790+ if (options.gss_server_identity)
2791+ gss_host = options.gss_server_identity;
2792+ else if (options.gss_trust_dns)
2793+ gss_host = get_canonical_hostname(1);
2794+ else
2795+ gss_host = authctxt->host;
2796
2797 /* Try one GSSAPI method at a time, rather than sending them all at
2798 * once. */
2799
2800 if (gss_supported == NULL)
2801- gss_indicate_mechs(&min, &gss_supported);
2802+ if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
2803+ gss_supported = NULL;
2804+ return 0;
2805+ }
2806
2807 /* Check to see if the mechanism is usable before we offer it */
2808 while (mech < gss_supported->count && !ok) {
2809 /* My DER encoding requires length<128 */
2810 if (gss_supported->elements[mech].length < 128 &&
2811 ssh_gssapi_check_mechanism(&gssctxt,
2812- &gss_supported->elements[mech], authctxt->host)) {
2813+ &gss_supported->elements[mech], gss_host,
2814+ options.gss_client_identity)) {
2815 ok = 1; /* Mechanism works */
2816 } else {
2817 mech++;
2818@@ -734,8 +808,8 @@
2819 {
2820 Authctxt *authctxt = ctxt;
2821 Gssctxt *gssctxt;
2822- int oidlen;
2823- char *oidv;
2824+ u_int oidlen;
2825+ u_char *oidv;
2826
2827 if (authctxt == NULL)
2828 fatal("input_gssapi_response: no authentication context");
2829@@ -844,6 +918,48 @@
2830 free(msg);
2831 free(lang);
2832 }
2833+
2834+int
2835+userauth_gsskeyex(Authctxt *authctxt)
2836+{
2837+ Buffer b;
2838+ gss_buffer_desc gssbuf;
2839+ gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
2840+ OM_uint32 ms;
2841+
2842+ static int attempt = 0;
2843+ if (attempt++ >= 1)
2844+ return (0);
2845+
2846+ if (gss_kex_context == NULL) {
2847+ debug("No valid Key exchange context");
2848+ return (0);
2849+ }
2850+
2851+ ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
2852+ "gssapi-keyex");
2853+
2854+ gssbuf.value = buffer_ptr(&b);
2855+ gssbuf.length = buffer_len(&b);
2856+
2857+ if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
2858+ buffer_free(&b);
2859+ return (0);
2860+ }
2861+
2862+ packet_start(SSH2_MSG_USERAUTH_REQUEST);
2863+ packet_put_cstring(authctxt->server_user);
2864+ packet_put_cstring(authctxt->service);
2865+ packet_put_cstring(authctxt->method->name);
2866+ packet_put_string(mic.value, mic.length);
2867+ packet_send();
2868+
2869+ buffer_free(&b);
2870+ gss_release_buffer(&ms, &mic);
2871+
2872+ return (1);
2873+}
2874+
2875 #endif /* GSSAPI */
2876
2877 int
2878Index: b/sshd.c
2879===================================================================
2880--- a/sshd.c
2881+++ b/sshd.c
2882@@ -122,6 +122,10 @@
2883 #include "ssh-sandbox.h"
2884 #include "version.h"
2885
2886+#ifdef USE_SECURITY_SESSION_API
2887+#include <Security/AuthSession.h>
2888+#endif
2889+
2890 #ifdef LIBWRAP
2891 #include <tcpd.h>
2892 #include <syslog.h>
2893@@ -1703,10 +1707,13 @@
2894 logit("Disabling protocol version 1. Could not load host key");
2895 options.protocol &= ~SSH_PROTO_1;
2896 }
2897+#ifndef GSSAPI
2898+ /* The GSSAPI key exchange can run without a host key */
2899 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
2900 logit("Disabling protocol version 2. Could not load host key");
2901 options.protocol &= ~SSH_PROTO_2;
2902 }
2903+#endif
2904 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
2905 logit("sshd: no hostkeys available -- exiting.");
2906 exit(1);
2907@@ -2035,6 +2042,60 @@
2908 /* Log the connection. */
2909 verbose("Connection from %.500s port %d", remote_ip, remote_port);
2910
2911+#ifdef USE_SECURITY_SESSION_API
2912+ /*
2913+ * Create a new security session for use by the new user login if
2914+ * the current session is the root session or we are not launched
2915+ * by inetd (eg: debugging mode or server mode). We do not
2916+ * necessarily need to create a session if we are launched from
2917+ * inetd because Panther xinetd will create a session for us.
2918+ *
2919+ * The only case where this logic will fail is if there is an
2920+ * inetd running in a non-root session which is not creating
2921+ * new sessions for us. Then all the users will end up in the
2922+ * same session (bad).
2923+ *
2924+ * When the client exits, the session will be destroyed for us
2925+ * automatically.
2926+ *
2927+ * We must create the session before any credentials are stored
2928+ * (including AFS pags, which happens a few lines below).
2929+ */
2930+ {
2931+ OSStatus err = 0;
2932+ SecuritySessionId sid = 0;
2933+ SessionAttributeBits sattrs = 0;
2934+
2935+ err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
2936+ if (err)
2937+ error("SessionGetInfo() failed with error %.8X",
2938+ (unsigned) err);
2939+ else
2940+ debug("Current Session ID is %.8X / Session Attributes are %.8X",
2941+ (unsigned) sid, (unsigned) sattrs);
2942+
2943+ if (inetd_flag && !(sattrs & sessionIsRoot))
2944+ debug("Running in inetd mode in a non-root session... "
2945+ "assuming inetd created the session for us.");
2946+ else {
2947+ debug("Creating new security session...");
2948+ err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
2949+ if (err)
2950+ error("SessionCreate() failed with error %.8X",
2951+ (unsigned) err);
2952+
2953+ err = SessionGetInfo(callerSecuritySession, &sid,
2954+ &sattrs);
2955+ if (err)
2956+ error("SessionGetInfo() failed with error %.8X",
2957+ (unsigned) err);
2958+ else
2959+ debug("New Session ID is %.8X / Session Attributes are %.8X",
2960+ (unsigned) sid, (unsigned) sattrs);
2961+ }
2962+ }
2963+#endif
2964+
2965 /*
2966 * We don't want to listen forever unless the other side
2967 * successfully authenticates itself. So we set up an alarm which is
2968@@ -2439,6 +2500,48 @@
2969
2970 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
2971
2972+#ifdef GSSAPI
2973+ {
2974+ char *orig;
2975+ char *gss = NULL;
2976+ char *newstr = NULL;
2977+ orig = myproposal[PROPOSAL_KEX_ALGS];
2978+
2979+ /*
2980+ * If we don't have a host key, then there's no point advertising
2981+ * the other key exchange algorithms
2982+ */
2983+
2984+ if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
2985+ orig = NULL;
2986+
2987+ if (options.gss_keyex)
2988+ gss = ssh_gssapi_server_mechanisms();
2989+ else
2990+ gss = NULL;
2991+
2992+ if (gss && orig)
2993+ xasprintf(&newstr, "%s,%s", gss, orig);
2994+ else if (gss)
2995+ newstr = gss;
2996+ else if (orig)
2997+ newstr = orig;
2998+
2999+ /*
3000+ * If we've got GSSAPI mechanisms, then we've got the 'null' host
3001+ * key alg, but we can't tell people about it unless its the only
3002+ * host key algorithm we support
3003+ */
3004+ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
3005+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
3006+
3007+ if (newstr)
3008+ myproposal[PROPOSAL_KEX_ALGS] = newstr;
3009+ else
3010+ fatal("No supported key exchange algorithms");
3011+ }
3012+#endif
3013+
3014 /* start key exchange */
3015 kex = kex_setup(myproposal);
3016 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
3017@@ -2446,6 +2549,13 @@
3018 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
3019 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
3020 kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
3021+#ifdef GSSAPI
3022+ if (options.gss_keyex) {
3023+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
3024+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
3025+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
3026+ }
3027+#endif
3028 kex->server = 1;
3029 kex->client_version_string=client_version_string;
3030 kex->server_version_string=server_version_string;
3031Index: b/sshd_config
3032===================================================================
3033--- a/sshd_config
3034+++ b/sshd_config
3035@@ -83,6 +83,8 @@
3036 # GSSAPI options
3037 #GSSAPIAuthentication no
3038 #GSSAPICleanupCredentials yes
3039+#GSSAPIStrictAcceptorCheck yes
3040+#GSSAPIKeyExchange no
3041
3042 # Set this to 'yes' to enable PAM authentication, account processing,
3043 # and session processing. If this is enabled, PAM authentication will
3044Index: b/sshd_config.5
3045===================================================================
3046--- a/sshd_config.5
3047+++ b/sshd_config.5
3048@@ -484,12 +484,40 @@
3049 The default is
3050 .Dq no .
3051 Note that this option applies to protocol version 2 only.
3052+.It Cm GSSAPIKeyExchange
3053+Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
3054+doesn't rely on ssh keys to verify host identity.
3055+The default is
3056+.Dq no .
3057+Note that this option applies to protocol version 2 only.
3058 .It Cm GSSAPICleanupCredentials
3059 Specifies whether to automatically destroy the user's credentials cache
3060 on logout.
3061 The default is
3062 .Dq yes .
3063 Note that this option applies to protocol version 2 only.
3064+.It Cm GSSAPIStrictAcceptorCheck
3065+Determines whether to be strict about the identity of the GSSAPI acceptor
3066+a client authenticates against. If
3067+.Dq yes
3068+then the client must authenticate against the
3069+.Pa host
3070+service on the current hostname. If
3071+.Dq no
3072+then the client may authenticate against any service key stored in the
3073+machine's default store. This facility is provided to assist with operation
3074+on multi homed machines.
3075+The default is
3076+.Dq yes .
3077+Note that this option applies only to protocol version 2 GSSAPI connections,
3078+and setting it to
3079+.Dq no
3080+may only work with recent Kerberos GSSAPI libraries.
3081+.It Cm GSSAPIStoreCredentialsOnRekey
3082+Controls whether the user's GSSAPI credentials should be updated following a
3083+successful connection rekeying. This option can be used to accepted renewed
3084+or updated credentials from a compatible client. The default is
3085+.Dq no .
3086 .It Cm HostbasedAuthentication
3087 Specifies whether rhosts or /etc/hosts.equiv authentication together
3088 with successful public key client host authentication is allowed