summaryrefslogtreecommitdiff
path: root/gss-serv.c
diff options
context:
space:
mode:
authorSimon Wilkinson <simon@sxw.org.uk>2014-02-09 16:09:48 +0000
committerColin Watson <cjwatson@debian.org>2015-11-29 17:26:06 +0000
commit233e78235070e871b658c8f289e600bd52a99711 (patch)
tree38c49e39e2a61ef635ce70062d8830d09fc963ff /gss-serv.c
parent58ddb8ad21f21f5358db0204c4ba9abf94a1ca11 (diff)
GSSAPI key exchange support
This patch has been rejected upstream: "None of the OpenSSH developers are in favour of adding this, and this situation has not changed for several years. This is not a slight on Simon's patch, which is of fine quality, but just that a) we don't trust GSSAPI implementations that much and b) we don't like adding new KEX since they are pre-auth attack surface. This one is particularly scary, since it requires hooks out to typically root-owned system resources." However, quite a lot of people rely on this in Debian, and it's better to have it merged into the main openssh package rather than having separate -krb5 packages (as we used to have). It seems to have a generally good security history. Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242 Last-Updated: 2015-11-29 Patch-Name: gssapi.patch
Diffstat (limited to 'gss-serv.c')
-rw-r--r--gss-serv.c185
1 files changed, 171 insertions, 14 deletions
diff --git a/gss-serv.c b/gss-serv.c
index 53993d674..2f6baf70d 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-serv.c,v 1.29 2015/05/22 03:50:02 djm Exp $ */ 1/* $OpenBSD: gss-serv.c,v 1.29 2015/05/22 03:50:02 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 4 * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
@@ -45,17 +45,22 @@
45#include "session.h" 45#include "session.h"
46#include "misc.h" 46#include "misc.h"
47#include "servconf.h" 47#include "servconf.h"
48#include "uidswap.h"
48 49
49#include "ssh-gss.h" 50#include "ssh-gss.h"
51#include "monitor_wrap.h"
52
53extern ServerOptions options;
50 54
51extern ServerOptions options; 55extern ServerOptions options;
52 56
53static ssh_gssapi_client gssapi_client = 57static ssh_gssapi_client gssapi_client =
54 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, 58 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
55 GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}}; 59 GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL,
60 {NULL, NULL, NULL, NULL, NULL}, 0, 0};
56 61
57ssh_gssapi_mech gssapi_null_mech = 62ssh_gssapi_mech gssapi_null_mech =
58 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; 63 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
59 64
60#ifdef KRB5 65#ifdef KRB5
61extern ssh_gssapi_mech gssapi_kerberos_mech; 66extern ssh_gssapi_mech gssapi_kerberos_mech;
@@ -142,6 +147,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
142} 147}
143 148
144/* Unprivileged */ 149/* Unprivileged */
150char *
151ssh_gssapi_server_mechanisms(void) {
152 gss_OID_set supported;
153
154 ssh_gssapi_supported_oids(&supported);
155 return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
156 NULL, NULL));
157}
158
159/* Unprivileged */
160int
161ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
162 const char *dummy) {
163 Gssctxt *ctx = NULL;
164 int res;
165
166 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
167 ssh_gssapi_delete_ctx(&ctx);
168
169 return (res);
170}
171
172/* Unprivileged */
145void 173void
146ssh_gssapi_supported_oids(gss_OID_set *oidset) 174ssh_gssapi_supported_oids(gss_OID_set *oidset)
147{ 175{
@@ -151,7 +179,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
151 gss_OID_set supported; 179 gss_OID_set supported;
152 180
153 gss_create_empty_oid_set(&min_status, oidset); 181 gss_create_empty_oid_set(&min_status, oidset);
154 gss_indicate_mechs(&min_status, &supported); 182
183 if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
184 return;
155 185
156 while (supported_mechs[i]->name != NULL) { 186 while (supported_mechs[i]->name != NULL) {
157 if (GSS_ERROR(gss_test_oid_set_member(&min_status, 187 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
@@ -277,8 +307,48 @@ OM_uint32
277ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 307ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
278{ 308{
279 int i = 0; 309 int i = 0;
310 int equal = 0;
311 gss_name_t new_name = GSS_C_NO_NAME;
312 gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
313
314 if (options.gss_store_rekey && client->used && ctx->client_creds) {
315 if (client->mech->oid.length != ctx->oid->length ||
316 (memcmp(client->mech->oid.elements,
317 ctx->oid->elements, ctx->oid->length) !=0)) {
318 debug("Rekeyed credentials have different mechanism");
319 return GSS_S_COMPLETE;
320 }
321
322 if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
323 ctx->client_creds, ctx->oid, &new_name,
324 NULL, NULL, NULL))) {
325 ssh_gssapi_error(ctx);
326 return (ctx->major);
327 }
328
329 ctx->major = gss_compare_name(&ctx->minor, client->name,
330 new_name, &equal);
331
332 if (GSS_ERROR(ctx->major)) {
333 ssh_gssapi_error(ctx);
334 return (ctx->major);
335 }
336
337 if (!equal) {
338 debug("Rekeyed credentials have different name");
339 return GSS_S_COMPLETE;
340 }
280 341
281 gss_buffer_desc ename; 342 debug("Marking rekeyed credentials for export");
343
344 gss_release_name(&ctx->minor, &client->name);
345 gss_release_cred(&ctx->minor, &client->creds);
346 client->name = new_name;
347 client->creds = ctx->client_creds;
348 ctx->client_creds = GSS_C_NO_CREDENTIAL;
349 client->updated = 1;
350 return GSS_S_COMPLETE;
351 }
282 352
283 client->mech = NULL; 353 client->mech = NULL;
284 354
@@ -293,6 +363,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
293 if (client->mech == NULL) 363 if (client->mech == NULL)
294 return GSS_S_FAILURE; 364 return GSS_S_FAILURE;
295 365
366 if (ctx->client_creds &&
367 (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
368 ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
369 ssh_gssapi_error(ctx);
370 return (ctx->major);
371 }
372
296 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, 373 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
297 &client->displayname, NULL))) { 374 &client->displayname, NULL))) {
298 ssh_gssapi_error(ctx); 375 ssh_gssapi_error(ctx);
@@ -310,6 +387,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
310 return (ctx->major); 387 return (ctx->major);
311 } 388 }
312 389
390 gss_release_buffer(&ctx->minor, &ename);
391
313 /* We can't copy this structure, so we just move the pointer to it */ 392 /* We can't copy this structure, so we just move the pointer to it */
314 client->creds = ctx->client_creds; 393 client->creds = ctx->client_creds;
315 ctx->client_creds = GSS_C_NO_CREDENTIAL; 394 ctx->client_creds = GSS_C_NO_CREDENTIAL;
@@ -357,7 +436,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
357 436
358/* Privileged */ 437/* Privileged */
359int 438int
360ssh_gssapi_userok(char *user) 439ssh_gssapi_userok(char *user, struct passwd *pw)
361{ 440{
362 OM_uint32 lmin; 441 OM_uint32 lmin;
363 442
@@ -367,9 +446,11 @@ ssh_gssapi_userok(char *user)
367 return 0; 446 return 0;
368 } 447 }
369 if (gssapi_client.mech && gssapi_client.mech->userok) 448 if (gssapi_client.mech && gssapi_client.mech->userok)
370 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) 449 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
450 gssapi_client.used = 1;
451 gssapi_client.store.owner = pw;
371 return 1; 452 return 1;
372 else { 453 } else {
373 /* Destroy delegated credentials if userok fails */ 454 /* Destroy delegated credentials if userok fails */
374 gss_release_buffer(&lmin, &gssapi_client.displayname); 455 gss_release_buffer(&lmin, &gssapi_client.displayname);
375 gss_release_buffer(&lmin, &gssapi_client.exportedname); 456 gss_release_buffer(&lmin, &gssapi_client.exportedname);
@@ -383,14 +464,90 @@ ssh_gssapi_userok(char *user)
383 return (0); 464 return (0);
384} 465}
385 466
386/* Privileged */ 467/* These bits are only used for rekeying. The unpriviledged child is running
387OM_uint32 468 * as the user, the monitor is root.
388ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) 469 *
470 * In the child, we want to :
471 * *) Ask the monitor to store our credentials into the store we specify
472 * *) If it succeeds, maybe do a PAM update
473 */
474
475/* Stuff for PAM */
476
477#ifdef USE_PAM
478static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
479 struct pam_response **resp, void *data)
389{ 480{
390 ctx->major = gss_verify_mic(&ctx->minor, ctx->context, 481 return (PAM_CONV_ERR);
391 gssbuf, gssmic, NULL); 482}
483#endif
392 484
393 return (ctx->major); 485void
486ssh_gssapi_rekey_creds(void) {
487 int ok;
488 int ret;
489#ifdef USE_PAM
490 pam_handle_t *pamh = NULL;
491 struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
492 char *envstr;
493#endif
494
495 if (gssapi_client.store.filename == NULL &&
496 gssapi_client.store.envval == NULL &&
497 gssapi_client.store.envvar == NULL)
498 return;
499
500 ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
501
502 if (!ok)
503 return;
504
505 debug("Rekeyed credentials stored successfully");
506
507 /* Actually managing to play with the ssh pam stack from here will
508 * be next to impossible. In any case, we may want different options
509 * for rekeying. So, use our own :)
510 */
511#ifdef USE_PAM
512 if (!use_privsep) {
513 debug("Not even going to try and do PAM with privsep disabled");
514 return;
515 }
516
517 ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
518 &pamconv, &pamh);
519 if (ret)
520 return;
521
522 xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
523 gssapi_client.store.envval);
524
525 ret = pam_putenv(pamh, envstr);
526 if (!ret)
527 pam_setcred(pamh, PAM_REINITIALIZE_CRED);
528 pam_end(pamh, PAM_SUCCESS);
529#endif
530}
531
532int
533ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
534 int ok = 0;
535
536 /* Check we've got credentials to store */
537 if (!gssapi_client.updated)
538 return 0;
539
540 gssapi_client.updated = 0;
541
542 temporarily_use_uid(gssapi_client.store.owner);
543 if (gssapi_client.mech && gssapi_client.mech->updatecreds)
544 ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
545 else
546 debug("No update function for this mechanism");
547
548 restore_uid();
549
550 return ok;
394} 551}
395 552
396#endif 553#endif