X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/905081a434bc720834aa516f11ad6c20c3405034..6f9f4dab1bca468a2d6fd906245c8fd0adfa658f:/openssh/gss-genr.c diff --git a/openssh/gss-genr.c b/openssh/gss-genr.c index 087690c..ccd6d7e 100644 --- a/openssh/gss-genr.c +++ b/openssh/gss-genr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001 Simon Wilkinson. All rights reserved. * + * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -37,6 +37,8 @@ #include "kex.h" #include "log.h" #include "compat.h" +#include "monitor_wrap.h" +#include "canohost.h" #include @@ -49,6 +51,8 @@ gss_buffer_desc gssapi_client_name = {0,NULL}; /* Name of our client */ gss_cred_id_t gssapi_client_creds = GSS_C_NO_CREDENTIAL; /* Their credentials */ enum ssh_gss_id gssapi_client_type = GSS_LAST_ENTRY; +unsigned char ssh1_key_digest[16]; /* used for ssh1 gssapi */ + /* The mechanism name used in the list below is defined in the internet * draft as the Base 64 encoding of the MD5 hash of the ASN.1 DER encoding * of the underlying GSSAPI mechanism's OID. @@ -100,9 +104,9 @@ ssh_gssapi_mechanisms(int server,char *host) { Buffer buf; int i = 0; int present; + int mech_count=0; char * mechs; - Gssctxt ctx; - gss_buffer_desc token; + Gssctxt * ctx = NULL; if (datafellows & SSH_OLD_GSSAPI) return NULL; @@ -118,33 +122,33 @@ ssh_gssapi_mechanisms(int server,char *host) { present=0; } if (present) { - ssh_gssapi_build_ctx(&ctx); - ssh_gssapi_set_oid(&ctx,&supported_mechs[i].oid); - if (server) { - if (ssh_gssapi_acquire_cred(&ctx)) { - ssh_gssapi_delete_ctx(&ctx); - continue; + if ((server && + !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, + &supported_mechs[i].oid)))) + || (!server && + !GSS_ERROR(ssh_gssapi_client_ctx(&ctx, + &supported_mechs[i].oid, + host)))) { + /* Append gss_group1_sha1_x to our list */ + if (++mech_count > 1) { + buffer_append(&buf, ",", 1); } + buffer_append(&buf, gssprefix, + strlen(gssprefix)); + buffer_append(&buf, + supported_mechs[i].enc_name, + strlen(supported_mechs[i].enc_name)); + debug("GSSAPI mechanism %s (%s%s) supported", + supported_mechs[i].name, gssprefix, + supported_mechs[i].enc_name); + } else { + debug("no credentials for GSSAPI mechanism %s", + supported_mechs[i].name); } - else { /* client */ - if (ssh_gssapi_import_name(&ctx,host)) - continue; - maj_status=ssh_gssapi_init_ctx(&ctx, 0, - GSS_C_NO_BUFFER, - &token, - NULL); - ssh_gssapi_delete_ctx(&ctx); - if (GSS_ERROR(maj_status)) { - continue; - } - } - - /* Append gss_group1_sha1_x to our list */ - buffer_append(&buf, gssprefix, - strlen(gssprefix)); - buffer_append(&buf, supported_mechs[i].enc_name, - strlen(supported_mechs[i].enc_name)); - } + } else { + debug("GSSAPI mechanism %s not supported", + supported_mechs[i].name); + } } while (supported_mechs[++i].name != NULL); buffer_put_char(&buf,'\0'); @@ -206,22 +210,23 @@ void ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid) { enum ssh_gss_id ssh_gssapi_get_ctype(Gssctxt *ctxt) { enum ssh_gss_id i=0; - while(supported_mechs[i].name!=NULL && - supported_mechs[i].oid.length != ctxt->oid->length && - (memcmp(supported_mechs[i].oid.elements, - ctxt->oid->elements,ctxt->oid->length) !=0)) { + while(supported_mechs[i].name!=NULL) { + if (supported_mechs[i].oid.length == ctxt->oid->length && + (memcmp(supported_mechs[i].oid.elements, + ctxt->oid->elements,ctxt->oid->length) == 0)) + return i; i++; } - return(i); + return(GSS_LAST_ENTRY); } /* Set the GSS context's OID to the oid indicated by the given key exchange * name. */ -int ssh_gssapi_id_kex(Gssctxt *ctx, char *name) { +gss_OID ssh_gssapi_id_kex(Gssctxt *ctx, char *name) { enum ssh_gss_id i=0; if (strncmp(name, gssprefix, strlen(gssprefix)-1) !=0) { - return(1); + return(NULL); } name+=strlen(gssprefix); /* Move to the start of the MIME string */ @@ -232,19 +237,24 @@ int ssh_gssapi_id_kex(Gssctxt *ctx, char *name) { } if (supported_mechs[i].name==NULL) - return (1); + return (NULL); - ssh_gssapi_set_oid(ctx,&supported_mechs[i].oid); + if (ctx) ssh_gssapi_set_oid(ctx,&supported_mechs[i].oid); - return 0; + debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i].name, + gssprefix, supported_mechs[i].enc_name); + + return &supported_mechs[i].oid; } /* All this effort to report an error ... */ -void -ssh_gssapi_error(OM_uint32 major_status,OM_uint32 minor_status) { +static void +ssh_gssapi_error_ex(gss_OID mech, OM_uint32 major_status, + OM_uint32 minor_status, + int send_packet) { OM_uint32 lmaj, lmin; - gss_buffer_desc msg; + gss_buffer_desc msg = {0,NULL}; OM_uint32 ctx; ctx = 0; @@ -252,10 +262,11 @@ ssh_gssapi_error(OM_uint32 major_status,OM_uint32 minor_status) { do { lmaj = gss_display_status(&lmin, major_status, GSS_C_GSS_CODE, - GSS_C_NULL_OID, + mech, &ctx, &msg); if (lmaj == GSS_S_COMPLETE) { debug((char *)msg.value); + if (send_packet) packet_send_debug((char *)msg.value); (void) gss_release_buffer(&lmin, &msg); } } while (ctx!=0); @@ -264,52 +275,77 @@ ssh_gssapi_error(OM_uint32 major_status,OM_uint32 minor_status) { do { lmaj = gss_display_status(&lmin, minor_status, GSS_C_MECH_CODE, - GSS_C_NULL_OID, + mech, &ctx, &msg); if (lmaj == GSS_S_COMPLETE) { debug((char *)msg.value); + if (send_packet) packet_send_debug((char *)msg.value); (void) gss_release_buffer(&lmin, &msg); } } while (ctx!=0); } +void +ssh_gssapi_error(gss_OID mech,OM_uint32 major_status,OM_uint32 minor_status) { + ssh_gssapi_error_ex(mech, major_status, minor_status, 0); +} + +void +ssh_gssapi_send_error(gss_OID mech, + OM_uint32 major_status,OM_uint32 minor_status) { + ssh_gssapi_error_ex(mech, major_status, minor_status, 1); +} + + + + /* Initialise our GSSAPI context. We use this opaque structure to contain all * of the data which both the client and server need to persist across * {accept,init}_sec_context calls, so that when we do it from the userauth * stuff life is a little easier */ void -ssh_gssapi_build_ctx(Gssctxt *ctx) +ssh_gssapi_build_ctx(Gssctxt **ctx) { - ctx->context=GSS_C_NO_CONTEXT; - ctx->name=GSS_C_NO_NAME; - ctx->oid=GSS_C_NO_OID; - ctx->creds=GSS_C_NO_CREDENTIAL; - ctx->client=GSS_C_NO_NAME; - ctx->client_creds=GSS_C_NO_CREDENTIAL; + *ctx=xmalloc(sizeof (Gssctxt)); + (*ctx)->context=GSS_C_NO_CONTEXT; + (*ctx)->name=GSS_C_NO_NAME; + (*ctx)->oid=GSS_C_NO_OID; + (*ctx)->creds=GSS_C_NO_CREDENTIAL; + (*ctx)->client=GSS_C_NO_NAME; + (*ctx)->client_creds=GSS_C_NO_CREDENTIAL; } /* Delete our context, providing it has been built correctly */ void -ssh_gssapi_delete_ctx(Gssctxt *ctx) +ssh_gssapi_delete_ctx(Gssctxt **ctx) { OM_uint32 ms; - if (ctx->context != GSS_C_NO_CONTEXT) - gss_delete_sec_context(&ms,&ctx->context,GSS_C_NO_BUFFER); - if (ctx->name != GSS_C_NO_NAME) - gss_release_name(&ms,&ctx->name); - if (ctx->oid != GSS_C_NO_OID) { - xfree(ctx->oid->elements); - xfree(ctx->oid); - ctx->oid = GSS_C_NO_OID; + /* Return if there's no context */ + if ((*ctx)==NULL) + return; + +#if !defined(MECHGLUE) /* mechglue has some memory management issues */ + if ((*ctx)->context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&ms,&(*ctx)->context,GSS_C_NO_BUFFER); + if ((*ctx)->name != GSS_C_NO_NAME) + gss_release_name(&ms,&(*ctx)->name); + if ((*ctx)->oid != GSS_C_NO_OID) { + xfree((*ctx)->oid->elements); + xfree((*ctx)->oid); + (*ctx)->oid = GSS_C_NO_OID; } - if (ctx->creds != GSS_C_NO_CREDENTIAL) - gss_release_cred(&ms,&ctx->creds); - if (ctx->client != GSS_C_NO_NAME) - gss_release_name(&ms,&ctx->client); - if (ctx->client_creds != GSS_C_NO_CREDENTIAL) - gss_release_cred(&ms,&ctx->client_creds); + if ((*ctx)->creds != GSS_C_NO_CREDENTIAL) + gss_release_cred(&ms,&(*ctx)->creds); + if ((*ctx)->client != GSS_C_NO_NAME) + gss_release_name(&ms,&(*ctx)->client); + if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL) + gss_release_cred(&ms,&(*ctx)->client_creds); +#endif + + xfree(*ctx); + *ctx=NULL; } /* Wrapper to init_sec_context @@ -346,7 +382,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, NULL); ctx->status=maj_status; if (GSS_ERROR(maj_status)) { - ssh_gssapi_error(maj_status,min_status); + ssh_gssapi_error(ctx->oid,maj_status,min_status); } return(maj_status); } @@ -360,7 +396,6 @@ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok, gss_buffer_desc *send_tok, OM_uint32 *flags) { OM_uint32 maj_status, min_status; - gss_OID mech; maj_status=gss_accept_sec_context(&min_status, &ctx->context, @@ -368,13 +403,13 @@ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok, recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &ctx->client, - &mech, + &ctx->oid, send_tok, flags, NULL, &ctx->client_creds); if (GSS_ERROR(maj_status)) { - ssh_gssapi_error(maj_status,min_status); + ssh_gssapi_send_error(ctx->oid,maj_status,min_status); } if (ctx->client_creds) { @@ -383,42 +418,51 @@ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok, debug("Got no client credentials"); } - /* FIXME: We should check that the mechanism thats being used is + /* FIXME: We should check that the me * the one that we asked for (in ctx->oid) */ ctx->status=maj_status; + /* Now, if we're complete and we have the right flags, then + * we flag the user as also having been authenticated + */ + + if (((flags==NULL) || ((*flags & GSS_C_MUTUAL_FLAG) && + (*flags & GSS_C_INTEG_FLAG))) && + (maj_status == GSS_S_COMPLETE)) { + if (ssh_gssapi_getclient(ctx,&gssapi_client_type, + &gssapi_client_name, + &gssapi_client_creds)) + fatal("Couldn't convert client name"); + } + return(maj_status); } /* Create a service name for the given host */ OM_uint32 -ssh_gssapi_import_name(Gssctxt *ctx,char *host) { - gss_buffer_desc gssbuf; +ssh_gssapi_import_name(Gssctxt *ctx, const char *host) { + gss_buffer_desc gssbuf = {0,NULL}; OM_uint32 maj_status, min_status; - struct hostent *hostinfo = NULL; char *xhost; /* Make a copy of the host name, in case it was returned by a * previous call to gethostbyname(). */ xhost = xstrdup(host); - /* Make sure we have the FQDN. Some GSSAPI implementations don't do + /* If xhost is the loopback interface, switch it to our + true local hostname. */ + resolve_localhost(&xhost); + + /* Make sure we have the FQHN. Some GSSAPI implementations don't do * this for us themselves */ - - hostinfo = gethostbyname(xhost); - - if ((hostinfo == NULL) || (hostinfo->h_name == NULL)) { - debug("Unable to get FQDN for \"%s\"", xhost); - } else { - xfree(xhost); - xhost = hostinfo->h_name; - } - + make_fqhn(&xhost); + gssbuf.length = sizeof("host@")+strlen(xhost); gssbuf.value = xmalloc(gssbuf.length); if (gssbuf.value == NULL) { + xfree(xhost); return(-1); } snprintf(gssbuf.value,gssbuf.length,"host@%s",xhost); @@ -426,16 +470,19 @@ ssh_gssapi_import_name(Gssctxt *ctx,char *host) { &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) { - ssh_gssapi_error(maj_status,min_status); + ssh_gssapi_error(ctx->oid, maj_status,min_status); } + xfree(xhost); xfree(gssbuf.value); return(maj_status); } /* 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 maj_status, min_status; @@ -460,7 +507,7 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx) { &ctx->creds, NULL, NULL))) { - ssh_gssapi_error(maj_status,min_status); + ssh_gssapi_error(GSS_C_NO_OID,maj_status,min_status); } gss_release_oid_set(&min_status, &oidset); @@ -478,7 +525,7 @@ ssh_gssapi_getclient(Gssctxt *ctx, enum ssh_gss_id *type, *type=ssh_gssapi_get_ctype(ctx); if ((maj_status=gss_display_name(&min_status,ctx->client,name,NULL))) { - ssh_gssapi_error(maj_status,min_status); + ssh_gssapi_error(GSS_C_NO_OID,maj_status,min_status); } /* This is icky. There appears to be no way to copy this structure, @@ -489,5 +536,52 @@ ssh_gssapi_getclient(Gssctxt *ctx, enum ssh_gss_id *type, ctx->client_creds=GSS_C_NO_CREDENTIAL; return(maj_status); } + +OM_uint32 +ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *buffer, gss_buffer_desc *hash) { + OM_uint32 maj_status,min_status; + /* ssh1 needs to exchange the hash of the keys */ + /* will us this hash to return it */ + if (!compat20) { + if ((maj_status=gss_wrap(&min_status,ctx->context, + 0, + GSS_C_QOP_DEFAULT, + buffer, + NULL, + hash))) + ssh_gssapi_error(ctx->oid,maj_status,min_status); + } + else + + if ((maj_status=gss_get_mic(&min_status,ctx->context, + GSS_C_QOP_DEFAULT, buffer, hash))) { + ssh_gssapi_error(ctx->oid,maj_status,min_status); + } + + return(maj_status); +} + +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)); +} + +OM_uint32 +ssh_gssapi_client_ctx(Gssctxt **ctx,gss_OID oid, char *host) { + gss_buffer_desc token = {0,NULL}; + OM_uint32 major,minor; + + if (*ctx) ssh_gssapi_delete_ctx(ctx); + ssh_gssapi_build_ctx(ctx); + ssh_gssapi_set_oid(*ctx,oid); + ssh_gssapi_import_name(*ctx,host); + major=ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, NULL); + gss_release_buffer(&minor,&token); + return(major); +} + #endif /* GSSAPI */