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