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