diff options
Diffstat (limited to 'gss-genr.c')
-rw-r--r-- | gss-genr.c | 176 |
1 files changed, 87 insertions, 89 deletions
diff --git a/gss-genr.c b/gss-genr.c index dfaa708ea..42f942b58 100644 --- a/gss-genr.c +++ b/gss-genr.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* $OpenBSD: gss-genr.c,v 1.6 2005/10/13 22:24:31 stevesk Exp $ */ | 1 | /* $OpenBSD: gss-genr.c,v 1.17 2006/08/29 12:02:30 dtucker Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2001-2005 Simon Wilkinson. All rights reserved. | 4 | * Copyright (c) 2001-2006 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 |
@@ -28,10 +28,20 @@ | |||
28 | 28 | ||
29 | #ifdef GSSAPI | 29 | #ifdef GSSAPI |
30 | 30 | ||
31 | #include <sys/types.h> | ||
32 | #include <sys/param.h> | ||
33 | |||
34 | #include <stdarg.h> | ||
35 | #include <string.h> | ||
36 | #include <unistd.h> | ||
37 | |||
31 | #include "xmalloc.h" | 38 | #include "xmalloc.h" |
32 | #include "bufaux.h" | 39 | #include "buffer.h" |
33 | #include "log.h" | 40 | #include "log.h" |
34 | #include "ssh2.h" | 41 | #include "ssh2.h" |
42 | #include "cipher.h" | ||
43 | #include "key.h" | ||
44 | #include "kex.h" | ||
35 | #include <openssl/evp.h> | 45 | #include <openssl/evp.h> |
36 | 46 | ||
37 | #include "ssh-gss.h" | 47 | #include "ssh-gss.h" |
@@ -65,7 +75,6 @@ ssh_gssapi_oid_table_ok() { | |||
65 | * a key exchange with a bad mechanism | 75 | * a key exchange with a bad mechanism |
66 | */ | 76 | */ |
67 | 77 | ||
68 | |||
69 | char * | 78 | char * |
70 | ssh_gssapi_client_mechanisms(const char *host) { | 79 | ssh_gssapi_client_mechanisms(const char *host) { |
71 | gss_OID_set gss_supported; | 80 | gss_OID_set gss_supported; |
@@ -74,35 +83,36 @@ ssh_gssapi_client_mechanisms(const char *host) { | |||
74 | gss_indicate_mechs(&min_status, &gss_supported); | 83 | gss_indicate_mechs(&min_status, &gss_supported); |
75 | 84 | ||
76 | return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, | 85 | return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, |
77 | (void *)host)); | 86 | host)); |
78 | } | 87 | } |
79 | 88 | ||
80 | char * | 89 | char * |
81 | ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, | 90 | ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, |
82 | void *data) { | 91 | const char *data) { |
83 | Buffer buf; | 92 | Buffer buf; |
84 | int i, oidpos, enclen; | 93 | size_t i; |
94 | int oidpos, enclen; | ||
85 | char *mechs, *encoded; | 95 | char *mechs, *encoded; |
86 | char digest[EVP_MAX_MD_SIZE]; | 96 | u_char digest[EVP_MAX_MD_SIZE]; |
87 | char deroid[2]; | 97 | char deroid[2]; |
88 | const EVP_MD *evp_md = EVP_md5(); | 98 | const EVP_MD *evp_md = EVP_md5(); |
89 | EVP_MD_CTX md; | 99 | EVP_MD_CTX md; |
90 | 100 | ||
91 | if (gss_enc2oid != NULL) { | 101 | if (gss_enc2oid != NULL) { |
92 | for (i=0;gss_enc2oid[i].encoded!=NULL;i++) | 102 | for (i = 0; gss_enc2oid[i].encoded != NULL; i++) |
93 | xfree(gss_enc2oid[i].encoded); | 103 | xfree(gss_enc2oid[i].encoded); |
94 | xfree(gss_enc2oid); | 104 | xfree(gss_enc2oid); |
95 | } | 105 | } |
96 | 106 | ||
97 | gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping)* | 107 | gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) * |
98 | (gss_supported->count+1)); | 108 | (gss_supported->count + 1)); |
99 | 109 | ||
100 | buffer_init(&buf); | 110 | buffer_init(&buf); |
101 | 111 | ||
102 | oidpos = 0; | 112 | oidpos = 0; |
103 | for (i = 0;i < gss_supported->count;i++) { | 113 | for (i = 0; i < gss_supported->count; i++) { |
104 | if (gss_supported->elements[i].length < 128 && | 114 | if (gss_supported->elements[i].length < 128 && |
105 | (*check)(&(gss_supported->elements[i]), data)) { | 115 | (*check)(NULL, &(gss_supported->elements[i]), data)) { |
106 | 116 | ||
107 | deroid[0] = SSH_GSS_OIDTYPE; | 117 | deroid[0] = SSH_GSS_OIDTYPE; |
108 | deroid[1] = gss_supported->elements[i].length; | 118 | deroid[1] = gss_supported->elements[i].length; |
@@ -114,19 +124,23 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, | |||
114 | gss_supported->elements[i].length); | 124 | gss_supported->elements[i].length); |
115 | EVP_DigestFinal(&md, digest, NULL); | 125 | EVP_DigestFinal(&md, digest, NULL); |
116 | 126 | ||
117 | encoded = xmalloc(EVP_MD_size(evp_md)*2); | 127 | encoded = xmalloc(EVP_MD_size(evp_md) * 2); |
118 | enclen = __b64_ntop(digest, EVP_MD_size(evp_md), | 128 | enclen = __b64_ntop(digest, EVP_MD_size(evp_md), |
119 | encoded, EVP_MD_size(evp_md)*2); | 129 | encoded, EVP_MD_size(evp_md) * 2); |
120 | 130 | ||
121 | if (oidpos != 0) | 131 | if (oidpos != 0) |
122 | buffer_put_char(&buf, ','); | 132 | buffer_put_char(&buf, ','); |
123 | 133 | ||
124 | buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, | 134 | buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, |
125 | sizeof(KEX_GSS_GEX_SHA1_ID)-1); | 135 | sizeof(KEX_GSS_GEX_SHA1_ID) - 1); |
126 | buffer_append(&buf, encoded, enclen); | 136 | buffer_append(&buf, encoded, enclen); |
127 | buffer_put_char(&buf,','); | 137 | buffer_put_char(&buf, ','); |
128 | buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, | 138 | buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, |
129 | sizeof(KEX_GSS_GRP1_SHA1_ID)-1); | 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); | ||
130 | buffer_append(&buf, encoded, enclen); | 144 | buffer_append(&buf, encoded, enclen); |
131 | 145 | ||
132 | gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); | 146 | gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); |
@@ -152,25 +166,26 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, | |||
152 | } | 166 | } |
153 | 167 | ||
154 | gss_OID | 168 | gss_OID |
155 | ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int *gex) { | 169 | ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) { |
156 | int i = 0; | 170 | int i = 0; |
157 | 171 | ||
158 | if (strncmp(name, KEX_GSS_GRP1_SHA1_ID, | 172 | switch (kex_type) { |
159 | sizeof(KEX_GSS_GRP1_SHA1_ID)-1) == 0) { | 173 | case KEX_GSS_GRP1_SHA1: |
160 | name+=sizeof(KEX_GSS_GRP1_SHA1_ID)-1; | 174 | name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1; |
161 | *gex = 0; | 175 | break; |
162 | } else if (strncmp(name, KEX_GSS_GEX_SHA1_ID, | 176 | case KEX_GSS_GRP14_SHA1: |
163 | sizeof(KEX_GSS_GEX_SHA1_ID)-1) == 0) { | 177 | name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1; |
164 | name+=sizeof(KEX_GSS_GEX_SHA1_ID)-1; | 178 | break; |
165 | *gex = 1; | 179 | case KEX_GSS_GEX_SHA1: |
166 | } else { | 180 | name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1; |
167 | return NULL; | 181 | break; |
182 | default: | ||
183 | return GSS_C_NO_OID; | ||
168 | } | 184 | } |
169 | 185 | ||
170 | while (gss_enc2oid[i].encoded != NULL && | 186 | while (gss_enc2oid[i].encoded != NULL && |
171 | strcmp(name, gss_enc2oid[i].encoded) != 0) { | 187 | strcmp(name, gss_enc2oid[i].encoded) != 0) |
172 | i++; | 188 | i++; |
173 | } | ||
174 | 189 | ||
175 | if (gss_enc2oid[i].oid != NULL && ctx != NULL) | 190 | if (gss_enc2oid[i].oid != NULL && ctx != NULL) |
176 | ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid); | 191 | ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid); |
@@ -212,7 +227,11 @@ ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid) | |||
212 | void | 227 | void |
213 | ssh_gssapi_error(Gssctxt *ctxt) | 228 | ssh_gssapi_error(Gssctxt *ctxt) |
214 | { | 229 | { |
215 | debug("%s", ssh_gssapi_last_error(ctxt, NULL, NULL)); | 230 | char *s; |
231 | |||
232 | s = ssh_gssapi_last_error(ctxt, NULL, NULL); | ||
233 | debug("%s", s); | ||
234 | xfree(s); | ||
216 | } | 235 | } |
217 | 236 | ||
218 | char * | 237 | char * |
@@ -236,7 +255,7 @@ ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *major_status, | |||
236 | /* The GSSAPI error */ | 255 | /* The GSSAPI error */ |
237 | do { | 256 | do { |
238 | gss_display_status(&lmin, ctxt->major, | 257 | gss_display_status(&lmin, ctxt->major, |
239 | GSS_C_GSS_CODE, GSS_C_NULL_OID, &ctx, &msg); | 258 | GSS_C_GSS_CODE, ctxt->oid, &ctx, &msg); |
240 | 259 | ||
241 | buffer_append(&b, msg.value, msg.length); | 260 | buffer_append(&b, msg.value, msg.length); |
242 | buffer_put_char(&b, '\n'); | 261 | buffer_put_char(&b, '\n'); |
@@ -247,7 +266,7 @@ ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *major_status, | |||
247 | /* The mechanism specific error */ | 266 | /* The mechanism specific error */ |
248 | do { | 267 | do { |
249 | gss_display_status(&lmin, ctxt->minor, | 268 | gss_display_status(&lmin, ctxt->minor, |
250 | GSS_C_MECH_CODE, GSS_C_NULL_OID, &ctx, &msg); | 269 | GSS_C_MECH_CODE, ctxt->oid, &ctx, &msg); |
251 | 270 | ||
252 | buffer_append(&b, msg.value, msg.length); | 271 | buffer_append(&b, msg.value, msg.length); |
253 | buffer_put_char(&b, '\n'); | 272 | buffer_put_char(&b, '\n'); |
@@ -271,9 +290,7 @@ ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *major_status, | |||
271 | void | 290 | void |
272 | ssh_gssapi_build_ctx(Gssctxt **ctx) | 291 | ssh_gssapi_build_ctx(Gssctxt **ctx) |
273 | { | 292 | { |
274 | *ctx = xmalloc(sizeof (Gssctxt)); | 293 | *ctx = xcalloc(1, sizeof (Gssctxt)); |
275 | (*ctx)->major = 0; | ||
276 | (*ctx)->minor = 0; | ||
277 | (*ctx)->context = GSS_C_NO_CONTEXT; | 294 | (*ctx)->context = GSS_C_NO_CONTEXT; |
278 | (*ctx)->name = GSS_C_NO_NAME; | 295 | (*ctx)->name = GSS_C_NO_NAME; |
279 | (*ctx)->oid = GSS_C_NO_OID; | 296 | (*ctx)->oid = GSS_C_NO_OID; |
@@ -343,10 +360,11 @@ OM_uint32 | |||
343 | ssh_gssapi_import_name(Gssctxt *ctx, const char *host) | 360 | ssh_gssapi_import_name(Gssctxt *ctx, const char *host) |
344 | { | 361 | { |
345 | gss_buffer_desc gssbuf; | 362 | gss_buffer_desc gssbuf; |
363 | char *val; | ||
346 | 364 | ||
347 | gssbuf.length = sizeof("host@") + strlen(host); | 365 | xasprintf(&val, "host@%s", host); |
348 | gssbuf.value = xmalloc(gssbuf.length); | 366 | gssbuf.value = val; |
349 | snprintf(gssbuf.value, gssbuf.length, "host@%s", host); | 367 | gssbuf.length = strlen(gssbuf.value); |
350 | 368 | ||
351 | if ((ctx->major = gss_import_name(&ctx->minor, | 369 | if ((ctx->major = gss_import_name(&ctx->minor, |
352 | &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) | 370 | &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) |
@@ -356,35 +374,6 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) | |||
356 | return (ctx->major); | 374 | return (ctx->major); |
357 | } | 375 | } |
358 | 376 | ||
359 | /* Acquire credentials for a server running on the current host. | ||
360 | * Requires that the context structure contains a valid OID | ||
361 | */ | ||
362 | |||
363 | /* Returns a GSSAPI error code */ | ||
364 | OM_uint32 | ||
365 | ssh_gssapi_acquire_cred(Gssctxt *ctx) | ||
366 | { | ||
367 | OM_uint32 status; | ||
368 | char lname[MAXHOSTNAMELEN]; | ||
369 | gss_OID_set oidset; | ||
370 | |||
371 | gss_create_empty_oid_set(&status, &oidset); | ||
372 | gss_add_oid_set_member(&status, ctx->oid, &oidset); | ||
373 | |||
374 | if (gethostname(lname, MAXHOSTNAMELEN)) | ||
375 | return (-1); | ||
376 | |||
377 | if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) | ||
378 | return (ctx->major); | ||
379 | |||
380 | if ((ctx->major = gss_acquire_cred(&ctx->minor, | ||
381 | ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) | ||
382 | ssh_gssapi_error(ctx); | ||
383 | |||
384 | gss_release_oid_set(&status, &oidset); | ||
385 | return (ctx->major); | ||
386 | } | ||
387 | |||
388 | OM_uint32 | 377 | OM_uint32 |
389 | ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) | 378 | ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) |
390 | { | 379 | { |
@@ -423,28 +412,37 @@ ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, | |||
423 | buffer_put_cstring(b, context); | 412 | buffer_put_cstring(b, context); |
424 | } | 413 | } |
425 | 414 | ||
426 | OM_uint32 | 415 | int |
427 | ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) | 416 | ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) |
428 | { | 417 | { |
429 | if (*ctx) | 418 | gss_buffer_desc token = GSS_C_EMPTY_BUFFER; |
430 | ssh_gssapi_delete_ctx(ctx); | 419 | OM_uint32 major, minor; |
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; | ||
425 | |||
426 | /* RFC 4462 says we MUST NOT do SPNEGO */ | ||
427 | if (oid->length == spnego_oid.length && | ||
428 | (memcmp(oid->elements, spnego_oid.elements, oid->length) == 0)) | ||
429 | return 0; /* false */ | ||
430 | |||
431 | ssh_gssapi_build_ctx(ctx); | 431 | ssh_gssapi_build_ctx(ctx); |
432 | ssh_gssapi_set_oid(*ctx, oid); | 432 | ssh_gssapi_set_oid(*ctx, oid); |
433 | return (ssh_gssapi_acquire_cred(*ctx)); | 433 | major = ssh_gssapi_import_name(*ctx, host); |
434 | } | 434 | if (!GSS_ERROR(major)) { |
435 | major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, | ||
436 | NULL); | ||
437 | gss_release_buffer(&minor, &token); | ||
438 | if ((*ctx)->context != GSS_C_NO_CONTEXT) | ||
439 | gss_delete_sec_context(&minor, &(*ctx)->context, | ||
440 | GSS_C_NO_BUFFER); | ||
441 | } | ||
442 | |||
443 | if (GSS_ERROR(major) || intctx != NULL) | ||
444 | ssh_gssapi_delete_ctx(ctx); | ||
435 | 445 | ||
436 | int | ||
437 | ssh_gssapi_check_mechanism(gss_OID oid, void *host) { | ||
438 | Gssctxt * ctx = NULL; | ||
439 | gss_buffer_desc token = GSS_C_EMPTY_BUFFER; | ||
440 | OM_uint32 major, minor; | ||
441 | |||
442 | ssh_gssapi_build_ctx(&ctx); | ||
443 | ssh_gssapi_set_oid(ctx, oid); | ||
444 | ssh_gssapi_import_name(ctx, host); | ||
445 | major = ssh_gssapi_init_ctx(ctx, 0, GSS_C_NO_BUFFER, &token, NULL); | ||
446 | gss_release_buffer(&minor, &token); | ||
447 | ssh_gssapi_delete_ctx(&ctx); | ||
448 | return (!GSS_ERROR(major)); | 446 | return (!GSS_ERROR(major)); |
449 | } | 447 | } |
450 | 448 | ||