summaryrefslogtreecommitdiff
path: root/gss-serv.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2010-01-01 23:53:30 +0000
committerColin Watson <cjwatson@debian.org>2010-01-01 23:53:30 +0000
commitdf03186a4f9e0c2ece398b5c0571cb6263d7a752 (patch)
tree1aab079441dff9615274769b19f2d734ddf508dd /gss-serv.c
parent6ad6994c288662fca6949f42bf91fec2aff00bca (diff)
parent99b402ea4c8457b0a3cafff37f5b3410a8dc6476 (diff)
* New upstream release (closes: #536182). Yes, I know 5.3p1 has been out
for a while, but there's no GSSAPI patch available for it yet. - Change the default cipher order to prefer the AES CTR modes and the revised "arcfour256" mode to CBC mode ciphers that are susceptible to CPNI-957037 "Plaintext Recovery Attack Against SSH". - Add countermeasures to mitigate CPNI-957037-style attacks against the SSH protocol's use of CBC-mode ciphers. Upon detection of an invalid packet length or Message Authentication Code, ssh/sshd will continue reading up to the maximum supported packet length rather than immediately terminating the connection. This eliminates most of the known differences in behaviour that leaked information about the plaintext of injected data which formed the basis of this attack (closes: #506115, LP: #379329). - ForceCommand directive now accepts commandline arguments for the internal-sftp server (closes: #524423, LP: #362511). - Add AllowAgentForwarding to available Match keywords list (closes: #540623). - Make ssh(1) send the correct channel number for SSH2_MSG_CHANNEL_SUCCESS and SSH2_MSG_CHANNEL_FAILURE messages to avoid triggering 'Non-public channel' error messages on sshd(8) in openssh-5.1. - Avoid printing 'Non-public channel' warnings in sshd(8), since the ssh(1) has sent incorrect channel numbers since ~2004 (this reverts a behaviour introduced in openssh-5.1; closes: #496017). * Update to GSSAPI patch from http://www.sxw.org.uk/computing/patches/openssh-5.2p1-gsskex-all-20090726.patch, including cascading credentials support (LP: #416958).
Diffstat (limited to 'gss-serv.c')
-rw-r--r--gss-serv.c161
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
55static ssh_gssapi_client gssapi_client = 56static 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
59ssh_gssapi_mech gssapi_null_mech = 60ssh_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
63extern ssh_gssapi_mech gssapi_kerberos_mech; 64extern 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 */
138int 139int
139ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data) { 140ssh_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
280ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 284ssh_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 */
362int 415int
363ssh_gssapi_userok(char *user) 416ssh_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
454static 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
461void
462ssh_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
508int
509ssh_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