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