X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/ae82558bfb0b9500c4739e0b867bec6574437e7e..9f2c8cb950fea61c599edeb9721aca66f4bd61f6:/openssh/gss-serv.c diff --git a/openssh/gss-serv.c b/openssh/gss-serv.c index 39184d7..6fbc09d 100644 --- a/openssh/gss-serv.c +++ b/openssh/gss-serv.c @@ -1,7 +1,7 @@ -/* $OpenBSD: gss-serv.c,v 1.20 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */ /* - * Copyright (c) 2001-2006 Simon Wilkinson. All rights reserved. + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,11 +29,13 @@ #ifdef GSSAPI #include +#include #include #include #include +#include "openbsd-compat/sys-queue.h" #include "xmalloc.h" #include "buffer.h" #include "key.h" @@ -44,6 +46,7 @@ #include "session.h" #include "misc.h" #include "servconf.h" +#include "uidswap.h" #include "xmalloc.h" #include "ssh-gss.h" @@ -54,10 +57,10 @@ extern Authctxt *the_authctxt; 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; @@ -80,6 +83,59 @@ ssh_gssapi_mech* supported_mechs[]= { static int limited = 0; #endif +/* + * Acquire credentials for a server running on the current host. + * Requires that the context structure contains a valid OID + */ + +/* Returns a GSSAPI error code */ +/* Privileged (called from ssh_gssapi_server_ctx) */ +static OM_uint32 +ssh_gssapi_acquire_cred(Gssctxt *ctx) +{ + OM_uint32 status; + char lname[MAXHOSTNAMELEN]; + gss_OID_set oidset; + + if (options.gss_strict_acceptor) { + gss_create_empty_oid_set(&status, &oidset); + gss_add_oid_set_member(&status, ctx->oid, &oidset); + + if (gethostname(lname, MAXHOSTNAMELEN)) { + gss_release_oid_set(&status, &oidset); + return (-1); + } + + if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { + gss_release_oid_set(&status, &oidset); + return (ctx->major); + } + + if ((ctx->major = gss_acquire_cred(&ctx->minor, + ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, + NULL, NULL))) + ssh_gssapi_error(ctx); + + gss_release_oid_set(&status, &oidset); + return (ctx->major); + } else { + ctx->name = GSS_C_NO_NAME; + ctx->creds = GSS_C_NO_CREDENTIAL; + } + return GSS_S_COMPLETE; +} + +/* Privileged */ +OM_uint32 +ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) +{ + if (*ctx) + ssh_gssapi_delete_ctx(ctx); + ssh_gssapi_build_ctx(ctx); + ssh_gssapi_set_oid(*ctx, oid); + return (ssh_gssapi_acquire_cred(*ctx)); +} + /* Unprivileged */ char * ssh_gssapi_server_mechanisms() { @@ -87,12 +143,13 @@ ssh_gssapi_server_mechanisms() { ssh_gssapi_supported_oids(&supported); return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech, - NULL)); + NULL, NULL)); } /* Unprivileged */ int -ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data) { +ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data, + const char *dummy) { Gssctxt *ctx = NULL; int res; @@ -112,8 +169,10 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset) gss_OID_set supported; gss_create_empty_oid_set(&min_status, oidset); - /* Ask priviledged process what mechanisms it supports. */ - PRIVSEP(gss_indicate_mechs(&min_status, &supported)); + + /* Ask privileged process what mechanisms it supports. */ + if (GSS_ERROR(PRIVSEP(gss_indicate_mechs(&min_status, &supported)))) + return; while (supported_mechs[i]->name != NULL) { if (GSS_ERROR(gss_test_oid_set_member(&min_status, @@ -128,56 +187,6 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset) gss_release_oid_set(&min_status, &supported); } -OM_uint32 -ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) -{ - if (*ctx) - ssh_gssapi_delete_ctx(ctx); - ssh_gssapi_build_ctx(ctx); - ssh_gssapi_set_oid(*ctx, oid); - return (ssh_gssapi_acquire_cred(*ctx)); -} - -/* Acquire credentials for a server running on the current host. - * Requires that the context structure contains a valid OID - */ - -/* Returns a GSSAPI error code */ -OM_uint32 -ssh_gssapi_acquire_cred(Gssctxt *ctx) -{ - OM_uint32 status; - char lname[MAXHOSTNAMELEN]; - gss_OID_set oidset; - - if (options.gss_strict_acceptor) { - gss_create_empty_oid_set(&status, &oidset); - gss_add_oid_set_member(&status, ctx->oid, &oidset); - - if (gethostname(lname, MAXHOSTNAMELEN)) { - gss_release_oid_set(&status, &oidset); - return (-1); - } - - if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { - gss_release_oid_set(&status, &oidset); - return (ctx->major); - } - - if ((ctx->major = gss_acquire_cred(&ctx->minor, - ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, - NULL, NULL))) - ssh_gssapi_error(ctx); - - gss_release_oid_set(&status, &oidset); - return (ctx->major); - } else { - ctx->name = GSS_C_NO_NAME; - ctx->creds = GSS_C_NO_CREDENTIAL; - } - return GSS_S_COMPLETE; -} - /* Wrapper around accept_sec_context * Requires that the context contains: @@ -302,8 +311,51 @@ OM_uint32 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; + } + + /* Call gss_inquire_cred rather than gss_inquire_cred_by_mech + because GSI doesn't support the latter. -jbasney */ + + if ((ctx->major = gss_inquire_cred(&ctx->minor, + ctx->client_creds, &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; @@ -318,6 +370,16 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) if (client->mech == NULL) return GSS_S_FAILURE; + /* Call gss_inquire_cred rather than gss_inquire_cred_by_mech + because GSI doesn't support the latter. -jbasney */ + + if (ctx->client_creds && + (ctx->major = gss_inquire_cred(&ctx->minor, + ctx->client_creds, &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); @@ -335,6 +397,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) 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; @@ -391,7 +455,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) /* Privileged */ int -ssh_gssapi_userok(char *user) +ssh_gssapi_userok(char *user, struct passwd *pw) { OM_uint32 lmin; @@ -407,9 +471,11 @@ ssh_gssapi_userok(char *user) } #endif 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); @@ -422,6 +488,9 @@ ssh_gssapi_userok(char *user) return (0); } +/* ssh_gssapi_checkmic() moved to gss-genr.c so it can be called by + kexgss_client(). */ + /* Priviledged */ int ssh_gssapi_localname(char **user) @@ -440,4 +509,109 @@ ssh_gssapi_localname(char **user) 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; +#ifdef USE_PAM + int ret; + pam_handle_t *pamh = NULL; + struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; + char *envstr; + char **p;char **pw; +#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; + + /* Put ssh pam stack env variables in this new pam stack env + * Using pam-pkinit, KRB5CCNAME is set during do_pam_session + * this addition enables pam-pkinit to access KRB5CCNAME if used + * in sshd-rekey stack too + */ + pw = p = fetch_pam_environment(); + while ( *pw != NULL ) { + pam_putenv(pamh,*pw); + pw++; + } + free_pam_environment(p); + + 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; +} + +void +ssh_gssapi_get_client_info(char **userdn, char **mech) { + *userdn = gssapi_client.displayname.value; + *mech = gssapi_client.mech->name; +} + #endif