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>2017-03-29 01:38:38 +0100
commitd51c7ac3328464dec21514fb398ab5c140a0664f (patch)
tree4f1a2aa08e99303f62c71cba0b38899f050d1b3d /gss-serv.c
parent6fabaf6fd9b07cc8bc6a17c9c4a5b76849cfc874 (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: 2017-01-16 Patch-Name: gssapi.patch
Diffstat (limited to 'gss-serv.c')
-rw-r--r--gss-serv.c184
1 files changed, 170 insertions, 14 deletions
diff --git a/gss-serv.c b/gss-serv.c
index 53993d674..2e27cbf9c 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,28 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
142} 147}
143 148
144/* Unprivileged */ 149/* Unprivileged */
150char *
151ssh_gssapi_server_mechanisms(void) {
152 if (supported_oids == NULL)
153 ssh_gssapi_prepare_supported_oids();
154 return (ssh_gssapi_kex_mechs(supported_oids,
155 &ssh_gssapi_server_check_mech, NULL, NULL));
156}
157
158/* Unprivileged */
159int
160ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
161 const char *dummy) {
162 Gssctxt *ctx = NULL;
163 int res;
164
165 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
166 ssh_gssapi_delete_ctx(&ctx);
167
168 return (res);
169}
170
171/* Unprivileged */
145void 172void
146ssh_gssapi_supported_oids(gss_OID_set *oidset) 173ssh_gssapi_supported_oids(gss_OID_set *oidset)
147{ 174{
@@ -151,7 +178,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
151 gss_OID_set supported; 178 gss_OID_set supported;
152 179
153 gss_create_empty_oid_set(&min_status, oidset); 180 gss_create_empty_oid_set(&min_status, oidset);
154 gss_indicate_mechs(&min_status, &supported); 181
182 if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
183 return;
155 184
156 while (supported_mechs[i]->name != NULL) { 185 while (supported_mechs[i]->name != NULL) {
157 if (GSS_ERROR(gss_test_oid_set_member(&min_status, 186 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
@@ -277,8 +306,48 @@ OM_uint32
277ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 306ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
278{ 307{
279 int i = 0; 308 int i = 0;
309 int equal = 0;
310 gss_name_t new_name = GSS_C_NO_NAME;
311 gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
312
313 if (options.gss_store_rekey && client->used && ctx->client_creds) {
314 if (client->mech->oid.length != ctx->oid->length ||
315 (memcmp(client->mech->oid.elements,
316 ctx->oid->elements, ctx->oid->length) !=0)) {
317 debug("Rekeyed credentials have different mechanism");
318 return GSS_S_COMPLETE;
319 }
320
321 if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
322 ctx->client_creds, ctx->oid, &new_name,
323 NULL, NULL, NULL))) {
324 ssh_gssapi_error(ctx);
325 return (ctx->major);
326 }
327
328 ctx->major = gss_compare_name(&ctx->minor, client->name,
329 new_name, &equal);
330
331 if (GSS_ERROR(ctx->major)) {
332 ssh_gssapi_error(ctx);
333 return (ctx->major);
334 }
335
336 if (!equal) {
337 debug("Rekeyed credentials have different name");
338 return GSS_S_COMPLETE;
339 }
280 340
281 gss_buffer_desc ename; 341 debug("Marking rekeyed credentials for export");
342
343 gss_release_name(&ctx->minor, &client->name);
344 gss_release_cred(&ctx->minor, &client->creds);
345 client->name = new_name;
346 client->creds = ctx->client_creds;
347 ctx->client_creds = GSS_C_NO_CREDENTIAL;
348 client->updated = 1;
349 return GSS_S_COMPLETE;
350 }
282 351
283 client->mech = NULL; 352 client->mech = NULL;
284 353
@@ -293,6 +362,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
293 if (client->mech == NULL) 362 if (client->mech == NULL)
294 return GSS_S_FAILURE; 363 return GSS_S_FAILURE;
295 364
365 if (ctx->client_creds &&
366 (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
367 ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
368 ssh_gssapi_error(ctx);
369 return (ctx->major);
370 }
371
296 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, 372 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
297 &client->displayname, NULL))) { 373 &client->displayname, NULL))) {
298 ssh_gssapi_error(ctx); 374 ssh_gssapi_error(ctx);
@@ -310,6 +386,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
310 return (ctx->major); 386 return (ctx->major);
311 } 387 }
312 388
389 gss_release_buffer(&ctx->minor, &ename);
390
313 /* We can't copy this structure, so we just move the pointer to it */ 391 /* We can't copy this structure, so we just move the pointer to it */
314 client->creds = ctx->client_creds; 392 client->creds = ctx->client_creds;
315 ctx->client_creds = GSS_C_NO_CREDENTIAL; 393 ctx->client_creds = GSS_C_NO_CREDENTIAL;
@@ -357,7 +435,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
357 435
358/* Privileged */ 436/* Privileged */
359int 437int
360ssh_gssapi_userok(char *user) 438ssh_gssapi_userok(char *user, struct passwd *pw)
361{ 439{
362 OM_uint32 lmin; 440 OM_uint32 lmin;
363 441
@@ -367,9 +445,11 @@ ssh_gssapi_userok(char *user)
367 return 0; 445 return 0;
368 } 446 }
369 if (gssapi_client.mech && gssapi_client.mech->userok) 447 if (gssapi_client.mech && gssapi_client.mech->userok)
370 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) 448 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
449 gssapi_client.used = 1;
450 gssapi_client.store.owner = pw;
371 return 1; 451 return 1;
372 else { 452 } else {
373 /* Destroy delegated credentials if userok fails */ 453 /* Destroy delegated credentials if userok fails */
374 gss_release_buffer(&lmin, &gssapi_client.displayname); 454 gss_release_buffer(&lmin, &gssapi_client.displayname);
375 gss_release_buffer(&lmin, &gssapi_client.exportedname); 455 gss_release_buffer(&lmin, &gssapi_client.exportedname);
@@ -383,14 +463,90 @@ ssh_gssapi_userok(char *user)
383 return (0); 463 return (0);
384} 464}
385 465
386/* Privileged */ 466/* These bits are only used for rekeying. The unpriviledged child is running
387OM_uint32 467 * as the user, the monitor is root.
388ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) 468 *
469 * In the child, we want to :
470 * *) Ask the monitor to store our credentials into the store we specify
471 * *) If it succeeds, maybe do a PAM update
472 */
473
474/* Stuff for PAM */
475
476#ifdef USE_PAM
477static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
478 struct pam_response **resp, void *data)
389{ 479{
390 ctx->major = gss_verify_mic(&ctx->minor, ctx->context, 480 return (PAM_CONV_ERR);
391 gssbuf, gssmic, NULL); 481}
482#endif
392 483
393 return (ctx->major); 484void
485ssh_gssapi_rekey_creds(void) {
486 int ok;
487 int ret;
488#ifdef USE_PAM
489 pam_handle_t *pamh = NULL;
490 struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
491 char *envstr;
492#endif
493
494 if (gssapi_client.store.filename == NULL &&
495 gssapi_client.store.envval == NULL &&
496 gssapi_client.store.envvar == NULL)
497 return;
498
499 ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
500
501 if (!ok)
502 return;
503
504 debug("Rekeyed credentials stored successfully");
505
506 /* Actually managing to play with the ssh pam stack from here will
507 * be next to impossible. In any case, we may want different options
508 * for rekeying. So, use our own :)
509 */
510#ifdef USE_PAM
511 if (!use_privsep) {
512 debug("Not even going to try and do PAM with privsep disabled");
513 return;
514 }
515
516 ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
517 &pamconv, &pamh);
518 if (ret)
519 return;
520
521 xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
522 gssapi_client.store.envval);
523
524 ret = pam_putenv(pamh, envstr);
525 if (!ret)
526 pam_setcred(pamh, PAM_REINITIALIZE_CRED);
527 pam_end(pamh, PAM_SUCCESS);
528#endif
529}
530
531int
532ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
533 int ok = 0;
534
535 /* Check we've got credentials to store */
536 if (!gssapi_client.updated)
537 return 0;
538
539 gssapi_client.updated = 0;
540
541 temporarily_use_uid(gssapi_client.store.owner);
542 if (gssapi_client.mech && gssapi_client.mech->updatecreds)
543 ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
544 else
545 debug("No update function for this mechanism");
546
547 restore_uid();
548
549 return ok;
394} 550}
395 551
396#endif 552#endif