diff options
Diffstat (limited to 'gss-serv.c')
-rw-r--r-- | gss-serv.c | 161 |
1 files changed, 151 insertions, 10 deletions
diff --git a/gss-serv.c b/gss-serv.c index 9227b797c..365e48d88 100644 --- a/gss-serv.c +++ b/gss-serv.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */ | 1 | /* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2001-2008 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 |
@@ -46,6 +46,7 @@ | |||
46 | #include "session.h" | 46 | #include "session.h" |
47 | #include "misc.h" | 47 | #include "misc.h" |
48 | #include "servconf.h" | 48 | #include "servconf.h" |
49 | #include "uidswap.h" | ||
49 | 50 | ||
50 | #include "ssh-gss.h" | 51 | #include "ssh-gss.h" |
51 | #include "monitor_wrap.h" | 52 | #include "monitor_wrap.h" |
@@ -54,10 +55,10 @@ extern ServerOptions options; | |||
54 | 55 | ||
55 | static ssh_gssapi_client gssapi_client = | 56 | static ssh_gssapi_client gssapi_client = |
56 | { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, | 57 | { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, |
57 | GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}}; | 58 | GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL}, 0, 0}; |
58 | 59 | ||
59 | ssh_gssapi_mech gssapi_null_mech = | 60 | ssh_gssapi_mech gssapi_null_mech = |
60 | { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; | 61 | { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; |
61 | 62 | ||
62 | #ifdef KRB5 | 63 | #ifdef KRB5 |
63 | extern ssh_gssapi_mech gssapi_kerberos_mech; | 64 | extern ssh_gssapi_mech gssapi_kerberos_mech; |
@@ -131,12 +132,13 @@ ssh_gssapi_server_mechanisms() { | |||
131 | 132 | ||
132 | ssh_gssapi_supported_oids(&supported); | 133 | ssh_gssapi_supported_oids(&supported); |
133 | return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech, | 134 | return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech, |
134 | NULL)); | 135 | NULL, NULL)); |
135 | } | 136 | } |
136 | 137 | ||
137 | /* Unprivileged */ | 138 | /* Unprivileged */ |
138 | int | 139 | int |
139 | ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data) { | 140 | ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data, |
141 | const char *dummy) { | ||
140 | Gssctxt *ctx = NULL; | 142 | Gssctxt *ctx = NULL; |
141 | int res; | 143 | int res; |
142 | 144 | ||
@@ -156,7 +158,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset) | |||
156 | gss_OID_set supported; | 158 | gss_OID_set supported; |
157 | 159 | ||
158 | gss_create_empty_oid_set(&min_status, oidset); | 160 | gss_create_empty_oid_set(&min_status, oidset); |
159 | gss_indicate_mechs(&min_status, &supported); | 161 | |
162 | if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported))) | ||
163 | return; | ||
160 | 164 | ||
161 | while (supported_mechs[i]->name != NULL) { | 165 | while (supported_mechs[i]->name != NULL) { |
162 | if (GSS_ERROR(gss_test_oid_set_member(&min_status, | 166 | if (GSS_ERROR(gss_test_oid_set_member(&min_status, |
@@ -280,8 +284,48 @@ OM_uint32 | |||
280 | ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) | 284 | ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) |
281 | { | 285 | { |
282 | int i = 0; | 286 | int i = 0; |
287 | int equal = 0; | ||
288 | gss_name_t new_name = GSS_C_NO_NAME; | ||
289 | gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; | ||
290 | |||
291 | if (options.gss_store_rekey && client->used && ctx->client_creds) { | ||
292 | if (client->mech->oid.length != ctx->oid->length || | ||
293 | (memcmp(client->mech->oid.elements, | ||
294 | ctx->oid->elements, ctx->oid->length) !=0)) { | ||
295 | debug("Rekeyed credentials have different mechanism"); | ||
296 | return GSS_S_COMPLETE; | ||
297 | } | ||
298 | |||
299 | if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, | ||
300 | ctx->client_creds, ctx->oid, &new_name, | ||
301 | NULL, NULL, NULL))) { | ||
302 | ssh_gssapi_error(ctx); | ||
303 | return (ctx->major); | ||
304 | } | ||
305 | |||
306 | ctx->major = gss_compare_name(&ctx->minor, client->name, | ||
307 | new_name, &equal); | ||
308 | |||
309 | if (GSS_ERROR(ctx->major)) { | ||
310 | ssh_gssapi_error(ctx); | ||
311 | return (ctx->major); | ||
312 | } | ||
313 | |||
314 | if (!equal) { | ||
315 | debug("Rekeyed credentials have different name"); | ||
316 | return GSS_S_COMPLETE; | ||
317 | } | ||
283 | 318 | ||
284 | gss_buffer_desc ename; | 319 | debug("Marking rekeyed credentials for export"); |
320 | |||
321 | gss_release_name(&ctx->minor, &client->name); | ||
322 | gss_release_cred(&ctx->minor, &client->creds); | ||
323 | client->name = new_name; | ||
324 | client->creds = ctx->client_creds; | ||
325 | ctx->client_creds = GSS_C_NO_CREDENTIAL; | ||
326 | client->updated = 1; | ||
327 | return GSS_S_COMPLETE; | ||
328 | } | ||
285 | 329 | ||
286 | client->mech = NULL; | 330 | client->mech = NULL; |
287 | 331 | ||
@@ -296,6 +340,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) | |||
296 | if (client->mech == NULL) | 340 | if (client->mech == NULL) |
297 | return GSS_S_FAILURE; | 341 | return GSS_S_FAILURE; |
298 | 342 | ||
343 | if (ctx->client_creds && | ||
344 | (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, | ||
345 | ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { | ||
346 | ssh_gssapi_error(ctx); | ||
347 | return (ctx->major); | ||
348 | } | ||
349 | |||
299 | if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, | 350 | if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, |
300 | &client->displayname, NULL))) { | 351 | &client->displayname, NULL))) { |
301 | ssh_gssapi_error(ctx); | 352 | ssh_gssapi_error(ctx); |
@@ -313,6 +364,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) | |||
313 | return (ctx->major); | 364 | return (ctx->major); |
314 | } | 365 | } |
315 | 366 | ||
367 | gss_release_buffer(&ctx->minor, &ename); | ||
368 | |||
316 | /* We can't copy this structure, so we just move the pointer to it */ | 369 | /* We can't copy this structure, so we just move the pointer to it */ |
317 | client->creds = ctx->client_creds; | 370 | client->creds = ctx->client_creds; |
318 | ctx->client_creds = GSS_C_NO_CREDENTIAL; | 371 | ctx->client_creds = GSS_C_NO_CREDENTIAL; |
@@ -360,7 +413,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) | |||
360 | 413 | ||
361 | /* Privileged */ | 414 | /* Privileged */ |
362 | int | 415 | int |
363 | ssh_gssapi_userok(char *user) | 416 | ssh_gssapi_userok(char *user, struct passwd *pw) |
364 | { | 417 | { |
365 | OM_uint32 lmin; | 418 | OM_uint32 lmin; |
366 | 419 | ||
@@ -370,9 +423,11 @@ ssh_gssapi_userok(char *user) | |||
370 | return 0; | 423 | return 0; |
371 | } | 424 | } |
372 | if (gssapi_client.mech && gssapi_client.mech->userok) | 425 | if (gssapi_client.mech && gssapi_client.mech->userok) |
373 | if ((*gssapi_client.mech->userok)(&gssapi_client, user)) | 426 | if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { |
427 | gssapi_client.used = 1; | ||
428 | gssapi_client.store.owner = pw; | ||
374 | return 1; | 429 | return 1; |
375 | else { | 430 | } else { |
376 | /* Destroy delegated credentials if userok fails */ | 431 | /* Destroy delegated credentials if userok fails */ |
377 | gss_release_buffer(&lmin, &gssapi_client.displayname); | 432 | gss_release_buffer(&lmin, &gssapi_client.displayname); |
378 | gss_release_buffer(&lmin, &gssapi_client.exportedname); | 433 | gss_release_buffer(&lmin, &gssapi_client.exportedname); |
@@ -385,4 +440,90 @@ ssh_gssapi_userok(char *user) | |||
385 | return (0); | 440 | return (0); |
386 | } | 441 | } |
387 | 442 | ||
443 | /* These bits are only used for rekeying. The unpriviledged child is running | ||
444 | * as the user, the monitor is root. | ||
445 | * | ||
446 | * In the child, we want to : | ||
447 | * *) Ask the monitor to store our credentials into the store we specify | ||
448 | * *) If it succeeds, maybe do a PAM update | ||
449 | */ | ||
450 | |||
451 | /* Stuff for PAM */ | ||
452 | |||
453 | #ifdef USE_PAM | ||
454 | static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, | ||
455 | struct pam_response **resp, void *data) | ||
456 | { | ||
457 | return (PAM_CONV_ERR); | ||
458 | } | ||
459 | #endif | ||
460 | |||
461 | void | ||
462 | ssh_gssapi_rekey_creds() { | ||
463 | int ok; | ||
464 | int ret; | ||
465 | #ifdef USE_PAM | ||
466 | pam_handle_t *pamh = NULL; | ||
467 | struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; | ||
468 | char *envstr; | ||
469 | #endif | ||
470 | |||
471 | if (gssapi_client.store.filename == NULL && | ||
472 | gssapi_client.store.envval == NULL && | ||
473 | gssapi_client.store.envvar == NULL) | ||
474 | return; | ||
475 | |||
476 | ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); | ||
477 | |||
478 | if (!ok) | ||
479 | return; | ||
480 | |||
481 | debug("Rekeyed credentials stored successfully"); | ||
482 | |||
483 | /* Actually managing to play with the ssh pam stack from here will | ||
484 | * be next to impossible. In any case, we may want different options | ||
485 | * for rekeying. So, use our own :) | ||
486 | */ | ||
487 | #ifdef USE_PAM | ||
488 | if (!use_privsep) { | ||
489 | debug("Not even going to try and do PAM with privsep disabled"); | ||
490 | return; | ||
491 | } | ||
492 | |||
493 | ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, | ||
494 | &pamconv, &pamh); | ||
495 | if (ret) | ||
496 | return; | ||
497 | |||
498 | xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, | ||
499 | gssapi_client.store.envval); | ||
500 | |||
501 | ret = pam_putenv(pamh, envstr); | ||
502 | if (!ret) | ||
503 | pam_setcred(pamh, PAM_REINITIALIZE_CRED); | ||
504 | pam_end(pamh, PAM_SUCCESS); | ||
505 | #endif | ||
506 | } | ||
507 | |||
508 | int | ||
509 | ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { | ||
510 | int ok = 0; | ||
511 | |||
512 | /* Check we've got credentials to store */ | ||
513 | if (!gssapi_client.updated) | ||
514 | return 0; | ||
515 | |||
516 | gssapi_client.updated = 0; | ||
517 | |||
518 | temporarily_use_uid(gssapi_client.store.owner); | ||
519 | if (gssapi_client.mech && gssapi_client.mech->updatecreds) | ||
520 | ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); | ||
521 | else | ||
522 | debug("No update function for this mechanism"); | ||
523 | |||
524 | restore_uid(); | ||
525 | |||
526 | return ok; | ||
527 | } | ||
528 | |||
388 | #endif | 529 | #endif |