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