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