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