summaryrefslogtreecommitdiff
path: root/gss-serv.c
diff options
context:
space:
mode:
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 */