summaryrefslogtreecommitdiff
path: root/gss-serv.c
diff options
context:
space:
mode:
Diffstat (limited to 'gss-serv.c')
-rw-r--r--gss-serv.c186
1 files changed, 171 insertions, 15 deletions
diff --git a/gss-serv.c b/gss-serv.c
index b5d4bb2d1..55f4d4bda 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-serv.c,v 1.32 2020/03/13 03:17:07 djm Exp $ */ 1/* $OpenBSD: gss-serv.c,v 1.32 2020/03/13 03:17:07 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
@@ -44,17 +44,19 @@
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"
49 51
50extern ServerOptions options; 52extern ServerOptions options;
51 53
52static ssh_gssapi_client gssapi_client = 54static ssh_gssapi_client gssapi_client =
53 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, 55 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL,
54 GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}}; 56 GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0};
55 57
56ssh_gssapi_mech gssapi_null_mech = 58ssh_gssapi_mech gssapi_null_mech =
57 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; 59 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
58 60
59#ifdef KRB5 61#ifdef KRB5
60extern ssh_gssapi_mech gssapi_kerberos_mech; 62extern ssh_gssapi_mech gssapi_kerberos_mech;
@@ -141,6 +143,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
141} 143}
142 144
143/* Unprivileged */ 145/* Unprivileged */
146char *
147ssh_gssapi_server_mechanisms(void) {
148 if (supported_oids == NULL)
149 ssh_gssapi_prepare_supported_oids();
150 return (ssh_gssapi_kex_mechs(supported_oids,
151 &ssh_gssapi_server_check_mech, NULL, NULL,
152 options.gss_kex_algorithms));
153}
154
155/* Unprivileged */
156int
157ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
158 const char *dummy) {
159 Gssctxt *ctx = NULL;
160 int res;
161
162 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
163 ssh_gssapi_delete_ctx(&ctx);
164
165 return (res);
166}
167
168/* Unprivileged */
144void 169void
145ssh_gssapi_supported_oids(gss_OID_set *oidset) 170ssh_gssapi_supported_oids(gss_OID_set *oidset)
146{ 171{
@@ -150,7 +175,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
150 gss_OID_set supported; 175 gss_OID_set supported;
151 176
152 gss_create_empty_oid_set(&min_status, oidset); 177 gss_create_empty_oid_set(&min_status, oidset);
153 gss_indicate_mechs(&min_status, &supported); 178
179 if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
180 return;
154 181
155 while (supported_mechs[i]->name != NULL) { 182 while (supported_mechs[i]->name != NULL) {
156 if (GSS_ERROR(gss_test_oid_set_member(&min_status, 183 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
@@ -276,8 +303,48 @@ OM_uint32
276ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 303ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
277{ 304{
278 int i = 0; 305 int i = 0;
306 int equal = 0;
307 gss_name_t new_name = GSS_C_NO_NAME;
308 gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
309
310 if (options.gss_store_rekey && client->used && ctx->client_creds) {
311 if (client->mech->oid.length != ctx->oid->length ||
312 (memcmp(client->mech->oid.elements,
313 ctx->oid->elements, ctx->oid->length) !=0)) {
314 debug("Rekeyed credentials have different mechanism");
315 return GSS_S_COMPLETE;
316 }
317
318 if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
319 ctx->client_creds, ctx->oid, &new_name,
320 NULL, NULL, NULL))) {
321 ssh_gssapi_error(ctx);
322 return (ctx->major);
323 }
324
325 ctx->major = gss_compare_name(&ctx->minor, client->name,
326 new_name, &equal);
327
328 if (GSS_ERROR(ctx->major)) {
329 ssh_gssapi_error(ctx);
330 return (ctx->major);
331 }
332
333 if (!equal) {
334 debug("Rekeyed credentials have different name");
335 return GSS_S_COMPLETE;
336 }
279 337
280 gss_buffer_desc ename; 338 debug("Marking rekeyed credentials for export");
339
340 gss_release_name(&ctx->minor, &client->name);
341 gss_release_cred(&ctx->minor, &client->creds);
342 client->name = new_name;
343 client->creds = ctx->client_creds;
344 ctx->client_creds = GSS_C_NO_CREDENTIAL;
345 client->updated = 1;
346 return GSS_S_COMPLETE;
347 }
281 348
282 client->mech = NULL; 349 client->mech = NULL;
283 350
@@ -292,6 +359,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
292 if (client->mech == NULL) 359 if (client->mech == NULL)
293 return GSS_S_FAILURE; 360 return GSS_S_FAILURE;
294 361
362 if (ctx->client_creds &&
363 (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
364 ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
365 ssh_gssapi_error(ctx);
366 return (ctx->major);
367 }
368
295 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, 369 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
296 &client->displayname, NULL))) { 370 &client->displayname, NULL))) {
297 ssh_gssapi_error(ctx); 371 ssh_gssapi_error(ctx);
@@ -309,6 +383,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
309 return (ctx->major); 383 return (ctx->major);
310 } 384 }
311 385
386 gss_release_buffer(&ctx->minor, &ename);
387
312 /* We can't copy this structure, so we just move the pointer to it */ 388 /* We can't copy this structure, so we just move the pointer to it */
313 client->creds = ctx->client_creds; 389 client->creds = ctx->client_creds;
314 ctx->client_creds = GSS_C_NO_CREDENTIAL; 390 ctx->client_creds = GSS_C_NO_CREDENTIAL;
@@ -356,19 +432,23 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
356 432
357/* Privileged */ 433/* Privileged */
358int 434int
359ssh_gssapi_userok(char *user) 435ssh_gssapi_userok(char *user, struct passwd *pw, int kex)
360{ 436{
361 OM_uint32 lmin; 437 OM_uint32 lmin;
362 438
439 (void) kex; /* used in privilege separation */
440
363 if (gssapi_client.exportedname.length == 0 || 441 if (gssapi_client.exportedname.length == 0 ||
364 gssapi_client.exportedname.value == NULL) { 442 gssapi_client.exportedname.value == NULL) {
365 debug("No suitable client data"); 443 debug("No suitable client data");
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#ifdef USE_PAM
487 int ret;
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 */