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 95348e251..97f366fdf 100644
--- a/gss-serv.c
+++ b/gss-serv.c
@@ -1,7 +1,7 @@
1/* $OpenBSD: gss-serv.c,v 1.24 2013/07/20 01:55:13 djm Exp $ */ 1/* $OpenBSD: gss-serv.c,v 1.24 2013/07/20 01:55:13 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;
@@ -81,25 +87,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
81 char lname[MAXHOSTNAMELEN]; 87 char lname[MAXHOSTNAMELEN];
82 gss_OID_set oidset; 88 gss_OID_set oidset;
83 89
84 gss_create_empty_oid_set(&status, &oidset); 90 if (options.gss_strict_acceptor) {
85 gss_add_oid_set_member(&status, ctx->oid, &oidset); 91 gss_create_empty_oid_set(&status, &oidset);
92 gss_add_oid_set_member(&status, ctx->oid, &oidset);
86 93
87 if (gethostname(lname, MAXHOSTNAMELEN)) { 94 if (gethostname(lname, MAXHOSTNAMELEN)) {
88 gss_release_oid_set(&status, &oidset); 95 gss_release_oid_set(&status, &oidset);
89 return (-1); 96 return (-1);
90 } 97 }
98
99 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
100 gss_release_oid_set(&status, &oidset);
101 return (ctx->major);
102 }
103
104 if ((ctx->major = gss_acquire_cred(&ctx->minor,
105 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds,
106 NULL, NULL)))
107 ssh_gssapi_error(ctx);
91 108
92 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
93 gss_release_oid_set(&status, &oidset); 109 gss_release_oid_set(&status, &oidset);
94 return (ctx->major); 110 return (ctx->major);
111 } else {
112 ctx->name = GSS_C_NO_NAME;
113 ctx->creds = GSS_C_NO_CREDENTIAL;
95 } 114 }
96 115 return GSS_S_COMPLETE;
97 if ((ctx->major = gss_acquire_cred(&ctx->minor,
98 ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
99 ssh_gssapi_error(ctx);
100
101 gss_release_oid_set(&status, &oidset);
102 return (ctx->major);
103} 116}
104 117
105/* Privileged */ 118/* Privileged */
@@ -114,6 +127,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
114} 127}
115 128
116/* Unprivileged */ 129/* Unprivileged */
130char *
131ssh_gssapi_server_mechanisms() {
132 gss_OID_set supported;
133
134 ssh_gssapi_supported_oids(&supported);
135 return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
136 NULL, NULL));
137}
138
139/* Unprivileged */
140int
141ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data,
142 const char *dummy) {
143 Gssctxt *ctx = NULL;
144 int res;
145
146 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
147 ssh_gssapi_delete_ctx(&ctx);
148
149 return (res);
150}
151
152/* Unprivileged */
117void 153void
118ssh_gssapi_supported_oids(gss_OID_set *oidset) 154ssh_gssapi_supported_oids(gss_OID_set *oidset)
119{ 155{
@@ -123,7 +159,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset)
123 gss_OID_set supported; 159 gss_OID_set supported;
124 160
125 gss_create_empty_oid_set(&min_status, oidset); 161 gss_create_empty_oid_set(&min_status, oidset);
126 gss_indicate_mechs(&min_status, &supported); 162
163 if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported)))
164 return;
127 165
128 while (supported_mechs[i]->name != NULL) { 166 while (supported_mechs[i]->name != NULL) {
129 if (GSS_ERROR(gss_test_oid_set_member(&min_status, 167 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
@@ -249,8 +287,48 @@ OM_uint32
249ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 287ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
250{ 288{
251 int i = 0; 289 int i = 0;
290 int equal = 0;
291 gss_name_t new_name = GSS_C_NO_NAME;
292 gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;
293
294 if (options.gss_store_rekey && client->used && ctx->client_creds) {
295 if (client->mech->oid.length != ctx->oid->length ||
296 (memcmp(client->mech->oid.elements,
297 ctx->oid->elements, ctx->oid->length) !=0)) {
298 debug("Rekeyed credentials have different mechanism");
299 return GSS_S_COMPLETE;
300 }
301
302 if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
303 ctx->client_creds, ctx->oid, &new_name,
304 NULL, NULL, NULL))) {
305 ssh_gssapi_error(ctx);
306 return (ctx->major);
307 }
308
309 ctx->major = gss_compare_name(&ctx->minor, client->name,
310 new_name, &equal);
252 311
253 gss_buffer_desc ename; 312 if (GSS_ERROR(ctx->major)) {
313 ssh_gssapi_error(ctx);
314 return (ctx->major);
315 }
316
317 if (!equal) {
318 debug("Rekeyed credentials have different name");
319 return GSS_S_COMPLETE;
320 }
321
322 debug("Marking rekeyed credentials for export");
323
324 gss_release_name(&ctx->minor, &client->name);
325 gss_release_cred(&ctx->minor, &client->creds);
326 client->name = new_name;
327 client->creds = ctx->client_creds;
328 ctx->client_creds = GSS_C_NO_CREDENTIAL;
329 client->updated = 1;
330 return GSS_S_COMPLETE;
331 }
254 332
255 client->mech = NULL; 333 client->mech = NULL;
256 334
@@ -265,6 +343,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
265 if (client->mech == NULL) 343 if (client->mech == NULL)
266 return GSS_S_FAILURE; 344 return GSS_S_FAILURE;
267 345
346 if (ctx->client_creds &&
347 (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
348 ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
349 ssh_gssapi_error(ctx);
350 return (ctx->major);
351 }
352
268 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, 353 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
269 &client->displayname, NULL))) { 354 &client->displayname, NULL))) {
270 ssh_gssapi_error(ctx); 355 ssh_gssapi_error(ctx);
@@ -282,6 +367,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
282 return (ctx->major); 367 return (ctx->major);
283 } 368 }
284 369
370 gss_release_buffer(&ctx->minor, &ename);
371
285 /* We can't copy this structure, so we just move the pointer to it */ 372 /* We can't copy this structure, so we just move the pointer to it */
286 client->creds = ctx->client_creds; 373 client->creds = ctx->client_creds;
287 ctx->client_creds = GSS_C_NO_CREDENTIAL; 374 ctx->client_creds = GSS_C_NO_CREDENTIAL;
@@ -329,7 +416,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep)
329 416
330/* Privileged */ 417/* Privileged */
331int 418int
332ssh_gssapi_userok(char *user) 419ssh_gssapi_userok(char *user, struct passwd *pw)
333{ 420{
334 OM_uint32 lmin; 421 OM_uint32 lmin;
335 422
@@ -339,9 +426,11 @@ ssh_gssapi_userok(char *user)
339 return 0; 426 return 0;
340 } 427 }
341 if (gssapi_client.mech && gssapi_client.mech->userok) 428 if (gssapi_client.mech && gssapi_client.mech->userok)
342 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) 429 if ((*gssapi_client.mech->userok)(&gssapi_client, user)) {
430 gssapi_client.used = 1;
431 gssapi_client.store.owner = pw;
343 return 1; 432 return 1;
344 else { 433 } else {
345 /* Destroy delegated credentials if userok fails */ 434 /* Destroy delegated credentials if userok fails */
346 gss_release_buffer(&lmin, &gssapi_client.displayname); 435 gss_release_buffer(&lmin, &gssapi_client.displayname);
347 gss_release_buffer(&lmin, &gssapi_client.exportedname); 436 gss_release_buffer(&lmin, &gssapi_client.exportedname);
@@ -354,14 +443,90 @@ ssh_gssapi_userok(char *user)
354 return (0); 443 return (0);
355} 444}
356 445
357/* Privileged */ 446/* These bits are only used for rekeying. The unpriviledged child is running
358OM_uint32 447 * as the user, the monitor is root.
359ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) 448 *
449 * In the child, we want to :
450 * *) Ask the monitor to store our credentials into the store we specify
451 * *) If it succeeds, maybe do a PAM update
452 */
453
454/* Stuff for PAM */
455
456#ifdef USE_PAM
457static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg,
458 struct pam_response **resp, void *data)
360{ 459{
361 ctx->major = gss_verify_mic(&ctx->minor, ctx->context, 460 return (PAM_CONV_ERR);
362 gssbuf, gssmic, NULL); 461}
462#endif
363 463
364 return (ctx->major); 464void
465ssh_gssapi_rekey_creds() {
466 int ok;
467 int ret;
468#ifdef USE_PAM
469 pam_handle_t *pamh = NULL;
470 struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
471 char *envstr;
472#endif
473
474 if (gssapi_client.store.filename == NULL &&
475 gssapi_client.store.envval == NULL &&
476 gssapi_client.store.envvar == NULL)
477 return;
478
479 ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));
480
481 if (!ok)
482 return;
483
484 debug("Rekeyed credentials stored successfully");
485
486 /* Actually managing to play with the ssh pam stack from here will
487 * be next to impossible. In any case, we may want different options
488 * for rekeying. So, use our own :)
489 */
490#ifdef USE_PAM
491 if (!use_privsep) {
492 debug("Not even going to try and do PAM with privsep disabled");
493 return;
494 }
495
496 ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
497 &pamconv, &pamh);
498 if (ret)
499 return;
500
501 xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar,
502 gssapi_client.store.envval);
503
504 ret = pam_putenv(pamh, envstr);
505 if (!ret)
506 pam_setcred(pamh, PAM_REINITIALIZE_CRED);
507 pam_end(pamh, PAM_SUCCESS);
508#endif
509}
510
511int
512ssh_gssapi_update_creds(ssh_gssapi_ccache *store) {
513 int ok = 0;
514
515 /* Check we've got credentials to store */
516 if (!gssapi_client.updated)
517 return 0;
518
519 gssapi_client.updated = 0;
520
521 temporarily_use_uid(gssapi_client.store.owner);
522 if (gssapi_client.mech && gssapi_client.mech->updatecreds)
523 ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client);
524 else
525 debug("No update function for this mechanism");
526
527 restore_uid();
528
529 return ok;
365} 530}
366 531
367#endif 532#endif