summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in4
-rw-r--r--acconfig.h6
-rw-r--r--auth-krb5.c19
-rw-r--r--auth.h1
-rw-r--r--auth2-gss.c41
-rw-r--r--auth2.c7
-rw-r--r--configure.ac22
-rw-r--r--gss-genr.c173
-rw-r--r--gss-serv.c32
-rw-r--r--kex.c12
-rw-r--r--kex.h12
-rw-r--r--kexgssc.c302
-rw-r--r--kexgsss.c254
-rw-r--r--key.c2
-rw-r--r--key.h1
-rw-r--r--monitor.c58
-rw-r--r--monitor.h1
-rw-r--r--monitor_wrap.c23
-rw-r--r--monitor_wrap.h1
-rw-r--r--readconf.c10
-rw-r--r--readconf.h1
-rw-r--r--servconf.c11
-rw-r--r--servconf.h1
-rw-r--r--ssh-gss.h22
-rw-r--r--ssh_config.510
-rw-r--r--sshconnect2.c94
-rw-r--r--sshd.c123
-rw-r--r--sshd_config.56
28 files changed, 1224 insertions, 25 deletions
diff --git a/Makefile.in b/Makefile.in
index fcbc522f2..f73219ba6 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -71,7 +71,7 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.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 74 entropy.o scard-opensc.o gss-genr.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 77 sshconnect.o sshconnect1.o sshconnect2.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 89 audit.o audit-bsm.o
90 90
diff --git a/acconfig.h b/acconfig.h
index 79b5e8191..619c4b801 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -347,6 +347,12 @@
347/* getaddrinfo is broken (if present) */ 347/* getaddrinfo is broken (if present) */
348#undef BROKEN_GETADDRINFO 348#undef BROKEN_GETADDRINFO
349 349
350/* platform uses an in-memory credentials cache */
351#undef USE_CCAPI
352
353/* platform has a Security Authorization Session API */
354#undef USE_SECURITY_SESSION_API
355
350/* updwtmpx is broken (if present) */ 356/* updwtmpx is broken (if present) */
351#undef BROKEN_UPDWTMPX 357#undef BROKEN_UPDWTMPX
352 358
diff --git a/auth-krb5.c b/auth-krb5.c
index c7367b49a..5f554a66b 100644
--- a/auth-krb5.c
+++ b/auth-krb5.c
@@ -159,8 +159,13 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
159 159
160 len = strlen(authctxt->krb5_ticket_file) + 6; 160 len = strlen(authctxt->krb5_ticket_file) + 6;
161 authctxt->krb5_ccname = xmalloc(len); 161 authctxt->krb5_ccname = xmalloc(len);
162#ifdef USE_CCAPI
163 snprintf(authctxt->krb5_ccname, len, "API:%s",
164 authctxt->krb5_ticket_file);
165#else
162 snprintf(authctxt->krb5_ccname, len, "FILE:%s", 166 snprintf(authctxt->krb5_ccname, len, "FILE:%s",
163 authctxt->krb5_ticket_file); 167 authctxt->krb5_ticket_file);
168#endif
164 169
165#ifdef USE_PAM 170#ifdef USE_PAM
166 if (options.use_pam) 171 if (options.use_pam)
@@ -212,15 +217,22 @@ krb5_cleanup_proc(Authctxt *authctxt)
212#ifndef HEIMDAL 217#ifndef HEIMDAL
213krb5_error_code 218krb5_error_code
214ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { 219ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
215 int tmpfd, ret; 220 int ret;
216 char ccname[40]; 221 char ccname[40];
217 mode_t old_umask; 222 mode_t old_umask;
223#ifdef USE_CCAPI
224 char cctemplate[] = "API:krb5cc_%d";
225#else
226 char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
227 int tmpfd;
228#endif
218 229
219 ret = snprintf(ccname, sizeof(ccname), 230 ret = snprintf(ccname, sizeof(ccname),
220 "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); 231 cctemplate, geteuid());
221 if (ret == -1 || ret >= sizeof(ccname)) 232 if (ret == -1 || ret >= (int) sizeof(ccname))
222 return ENOMEM; 233 return ENOMEM;
223 234
235#ifndef USE_CCAPI
224 old_umask = umask(0177); 236 old_umask = umask(0177);
225 tmpfd = mkstemp(ccname + strlen("FILE:")); 237 tmpfd = mkstemp(ccname + strlen("FILE:"));
226 umask(old_umask); 238 umask(old_umask);
@@ -235,6 +247,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
235 return errno; 247 return errno;
236 } 248 }
237 close(tmpfd); 249 close(tmpfd);
250#endif
238 251
239 return (krb5_cc_resolve(ctx, ccname, ccache)); 252 return (krb5_cc_resolve(ctx, ccname, ccache));
240} 253}
diff --git a/auth.h b/auth.h
index 8b814ba6a..456d28f37 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 4d468a0e8..9cbc29605 100644
--- a/auth2-gss.c
+++ b/auth2-gss.c
@@ -47,6 +47,39 @@ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
47static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); 47static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
48static void input_gssapi_errtok(int, u_int32_t, void *); 48static void input_gssapi_errtok(int, u_int32_t, void *);
49 49
50/*
51 * The 'gssapi_keyex' userauth mechanism.
52 */
53static int
54userauth_gsskeyex(Authctxt *authctxt)
55{
56 int authenticated = 0;
57 Buffer b;
58 gss_buffer_desc mic, gssbuf;
59 u_int len;
60
61 mic.value = packet_get_string(&len);
62 mic.length = len;
63
64 packet_check_eom();
65
66 ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
67 "gssapi-keyex");
68
69 gssbuf.value = buffer_ptr(&b);
70 gssbuf.length = buffer_len(&b);
71
72 /* gss_kex_context is NULL with privsep, so we can't check it here */
73 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
74 &gssbuf, &mic))))
75 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
76
77 buffer_free(&b);
78 xfree(mic.value);
79
80 return (authenticated);
81}
82
50/* 83/*
51 * We only support those mechanisms that we know about (ie ones that we know 84 * We only support those mechanisms that we know about (ie ones that we know
52 * how to check local user kuserok and the like 85 * how to check local user kuserok and the like
@@ -97,11 +130,13 @@ userauth_gssapi(Authctxt *authctxt)
97 130
98 if (!present) { 131 if (!present) {
99 xfree(doid); 132 xfree(doid);
133 authctxt->server_caused_failure = 1;
100 return (0); 134 return (0);
101 } 135 }
102 136
103 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) { 137 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) {
104 xfree(doid); 138 xfree(doid);
139 authctxt->server_caused_failure = 1;
105 return (0); 140 return (0);
106 } 141 }
107 142
@@ -285,6 +320,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
285 userauth_finish(authctxt, authenticated, "gssapi-with-mic"); 320 userauth_finish(authctxt, authenticated, "gssapi-with-mic");
286} 321}
287 322
323Authmethod method_gsskeyex = {
324 "gssapi-keyex",
325 userauth_gsskeyex,
326 &options.gss_authentication
327};
328
288Authmethod method_gssapi = { 329Authmethod method_gssapi = {
289 "gssapi-with-mic", 330 "gssapi-with-mic",
290 userauth_gssapi, 331 userauth_gssapi,
diff --git a/auth2.c b/auth2.c
index 613b0e2bc..87f8ad507 100644
--- a/auth2.c
+++ b/auth2.c
@@ -55,6 +55,7 @@ extern Authmethod method_passwd;
55extern Authmethod method_kbdint; 55extern Authmethod method_kbdint;
56extern Authmethod method_hostbased; 56extern Authmethod method_hostbased;
57#ifdef GSSAPI 57#ifdef GSSAPI
58extern Authmethod method_gsskeyex;
58extern Authmethod method_gssapi; 59extern Authmethod method_gssapi;
59#endif 60#endif
60 61
@@ -62,6 +63,7 @@ Authmethod *authmethods[] = {
62 &method_none, 63 &method_none,
63 &method_pubkey, 64 &method_pubkey,
64#ifdef GSSAPI 65#ifdef GSSAPI
66 &method_gsskeyex,
65 &method_gssapi, 67 &method_gssapi,
66#endif 68#endif
67 &method_passwd, 69 &method_passwd,
@@ -192,6 +194,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
192#endif 194#endif
193 195
194 authctxt->postponed = 0; 196 authctxt->postponed = 0;
197 authctxt->server_caused_failure = 0;
195 198
196 /* try to authenticate user */ 199 /* try to authenticate user */
197 m = authmethod_lookup(method); 200 m = authmethod_lookup(method);
@@ -262,7 +265,9 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
262 /* now we can break out */ 265 /* now we can break out */
263 authctxt->success = 1; 266 authctxt->success = 1;
264 } else { 267 } else {
265 if (authctxt->failures++ > options.max_authtries) { 268 /* Dont count server configuration issues against the client */
269 if (!authctxt->server_caused_failure &&
270 authctxt->failures++ > options.max_authtries) {
266#ifdef SSH_AUDIT_EVENTS 271#ifdef SSH_AUDIT_EVENTS
267 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES)); 272 PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
268#endif 273#endif
diff --git a/configure.ac b/configure.ac
index 1e4df2e33..6e36aa22b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -266,6 +266,28 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
266 AC_DEFINE(BROKEN_SETREUID) 266 AC_DEFINE(BROKEN_SETREUID)
267 AC_DEFINE(BROKEN_SETREGID) 267 AC_DEFINE(BROKEN_SETREGID)
268 AC_DEFINE_UNQUOTED(BIND_8_COMPAT, 1) 268 AC_DEFINE_UNQUOTED(BIND_8_COMPAT, 1)
269 AC_MSG_CHECKING(if we have the Security Authorization Session API)
270 AC_TRY_COMPILE([#include <Security/AuthSession.h>],
271 [SessionCreate(0, 0);],
272 [ac_cv_use_security_session_api="yes"
273 AC_DEFINE(USE_SECURITY_SESSION_API)
274 LIBS="$LIBS -framework Security"
275 AC_MSG_RESULT(yes)],
276 [ac_cv_use_security_session_api="no"
277 AC_MSG_RESULT(no)])
278 AC_MSG_CHECKING(if we have an in-memory credentials cache)
279 AC_TRY_COMPILE(
280 [#include <Kerberos/Kerberos.h>],
281 [cc_context_t c;
282 (void) cc_initialize (&c, 0, NULL, NULL);],
283 [AC_DEFINE(USE_CCAPI)
284 LIBS="$LIBS -framework Security"
285 AC_MSG_RESULT(yes)
286 if test "x$ac_cv_use_security_session_api" = "xno"; then
287 AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***)
288 fi],
289 [AC_MSG_RESULT(no)]
290 )
269 ;; 291 ;;
270*-*-hpux*) 292*-*-hpux*)
271 # first we define all of the options common to all HP-UX releases 293 # first we define all of the options common to all HP-UX releases
diff --git a/gss-genr.c b/gss-genr.c
index 9bc31aa2a..9dec270a3 100644
--- a/gss-genr.c
+++ b/gss-genr.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-genr.c,v 1.4 2005/07/17 07:17:55 djm Exp $ */ 1/* $OpenBSD: gss-genr.c,v 1.4 2005/07/17 07:17:55 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2005 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
@@ -34,12 +34,152 @@
34#include "log.h" 34#include "log.h"
35#include "monitor_wrap.h" 35#include "monitor_wrap.h"
36#include "ssh2.h" 36#include "ssh2.h"
37#include <openssl/evp.h>
37 38
38#include "ssh-gss.h" 39#include "ssh-gss.h"
39 40
40extern u_char *session_id2; 41extern u_char *session_id2;
41extern u_int session_id2_len; 42extern u_int session_id2_len;
42 43
44typedef struct {
45 char *encoded;
46 gss_OID oid;
47} ssh_gss_kex_mapping;
48
49/*
50 * XXX - It would be nice to find a more elegant way of handling the
51 * XXX passing of the key exchange context to the userauth routines
52 */
53
54Gssctxt *gss_kex_context = NULL;
55
56static ssh_gss_kex_mapping *gss_enc2oid = NULL;
57
58int
59ssh_gssapi_oid_table_ok() {
60 return (gss_enc2oid != NULL);
61}
62
63/*
64 * Return a list of the gss-group1-sha1 mechanisms supported by this program
65 *
66 * We test mechanisms to ensure that we can use them, to avoid starting
67 * a key exchange with a bad mechanism
68 */
69
70
71char *
72ssh_gssapi_client_mechanisms(const char *host) {
73 gss_OID_set gss_supported;
74 OM_uint32 min_status;
75
76 gss_indicate_mechs(&min_status, &gss_supported);
77
78 return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
79 (void *)host));
80}
81
82char *
83ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
84 void *data) {
85 Buffer buf;
86 int i, oidpos, enclen;
87 char *mechs, *encoded;
88 char digest[EVP_MAX_MD_SIZE];
89 char deroid[2];
90 const EVP_MD *evp_md = EVP_md5();
91 EVP_MD_CTX md;
92
93 if (gss_enc2oid != NULL) {
94 for (i=0;gss_enc2oid[i].encoded!=NULL;i++)
95 xfree(gss_enc2oid[i].encoded);
96 xfree(gss_enc2oid);
97 }
98
99 gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping)*
100 (gss_supported->count+1));
101
102 buffer_init(&buf);
103
104 oidpos = 0;
105 for (i = 0;i < gss_supported->count;i++) {
106 if (gss_supported->elements[i].length < 128 &&
107 (*check)(&(gss_supported->elements[i]), data)) {
108
109 deroid[0] = SSH_GSS_OIDTYPE;
110 deroid[1] = gss_supported->elements[i].length;
111
112 EVP_DigestInit(&md, evp_md);
113 EVP_DigestUpdate(&md, deroid, 2);
114 EVP_DigestUpdate(&md,
115 gss_supported->elements[i].elements,
116 gss_supported->elements[i].length);
117 EVP_DigestFinal(&md, digest, NULL);
118
119 encoded = xmalloc(EVP_MD_size(evp_md)*2);
120 enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
121 encoded, EVP_MD_size(evp_md)*2);
122
123 if (oidpos != 0)
124 buffer_put_char(&buf, ',');
125
126 buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
127 sizeof(KEX_GSS_GEX_SHA1_ID)-1);
128 buffer_append(&buf, encoded, enclen);
129 buffer_put_char(&buf,',');
130 buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
131 sizeof(KEX_GSS_GRP1_SHA1_ID)-1);
132 buffer_append(&buf, encoded, enclen);
133
134 gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
135 gss_enc2oid[oidpos].encoded = encoded;
136 oidpos++;
137 }
138 }
139 gss_enc2oid[oidpos].oid = NULL;
140 gss_enc2oid[oidpos].encoded = NULL;
141
142 buffer_put_char(&buf, '\0');
143
144 mechs = xmalloc(buffer_len(&buf));
145 buffer_get(&buf, mechs, buffer_len(&buf));
146 buffer_free(&buf);
147
148 if (strlen(mechs) == 0) {
149 xfree(mechs);
150 mechs = NULL;
151 }
152
153 return (mechs);
154}
155
156gss_OID
157ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int *gex) {
158 int i = 0;
159
160 if (strncmp(name, KEX_GSS_GRP1_SHA1_ID,
161 sizeof(KEX_GSS_GRP1_SHA1_ID)-1) == 0) {
162 name+=sizeof(KEX_GSS_GRP1_SHA1_ID)-1;
163 *gex = 0;
164 } else if (strncmp(name, KEX_GSS_GEX_SHA1_ID,
165 sizeof(KEX_GSS_GEX_SHA1_ID)-1) == 0) {
166 name+=sizeof(KEX_GSS_GEX_SHA1_ID)-1;
167 *gex = 1;
168 } else {
169 return NULL;
170 }
171
172 while (gss_enc2oid[i].encoded != NULL &&
173 strcmp(name, gss_enc2oid[i].encoded) != 0) {
174 i++;
175 }
176
177 if (gss_enc2oid[i].oid != NULL && ctx != NULL)
178 ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
179
180 return gss_enc2oid[i].oid;
181}
182
43/* Check that the OID in a data stream matches that in the context */ 183/* Check that the OID in a data stream matches that in the context */
44int 184int
45ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) 185ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
@@ -250,6 +390,9 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
250OM_uint32 390OM_uint32
251ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) 391ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
252{ 392{
393 if (ctx == NULL)
394 return -1;
395
253 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, 396 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
254 GSS_C_QOP_DEFAULT, buffer, hash))) 397 GSS_C_QOP_DEFAULT, buffer, hash)))
255 ssh_gssapi_error(ctx); 398 ssh_gssapi_error(ctx);
@@ -257,6 +400,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
257 return (ctx->major); 400 return (ctx->major);
258} 401}
259 402
403/* Priviledged when used by server */
404OM_uint32
405ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
406{
407 if (ctx == NULL)
408 return -1;
409
410 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
411 gssbuf, gssmic, NULL);
412
413 return (ctx->major);
414}
415
260void 416void
261ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, 417ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
262 const char *context) 418 const char *context)
@@ -278,4 +434,19 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) {
278 return (ssh_gssapi_acquire_cred(*ctx)); 434 return (ssh_gssapi_acquire_cred(*ctx));
279} 435}
280 436
437int
438ssh_gssapi_check_mechanism(gss_OID oid, void *host) {
439 Gssctxt * ctx = NULL;
440 gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
441 OM_uint32 major, minor;
442
443 ssh_gssapi_build_ctx(&ctx);
444 ssh_gssapi_set_oid(ctx, oid);
445 ssh_gssapi_import_name(ctx, host);
446 major = ssh_gssapi_init_ctx(ctx, 0, GSS_C_NO_BUFFER, &token, NULL);
447 gss_release_buffer(&minor, &token);
448 ssh_gssapi_delete_ctx(&ctx);
449 return (!GSS_ERROR(major));
450}
451
281#endif /* GSSAPI */ 452#endif /* GSSAPI */
diff --git a/gss-serv.c b/gss-serv.c
index 117130459..05ae54e97 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -62,6 +62,28 @@ ssh_gssapi_mech* supported_mechs[]= {
62}; 62};
63 63
64/* Unpriviledged */ 64/* Unpriviledged */
65char *
66ssh_gssapi_server_mechanisms() {
67 gss_OID_set supported;
68
69 ssh_gssapi_supported_oids(&supported);
70 return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
71 NULL));
72}
73
74/* Unpriviledged */
75int
76ssh_gssapi_server_check_mech(gss_OID oid, void *data) {
77 Gssctxt * ctx = NULL;
78 int res;
79
80 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
81 ssh_gssapi_delete_ctx(&ctx);
82
83 return (res);
84}
85
86/* Unpriviledged */
65void 87void
66ssh_gssapi_supported_oids(gss_OID_set *oidset) 88ssh_gssapi_supported_oids(gss_OID_set *oidset)
67{ 89{
@@ -298,14 +320,4 @@ ssh_gssapi_userok(char *user)
298 return (0); 320 return (0);
299} 321}
300 322
301/* Priviledged */
302OM_uint32
303ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
304{
305 ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
306 gssbuf, gssmic, NULL);
307
308 return (ctx->major);
309}
310
311#endif 323#endif
diff --git a/kex.c b/kex.c
index 5dce335fe..8cd851d23 100644
--- a/kex.c
+++ b/kex.c
@@ -42,6 +42,10 @@ RCSID("$OpenBSD: kex.c,v 1.64 2005/07/25 11:59:39 markus Exp $");
42#include "dispatch.h" 42#include "dispatch.h"
43#include "monitor.h" 43#include "monitor.h"
44 44
45#ifdef GSSAPI
46#include "ssh-gss.h"
47#endif
48
45#define KEX_COOKIE_LEN 16 49#define KEX_COOKIE_LEN 16
46 50
47/* prototype */ 51/* prototype */
@@ -298,6 +302,14 @@ choose_kex(Kex *k, char *client, char *server)
298 k->kex_type = KEX_DH_GRP14_SHA1; 302 k->kex_type = KEX_DH_GRP14_SHA1;
299 } else if (strcmp(k->name, KEX_DHGEX) == 0) { 303 } else if (strcmp(k->name, KEX_DHGEX) == 0) {
300 k->kex_type = KEX_DH_GEX_SHA1; 304 k->kex_type = KEX_DH_GEX_SHA1;
305#ifdef GSSAPI
306 } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID,
307 sizeof(KEX_GSS_GEX_SHA1_ID)-1) == 0) {
308 k->kex_type = KEX_GSS_GEX_SHA1;
309 } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID,
310 sizeof(KEX_GSS_GRP1_SHA1_ID)-1) == 0) {
311 k->kex_type = KEX_GSS_GRP1_SHA1;
312#endif
301 } else 313 } else
302 fatal("bad kex alg %s", k->name); 314 fatal("bad kex alg %s", k->name);
303} 315}
diff --git a/kex.h b/kex.h
index 3024a2717..b458c2d1e 100644
--- a/kex.h
+++ b/kex.h
@@ -63,6 +63,8 @@ enum kex_exchange {
63 KEX_DH_GRP1_SHA1, 63 KEX_DH_GRP1_SHA1,
64 KEX_DH_GRP14_SHA1, 64 KEX_DH_GRP14_SHA1,
65 KEX_DH_GEX_SHA1, 65 KEX_DH_GEX_SHA1,
66 KEX_GSS_GRP1_SHA1,
67 KEX_GSS_GEX_SHA1,
66 KEX_MAX 68 KEX_MAX
67}; 69};
68 70
@@ -114,6 +116,11 @@ struct Kex {
114 Buffer peer; 116 Buffer peer;
115 int done; 117 int done;
116 int flags; 118 int flags;
119#ifdef GSSAPI
120 int gss_deleg_creds;
121 int gss_trust_dns;
122 char *gss_host;
123#endif
117 char *client_version_string; 124 char *client_version_string;
118 char *server_version_string; 125 char *server_version_string;
119 int (*verify_host_key)(Key *); 126 int (*verify_host_key)(Key *);
@@ -136,6 +143,11 @@ void kexdh_server(Kex *);
136void kexgex_client(Kex *); 143void kexgex_client(Kex *);
137void kexgex_server(Kex *); 144void kexgex_server(Kex *);
138 145
146#ifdef GSSAPI
147void kexgss_client(Kex *);
148void kexgss_server(Kex *);
149#endif
150
139u_char * 151u_char *
140kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, 152kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
141 BIGNUM *, BIGNUM *, BIGNUM *); 153 BIGNUM *, BIGNUM *, BIGNUM *);
diff --git a/kexgssc.c b/kexgssc.c
new file mode 100644
index 000000000..1843403b6
--- /dev/null
+++ b/kexgssc.c
@@ -0,0 +1,302 @@
1/*
2 * Copyright (c) 2001-2005 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 <openssl/crypto.h>
30#include <openssl/bn.h>
31
32#include "xmalloc.h"
33#include "buffer.h"
34#include "bufaux.h"
35#include "kex.h"
36#include "log.h"
37#include "packet.h"
38#include "dh.h"
39#include "canohost.h"
40#include "ssh2.h"
41#include "ssh-gss.h"
42
43void
44kexgss_client(Kex *kex) {
45 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
46 gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
47 Gssctxt *ctxt;
48 OM_uint32 maj_status, min_status, ret_flags;
49 unsigned int klen, kout;
50 DH *dh;
51 BIGNUM *dh_server_pub = NULL;
52 BIGNUM *shared_secret = NULL;
53 BIGNUM *p = NULL;
54 BIGNUM *g = NULL;
55 unsigned char *kbuf;
56 unsigned char *hash;
57 unsigned char *serverhostkey = NULL;
58 char *msg;
59 char *lang;
60 int type = 0;
61 int first = 1;
62 int slen = 0;
63 int gex = 0;
64 int nbits, min, max;
65 u_int strlen;
66
67 /* Initialise our GSSAPI world */
68 ssh_gssapi_build_ctx(&ctxt);
69 if (ssh_gssapi_id_kex(ctxt, kex->name, &gex) == NULL)
70 fatal("Couldn't identify host exchange");
71
72 if (ssh_gssapi_import_name(ctxt, kex->gss_host))
73 fatal("Couldn't import hostname");
74
75 if (gex) {
76 debug("Doing group exchange\n");
77 nbits = dh_estimate(kex->we_need * 8);
78 min = DH_GRP_MIN;
79 max = DH_GRP_MAX;
80 packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
81 packet_put_int(min);
82 packet_put_int(nbits);
83 packet_put_int(max);
84
85 packet_send();
86
87 packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
88
89 if ((p = BN_new()) == NULL)
90 fatal("BN_new() failed");
91 packet_get_bignum2(p);
92 if ((g = BN_new()) == NULL)
93 fatal("BN_new() failed");
94 packet_get_bignum2(g);
95 packet_check_eom();
96
97 if (BN_num_bits(p) < min || BN_num_bits(p) > max)
98 fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
99 min, BN_num_bits(p), max);
100
101 dh = dh_new_group(g, p);
102 } else {
103 dh = dh_new_group1();
104 }
105
106 /* Step 1 - e is dh->pub_key */
107 dh_gen_key(dh, kex->we_need * 8);
108
109 /* This is f, we initialise it now to make life easier */
110 dh_server_pub = BN_new();
111 if (dh_server_pub == NULL)
112 fatal("dh_server_pub == NULL");
113
114 token_ptr = GSS_C_NO_BUFFER;
115
116 do {
117 debug("Calling gss_init_sec_context");
118
119 maj_status = ssh_gssapi_init_ctx(ctxt,
120 kex->gss_deleg_creds, token_ptr, &send_tok,
121 &ret_flags);
122
123 if (GSS_ERROR(maj_status)) {
124 if (send_tok.length != 0) {
125 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
126 packet_put_string(send_tok.value,
127 send_tok.length);
128 }
129 fatal("gss_init_context failed");
130 }
131
132 /* If we've got an old receive buffer get rid of it */
133 if (token_ptr != GSS_C_NO_BUFFER)
134 xfree(recv_tok.value);
135
136 if (maj_status == GSS_S_COMPLETE) {
137 /* If mutual state flag is not true, kex fails */
138 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
139 fatal("Mutual authentication failed");
140
141 /* If integ avail flag is not true kex fails */
142 if (!(ret_flags & GSS_C_INTEG_FLAG))
143 fatal("Integrity check failed");
144 }
145
146 /*
147 * If we have data to send, then the last message that we
148 * received cannot have been a 'complete'.
149 */
150 if (send_tok.length != 0) {
151 if (first) {
152 packet_start(SSH2_MSG_KEXGSS_INIT);
153 packet_put_string(send_tok.value,
154 send_tok.length);
155 packet_put_bignum2(dh->pub_key);
156 first = 0;
157 } else {
158 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
159 packet_put_string(send_tok.value,
160 send_tok.length);
161 }
162 packet_send();
163 gss_release_buffer(&min_status, &send_tok);
164
165 /* If we've sent them data, they should reply */
166 do {
167 type = packet_read();
168 if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
169 debug("Received KEXGSS_HOSTKEY");
170 if (serverhostkey)
171 fatal("Server host key received more than once");
172 serverhostkey =
173 packet_get_string(&slen);
174 }
175 } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
176
177 switch (type) {
178 case SSH2_MSG_KEXGSS_CONTINUE:
179 debug("Received GSSAPI_CONTINUE");
180 if (maj_status == GSS_S_COMPLETE)
181 fatal("GSSAPI Continue received from server when complete");
182 recv_tok.value = packet_get_string(&strlen);
183 recv_tok.length = strlen;
184 break;
185 case SSH2_MSG_KEXGSS_COMPLETE:
186 debug("Received GSSAPI_COMPLETE");
187 packet_get_bignum2(dh_server_pub);
188 msg_tok.value = packet_get_string(&strlen);
189 msg_tok.length = strlen;
190
191 /* Is there a token included? */
192 if (packet_get_char()) {
193 recv_tok.value=
194 packet_get_string(&strlen);
195 recv_tok.length = strlen;
196 /* If we're already complete - protocol error */
197 if (maj_status == GSS_S_COMPLETE)
198 packet_disconnect("Protocol error: received token when complete");
199 } else {
200 /* No token included */
201 if (maj_status != GSS_S_COMPLETE)
202 packet_disconnect("Protocol error: did not receive final token");
203 }
204 break;
205 case SSH2_MSG_KEXGSS_ERROR:
206 debug("Received Error");
207 maj_status = packet_get_int();
208 min_status = packet_get_int();
209 msg = packet_get_string(NULL);
210 lang = packet_get_string(NULL);
211 fatal("GSSAPI Error: \n%s",msg);
212 default:
213 packet_disconnect("Protocol error: didn't expect packet type %d",
214 type);
215 }
216 token_ptr = &recv_tok;
217 } else {
218 /* No data, and not complete */
219 if (maj_status != GSS_S_COMPLETE)
220 fatal("Not complete, and no token output");
221 }
222 } while (maj_status & GSS_S_CONTINUE_NEEDED);
223
224 /*
225 * We _must_ have received a COMPLETE message in reply from the
226 * server, which will have set dh_server_pub and msg_tok
227 */
228
229 if (type != SSH2_MSG_KEXGSS_COMPLETE)
230 fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
231
232 /* Check f in range [1, p-1] */
233 if (!dh_pub_is_valid(dh, dh_server_pub))
234 packet_disconnect("bad server public DH value");
235
236 /* compute K=f^x mod p */
237 klen = DH_size(dh);
238 kbuf = xmalloc(klen);
239 kout = DH_compute_key(kbuf, dh_server_pub, dh);
240
241 shared_secret = BN_new();
242 BN_bin2bn(kbuf,kout, shared_secret);
243 memset(kbuf, 0, klen);
244 xfree(kbuf);
245
246 if (gex) {
247 hash = kexgex_hash( kex->client_version_string,
248 kex->server_version_string,
249 buffer_ptr(&kex->my), buffer_len(&kex->my),
250 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
251 serverhostkey, slen,
252 min, nbits, max,
253 dh->p, dh->g,
254 dh->pub_key,
255 dh_server_pub,
256 shared_secret
257 );
258 } else {
259 /* The GSS hash is identical to the DH one */
260 hash = kex_dh_hash( kex->client_version_string,
261 kex->server_version_string,
262 buffer_ptr(&kex->my), buffer_len(&kex->my),
263 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
264 serverhostkey, slen, /* server host key */
265 dh->pub_key, /* e */
266 dh_server_pub, /* f */
267 shared_secret /* K */
268 );
269 }
270
271 gssbuf.value = hash;
272 gssbuf.length = 20;
273
274 /* Verify that the hash matches the MIC we just got. */
275 if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
276 packet_disconnect("Hash's MIC didn't verify");
277
278 xfree(msg_tok.value);
279
280 DH_free(dh);
281 if (serverhostkey)
282 xfree(serverhostkey);
283 BN_clear_free(dh_server_pub);
284
285 /* save session id */
286 if (kex->session_id == NULL) {
287 kex->session_id_len = 20;
288 kex->session_id = xmalloc(kex->session_id_len);
289 memcpy(kex->session_id, hash, kex->session_id_len);
290 }
291
292 if (gss_kex_context == NULL)
293 gss_kex_context = ctxt;
294 else
295 ssh_gssapi_delete_ctx(&ctxt);
296
297 kex_derive_keys(kex, hash, shared_secret);
298 BN_clear_free(shared_secret);
299 kex_finish(kex);
300}
301
302#endif /* GSSAPI */
diff --git a/kexgsss.c b/kexgsss.c
new file mode 100644
index 000000000..268eeccae
--- /dev/null
+++ b/kexgsss.c
@@ -0,0 +1,254 @@
1/*
2 * Copyright (c) 2001-2005 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 <openssl/crypto.h>
30#include <openssl/bn.h>
31
32#include "xmalloc.h"
33#include "buffer.h"
34#include "bufaux.h"
35#include "kex.h"
36#include "log.h"
37#include "packet.h"
38#include "dh.h"
39#include "ssh2.h"
40#include "ssh-gss.h"
41#include "monitor_wrap.h"
42
43void
44kexgss_server(Kex *kex)
45{
46 OM_uint32 maj_status, min_status;
47
48 /*
49 * Some GSSAPI implementations use the input value of ret_flags (an
50 * output variable) as a means of triggering mechanism specific
51 * features. Initializing it to zero avoids inadvertently
52 * activating this non-standard behaviour.
53 */
54
55 OM_uint32 ret_flags = 0;
56 gss_buffer_desc gssbuf, recv_tok, msg_tok;
57 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
58 Gssctxt *ctxt = NULL;
59 unsigned int klen, kout;
60 unsigned char *kbuf, *hash;
61 DH *dh;
62 int min = -1, max = -1, nbits = -1;
63 BIGNUM *shared_secret = NULL;
64 BIGNUM *dh_client_pub = NULL;
65 int type = 0;
66 int gex;
67 u_int slen;
68 gss_OID oid;
69
70 /* Initialise GSSAPI */
71
72 /* If we're rekeying, privsep means that some of the private structures
73 * in the GSSAPI code are no longer available. This kludges them back
74 * into life
75 */
76 if (!ssh_gssapi_oid_table_ok())
77 ssh_gssapi_server_mechanisms();
78
79 debug2("%s: Identifying %s", __func__, kex->name);
80 oid = ssh_gssapi_id_kex(NULL, kex->name, &gex);
81 if (oid == NULL)
82 fatal("Unknown gssapi mechanism");
83
84 debug2("%s: Acquiring credentials", __func__);
85
86 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid))))
87 fatal("Unable to acquire credentials for the server");
88
89 if (gex) {
90 debug("Doing group exchange");
91 packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
92 min = packet_get_int();
93 nbits = packet_get_int();
94 max = packet_get_int();
95 min = MAX(DH_GRP_MIN, min);
96 max = MIN(DH_GRP_MAX, max);
97 packet_check_eom();
98 if (max < min || nbits < min || max < nbits)
99 fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
100 min, nbits, max);
101 dh = PRIVSEP(choose_dh(min, nbits, max));
102 if (dh == NULL)
103 packet_disconnect("Protocol error: no matching group found");
104
105 packet_start(SSH2_MSG_KEXGSS_GROUP);
106 packet_put_bignum2(dh->p);
107 packet_put_bignum2(dh->g);
108 packet_send();
109
110 packet_write_wait();
111
112 } else {
113 dh = dh_new_group1();
114 }
115 dh_gen_key(dh, kex->we_need * 8);
116
117 do {
118 debug("Wait SSH2_MSG_GSSAPI_INIT");
119 type = packet_read();
120 switch(type) {
121 case SSH2_MSG_KEXGSS_INIT:
122 if (dh_client_pub != NULL)
123 fatal("Received KEXGSS_INIT after initialising");
124 recv_tok.value = packet_get_string(&slen);
125 recv_tok.length = slen;
126
127 if ((dh_client_pub = BN_new()) == NULL)
128 fatal("dh_client_pub == NULL");
129
130 packet_get_bignum2(dh_client_pub);
131
132 /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
133 break;
134 case SSH2_MSG_KEXGSS_CONTINUE:
135 recv_tok.value = packet_get_string(&slen);
136 recv_tok.length = slen;
137 break;
138 default:
139 packet_disconnect(
140 "Protocol error: didn't expect packet type %d",
141 type);
142 }
143
144 maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok,
145 &send_tok, &ret_flags));
146
147 xfree(recv_tok.value);
148
149 if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
150 fatal("Zero length token output when incomplete");
151
152 if (dh_client_pub == NULL)
153 fatal("No client public key");
154
155 if (maj_status & GSS_S_CONTINUE_NEEDED) {
156 debug("Sending GSSAPI_CONTINUE");
157 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
158 packet_put_string(send_tok.value, send_tok.length);
159 packet_send();
160 gss_release_buffer(&min_status, &send_tok);
161 }
162 } while (maj_status & GSS_S_CONTINUE_NEEDED);
163
164 if (GSS_ERROR(maj_status)) {
165 if (send_tok.length > 0) {
166 packet_start(SSH2_MSG_KEXGSS_CONTINUE);
167 packet_put_string(send_tok.value, send_tok.length);
168 packet_send();
169 }
170 fatal("accept_ctx died");
171 }
172
173 if (!(ret_flags & GSS_C_MUTUAL_FLAG))
174 fatal("Mutual Authentication flag wasn't set");
175
176 if (!(ret_flags & GSS_C_INTEG_FLAG))
177 fatal("Integrity flag wasn't set");
178
179 if (!dh_pub_is_valid(dh, dh_client_pub))
180 packet_disconnect("bad client public DH value");
181
182 klen = DH_size(dh);
183 kbuf = xmalloc(klen);
184 kout = DH_compute_key(kbuf, dh_client_pub, dh);
185
186 shared_secret = BN_new();
187 BN_bin2bn(kbuf, kout, shared_secret);
188 memset(kbuf, 0, klen);
189 xfree(kbuf);
190
191 if (gex) {
192 hash = kexgex_hash(
193 kex->client_version_string, kex->server_version_string,
194 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
195 buffer_ptr(&kex->my), buffer_len(&kex->my),
196 NULL, 0,
197 min, nbits, max,
198 dh->p, dh->g,
199 dh_client_pub,
200 dh->pub_key,
201 shared_secret
202 );
203 }
204 else {
205 /* The GSSAPI hash is identical to the Diffie Helman one */
206 hash = kex_dh_hash(
207 kex->client_version_string, kex->server_version_string,
208 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
209 buffer_ptr(&kex->my), buffer_len(&kex->my),
210 NULL, 0, /* Change this if we start sending host keys */
211 dh_client_pub, dh->pub_key, shared_secret
212 );
213 }
214 BN_free(dh_client_pub);
215
216 if (kex->session_id == NULL) {
217 kex->session_id_len = 20;
218 kex->session_id = xmalloc(kex->session_id_len);
219 memcpy(kex->session_id, hash, kex->session_id_len);
220 }
221
222 gssbuf.value = hash;
223 gssbuf.length = 20; /* Hashlen appears to always be 20 */
224
225 if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
226 fatal("Couldn't get MIC");
227
228 packet_start(SSH2_MSG_KEXGSS_COMPLETE);
229 packet_put_bignum2(dh->pub_key);
230 packet_put_string((char *)msg_tok.value,msg_tok.length);
231
232 if (send_tok.length != 0) {
233 packet_put_char(1); /* true */
234 packet_put_string((char *)send_tok.value, send_tok.length);
235 } else {
236 packet_put_char(0); /* false */
237 }
238 packet_send();
239
240 gss_release_buffer(&min_status, &send_tok);
241 gss_release_buffer(&min_status, &msg_tok);
242
243 if (gss_kex_context == NULL)
244 gss_kex_context = ctxt;
245 else
246 ssh_gssapi_delete_ctx(&ctxt);
247
248 DH_free(dh);
249
250 kex_derive_keys(kex, hash, shared_secret);
251 BN_clear_free(shared_secret);
252 kex_finish(kex);
253}
254#endif /* GSSAPI */
diff --git a/key.c b/key.c
index 08c158b59..239a35919 100644
--- a/key.c
+++ b/key.c
@@ -650,6 +650,8 @@ key_type_from_name(char *name)
650 return KEY_RSA; 650 return KEY_RSA;
651 } else if (strcmp(name, "ssh-dss") == 0) { 651 } else if (strcmp(name, "ssh-dss") == 0) {
652 return KEY_DSA; 652 return KEY_DSA;
653 } else if (strcmp(name, "null") == 0) {
654 return KEY_NULL;
653 } 655 }
654 debug2("key_type_from_name: unknown key type '%s'", name); 656 debug2("key_type_from_name: unknown key type '%s'", name);
655 return KEY_UNSPEC; 657 return KEY_UNSPEC;
diff --git a/key.h b/key.h
index 50df8500b..6358e955f 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 ef613cd3c..86fe23931 100644
--- a/monitor.c
+++ b/monitor.c
@@ -141,6 +141,7 @@ int mm_answer_gss_setup_ctx(int, Buffer *);
141int mm_answer_gss_accept_ctx(int, Buffer *); 141int mm_answer_gss_accept_ctx(int, Buffer *);
142int mm_answer_gss_userok(int, Buffer *); 142int mm_answer_gss_userok(int, Buffer *);
143int mm_answer_gss_checkmic(int, Buffer *); 143int mm_answer_gss_checkmic(int, Buffer *);
144int mm_answer_gss_sign(int, Buffer *);
144#endif 145#endif
145 146
146#ifdef SSH_AUDIT_EVENTS 147#ifdef SSH_AUDIT_EVENTS
@@ -209,11 +210,17 @@ struct mon_table mon_dispatch_proto20[] = {
209 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, 210 {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
210 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, 211 {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
211 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, 212 {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
213 {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
212#endif 214#endif
213 {0, 0, NULL} 215 {0, 0, NULL}
214}; 216};
215 217
216struct mon_table mon_dispatch_postauth20[] = { 218struct mon_table mon_dispatch_postauth20[] = {
219#ifdef GSSAPI
220 {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
221 {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
222 {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
223#endif
217 {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, 224 {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
218 {MONITOR_REQ_SIGN, 0, mm_answer_sign}, 225 {MONITOR_REQ_SIGN, 0, mm_answer_sign},
219 {MONITOR_REQ_PTY, 0, mm_answer_pty}, 226 {MONITOR_REQ_PTY, 0, mm_answer_pty},
@@ -318,6 +325,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
318 /* Permit requests for moduli and signatures */ 325 /* Permit requests for moduli and signatures */
319 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 326 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
320 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 327 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
328#ifdef GSSAPI
329 /* and for the GSSAPI key exchange */
330 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
331#endif
321 } else { 332 } else {
322 mon_dispatch = mon_dispatch_proto15; 333 mon_dispatch = mon_dispatch_proto15;
323 334
@@ -391,6 +402,10 @@ monitor_child_postauth(struct monitor *pmonitor)
391 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); 402 monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
392 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); 403 monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
393 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 404 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
405#ifdef GSSAPI
406 /* and for the GSSAPI key exchange */
407 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
408#endif
394 } else { 409 } else {
395 mon_dispatch = mon_dispatch_postauth15; 410 mon_dispatch = mon_dispatch_postauth15;
396 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); 411 monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
@@ -1623,6 +1638,10 @@ mm_get_kex(Buffer *m)
1623 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 1638 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
1624 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; 1639 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
1625 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 1640 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
1641#ifdef GSSAPI
1642 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
1643 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
1644#endif
1626 kex->server = 1; 1645 kex->server = 1;
1627 kex->hostkey_type = buffer_get_int(m); 1646 kex->hostkey_type = buffer_get_int(m);
1628 kex->kex_type = buffer_get_int(m); 1647 kex->kex_type = buffer_get_int(m);
@@ -1865,6 +1884,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
1865 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); 1884 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
1866 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); 1885 monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
1867 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); 1886 monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
1887 monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
1868 } 1888 }
1869 return (0); 1889 return (0);
1870} 1890}
@@ -1915,4 +1935,42 @@ mm_answer_gss_userok(int sock, Buffer *m)
1915 /* Monitor loop will terminate if authenticated */ 1935 /* Monitor loop will terminate if authenticated */
1916 return (authenticated); 1936 return (authenticated);
1917} 1937}
1938
1939int
1940mm_answer_gss_sign(int socket, Buffer *m)
1941{
1942 gss_buffer_desc data;
1943 gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
1944 OM_uint32 major, minor;
1945 u_int len;
1946
1947 data.value = buffer_get_string(m, &len);
1948 data.length = len;
1949 if (data.length != 20)
1950 fatal("%s: data length incorrect: %d", __func__, data.length);
1951
1952 /* Save the session ID on the first time around */
1953 if (session_id2_len == 0) {
1954 session_id2_len = data.length;
1955 session_id2 = xmalloc(session_id2_len);
1956 memcpy(session_id2, data.value, session_id2_len);
1957 }
1958 major = ssh_gssapi_sign(gsscontext, &data, &hash);
1959
1960 xfree(data.value);
1961
1962 buffer_clear(m);
1963 buffer_put_int(m, major);
1964 buffer_put_string(m, hash.value, hash.length);
1965
1966 mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
1967
1968 gss_release_buffer(&minor, &hash);
1969
1970 /* Turn on getpwnam permissions */
1971 monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
1972
1973 return (0);
1974}
1975
1918#endif /* GSSAPI */ 1976#endif /* GSSAPI */
diff --git a/monitor.h b/monitor.h
index 13ce3e1ca..7b306b4af 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 1489e7f08..72b75d50a 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1216,4 +1216,27 @@ mm_ssh_gssapi_userok(char *user)
1216 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); 1216 debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
1217 return (authenticated); 1217 return (authenticated);
1218} 1218}
1219
1220OM_uint32
1221mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
1222{
1223 Buffer m;
1224 OM_uint32 major;
1225 u_int len;
1226
1227 buffer_init(&m);
1228 buffer_put_string(&m, data->value, data->length);
1229
1230 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
1231 mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
1232
1233 major = buffer_get_int(&m);
1234 hash->value = buffer_get_string(&m, &len);
1235 hash->length = len;
1236
1237 buffer_free(&m);
1238
1239 return(major);
1240}
1241
1219#endif /* GSSAPI */ 1242#endif /* GSSAPI */
diff --git a/monitor_wrap.h b/monitor_wrap.h
index 310b42513..871eabb9d 100644
--- a/monitor_wrap.h
+++ b/monitor_wrap.h
@@ -63,6 +63,7 @@ OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
63 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); 63 gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
64int mm_ssh_gssapi_userok(char *user); 64int mm_ssh_gssapi_userok(char *user);
65OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 65OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
66OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
66#endif 67#endif
67 68
68#ifdef USE_PAM 69#ifdef USE_PAM
diff --git a/readconf.c b/readconf.c
index cf27a9f41..345df9c25 100644
--- a/readconf.c
+++ b/readconf.c
@@ -105,6 +105,7 @@ typedef enum {
105 oClearAllForwardings, oNoHostAuthenticationForLocalhost, 105 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
106 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 106 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
107 oAddressFamily, oGssAuthentication, oGssDelegateCreds, 107 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
108 oGssTrustDns,
108 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 109 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
109 oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, 110 oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
110 oDeprecated, oUnsupported 111 oDeprecated, oUnsupported
@@ -140,9 +141,11 @@ static struct {
140#if defined(GSSAPI) 141#if defined(GSSAPI)
141 { "gssapiauthentication", oGssAuthentication }, 142 { "gssapiauthentication", oGssAuthentication },
142 { "gssapidelegatecredentials", oGssDelegateCreds }, 143 { "gssapidelegatecredentials", oGssDelegateCreds },
144 { "gssapitrustdns", oGssTrustDns },
143#else 145#else
144 { "gssapiauthentication", oUnsupported }, 146 { "gssapiauthentication", oUnsupported },
145 { "gssapidelegatecredentials", oUnsupported }, 147 { "gssapidelegatecredentials", oUnsupported },
148 { "gssapitrustdns", oUnsupported },
146#endif 149#endif
147 { "fallbacktorsh", oDeprecated }, 150 { "fallbacktorsh", oDeprecated },
148 { "usersh", oDeprecated }, 151 { "usersh", oDeprecated },
@@ -410,6 +413,10 @@ parse_flag:
410 intptr = &options->gss_deleg_creds; 413 intptr = &options->gss_deleg_creds;
411 goto parse_flag; 414 goto parse_flag;
412 415
416 case oGssTrustDns:
417 intptr = &options->gss_trust_dns;
418 goto parse_flag;
419
413 case oBatchMode: 420 case oBatchMode:
414 intptr = &options->batch_mode; 421 intptr = &options->batch_mode;
415 goto parse_flag; 422 goto parse_flag;
@@ -917,6 +924,7 @@ initialize_options(Options * options)
917 options->challenge_response_authentication = -1; 924 options->challenge_response_authentication = -1;
918 options->gss_authentication = -1; 925 options->gss_authentication = -1;
919 options->gss_deleg_creds = -1; 926 options->gss_deleg_creds = -1;
927 options->gss_trust_dns = -1;
920 options->password_authentication = -1; 928 options->password_authentication = -1;
921 options->kbd_interactive_authentication = -1; 929 options->kbd_interactive_authentication = -1;
922 options->kbd_interactive_devices = NULL; 930 options->kbd_interactive_devices = NULL;
@@ -1000,6 +1008,8 @@ fill_default_options(Options * options)
1000 options->gss_authentication = 0; 1008 options->gss_authentication = 0;
1001 if (options->gss_deleg_creds == -1) 1009 if (options->gss_deleg_creds == -1)
1002 options->gss_deleg_creds = 0; 1010 options->gss_deleg_creds = 0;
1011 if (options->gss_trust_dns == -1)
1012 options->gss_trust_dns = 0;
1003 if (options->password_authentication == -1) 1013 if (options->password_authentication == -1)
1004 options->password_authentication = 1; 1014 options->password_authentication = 1;
1005 if (options->kbd_interactive_authentication == -1) 1015 if (options->kbd_interactive_authentication == -1)
diff --git a/readconf.h b/readconf.h
index 2b9deb9db..b403c10ec 100644
--- a/readconf.h
+++ b/readconf.h
@@ -46,6 +46,7 @@ typedef struct {
46 /* Try S/Key or TIS, authentication. */ 46 /* Try S/Key or TIS, authentication. */
47 int gss_authentication; /* Try GSS authentication */ 47 int gss_authentication; /* Try GSS authentication */
48 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 */
49 int password_authentication; /* Try password 50 int password_authentication; /* Try password
50 * authentication. */ 51 * authentication. */
51 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 9e420a527..becd5b7c5 100644
--- a/servconf.c
+++ b/servconf.c
@@ -72,6 +72,7 @@ initialize_server_options(ServerOptions *options)
72 options->kerberos_ticket_cleanup = -1; 72 options->kerberos_ticket_cleanup = -1;
73 options->kerberos_get_afs_token = -1; 73 options->kerberos_get_afs_token = -1;
74 options->gss_authentication=-1; 74 options->gss_authentication=-1;
75 options->gss_keyex = -1;
75 options->gss_cleanup_creds = -1; 76 options->gss_cleanup_creds = -1;
76 options->password_authentication = -1; 77 options->password_authentication = -1;
77 options->kbd_interactive_authentication = -1; 78 options->kbd_interactive_authentication = -1;
@@ -186,6 +187,8 @@ fill_default_server_options(ServerOptions *options)
186 options->kerberos_get_afs_token = 0; 187 options->kerberos_get_afs_token = 0;
187 if (options->gss_authentication == -1) 188 if (options->gss_authentication == -1)
188 options->gss_authentication = 0; 189 options->gss_authentication = 0;
190 if (options->gss_keyex == -1)
191 options->gss_keyex = 0;
189 if (options->gss_cleanup_creds == -1) 192 if (options->gss_cleanup_creds == -1)
190 options->gss_cleanup_creds = 1; 193 options->gss_cleanup_creds = 1;
191 if (options->password_authentication == -1) 194 if (options->password_authentication == -1)
@@ -270,7 +273,7 @@ typedef enum {
270 sBanner, sUseDNS, sHostbasedAuthentication, 273 sBanner, sUseDNS, sHostbasedAuthentication,
271 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 274 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
272 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, 275 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
273 sGssAuthentication, sGssCleanupCreds, sAcceptEnv, 276 sGssAuthentication, sGssKeyEx, sGssCleanupCreds, sAcceptEnv,
274 sUsePrivilegeSeparation, 277 sUsePrivilegeSeparation,
275 sDeprecated, sUnsupported 278 sDeprecated, sUnsupported
276} ServerOpCodes; 279} ServerOpCodes;
@@ -324,9 +327,11 @@ static struct {
324 { "afstokenpassing", sUnsupported }, 327 { "afstokenpassing", sUnsupported },
325#ifdef GSSAPI 328#ifdef GSSAPI
326 { "gssapiauthentication", sGssAuthentication }, 329 { "gssapiauthentication", sGssAuthentication },
330 { "gssapikeyexchange", sGssKeyEx },
327 { "gssapicleanupcredentials", sGssCleanupCreds }, 331 { "gssapicleanupcredentials", sGssCleanupCreds },
328#else 332#else
329 { "gssapiauthentication", sUnsupported }, 333 { "gssapiauthentication", sUnsupported },
334 { "gssapikeyexchange", sUnsupported },
330 { "gssapicleanupcredentials", sUnsupported }, 335 { "gssapicleanupcredentials", sUnsupported },
331#endif 336#endif
332 { "passwordauthentication", sPasswordAuthentication }, 337 { "passwordauthentication", sPasswordAuthentication },
@@ -669,6 +674,10 @@ parse_flag:
669 intptr = &options->gss_authentication; 674 intptr = &options->gss_authentication;
670 goto parse_flag; 675 goto parse_flag;
671 676
677 case sGssKeyEx:
678 intptr = &options->gss_keyex;
679 goto parse_flag;
680
672 case sGssCleanupCreds: 681 case sGssCleanupCreds:
673 intptr = &options->gss_cleanup_creds; 682 intptr = &options->gss_cleanup_creds;
674 goto parse_flag; 683 goto parse_flag;
diff --git a/servconf.h b/servconf.h
index f7e56d521..3e4e07e08 100644
--- a/servconf.h
+++ b/servconf.h
@@ -88,6 +88,7 @@ typedef struct {
88 int kerberos_get_afs_token; /* If true, try to get AFS token if 88 int kerberos_get_afs_token; /* If true, try to get AFS token if
89 * authenticated with Kerberos. */ 89 * authenticated with Kerberos. */
90 int gss_authentication; /* If true, permit GSSAPI authentication */ 90 int gss_authentication; /* If true, permit GSSAPI authentication */
91 int gss_keyex; /* If true, permit GSSAPI key exchange */
91 int gss_cleanup_creds; /* If true, destroy cred cache on logout */ 92 int gss_cleanup_creds; /* If true, destroy cred cache on logout */
92 int password_authentication; /* If true, permit password 93 int password_authentication; /* If true, permit password
93 * authentication. */ 94 * authentication. */
diff --git a/ssh-gss.h b/ssh-gss.h
index 52fb49a6f..213930103 100644
--- a/ssh-gss.h
+++ b/ssh-gss.h
@@ -62,6 +62,16 @@
62 62
63#define SSH_GSS_OIDTYPE 0x06 63#define SSH_GSS_OIDTYPE 0x06
64 64
65#define SSH2_MSG_KEXGSS_INIT 30
66#define SSH2_MSG_KEXGSS_CONTINUE 31
67#define SSH2_MSG_KEXGSS_COMPLETE 32
68#define SSH2_MSG_KEXGSS_HOSTKEY 33
69#define SSH2_MSG_KEXGSS_ERROR 34
70#define SSH2_MSG_KEXGSS_GROUPREQ 40
71#define SSH2_MSG_KEXGSS_GROUP 41
72#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-"
73#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-"
74
65typedef struct { 75typedef struct {
66 char *filename; 76 char *filename;
67 char *envvar; 77 char *envvar;
@@ -99,6 +109,7 @@ typedef struct {
99} Gssctxt; 109} Gssctxt;
100 110
101extern ssh_gssapi_mech *supported_mechs[]; 111extern ssh_gssapi_mech *supported_mechs[];
112extern Gssctxt *gss_kex_context;
102 113
103int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); 114int ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
104void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); 115void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
@@ -121,13 +132,20 @@ OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
121OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); 132OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
122void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); 133void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
123 134
124/* In the server */ 135typedef int ssh_gssapi_check_fn(gss_OID, void *);
136char *ssh_gssapi_client_mechanisms(const char *host);
137char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, void *);
138int ssh_gssapi_check_mechanism(gss_OID, void *);
139gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int *);
140
141int ssh_gssapi_server_check_mech(gss_OID, void *);
125int ssh_gssapi_userok(char *name); 142int ssh_gssapi_userok(char *name);
126OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); 143OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
127void ssh_gssapi_do_child(char ***, u_int *); 144void ssh_gssapi_do_child(char ***, u_int *);
128void ssh_gssapi_cleanup_creds(void); 145void ssh_gssapi_cleanup_creds(void);
129void ssh_gssapi_storecreds(void); 146void ssh_gssapi_storecreds(void);
130 147char * ssh_gssapi_server_mechanisms(void);
148int ssh_gssapi_oid_table_ok();
131#endif /* GSSAPI */ 149#endif /* GSSAPI */
132 150
133#endif /* _SSH_GSS_H */ 151#endif /* _SSH_GSS_H */
diff --git a/ssh_config.5 b/ssh_config.5
index 9ddb09480..9033185b1 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -447,6 +447,16 @@ Forward (delegate) credentials to the server.
447The default is 447The default is
448.Dq no . 448.Dq no .
449Note that this option applies to protocol version 2 only. 449Note that this option applies to protocol version 2 only.
450.It Cm GSSAPITrustDns
451Set to
452.Dq yes to indicate that the DNS is trusted to securely canonicalize
453the name of the host being connected to. If
454.Dq no, the hostname entered on the
455command line will be passed untouched to the GSSAPI library.
456The default is
457.Dq no .
458This option only applies to protocol version 2 connections using GSSAPI
459key exchange.
450.It Cm HashKnownHosts 460.It Cm HashKnownHosts
451Indicates that 461Indicates that
452.Nm ssh 462.Nm ssh
diff --git a/sshconnect2.c b/sshconnect2.c
index ee7932d68..aa0b6ec59 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -84,9 +84,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
84{ 84{
85 Kex *kex; 85 Kex *kex;
86 86
87#ifdef GSSAPI
88 char *orig, *gss;
89 int len;
90 char *gss_host;
91#endif
92
87 xxx_host = host; 93 xxx_host = host;
88 xxx_hostaddr = hostaddr; 94 xxx_hostaddr = hostaddr;
89 95
96#ifdef GSSAPI
97 /* Add the GSSAPI mechanisms currently supported on this client to
98 * the key exchange algorithm proposal */
99 orig = myproposal[PROPOSAL_KEX_ALGS];
100 if (options.gss_trust_dns)
101 gss_host = (char *)get_canonical_hostname(1);
102 else
103 gss_host = host;
104
105 gss = ssh_gssapi_client_mechanisms(gss_host);
106 if (gss) {
107 debug("Offering GSSAPI proposal: %s", gss);
108 len = strlen(orig) + strlen(gss) + 2;
109 myproposal[PROPOSAL_KEX_ALGS] = xmalloc(len);
110 snprintf(myproposal[PROPOSAL_KEX_ALGS], len, "%s,%s", gss,
111 orig);
112 }
113#endif
114
90 if (options.ciphers == (char *)-1) { 115 if (options.ciphers == (char *)-1) {
91 logit("No valid ciphers for protocol version 2 given, using defaults."); 116 logit("No valid ciphers for protocol version 2 given, using defaults.");
92 options.ciphers = NULL; 117 options.ciphers = NULL;
@@ -114,6 +139,18 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
114 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = 139 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
115 options.hostkeyalgorithms; 140 options.hostkeyalgorithms;
116 141
142#ifdef GSSAPI
143 /* If we've got GSSAPI algorithms, then we also support the
144 * 'null' hostkey, as a last resort */
145 if (gss) {
146 orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
147 len = strlen(orig) + sizeof(",null");
148 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = xmalloc(len);
149 snprintf(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], len,
150 "%s,null", orig);
151 }
152#endif
153
117 if (options.rekey_limit) 154 if (options.rekey_limit)
118 packet_set_rekey_limit(options.rekey_limit); 155 packet_set_rekey_limit(options.rekey_limit);
119 156
@@ -122,10 +159,20 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
122 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; 159 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
123 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; 160 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
124 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; 161 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
162#ifdef GSSAPI
163 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
164 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
165#endif
125 kex->client_version_string=client_version_string; 166 kex->client_version_string=client_version_string;
126 kex->server_version_string=server_version_string; 167 kex->server_version_string=server_version_string;
127 kex->verify_host_key=&verify_host_key_callback; 168 kex->verify_host_key=&verify_host_key_callback;
128 169
170#ifdef GSSAPI
171 kex->gss_deleg_creds = options.gss_deleg_creds;
172 kex->gss_trust_dns = options.gss_trust_dns;
173 kex->gss_host = gss_host;
174#endif
175
129 xxx_kex = kex; 176 xxx_kex = kex;
130 177
131 dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 178 dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -208,6 +255,7 @@ void input_gssapi_token(int type, u_int32_t, void *);
208void input_gssapi_hash(int type, u_int32_t, void *); 255void input_gssapi_hash(int type, u_int32_t, void *);
209void input_gssapi_error(int, u_int32_t, void *); 256void input_gssapi_error(int, u_int32_t, void *);
210void input_gssapi_errtok(int, u_int32_t, void *); 257void input_gssapi_errtok(int, u_int32_t, void *);
258int userauth_gsskeyex(Authctxt *authctxt);
211#endif 259#endif
212 260
213void userauth(Authctxt *, char *); 261void userauth(Authctxt *, char *);
@@ -223,6 +271,10 @@ static char *authmethods_get(void);
223 271
224Authmethod authmethods[] = { 272Authmethod authmethods[] = {
225#ifdef GSSAPI 273#ifdef GSSAPI
274 {"gssapi-keyex",
275 userauth_gsskeyex,
276 &options.gss_authentication,
277 NULL},
226 {"gssapi-with-mic", 278 {"gssapi-with-mic",
227 userauth_gssapi, 279 userauth_gssapi,
228 &options.gss_authentication, 280 &options.gss_authentication,
@@ -706,6 +758,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
706 xfree(msg); 758 xfree(msg);
707 xfree(lang); 759 xfree(lang);
708} 760}
761
762int
763userauth_gsskeyex(Authctxt *authctxt)
764{
765 Buffer b;
766 gss_buffer_desc gssbuf;
767 gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
768 OM_uint32 ms;
769
770 static int attempt = 0;
771 if (attempt++ >= 1)
772 return (0);
773
774 if (gss_kex_context == NULL) {
775 debug("No valid Key exchange context");
776 return (0);
777 }
778
779 ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
780 "gssapi-keyex");
781
782 gssbuf.value = buffer_ptr(&b);
783 gssbuf.length = buffer_len(&b);
784
785 if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
786 buffer_free(&b);
787 return (0);
788 }
789
790 packet_start(SSH2_MSG_USERAUTH_REQUEST);
791 packet_put_cstring(authctxt->server_user);
792 packet_put_cstring(authctxt->service);
793 packet_put_cstring(authctxt->method->name);
794 packet_put_string(mic.value, mic.length);
795 packet_send();
796
797 buffer_free(&b);
798 gss_release_buffer(&ms, &mic);
799
800 return (1);
801}
802
709#endif /* GSSAPI */ 803#endif /* GSSAPI */
710 804
711int 805int
diff --git a/sshd.c b/sshd.c
index 92aa9bbd2..da0b26587 100644
--- a/sshd.c
+++ b/sshd.c
@@ -86,6 +86,10 @@ RCSID("$OpenBSD: sshd.c,v 1.312 2005/07/25 11:59:40 markus Exp $");
86#include "monitor_wrap.h" 86#include "monitor_wrap.h"
87#include "monitor_fdpass.h" 87#include "monitor_fdpass.h"
88 88
89#ifdef USE_SECURITY_SESSION_API
90#include <Security/AuthSession.h>
91#endif
92
89#ifdef LIBWRAP 93#ifdef LIBWRAP
90#include <tcpd.h> 94#include <tcpd.h>
91#include <syslog.h> 95#include <syslog.h>
@@ -1117,10 +1121,13 @@ main(int ac, char **av)
1117 logit("Disabling protocol version 1. Could not load host key"); 1121 logit("Disabling protocol version 1. Could not load host key");
1118 options.protocol &= ~SSH_PROTO_1; 1122 options.protocol &= ~SSH_PROTO_1;
1119 } 1123 }
1124#ifndef GSSAPI
1125 /* The GSSAPI key exchange can run without a host key */
1120 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { 1126 if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
1121 logit("Disabling protocol version 2. Could not load host key"); 1127 logit("Disabling protocol version 2. Could not load host key");
1122 options.protocol &= ~SSH_PROTO_2; 1128 options.protocol &= ~SSH_PROTO_2;
1123 } 1129 }
1130#endif
1124 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { 1131 if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
1125 logit("sshd: no hostkeys available -- exiting."); 1132 logit("sshd: no hostkeys available -- exiting.");
1126 exit(1); 1133 exit(1);
@@ -1663,6 +1670,62 @@ main(int ac, char **av)
1663 /* Log the connection. */ 1670 /* Log the connection. */
1664 verbose("Connection from %.500s port %d", remote_ip, remote_port); 1671 verbose("Connection from %.500s port %d", remote_ip, remote_port);
1665 1672
1673#ifdef USE_SECURITY_SESSION_API
1674 /*
1675 * Create a new security session for use by the new user login if
1676 * the current session is the root session or we are not launched
1677 * by inetd (eg: debugging mode or server mode). We do not
1678 * necessarily need to create a session if we are launched from
1679 * inetd because Panther xinetd will create a session for us.
1680 *
1681 * The only case where this logic will fail is if there is an
1682 * inetd running in a non-root session which is not creating
1683 * new sessions for us. Then all the users will end up in the
1684 * same session (bad).
1685 *
1686 * When the client exits, the session will be destroyed for us
1687 * automatically.
1688 *
1689 * We must create the session before any credentials are stored
1690 * (including AFS pags, which happens a few lines below).
1691 */
1692 {
1693 OSStatus err = 0;
1694 SecuritySessionId sid = 0;
1695 SessionAttributeBits sattrs = 0;
1696
1697 err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
1698 if (err)
1699 error("SessionGetInfo() failed with error %.8X",
1700 (unsigned) err);
1701 else
1702 debug("Current Session ID is %.8X / Session Attributes a
1703re %.8X",
1704 (unsigned) sid, (unsigned) sattrs);
1705
1706 if (inetd_flag && !(sattrs & sessionIsRoot))
1707 debug("Running in inetd mode in a non-root session... "
1708 "assuming inetd created the session for us.");
1709 else {
1710 debug("Creating new security session...");
1711 err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
1712 if (err)
1713 error("SessionCreate() failed with error %.8X",
1714 (unsigned) err);
1715
1716 err = SessionGetInfo(callerSecuritySession, &sid,
1717 &sattrs);
1718 if (err)
1719 error("SessionGetInfo() failed with error %.8X",
1720 (unsigned) err);
1721 else
1722 debug("New Session ID is %.8X / Session Attribut
1723es are %.8X",
1724 (unsigned) sid, (unsigned) sattrs);
1725 }
1726 }
1727#endif
1728
1666 /* 1729 /*
1667 * We don\'t want to listen forever unless the other side 1730 * We don\'t want to listen forever unless the other side
1668 * successfully authenticates itself. So we set up an alarm which is 1731 * successfully authenticates itself. So we set up an alarm which is
@@ -2006,13 +2069,63 @@ do_ssh2_kex(void)
2006 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); 2069 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
2007 2070
2008 /* start key exchange */ 2071 /* start key exchange */
2009 kex = kex_setup(myproposal); 2072
2010 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 2073#ifdef GSSAPI
2074 {
2075 char *orig;
2076 char *gss = NULL;
2077 char *newstr = NULL;
2078 orig = myproposal[PROPOSAL_KEX_ALGS];
2079
2080 /*
2081 * If we don't have a host key, then there's no point advertising
2082 * the other key exchange algorithms
2083 */
2084
2085 if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
2086 orig = NULL;
2087
2088 if (options.gss_keyex)
2089 gss = ssh_gssapi_server_mechanisms();
2090 else
2091 gss = NULL;
2092
2093 if (gss && orig) {
2094 int len = strlen(orig) + strlen(gss) + 2;
2095 newstr = xmalloc(len);
2096 snprintf(newstr, len, "%s,%s", gss, orig);
2097 } else if (gss) {
2098 newstr = gss;
2099 } else if (orig) {
2100 newstr = orig;
2101 }
2102 /*
2103 * If we've got GSSAPI mechanisms, then we've got the 'null' host
2104 * key alg, but we can't tell people about it unless its the only
2105 * host key algorithm we support
2106 */
2107 if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
2108 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
2109
2110 if (newstr)
2111 myproposal[PROPOSAL_KEX_ALGS] = newstr;
2112 else
2113 fatal("No supported key exchange algorithms");
2114 }
2115#endif
2116
2117 /* start key exchange */
2118 kex = kex_setup(myproposal);
2119 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
2011 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; 2120 kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
2012 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 2121 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
2013 kex->server = 1; 2122#ifdef GSSAPI
2014 kex->client_version_string=client_version_string; 2123 kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
2015 kex->server_version_string=server_version_string; 2124 kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
2125#endif
2126 kex->server = 1;
2127 kex->client_version_string=client_version_string;
2128 kex->server_version_string=server_version_string;
2016 kex->load_host_key=&get_hostkey_by_type; 2129 kex->load_host_key=&get_hostkey_by_type;
2017 kex->host_key_index=&get_hostkey_index; 2130 kex->host_key_index=&get_hostkey_index;
2018 2131
diff --git a/sshd_config.5 b/sshd_config.5
index 048e8924e..5af4b1b27 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -277,6 +277,12 @@ Specifies whether user authentication based on GSSAPI is allowed.
277The default is 277The default is
278.Dq no . 278.Dq no .
279Note that this option applies to protocol version 2 only. 279Note that this option applies to protocol version 2 only.
280.It Cm GSSAPIKeyExchange
281Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange
282doesn't rely on ssh keys to verify host identity.
283The default is
284.Dq no .
285Note that this option applies to protocol version 2 only.
280.It Cm GSSAPICleanupCredentials 286.It Cm GSSAPICleanupCredentials
281Specifies whether to automatically destroy the user's credentials cache 287Specifies whether to automatically destroy the user's credentials cache
282on logout. 288on logout.