summaryrefslogtreecommitdiff
path: root/gss-serv.c
diff options
context:
space:
mode:
Diffstat (limited to 'gss-serv.c')
-rw-r--r--gss-serv.c221
1 files changed, 193 insertions, 28 deletions
diff --git a/gss-serv.c b/gss-serv.c
index 5c599247b..50fa43834 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-serv.c,v 1.27 2014/07/03 03:34:09 djm Exp $ */ 1/* $OpenBSD: gss-serv.c,v 1.27 2014/07/03 03:34:09 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,15 +45,21 @@
45#include "channels.h" 45#include "channels.h"
46#include "session.h" 46#include "session.h"
47#include "misc.h" 47#include "misc.h"
48#include "servconf.h"
49#include "uidswap.h"
48 50
49#include "ssh-gss.h" 51#include "ssh-gss.h"
52#include "monitor_wrap.h"
53
54extern ServerOptions options;
50 55
51static ssh_gssapi_client gssapi_client = 56static ssh_gssapi_client gssapi_client =
52 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, 57 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
53 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};
54 60
55ssh_gssapi_mech gssapi_null_mech = 61ssh_gssapi_mech gssapi_null_mech =
56 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; 62 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL};
57 63
58#ifdef KRB5 64#ifdef KRB5
59extern ssh_gssapi_mech gssapi_kerberos_mech; 65extern ssh_gssapi_mech gssapi_kerberos_mech;
@@ -100,25 +106,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
100 char lname[NI_MAXHOST]; 106 char lname[NI_MAXHOST];
101 gss_OID_set oidset; 107 gss_OID_set oidset;
102 108
103 gss_create_empty_oid_set(&status, &oidset); 109 if (options.gss_strict_acceptor) {
104 gss_add_oid_set_member(&status, ctx->oid, &oidset); 110 gss_create_empty_oid_set(&status, &oidset);
111 gss_add_oid_set_member(&status, ctx->oid, &oidset);
105 112
106 if (gethostname(lname, sizeof(lname))) { 113 if (gethostname(lname, sizeof(lname))) {
107 gss_release_oid_set(&status, &oidset); 114 gss_release_oid_set(&status, &oidset);
108 return (-1); 115 return (-1);
109 } 116 }
117
118 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
119 gss_release_oid_set(&status, &oidset);
120 return (ctx->major);
121 }
122
123 if ((ctx->major = gss_acquire_cred(&ctx->minor,
124 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds,
125 NULL, NULL)))
126 ssh_gssapi_error(ctx);
110 127
111 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
112 gss_release_oid_set(&status, &oidset); 128 gss_release_oid_set(&status, &oidset);
113 return (ctx->major); 129 return (ctx->major);
130 } else {
131 ctx->name = GSS_C_NO_NAME;
132 ctx->creds = GSS_C_NO_CREDENTIAL;
114 } 133 }
115 134 return GSS_S_COMPLETE;
116 if ((ctx->major = gss_acquire_cred(&ctx->minor,
117 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
118 ssh_gssapi_error(ctx);
119
120 gss_release_oid_set(&status, &oidset);
121 return (ctx->major);
122} 135}
123 136
124/* Privileged */ 137/* Privileged */
@@ -133,6 +146,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
133} 146}
134 147
135/* Unprivileged */ 148/* Unprivileged */
149char *
150ssh_gssapi_server_mechanisms(void) {
151 gss_OID_set supported;
152
153 ssh_gssapi_supported_oids(&supported);
154 return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
155 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 */
136void 172void
137ssh_gssapi_supported_oids(gss_OID_set *oidset) 173ssh_gssapi_supported_oids(gss_OID_set *oidset)
138{ 174{
@@ -142,7 +178,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
142 gss_OID_set supported; 178 gss_OID_set supported;
143 179
144 gss_create_empty_oid_set(&min_status, oidset); 180 gss_create_empty_oid_set(&min_status, oidset);
145 gss_indicate_mechs(&min_status, &supported); 181
182 if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
183 return;
146 184
147 while (supported_mechs[i]->name != NULL) { 185 while (supported_mechs[i]->name != NULL) {
148 if (GSS_ERROR(gss_test_oid_set_member(&min_status, 186 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
@@ -268,8 +306,48 @@ OM_uint32
268ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 306ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
269{ 307{
270 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);
271 330
272 gss_buffer_desc ename; 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 }
340
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 }
273 351
274 client->mech = NULL; 352 client->mech = NULL;
275 353
@@ -284,6 +362,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
284 if (client->mech == NULL) 362 if (client->mech == NULL)
285 return GSS_S_FAILURE; 363 return GSS_S_FAILURE;
286 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
287 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, 372 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
288 &client->displayname, NULL))) { 373 &client->displayname, NULL))) {
289 ssh_gssapi_error(ctx); 374 ssh_gssapi_error(ctx);
@@ -301,6 +386,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
301 return (ctx->major); 386 return (ctx->major);
302 } 387 }
303 388
389 gss_release_buffer(&ctx->minor, &ename);
390
304 /* 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 */
305 client->creds = ctx->client_creds; 392 client->creds = ctx->client_creds;
306 ctx->client_creds = GSS_C_NO_CREDENTIAL; 393 ctx->client_creds = GSS_C_NO_CREDENTIAL;
@@ -348,7 +435,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
348 435
349/* Privileged */ 436/* Privileged */
350int 437int
351ssh_gssapi_userok(char *user) 438ssh_gssapi_userok(char *user, struct passwd *pw)
352{ 439{
353 OM_uint32 lmin; 440 OM_uint32 lmin;
354 441
@@ -358,9 +445,11 @@ ssh_gssapi_userok(char *user)
358 return 0; 445 return 0;
359 } 446 }
360 if (gssapi_client.mech && gssapi_client.mech->userok) 447 if (gssapi_client.mech && gssapi_client.mech->userok)
361 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;
362 return 1; 451 return 1;
363 else { 452 } else {
364 /* Destroy delegated credentials if userok fails */ 453 /* Destroy delegated credentials if userok fails */
365 gss_release_buffer(&lmin, &gssapi_client.displayname); 454 gss_release_buffer(&lmin, &gssapi_client.displayname);
366 gss_release_buffer(&lmin, &gssapi_client.exportedname); 455 gss_release_buffer(&lmin, &gssapi_client.exportedname);
@@ -374,14 +463,90 @@ ssh_gssapi_userok(char *user)
374 return (0); 463 return (0);
375} 464}
376 465
377/* Privileged */ 466/* These bits are only used for rekeying. The unpriviledged child is running
378OM_uint32 467 * as the user, the monitor is root.
379ssh_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)
380{ 479{
381 ctx->major = gss_verify_mic(&ctx->minor, ctx->context, 480 return (PAM_CONV_ERR);
382 gssbuf, gssmic, NULL); 481}
482#endif
383 483
384 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;
385} 550}
386 551
387#endif 552#endif