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