diff -u openssh-keyex/auth2-gss.c openssh-keyex-reconnect/auth2-gss.c --- openssh-keyex/auth2-gss.c 2008-04-04 12:52:22.000000000 +0100 +++ openssh-keyex-reconnect/auth2-gss.c 2008-04-04 12:51:44.000000000 +0100 @@ -1,7 +1,7 @@ /* $OpenBSD: auth2-gss.c,v 1.16 2007/10/29 00:52:45 dtucker Exp $ */ /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -77,7 +77,8 @@ /* gss_kex_context is NULL with privsep, so we can't check it here */ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, &gssbuf, &mic)))) - authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); + authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, + authctxt->pw)); buffer_free(&b); xfree(mic.value); @@ -277,7 +278,8 @@ packet_check_eom(); - authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); + authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, + authctxt->pw)); authctxt->postponed = 0; dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); @@ -312,7 +314,8 @@ gssbuf.length = buffer_len(&b); if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) - authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); + authenticated = + PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw)); else logit("GSSAPI MIC check failed"); diff -u openssh-keyex/clientloop.c openssh-keyex-reconnect/clientloop.c --- openssh-keyex/clientloop.c 2008-04-04 12:52:23.000000000 +0100 +++ openssh-keyex-reconnect/clientloop.c 2008-04-04 12:51:45.000000000 +0100 @@ -110,6 +110,10 @@ #include "match.h" #include "msg.h" +#ifdef GSSAPI +#include "ssh-gss.h" +#endif + /* import options */ extern Options options; @@ -1514,6 +1518,13 @@ /* Do channel operations unless rekeying in progress. */ if (!rekeying) { channel_after_select(readset, writeset); + + if (options.gss_renewal_rekey && + ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) { + debug("credentials updated - forcing rekey"); + need_rekeying = 1; + } + if (need_rekeying || packet_need_rekeying()) { debug("need rekeying"); xxx_kex->done = 0; diff -u openssh-keyex/gss-genr.c openssh-keyex-reconnect/gss-genr.c --- openssh-keyex/gss-genr.c 2007-09-27 21:20:20.000000000 +0100 +++ openssh-keyex-reconnect/gss-genr.c 2007-10-05 13:54:01.000000000 +0100 @@ -446,4 +446,61 @@ return (!GSS_ERROR(major)); } +int +ssh_gssapi_credentials_updated(Gssctxt *ctxt) { + static gss_name_t saved_name = GSS_C_NO_NAME; + static OM_uint32 saved_lifetime = 0; + static gss_OID saved_mech = GSS_C_NO_OID; + static gss_name_t name; + static OM_uint32 last_call = 0; + OM_uint32 lifetime, now, major, minor; + int equal; + gss_cred_usage_t usage = GSS_C_INITIATE; + + now = time(NULL); + + if (ctxt) { + debug("Rekey has happened - updating saved versions"); + + if (saved_name != GSS_C_NO_NAME) + gss_release_name(&minor, &saved_name); + + major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, + &saved_name, &saved_lifetime, NULL, NULL); + + if (!GSS_ERROR(major)) { + saved_mech = ctxt->oid; + saved_lifetime+= now; + } else { + /* Handle the error */ + } + return 0; + } + + if (now - last_call < 10) + return 0; + + last_call = now; + + if (saved_mech == GSS_C_NO_OID) + return 0; + + major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, + &name, &lifetime, NULL, NULL); + if (major == GSS_S_CREDENTIALS_EXPIRED) + return 0; + else if (GSS_ERROR(major)) + return 0; + + major = gss_compare_name(&minor, saved_name, name, &equal); + gss_release_name(&minor, &name); + if (GSS_ERROR(major)) + return 0; + + if (equal && (saved_lifetime < lifetime + now - 10)) + return 1; + + return 0; +} + #endif /* GSSAPI */ diff -u openssh-keyex/gss-serv.c openssh-keyex-reconnect/gss-serv.c --- openssh-keyex/gss-serv.c 2008-04-04 12:44:06.000000000 +0100 +++ openssh-keyex-reconnect/gss-serv.c 2008-04-04 12:50:01.000000000 +0100 @@ -45,6 +45,7 @@ #include "session.h" #include "misc.h" #include "servconf.h" +#include "uidswap.h" #include "ssh-gss.h" #include "monitor_wrap.h" @@ -53,10 +54,10 @@ static ssh_gssapi_client gssapi_client = { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, - GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}}; + GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL}, 0, 0}; ssh_gssapi_mech gssapi_null_mech = - { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; + { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; #ifdef KRB5 extern ssh_gssapi_mech gssapi_kerberos_mech; @@ -279,8 +280,48 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) { int i = 0; + int equal = 0; + gss_name_t new_name = GSS_C_NO_NAME; + gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; + + if (options.gss_store_rekey && client->used && ctx->client_creds) { + if (client->mech->oid.length != ctx->oid->length || + (memcmp(client->mech->oid.elements, + ctx->oid->elements, ctx->oid->length) !=0)) { + debug("Rekeyed credentials have different mechanism"); + return GSS_S_COMPLETE; + } + + if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, + ctx->client_creds, ctx->oid, &new_name, + NULL, NULL, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } + + ctx->major = gss_compare_name(&ctx->minor, client->name, + new_name, &equal); + + if (GSS_ERROR(ctx->major)) { + ssh_gssapi_error(ctx); + return (ctx->major); + } + + if (!equal) { + debug("Rekeyed credentials have different name"); + return GSS_S_COMPLETE; + } - gss_buffer_desc ename; + debug("Marking rekeyed credentials for export"); + + gss_release_name(&ctx->minor, &client->name); + gss_release_cred(&ctx->minor, &client->creds); + client->name = new_name; + client->creds = ctx->client_creds; + ctx->client_creds = GSS_C_NO_CREDENTIAL; + client->updated = 1; + return GSS_S_COMPLETE; + } client->mech = NULL; @@ -295,6 +336,13 @@ if (client->mech == NULL) return GSS_S_FAILURE; + if (ctx->client_creds && + (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, + ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } + if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, &client->displayname, NULL))) { ssh_gssapi_error(ctx); @@ -312,6 +360,8 @@ return (ctx->major); } + gss_release_buffer(&ctx->minor, &ename); + /* We can't copy this structure, so we just move the pointer to it */ client->creds = ctx->client_creds; ctx->client_creds = GSS_C_NO_CREDENTIAL; @@ -359,7 +409,7 @@ /* Privileged */ int -ssh_gssapi_userok(char *user) +ssh_gssapi_userok(char *user, struct passwd *pw) { OM_uint32 lmin; @@ -369,9 +419,11 @@ return 0; } if (gssapi_client.mech && gssapi_client.mech->userok) - if ((*gssapi_client.mech->userok)(&gssapi_client, user)) + if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { + gssapi_client.used = 1; + gssapi_client.store.owner = pw; return 1; - else { + } else { /* Destroy delegated credentials if userok fails */ gss_release_buffer(&lmin, &gssapi_client.displayname); gss_release_buffer(&lmin, &gssapi_client.exportedname); @@ -384,4 +436,90 @@ return (0); } +/* These bits are only used for rekeying. The unpriviledged child is running + * as the user, the monitor is root. + * + * In the child, we want to : + * *) Ask the monitor to store our credentials into the store we specify + * *) If it succeeds, maybe do a PAM update + */ + +/* Stuff for PAM */ + +#ifdef USE_PAM +static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, + struct pam_response **resp, void *data) +{ + return (PAM_CONV_ERR); +} +#endif + +void +ssh_gssapi_rekey_creds() { + int ok; + int ret; +#ifdef USE_PAM + pam_handle_t *pamh = NULL; + struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; + char *envstr; +#endif + + if (gssapi_client.store.filename == NULL && + gssapi_client.store.envval == NULL && + gssapi_client.store.envvar == NULL) + return; + + ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); + + if (!ok) + return; + + debug("Rekeyed credentials stored successfully"); + + /* Actually managing to play with the ssh pam stack from here will + * be next to impossible. In any case, we may want different options + * for rekeying. So, use our own :) + */ +#ifdef USE_PAM + if (!use_privsep) { + debug("Not even going to try and do PAM with privsep disabled"); + return; + } + + ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, + &pamconv, &pamh); + if (ret) + return; + + xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, + gssapi_client.store.envval); + + ret = pam_putenv(pamh, envstr); + if (!ret) + pam_setcred(pamh, PAM_REINITIALIZE_CRED); + pam_end(pamh, PAM_SUCCESS); +#endif +} + +int +ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { + int ok = 0; + + /* Check we've got credentials to store */ + if (!gssapi_client.updated) + return 0; + + gssapi_client.updated = 0; + + temporarily_use_uid(gssapi_client.store.owner); + if (gssapi_client.mech && gssapi_client.mech->updatecreds) + ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); + else + debug("No update function for this mechanism"); + + restore_uid(); + + return ok; +} + #endif diff -u openssh-keyex/gss-serv.c.orig openssh-keyex-reconnect/gss-serv.c.orig --- openssh-keyex/gss-serv.c.orig 2007-09-27 22:15:39.000000000 +0100 +++ openssh-keyex-reconnect/gss-serv.c.orig 2008-03-28 14:48:33.000000000 +0000 @@ -1,7 +1,7 @@ /* $OpenBSD: gss-serv.c,v 1.21 2007/06/12 08:20:00 djm Exp $ */ /* - * Copyright (c) 2001-2006 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2008 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,6 +45,7 @@ #include "session.h" #include "misc.h" #include "servconf.h" +#include "uidswap.h" #include "ssh-gss.h" #include "monitor_wrap.h" @@ -53,10 +54,10 @@ static ssh_gssapi_client gssapi_client = { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, - GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}}; + GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL}, 0, 0}; ssh_gssapi_mech gssapi_null_mech = - { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; + { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; #ifdef KRB5 extern ssh_gssapi_mech gssapi_kerberos_mech; @@ -272,8 +273,48 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) { int i = 0; + int equal = 0; + gss_name_t new_name = GSS_C_NO_NAME; + gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; + + if (options.gss_store_rekey && client->used && ctx->client_creds) { + if (client->mech->oid.length != ctx->oid->length || + (memcmp(client->mech->oid.elements, + ctx->oid->elements, ctx->oid->length) !=0)) { + debug("Rekeyed credentials have different mechanism"); + return GSS_S_COMPLETE; + } + + if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, + ctx->client_creds, ctx->oid, &new_name, + NULL, NULL, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } - gss_buffer_desc ename; + ctx->major = gss_compare_name(&ctx->minor, client->name, + new_name, &equal); + + if (GSS_ERROR(ctx->major)) { + ssh_gssapi_error(ctx); + return (ctx->major); + } + + if (!equal) { + debug("Rekeyed credentials have different name"); + return GSS_S_COMPLETE; + } + + debug("Marking rekeyed credentials for export"); + + gss_release_name(&ctx->minor, &client->name); + gss_release_cred(&ctx->minor, &client->creds); + client->name = new_name; + client->creds = ctx->client_creds; + ctx->client_creds = GSS_C_NO_CREDENTIAL; + client->updated = 1; + return GSS_S_COMPLETE; + } client->mech = NULL; @@ -288,6 +329,13 @@ if (client->mech == NULL) return GSS_S_FAILURE; + if (ctx->client_creds && + (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, + ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } + if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, &client->displayname, NULL))) { ssh_gssapi_error(ctx); @@ -305,6 +353,8 @@ return (ctx->major); } + gss_release_buffer(&ctx->minor, &ename); + /* We can't copy this structure, so we just move the pointer to it */ client->creds = ctx->client_creds; ctx->client_creds = GSS_C_NO_CREDENTIAL; @@ -352,7 +402,7 @@ /* Privileged */ int -ssh_gssapi_userok(char *user) +ssh_gssapi_userok(char *user, struct passwd *pw) { OM_uint32 lmin; @@ -362,9 +412,11 @@ return 0; } if (gssapi_client.mech && gssapi_client.mech->userok) - if ((*gssapi_client.mech->userok)(&gssapi_client, user)) + if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { + gssapi_client.used = 1; + gssapi_client.store.owner = pw; return 1; - else { + } else { /* Destroy delegated credentials if userok fails */ gss_release_buffer(&lmin, &gssapi_client.displayname); gss_release_buffer(&lmin, &gssapi_client.exportedname); @@ -377,4 +429,90 @@ return (0); } +/* These bits are only used for rekeying. The unpriviledged child is running + * as the user, the monitor is root. + * + * In the child, we want to : + * *) Ask the monitor to store our credentials into the store we specify + * *) If it succeeds, maybe do a PAM update + */ + +/* Stuff for PAM */ + +#ifdef USE_PAM +static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, + struct pam_response **resp, void *data) +{ + return (PAM_CONV_ERR); +} +#endif + +void +ssh_gssapi_rekey_creds() { + int ok; + int ret; +#ifdef USE_PAM + pam_handle_t *pamh = NULL; + struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; + char *envstr; +#endif + + if (gssapi_client.store.filename == NULL && + gssapi_client.store.envval == NULL && + gssapi_client.store.envvar == NULL) + return; + + ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); + + if (!ok) + return; + + debug("Rekeyed credentials stored successfully"); + + /* Actually managing to play with the ssh pam stack from here will + * be next to impossible. In any case, we may want different options + * for rekeying. So, use our own :) + */ +#ifdef USE_PAM + if (!use_privsep) { + debug("Not even going to try and do PAM with privsep disabled"); + return; + } + + ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, + &pamconv, &pamh); + if (ret) + return; + + xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, + gssapi_client.store.envval); + + ret = pam_putenv(pamh, envstr); + if (!ret) + pam_setcred(pamh, PAM_REINITIALIZE_CRED); + pam_end(pamh, PAM_SUCCESS); +#endif +} + +int +ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { + int ok = 0; + + /* Check we've got credentials to store */ + if (!gssapi_client.updated) + return 0; + + gssapi_client.updated = 0; + + temporarily_use_uid(gssapi_client.store.owner); + if (gssapi_client.mech && gssapi_client.mech->updatecreds) + ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); + else + debug("No update function for this mechanism"); + + restore_uid(); + + return ok; +} + #endif diff -u openssh-keyex/gss-serv-krb5.c openssh-keyex-reconnect/gss-serv-krb5.c --- openssh-keyex/gss-serv-krb5.c 2007-03-12 20:47:53.000000000 +0000 +++ openssh-keyex-reconnect/gss-serv-krb5.c 2007-10-05 14:00:55.000000000 +0100 @@ -1,7 +1,7 @@ /* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */ /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -190,6 +190,71 @@ return; } +int +ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, + ssh_gssapi_client *client) +{ + krb5_ccache ccache = NULL; + krb5_principal principal = NULL; + char *name = NULL; + krb5_error_code problem; + OM_uint32 maj_status, min_status; + + if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { + logit("krb5_cc_resolve(): %.100s", + krb5_get_err_text(krb_context, problem)); + return 0; + } + + /* Find out who the principal in this cache is */ + if ((problem = krb5_cc_get_principal(krb_context, ccache, + &principal))) { + logit("krb5_cc_get_principal(): %.100s", + krb5_get_err_text(krb_context, problem)); + krb5_cc_close(krb_context, ccache); + return 0; + } + + if ((problem = krb5_unparse_name(krb_context, principal, &name))) { + logit("krb5_unparse_name(): %.100s", + krb5_get_err_text(krb_context, problem)); + krb5_free_principal(krb_context, principal); + krb5_cc_close(krb_context, ccache); + return 0; + } + + + if (strcmp(name,client->exportedname.value)!=0) { + debug("Name in local credentials cache differs. Not storing"); + krb5_free_principal(krb_context, principal); + krb5_cc_close(krb_context, ccache); + krb5_free_unparsed_name(krb_context, name); + return 0; + } + krb5_free_unparsed_name(krb_context, name); + + /* Name matches, so lets get on with it! */ + + if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) { + logit("krb5_cc_initialize(): %.100s", + krb5_get_err_text(krb_context, problem)); + krb5_free_principal(krb_context, principal); + krb5_cc_close(krb_context, ccache); + return 0; + } + + krb5_free_principal(krb_context, principal); + + if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, + ccache))) { + logit("gss_krb5_copy_ccache() failed. Sorry!"); + krb5_cc_close(krb_context, ccache); + return 0; + } + + return 1; +} + ssh_gssapi_mech gssapi_kerberos_mech = { "toWM5Slw5Ew8Mqkay+al2g==", "Kerberos", @@ -197,7 +262,8 @@ NULL, &ssh_gssapi_krb5_userok, NULL, - &ssh_gssapi_krb5_storecreds + &ssh_gssapi_krb5_storecreds, + &ssh_gssapi_krb5_updatecreds }; #endif /* KRB5 */ diff -u openssh-keyex/kexgssc.c openssh-keyex-reconnect/kexgssc.c --- openssh-keyex/kexgssc.c 2006-09-11 16:19:44.000000000 +0100 +++ openssh-keyex-reconnect/kexgssc.c 2006-09-11 16:20:57.000000000 +0100 @@ -306,6 +306,9 @@ memcpy(kex->session_id, hash, kex->session_id_len); } + if (kex->gss_deleg_creds) + ssh_gssapi_credentials_updated(ctxt); + if (gss_kex_context == NULL) gss_kex_context = ctxt; else diff -u openssh-keyex/kexgsss.c openssh-keyex-reconnect/kexgsss.c --- openssh-keyex/kexgsss.c 2006-09-11 16:20:04.000000000 +0100 +++ openssh-keyex-reconnect/kexgsss.c 2007-01-10 22:08:07.000000000 +0000 @@ -42,6 +42,9 @@ #include "dh.h" #include "ssh-gss.h" #include "monitor_wrap.h" +#include "servconf.h" + +extern ServerOptions options; void kexgss_server(Kex *kex) @@ -267,5 +270,10 @@ kex_derive_keys(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); + + /* If this was a rekey, then save out any delegated credentials we + * just exchanged. */ + if (options.gss_store_rekey) + ssh_gssapi_rekey_creds(); } #endif /* GSSAPI */ diff -u openssh-keyex/monitor.c openssh-keyex-reconnect/monitor.c --- openssh-keyex/monitor.c 2008-04-04 12:52:24.000000000 +0100 +++ openssh-keyex-reconnect/monitor.c 2008-04-04 12:51:46.000000000 +0100 @@ -164,6 +164,7 @@ int mm_answer_gss_userok(int, Buffer *); int mm_answer_gss_checkmic(int, Buffer *); int mm_answer_gss_sign(int, Buffer *); +int mm_answer_gss_updatecreds(int, Buffer *); #endif #ifdef SSH_AUDIT_EVENTS @@ -243,6 +244,7 @@ {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, + {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, #endif {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, {MONITOR_REQ_SIGN, 0, mm_answer_sign}, @@ -1969,7 +1971,8 @@ { int authenticated; - authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); + authenticated = authctxt->valid && + ssh_gssapi_userok(authctxt->user, authctxt->pw); buffer_clear(m); buffer_put_int(m, authenticated); @@ -2016,8 +2019,34 @@ /* Turn on getpwnam permissions */ monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); + + /* And credential updating, for when rekeying */ + monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1); return (0); } +int +mm_answer_gss_updatecreds(int socket, Buffer *m) { + ssh_gssapi_ccache store; + int ok; + + store.filename = buffer_get_string(m, NULL); + store.envvar = buffer_get_string(m, NULL); + store.envval = buffer_get_string(m, NULL); + + ok = ssh_gssapi_update_creds(&store); + + xfree(store.filename); + xfree(store.envvar); + xfree(store.envval); + + buffer_clear(m); + buffer_put_int(m, ok); + + mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m); + + return(0); +} + #endif /* GSSAPI */ diff -u openssh-keyex/monitor.h openssh-keyex-reconnect/monitor.h --- openssh-keyex/monitor.h 2006-09-08 14:33:06.000000000 +0100 +++ openssh-keyex-reconnect/monitor.h 2006-09-09 00:49:34.000000000 +0100 @@ -54,6 +54,7 @@ MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN, + MONITOR_REQ_GSSUPCREDS, MONITOR_ANS_GSSUPCREDS, MONITOR_REQ_PAM_START, MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, diff -u openssh-keyex/monitor_wrap.c openssh-keyex-reconnect/monitor_wrap.c --- openssh-keyex/monitor_wrap.c 2008-04-04 12:52:24.000000000 +0100 +++ openssh-keyex-reconnect/monitor_wrap.c 2008-04-04 12:51:47.000000000 +0100 @@ -1221,7 +1221,7 @@ } int -mm_ssh_gssapi_userok(char *user) +mm_ssh_gssapi_userok(char *user, struct passwd *pw) { Buffer m; int authenticated = 0; @@ -1261,4 +1261,26 @@ return(major); } +int +mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) +{ + Buffer m; + int ok; + + buffer_init(&m); + + buffer_put_cstring(&m, store->filename ? store->filename : ""); + buffer_put_cstring(&m, store->envvar ? store->envvar : ""); + buffer_put_cstring(&m, store->envval ? store->envval : ""); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m); + + ok = buffer_get_int(&m); + + buffer_free(&m); + + return (ok); +} + #endif /* GSSAPI */ diff -u openssh-keyex/monitor_wrap.h openssh-keyex-reconnect/monitor_wrap.h --- openssh-keyex/monitor_wrap.h 2006-09-08 14:33:06.000000000 +0100 +++ openssh-keyex-reconnect/monitor_wrap.h 2006-09-09 00:30:31.000000000 +0100 @@ -57,9 +57,10 @@ OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); -int mm_ssh_gssapi_userok(char *user); +int mm_ssh_gssapi_userok(char *user, struct passwd *); OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); +int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *); #endif #ifdef USE_PAM diff -u openssh-keyex/readconf.c openssh-keyex-reconnect/readconf.c --- openssh-keyex/readconf.c 2008-04-04 12:52:24.000000000 +0100 +++ openssh-keyex-reconnect/readconf.c 2008-04-04 12:51:47.000000000 +0100 @@ -128,7 +128,7 @@ oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, oGssKeyEx, - oGssTrustDns, + oGssTrustDns, oGssRenewalRekey, oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, @@ -168,11 +168,13 @@ { "gssapikeyexchange", oGssKeyEx }, { "gssapidelegatecredentials", oGssDelegateCreds }, { "gssapitrustdns", oGssTrustDns }, + { "gssapirenewalforcesrekey", oGssRenewalRekey }, #else { "gssapiauthentication", oUnsupported }, { "gssapikeyexchange", oUnsupported }, { "gssapidelegatecredentials", oUnsupported }, { "gssapitrustdns", oUnsupported }, + { "gssapirenewalforcesrekey", oUnsupported }, #endif { "fallbacktorsh", oDeprecated }, { "usersh", oDeprecated }, @@ -460,6 +462,10 @@ intptr = &options->gss_trust_dns; goto parse_flag; + case oGssRenewalRekey: + intptr = &options->gss_renewal_rekey; + goto parse_flag; + case oBatchMode: intptr = &options->batch_mode; goto parse_flag; @@ -1027,6 +1033,7 @@ options->gss_keyex = -1; options->gss_deleg_creds = -1; options->gss_trust_dns = -1; + options->gss_renewal_rekey = -1; options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->kbd_interactive_devices = NULL; @@ -1121,6 +1128,8 @@ options->gss_deleg_creds = 0; if (options->gss_trust_dns == -1) options->gss_trust_dns = 0; + if (options->gss_renewal_rekey == -1) + options->gss_renewal_rekey = 0; if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) diff -u openssh-keyex/readconf.h openssh-keyex-reconnect/readconf.h --- openssh-keyex/readconf.h 2008-04-04 12:52:24.000000000 +0100 +++ openssh-keyex-reconnect/readconf.h 2008-04-04 12:51:47.000000000 +0100 @@ -47,6 +47,7 @@ int gss_keyex; /* Try GSS key exchange */ int gss_deleg_creds; /* Delegate GSS credentials */ int gss_trust_dns; /* Trust DNS for GSS canonicalization */ + int gss_renewal_rekey; /* GSS credential renewal forces conneciton rekey */ int password_authentication; /* Try password * authentication. */ int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ diff -u openssh-keyex/servconf.c openssh-keyex-reconnect/servconf.c --- openssh-keyex/servconf.c 2008-04-04 12:54:35.000000000 +0100 +++ openssh-keyex-reconnect/servconf.c 2008-04-04 12:54:43.000000000 +0100 @@ -93,6 +93,7 @@ options->gss_keyex = -1; options->gss_cleanup_creds = -1; options->gss_strict_acceptor = -1; + options->gss_store_rekey = -1; options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->challenge_response_authentication = -1; @@ -213,6 +214,8 @@ options->gss_cleanup_creds = 1; if (options->gss_strict_acceptor == -1) options->gss_strict_acceptor = 1; + if (options->gss_store_rekey == -1) + options->gss_store_rekey = 0; if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) @@ -298,7 +301,7 @@ sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, - sGssKeyEx, + sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, @@ -362,11 +365,13 @@ { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, #else { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, #endif { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, @@ -899,6 +904,10 @@ intptr = &options->gss_strict_acceptor; goto parse_flag; + case sGssStoreRekey: + intptr = &options->gss_store_rekey; + goto parse_flag; + case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; diff -u openssh-keyex/servconf.h openssh-keyex-reconnect/servconf.h --- openssh-keyex/servconf.h 2008-04-04 12:52:25.000000000 +0100 +++ openssh-keyex-reconnect/servconf.h 2008-04-04 12:51:47.000000000 +0100 @@ -93,6 +93,7 @@ int gss_keyex; /* If true, permit GSSAPI key exchange */ int gss_cleanup_creds; /* If true, destroy cred cache on logout */ int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ + int gss_store_rekey; int password_authentication; /* If true, permit password * authentication. */ int kbd_interactive_authentication; /* If true, permit */ diff -u openssh-keyex/ssh_config.5 openssh-keyex-reconnect/ssh_config.5 --- openssh-keyex/ssh_config.5 2008-04-04 12:52:26.000000000 +0100 +++ openssh-keyex-reconnect/ssh_config.5 2008-04-04 12:51:48.000000000 +0100 @@ -490,15 +490,23 @@ Note that this option applies to protocol version 2 only. .It Cm GSSAPITrustDns Set to -.Dq yes +.Dq yes to indicate that the DNS is trusted to securely canonicalize the name of the host being connected to. If -.Dq no , +.Dq no , the hostname entered on the command line will be passed untouched to the GSSAPI library. The default is .Dq no . This option only applies to protocol version 2 connections using GSSAPI. +.It Cm GSSAPIRenewalForcesRekey +If set to +.Dq yes +then renewal of the client's GSSAPI credentials will force the rekeying of the +ssh connection. With a compatible server, this can delegate the renewed +credentials to a session on the server. +The default is +.Dq no . .It Cm HashKnownHosts Indicates that .Xr ssh 1 diff -u openssh-keyex/sshd_config.5 openssh-keyex-reconnect/sshd_config.5 --- openssh-keyex/sshd_config.5 2008-04-04 12:52:26.000000000 +0100 +++ openssh-keyex-reconnect/sshd_config.5 2008-04-04 12:51:49.000000000 +0100 @@ -394,6 +394,11 @@ and setting it to .Dq no may only work with recent Kerberos GSSAPI libraries. +.It Cm GSSAPIStoreCredentialsOnRekey +Controls whether the user's GSSAPI credentials should be updated following a +successful connection rekeying. This option can be used to accepted renewed +or updated credentials from a compatible client. The default is +.Dq no . .It Cm HostbasedAuthentication Specifies whether rhosts or /etc/hosts.equiv authentication together with successful public key client host authentication is allowed diff -u openssh-keyex/ssh-gss.h openssh-keyex-reconnect/ssh-gss.h --- openssh-keyex/ssh-gss.h 2007-09-27 21:17:08.000000000 +0100 +++ openssh-keyex-reconnect/ssh-gss.h 2007-10-05 14:05:42.000000000 +0100 @@ -1,6 +1,6 @@ /* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */ /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -75,6 +75,7 @@ char *filename; char *envvar; char *envval; + struct passwd *owner; void *data; } ssh_gssapi_ccache; @@ -82,8 +83,11 @@ gss_buffer_desc displayname; gss_buffer_desc exportedname; gss_cred_id_t creds; + gss_name_t name; struct ssh_gssapi_mech_struct *mech; ssh_gssapi_ccache store; + int used; + int updated; } ssh_gssapi_client; typedef struct ssh_gssapi_mech_struct { @@ -94,6 +98,7 @@ int (*userok) (ssh_gssapi_client *, char *); int (*localname) (ssh_gssapi_client *, char **); void (*storecreds) (ssh_gssapi_client *); + int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); } ssh_gssapi_mech; typedef struct { @@ -129,6 +134,7 @@ OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); +int ssh_gssapi_credentials_updated(Gssctxt *); /* In the server */ typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *); @@ -137,7 +143,7 @@ gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *); OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); -int ssh_gssapi_userok(char *name); +int ssh_gssapi_userok(char *name, struct passwd *); OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); void ssh_gssapi_do_child(char ***, u_int *); void ssh_gssapi_cleanup_creds(void); @@ -145,6 +151,8 @@ char *ssh_gssapi_server_mechanisms(void); int ssh_gssapi_oid_table_ok(); + +int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); #endif /* GSSAPI */ #endif /* _SSH_GSS_H */