summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.gssapi103
-rw-r--r--Makefile.in5
-rw-r--r--auth-krb5.c17
-rw-r--r--auth.h1
-rw-r--r--auth2-gss.c50
-rw-r--r--auth2.c6
-rw-r--r--clientloop.c13
-rw-r--r--configure.ac24
-rw-r--r--gss-genr.c276
-rw-r--r--gss-serv-krb5.c84
-rw-r--r--gss-serv.c220
-rw-r--r--kex.c18
-rw-r--r--kex.h14
-rw-r--r--kexgssc.c334
-rw-r--r--kexgsss.c288
-rw-r--r--key.c2
-rw-r--r--key.h1
-rw-r--r--monitor.c108
-rw-r--r--monitor.h2
-rw-r--r--monitor_wrap.c47
-rw-r--r--monitor_wrap.h4
-rw-r--r--readconf.c35
-rw-r--r--readconf.h4
-rw-r--r--servconf.c31
-rw-r--r--servconf.h3
-rw-r--r--ssh-gss.h39
-rw-r--r--ssh_config2
-rw-r--r--ssh_config.529
-rw-r--r--sshconnect2.c118
-rw-r--r--sshd.c110
-rw-r--r--sshd_config2
-rw-r--r--sshd_config.528
32 files changed, 1959 insertions, 59 deletions
diff --git a/ChangeLog.gssapi b/ChangeLog.gssapi
new file mode 100644
index 000000000..0c3f5a44f
--- /dev/null
+++ b/ChangeLog.gssapi
@@ -0,0 +1,103 @@
120100124
2 - [ sshconnect2.c ]
3 Adapt to deal with additional element in Authmethod structure. Thanks to
4 Colin Wilson
5 - [ clientloop.c ]
6 Protect credentials updated code with suitable #ifdefs. Thanks to Colin
7 Wilson
8
920090615
10 - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c
11 sshd.c ]
12 Fix issues identified by Greg Hudson following a code review
13 Check return value of gss_indicate_mechs
14 Protect GSSAPI calls in monitor, so they can only be used if enabled
15 Check return values of bignum functions in key exchange
16 Use BN_clear_free to clear other side's DH value
17 Make ssh_gssapi_id_kex more robust
18 Only configure kex table pointers if GSSAPI is enabled
19 Don't leak mechanism list, or gss mechanism list
20 Cast data.length before printing
21 If serverkey isn't provided, use an empty string, rather than NULL
22
2320090201
24 - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h
25 ssh_config.5 sshconnet2.c ]
26 Add support for the GSSAPIClientIdentity option, which allows the user
27 to specify which GSSAPI identity to use to contact a given server
28
2920080404
30 - [ gss-serv.c ]
31 Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow
32 been omitted from a previous version of this patch. Reported by Borislav
33 Stoichkov
34
3520070317
36 - [ gss-serv-krb5.c ]
37 Remove C99ism, where new_ccname was being declared in the middle of a
38 function
39
4020061220
41 - [ servconf.c ]
42 Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and
43 documented, behaviour. Reported by Dan Watson.
44
4520060910
46 - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c
47 ssh-gss.h ]
48 add support for gss-group14-sha1 key exchange mechanisms
49 - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ]
50 Add GSSAPIStrictAcceptorCheck option to allow the disabling of
51 acceptor principal checking on multi-homed machines.
52 <Bugzilla #928>
53 - [ sshd_config ssh_config ]
54 Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample
55 configuration files
56 - [ kexgss.c kegsss.c sshconnect2.c sshd.c ]
57 Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf()
58 Limit length of error messages displayed by client
59
6020060909
61 - [ gss-genr.c gss-serv.c ]
62 move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server
63 only, where they belong
64 <Bugzilla #1225>
65
6620060829
67 - [ gss-serv-krb5.c ]
68 Fix CCAPI credentials cache name when creating KRB5CCNAME environment
69 variable
70
7120060828
72 - [ gss-genr.c ]
73 Avoid Heimdal context freeing problem
74 <Fixed upstream 20060829>
75
7620060818
77 - [ gss-genr.c ssh-gss.h sshconnect2.c ]
78 Make sure that SPENGO is disabled
79 <Bugzilla #1218 - Fixed upstream 20060818>
80
8120060421
82 - [ gssgenr.c, sshconnect2.c ]
83 a few type changes (signed versus unsigned, int versus size_t) to
84 fix compiler errors/warnings
85 (from jbasney AT ncsa.uiuc.edu)
86 - [ kexgssc.c, sshconnect2.c ]
87 fix uninitialized variable warnings
88 (from jbasney AT ncsa.uiuc.edu)
89 - [ gssgenr.c ]
90 pass oid to gss_display_status (helpful when using GSSAPI mechglue)
91 (from jbasney AT ncsa.uiuc.edu)
92 <Bugzilla #1220 >
93 - [ gss-serv-krb5.c ]
94 #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H
95 (from jbasney AT ncsa.uiuc.edu)
96 <Fixed upstream 20060304>
97 - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c
98 add client-side GssapiKeyExchange option
99 (from jbasney AT ncsa.uiuc.edu)
100 - [ sshconnect2.c ]
101 add support for GssapiTrustDns option for gssapi-with-mic
102 (from jbasney AT ncsa.uiuc.edu)
103 <gssapi-with-mic support is Bugzilla #1008>
diff --git a/Makefile.in b/Makefile.in
index c5ecd5b39..f122f4b39 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -71,7 +71,8 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
71 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ 71 atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
72 monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \ 72 monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \
73 kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \ 73 kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \
74 entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o 74 entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o \
75 kexgssc.o
75 76
76SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ 77SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
77 sshconnect.o sshconnect1.o sshconnect2.o mux.o \ 78 sshconnect.o sshconnect1.o sshconnect2.o mux.o \
@@ -85,7 +86,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
85 auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \ 86 auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \
86 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \ 87 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \
87 auth-krb5.o \ 88 auth-krb5.o \
88 auth2-gss.o gss-serv.o gss-serv-krb5.o \ 89 auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
89 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ 90 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
90 audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \ 91 audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \
91 roaming_common.o 92 roaming_common.o
diff --git a/auth-krb5.c b/auth-krb5.c
index 868288126..38164fda8 100644
--- a/auth-krb5.c
+++ b/auth-krb5.c
@@ -166,8 +166,13 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
166 166
167 len = strlen(authctxt->krb5_ticket_file) + 6; 167 len = strlen(authctxt->krb5_ticket_file) + 6;
168 authctxt->krb5_ccname = xmalloc(len); 168 authctxt->krb5_ccname = xmalloc(len);
169#ifdef USE_CCAPI
170 snprintf(authctxt->krb5_ccname, len, "API:%s",
171 authctxt->krb5_ticket_file);
172#else
169 snprintf(authctxt->krb5_ccname, len, "FILE:%s", 173 snprintf(authctxt->krb5_ccname, len, "FILE:%s",
170 authctxt->krb5_ticket_file); 174 authctxt->krb5_ticket_file);
175#endif
171 176
172#ifdef USE_PAM 177#ifdef USE_PAM
173 if (options.use_pam) 178 if (options.use_pam)
@@ -219,15 +224,22 @@ krb5_cleanup_proc(Authctxt *authctxt)
219#ifndef HEIMDAL 224#ifndef HEIMDAL
220krb5_error_code 225krb5_error_code
221ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { 226ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
222 int tmpfd, ret; 227 int ret;
223 char ccname[40]; 228 char ccname[40];
224 mode_t old_umask; 229 mode_t old_umask;
230#ifdef USE_CCAPI
231 char cctemplate[] = "API:krb5cc_%d";
232#else
233 char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
234 int tmpfd;
235#endif
225 236
226 ret = snprintf(ccname, sizeof(ccname), 237 ret = snprintf(ccname, sizeof(ccname),
227 "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); 238 cctemplate, geteuid());
228 if (ret < 0 || (size_t)ret >= sizeof(ccname)) 239 if (ret < 0 || (size_t)ret >= sizeof(ccname))
229 return ENOMEM; 240 return ENOMEM;
230 241
242#ifndef USE_CCAPI
231 old_umask = umask(0177); 243 old_umask = umask(0177);
232 tmpfd = mkstemp(ccname + strlen("FILE:")); 244 tmpfd = mkstemp(ccname + strlen("FILE:"));
233 umask(old_umask); 245 umask(old_umask);
@@ -242,6 +254,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
242 return errno; 254 return errno;
243 } 255 }
244 close(tmpfd); 256 close(tmpfd);
257#endif
245 258
246 return (krb5_cc_resolve(ctx, ccname, ccache)); 259 return (krb5_cc_resolve(ctx, ccname, ccache));
247} 260}
diff --git a/auth.h b/auth.h
index 3a70f4421..303c22d30 100644
--- a/auth.h
+++ b/auth.h
@@ -53,6 +53,7 @@ struct Authctxt {
53 int valid; /* user exists and is allowed to login */ 53 int valid; /* user exists and is allowed to login */
54 int attempt; 54 int attempt;
55 int failures; 55 int failures;
56 int server_caused_failure;
56 int force_pwchange; 57 int force_pwchange;
57 char *user; /* username sent by the client */ 58 char *user; /* username sent by the client */
58 char *service; 59 char *service;
diff --git a/auth2-gss.c b/auth2-gss.c
index 0e08d889c..a192d282f 100644
--- a/auth2-gss.c
+++ b/auth2-gss.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: auth2-gss.c,v 1.16 2007/10/29 00:52:45 dtucker Exp $ */ 1/* $OpenBSD: auth2-gss.c,v 1.16 2007/10/29 00:52:45 dtucker Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
@@ -52,6 +52,40 @@ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
52static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); 52static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
53static void input_gssapi_errtok(int, u_int32_t, void *); 53static void input_gssapi_errtok(int, u_int32_t, void *);
54 54
55/*
56 * The 'gssapi_keyex' userauth mechanism.
57 */
58static int
59userauth_gsskeyex(Authctxt *authctxt)
60{
61 int authenticated = 0;
62 Buffer b;
63 gss_buffer_desc mic, gssbuf;
64 u_int len;
65
66 mic.value = packet_get_string(&len);
67 mic.length = len;
68
69 packet_check_eom();
70
71 ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
72 "gssapi-keyex");
73
74 gssbuf.value = buffer_ptr(&b);
75 gssbuf.length = buffer_len(&b);
76
77 /* gss_kex_context is NULL with privsep, so we can't check it here */
78 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
79 &gssbuf, &mic))))
80 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
81 authctxt->pw));
82
83 buffer_free(&b);
84 xfree(mic.value);
85
86 return (authenticated);
87}
88
55/* 89/*
56 * We only support those mechanisms that we know about (ie ones that we know 90 * We only support those mechanisms that we know about (ie ones that we know
57 * how to check local user kuserok and the like) 91 * how to check local user kuserok and the like)
@@ -102,6 +136,7 @@ userauth_gssapi(Authctxt *authctxt)
102 136
103 if (!present) { 137 if (!present) {
104 xfree(doid); 138 xfree(doid);
139 authctxt->server_caused_failure = 1;
105 return (0); 140 return (0);
106 } 141 }
107 142
@@ -109,6 +144,7 @@ userauth_gssapi(Authctxt *authctxt)
109 if (ctxt != NULL) 144 if (ctxt != NULL)
110 ssh_gssapi_delete_ctx(&ctxt); 145 ssh_gssapi_delete_ctx(&ctxt);
111 xfree(doid); 146 xfree(doid);
147 authctxt->server_caused_failure = 1;
112 return (0); 148 return (0);
113 } 149 }
114 150
@@ -242,7 +278,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
242 278
243 packet_check_eom(); 279 packet_check_eom();
244 280
245 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 281 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
282 authctxt->pw));
246 283
247 authctxt->postponed = 0; 284 authctxt->postponed = 0;
248 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 285 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
@@ -277,7 +314,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
277 gssbuf.length = buffer_len(&b); 314 gssbuf.length = buffer_len(&b);
278 315
279 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) 316 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
280 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 317 authenticated =
318 PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
281 else 319 else
282 logit("GSSAPI MIC check failed"); 320 logit("GSSAPI MIC check failed");
283 321
@@ -292,6 +330,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
292 userauth_finish(authctxt, authenticated, "gssapi-with-mic"); 330 userauth_finish(authctxt, authenticated, "gssapi-with-mic");
293} 331}
294 332
333Authmethod method_gsskeyex = {
334 "gssapi-keyex",
335 userauth_gsskeyex,
336 &options.gss_authentication
337};
338
295Authmethod method_gssapi = { 339Authmethod method_gssapi = {
296 "gssapi-with-mic", 340 "gssapi-with-mic",
297 userauth_gssapi, 341 userauth_gssapi,
diff --git a/auth2.c b/auth2.c
index 5d5468559..61b5c0148 100644
--- a/auth2.c
+++ b/auth2.c
@@ -69,6 +69,7 @@ extern Authmethod method_passwd;
69extern Authmethod method_kbdint; 69extern Authmethod method_kbdint;
70extern Authmethod method_hostbased; 70extern Authmethod method_hostbased;
71#ifdef GSSAPI 71#ifdef GSSAPI
72extern Authmethod method_gsskeyex;
72extern Authmethod method_gssapi; 73extern Authmethod method_gssapi;
73#endif 74#endif
74#ifdef JPAKE 75#ifdef JPAKE
@@ -79,6 +80,7 @@ Authmethod *authmethods[] = {
79 &method_none, 80 &method_none,
80 &method_pubkey, 81 &method_pubkey,
81#ifdef GSSAPI 82#ifdef GSSAPI
83 &method_gsskeyex,
82 &method_gssapi, 84 &method_gssapi,
83#endif 85#endif
84#ifdef JPAKE 86#ifdef JPAKE
@@ -274,6 +276,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
274#endif 276#endif
275 277
276 authctxt->postponed = 0; 278 authctxt->postponed = 0;
279 authctxt->server_caused_failure = 0;
277 280
278 /* try to authenticate user */ 281 /* try to authenticate user */
279 m = authmethod_lookup(method); 282 m = authmethod_lookup(method);
@@ -346,7 +349,8 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
346 } else { 349 } else {
347 350
348 /* Allow initial try of "none" auth without failure penalty */ 351 /* Allow initial try of "none" auth without failure penalty */
349 if (authctxt->attempt > 1 || strcmp(method, "none") != 0) 352 if (!authctxt->server_caused_failure &&
353 (authctxt->attempt > 1 || strcmp(method, "none") != 0))
350 authctxt->failures++; 354 authctxt->failures++;
351 if (authctxt->failures >= options.max_authtries) { 355 if (authctxt->failures >= options.max_authtries) {
352#ifdef SSH_AUDIT_EVENTS 356#ifdef SSH_AUDIT_EVENTS
diff --git a/clientloop.c b/clientloop.c
index 9a7dc0ab0..141e0fff5 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -111,6 +111,10 @@
111#include "msg.h" 111#include "msg.h"
112#include "roaming.h" 112#include "roaming.h"
113 113
114#ifdef GSSAPI
115#include "ssh-gss.h"
116#endif
117
114/* import options */ 118/* import options */
115extern Options options; 119extern Options options;
116 120
@@ -1430,6 +1434,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
1430 /* Do channel operations unless rekeying in progress. */ 1434 /* Do channel operations unless rekeying in progress. */
1431 if (!rekeying) { 1435 if (!rekeying) {
1432 channel_after_select(readset, writeset); 1436 channel_after_select(readset, writeset);
1437
1438#ifdef GSSAPI
1439 if (options.gss_renewal_rekey &&
1440 ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) {
1441 debug("credentials updated - forcing rekey");
1442 need_rekeying = 1;
1443 }
1444#endif
1445
1433 if (need_rekeying || packet_need_rekeying()) { 1446 if (need_rekeying || packet_need_rekeying()) {
1434 debug("need rekeying"); 1447 debug("need rekeying");
1435 xxx_kex->done = 0; 1448 xxx_kex->done = 0;
diff --git a/configure.ac b/configure.ac
index ea9f1bb56..2f1dfbaff 100644
--- a/configure.ac
+++ b/configure.ac
@@ -477,6 +477,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
477 [Use tunnel device compatibility to OpenBSD]) 477 [Use tunnel device compatibility to OpenBSD])
478 AC_DEFINE(SSH_TUN_PREPEND_AF, 1, 478 AC_DEFINE(SSH_TUN_PREPEND_AF, 1,
479 [Prepend the address family to IP tunnel traffic]) 479 [Prepend the address family to IP tunnel traffic])
480 AC_MSG_CHECKING(if we have the Security Authorization Session API)
481 AC_TRY_COMPILE([#include <Security/AuthSession.h>],
482 [SessionCreate(0, 0);],
483 [ac_cv_use_security_session_api="yes"
484 AC_DEFINE(USE_SECURITY_SESSION_API, 1,
485 [platform has the Security Authorization Session API])
486 LIBS="$LIBS -framework Security"
487 AC_MSG_RESULT(yes)],
488 [ac_cv_use_security_session_api="no"
489 AC_MSG_RESULT(no)])
490 AC_MSG_CHECKING(if we have an in-memory credentials cache)
491 AC_TRY_COMPILE(
492 [#include <Kerberos/Kerberos.h>],
493 [cc_context_t c;
494 (void) cc_initialize (&c, 0, NULL, NULL);],
495 [AC_DEFINE(USE_CCAPI, 1,
496 [platform uses an in-memory credentials cache])
497 LIBS="$LIBS -framework Security"
498 AC_MSG_RESULT(yes)
499 if test "x$ac_cv_use_security_session_api" = "xno"; then
500 AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***)
501 fi],
502 [AC_MSG_RESULT(no)]
503 )
480 m4_pattern_allow(AU_IPv) 504 m4_pattern_allow(AU_IPv)
481 AC_CHECK_DECL(AU_IPv4, [], 505 AC_CHECK_DECL(AU_IPv4, [],
482 AC_DEFINE(AU_IPv4, 0, [System only supports IPv4 audit records]) 506 AC_DEFINE(AU_IPv4, 0, [System only supports IPv4 audit records])
diff --git a/gss-genr.c b/gss-genr.c
index 842f38582..f9b39cfd5 100644
--- a/gss-genr.c
+++ b/gss-genr.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-genr.c,v 1.20 2009/06/22 05:39:28 dtucker Exp $ */ 1/* $OpenBSD: gss-genr.c,v 1.20 2009/06/22 05:39:28 dtucker Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
@@ -39,12 +39,167 @@
39#include "buffer.h" 39#include "buffer.h"
40#include "log.h" 40#include "log.h"
41#include "ssh2.h" 41#include "ssh2.h"
42#include "cipher.h"
43#include "key.h"
44#include "kex.h"
45#include <openssl/evp.h>
42 46
43#include "ssh-gss.h" 47#include "ssh-gss.h"
44 48
45extern u_char *session_id2; 49extern u_char *session_id2;
46extern u_int session_id2_len; 50extern u_int session_id2_len;
47 51
52typedef struct {
53 char *encoded;
54 gss_OID oid;
55} ssh_gss_kex_mapping;
56
57/*
58 * XXX - It would be nice to find a more elegant way of handling the
59 * XXX passing of the key exchange context to the userauth routines
60 */
61
62Gssctxt *gss_kex_context = NULL;
63
64static ssh_gss_kex_mapping *gss_enc2oid = NULL;
65
66int
67ssh_gssapi_oid_table_ok() {
68 return (gss_enc2oid != NULL);
69}
70
71/*
72 * Return a list of the gss-group1-sha1 mechanisms supported by this program
73 *
74 * We test mechanisms to ensure that we can use them, to avoid starting
75 * a key exchange with a bad mechanism
76 */
77
78char *
79ssh_gssapi_client_mechanisms(const char *host, const char *client) {
80 gss_OID_set gss_supported;
81 OM_uint32 min_status;
82
83 if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
84 return NULL;
85
86 return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
87 host, client));
88}
89
90char *
91ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
92 const char *host, const char *client) {
93 Buffer buf;
94 size_t i;
95 int oidpos, enclen;
96 char *mechs, *encoded;
97 u_char digest[EVP_MAX_MD_SIZE];
98 char deroid[2];
99 const EVP_MD *evp_md = EVP_md5();
100 EVP_MD_CTX md;
101
102 if (gss_enc2oid != NULL) {
103 for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
104 xfree(gss_enc2oid[i].encoded);
105 xfree(gss_enc2oid);
106 }
107
108 gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
109 (gss_supported->count + 1));
110
111 buffer_init(&buf);
112
113 oidpos = 0;
114 for (i = 0; i < gss_supported->count; i++) {
115 if (gss_supported->elements[i].length < 128 &&
116 (*check)(NULL, &(gss_supported->elements[i]), host, client)) {
117
118 deroid[0] = SSH_GSS_OIDTYPE;
119 deroid[1] = gss_supported->elements[i].length;
120
121 EVP_DigestInit(&md, evp_md);
122 EVP_DigestUpdate(&md, deroid, 2);
123 EVP_DigestUpdate(&md,
124 gss_supported->elements[i].elements,
125 gss_supported->elements[i].length);
126 EVP_DigestFinal(&md, digest, NULL);
127
128 encoded = xmalloc(EVP_MD_size(evp_md) * 2);
129 enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
130 encoded, EVP_MD_size(evp_md) * 2);
131
132 if (oidpos != 0)
133 buffer_put_char(&buf, ',');
134
135 buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
136 sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
137 buffer_append(&buf, encoded, enclen);
138 buffer_put_char(&buf, ',');
139 buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
140 sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
141 buffer_append(&buf, encoded, enclen);
142 buffer_put_char(&buf, ',');
143 buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
144 sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
145 buffer_append(&buf, encoded, enclen);
146
147 gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
148 gss_enc2oid[oidpos].encoded = encoded;
149 oidpos++;
150 }
151 }
152 gss_enc2oid[oidpos].oid = NULL;
153 gss_enc2oid[oidpos].encoded = NULL;
154
155 buffer_put_char(&buf, '\0');
156
157 mechs = xmalloc(buffer_len(&buf));
158 buffer_get(&buf, mechs, buffer_len(&buf));
159 buffer_free(&buf);
160
161 if (strlen(mechs) == 0) {
162 xfree(mechs);
163 mechs = NULL;
164 }
165
166 return (mechs);
167}
168
169gss_OID
170ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
171 int i = 0;
172
173 switch (kex_type) {
174 case KEX_GSS_GRP1_SHA1:
175 if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
176 return GSS_C_NO_OID;
177 name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
178 break;
179 case KEX_GSS_GRP14_SHA1:
180 if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
181 return GSS_C_NO_OID;
182 name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
183 break;
184 case KEX_GSS_GEX_SHA1:
185 if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
186 return GSS_C_NO_OID;
187 name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
188 break;
189 default:
190 return GSS_C_NO_OID;
191 }
192
193 while (gss_enc2oid[i].encoded != NULL &&
194 strcmp(name, gss_enc2oid[i].encoded) != 0)
195 i++;
196
197 if (gss_enc2oid[i].oid != NULL && ctx != NULL)
198 ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
199
200 return gss_enc2oid[i].oid;
201}
202
48/* Check that the OID in a data stream matches that in the context */ 203/* Check that the OID in a data stream matches that in the context */
49int 204int
50ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) 205ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
@@ -197,7 +352,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
197 } 352 }
198 353
199 ctx->major = gss_init_sec_context(&ctx->minor, 354 ctx->major = gss_init_sec_context(&ctx->minor,
200 GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, 355 ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
201 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 356 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
202 0, NULL, recv_tok, NULL, send_tok, flags, NULL); 357 0, NULL, recv_tok, NULL, send_tok, flags, NULL);
203 358
@@ -227,8 +382,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
227} 382}
228 383
229OM_uint32 384OM_uint32
385ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
386{
387 gss_buffer_desc gssbuf;
388 gss_name_t gssname;
389 OM_uint32 status;
390 gss_OID_set oidset;
391
392 gssbuf.value = (void *) name;
393 gssbuf.length = strlen(gssbuf.value);
394
395 gss_create_empty_oid_set(&status, &oidset);
396 gss_add_oid_set_member(&status, ctx->oid, &oidset);
397
398 ctx->major = gss_import_name(&ctx->minor, &gssbuf,
399 GSS_C_NT_USER_NAME, &gssname);
400
401 if (!ctx->major)
402 ctx->major = gss_acquire_cred(&ctx->minor,
403 gssname, 0, oidset, GSS_C_INITIATE,
404 &ctx->client_creds, NULL, NULL);
405
406 gss_release_name(&status, &gssname);
407 gss_release_oid_set(&status, &oidset);
408
409 if (ctx->major)
410 ssh_gssapi_error(ctx);
411
412 return(ctx->major);
413}
414
415OM_uint32
230ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 416ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
231{ 417{
418 if (ctx == NULL)
419 return -1;
420
232 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, 421 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
233 GSS_C_QOP_DEFAULT, buffer, hash))) 422 GSS_C_QOP_DEFAULT, buffer, hash)))
234 ssh_gssapi_error(ctx); 423 ssh_gssapi_error(ctx);
@@ -236,6 +425,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
236 return (ctx->major); 425 return (ctx->major);
237} 426}
238 427
428/* Priviledged when used by server */
429OM_uint32
430ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
431{
432 if (ctx == NULL)
433 return -1;
434
435 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
436 gssbuf, gssmic, NULL);
437
438 return (ctx->major);
439}
440
239void 441void
240ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, 442ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
241 const char *context) 443 const char *context)
@@ -249,11 +451,16 @@ ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
249} 451}
250 452
251int 453int
252ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) 454ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
455 const char *client)
253{ 456{
254 gss_buffer_desc token = GSS_C_EMPTY_BUFFER; 457 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
255 OM_uint32 major, minor; 458 OM_uint32 major, minor;
256 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; 459 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
460 Gssctxt *intctx = NULL;
461
462 if (ctx == NULL)
463 ctx = &intctx;
257 464
258 /* RFC 4462 says we MUST NOT do SPNEGO */ 465 /* RFC 4462 says we MUST NOT do SPNEGO */
259 if (oid->length == spnego_oid.length && 466 if (oid->length == spnego_oid.length &&
@@ -263,6 +470,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
263 ssh_gssapi_build_ctx(ctx); 470 ssh_gssapi_build_ctx(ctx);
264 ssh_gssapi_set_oid(*ctx, oid); 471 ssh_gssapi_set_oid(*ctx, oid);
265 major = ssh_gssapi_import_name(*ctx, host); 472 major = ssh_gssapi_import_name(*ctx, host);
473
474 if (!GSS_ERROR(major) && client)
475 major = ssh_gssapi_client_identity(*ctx, client);
476
266 if (!GSS_ERROR(major)) { 477 if (!GSS_ERROR(major)) {
267 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, 478 major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
268 NULL); 479 NULL);
@@ -272,10 +483,67 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
272 GSS_C_NO_BUFFER); 483 GSS_C_NO_BUFFER);
273 } 484 }
274 485
275 if (GSS_ERROR(major)) 486 if (GSS_ERROR(major) || intctx != NULL)
276 ssh_gssapi_delete_ctx(ctx); 487 ssh_gssapi_delete_ctx(ctx);
277 488
278 return (!GSS_ERROR(major)); 489 return (!GSS_ERROR(major));
279} 490}
280 491
492int
493ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
494 static gss_name_t saved_name = GSS_C_NO_NAME;
495 static OM_uint32 saved_lifetime = 0;
496 static gss_OID saved_mech = GSS_C_NO_OID;
497 static gss_name_t name;
498 static OM_uint32 last_call = 0;
499 OM_uint32 lifetime, now, major, minor;
500 int equal;
501 gss_cred_usage_t usage = GSS_C_INITIATE;
502
503 now = time(NULL);
504
505 if (ctxt) {
506 debug("Rekey has happened - updating saved versions");
507
508 if (saved_name != GSS_C_NO_NAME)
509 gss_release_name(&minor, &saved_name);
510
511 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
512 &saved_name, &saved_lifetime, NULL, NULL);
513
514 if (!GSS_ERROR(major)) {
515 saved_mech = ctxt->oid;
516 saved_lifetime+= now;
517 } else {
518 /* Handle the error */
519 }
520 return 0;
521 }
522
523 if (now - last_call < 10)
524 return 0;
525
526 last_call = now;
527
528 if (saved_mech == GSS_C_NO_OID)
529 return 0;
530
531 major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
532 &name, &lifetime, NULL, NULL);
533 if (major == GSS_S_CREDENTIALS_EXPIRED)
534 return 0;
535 else if (GSS_ERROR(major))
536 return 0;
537
538 major = gss_compare_name(&minor, saved_name, name, &equal);
539 gss_release_name(&minor, &name);
540 if (GSS_ERROR(major))
541 return 0;
542
543 if (equal && (saved_lifetime < lifetime + now - 10))
544 return 1;
545
546 return 0;
547}
548
281#endif /* GSSAPI */ 549#endif /* GSSAPI */
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
index 5a625acb8..e7170ee41 100644
--- a/gss-serv-krb5.c
+++ b/gss-serv-krb5.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */ 1/* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
@@ -120,6 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
120 krb5_principal princ; 120 krb5_principal princ;
121 OM_uint32 maj_status, min_status; 121 OM_uint32 maj_status, min_status;
122 int len; 122 int len;
123 const char *new_ccname;
123 124
124 if (client->creds == NULL) { 125 if (client->creds == NULL) {
125 debug("No credentials stored"); 126 debug("No credentials stored");
@@ -168,11 +169,16 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
168 return; 169 return;
169 } 170 }
170 171
171 client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); 172 new_ccname = krb5_cc_get_name(krb_context, ccache);
173
172 client->store.envvar = "KRB5CCNAME"; 174 client->store.envvar = "KRB5CCNAME";
173 len = strlen(client->store.filename) + 6; 175#ifdef USE_CCAPI
174 client->store.envval = xmalloc(len); 176 xasprintf(&client->store.envval, "API:%s", new_ccname);
175 snprintf(client->store.envval, len, "FILE:%s", client->store.filename); 177 client->store.filename = NULL;
178#else
179 xasprintf(&client->store.envval, "FILE:%s", new_ccname);
180 client->store.filename = xstrdup(new_ccname);
181#endif
176 182
177#ifdef USE_PAM 183#ifdef USE_PAM
178 if (options.use_pam) 184 if (options.use_pam)
@@ -184,6 +190,71 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
184 return; 190 return;
185} 191}
186 192
193int
194ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store,
195 ssh_gssapi_client *client)
196{
197 krb5_ccache ccache = NULL;
198 krb5_principal principal = NULL;
199 char *name = NULL;
200 krb5_error_code problem;
201 OM_uint32 maj_status, min_status;
202
203 if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) {
204 logit("krb5_cc_resolve(): %.100s",
205 krb5_get_err_text(krb_context, problem));
206 return 0;
207 }
208
209 /* Find out who the principal in this cache is */
210 if ((problem = krb5_cc_get_principal(krb_context, ccache,
211 &principal))) {
212 logit("krb5_cc_get_principal(): %.100s",
213 krb5_get_err_text(krb_context, problem));
214 krb5_cc_close(krb_context, ccache);
215 return 0;
216 }
217
218 if ((problem = krb5_unparse_name(krb_context, principal, &name))) {
219 logit("krb5_unparse_name(): %.100s",
220 krb5_get_err_text(krb_context, problem));
221 krb5_free_principal(krb_context, principal);
222 krb5_cc_close(krb_context, ccache);
223 return 0;
224 }
225
226
227 if (strcmp(name,client->exportedname.value)!=0) {
228 debug("Name in local credentials cache differs. Not storing");
229 krb5_free_principal(krb_context, principal);
230 krb5_cc_close(krb_context, ccache);
231 krb5_free_unparsed_name(krb_context, name);
232 return 0;
233 }
234 krb5_free_unparsed_name(krb_context, name);
235
236 /* Name matches, so lets get on with it! */
237
238 if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) {
239 logit("krb5_cc_initialize(): %.100s",
240 krb5_get_err_text(krb_context, problem));
241 krb5_free_principal(krb_context, principal);
242 krb5_cc_close(krb_context, ccache);
243 return 0;
244 }
245
246 krb5_free_principal(krb_context, principal);
247
248 if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds,
249 ccache))) {
250 logit("gss_krb5_copy_ccache() failed. Sorry!");
251 krb5_cc_close(krb_context, ccache);
252 return 0;
253 }
254
255 return 1;
256}
257
187ssh_gssapi_mech gssapi_kerberos_mech = { 258ssh_gssapi_mech gssapi_kerberos_mech = {
188 "toWM5Slw5Ew8Mqkay+al2g==", 259 "toWM5Slw5Ew8Mqkay+al2g==",
189 "Kerberos", 260 "Kerberos",
@@ -191,7 +262,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = {
191 NULL, 262 NULL,
192 &ssh_gssapi_krb5_userok, 263 &ssh_gssapi_krb5_userok,
193 NULL, 264 NULL,
194 &ssh_gssapi_krb5_storecreds 265 &ssh_gssapi_krb5_storecreds,
266 &ssh_gssapi_krb5_updatecreds
195}; 267};
196 268
197#endif /* KRB5 */ 269#endif /* KRB5 */
diff --git a/gss-serv.c b/gss-serv.c
index 2ec7ea19c..365e48d88 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */ 1/* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
@@ -45,15 +45,20 @@
45#include "channels.h" 45#include "channels.h"
46#include "session.h" 46#include "session.h"
47#include "misc.h" 47#include "misc.h"
48#include "servconf.h"
49#include "uidswap.h"
48 50
49#include "ssh-gss.h" 51#include "ssh-gss.h"
52#include "monitor_wrap.h"
53
54extern ServerOptions options;
50 55
51static ssh_gssapi_client gssapi_client = 56static ssh_gssapi_client gssapi_client =
52 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, 57 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
53 GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}}; 58 GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL}, 0, 0};
54 59
55ssh_gssapi_mech gssapi_null_mech = 60ssh_gssapi_mech gssapi_null_mech =
56 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; 61 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
57 62
58#ifdef KRB5 63#ifdef KRB5
59extern ssh_gssapi_mech gssapi_kerberos_mech; 64extern ssh_gssapi_mech gssapi_kerberos_mech;
@@ -81,25 +86,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
81 char lname[MAXHOSTNAMELEN]; 86 char lname[MAXHOSTNAMELEN];
82 gss_OID_set oidset; 87 gss_OID_set oidset;
83 88
84 gss_create_empty_oid_set(&status, &oidset); 89 if (options.gss_strict_acceptor) {
85 gss_add_oid_set_member(&status, ctx->oid, &oidset); 90 gss_create_empty_oid_set(&status, &oidset);
91 gss_add_oid_set_member(&status, ctx->oid, &oidset);
86 92
87 if (gethostname(lname, MAXHOSTNAMELEN)) { 93 if (gethostname(lname, MAXHOSTNAMELEN)) {
88 gss_release_oid_set(&status, &oidset); 94 gss_release_oid_set(&status, &oidset);
89 return (-1); 95 return (-1);
90 } 96 }
97
98 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
99 gss_release_oid_set(&status, &oidset);
100 return (ctx->major);
101 }
102
103 if ((ctx->major = gss_acquire_cred(&ctx->minor,
104 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds,
105 NULL, NULL)))
106 ssh_gssapi_error(ctx);
91 107
92 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
93 gss_release_oid_set(&status, &oidset); 108 gss_release_oid_set(&status, &oidset);
94 return (ctx->major); 109 return (ctx->major);
110 } else {
111 ctx->name = GSS_C_NO_NAME;
112 ctx->creds = GSS_C_NO_CREDENTIAL;
95 } 113 }
96 114 return GSS_S_COMPLETE;
97 if ((ctx->major = gss_acquire_cred(&ctx->minor,
98 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
99 ssh_gssapi_error(ctx);
100
101 gss_release_oid_set(&status, &oidset);
102 return (ctx->major);
103} 115}
104 116
105/* Privileged */ 117/* Privileged */
@@ -114,6 +126,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
114} 126}
115 127
116/* Unprivileged */ 128/* Unprivileged */
129char *
130ssh_gssapi_server_mechanisms() {
131 gss_OID_set supported;
132
133 ssh_gssapi_supported_oids(&supported);
134 return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
135 NULL, NULL));
136}
137
138/* Unprivileged */
139int
140ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
141 const char *dummy) {
142 Gssctxt *ctx = NULL;
143 int res;
144
145 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
146 ssh_gssapi_delete_ctx(&ctx);
147
148 return (res);
149}
150
151/* Unprivileged */
117void 152void
118ssh_gssapi_supported_oids(gss_OID_set *oidset) 153ssh_gssapi_supported_oids(gss_OID_set *oidset)
119{ 154{
@@ -123,7 +158,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
123 gss_OID_set supported; 158 gss_OID_set supported;
124 159
125 gss_create_empty_oid_set(&min_status, oidset); 160 gss_create_empty_oid_set(&min_status, oidset);
126 gss_indicate_mechs(&min_status, &supported); 161
162 if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
163 return;
127 164
128 while (supported_mechs[i]->name != NULL) { 165 while (supported_mechs[i]->name != NULL) {
129 if (GSS_ERROR(gss_test_oid_set_member(&min_status, 166 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
@@ -247,8 +284,48 @@ OM_uint32
247ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 284ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
248{ 285{
249 int i = 0; 286 int i = 0;
287 int equal = 0;
288 gss_name_t new_name = GSS_C_NO_NAME;
289 gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
290
291 if (options.gss_store_rekey && client->used && ctx->client_creds) {
292 if (client->mech->oid.length != ctx->oid->length ||
293 (memcmp(client->mech->oid.elements,
294 ctx->oid->elements, ctx->oid->length) !=0)) {
295 debug("Rekeyed credentials have different mechanism");
296 return GSS_S_COMPLETE;
297 }
298
299 if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
300 ctx->client_creds, ctx->oid, &new_name,
301 NULL, NULL, NULL))) {
302 ssh_gssapi_error(ctx);
303 return (ctx->major);
304 }
305
306 ctx->major = gss_compare_name(&ctx->minor, client->name,
307 new_name, &equal);
250 308
251 gss_buffer_desc ename; 309 if (GSS_ERROR(ctx->major)) {
310 ssh_gssapi_error(ctx);
311 return (ctx->major);
312 }
313
314 if (!equal) {
315 debug("Rekeyed credentials have different name");
316 return GSS_S_COMPLETE;
317 }
318
319 debug("Marking rekeyed credentials for export");
320
321 gss_release_name(&ctx->minor, &client->name);
322 gss_release_cred(&ctx->minor, &client->creds);
323 client->name = new_name;
324 client->creds = ctx->client_creds;
325 ctx->client_creds = GSS_C_NO_CREDENTIAL;
326 client->updated = 1;
327 return GSS_S_COMPLETE;
328 }
252 329
253 client->mech = NULL; 330 client->mech = NULL;
254 331
@@ -263,6 +340,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
263 if (client->mech == NULL) 340 if (client->mech == NULL)
264 return GSS_S_FAILURE; 341 return GSS_S_FAILURE;
265 342
343 if (ctx->client_creds &&
344 (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
345 ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
346 ssh_gssapi_error(ctx);
347 return (ctx->major);
348 }
349
266 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, 350 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
267 &client->displayname, NULL))) { 351 &client->displayname, NULL))) {
268 ssh_gssapi_error(ctx); 352 ssh_gssapi_error(ctx);
@@ -280,6 +364,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
280 return (ctx->major); 364 return (ctx->major);
281 } 365 }
282 366
367 gss_release_buffer(&ctx->minor, &ename);
368
283 /* We can't copy this structure, so we just move the pointer to it */ 369 /* We can't copy this structure, so we just move the pointer to it */
284 client->creds = ctx->client_creds; 370 client->creds = ctx->client_creds;
285 ctx->client_creds = GSS_C_NO_CREDENTIAL; 371 ctx->client_creds = GSS_C_NO_CREDENTIAL;
@@ -327,7 +413,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
327 413
328/* Privileged */ 414/* Privileged */
329int 415int
330ssh_gssapi_userok(char *user) 416ssh_gssapi_userok(char *user, struct passwd *pw)
331{ 417{
332 OM_uint32 lmin; 418 OM_uint32 lmin;
333 419
@@ -337,9 +423,11 @@ ssh_gssapi_userok(char *user)
337 return 0; 423 return 0;
338 } 424 }
339 if (gssapi_client.mech && gssapi_client.mech->userok) 425 if (gssapi_client.mech && gssapi_client.mech->userok)
340 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) 426 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
427 gssapi_client.used = 1;
428 gssapi_client.store.owner = pw;
341 return 1; 429 return 1;
342 else { 430 } else {
343 /* Destroy delegated credentials if userok fails */ 431 /* Destroy delegated credentials if userok fails */
344 gss_release_buffer(&lmin, &gssapi_client.displayname); 432 gss_release_buffer(&lmin, &gssapi_client.displayname);
345 gss_release_buffer(&lmin, &gssapi_client.exportedname); 433 gss_release_buffer(&lmin, &gssapi_client.exportedname);
@@ -352,14 +440,90 @@ ssh_gssapi_userok(char *user)
352 return (0); 440 return (0);
353} 441}
354 442
355/* Privileged */ 443/* These bits are only used for rekeying. The unpriviledged child is running
356OM_uint32 444 * as the user, the monitor is root.
357ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) 445 *
446 * In the child, we want to :
447 * *) Ask the monitor to store our credentials into the store we specify
448 * *) If it succeeds, maybe do a PAM update
449 */
450
451/* Stuff for PAM */
452
453#ifdef USE_PAM
454static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
455 struct pam_response **resp, void *data)
358{ 456{
359 ctx->major = gss_verify_mic(&ctx->minor, ctx->context, 457 return (PAM_CONV_ERR);
360 gssbuf, gssmic, NULL); 458}
459#endif
361 460
362 return (ctx->major); 461void
462ssh_gssapi_rekey_creds() {
463 int ok;
464 int ret;
465#ifdef USE_PAM
466 pam_handle_t *pamh = NULL;
467 struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
468 char *envstr;
469#endif
470
471 if (gssapi_client.store.filename == NULL &&
472 gssapi_client.store.envval == NULL &&
473 gssapi_client.store.envvar == NULL)
474 return;
475
476 ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
477
478 if (!ok)
479 return;
480
481 debug("Rekeyed credentials stored successfully");
482
483 /* Actually managing to play with the ssh pam stack from here will
484 * be next to impossible. In any case, we may want different options
485 * for rekeying. So, use our own :)
486 */
487#ifdef USE_PAM
488 if (!use_privsep) {
489 debug("Not even going to try and do PAM with privsep disabled");
490 return;
491 }
492
493 ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
494 &pamconv, &pamh);
495 if (ret)
496 return;
497
498 xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
499 gssapi_client.store.envval);
500
501 ret = pam_putenv(pamh, envstr);
502 if (!ret)
503 pam_setcred(pamh, PAM_REINITIALIZE_CRED);
504 pam_end(pamh, PAM_SUCCESS);
505#endif
506}
507
508int
509ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
510 int ok = 0;
511
512 /* Check we've got credentials to store */
513 if (!gssapi_client.updated)
514 return 0;
515
516 gssapi_client.updated = 0;
517
518 temporarily_use_uid(gssapi_client.store.owner);
519 if (gssapi_client.mech && gssapi_client.mech->updatecreds)
520 ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
521 else
522 debug("No update function for this mechanism");
523
524 restore_uid();
525
526 return ok;
363} 527}
364 528
365#endif 529#endif
diff --git a/kex.c b/kex.c
index f4f44f095..4c19be9a0 100644
--- a/kex.c
+++ b/kex.c
@@ -49,6 +49,10 @@
49#include "dispatch.h" 49#include "dispatch.h"
50#include "monitor.h" 50#include "monitor.h"
51 51
52#ifdef GSSAPI
53#include "ssh-gss.h"
54#endif
55
52#if OPENSSL_VERSION_NUMBER >= 0x00907000L 56#if OPENSSL_VERSION_NUMBER >= 0x00907000L
53# if defined(HAVE_EVP_SHA256) 57# if defined(HAVE_EVP_SHA256)
54# define evp_ssh_sha256 EVP_sha256 58# define evp_ssh_sha256 EVP_sha256
@@ -325,6 +329,20 @@ choose_kex(Kex *k, char *client, char *server)
325 k->kex_type = KEX_DH_GEX_SHA256; 329 k->kex_type = KEX_DH_GEX_SHA256;
326 k->evp_md = evp_ssh_sha256(); 330 k->evp_md = evp_ssh_sha256();
327#endif 331#endif
332#ifdef GSSAPI
333 } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID,
334 sizeof(KEX_GSS_GEX_SHA1_ID) - 1) == 0) {
335 k->kex_type = KEX_GSS_GEX_SHA1;
336 k->evp_md = EVP_sha1();
337 } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID,
338 sizeof(KEX_GSS_GRP1_SHA1_ID) - 1) == 0) {
339 k->kex_type = KEX_GSS_GRP1_SHA1;
340 k->evp_md = EVP_sha1();
341 } else if (strncmp(k->name, KEX_GSS_GRP14_SHA1_ID,
342 sizeof(KEX_GSS_GRP14_SHA1_ID) - 1) == 0) {
343 k->kex_type = KEX_GSS_GRP14_SHA1;
344 k->evp_md = EVP_sha1();
345#endif
328 } else 346 } else
329 fatal("bad kex alg %s", k->name); 347 fatal("bad kex alg %s", k->name);
330} 348}
diff --git a/kex.h b/kex.h
index 68c80c5a9..c3856f0bc 100644
--- a/kex.h
+++ b/kex.h
@@ -66,6 +66,9 @@ enum kex_exchange {
66 KEX_DH_GRP14_SHA1, 66 KEX_DH_GRP14_SHA1,
67 KEX_DH_GEX_SHA1, 67 KEX_DH_GEX_SHA1,
68 KEX_DH_GEX_SHA256, 68 KEX_DH_GEX_SHA256,
69 KEX_GSS_GRP1_SHA1,
70 KEX_GSS_GRP14_SHA1,
71 KEX_GSS_GEX_SHA1,
69 KEX_MAX 72 KEX_MAX
70}; 73};
71 74
@@ -121,6 +124,12 @@ struct Kex {
121 sig_atomic_t done; 124 sig_atomic_t done;
122 int flags; 125 int flags;
123 const EVP_MD *evp_md; 126 const EVP_MD *evp_md;
127#ifdef GSSAPI
128 int gss_deleg_creds;
129 int gss_trust_dns;
130 char *gss_host;
131 char *gss_client;
132#endif
124 char *client_version_string; 133 char *client_version_string;
125 char *server_version_string; 134 char *server_version_string;
126 int (*verify_host_key)(Key *); 135 int (*verify_host_key)(Key *);
@@ -143,6 +152,11 @@ void kexdh_server(Kex *);
143void kexgex_client(Kex *); 152void kexgex_client(Kex *);
144void kexgex_server(Kex *); 153void kexgex_server(Kex *);
145 154
155#ifdef GSSAPI
156void kexgss_client(Kex *);
157void kexgss_server(Kex *);
158#endif
159
146void 160void
147kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, 161kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
148 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); 162 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
diff --git a/kexgssc.c b/kexgssc.c
new file mode 100644
index 000000000..39be40531
--- /dev/null
+++ b/kexgssc.c
@@ -0,0 +1,334 @@
1/*
2 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26
27#ifdef GSSAPI
28
29#include "includes.h"
30
31#include <openssl/crypto.h>
32#include <openssl/bn.h>
33
34#include <string.h>
35
36#include "xmalloc.h"
37#include "buffer.h"
38#include "ssh2.h"
39#include "key.h"
40#include "cipher.h"
41#include "kex.h"
42#include "log.h"
43#include "packet.h"
44#include "dh.h"
45
46#include "ssh-gss.h"
47
48void
49kexgss_client(Kex *kex) {
50 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
51 gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
52 Gssctxt *ctxt;
53 OM_uint32 maj_status, min_status, ret_flags;
54 u_int klen, kout, slen = 0, hashlen, strlen;
55 DH *dh;
56 BIGNUM *dh_server_pub = NULL;
57 BIGNUM *shared_secret = NULL;
58 BIGNUM *p = NULL;
59 BIGNUM *g = NULL;
60 u_char *kbuf, *hash;
61 u_char *serverhostkey = NULL;
62 u_char *empty = "";
63 char *msg;
64 char *lang;
65 int type = 0;
66 int first = 1;
67 int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
68
69 /* Initialise our GSSAPI world */
70 ssh_gssapi_build_ctx(&ctxt);
71 if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
72 == GSS_C_NO_OID)
73 fatal("Couldn't identify host exchange");
74
75 if (ssh_gssapi_import_name(ctxt, kex->gss_host))
76 fatal("Couldn't import hostname");
77
78 if (kex->gss_client &&
79 ssh_gssapi_client_identity(ctxt, kex->gss_client))
80 fatal("Couldn't acquire client credentials");
81
82 switch (kex->kex_type) {
83 case KEX_GSS_GRP1_SHA1:
84 dh = dh_new_group1();
85 break;
86 case KEX_GSS_GRP14_SHA1:
87 dh = dh_new_group14();
88 break;
89 case KEX_GSS_GEX_SHA1:
90 debug("Doing group exchange\n");
91 nbits = dh_estimate(kex->we_need * 8);
92 packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
93 packet_put_int(min);
94 packet_put_int(nbits);
95 packet_put_int(max);
96
97 packet_send();
98
99 packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
100
101 if ((p = BN_new()) == NULL)
102 fatal("BN_new() failed");
103 packet_get_bignum2(p);
104 if ((g = BN_new()) == NULL)
105 fatal("BN_new() failed");
106 packet_get_bignum2(g);
107 packet_check_eom();
108
109 if (BN_num_bits(p) < min || BN_num_bits(p) > max)
110 fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
111 min, BN_num_bits(p), max);
112
113 dh = dh_new_group(g, p);
114 break;
115 default:
116 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
117 }
118
119 /* Step 1 - e is dh->pub_key */
120 dh_gen_key(dh, kex->we_need * 8);
121
122 /* This is f, we initialise it now to make life easier */
123 dh_server_pub = BN_new();
124 if (dh_server_pub == NULL)
125 fatal("dh_server_pub == NULL");
126
127 token_ptr = GSS_C_NO_BUFFER;
128
129 do {
130 debug("Calling gss_init_sec_context");
131
132 maj_status = ssh_gssapi_init_ctx(ctxt,
133 kex->gss_deleg_creds, token_ptr, &send_tok,
134 &ret_flags);
135
136 if (GSS_ERROR(maj_status)) {
137 if (send_tok.length != 0) {
138 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
139 packet_put_string(send_tok.value,
140 send_tok.length);
141 }
142 fatal("gss_init_context failed");
143 }
144
145 /* If we've got an old receive buffer get rid of it */
146 if (token_ptr != GSS_C_NO_BUFFER)
147 xfree(recv_tok.value);
148
149 if (maj_status == GSS_S_COMPLETE) {
150 /* If mutual state flag is not true, kex fails */
151 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
152 fatal("Mutual authentication failed");
153
154 /* If integ avail flag is not true kex fails */
155 if (!(ret_flags & GSS_C_INTEG_FLAG))
156 fatal("Integrity check failed");
157 }
158
159 /*
160 * If we have data to send, then the last message that we
161 * received cannot have been a 'complete'.
162 */
163 if (send_tok.length != 0) {
164 if (first) {
165 packet_start(SSH2_MSG_KEXGSS_INIT);
166 packet_put_string(send_tok.value,
167 send_tok.length);
168 packet_put_bignum2(dh->pub_key);
169 first = 0;
170 } else {
171 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
172 packet_put_string(send_tok.value,
173 send_tok.length);
174 }
175 packet_send();
176 gss_release_buffer(&min_status, &send_tok);
177
178 /* If we've sent them data, they should reply */
179 do {
180 type = packet_read();
181 if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
182 debug("Received KEXGSS_HOSTKEY");
183 if (serverhostkey)
184 fatal("Server host key received more than once");
185 serverhostkey =
186 packet_get_string(&slen);
187 }
188 } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
189
190 switch (type) {
191 case SSH2_MSG_KEXGSS_CONTINUE:
192 debug("Received GSSAPI_CONTINUE");
193 if (maj_status == GSS_S_COMPLETE)
194 fatal("GSSAPI Continue received from server when complete");
195 recv_tok.value = packet_get_string(&strlen);
196 recv_tok.length = strlen;
197 break;
198 case SSH2_MSG_KEXGSS_COMPLETE:
199 debug("Received GSSAPI_COMPLETE");
200 packet_get_bignum2(dh_server_pub);
201 msg_tok.value = packet_get_string(&strlen);
202 msg_tok.length = strlen;
203
204 /* Is there a token included? */
205 if (packet_get_char()) {
206 recv_tok.value=
207 packet_get_string(&strlen);
208 recv_tok.length = strlen;
209 /* If we're already complete - protocol error */
210 if (maj_status == GSS_S_COMPLETE)
211 packet_disconnect("Protocol error: received token when complete");
212 } else {
213 /* No token included */
214 if (maj_status != GSS_S_COMPLETE)
215 packet_disconnect("Protocol error: did not receive final token");
216 }
217 break;
218 case SSH2_MSG_KEXGSS_ERROR:
219 debug("Received Error");
220 maj_status = packet_get_int();
221 min_status = packet_get_int();
222 msg = packet_get_string(NULL);
223 lang = packet_get_string(NULL);
224 fatal("GSSAPI Error: \n%.400s",msg);
225 default:
226 packet_disconnect("Protocol error: didn't expect packet type %d",
227 type);
228 }
229 token_ptr = &recv_tok;
230 } else {
231 /* No data, and not complete */
232 if (maj_status != GSS_S_COMPLETE)
233 fatal("Not complete, and no token output");
234 }
235 } while (maj_status & GSS_S_CONTINUE_NEEDED);
236
237 /*
238 * We _must_ have received a COMPLETE message in reply from the
239 * server, which will have set dh_server_pub and msg_tok
240 */
241
242 if (type != SSH2_MSG_KEXGSS_COMPLETE)
243 fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
244
245 /* Check f in range [1, p-1] */
246 if (!dh_pub_is_valid(dh, dh_server_pub))
247 packet_disconnect("bad server public DH value");
248
249 /* compute K=f^x mod p */
250 klen = DH_size(dh);
251 kbuf = xmalloc(klen);
252 kout = DH_compute_key(kbuf, dh_server_pub, dh);
253 if (kout < 0)
254 fatal("DH_compute_key: failed");
255
256 shared_secret = BN_new();
257 if (shared_secret == NULL)
258 fatal("kexgss_client: BN_new failed");
259
260 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
261 fatal("kexdh_client: BN_bin2bn failed");
262
263 memset(kbuf, 0, klen);
264 xfree(kbuf);
265
266 switch (kex->kex_type) {
267 case KEX_GSS_GRP1_SHA1:
268 case KEX_GSS_GRP14_SHA1:
269 kex_dh_hash( kex->client_version_string,
270 kex->server_version_string,
271 buffer_ptr(&kex->my), buffer_len(&kex->my),
272 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
273 (serverhostkey ? serverhostkey : empty), slen,
274 dh->pub_key, /* e */
275 dh_server_pub, /* f */
276 shared_secret, /* K */
277 &hash, &hashlen
278 );
279 break;
280 case KEX_GSS_GEX_SHA1:
281 kexgex_hash(
282 kex->evp_md,
283 kex->client_version_string,
284 kex->server_version_string,
285 buffer_ptr(&kex->my), buffer_len(&kex->my),
286 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
287 (serverhostkey ? serverhostkey : empty), slen,
288 min, nbits, max,
289 dh->p, dh->g,
290 dh->pub_key,
291 dh_server_pub,
292 shared_secret,
293 &hash, &hashlen
294 );
295 break;
296 default:
297 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
298 }
299
300 gssbuf.value = hash;
301 gssbuf.length = hashlen;
302
303 /* Verify that the hash matches the MIC we just got. */
304 if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
305 packet_disconnect("Hash's MIC didn't verify");
306
307 xfree(msg_tok.value);
308
309 DH_free(dh);
310 if (serverhostkey)
311 xfree(serverhostkey);
312 BN_clear_free(dh_server_pub);
313
314 /* save session id */
315 if (kex->session_id == NULL) {
316 kex->session_id_len = hashlen;
317 kex->session_id = xmalloc(kex->session_id_len);
318 memcpy(kex->session_id, hash, kex->session_id_len);
319 }
320
321 if (kex->gss_deleg_creds)
322 ssh_gssapi_credentials_updated(ctxt);
323
324 if (gss_kex_context == NULL)
325 gss_kex_context = ctxt;
326 else
327 ssh_gssapi_delete_ctx(&ctxt);
328
329 kex_derive_keys(kex, hash, hashlen, shared_secret);
330 BN_clear_free(shared_secret);
331 kex_finish(kex);
332}
333
334#endif /* GSSAPI */
diff --git a/kexgsss.c b/kexgsss.c
new file mode 100644
index 000000000..0c3eeaa63
--- /dev/null
+++ b/kexgsss.c
@@ -0,0 +1,288 @@
1/*
2 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26
27#ifdef GSSAPI
28
29#include <string.h>
30
31#include <openssl/crypto.h>
32#include <openssl/bn.h>
33
34#include "xmalloc.h"
35#include "buffer.h"
36#include "ssh2.h"
37#include "key.h"
38#include "cipher.h"
39#include "kex.h"
40#include "log.h"
41#include "packet.h"
42#include "dh.h"
43#include "ssh-gss.h"
44#include "monitor_wrap.h"
45#include "servconf.h"
46
47extern ServerOptions options;
48
49void
50kexgss_server(Kex *kex)
51{
52 OM_uint32 maj_status, min_status;
53
54 /*
55 * Some GSSAPI implementations use the input value of ret_flags (an
56 * output variable) as a means of triggering mechanism specific
57 * features. Initializing it to zero avoids inadvertently
58 * activating this non-standard behaviour.
59 */
60
61 OM_uint32 ret_flags = 0;
62 gss_buffer_desc gssbuf, recv_tok, msg_tok;
63 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
64 Gssctxt *ctxt = NULL;
65 u_int slen, klen, kout, hashlen;
66 u_char *kbuf, *hash;
67 DH *dh;
68 int min = -1, max = -1, nbits = -1;
69 BIGNUM *shared_secret = NULL;
70 BIGNUM *dh_client_pub = NULL;
71 int type = 0;
72 gss_OID oid;
73 char *mechs;
74
75 /* Initialise GSSAPI */
76
77 /* If we're rekeying, privsep means that some of the private structures
78 * in the GSSAPI code are no longer available. This kludges them back
79 * into life
80 */
81 if (!ssh_gssapi_oid_table_ok())
82 if ((mechs = ssh_gssapi_server_mechanisms()))
83 xfree(mechs);
84
85 debug2("%s: Identifying %s", __func__, kex->name);
86 oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
87 if (oid == GSS_C_NO_OID)
88 fatal("Unknown gssapi mechanism");
89
90 debug2("%s: Acquiring credentials", __func__);
91
92 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
93 fatal("Unable to acquire credentials for the server");
94
95 switch (kex->kex_type) {
96 case KEX_GSS_GRP1_SHA1:
97 dh = dh_new_group1();
98 break;
99 case KEX_GSS_GRP14_SHA1:
100 dh = dh_new_group14();
101 break;
102 case KEX_GSS_GEX_SHA1:
103 debug("Doing group exchange");
104 packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
105 min = packet_get_int();
106 nbits = packet_get_int();
107 max = packet_get_int();
108 min = MAX(DH_GRP_MIN, min);
109 max = MIN(DH_GRP_MAX, max);
110 packet_check_eom();
111 if (max < min || nbits < min || max < nbits)
112 fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
113 min, nbits, max);
114 dh = PRIVSEP(choose_dh(min, nbits, max));
115 if (dh == NULL)
116 packet_disconnect("Protocol error: no matching group found");
117
118 packet_start(SSH2_MSG_KEXGSS_GROUP);
119 packet_put_bignum2(dh->p);
120 packet_put_bignum2(dh->g);
121 packet_send();
122
123 packet_write_wait();
124 break;
125 default:
126 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
127 }
128
129 dh_gen_key(dh, kex->we_need * 8);
130
131 do {
132 debug("Wait SSH2_MSG_GSSAPI_INIT");
133 type = packet_read();
134 switch(type) {
135 case SSH2_MSG_KEXGSS_INIT:
136 if (dh_client_pub != NULL)
137 fatal("Received KEXGSS_INIT after initialising");
138 recv_tok.value = packet_get_string(&slen);
139 recv_tok.length = slen;
140
141 if ((dh_client_pub = BN_new()) == NULL)
142 fatal("dh_client_pub == NULL");
143
144 packet_get_bignum2(dh_client_pub);
145
146 /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
147 break;
148 case SSH2_MSG_KEXGSS_CONTINUE:
149 recv_tok.value = packet_get_string(&slen);
150 recv_tok.length = slen;
151 break;
152 default:
153 packet_disconnect(
154 "Protocol error: didn't expect packet type %d",
155 type);
156 }
157
158 maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
159 &send_tok, &ret_flags));
160
161 xfree(recv_tok.value);
162
163 if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
164 fatal("Zero length token output when incomplete");
165
166 if (dh_client_pub == NULL)
167 fatal("No client public key");
168
169 if (maj_status & GSS_S_CONTINUE_NEEDED) {
170 debug("Sending GSSAPI_CONTINUE");
171 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
172 packet_put_string(send_tok.value, send_tok.length);
173 packet_send();
174 gss_release_buffer(&min_status, &send_tok);
175 }
176 } while (maj_status & GSS_S_CONTINUE_NEEDED);
177
178 if (GSS_ERROR(maj_status)) {
179 if (send_tok.length > 0) {
180 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
181 packet_put_string(send_tok.value, send_tok.length);
182 packet_send();
183 }
184 fatal("accept_ctx died");
185 }
186
187 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
188 fatal("Mutual Authentication flag wasn't set");
189
190 if (!(ret_flags & GSS_C_INTEG_FLAG))
191 fatal("Integrity flag wasn't set");
192
193 if (!dh_pub_is_valid(dh, dh_client_pub))
194 packet_disconnect("bad client public DH value");
195
196 klen = DH_size(dh);
197 kbuf = xmalloc(klen);
198 kout = DH_compute_key(kbuf, dh_client_pub, dh);
199 if (kout < 0)
200 fatal("DH_compute_key: failed");
201
202 shared_secret = BN_new();
203 if (shared_secret == NULL)
204 fatal("kexgss_server: BN_new failed");
205
206 if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
207 fatal("kexgss_server: BN_bin2bn failed");
208
209 memset(kbuf, 0, klen);
210 xfree(kbuf);
211
212 switch (kex->kex_type) {
213 case KEX_GSS_GRP1_SHA1:
214 case KEX_GSS_GRP14_SHA1:
215 kex_dh_hash(
216 kex->client_version_string, kex->server_version_string,
217 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
218 buffer_ptr(&kex->my), buffer_len(&kex->my),
219 NULL, 0, /* Change this if we start sending host keys */
220 dh_client_pub, dh->pub_key, shared_secret,
221 &hash, &hashlen
222 );
223 break;
224 case KEX_GSS_GEX_SHA1:
225 kexgex_hash(
226 kex->evp_md,
227 kex->client_version_string, kex->server_version_string,
228 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
229 buffer_ptr(&kex->my), buffer_len(&kex->my),
230 NULL, 0,
231 min, nbits, max,
232 dh->p, dh->g,
233 dh_client_pub,
234 dh->pub_key,
235 shared_secret,
236 &hash, &hashlen
237 );
238 break;
239 default:
240 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
241 }
242
243 BN_clear_free(dh_client_pub);
244
245 if (kex->session_id == NULL) {
246 kex->session_id_len = hashlen;
247 kex->session_id = xmalloc(kex->session_id_len);
248 memcpy(kex->session_id, hash, kex->session_id_len);
249 }
250
251 gssbuf.value = hash;
252 gssbuf.length = hashlen;
253
254 if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
255 fatal("Couldn't get MIC");
256
257 packet_start(SSH2_MSG_KEXGSS_COMPLETE);
258 packet_put_bignum2(dh->pub_key);
259 packet_put_string(msg_tok.value,msg_tok.length);
260
261 if (send_tok.length != 0) {
262 packet_put_char(1); /* true */
263 packet_put_string(send_tok.value, send_tok.length);
264 } else {
265 packet_put_char(0); /* false */
266 }
267 packet_send();
268
269 gss_release_buffer(&min_status, &send_tok);
270 gss_release_buffer(&min_status, &msg_tok);
271
272 if (gss_kex_context == NULL)
273 gss_kex_context = ctxt;
274 else
275 ssh_gssapi_delete_ctx(&ctxt);
276
277 DH_free(dh);
278
279 kex_derive_keys(kex, hash, hashlen, shared_secret);
280 BN_clear_free(shared_secret);
281 kex_finish(kex);
282
283 /* If this was a rekey, then save out any delegated credentials we
284 * just exchanged. */
285 if (options.gss_store_rekey)
286 ssh_gssapi_rekey_creds();
287}
288#endif /* GSSAPI */
diff --git a/key.c b/key.c
index 3e17da601..327aa4e7f 100644
--- a/key.c
+++ b/key.c
@@ -764,6 +764,8 @@ key_type_from_name(char *name)
764 return KEY_RSA; 764 return KEY_RSA;
765 } else if (strcmp(name, "ssh-dss") == 0) { 765 } else if (strcmp(name, "ssh-dss") == 0) {
766 return KEY_DSA; 766 return KEY_DSA;
767 } else if (strcmp(name, "null") == 0) {
768 return KEY_NULL;
767 } 769 }
768 debug2("key_type_from_name: unknown key type '%s'", name); 770 debug2("key_type_from_name: unknown key type '%s'", name);
769 return KEY_UNSPEC; 771 return KEY_UNSPEC;
diff --git a/key.h b/key.h
index 14aac79c2..db609d326 100644
--- a/key.h
+++ b/key.h
@@ -34,6 +34,7 @@ enum types {
34 KEY_RSA1, 34 KEY_RSA1,
35 KEY_RSA, 35 KEY_RSA,
36 KEY_DSA, 36 KEY_DSA,
37 KEY_NULL,
37 KEY_UNSPEC 38 KEY_UNSPEC
38}; 39};
39enum fp_type { 40enum fp_type {
diff --git a/monitor.c b/monitor.c
index ace25c404..fd287d8c0 100644
--- a/monitor.c
+++ b/monitor.c
@@ -172,6 +172,8 @@ int mm_answer_gss_setup_ctx(int, Buffer *);
172int mm_answer_gss_accept_ctx(int, Buffer *); 172int mm_answer_gss_accept_ctx(int, Buffer *);
173int mm_answer_gss_userok(int, Buffer *); 173int mm_answer_gss_userok(int, Buffer *);
174int mm_answer_gss_checkmic(int, Buffer *); 174int mm_answer_gss_checkmic(int, Buffer *);
175int mm_answer_gss_sign(int, Buffer *);
176int mm_answer_gss_updatecreds(int, Buffer *);
175#endif 177#endif
176 178
177#ifdef SSH_AUDIT_EVENTS 179#ifdef SSH_AUDIT_EVENTS
@@ -241,6 +243,7 @@ struct mon_table mon_dispatch_proto20[] = {
241 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, 243 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
242 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, 244 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
243 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, 245 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
246 {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
244#endif 247#endif
245#ifdef JPAKE 248#ifdef JPAKE
246 {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata}, 249 {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
@@ -253,6 +256,12 @@ struct mon_table mon_dispatch_proto20[] = {
253}; 256};
254 257
255struct mon_table mon_dispatch_postauth20[] = { 258struct mon_table mon_dispatch_postauth20[] = {
259#ifdef GSSAPI
260 {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
261 {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
262 {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
263 {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds},
264#endif
256 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, 265 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
257 {MONITOR_REQ_SIGN, 0, mm_answer_sign}, 266 {MONITOR_REQ_SIGN, 0, mm_answer_sign},
258 {MONITOR_REQ_PTY, 0, mm_answer_pty}, 267 {MONITOR_REQ_PTY, 0, mm_answer_pty},
@@ -357,6 +366,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
357 /* Permit requests for moduli and signatures */ 366 /* Permit requests for moduli and signatures */
358 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 367 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
359 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 368 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
369#ifdef GSSAPI
370 /* and for the GSSAPI key exchange */
371 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
372#endif
360 } else { 373 } else {
361 mon_dispatch = mon_dispatch_proto15; 374 mon_dispatch = mon_dispatch_proto15;
362 375
@@ -443,6 +456,10 @@ monitor_child_postauth(struct monitor *pmonitor)
443 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 456 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
444 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 457 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
445 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 458 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
459#ifdef GSSAPI
460 /* and for the GSSAPI key exchange */
461 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
462#endif
446 } else { 463 } else {
447 mon_dispatch = mon_dispatch_postauth15; 464 mon_dispatch = mon_dispatch_postauth15;
448 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 465 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
@@ -1706,6 +1723,13 @@ mm_get_kex(Buffer *m)
1706 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; 1723 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
1707 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 1724 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
1708 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 1725 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
1726#ifdef GSSAPI
1727 if (options.gss_keyex) {
1728 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
1729 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
1730 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
1731 }
1732#endif
1709 kex->server = 1; 1733 kex->server = 1;
1710 kex->hostkey_type = buffer_get_int(m); 1734 kex->hostkey_type = buffer_get_int(m);
1711 kex->kex_type = buffer_get_int(m); 1735 kex->kex_type = buffer_get_int(m);
@@ -1911,6 +1935,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m)
1911 OM_uint32 major; 1935 OM_uint32 major;
1912 u_int len; 1936 u_int len;
1913 1937
1938 if (!options.gss_authentication && !options.gss_keyex)
1939 fatal("In GSSAPI monitor when GSSAPI is disabled");
1940
1914 goid.elements = buffer_get_string(m, &len); 1941 goid.elements = buffer_get_string(m, &len);
1915 goid.length = len; 1942 goid.length = len;
1916 1943
@@ -1938,6 +1965,9 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
1938 OM_uint32 flags = 0; /* GSI needs this */ 1965 OM_uint32 flags = 0; /* GSI needs this */
1939 u_int len; 1966 u_int len;
1940 1967
1968 if (!options.gss_authentication && !options.gss_keyex)
1969 fatal("In GSSAPI monitor when GSSAPI is disabled");
1970
1941 in.value = buffer_get_string(m, &len); 1971 in.value = buffer_get_string(m, &len);
1942 in.length = len; 1972 in.length = len;
1943 major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); 1973 major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
@@ -1955,6 +1985,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
1955 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); 1985 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
1956 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); 1986 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
1957 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); 1987 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
1988 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
1958 } 1989 }
1959 return (0); 1990 return (0);
1960} 1991}
@@ -1966,6 +1997,9 @@ mm_answer_gss_checkmic(int sock, Buffer *m)
1966 OM_uint32 ret; 1997 OM_uint32 ret;
1967 u_int len; 1998 u_int len;
1968 1999
2000 if (!options.gss_authentication && !options.gss_keyex)
2001 fatal("In GSSAPI monitor when GSSAPI is disabled");
2002
1969 gssbuf.value = buffer_get_string(m, &len); 2003 gssbuf.value = buffer_get_string(m, &len);
1970 gssbuf.length = len; 2004 gssbuf.length = len;
1971 mic.value = buffer_get_string(m, &len); 2005 mic.value = buffer_get_string(m, &len);
@@ -1992,7 +2026,11 @@ mm_answer_gss_userok(int sock, Buffer *m)
1992{ 2026{
1993 int authenticated; 2027 int authenticated;
1994 2028
1995 authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); 2029 if (!options.gss_authentication && !options.gss_keyex)
2030 fatal("In GSSAPI monitor when GSSAPI is disabled");
2031
2032 authenticated = authctxt->valid &&
2033 ssh_gssapi_userok(authctxt->user, authctxt->pw);
1996 2034
1997 buffer_clear(m); 2035 buffer_clear(m);
1998 buffer_put_int(m, authenticated); 2036 buffer_put_int(m, authenticated);
@@ -2005,6 +2043,74 @@ mm_answer_gss_userok(int sock, Buffer *m)
2005 /* Monitor loop will terminate if authenticated */ 2043 /* Monitor loop will terminate if authenticated */
2006 return (authenticated); 2044 return (authenticated);
2007} 2045}
2046
2047int
2048mm_answer_gss_sign(int socket, Buffer *m)
2049{
2050 gss_buffer_desc data;
2051 gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
2052 OM_uint32 major, minor;
2053 u_int len;
2054
2055 if (!options.gss_authentication && !options.gss_keyex)
2056 fatal("In GSSAPI monitor when GSSAPI is disabled");
2057
2058 data.value = buffer_get_string(m, &len);
2059 data.length = len;
2060 if (data.length != 20)
2061 fatal("%s: data length incorrect: %d", __func__,
2062 (int) data.length);
2063
2064 /* Save the session ID on the first time around */
2065 if (session_id2_len == 0) {
2066 session_id2_len = data.length;
2067 session_id2 = xmalloc(session_id2_len);
2068 memcpy(session_id2, data.value, session_id2_len);
2069 }
2070 major = ssh_gssapi_sign(gsscontext, &data, &hash);
2071
2072 xfree(data.value);
2073
2074 buffer_clear(m);
2075 buffer_put_int(m, major);
2076 buffer_put_string(m, hash.value, hash.length);
2077
2078 mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
2079
2080 gss_release_buffer(&minor, &hash);
2081
2082 /* Turn on getpwnam permissions */
2083 monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
2084
2085 /* And credential updating, for when rekeying */
2086 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1);
2087
2088 return (0);
2089}
2090
2091int
2092mm_answer_gss_updatecreds(int socket, Buffer *m) {
2093 ssh_gssapi_ccache store;
2094 int ok;
2095
2096 store.filename = buffer_get_string(m, NULL);
2097 store.envvar = buffer_get_string(m, NULL);
2098 store.envval = buffer_get_string(m, NULL);
2099
2100 ok = ssh_gssapi_update_creds(&store);
2101
2102 xfree(store.filename);
2103 xfree(store.envvar);
2104 xfree(store.envval);
2105
2106 buffer_clear(m);
2107 buffer_put_int(m, ok);
2108
2109 mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m);
2110
2111 return(0);
2112}
2113
2008#endif /* GSSAPI */ 2114#endif /* GSSAPI */
2009 2115
2010#ifdef JPAKE 2116#ifdef JPAKE
diff --git a/monitor.h b/monitor.h
index a8a2c0c19..aa38b163c 100644
--- a/monitor.h
+++ b/monitor.h
@@ -53,6 +53,8 @@ enum monitor_reqtype {
53 MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP, 53 MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
54 MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, 54 MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
55 MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, 55 MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC,
56 MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN,
57 MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS,
56 MONITOR_REQ_PAM_START, 58 MONITOR_REQ_PAM_START,
57 MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, 59 MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT,
58 MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, 60 MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX,
diff --git a/monitor_wrap.c b/monitor_wrap.c
index b8e8710f7..a737fce7a 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1248,7 +1248,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
1248} 1248}
1249 1249
1250int 1250int
1251mm_ssh_gssapi_userok(char *user) 1251mm_ssh_gssapi_userok(char *user, struct passwd *pw)
1252{ 1252{
1253 Buffer m; 1253 Buffer m;
1254 int authenticated = 0; 1254 int authenticated = 0;
@@ -1265,6 +1265,51 @@ mm_ssh_gssapi_userok(char *user)
1265 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); 1265 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
1266 return (authenticated); 1266 return (authenticated);
1267} 1267}
1268
1269OM_uint32
1270mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
1271{
1272 Buffer m;
1273 OM_uint32 major;
1274 u_int len;
1275
1276 buffer_init(&m);
1277 buffer_put_string(&m, data->value, data->length);
1278
1279 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
1280 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
1281
1282 major = buffer_get_int(&m);
1283 hash->value = buffer_get_string(&m, &len);
1284 hash->length = len;
1285
1286 buffer_free(&m);
1287
1288 return(major);
1289}
1290
1291int
1292mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store)
1293{
1294 Buffer m;
1295 int ok;
1296
1297 buffer_init(&m);
1298
1299 buffer_put_cstring(&m, store->filename ? store->filename : "");
1300 buffer_put_cstring(&m, store->envvar ? store->envvar : "");
1301 buffer_put_cstring(&m, store->envval ? store->envval : "");
1302
1303 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m);
1304 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m);
1305
1306 ok = buffer_get_int(&m);
1307
1308 buffer_free(&m);
1309
1310 return (ok);
1311}
1312
1268#endif /* GSSAPI */ 1313#endif /* GSSAPI */
1269 1314
1270#ifdef JPAKE 1315#ifdef JPAKE
diff --git a/monitor_wrap.h b/monitor_wrap.h
index de2d16f66..432953fbf 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -57,8 +57,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(Key *);
57OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 57OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
58OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, 58OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
59 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); 59 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
60int mm_ssh_gssapi_userok(char *user); 60int mm_ssh_gssapi_userok(char *user, struct passwd *);
61OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 61OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
62OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
63int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *);
62#endif 64#endif
63 65
64#ifdef USE_PAM 66#ifdef USE_PAM
diff --git a/readconf.c b/readconf.c
index 0bf5d7cb4..b6abeed06 100644
--- a/readconf.c
+++ b/readconf.c
@@ -127,6 +127,7 @@ typedef enum {
127 oClearAllForwardings, oNoHostAuthenticationForLocalhost, 127 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
128 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 128 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
129 oAddressFamily, oGssAuthentication, oGssDelegateCreds, 129 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
130 oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey,
130 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 131 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
131 oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, 132 oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
132 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, 133 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
@@ -164,10 +165,18 @@ static struct {
164 { "afstokenpassing", oUnsupported }, 165 { "afstokenpassing", oUnsupported },
165#if defined(GSSAPI) 166#if defined(GSSAPI)
166 { "gssapiauthentication", oGssAuthentication }, 167 { "gssapiauthentication", oGssAuthentication },
168 { "gssapikeyexchange", oGssKeyEx },
167 { "gssapidelegatecredentials", oGssDelegateCreds }, 169 { "gssapidelegatecredentials", oGssDelegateCreds },
170 { "gssapitrustdns", oGssTrustDns },
171 { "gssapiclientidentity", oGssClientIdentity },
172 { "gssapirenewalforcesrekey", oGssRenewalRekey },
168#else 173#else
169 { "gssapiauthentication", oUnsupported }, 174 { "gssapiauthentication", oUnsupported },
175 { "gssapikeyexchange", oUnsupported },
170 { "gssapidelegatecredentials", oUnsupported }, 176 { "gssapidelegatecredentials", oUnsupported },
177 { "gssapitrustdns", oUnsupported },
178 { "gssapiclientidentity", oUnsupported },
179 { "gssapirenewalforcesrekey", oUnsupported },
171#endif 180#endif
172 { "fallbacktorsh", oDeprecated }, 181 { "fallbacktorsh", oDeprecated },
173 { "usersh", oDeprecated }, 182 { "usersh", oDeprecated },
@@ -454,10 +463,26 @@ parse_flag:
454 intptr = &options->gss_authentication; 463 intptr = &options->gss_authentication;
455 goto parse_flag; 464 goto parse_flag;
456 465
466 case oGssKeyEx:
467 intptr = &options->gss_keyex;
468 goto parse_flag;
469
457 case oGssDelegateCreds: 470 case oGssDelegateCreds:
458 intptr = &options->gss_deleg_creds; 471 intptr = &options->gss_deleg_creds;
459 goto parse_flag; 472 goto parse_flag;
460 473
474 case oGssTrustDns:
475 intptr = &options->gss_trust_dns;
476 goto parse_flag;
477
478 case oGssClientIdentity:
479 charptr = &options->gss_client_identity;
480 goto parse_string;
481
482 case oGssRenewalRekey:
483 intptr = &options->gss_renewal_rekey;
484 goto parse_flag;
485
461 case oBatchMode: 486 case oBatchMode:
462 intptr = &options->batch_mode; 487 intptr = &options->batch_mode;
463 goto parse_flag; 488 goto parse_flag;
@@ -1013,7 +1038,11 @@ initialize_options(Options * options)
1013 options->pubkey_authentication = -1; 1038 options->pubkey_authentication = -1;
1014 options->challenge_response_authentication = -1; 1039 options->challenge_response_authentication = -1;
1015 options->gss_authentication = -1; 1040 options->gss_authentication = -1;
1041 options->gss_keyex = -1;
1016 options->gss_deleg_creds = -1; 1042 options->gss_deleg_creds = -1;
1043 options->gss_trust_dns = -1;
1044 options->gss_renewal_rekey = -1;
1045 options->gss_client_identity = NULL;
1017 options->password_authentication = -1; 1046 options->password_authentication = -1;
1018 options->kbd_interactive_authentication = -1; 1047 options->kbd_interactive_authentication = -1;
1019 options->kbd_interactive_devices = NULL; 1048 options->kbd_interactive_devices = NULL;
@@ -1105,8 +1134,14 @@ fill_default_options(Options * options)
1105 options->challenge_response_authentication = 1; 1134 options->challenge_response_authentication = 1;
1106 if (options->gss_authentication == -1) 1135 if (options->gss_authentication == -1)
1107 options->gss_authentication = 0; 1136 options->gss_authentication = 0;
1137 if (options->gss_keyex == -1)
1138 options->gss_keyex = 0;
1108 if (options->gss_deleg_creds == -1) 1139 if (options->gss_deleg_creds == -1)
1109 options->gss_deleg_creds = 0; 1140 options->gss_deleg_creds = 0;
1141 if (options->gss_trust_dns == -1)
1142 options->gss_trust_dns = 0;
1143 if (options->gss_renewal_rekey == -1)
1144 options->gss_renewal_rekey = 0;
1110 if (options->password_authentication == -1) 1145 if (options->password_authentication == -1)
1111 options->password_authentication = 1; 1146 options->password_authentication = 1;
1112 if (options->kbd_interactive_authentication == -1) 1147 if (options->kbd_interactive_authentication == -1)
diff --git a/readconf.h b/readconf.h
index 2ebfebe94..c3de71f3e 100644
--- a/readconf.h
+++ b/readconf.h
@@ -44,7 +44,11 @@ typedef struct {
44 int challenge_response_authentication; 44 int challenge_response_authentication;
45 /* Try S/Key or TIS, authentication. */ 45 /* Try S/Key or TIS, authentication. */
46 int gss_authentication; /* Try GSS authentication */ 46 int gss_authentication; /* Try GSS authentication */
47 int gss_keyex; /* Try GSS key exchange */
47 int gss_deleg_creds; /* Delegate GSS credentials */ 48 int gss_deleg_creds; /* Delegate GSS credentials */
49 int gss_trust_dns; /* Trust DNS for GSS canonicalization */
50 int gss_renewal_rekey; /* Credential renewal forces rekey */
51 char *gss_client_identity; /* Principal to initiate GSSAPI with */
48 int password_authentication; /* Try password 52 int password_authentication; /* Try password
49 * authentication. */ 53 * authentication. */
50 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ 54 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
diff --git a/servconf.c b/servconf.c
index b51b86a8f..d9726c435 100644
--- a/servconf.c
+++ b/servconf.c
@@ -92,7 +92,10 @@ initialize_server_options(ServerOptions *options)
92 options->kerberos_ticket_cleanup = -1; 92 options->kerberos_ticket_cleanup = -1;
93 options->kerberos_get_afs_token = -1; 93 options->kerberos_get_afs_token = -1;
94 options->gss_authentication=-1; 94 options->gss_authentication=-1;
95 options->gss_keyex = -1;
95 options->gss_cleanup_creds = -1; 96 options->gss_cleanup_creds = -1;
97 options->gss_strict_acceptor = -1;
98 options->gss_store_rekey = -1;
96 options->password_authentication = -1; 99 options->password_authentication = -1;
97 options->kbd_interactive_authentication = -1; 100 options->kbd_interactive_authentication = -1;
98 options->challenge_response_authentication = -1; 101 options->challenge_response_authentication = -1;
@@ -210,8 +213,14 @@ fill_default_server_options(ServerOptions *options)
210 options->kerberos_get_afs_token = 0; 213 options->kerberos_get_afs_token = 0;
211 if (options->gss_authentication == -1) 214 if (options->gss_authentication == -1)
212 options->gss_authentication = 0; 215 options->gss_authentication = 0;
216 if (options->gss_keyex == -1)
217 options->gss_keyex = 0;
213 if (options->gss_cleanup_creds == -1) 218 if (options->gss_cleanup_creds == -1)
214 options->gss_cleanup_creds = 1; 219 options->gss_cleanup_creds = 1;
220 if (options->gss_strict_acceptor == -1)
221 options->gss_strict_acceptor = 1;
222 if (options->gss_store_rekey == -1)
223 options->gss_store_rekey = 0;
215 if (options->password_authentication == -1) 224 if (options->password_authentication == -1)
216 options->password_authentication = 1; 225 options->password_authentication = 1;
217 if (options->kbd_interactive_authentication == -1) 226 if (options->kbd_interactive_authentication == -1)
@@ -302,7 +311,9 @@ typedef enum {
302 sBanner, sUseDNS, sHostbasedAuthentication, 311 sBanner, sUseDNS, sHostbasedAuthentication,
303 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 312 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
304 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, 313 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
305 sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, 314 sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
315 sGssKeyEx, sGssStoreRekey,
316 sAcceptEnv, sPermitTunnel,
306 sMatch, sPermitOpen, sForceCommand, sChrootDirectory, 317 sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
307 sUsePrivilegeSeparation, sAllowAgentForwarding, 318 sUsePrivilegeSeparation, sAllowAgentForwarding,
308 sZeroKnowledgePasswordAuthentication, 319 sZeroKnowledgePasswordAuthentication,
@@ -364,9 +375,15 @@ static struct {
364#ifdef GSSAPI 375#ifdef GSSAPI
365 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, 376 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
366 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, 377 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
378 { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
379 { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
380 { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL },
367#else 381#else
368 { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, 382 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
369 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, 383 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
384 { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
385 { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
386 { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL },
370#endif 387#endif
371 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, 388 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
372 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, 389 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
@@ -891,10 +908,22 @@ process_server_config_line(ServerOptions *options, char *line,
891 intptr = &options->gss_authentication; 908 intptr = &options->gss_authentication;
892 goto parse_flag; 909 goto parse_flag;
893 910
911 case sGssKeyEx:
912 intptr = &options->gss_keyex;
913 goto parse_flag;
914
894 case sGssCleanupCreds: 915 case sGssCleanupCreds:
895 intptr = &options->gss_cleanup_creds; 916 intptr = &options->gss_cleanup_creds;
896 goto parse_flag; 917 goto parse_flag;
897 918
919 case sGssStrictAcceptor:
920 intptr = &options->gss_strict_acceptor;
921 goto parse_flag;
922
923 case sGssStoreRekey:
924 intptr = &options->gss_store_rekey;
925 goto parse_flag;
926
898 case sPasswordAuthentication: 927 case sPasswordAuthentication:
899 intptr = &options->password_authentication; 928 intptr = &options->password_authentication;
900 goto parse_flag; 929 goto parse_flag;
diff --git a/servconf.h b/servconf.h
index b3ac7da4b..8a9fae9cf 100644
--- a/servconf.h
+++ b/servconf.h
@@ -91,7 +91,10 @@ typedef struct {
91 int kerberos_get_afs_token; /* If true, try to get AFS token if 91 int kerberos_get_afs_token; /* If true, try to get AFS token if
92 * authenticated with Kerberos. */ 92 * authenticated with Kerberos. */
93 int gss_authentication; /* If true, permit GSSAPI authentication */ 93 int gss_authentication; /* If true, permit GSSAPI authentication */
94 int gss_keyex; /* If true, permit GSSAPI key exchange */
94 int gss_cleanup_creds; /* If true, destroy cred cache on logout */ 95 int gss_cleanup_creds; /* If true, destroy cred cache on logout */
96 int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */
97 int gss_store_rekey;
95 int password_authentication; /* If true, permit password 98 int password_authentication; /* If true, permit password
96 * authentication. */ 99 * authentication. */
97 int kbd_interactive_authentication; /* If true, permit */ 100 int kbd_interactive_authentication; /* If true, permit */
diff --git a/ssh-gss.h b/ssh-gss.h
index c29a1b7e7..31d5a0835 100644
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -1,6 +1,6 @@
1/* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */ 1/* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 3 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
@@ -60,10 +60,22 @@
60 60
61#define SSH_GSS_OIDTYPE 0x06 61#define SSH_GSS_OIDTYPE 0x06
62 62
63#define SSH2_MSG_KEXGSS_INIT 30
64#define SSH2_MSG_KEXGSS_CONTINUE 31
65#define SSH2_MSG_KEXGSS_COMPLETE 32
66#define SSH2_MSG_KEXGSS_HOSTKEY 33
67#define SSH2_MSG_KEXGSS_ERROR 34
68#define SSH2_MSG_KEXGSS_GROUPREQ 40
69#define SSH2_MSG_KEXGSS_GROUP 41
70#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-"
71#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-"
72#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-"
73
63typedef struct { 74typedef struct {
64 char *filename; 75 char *filename;
65 char *envvar; 76 char *envvar;
66 char *envval; 77 char *envval;
78 struct passwd *owner;
67 void *data; 79 void *data;
68} ssh_gssapi_ccache; 80} ssh_gssapi_ccache;
69 81
@@ -71,8 +83,11 @@ typedef struct {
71 gss_buffer_desc displayname; 83 gss_buffer_desc displayname;
72 gss_buffer_desc exportedname; 84 gss_buffer_desc exportedname;
73 gss_cred_id_t creds; 85 gss_cred_id_t creds;
86 gss_name_t name;
74 struct ssh_gssapi_mech_struct *mech; 87 struct ssh_gssapi_mech_struct *mech;
75 ssh_gssapi_ccache store; 88 ssh_gssapi_ccache store;
89 int used;
90 int updated;
76} ssh_gssapi_client; 91} ssh_gssapi_client;
77 92
78typedef struct ssh_gssapi_mech_struct { 93typedef struct ssh_gssapi_mech_struct {
@@ -83,6 +98,7 @@ typedef struct ssh_gssapi_mech_struct {
83 int (*userok) (ssh_gssapi_client *, char *); 98 int (*userok) (ssh_gssapi_client *, char *);
84 int (*localname) (ssh_gssapi_client *, char **); 99 int (*localname) (ssh_gssapi_client *, char **);
85 void (*storecreds) (ssh_gssapi_client *); 100 void (*storecreds) (ssh_gssapi_client *);
101 int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *);
86} ssh_gssapi_mech; 102} ssh_gssapi_mech;
87 103
88typedef struct { 104typedef struct {
@@ -93,10 +109,11 @@ typedef struct {
93 gss_OID oid; /* client */ 109 gss_OID oid; /* client */
94 gss_cred_id_t creds; /* server */ 110 gss_cred_id_t creds; /* server */
95 gss_name_t client; /* server */ 111 gss_name_t client; /* server */
96 gss_cred_id_t client_creds; /* server */ 112 gss_cred_id_t client_creds; /* both */
97} Gssctxt; 113} Gssctxt;
98 114
99extern ssh_gssapi_mech *supported_mechs[]; 115extern ssh_gssapi_mech *supported_mechs[];
116extern Gssctxt *gss_kex_context;
100 117
101int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); 118int ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
102void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); 119void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
@@ -116,16 +133,30 @@ void ssh_gssapi_build_ctx(Gssctxt **);
116void ssh_gssapi_delete_ctx(Gssctxt **); 133void ssh_gssapi_delete_ctx(Gssctxt **);
117OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); 134OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
118void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); 135void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
119int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); 136int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *);
137OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *);
138int ssh_gssapi_credentials_updated(Gssctxt *);
120 139
121/* In the server */ 140/* In the server */
141typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *,
142 const char *);
143char *ssh_gssapi_client_mechanisms(const char *, const char *);
144char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *,
145 const char *);
146gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
147int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *,
148 const char *);
122OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 149OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
123int ssh_gssapi_userok(char *name); 150int ssh_gssapi_userok(char *name, struct passwd *);
124OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 151OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
125void ssh_gssapi_do_child(char ***, u_int *); 152void ssh_gssapi_do_child(char ***, u_int *);
126void ssh_gssapi_cleanup_creds(void); 153void ssh_gssapi_cleanup_creds(void);
127void ssh_gssapi_storecreds(void); 154void ssh_gssapi_storecreds(void);
128 155
156char *ssh_gssapi_server_mechanisms(void);
157int ssh_gssapi_oid_table_ok();
158
159int ssh_gssapi_update_creds(ssh_gssapi_ccache *store);
129#endif /* GSSAPI */ 160#endif /* GSSAPI */
130 161
131#endif /* _SSH_GSS_H */ 162#endif /* _SSH_GSS_H */
diff --git a/ssh_config b/ssh_config
index f28d59583..93a28014b 100644
--- a/ssh_config
+++ b/ssh_config
@@ -26,6 +26,8 @@
26# HostbasedAuthentication no 26# HostbasedAuthentication no
27# GSSAPIAuthentication no 27# GSSAPIAuthentication no
28# GSSAPIDelegateCredentials no 28# GSSAPIDelegateCredentials no
29# GSSAPIKeyExchange no
30# GSSAPITrustDNS no
29# BatchMode no 31# BatchMode no
30# CheckHostIP yes 32# CheckHostIP yes
31# AddressFamily any 33# AddressFamily any
diff --git a/ssh_config.5 b/ssh_config.5
index ea9a20b23..024491b90 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -478,11 +478,38 @@ Specifies whether user authentication based on GSSAPI is allowed.
478The default is 478The default is
479.Dq no . 479.Dq no .
480Note that this option applies to protocol version 2 only. 480Note that this option applies to protocol version 2 only.
481.It Cm GSSAPIKeyExchange
482Specifies whether key exchange based on GSSAPI may be used. When using
483GSSAPI key exchange the server need not have a host key.
484The default is
485.Dq no .
486Note that this option applies to protocol version 2 only.
487.It Cm GSSAPIClientIdentity
488If set, specifies the GSSAPI client identity that ssh should use when
489connecting to the server. The default is unset, which means that the default
490identity will be used.
481.It Cm GSSAPIDelegateCredentials 491.It Cm GSSAPIDelegateCredentials
482Forward (delegate) credentials to the server. 492Forward (delegate) credentials to the server.
483The default is 493The default is
484.Dq no . 494.Dq no .
485Note that this option applies to protocol version 2 only. 495Note that this option applies to protocol version 2 connections using GSSAPI.
496.It Cm GSSAPIRenewalForcesRekey
497If set to
498.Dq yes
499then renewal of the client's GSSAPI credentials will force the rekeying of the
500ssh connection. With a compatible server, this can delegate the renewed
501credentials to a session on the server.
502The default is
503.Dq no .
504.It Cm GSSAPITrustDns
505Set to
506.Dq yes to indicate that the DNS is trusted to securely canonicalize
507the name of the host being connected to. If
508.Dq no, the hostname entered on the
509command line will be passed untouched to the GSSAPI library.
510The default is
511.Dq no .
512This option only applies to protocol version 2 connections using GSSAPI.
486.It Cm HashKnownHosts 513.It Cm HashKnownHosts
487Indicates that 514Indicates that
488.Xr ssh 1 515.Xr ssh 1
diff --git a/sshconnect2.c b/sshconnect2.c
index 260c6307a..77806595c 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -105,9 +105,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
105{ 105{
106 Kex *kex; 106 Kex *kex;
107 107
108#ifdef GSSAPI
109 char *orig = NULL, *gss = NULL;
110 char *gss_host = NULL;
111#endif
112
108 xxx_host = host; 113 xxx_host = host;
109 xxx_hostaddr = hostaddr; 114 xxx_hostaddr = hostaddr;
110 115
116#ifdef GSSAPI
117 if (options.gss_keyex) {
118 /* Add the GSSAPI mechanisms currently supported on this
119 * client to the key exchange algorithm proposal */
120 orig = myproposal[PROPOSAL_KEX_ALGS];
121
122 if (options.gss_trust_dns)
123 gss_host = (char *)get_canonical_hostname(1);
124 else
125 gss_host = host;
126
127 gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
128 if (gss) {
129 debug("Offering GSSAPI proposal: %s", gss);
130 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
131 "%s,%s", gss, orig);
132 }
133 }
134#endif
135
111 if (options.ciphers == (char *)-1) { 136 if (options.ciphers == (char *)-1) {
112 logit("No valid ciphers for protocol version 2 given, using defaults."); 137 logit("No valid ciphers for protocol version 2 given, using defaults.");
113 options.ciphers = NULL; 138 options.ciphers = NULL;
@@ -135,6 +160,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
135 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 160 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
136 options.hostkeyalgorithms; 161 options.hostkeyalgorithms;
137 162
163#ifdef GSSAPI
164 /* If we've got GSSAPI algorithms, then we also support the
165 * 'null' hostkey, as a last resort */
166 if (options.gss_keyex && gss) {
167 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
168 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
169 "%s,null", orig);
170 xfree(gss);
171 }
172#endif
173
138 if (options.rekey_limit) 174 if (options.rekey_limit)
139 packet_set_rekey_limit((u_int32_t)options.rekey_limit); 175 packet_set_rekey_limit((u_int32_t)options.rekey_limit);
140 176
@@ -144,10 +180,26 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
144 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; 180 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
145 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 181 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
146 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 182 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
183#ifdef GSSAPI
184 if (options.gss_keyex) {
185 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
186 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
187 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
188 }
189#endif
147 kex->client_version_string=client_version_string; 190 kex->client_version_string=client_version_string;
148 kex->server_version_string=server_version_string; 191 kex->server_version_string=server_version_string;
149 kex->verify_host_key=&verify_host_key_callback; 192 kex->verify_host_key=&verify_host_key_callback;
150 193
194#ifdef GSSAPI
195 if (options.gss_keyex) {
196 kex->gss_deleg_creds = options.gss_deleg_creds;
197 kex->gss_trust_dns = options.gss_trust_dns;
198 kex->gss_client = options.gss_client_identity;
199 kex->gss_host = gss_host;
200 }
201#endif
202
151 xxx_kex = kex; 203 xxx_kex = kex;
152 204
153 dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 205 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -236,6 +288,7 @@ void input_gssapi_token(int type, u_int32_t, void *);
236void input_gssapi_hash(int type, u_int32_t, void *); 288void input_gssapi_hash(int type, u_int32_t, void *);
237void input_gssapi_error(int, u_int32_t, void *); 289void input_gssapi_error(int, u_int32_t, void *);
238void input_gssapi_errtok(int, u_int32_t, void *); 290void input_gssapi_errtok(int, u_int32_t, void *);
291int userauth_gsskeyex(Authctxt *authctxt);
239#endif 292#endif
240 293
241void userauth(Authctxt *, char *); 294void userauth(Authctxt *, char *);
@@ -251,6 +304,11 @@ static char *authmethods_get(void);
251 304
252Authmethod authmethods[] = { 305Authmethod authmethods[] = {
253#ifdef GSSAPI 306#ifdef GSSAPI
307 {"gssapi-keyex",
308 userauth_gsskeyex,
309 NULL,
310 &options.gss_authentication,
311 NULL},
254 {"gssapi-with-mic", 312 {"gssapi-with-mic",
255 userauth_gssapi, 313 userauth_gssapi,
256 NULL, 314 NULL,
@@ -542,19 +600,29 @@ userauth_gssapi(Authctxt *authctxt)
542 static u_int mech = 0; 600 static u_int mech = 0;
543 OM_uint32 min; 601 OM_uint32 min;
544 int ok = 0; 602 int ok = 0;
603 const char *gss_host;
604
605 if (options.gss_trust_dns)
606 gss_host = get_canonical_hostname(1);
607 else
608 gss_host = authctxt->host;
545 609
546 /* Try one GSSAPI method at a time, rather than sending them all at 610 /* Try one GSSAPI method at a time, rather than sending them all at
547 * once. */ 611 * once. */
548 612
549 if (gss_supported == NULL) 613 if (gss_supported == NULL)
550 gss_indicate_mechs(&min, &gss_supported); 614 if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
615 gss_supported = NULL;
616 return 0;
617 }
551 618
552 /* Check to see if the mechanism is usable before we offer it */ 619 /* Check to see if the mechanism is usable before we offer it */
553 while (mech < gss_supported->count && !ok) { 620 while (mech < gss_supported->count && !ok) {
554 /* My DER encoding requires length<128 */ 621 /* My DER encoding requires length<128 */
555 if (gss_supported->elements[mech].length < 128 && 622 if (gss_supported->elements[mech].length < 128 &&
556 ssh_gssapi_check_mechanism(&gssctxt, 623 ssh_gssapi_check_mechanism(&gssctxt,
557 &gss_supported->elements[mech], authctxt->host)) { 624 &gss_supported->elements[mech], gss_host,
625 options.gss_client_identity)) {
558 ok = 1; /* Mechanism works */ 626 ok = 1; /* Mechanism works */
559 } else { 627 } else {
560 mech++; 628 mech++;
@@ -651,8 +719,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
651{ 719{
652 Authctxt *authctxt = ctxt; 720 Authctxt *authctxt = ctxt;
653 Gssctxt *gssctxt; 721 Gssctxt *gssctxt;
654 int oidlen; 722 u_int oidlen;
655 char *oidv; 723 u_char *oidv;
656 724
657 if (authctxt == NULL) 725 if (authctxt == NULL)
658 fatal("input_gssapi_response: no authentication context"); 726 fatal("input_gssapi_response: no authentication context");
@@ -762,6 +830,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
762 xfree(msg); 830 xfree(msg);
763 xfree(lang); 831 xfree(lang);
764} 832}
833
834int
835userauth_gsskeyex(Authctxt *authctxt)
836{
837 Buffer b;
838 gss_buffer_desc gssbuf;
839 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
840 OM_uint32 ms;
841
842 static int attempt = 0;
843 if (attempt++ >= 1)
844 return (0);
845
846 if (gss_kex_context == NULL) {
847 debug("No valid Key exchange context");
848 return (0);
849 }
850
851 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
852 "gssapi-keyex");
853
854 gssbuf.value = buffer_ptr(&b);
855 gssbuf.length = buffer_len(&b);
856
857 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
858 buffer_free(&b);
859 return (0);
860 }
861
862 packet_start(SSH2_MSG_USERAUTH_REQUEST);
863 packet_put_cstring(authctxt->server_user);
864 packet_put_cstring(authctxt->service);
865 packet_put_cstring(authctxt->method->name);
866 packet_put_string(mic.value, mic.length);
867 packet_send();
868
869 buffer_free(&b);
870 gss_release_buffer(&ms, &mic);
871
872 return (1);
873}
874
765#endif /* GSSAPI */ 875#endif /* GSSAPI */
766 876
767int 877int
diff --git a/sshd.c b/sshd.c
index 13a455d1f..2b2cc81a5 100644
--- a/sshd.c
+++ b/sshd.c
@@ -120,6 +120,10 @@
120#include "roaming.h" 120#include "roaming.h"
121#include "version.h" 121#include "version.h"
122 122
123#ifdef USE_SECURITY_SESSION_API
124#include <Security/AuthSession.h>
125#endif
126
123#ifdef LIBWRAP 127#ifdef LIBWRAP
124#include <tcpd.h> 128#include <tcpd.h>
125#include <syslog.h> 129#include <syslog.h>
@@ -1531,10 +1535,13 @@ main(int ac, char **av)
1531 logit("Disabling protocol version 1. Could not load host key"); 1535 logit("Disabling protocol version 1. Could not load host key");
1532 options.protocol &= ~SSH_PROTO_1; 1536 options.protocol &= ~SSH_PROTO_1;
1533 } 1537 }
1538#ifndef GSSAPI
1539 /* The GSSAPI key exchange can run without a host key */
1534 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { 1540 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
1535 logit("Disabling protocol version 2. Could not load host key"); 1541 logit("Disabling protocol version 2. Could not load host key");
1536 options.protocol &= ~SSH_PROTO_2; 1542 options.protocol &= ~SSH_PROTO_2;
1537 } 1543 }
1544#endif
1538 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { 1545 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
1539 logit("sshd: no hostkeys available -- exiting."); 1546 logit("sshd: no hostkeys available -- exiting.");
1540 exit(1); 1547 exit(1);
@@ -1818,6 +1825,60 @@ main(int ac, char **av)
1818 /* Log the connection. */ 1825 /* Log the connection. */
1819 verbose("Connection from %.500s port %d", remote_ip, remote_port); 1826 verbose("Connection from %.500s port %d", remote_ip, remote_port);
1820 1827
1828#ifdef USE_SECURITY_SESSION_API
1829 /*
1830 * Create a new security session for use by the new user login if
1831 * the current session is the root session or we are not launched
1832 * by inetd (eg: debugging mode or server mode). We do not
1833 * necessarily need to create a session if we are launched from
1834 * inetd because Panther xinetd will create a session for us.
1835 *
1836 * The only case where this logic will fail is if there is an
1837 * inetd running in a non-root session which is not creating
1838 * new sessions for us. Then all the users will end up in the
1839 * same session (bad).
1840 *
1841 * When the client exits, the session will be destroyed for us
1842 * automatically.
1843 *
1844 * We must create the session before any credentials are stored
1845 * (including AFS pags, which happens a few lines below).
1846 */
1847 {
1848 OSStatus err = 0;
1849 SecuritySessionId sid = 0;
1850 SessionAttributeBits sattrs = 0;
1851
1852 err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
1853 if (err)
1854 error("SessionGetInfo() failed with error %.8X",
1855 (unsigned) err);
1856 else
1857 debug("Current Session ID is %.8X / Session Attributes are %.8X",
1858 (unsigned) sid, (unsigned) sattrs);
1859
1860 if (inetd_flag && !(sattrs & sessionIsRoot))
1861 debug("Running in inetd mode in a non-root session... "
1862 "assuming inetd created the session for us.");
1863 else {
1864 debug("Creating new security session...");
1865 err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
1866 if (err)
1867 error("SessionCreate() failed with error %.8X",
1868 (unsigned) err);
1869
1870 err = SessionGetInfo(callerSecuritySession, &sid,
1871 &sattrs);
1872 if (err)
1873 error("SessionGetInfo() failed with error %.8X",
1874 (unsigned) err);
1875 else
1876 debug("New Session ID is %.8X / Session Attributes are %.8X",
1877 (unsigned) sid, (unsigned) sattrs);
1878 }
1879 }
1880#endif
1881
1821 /* 1882 /*
1822 * We don't want to listen forever unless the other side 1883 * We don't want to listen forever unless the other side
1823 * successfully authenticates itself. So we set up an alarm which is 1884 * successfully authenticates itself. So we set up an alarm which is
@@ -2195,12 +2256,61 @@ do_ssh2_kex(void)
2195 2256
2196 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); 2257 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
2197 2258
2259#ifdef GSSAPI
2260 {
2261 char *orig;
2262 char *gss = NULL;
2263 char *newstr = NULL;
2264 orig = myproposal[PROPOSAL_KEX_ALGS];
2265
2266 /*
2267 * If we don't have a host key, then there's no point advertising
2268 * the other key exchange algorithms
2269 */
2270
2271 if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
2272 orig = NULL;
2273
2274 if (options.gss_keyex)
2275 gss = ssh_gssapi_server_mechanisms();
2276 else
2277 gss = NULL;
2278
2279 if (gss && orig)
2280 xasprintf(&newstr, "%s,%s", gss, orig);
2281 else if (gss)
2282 newstr = gss;
2283 else if (orig)
2284 newstr = orig;
2285
2286 /*
2287 * If we've got GSSAPI mechanisms, then we've got the 'null' host
2288 * key alg, but we can't tell people about it unless its the only
2289 * host key algorithm we support
2290 */
2291 if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
2292 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
2293
2294 if (newstr)
2295 myproposal[PROPOSAL_KEX_ALGS] = newstr;
2296 else
2297 fatal("No supported key exchange algorithms");
2298 }
2299#endif
2300
2198 /* start key exchange */ 2301 /* start key exchange */
2199 kex = kex_setup(myproposal); 2302 kex = kex_setup(myproposal);
2200 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 2303 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
2201 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; 2304 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
2202 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 2305 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
2203 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 2306 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
2307#ifdef GSSAPI
2308 if (options.gss_keyex) {
2309 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
2310 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
2311 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
2312 }
2313#endif
2204 kex->server = 1; 2314 kex->server = 1;
2205 kex->client_version_string=client_version_string; 2315 kex->client_version_string=client_version_string;
2206 kex->server_version_string=server_version_string; 2316 kex->server_version_string=server_version_string;
diff --git a/sshd_config b/sshd_config
index 1b53a0efb..e03b3b15f 100644
--- a/sshd_config
+++ b/sshd_config
@@ -73,6 +73,8 @@ Protocol 2
73# GSSAPI options 73# GSSAPI options
74#GSSAPIAuthentication no 74#GSSAPIAuthentication no
75#GSSAPICleanupCredentials yes 75#GSSAPICleanupCredentials yes
76#GSSAPIStrictAcceptorCheck yes
77#GSSAPIKeyExchange no
76 78
77# Set this to 'yes' to enable PAM authentication, account processing, 79# Set this to 'yes' to enable PAM authentication, account processing,
78# and session processing. If this is enabled, PAM authentication will 80# and session processing. If this is enabled, PAM authentication will
diff --git a/sshd_config.5 b/sshd_config.5
index 588aed56e..6c3ef6947 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -379,12 +379,40 @@ Specifies whether user authentication based on GSSAPI is allowed.
379The default is 379The default is
380.Dq no . 380.Dq no .
381Note that this option applies to protocol version 2 only. 381Note that this option applies to protocol version 2 only.
382.It Cm GSSAPIKeyExchange
383Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
384doesn't rely on ssh keys to verify host identity.
385The default is
386.Dq no .
387Note that this option applies to protocol version 2 only.
382.It Cm GSSAPICleanupCredentials 388.It Cm GSSAPICleanupCredentials
383Specifies whether to automatically destroy the user's credentials cache 389Specifies whether to automatically destroy the user's credentials cache
384on logout. 390on logout.
385The default is 391The default is
386.Dq yes . 392.Dq yes .
387Note that this option applies to protocol version 2 only. 393Note that this option applies to protocol version 2 only.
394.It Cm GSSAPIStrictAcceptorCheck
395Determines whether to be strict about the identity of the GSSAPI acceptor
396a client authenticates against. If
397.Dq yes
398then the client must authenticate against the
399.Pa host
400service on the current hostname. If
401.Dq no
402then the client may authenticate against any service key stored in the
403machine's default store. This facility is provided to assist with operation
404on multi homed machines.
405The default is
406.Dq yes .
407Note that this option applies only to protocol version 2 GSSAPI connections,
408and setting it to
409.Dq no
410may only work with recent Kerberos GSSAPI libraries.
411.It Cm GSSAPIStoreCredentialsOnRekey
412Controls whether the user's GSSAPI credentials should be updated following a
413successful connection rekeying. This option can be used to accepted renewed
414or updated credentials from a compatible client. The default is
415.Dq no .
388.It Cm HostbasedAuthentication 416.It Cm HostbasedAuthentication
389Specifies whether rhosts or /etc/hosts.equiv authentication together 417Specifies whether rhosts or /etc/hosts.equiv authentication together
390with successful public key client host authentication is allowed 418with successful public key client host authentication is allowed