summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.gssapi75
-rw-r--r--Makefile.in4
-rw-r--r--auth-krb5.c17
-rw-r--r--auth.h1
-rw-r--r--auth2-gss.c41
-rw-r--r--auth2.c3
-rw-r--r--configure.ac24
-rw-r--r--gss-genr.c170
-rw-r--r--gss-serv-krb5.c14
-rw-r--r--gss-serv.c73
-rw-r--r--kex.c18
-rw-r--r--kex.h13
-rw-r--r--kexgssc.c319
-rw-r--r--kexgsss.c271
-rw-r--r--key.c2
-rw-r--r--key.h1
-rw-r--r--monitor.c59
-rw-r--r--monitor.h1
-rw-r--r--monitor_wrap.c23
-rw-r--r--monitor_wrap.h1
-rw-r--r--readconf.c20
-rw-r--r--readconf.h2
-rw-r--r--servconf.c22
-rw-r--r--servconf.h2
-rw-r--r--ssh-gss.h19
-rw-r--r--ssh_config2
-rw-r--r--ssh_config.517
-rw-r--r--sshconnect2.c105
-rw-r--r--sshd.c108
-rw-r--r--sshd_config2
-rw-r--r--sshd_config.523
31 files changed, 1414 insertions, 38 deletions
diff --git a/ChangeLog.gssapi b/ChangeLog.gssapi
new file mode 100644
index 000000000..5c110d0d8
--- /dev/null
+++ b/ChangeLog.gssapi
@@ -0,0 +1,75 @@
120080404
2 - [ gss-serv.c ]
3 Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow
4 been omitted from a previous version of this patch. Reported by Borislav
5 Stoichkov
6
720070317
8 - [ gss-serv-krb5.c ]
9 Remove C99ism, where new_ccname was being declared in the middle of a
10 function
11
1220061220
13 - [ servconf.c ]
14 Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and
15 documented, behaviour. Reported by Dan Watson.
16
1720060910
18 - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c
19 ssh-gss.h ]
20 add support for gss-group14-sha1 key exchange mechanisms
21 - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ]
22 Add GSSAPIStrictAcceptorCheck option to allow the disabling of
23 acceptor principal checking on multi-homed machines.
24 <Bugzilla #928>
25 - [ sshd_config ssh_config ]
26 Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample
27 configuration files
28 - [ kexgss.c kegsss.c sshconnect2.c sshd.c ]
29 Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf()
30 Limit length of error messages displayed by client
31
3220060909
33 - [ gss-genr.c gss-serv.c ]
34 move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server
35 only, where they belong
36 <Bugzilla #1225>
37
3820060829
39 - [ gss-serv-krb5.c ]
40 Fix CCAPI credentials cache name when creating KRB5CCNAME environment
41 variable
42
4320060828
44 - [ gss-genr.c ]
45 Avoid Heimdal context freeing problem
46 <Fixed upstream 20060829>
47
4820060818
49 - [ gss-genr.c ssh-gss.h sshconnect2.c ]
50 Make sure that SPENGO is disabled
51 <Bugzilla #1218 - Fixed upstream 20060818>
52
5320060421
54 - [ gssgenr.c, sshconnect2.c ]
55 a few type changes (signed versus unsigned, int versus size_t) to
56 fix compiler errors/warnings
57 (from jbasney AT ncsa.uiuc.edu)
58 - [ kexgssc.c, sshconnect2.c ]
59 fix uninitialized variable warnings
60 (from jbasney AT ncsa.uiuc.edu)
61 - [ gssgenr.c ]
62 pass oid to gss_display_status (helpful when using GSSAPI mechglue)
63 (from jbasney AT ncsa.uiuc.edu)
64 <Bugzilla #1220 >
65 - [ gss-serv-krb5.c ]
66 #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H
67 (from jbasney AT ncsa.uiuc.edu)
68 <Fixed upstream 20060304>
69 - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c
70 add client-side GssapiKeyExchange option
71 (from jbasney AT ncsa.uiuc.edu)
72 - [ sshconnect2.c ]
73 add support for GssapiTrustDns option for gssapi-with-mic
74 (from jbasney AT ncsa.uiuc.edu)
75 <gssapi-with-mic support is Bugzilla #1008>
diff --git a/Makefile.in b/Makefile.in
index c1b7ab5a6..a81693d91 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -71,7 +71,7 @@ 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 74 entropy.o scard-opensc.o gss-genr.o umac.o kexgssc.o
75 75
76SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ 76SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
77 sshconnect.o sshconnect1.o sshconnect2.o mux.o 77 sshconnect.o sshconnect1.o sshconnect2.o mux.o
@@ -84,7 +84,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
84 auth2-none.o auth2-passwd.o auth2-pubkey.o \ 84 auth2-none.o auth2-passwd.o auth2-pubkey.o \
85 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \ 85 monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \
86 auth-krb5.o \ 86 auth-krb5.o \
87 auth2-gss.o gss-serv.o gss-serv-krb5.o \ 87 auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o\
88 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ 88 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
89 audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o 89 audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o
90 90
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 6a70f0eb6..1cba01f6e 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..9f76f59bd 100644
--- a/auth2-gss.c
+++ b/auth2-gss.c
@@ -52,6 +52,39 @@ 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
82 buffer_free(&b);
83 xfree(mic.value);
84
85 return (authenticated);
86}
87
55/* 88/*
56 * We only support those mechanisms that we know about (ie ones that we know 89 * We only support those mechanisms that we know about (ie ones that we know
57 * how to check local user kuserok and the like) 90 * how to check local user kuserok and the like)
@@ -102,6 +135,7 @@ userauth_gssapi(Authctxt *authctxt)
102 135
103 if (!present) { 136 if (!present) {
104 xfree(doid); 137 xfree(doid);
138 authctxt->server_caused_failure = 1;
105 return (0); 139 return (0);
106 } 140 }
107 141
@@ -109,6 +143,7 @@ userauth_gssapi(Authctxt *authctxt)
109 if (ctxt != NULL) 143 if (ctxt != NULL)
110 ssh_gssapi_delete_ctx(&ctxt); 144 ssh_gssapi_delete_ctx(&ctxt);
111 xfree(doid); 145 xfree(doid);
146 authctxt->server_caused_failure = 1;
112 return (0); 147 return (0);
113 } 148 }
114 149
@@ -292,6 +327,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
292 userauth_finish(authctxt, authenticated, "gssapi-with-mic"); 327 userauth_finish(authctxt, authenticated, "gssapi-with-mic");
293} 328}
294 329
330Authmethod method_gsskeyex = {
331 "gssapi-keyex",
332 userauth_gsskeyex,
333 &options.gss_authentication
334};
335
295Authmethod method_gssapi = { 336Authmethod method_gssapi = {
296 "gssapi-with-mic", 337 "gssapi-with-mic",
297 userauth_gssapi, 338 userauth_gssapi,
diff --git a/auth2.c b/auth2.c
index a835abfc6..3ee44014d 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 75
@@ -76,6 +77,7 @@ Authmethod *authmethods[] = {
76 &method_none, 77 &method_none,
77 &method_pubkey, 78 &method_pubkey,
78#ifdef GSSAPI 79#ifdef GSSAPI
80 &method_gsskeyex,
79 &method_gssapi, 81 &method_gssapi,
80#endif 82#endif
81 &method_passwd, 83 &method_passwd,
@@ -264,6 +266,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
264#endif 266#endif
265 267
266 authctxt->postponed = 0; 268 authctxt->postponed = 0;
269 authctxt->server_caused_failure = 0;
267 270
268 /* try to authenticate user */ 271 /* try to authenticate user */
269 m = authmethod_lookup(method); 272 m = authmethod_lookup(method);
diff --git a/configure.ac b/configure.ac
index fcf7e416b..ba9d9a37a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -473,6 +473,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
473 [Use tunnel device compatibility to OpenBSD]) 473 [Use tunnel device compatibility to OpenBSD])
474 AC_DEFINE(SSH_TUN_PREPEND_AF, 1, 474 AC_DEFINE(SSH_TUN_PREPEND_AF, 1,
475 [Prepend the address family to IP tunnel traffic]) 475 [Prepend the address family to IP tunnel traffic])
476 AC_MSG_CHECKING(if we have the Security Authorization Session API)
477 AC_TRY_COMPILE([#include <Security/AuthSession.h>],
478 [SessionCreate(0, 0);],
479 [ac_cv_use_security_session_api="yes"
480 AC_DEFINE(USE_SECURITY_SESSION_API, 1,
481 [platform has the Security Authorization Session API])
482 LIBS="$LIBS -framework Security"
483 AC_MSG_RESULT(yes)],
484 [ac_cv_use_security_session_api="no"
485 AC_MSG_RESULT(no)])
486 AC_MSG_CHECKING(if we have an in-memory credentials cache)
487 AC_TRY_COMPILE(
488 [#include <Kerberos/Kerberos.h>],
489 [cc_context_t c;
490 (void) cc_initialize (&c, 0, NULL, NULL);],
491 [AC_DEFINE(USE_CCAPI, 1,
492 [platform uses an in-memory credentials cache])
493 LIBS="$LIBS -framework Security"
494 AC_MSG_RESULT(yes)
495 if test "x$ac_cv_use_security_session_api" = "xno"; then
496 AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***)
497 fi],
498 [AC_MSG_RESULT(no)]
499 )
476 m4_pattern_allow(AU_IPv) 500 m4_pattern_allow(AU_IPv)
477 AC_CHECK_DECL(AU_IPv4, [], 501 AC_CHECK_DECL(AU_IPv4, [],
478 AC_DEFINE(AU_IPv4, 0, [System only supports IPv4 audit records]) 502 AC_DEFINE(AU_IPv4, 0, [System only supports IPv4 audit records])
diff --git a/gss-genr.c b/gss-genr.c
index e9190575d..822a08212 100644
--- a/gss-genr.c
+++ b/gss-genr.c
@@ -39,12 +39,160 @@
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) {
80 gss_OID_set gss_supported;
81 OM_uint32 min_status;
82
83 gss_indicate_mechs(&min_status, &gss_supported);
84
85 return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
86 host));
87}
88
89char *
90ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
91 const char *data) {
92 Buffer buf;
93 size_t i;
94 int oidpos, enclen;
95 char *mechs, *encoded;
96 u_char digest[EVP_MAX_MD_SIZE];
97 char deroid[2];
98 const EVP_MD *evp_md = EVP_md5();
99 EVP_MD_CTX md;
100
101 if (gss_enc2oid != NULL) {
102 for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
103 xfree(gss_enc2oid[i].encoded);
104 xfree(gss_enc2oid);
105 }
106
107 gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
108 (gss_supported->count + 1));
109
110 buffer_init(&buf);
111
112 oidpos = 0;
113 for (i = 0; i < gss_supported->count; i++) {
114 if (gss_supported->elements[i].length < 128 &&
115 (*check)(NULL, &(gss_supported->elements[i]), data)) {
116
117 deroid[0] = SSH_GSS_OIDTYPE;
118 deroid[1] = gss_supported->elements[i].length;
119
120 EVP_DigestInit(&md, evp_md);
121 EVP_DigestUpdate(&md, deroid, 2);
122 EVP_DigestUpdate(&md,
123 gss_supported->elements[i].elements,
124 gss_supported->elements[i].length);
125 EVP_DigestFinal(&md, digest, NULL);
126
127 encoded = xmalloc(EVP_MD_size(evp_md) * 2);
128 enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
129 encoded, EVP_MD_size(evp_md) * 2);
130
131 if (oidpos != 0)
132 buffer_put_char(&buf, ',');
133
134 buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
135 sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
136 buffer_append(&buf, encoded, enclen);
137 buffer_put_char(&buf, ',');
138 buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
139 sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
140 buffer_append(&buf, encoded, enclen);
141 buffer_put_char(&buf, ',');
142 buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
143 sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
144 buffer_append(&buf, encoded, enclen);
145
146 gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
147 gss_enc2oid[oidpos].encoded = encoded;
148 oidpos++;
149 }
150 }
151 gss_enc2oid[oidpos].oid = NULL;
152 gss_enc2oid[oidpos].encoded = NULL;
153
154 buffer_put_char(&buf, '\0');
155
156 mechs = xmalloc(buffer_len(&buf));
157 buffer_get(&buf, mechs, buffer_len(&buf));
158 buffer_free(&buf);
159
160 if (strlen(mechs) == 0) {
161 xfree(mechs);
162 mechs = NULL;
163 }
164
165 return (mechs);
166}
167
168gss_OID
169ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
170 int i = 0;
171
172 switch (kex_type) {
173 case KEX_GSS_GRP1_SHA1:
174 name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
175 break;
176 case KEX_GSS_GRP14_SHA1:
177 name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
178 break;
179 case KEX_GSS_GEX_SHA1:
180 name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
181 break;
182 default:
183 return GSS_C_NO_OID;
184 }
185
186 while (gss_enc2oid[i].encoded != NULL &&
187 strcmp(name, gss_enc2oid[i].encoded) != 0)
188 i++;
189
190 if (gss_enc2oid[i].oid != NULL && ctx != NULL)
191 ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
192
193 return gss_enc2oid[i].oid;
194}
195
48/* Check that the OID in a data stream matches that in the context */ 196/* Check that the OID in a data stream matches that in the context */
49int 197int
50ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) 198ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
@@ -229,6 +377,9 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
229OM_uint32 377OM_uint32
230ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 378ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
231{ 379{
380 if (ctx == NULL)
381 return -1;
382
232 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, 383 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
233 GSS_C_QOP_DEFAULT, buffer, hash))) 384 GSS_C_QOP_DEFAULT, buffer, hash)))
234 ssh_gssapi_error(ctx); 385 ssh_gssapi_error(ctx);
@@ -236,6 +387,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
236 return (ctx->major); 387 return (ctx->major);
237} 388}
238 389
390/* Priviledged when used by server */
391OM_uint32
392ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
393{
394 if (ctx == NULL)
395 return -1;
396
397 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
398 gssbuf, gssmic, NULL);
399
400 return (ctx->major);
401}
402
239void 403void
240ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, 404ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
241 const char *context) 405 const char *context)
@@ -254,6 +418,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
254 gss_buffer_desc token = GSS_C_EMPTY_BUFFER; 418 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
255 OM_uint32 major, minor; 419 OM_uint32 major, minor;
256 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; 420 gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
421 Gssctxt *intctx = NULL;
422
423 if (ctx == NULL)
424 ctx = &intctx;
257 425
258 /* RFC 4462 says we MUST NOT do SPNEGO */ 426 /* RFC 4462 says we MUST NOT do SPNEGO */
259 if (oid->length == spnego_oid.length && 427 if (oid->length == spnego_oid.length &&
@@ -272,7 +440,7 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
272 GSS_C_NO_BUFFER); 440 GSS_C_NO_BUFFER);
273 } 441 }
274 442
275 if (GSS_ERROR(major)) 443 if (GSS_ERROR(major) || intctx != NULL)
276 ssh_gssapi_delete_ctx(ctx); 444 ssh_gssapi_delete_ctx(ctx);
277 445
278 return (!GSS_ERROR(major)); 446 return (!GSS_ERROR(major));
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
index 5a625acb8..b400081f6 100644
--- a/gss-serv-krb5.c
+++ b/gss-serv-krb5.c
@@ -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)
diff --git a/gss-serv.c b/gss-serv.c
index 2ec7ea19c..9227b797c 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-2008 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,8 +45,12 @@
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"
48 49
49#include "ssh-gss.h" 50#include "ssh-gss.h"
51#include "monitor_wrap.h"
52
53extern ServerOptions options;
50 54
51static ssh_gssapi_client gssapi_client = 55static ssh_gssapi_client gssapi_client =
52 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, 56 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
@@ -81,25 +85,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
81 char lname[MAXHOSTNAMELEN]; 85 char lname[MAXHOSTNAMELEN];
82 gss_OID_set oidset; 86 gss_OID_set oidset;
83 87
84 gss_create_empty_oid_set(&status, &oidset); 88 if (options.gss_strict_acceptor) {
85 gss_add_oid_set_member(&status, ctx->oid, &oidset); 89 gss_create_empty_oid_set(&status, &oidset);
90 gss_add_oid_set_member(&status, ctx->oid, &oidset);
86 91
87 if (gethostname(lname, MAXHOSTNAMELEN)) { 92 if (gethostname(lname, MAXHOSTNAMELEN)) {
88 gss_release_oid_set(&status, &oidset); 93 gss_release_oid_set(&status, &oidset);
89 return (-1); 94 return (-1);
90 } 95 }
96
97 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
98 gss_release_oid_set(&status, &oidset);
99 return (ctx->major);
100 }
101
102 if ((ctx->major = gss_acquire_cred(&ctx->minor,
103 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds,
104 NULL, NULL)))
105 ssh_gssapi_error(ctx);
91 106
92 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
93 gss_release_oid_set(&status, &oidset); 107 gss_release_oid_set(&status, &oidset);
94 return (ctx->major); 108 return (ctx->major);
109 } else {
110 ctx->name = GSS_C_NO_NAME;
111 ctx->creds = GSS_C_NO_CREDENTIAL;
95 } 112 }
96 113 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} 114}
104 115
105/* Privileged */ 116/* Privileged */
@@ -114,6 +125,28 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
114} 125}
115 126
116/* Unprivileged */ 127/* Unprivileged */
128char *
129ssh_gssapi_server_mechanisms() {
130 gss_OID_set supported;
131
132 ssh_gssapi_supported_oids(&supported);
133 return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
134 NULL));
135}
136
137/* Unprivileged */
138int
139ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data) {
140 Gssctxt *ctx = NULL;
141 int res;
142
143 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
144 ssh_gssapi_delete_ctx(&ctx);
145
146 return (res);
147}
148
149/* Unprivileged */
117void 150void
118ssh_gssapi_supported_oids(gss_OID_set *oidset) 151ssh_gssapi_supported_oids(gss_OID_set *oidset)
119{ 152{
@@ -352,14 +385,4 @@ ssh_gssapi_userok(char *user)
352 return (0); 385 return (0);
353} 386}
354 387
355/* Privileged */
356OM_uint32
357ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
358{
359 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
360 gssbuf, gssmic, NULL);
361
362 return (ctx->major);
363}
364
365#endif 388#endif
diff --git a/kex.c b/kex.c
index 332fadf6e..5c8361bac 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#define KEX_COOKIE_LEN 16 56#define KEX_COOKIE_LEN 16
53 57
54#if OPENSSL_VERSION_NUMBER >= 0x00907000L 58#if OPENSSL_VERSION_NUMBER >= 0x00907000L
@@ -327,6 +331,20 @@ choose_kex(Kex *k, char *client, char *server)
327 k->kex_type = KEX_DH_GEX_SHA256; 331 k->kex_type = KEX_DH_GEX_SHA256;
328 k->evp_md = evp_ssh_sha256(); 332 k->evp_md = evp_ssh_sha256();
329#endif 333#endif
334#ifdef GSSAPI
335 } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID,
336 sizeof(KEX_GSS_GEX_SHA1_ID) - 1) == 0) {
337 k->kex_type = KEX_GSS_GEX_SHA1;
338 k->evp_md = EVP_sha1();
339 } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID,
340 sizeof(KEX_GSS_GRP1_SHA1_ID) - 1) == 0) {
341 k->kex_type = KEX_GSS_GRP1_SHA1;
342 k->evp_md = EVP_sha1();
343 } else if (strncmp(k->name, KEX_GSS_GRP14_SHA1_ID,
344 sizeof(KEX_GSS_GRP14_SHA1_ID) - 1) == 0) {
345 k->kex_type = KEX_GSS_GRP14_SHA1;
346 k->evp_md = EVP_sha1();
347#endif
330 } else 348 } else
331 fatal("bad kex alg %s", k->name); 349 fatal("bad kex alg %s", k->name);
332} 350}
diff --git a/kex.h b/kex.h
index 8e29c90e9..bd763a074 100644
--- a/kex.h
+++ b/kex.h
@@ -64,6 +64,9 @@ enum kex_exchange {
64 KEX_DH_GRP14_SHA1, 64 KEX_DH_GRP14_SHA1,
65 KEX_DH_GEX_SHA1, 65 KEX_DH_GEX_SHA1,
66 KEX_DH_GEX_SHA256, 66 KEX_DH_GEX_SHA256,
67 KEX_GSS_GRP1_SHA1,
68 KEX_GSS_GRP14_SHA1,
69 KEX_GSS_GEX_SHA1,
67 KEX_MAX 70 KEX_MAX
68}; 71};
69 72
@@ -119,6 +122,11 @@ struct Kex {
119 sig_atomic_t done; 122 sig_atomic_t done;
120 int flags; 123 int flags;
121 const EVP_MD *evp_md; 124 const EVP_MD *evp_md;
125#ifdef GSSAPI
126 int gss_deleg_creds;
127 int gss_trust_dns;
128 char *gss_host;
129#endif
122 char *client_version_string; 130 char *client_version_string;
123 char *server_version_string; 131 char *server_version_string;
124 int (*verify_host_key)(Key *); 132 int (*verify_host_key)(Key *);
@@ -141,6 +149,11 @@ void kexdh_server(Kex *);
141void kexgex_client(Kex *); 149void kexgex_client(Kex *);
142void kexgex_server(Kex *); 150void kexgex_server(Kex *);
143 151
152#ifdef GSSAPI
153void kexgss_client(Kex *);
154void kexgss_server(Kex *);
155#endif
156
144void 157void
145kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, 158kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
146 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); 159 BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
diff --git a/kexgssc.c b/kexgssc.c
new file mode 100644
index 000000000..7c4a56f45
--- /dev/null
+++ b/kexgssc.c
@@ -0,0 +1,319 @@
1/*
2 * Copyright (c) 2001-2006 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 char *msg;
63 char *lang;
64 int type = 0;
65 int first = 1;
66 int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
67
68 /* Initialise our GSSAPI world */
69 ssh_gssapi_build_ctx(&ctxt);
70 if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type)
71 == GSS_C_NO_OID)
72 fatal("Couldn't identify host exchange");
73
74 if (ssh_gssapi_import_name(ctxt, kex->gss_host))
75 fatal("Couldn't import hostname");
76
77 switch (kex->kex_type) {
78 case KEX_GSS_GRP1_SHA1:
79 dh = dh_new_group1();
80 break;
81 case KEX_GSS_GRP14_SHA1:
82 dh = dh_new_group14();
83 break;
84 case KEX_GSS_GEX_SHA1:
85 debug("Doing group exchange\n");
86 nbits = dh_estimate(kex->we_need * 8);
87 packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
88 packet_put_int(min);
89 packet_put_int(nbits);
90 packet_put_int(max);
91
92 packet_send();
93
94 packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
95
96 if ((p = BN_new()) == NULL)
97 fatal("BN_new() failed");
98 packet_get_bignum2(p);
99 if ((g = BN_new()) == NULL)
100 fatal("BN_new() failed");
101 packet_get_bignum2(g);
102 packet_check_eom();
103
104 if (BN_num_bits(p) < min || BN_num_bits(p) > max)
105 fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
106 min, BN_num_bits(p), max);
107
108 dh = dh_new_group(g, p);
109 break;
110 default:
111 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
112 }
113
114 /* Step 1 - e is dh->pub_key */
115 dh_gen_key(dh, kex->we_need * 8);
116
117 /* This is f, we initialise it now to make life easier */
118 dh_server_pub = BN_new();
119 if (dh_server_pub == NULL)
120 fatal("dh_server_pub == NULL");
121
122 token_ptr = GSS_C_NO_BUFFER;
123
124 do {
125 debug("Calling gss_init_sec_context");
126
127 maj_status = ssh_gssapi_init_ctx(ctxt,
128 kex->gss_deleg_creds, token_ptr, &send_tok,
129 &ret_flags);
130
131 if (GSS_ERROR(maj_status)) {
132 if (send_tok.length != 0) {
133 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
134 packet_put_string(send_tok.value,
135 send_tok.length);
136 }
137 fatal("gss_init_context failed");
138 }
139
140 /* If we've got an old receive buffer get rid of it */
141 if (token_ptr != GSS_C_NO_BUFFER)
142 xfree(recv_tok.value);
143
144 if (maj_status == GSS_S_COMPLETE) {
145 /* If mutual state flag is not true, kex fails */
146 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
147 fatal("Mutual authentication failed");
148
149 /* If integ avail flag is not true kex fails */
150 if (!(ret_flags & GSS_C_INTEG_FLAG))
151 fatal("Integrity check failed");
152 }
153
154 /*
155 * If we have data to send, then the last message that we
156 * received cannot have been a 'complete'.
157 */
158 if (send_tok.length != 0) {
159 if (first) {
160 packet_start(SSH2_MSG_KEXGSS_INIT);
161 packet_put_string(send_tok.value,
162 send_tok.length);
163 packet_put_bignum2(dh->pub_key);
164 first = 0;
165 } else {
166 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
167 packet_put_string(send_tok.value,
168 send_tok.length);
169 }
170 packet_send();
171 gss_release_buffer(&min_status, &send_tok);
172
173 /* If we've sent them data, they should reply */
174 do {
175 type = packet_read();
176 if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
177 debug("Received KEXGSS_HOSTKEY");
178 if (serverhostkey)
179 fatal("Server host key received more than once");
180 serverhostkey =
181 packet_get_string(&slen);
182 }
183 } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
184
185 switch (type) {
186 case SSH2_MSG_KEXGSS_CONTINUE:
187 debug("Received GSSAPI_CONTINUE");
188 if (maj_status == GSS_S_COMPLETE)
189 fatal("GSSAPI Continue received from server when complete");
190 recv_tok.value = packet_get_string(&strlen);
191 recv_tok.length = strlen;
192 break;
193 case SSH2_MSG_KEXGSS_COMPLETE:
194 debug("Received GSSAPI_COMPLETE");
195 packet_get_bignum2(dh_server_pub);
196 msg_tok.value = packet_get_string(&strlen);
197 msg_tok.length = strlen;
198
199 /* Is there a token included? */
200 if (packet_get_char()) {
201 recv_tok.value=
202 packet_get_string(&strlen);
203 recv_tok.length = strlen;
204 /* If we're already complete - protocol error */
205 if (maj_status == GSS_S_COMPLETE)
206 packet_disconnect("Protocol error: received token when complete");
207 } else {
208 /* No token included */
209 if (maj_status != GSS_S_COMPLETE)
210 packet_disconnect("Protocol error: did not receive final token");
211 }
212 break;
213 case SSH2_MSG_KEXGSS_ERROR:
214 debug("Received Error");
215 maj_status = packet_get_int();
216 min_status = packet_get_int();
217 msg = packet_get_string(NULL);
218 lang = packet_get_string(NULL);
219 fatal("GSSAPI Error: \n%.400s",msg);
220 default:
221 packet_disconnect("Protocol error: didn't expect packet type %d",
222 type);
223 }
224 token_ptr = &recv_tok;
225 } else {
226 /* No data, and not complete */
227 if (maj_status != GSS_S_COMPLETE)
228 fatal("Not complete, and no token output");
229 }
230 } while (maj_status & GSS_S_CONTINUE_NEEDED);
231
232 /*
233 * We _must_ have received a COMPLETE message in reply from the
234 * server, which will have set dh_server_pub and msg_tok
235 */
236
237 if (type != SSH2_MSG_KEXGSS_COMPLETE)
238 fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
239
240 /* Check f in range [1, p-1] */
241 if (!dh_pub_is_valid(dh, dh_server_pub))
242 packet_disconnect("bad server public DH value");
243
244 /* compute K=f^x mod p */
245 klen = DH_size(dh);
246 kbuf = xmalloc(klen);
247 kout = DH_compute_key(kbuf, dh_server_pub, dh);
248
249 shared_secret = BN_new();
250 BN_bin2bn(kbuf,kout, shared_secret);
251 memset(kbuf, 0, klen);
252 xfree(kbuf);
253
254 switch (kex->kex_type) {
255 case KEX_GSS_GRP1_SHA1:
256 case KEX_GSS_GRP14_SHA1:
257 kex_dh_hash( kex->client_version_string,
258 kex->server_version_string,
259 buffer_ptr(&kex->my), buffer_len(&kex->my),
260 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
261 serverhostkey, slen, /* server host key */
262 dh->pub_key, /* e */
263 dh_server_pub, /* f */
264 shared_secret, /* K */
265 &hash, &hashlen
266 );
267 break;
268 case KEX_GSS_GEX_SHA1:
269 kexgex_hash(
270 kex->evp_md,
271 kex->client_version_string,
272 kex->server_version_string,
273 buffer_ptr(&kex->my), buffer_len(&kex->my),
274 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
275 serverhostkey, slen,
276 min, nbits, max,
277 dh->p, dh->g,
278 dh->pub_key,
279 dh_server_pub,
280 shared_secret,
281 &hash, &hashlen
282 );
283 break;
284 default:
285 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
286 }
287
288 gssbuf.value = hash;
289 gssbuf.length = hashlen;
290
291 /* Verify that the hash matches the MIC we just got. */
292 if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
293 packet_disconnect("Hash's MIC didn't verify");
294
295 xfree(msg_tok.value);
296
297 DH_free(dh);
298 if (serverhostkey)
299 xfree(serverhostkey);
300 BN_clear_free(dh_server_pub);
301
302 /* save session id */
303 if (kex->session_id == NULL) {
304 kex->session_id_len = hashlen;
305 kex->session_id = xmalloc(kex->session_id_len);
306 memcpy(kex->session_id, hash, kex->session_id_len);
307 }
308
309 if (gss_kex_context == NULL)
310 gss_kex_context = ctxt;
311 else
312 ssh_gssapi_delete_ctx(&ctxt);
313
314 kex_derive_keys(kex, hash, hashlen, shared_secret);
315 BN_clear_free(shared_secret);
316 kex_finish(kex);
317}
318
319#endif /* GSSAPI */
diff --git a/kexgsss.c b/kexgsss.c
new file mode 100644
index 000000000..3ca23bbb2
--- /dev/null
+++ b/kexgsss.c
@@ -0,0 +1,271 @@
1/*
2 * Copyright (c) 2001-2006 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
46void
47kexgss_server(Kex *kex)
48{
49 OM_uint32 maj_status, min_status;
50
51 /*
52 * Some GSSAPI implementations use the input value of ret_flags (an
53 * output variable) as a means of triggering mechanism specific
54 * features. Initializing it to zero avoids inadvertently
55 * activating this non-standard behaviour.
56 */
57
58 OM_uint32 ret_flags = 0;
59 gss_buffer_desc gssbuf, recv_tok, msg_tok;
60 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
61 Gssctxt *ctxt = NULL;
62 u_int slen, klen, kout, hashlen;
63 u_char *kbuf, *hash;
64 DH *dh;
65 int min = -1, max = -1, nbits = -1;
66 BIGNUM *shared_secret = NULL;
67 BIGNUM *dh_client_pub = NULL;
68 int type = 0;
69 gss_OID oid;
70
71 /* Initialise GSSAPI */
72
73 /* If we're rekeying, privsep means that some of the private structures
74 * in the GSSAPI code are no longer available. This kludges them back
75 * into life
76 */
77 if (!ssh_gssapi_oid_table_ok())
78 ssh_gssapi_server_mechanisms();
79
80 debug2("%s: Identifying %s", __func__, kex->name);
81 oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type);
82 if (oid == GSS_C_NO_OID)
83 fatal("Unknown gssapi mechanism");
84
85 debug2("%s: Acquiring credentials", __func__);
86
87 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
88 fatal("Unable to acquire credentials for the server");
89
90 switch (kex->kex_type) {
91 case KEX_GSS_GRP1_SHA1:
92 dh = dh_new_group1();
93 break;
94 case KEX_GSS_GRP14_SHA1:
95 dh = dh_new_group14();
96 break;
97 case KEX_GSS_GEX_SHA1:
98 debug("Doing group exchange");
99 packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
100 min = packet_get_int();
101 nbits = packet_get_int();
102 max = packet_get_int();
103 min = MAX(DH_GRP_MIN, min);
104 max = MIN(DH_GRP_MAX, max);
105 packet_check_eom();
106 if (max < min || nbits < min || max < nbits)
107 fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
108 min, nbits, max);
109 dh = PRIVSEP(choose_dh(min, nbits, max));
110 if (dh == NULL)
111 packet_disconnect("Protocol error: no matching group found");
112
113 packet_start(SSH2_MSG_KEXGSS_GROUP);
114 packet_put_bignum2(dh->p);
115 packet_put_bignum2(dh->g);
116 packet_send();
117
118 packet_write_wait();
119 break;
120 default:
121 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
122 }
123
124 dh_gen_key(dh, kex->we_need * 8);
125
126 do {
127 debug("Wait SSH2_MSG_GSSAPI_INIT");
128 type = packet_read();
129 switch(type) {
130 case SSH2_MSG_KEXGSS_INIT:
131 if (dh_client_pub != NULL)
132 fatal("Received KEXGSS_INIT after initialising");
133 recv_tok.value = packet_get_string(&slen);
134 recv_tok.length = slen;
135
136 if ((dh_client_pub = BN_new()) == NULL)
137 fatal("dh_client_pub == NULL");
138
139 packet_get_bignum2(dh_client_pub);
140
141 /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
142 break;
143 case SSH2_MSG_KEXGSS_CONTINUE:
144 recv_tok.value = packet_get_string(&slen);
145 recv_tok.length = slen;
146 break;
147 default:
148 packet_disconnect(
149 "Protocol error: didn't expect packet type %d",
150 type);
151 }
152
153 maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
154 &send_tok, &ret_flags));
155
156 xfree(recv_tok.value);
157
158 if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
159 fatal("Zero length token output when incomplete");
160
161 if (dh_client_pub == NULL)
162 fatal("No client public key");
163
164 if (maj_status & GSS_S_CONTINUE_NEEDED) {
165 debug("Sending GSSAPI_CONTINUE");
166 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
167 packet_put_string(send_tok.value, send_tok.length);
168 packet_send();
169 gss_release_buffer(&min_status, &send_tok);
170 }
171 } while (maj_status & GSS_S_CONTINUE_NEEDED);
172
173 if (GSS_ERROR(maj_status)) {
174 if (send_tok.length > 0) {
175 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
176 packet_put_string(send_tok.value, send_tok.length);
177 packet_send();
178 }
179 fatal("accept_ctx died");
180 }
181
182 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
183 fatal("Mutual Authentication flag wasn't set");
184
185 if (!(ret_flags & GSS_C_INTEG_FLAG))
186 fatal("Integrity flag wasn't set");
187
188 if (!dh_pub_is_valid(dh, dh_client_pub))
189 packet_disconnect("bad client public DH value");
190
191 klen = DH_size(dh);
192 kbuf = xmalloc(klen);
193 kout = DH_compute_key(kbuf, dh_client_pub, dh);
194
195 shared_secret = BN_new();
196 BN_bin2bn(kbuf, kout, shared_secret);
197 memset(kbuf, 0, klen);
198 xfree(kbuf);
199
200 switch (kex->kex_type) {
201 case KEX_GSS_GRP1_SHA1:
202 case KEX_GSS_GRP14_SHA1:
203 kex_dh_hash(
204 kex->client_version_string, kex->server_version_string,
205 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
206 buffer_ptr(&kex->my), buffer_len(&kex->my),
207 NULL, 0, /* Change this if we start sending host keys */
208 dh_client_pub, dh->pub_key, shared_secret,
209 &hash, &hashlen
210 );
211 break;
212 case KEX_GSS_GEX_SHA1:
213 kexgex_hash(
214 kex->evp_md,
215 kex->client_version_string, kex->server_version_string,
216 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
217 buffer_ptr(&kex->my), buffer_len(&kex->my),
218 NULL, 0,
219 min, nbits, max,
220 dh->p, dh->g,
221 dh_client_pub,
222 dh->pub_key,
223 shared_secret,
224 &hash, &hashlen
225 );
226 break;
227 default:
228 fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
229 }
230
231 BN_free(dh_client_pub);
232
233 if (kex->session_id == NULL) {
234 kex->session_id_len = hashlen;
235 kex->session_id = xmalloc(kex->session_id_len);
236 memcpy(kex->session_id, hash, kex->session_id_len);
237 }
238
239 gssbuf.value = hash;
240 gssbuf.length = hashlen;
241
242 if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
243 fatal("Couldn't get MIC");
244
245 packet_start(SSH2_MSG_KEXGSS_COMPLETE);
246 packet_put_bignum2(dh->pub_key);
247 packet_put_string(msg_tok.value,msg_tok.length);
248
249 if (send_tok.length != 0) {
250 packet_put_char(1); /* true */
251 packet_put_string(send_tok.value, send_tok.length);
252 } else {
253 packet_put_char(0); /* false */
254 }
255 packet_send();
256
257 gss_release_buffer(&min_status, &send_tok);
258 gss_release_buffer(&min_status, &msg_tok);
259
260 if (gss_kex_context == NULL)
261 gss_kex_context = ctxt;
262 else
263 ssh_gssapi_delete_ctx(&ctxt);
264
265 DH_free(dh);
266
267 kex_derive_keys(kex, hash, hashlen, shared_secret);
268 BN_clear_free(shared_secret);
269 kex_finish(kex);
270}
271#endif /* GSSAPI */
diff --git a/key.c b/key.c
index 2ea13d27d..484b97f67 100644
--- a/key.c
+++ b/key.c
@@ -763,6 +763,8 @@ key_type_from_name(char *name)
763 return KEY_RSA; 763 return KEY_RSA;
764 } else if (strcmp(name, "ssh-dss") == 0) { 764 } else if (strcmp(name, "ssh-dss") == 0) {
765 return KEY_DSA; 765 return KEY_DSA;
766 } else if (strcmp(name, "null") == 0) {
767 return KEY_NULL;
766 } 768 }
767 debug2("key_type_from_name: unknown key type '%s'", name); 769 debug2("key_type_from_name: unknown key type '%s'", name);
768 return KEY_UNSPEC; 770 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 73cf6bc9b..ef46938c4 100644
--- a/monitor.c
+++ b/monitor.c
@@ -164,6 +164,7 @@ int mm_answer_gss_setup_ctx(int, Buffer *);
164int mm_answer_gss_accept_ctx(int, Buffer *); 164int mm_answer_gss_accept_ctx(int, Buffer *);
165int mm_answer_gss_userok(int, Buffer *); 165int mm_answer_gss_userok(int, Buffer *);
166int mm_answer_gss_checkmic(int, Buffer *); 166int mm_answer_gss_checkmic(int, Buffer *);
167int mm_answer_gss_sign(int, Buffer *);
167#endif 168#endif
168 169
169#ifdef SSH_AUDIT_EVENTS 170#ifdef SSH_AUDIT_EVENTS
@@ -233,11 +234,17 @@ struct mon_table mon_dispatch_proto20[] = {
233 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, 234 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
234 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, 235 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
235 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, 236 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
237 {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
236#endif 238#endif
237 {0, 0, NULL} 239 {0, 0, NULL}
238}; 240};
239 241
240struct mon_table mon_dispatch_postauth20[] = { 242struct mon_table mon_dispatch_postauth20[] = {
243#ifdef GSSAPI
244 {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
245 {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
246 {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
247#endif
241 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, 248 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
242 {MONITOR_REQ_SIGN, 0, mm_answer_sign}, 249 {MONITOR_REQ_SIGN, 0, mm_answer_sign},
243 {MONITOR_REQ_PTY, 0, mm_answer_pty}, 250 {MONITOR_REQ_PTY, 0, mm_answer_pty},
@@ -342,6 +349,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
342 /* Permit requests for moduli and signatures */ 349 /* Permit requests for moduli and signatures */
343 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 350 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
344 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 351 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
352#ifdef GSSAPI
353 /* and for the GSSAPI key exchange */
354 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
355#endif
345 } else { 356 } else {
346 mon_dispatch = mon_dispatch_proto15; 357 mon_dispatch = mon_dispatch_proto15;
347 358
@@ -419,6 +430,10 @@ monitor_child_postauth(struct monitor *pmonitor)
419 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 430 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
420 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 431 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
421 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 432 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
433#ifdef GSSAPI
434 /* and for the GSSAPI key exchange */
435 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
436#endif
422 } else { 437 } else {
423 mon_dispatch = mon_dispatch_postauth15; 438 mon_dispatch = mon_dispatch_postauth15;
424 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 439 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
@@ -1675,6 +1690,11 @@ mm_get_kex(Buffer *m)
1675 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; 1690 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
1676 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 1691 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
1677 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; 1692 kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
1693#ifdef GSSAPI
1694 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
1695 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
1696 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
1697#endif
1678 kex->server = 1; 1698 kex->server = 1;
1679 kex->hostkey_type = buffer_get_int(m); 1699 kex->hostkey_type = buffer_get_int(m);
1680 kex->kex_type = buffer_get_int(m); 1700 kex->kex_type = buffer_get_int(m);
@@ -1918,6 +1938,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
1918 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); 1938 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
1919 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); 1939 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
1920 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); 1940 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
1941 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
1921 } 1942 }
1922 return (0); 1943 return (0);
1923} 1944}
@@ -1968,4 +1989,42 @@ mm_answer_gss_userok(int sock, Buffer *m)
1968 /* Monitor loop will terminate if authenticated */ 1989 /* Monitor loop will terminate if authenticated */
1969 return (authenticated); 1990 return (authenticated);
1970} 1991}
1992
1993int
1994mm_answer_gss_sign(int socket, Buffer *m)
1995{
1996 gss_buffer_desc data;
1997 gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
1998 OM_uint32 major, minor;
1999 u_int len;
2000
2001 data.value = buffer_get_string(m, &len);
2002 data.length = len;
2003 if (data.length != 20)
2004 fatal("%s: data length incorrect: %d", __func__, data.length);
2005
2006 /* Save the session ID on the first time around */
2007 if (session_id2_len == 0) {
2008 session_id2_len = data.length;
2009 session_id2 = xmalloc(session_id2_len);
2010 memcpy(session_id2, data.value, session_id2_len);
2011 }
2012 major = ssh_gssapi_sign(gsscontext, &data, &hash);
2013
2014 xfree(data.value);
2015
2016 buffer_clear(m);
2017 buffer_put_int(m, major);
2018 buffer_put_string(m, hash.value, hash.length);
2019
2020 mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
2021
2022 gss_release_buffer(&minor, &hash);
2023
2024 /* Turn on getpwnam permissions */
2025 monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
2026
2027 return (0);
2028}
2029
1971#endif /* GSSAPI */ 2030#endif /* GSSAPI */
diff --git a/monitor.h b/monitor.h
index 464009ad8..5bf7d01c0 100644
--- a/monitor.h
+++ b/monitor.h
@@ -53,6 +53,7 @@ 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,
56 MONITOR_REQ_PAM_START, 57 MONITOR_REQ_PAM_START,
57 MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, 58 MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT,
58 MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, 59 MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX,
diff --git a/monitor_wrap.c b/monitor_wrap.c
index 40463d078..b559c77bf 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1255,4 +1255,27 @@ mm_ssh_gssapi_userok(char *user)
1255 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); 1255 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
1256 return (authenticated); 1256 return (authenticated);
1257} 1257}
1258
1259OM_uint32
1260mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
1261{
1262 Buffer m;
1263 OM_uint32 major;
1264 u_int len;
1265
1266 buffer_init(&m);
1267 buffer_put_string(&m, data->value, data->length);
1268
1269 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
1270 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
1271
1272 major = buffer_get_int(&m);
1273 hash->value = buffer_get_string(&m, &len);
1274 hash->length = len;
1275
1276 buffer_free(&m);
1277
1278 return(major);
1279}
1280
1258#endif /* GSSAPI */ 1281#endif /* GSSAPI */
diff --git a/monitor_wrap.h b/monitor_wrap.h
index 329189c2a..2a7bf7c87 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -59,6 +59,7 @@ OM_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);
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);
62#endif 63#endif
63 64
64#ifdef USE_PAM 65#ifdef USE_PAM
diff --git a/readconf.c b/readconf.c
index 73f6eb361..3aedd6f5a 100644
--- a/readconf.c
+++ b/readconf.c
@@ -127,6 +127,8 @@ 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 oGssKeyEx,
131 oGssTrustDns,
130 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 132 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
131 oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, 133 oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
132 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, 134 oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
@@ -164,10 +166,14 @@ static struct {
164 { "afstokenpassing", oUnsupported }, 166 { "afstokenpassing", oUnsupported },
165#if defined(GSSAPI) 167#if defined(GSSAPI)
166 { "gssapiauthentication", oGssAuthentication }, 168 { "gssapiauthentication", oGssAuthentication },
169 { "gssapikeyexchange", oGssKeyEx },
167 { "gssapidelegatecredentials", oGssDelegateCreds }, 170 { "gssapidelegatecredentials", oGssDelegateCreds },
171 { "gssapitrustdns", oGssTrustDns },
168#else 172#else
169 { "gssapiauthentication", oUnsupported }, 173 { "gssapiauthentication", oUnsupported },
174 { "gssapikeyexchange", oUnsupported },
170 { "gssapidelegatecredentials", oUnsupported }, 175 { "gssapidelegatecredentials", oUnsupported },
176 { "gssapitrustdns", oUnsupported },
171#endif 177#endif
172 { "fallbacktorsh", oDeprecated }, 178 { "fallbacktorsh", oDeprecated },
173 { "usersh", oDeprecated }, 179 { "usersh", oDeprecated },
@@ -444,10 +450,18 @@ parse_flag:
444 intptr = &options->gss_authentication; 450 intptr = &options->gss_authentication;
445 goto parse_flag; 451 goto parse_flag;
446 452
453 case oGssKeyEx:
454 intptr = &options->gss_keyex;
455 goto parse_flag;
456
447 case oGssDelegateCreds: 457 case oGssDelegateCreds:
448 intptr = &options->gss_deleg_creds; 458 intptr = &options->gss_deleg_creds;
449 goto parse_flag; 459 goto parse_flag;
450 460
461 case oGssTrustDns:
462 intptr = &options->gss_trust_dns;
463 goto parse_flag;
464
451 case oBatchMode: 465 case oBatchMode:
452 intptr = &options->batch_mode; 466 intptr = &options->batch_mode;
453 goto parse_flag; 467 goto parse_flag;
@@ -1016,7 +1030,9 @@ initialize_options(Options * options)
1016 options->pubkey_authentication = -1; 1030 options->pubkey_authentication = -1;
1017 options->challenge_response_authentication = -1; 1031 options->challenge_response_authentication = -1;
1018 options->gss_authentication = -1; 1032 options->gss_authentication = -1;
1033 options->gss_keyex = -1;
1019 options->gss_deleg_creds = -1; 1034 options->gss_deleg_creds = -1;
1035 options->gss_trust_dns = -1;
1020 options->password_authentication = -1; 1036 options->password_authentication = -1;
1021 options->kbd_interactive_authentication = -1; 1037 options->kbd_interactive_authentication = -1;
1022 options->kbd_interactive_devices = NULL; 1038 options->kbd_interactive_devices = NULL;
@@ -1106,8 +1122,12 @@ fill_default_options(Options * options)
1106 options->challenge_response_authentication = 1; 1122 options->challenge_response_authentication = 1;
1107 if (options->gss_authentication == -1) 1123 if (options->gss_authentication == -1)
1108 options->gss_authentication = 0; 1124 options->gss_authentication = 0;
1125 if (options->gss_keyex == -1)
1126 options->gss_keyex = 0;
1109 if (options->gss_deleg_creds == -1) 1127 if (options->gss_deleg_creds == -1)
1110 options->gss_deleg_creds = 0; 1128 options->gss_deleg_creds = 0;
1129 if (options->gss_trust_dns == -1)
1130 options->gss_trust_dns = 0;
1111 if (options->password_authentication == -1) 1131 if (options->password_authentication == -1)
1112 options->password_authentication = 1; 1132 options->password_authentication = 1;
1113 if (options->kbd_interactive_authentication == -1) 1133 if (options->kbd_interactive_authentication == -1)
diff --git a/readconf.h b/readconf.h
index 47c7aef4e..10067f117 100644
--- a/readconf.h
+++ b/readconf.h
@@ -44,7 +44,9 @@ 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 */
48 int password_authentication; /* Try password 50 int password_authentication; /* Try password
49 * authentication. */ 51 * authentication. */
50 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ 52 int kbd_interactive_authentication; /* Try keyboard-interactive auth. */
diff --git a/servconf.c b/servconf.c
index 66e22979f..ede032567 100644
--- a/servconf.c
+++ b/servconf.c
@@ -92,7 +92,9 @@ 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;
96 options->password_authentication = -1; 98 options->password_authentication = -1;
97 options->kbd_interactive_authentication = -1; 99 options->kbd_interactive_authentication = -1;
98 options->challenge_response_authentication = -1; 100 options->challenge_response_authentication = -1;
@@ -209,8 +211,12 @@ fill_default_server_options(ServerOptions *options)
209 options->kerberos_get_afs_token = 0; 211 options->kerberos_get_afs_token = 0;
210 if (options->gss_authentication == -1) 212 if (options->gss_authentication == -1)
211 options->gss_authentication = 0; 213 options->gss_authentication = 0;
214 if (options->gss_keyex == -1)
215 options->gss_keyex = 0;
212 if (options->gss_cleanup_creds == -1) 216 if (options->gss_cleanup_creds == -1)
213 options->gss_cleanup_creds = 1; 217 options->gss_cleanup_creds = 1;
218 if (options->gss_strict_acceptor == -1)
219 options->gss_strict_acceptor = 1;
214 if (options->password_authentication == -1) 220 if (options->password_authentication == -1)
215 options->password_authentication = 1; 221 options->password_authentication = 1;
216 if (options->kbd_interactive_authentication == -1) 222 if (options->kbd_interactive_authentication == -1)
@@ -299,7 +305,9 @@ typedef enum {
299 sBanner, sUseDNS, sHostbasedAuthentication, 305 sBanner, sUseDNS, sHostbasedAuthentication,
300 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 306 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
301 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, 307 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
302 sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, 308 sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
309 sGssKeyEx,
310 sAcceptEnv, sPermitTunnel,
303 sMatch, sPermitOpen, sForceCommand, sChrootDirectory, 311 sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
304 sUsePrivilegeSeparation, sAllowAgentForwarding, 312 sUsePrivilegeSeparation, sAllowAgentForwarding,
305 sDeprecated, sUnsupported 313 sDeprecated, sUnsupported
@@ -360,9 +368,13 @@ static struct {
360#ifdef GSSAPI 368#ifdef GSSAPI
361 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, 369 { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
362 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, 370 { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
371 { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL },
372 { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL },
363#else 373#else
364 { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, 374 { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
365 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, 375 { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
376 { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL },
377 { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL },
366#endif 378#endif
367 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, 379 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
368 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, 380 { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
@@ -882,10 +894,18 @@ process_server_config_line(ServerOptions *options, char *line,
882 intptr = &options->gss_authentication; 894 intptr = &options->gss_authentication;
883 goto parse_flag; 895 goto parse_flag;
884 896
897 case sGssKeyEx:
898 intptr = &options->gss_keyex;
899 goto parse_flag;
900
885 case sGssCleanupCreds: 901 case sGssCleanupCreds:
886 intptr = &options->gss_cleanup_creds; 902 intptr = &options->gss_cleanup_creds;
887 goto parse_flag; 903 goto parse_flag;
888 904
905 case sGssStrictAcceptor:
906 intptr = &options->gss_strict_acceptor;
907 goto parse_flag;
908
889 case sPasswordAuthentication: 909 case sPasswordAuthentication:
890 intptr = &options->password_authentication; 910 intptr = &options->password_authentication;
891 goto parse_flag; 911 goto parse_flag;
diff --git a/servconf.h b/servconf.h
index 40ac64f13..bad73a510 100644
--- a/servconf.h
+++ b/servconf.h
@@ -91,7 +91,9 @@ 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 */
95 int password_authentication; /* If true, permit password 97 int password_authentication; /* If true, permit password
96 * authentication. */ 98 * authentication. */
97 int kbd_interactive_authentication; /* If true, permit */ 99 int kbd_interactive_authentication; /* If true, permit */
diff --git a/ssh-gss.h b/ssh-gss.h
index c29a1b7e7..4e9e357b5 100644
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -60,6 +60,17 @@
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;
@@ -97,6 +108,7 @@ typedef struct {
97} Gssctxt; 108} Gssctxt;
98 109
99extern ssh_gssapi_mech *supported_mechs[]; 110extern ssh_gssapi_mech *supported_mechs[];
111extern Gssctxt *gss_kex_context;
100 112
101int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); 113int ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
102void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); 114void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
@@ -119,6 +131,11 @@ void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
119int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); 131int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *);
120 132
121/* In the server */ 133/* In the server */
134typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *);
135char *ssh_gssapi_client_mechanisms(const char *host);
136char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *);
137gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int);
138int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *);
122OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 139OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
123int ssh_gssapi_userok(char *name); 140int ssh_gssapi_userok(char *name);
124OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 141OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
@@ -126,6 +143,8 @@ void ssh_gssapi_do_child(char ***, u_int *);
126void ssh_gssapi_cleanup_creds(void); 143void ssh_gssapi_cleanup_creds(void);
127void ssh_gssapi_storecreds(void); 144void ssh_gssapi_storecreds(void);
128 145
146char *ssh_gssapi_server_mechanisms(void);
147int ssh_gssapi_oid_table_ok();
129#endif /* GSSAPI */ 148#endif /* GSSAPI */
130 149
131#endif /* _SSH_GSS_H */ 150#endif /* _SSH_GSS_H */
diff --git a/ssh_config b/ssh_config
index 8cb0698a8..5e3cd7426 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 85e7ba06d..15eecb6ff 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -478,11 +478,28 @@ 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.
481.It Cm GSSAPIDelegateCredentials 487.It Cm GSSAPIDelegateCredentials
482Forward (delegate) credentials to the server. 488Forward (delegate) credentials to the server.
483The default is 489The default is
484.Dq no . 490.Dq no .
485Note that this option applies to protocol version 2 only. 491Note that this option applies to protocol version 2 only.
492.It Cm GSSAPITrustDns
493Set to
494.Dq yes
495to indicate that the DNS is trusted to securely canonicalize
496the name of the host being connected to. If
497.Dq no ,
498the hostname entered on the
499command line will be passed untouched to the GSSAPI library.
500The default is
501.Dq no .
502This option only applies to protocol version 2 connections using GSSAPI.
486.It Cm HashKnownHosts 503.It Cm HashKnownHosts
487Indicates that 504Indicates that
488.Xr ssh 1 505.Xr ssh 1
diff --git a/sshconnect2.c b/sshconnect2.c
index 389bec9e4..f7d34bf02 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -102,9 +102,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
102{ 102{
103 Kex *kex; 103 Kex *kex;
104 104
105#ifdef GSSAPI
106 char *orig = NULL, *gss = NULL;
107 char *gss_host = NULL;
108#endif
109
105 xxx_host = host; 110 xxx_host = host;
106 xxx_hostaddr = hostaddr; 111 xxx_hostaddr = hostaddr;
107 112
113#ifdef GSSAPI
114 if (options.gss_keyex) {
115 /* Add the GSSAPI mechanisms currently supported on this
116 * client to the key exchange algorithm proposal */
117 orig = myproposal[PROPOSAL_KEX_ALGS];
118
119 if (options.gss_trust_dns)
120 gss_host = (char *)get_canonical_hostname(1);
121 else
122 gss_host = host;
123
124 gss = ssh_gssapi_client_mechanisms(gss_host);
125 if (gss) {
126 debug("Offering GSSAPI proposal: %s", gss);
127 xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
128 "%s,%s", gss, orig);
129 }
130 }
131#endif
132
108 if (options.ciphers == (char *)-1) { 133 if (options.ciphers == (char *)-1) {
109 logit("No valid ciphers for protocol version 2 given, using defaults."); 134 logit("No valid ciphers for protocol version 2 given, using defaults.");
110 options.ciphers = NULL; 135 options.ciphers = NULL;
@@ -132,6 +157,16 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
132 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 157 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
133 options.hostkeyalgorithms; 158 options.hostkeyalgorithms;
134 159
160#ifdef GSSAPI
161 /* If we've got GSSAPI algorithms, then we also support the
162 * 'null' hostkey, as a last resort */
163 if (options.gss_keyex && gss) {
164 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
165 xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],
166 "%s,null", orig);
167 }
168#endif
169
135 if (options.rekey_limit) 170 if (options.rekey_limit)
136 packet_set_rekey_limit((u_int32_t)options.rekey_limit); 171 packet_set_rekey_limit((u_int32_t)options.rekey_limit);
137 172
@@ -141,10 +176,21 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
141 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; 176 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
142 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 177 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
143 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; 178 kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
179#ifdef GSSAPI
180 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
181 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client;
182 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
183#endif
144 kex->client_version_string=client_version_string; 184 kex->client_version_string=client_version_string;
145 kex->server_version_string=server_version_string; 185 kex->server_version_string=server_version_string;
146 kex->verify_host_key=&verify_host_key_callback; 186 kex->verify_host_key=&verify_host_key_callback;
147 187
188#ifdef GSSAPI
189 kex->gss_deleg_creds = options.gss_deleg_creds;
190 kex->gss_trust_dns = options.gss_trust_dns;
191 kex->gss_host = gss_host;
192#endif
193
148 xxx_kex = kex; 194 xxx_kex = kex;
149 195
150 dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 196 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -227,6 +273,7 @@ void input_gssapi_token(int type, u_int32_t, void *);
227void input_gssapi_hash(int type, u_int32_t, void *); 273void input_gssapi_hash(int type, u_int32_t, void *);
228void input_gssapi_error(int, u_int32_t, void *); 274void input_gssapi_error(int, u_int32_t, void *);
229void input_gssapi_errtok(int, u_int32_t, void *); 275void input_gssapi_errtok(int, u_int32_t, void *);
276int userauth_gsskeyex(Authctxt *authctxt);
230#endif 277#endif
231 278
232void userauth(Authctxt *, char *); 279void userauth(Authctxt *, char *);
@@ -242,6 +289,10 @@ static char *authmethods_get(void);
242 289
243Authmethod authmethods[] = { 290Authmethod authmethods[] = {
244#ifdef GSSAPI 291#ifdef GSSAPI
292 {"gssapi-keyex",
293 userauth_gsskeyex,
294 &options.gss_authentication,
295 NULL},
245 {"gssapi-with-mic", 296 {"gssapi-with-mic",
246 userauth_gssapi, 297 userauth_gssapi,
247 &options.gss_authentication, 298 &options.gss_authentication,
@@ -511,6 +562,12 @@ userauth_gssapi(Authctxt *authctxt)
511 static u_int mech = 0; 562 static u_int mech = 0;
512 OM_uint32 min; 563 OM_uint32 min;
513 int ok = 0; 564 int ok = 0;
565 char *gss_host = NULL;
566
567 if (options.gss_trust_dns)
568 gss_host = (char *)get_canonical_hostname(1);
569 else
570 gss_host = (char *)authctxt->host;
514 571
515 /* Try one GSSAPI method at a time, rather than sending them all at 572 /* Try one GSSAPI method at a time, rather than sending them all at
516 * once. */ 573 * once. */
@@ -523,7 +580,7 @@ userauth_gssapi(Authctxt *authctxt)
523 /* My DER encoding requires length<128 */ 580 /* My DER encoding requires length<128 */
524 if (gss_supported->elements[mech].length < 128 && 581 if (gss_supported->elements[mech].length < 128 &&
525 ssh_gssapi_check_mechanism(&gssctxt, 582 ssh_gssapi_check_mechanism(&gssctxt,
526 &gss_supported->elements[mech], authctxt->host)) { 583 &gss_supported->elements[mech], gss_host)) {
527 ok = 1; /* Mechanism works */ 584 ok = 1; /* Mechanism works */
528 } else { 585 } else {
529 mech++; 586 mech++;
@@ -619,8 +676,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
619{ 676{
620 Authctxt *authctxt = ctxt; 677 Authctxt *authctxt = ctxt;
621 Gssctxt *gssctxt; 678 Gssctxt *gssctxt;
622 int oidlen; 679 u_int oidlen;
623 char *oidv; 680 u_char *oidv;
624 681
625 if (authctxt == NULL) 682 if (authctxt == NULL)
626 fatal("input_gssapi_response: no authentication context"); 683 fatal("input_gssapi_response: no authentication context");
@@ -727,6 +784,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
727 xfree(msg); 784 xfree(msg);
728 xfree(lang); 785 xfree(lang);
729} 786}
787
788int
789userauth_gsskeyex(Authctxt *authctxt)
790{
791 Buffer b;
792 gss_buffer_desc gssbuf;
793 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
794 OM_uint32 ms;
795
796 static int attempt = 0;
797 if (attempt++ >= 1)
798 return (0);
799
800 if (gss_kex_context == NULL) {
801 debug("No valid Key exchange context");
802 return (0);
803 }
804
805 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
806 "gssapi-keyex");
807
808 gssbuf.value = buffer_ptr(&b);
809 gssbuf.length = buffer_len(&b);
810
811 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
812 buffer_free(&b);
813 return (0);
814 }
815
816 packet_start(SSH2_MSG_USERAUTH_REQUEST);
817 packet_put_cstring(authctxt->server_user);
818 packet_put_cstring(authctxt->service);
819 packet_put_cstring(authctxt->method->name);
820 packet_put_string(mic.value, mic.length);
821 packet_send();
822
823 buffer_free(&b);
824 gss_release_buffer(&ms, &mic);
825
826 return (1);
827}
828
730#endif /* GSSAPI */ 829#endif /* GSSAPI */
731 830
732int 831int
diff --git a/sshd.c b/sshd.c
index 6e5bb5476..be3b3b8bb 100644
--- a/sshd.c
+++ b/sshd.c
@@ -120,6 +120,10 @@
120#include "monitor_fdpass.h" 120#include "monitor_fdpass.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,59 @@ 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 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
2309 kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server;
2310 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
2311#endif
2204 kex->server = 1; 2312 kex->server = 1;
2205 kex->client_version_string=client_version_string; 2313 kex->client_version_string=client_version_string;
2206 kex->server_version_string=server_version_string; 2314 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 7255b1c22..e58b7cfc7 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -374,12 +374,35 @@ Specifies whether user authentication based on GSSAPI is allowed.
374The default is 374The default is
375.Dq no . 375.Dq no .
376Note that this option applies to protocol version 2 only. 376Note that this option applies to protocol version 2 only.
377.It Cm GSSAPIKeyExchange
378Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
379doesn't rely on ssh keys to verify host identity.
380The default is
381.Dq no .
382Note that this option applies to protocol version 2 only.
377.It Cm GSSAPICleanupCredentials 383.It Cm GSSAPICleanupCredentials
378Specifies whether to automatically destroy the user's credentials cache 384Specifies whether to automatically destroy the user's credentials cache
379on logout. 385on logout.
380The default is 386The default is
381.Dq yes . 387.Dq yes .
382Note that this option applies to protocol version 2 only. 388Note that this option applies to protocol version 2 only.
389.It Cm GSSAPIStrictAcceptorCheck
390Determines whether to be strict about the identity of the GSSAPI acceptor
391a client authenticates against. If
392.Dq yes
393then the client must authenticate against the
394.Pa host
395service on the current hostname. If
396.Dq no
397then the client may authenticate against any service key stored in the
398machine's default store. This facility is provided to assist with operation
399on multi homed machines.
400The default is
401.Dq yes .
402Note that this option applies only to protocol version 2 GSSAPI connections,
403and setting it to
404.Dq no
405may only work with recent Kerberos GSSAPI libraries.
383.It Cm HostbasedAuthentication 406.It Cm HostbasedAuthentication
384Specifies whether rhosts or /etc/hosts.equiv authentication together 407Specifies whether rhosts or /etc/hosts.equiv authentication together
385with successful public key client host authentication is allowed 408with successful public key client host authentication is allowed