From 3e8ad5e079b54db722a97f41d45e098e80fad863 Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Wed, 7 Sep 2011 14:33:19 +0100 Subject: [PATCH] support for libmoonshot identity selector --- acinclude.m4 | 40 +++ configure.ac | 1 + mech_eap/Makefile.am | 1 + mech_eap/accept_sec_context.c | 27 +- mech_eap/acquire_cred.c | 2 +- mech_eap/acquire_cred_with_password.c | 20 +- mech_eap/add_cred.c | 1 - mech_eap/add_cred_with_password.c | 13 +- mech_eap/gssapiP_eap.h | 16 +- mech_eap/gsseap_err.et | 12 + mech_eap/init_sec_context.c | 52 ++-- mech_eap/set_cred_option.c | 16 +- mech_eap/util.h | 47 +++- mech_eap/util_context.c | 2 +- mech_eap/util_cred.c | 472 +++++++++++++++++++++++++--------- mech_eap/util_moonshot.c | 238 +++++++++++++++++ 16 files changed, 771 insertions(+), 189 deletions(-) create mode 100644 mech_eap/util_moonshot.c diff --git a/acinclude.m4 b/acinclude.m4 index 80c71bb..f8a7efb 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -258,3 +258,43 @@ else AC_SUBST(JANSSON_LIBS) fi ])dnl + +AC_DEFUN([AX_CHECK_LIBMOONSHOT], +[AC_MSG_CHECKING(for Moonshot identity selector implementation) +LIBMOONSHOT_DIR= +found_libmoonshot="no" +AC_ARG_WITH(libmoonshot, + AC_HELP_STRING([--with-libmoonshot], + [Use libmoonshot (in specified installation directory)]), + [check_libmoonshot_dir="$withval"], + [check_libmoonshot_dir=]) +for dir in $check_libmoonshot_dir $prefix /usr /usr/local ../../moonshot-ui/libmoonshot ; do + libmoonshotdir="$dir" + if test -f "$dir/include/libmoonshot.h"; then + found_libmoonshot="yes"; + LIBMOONSHOT_DIR="${libmoonshotdir}" + LIBMOONSHOT_CFLAGS="-I$libmoonshotdir/include"; + break; + fi +done +AC_MSG_RESULT($found_libmoonshot) +if test x_$found_libmoonshot != x_yes; then + AC_MSG_ERROR([ +---------------------------------------------------------------------- + Cannot find Moonshot identity selector libraries. + + Please install wpa_supplicant or specify installation directory with + --with-libmoonshot=(dir). +---------------------------------------------------------------------- +]) +else + printf "libmoonshot found in $libmoonshotdir\n"; + LIBMOONSHOT_LIBS="-lmoonshot"; + LIBMOONSHOT_LDFLAGS="-L$libmoonshot/lib"; + AC_SUBST(LIBMOONSHOT_CFLAGS) + AC_SUBST(LIBMOONSHOT_LDFLAGS) + AC_SUBST(LIBMOONSHOT_LIBS) + AC_CHECK_LIB(moonshot, moonshot_get_identity, [AC_DEFINE_UNQUOTED([HAVE_MOONSHOT_GET_IDENTITY], 1, [Define if Moonshot identity selector is available])], [], "$LIBMOONSHOT_LIBS") +fi +])dnl + diff --git a/configure.ac b/configure.ac index 5ab930c..ccf5832 100644 --- a/configure.ac +++ b/configure.ac @@ -53,5 +53,6 @@ AX_CHECK_SHIBSP AX_CHECK_SHIBRESOLVER AX_CHECK_RADSEC AX_CHECK_JANSSON +AX_CHECK_LIBMOONSHOT AC_CONFIG_FILES([Makefile libeap/Makefile mech_eap/Makefile]) AC_OUTPUT diff --git a/mech_eap/Makefile.am b/mech_eap/Makefile.am index 55014cb..1f26d7d 100644 --- a/mech_eap/Makefile.am +++ b/mech_eap/Makefile.am @@ -85,6 +85,7 @@ mech_eap_la_SOURCES = \ util_krb.c \ util_lucid.c \ util_mech.c \ + util_moonshot.c \ util_name.c \ util_oid.c \ util_ordering.c \ diff --git a/mech_eap/accept_sec_context.c b/mech_eap/accept_sec_context.c index cc8702d..afbd554 100644 --- a/mech_eap/accept_sec_context.c +++ b/mech_eap/accept_sec_context.c @@ -431,10 +431,10 @@ createRadiusHandle(OM_uint32 *minor, return GSS_S_FAILURE; } - if (cred->radiusConfigFile != NULL) - configFile = cred->radiusConfigFile; - if (cred->radiusConfigStanza != NULL) - configStanza = cred->radiusConfigStanza; + if (cred->radiusConfigFile.value != NULL) + configFile = (const char *)cred->radiusConfigFile.value; + if (cred->radiusConfigStanza.value != NULL) + configStanza = (const char *)cred->radiusConfigStanza.value; ralloc.calloc = GSSEAP_CALLOC; ralloc.malloc = GSSEAP_MALLOC; @@ -840,30 +840,31 @@ gss_accept_sec_context(OM_uint32 *minor, GSSEAP_MUTEX_LOCK(&ctx->mutex); if (cred == GSS_C_NO_CREDENTIAL) { - if (ctx->defaultCred == GSS_C_NO_CREDENTIAL) { + if (ctx->cred == GSS_C_NO_CREDENTIAL) { major = gssEapAcquireCred(minor, GSS_C_NO_NAME, - GSS_C_NO_BUFFER, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT, - &ctx->defaultCred, + &ctx->cred, NULL, NULL); if (GSS_ERROR(major)) goto cleanup; } - cred = ctx->defaultCred; + cred = ctx->cred; } GSSEAP_MUTEX_LOCK(&cred->mutex); - if (cred->name != GSS_C_NO_NAME) { - major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName); - if (GSS_ERROR(major)) - goto cleanup; - } + /* + * Calling gssEapInquireCred() forces the default acceptor credential name + * to be resolved. + */ + major = gssEapInquireCred(minor, cred, &ctx->acceptorName, NULL, NULL, NULL); + if (GSS_ERROR(major)) + goto cleanup; major = gssEapSmStep(minor, cred, diff --git a/mech_eap/acquire_cred.c b/mech_eap/acquire_cred.c index 2326eaa..9e3f027 100644 --- a/mech_eap/acquire_cred.c +++ b/mech_eap/acquire_cred.c @@ -46,7 +46,7 @@ gss_acquire_cred(OM_uint32 *minor, gss_OID_set *actual_mechs, OM_uint32 *time_rec) { - return gssEapAcquireCred(minor, desired_name, GSS_C_NO_BUFFER, + return gssEapAcquireCred(minor, desired_name, time_req, desired_mechs, cred_usage, output_cred_handle, actual_mechs, time_rec); } diff --git a/mech_eap/acquire_cred_with_password.c b/mech_eap/acquire_cred_with_password.c index c0f4159..466473b 100644 --- a/mech_eap/acquire_cred_with_password.c +++ b/mech_eap/acquire_cred_with_password.c @@ -47,7 +47,21 @@ gssspi_acquire_cred_with_password(OM_uint32 *minor, gss_OID_set *actual_mechs, OM_uint32 *time_rec) { - return gssEapAcquireCred(minor, desired_name, password, - time_req, desired_mechs, cred_usage, - output_cred_handle, actual_mechs, time_rec); + OM_uint32 major, tmpMinor; + + major = gssEapAcquireCred(minor, desired_name, + time_req, desired_mechs, cred_usage, + output_cred_handle, actual_mechs, time_rec); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssEapSetCredPassword(minor, *output_cred_handle, password); + if (GSS_ERROR(major)) + goto cleanup; + +cleanup: + if (GSS_ERROR(major)) + gssEapReleaseCred(&tmpMinor, output_cred_handle); + + return major; } diff --git a/mech_eap/add_cred.c b/mech_eap/add_cred.c index 37d0add..f1598ed 100644 --- a/mech_eap/add_cred.c +++ b/mech_eap/add_cred.c @@ -71,7 +71,6 @@ gss_add_cred(OM_uint32 *minor, major = gssEapAcquireCred(minor, desired_name, - GSS_C_NO_BUFFER, time_req, &mechs, cred_usage, diff --git a/mech_eap/add_cred_with_password.c b/mech_eap/add_cred_with_password.c index 7907138..f634f96 100644 --- a/mech_eap/add_cred_with_password.c +++ b/mech_eap/add_cred_with_password.c @@ -50,7 +50,7 @@ gss_add_cred_with_password(OM_uint32 *minor, OM_uint32 *initiator_time_rec, OM_uint32 *acceptor_time_rec) { - OM_uint32 major; + OM_uint32 major, tmpMinor; OM_uint32 time_req, time_rec = 0; gss_OID_set_desc mechs; @@ -67,18 +67,27 @@ gss_add_cred_with_password(OM_uint32 *minor, major = gssEapAcquireCred(minor, desired_name, - password, time_req, &mechs, cred_usage, output_cred_handle, actual_mechs, &time_rec); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssEapSetCredPassword(minor, *output_cred_handle, password); + if (GSS_ERROR(major)) + goto cleanup; if (initiator_time_rec != NULL) *initiator_time_rec = time_rec; if (acceptor_time_rec != NULL) *acceptor_time_rec = time_rec; +cleanup: + if (GSS_ERROR(major)) + gssEapReleaseCred(&tmpMinor, output_cred_handle); + return major; } diff --git a/mech_eap/gssapiP_eap.h b/mech_eap/gssapiP_eap.h index 8bad9a8..cb67110 100644 --- a/mech_eap/gssapiP_eap.h +++ b/mech_eap/gssapiP_eap.h @@ -118,9 +118,9 @@ struct gss_name_struct #define CRED_FLAG_INITIATE 0x00010000 #define CRED_FLAG_ACCEPT 0x00020000 -#define CRED_FLAG_DEFAULT_IDENTITY 0x00040000 -#define CRED_FLAG_PASSWORD 0x00080000 -#define CRED_FLAG_DEFAULT_CCACHE 0x00100000 +#define CRED_FLAG_PASSWORD 0x00040000 +#define CRED_FLAG_DEFAULT_CCACHE 0x00080000 +#define CRED_FLAG_RESOLVED 0x00100000 #define CRED_FLAG_PUBLIC_MASK 0x0000FFFF #ifdef HAVE_HEIMDAL_VERSION @@ -132,11 +132,15 @@ struct gss_cred_id_struct GSSEAP_MUTEX mutex; OM_uint32 flags; gss_name_t name; + gss_name_t target; /* for initiator */ gss_buffer_desc password; gss_OID_set mechanisms; time_t expiryTime; - char *radiusConfigFile; - char *radiusConfigStanza; + gss_buffer_desc radiusConfigFile; + gss_buffer_desc radiusConfigStanza; + gss_buffer_desc caCertificate; + gss_buffer_desc subjectNameConstraint; + gss_buffer_desc subjectAltNameConstraint; #ifdef GSSEAP_ENABLE_REAUTH krb5_ccache krbCredCache; gss_cred_id_t reauthCred; @@ -196,7 +200,7 @@ struct gss_ctx_id_struct time_t expiryTime; uint64_t sendSeq, recvSeq; void *seqState; - gss_cred_id_t defaultCred; + gss_cred_id_t cred; union { struct gss_eap_initiator_ctx initiator; #define initiatorCtx ctxU.initiator diff --git a/mech_eap/gsseap_err.et b/mech_eap/gsseap_err.et index 6bcfff0..f8ec5ef 100644 --- a/mech_eap/gsseap_err.et +++ b/mech_eap/gsseap_err.et @@ -82,6 +82,18 @@ error_code GSSEAP_CRED_EXPIRED, "Attributes indicate credentials error_code GSSEAP_BAD_CRED_OPTION, "Bad credential option" error_code GSSEAP_NO_DEFAULT_IDENTITY, "Default credentials identity unavailable" error_code GSSEAP_NO_DEFAULT_CRED, "Missing default password or other credentials" +error_code GSSEAP_CRED_RESOLVED, "Credential is already fully resolved" + +# +# Local identity service errors +# +error_code GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE, "Unable to start identity service" +error_code GSSEAP_NO_IDENTITY_SELECTED, "No identity selected" +error_code GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR, "Identity service installation error" +error_code GSSEAP_IDENTITY_SERVICE_OS_ERROR, "Identity service OS error" +error_code GSSEAP_IDENTITY_SERVICE_IPC_ERROR, "Identity service IPC error" +error_code GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR, "Unknown identity service error" + # # Wrap/unwrap/PRF errors # diff --git a/mech_eap/init_sec_context.c b/mech_eap/init_sec_context.c index 42f9b93..e08e059 100644 --- a/mech_eap/init_sec_context.c +++ b/mech_eap/init_sec_context.c @@ -195,15 +195,14 @@ extern int wpa_debug_level; #endif static OM_uint32 -peerConfigInit(OM_uint32 *minor, - gss_cred_id_t cred, - gss_ctx_id_t ctx) +peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx) { OM_uint32 major; krb5_context krbContext; struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig; gss_buffer_desc identity = GSS_C_EMPTY_BUFFER; gss_buffer_desc realm = GSS_C_EMPTY_BUFFER; + gss_cred_id_t cred = ctx->cred; eapPeerConfig->identity = NULL; eapPeerConfig->identity_len = 0; @@ -254,6 +253,11 @@ peerConfigInit(OM_uint32 *minor, eapPeerConfig->password = (unsigned char *)cred->password.value; eapPeerConfig->password_len = cred->password.length; + /* certs */ + eapPeerConfig->ca_cert = (unsigned char *)cred->caCertificate.value; + eapPeerConfig->subject_match = (unsigned char *)cred->subjectNameConstraint.value; + eapPeerConfig->altsubject_match = (unsigned char *)cred->subjectAltNameConstraint.value; + *minor = 0; return GSS_S_COMPLETE; } @@ -341,7 +345,6 @@ initReady(OM_uint32 *minor, gss_ctx_id_t ctx, OM_uint32 reqFlags) static OM_uint32 initBegin(OM_uint32 *minor, - gss_cred_id_t cred, gss_ctx_id_t ctx, gss_name_t target, gss_OID mech, @@ -350,6 +353,7 @@ initBegin(OM_uint32 *minor, gss_channel_bindings_t chanBindings GSSEAP_UNUSED) { OM_uint32 major; + gss_cred_id_t cred = ctx->cred; assert(cred != GSS_C_NO_CREDENTIAL); @@ -634,7 +638,7 @@ eapGssSmInitIdentity(OM_uint32 *minor, static OM_uint32 eapGssSmInitAuthenticate(OM_uint32 *minor, - gss_cred_id_t cred, + gss_cred_id_t cred GSSEAP_UNUSED, gss_ctx_id_t ctx, gss_name_t target GSSEAP_UNUSED, gss_OID mech GSSEAP_UNUSED, @@ -653,7 +657,7 @@ eapGssSmInitAuthenticate(OM_uint32 *minor, assert(inputToken != GSS_C_NO_BUFFER); - major = peerConfigInit(minor, cred, ctx); + major = peerConfigInit(minor, ctx); if (GSS_ERROR(major)) goto cleanup; @@ -938,34 +942,24 @@ gss_init_sec_context(OM_uint32 *minor, GSSEAP_MUTEX_LOCK(&ctx->mutex); - if (cred == GSS_C_NO_CREDENTIAL) { - if (ctx->defaultCred == GSS_C_NO_CREDENTIAL) { - major = gssEapAcquireCred(minor, - GSS_C_NO_NAME, - GSS_C_NO_BUFFER, - time_req, - GSS_C_NO_OID_SET, - GSS_C_INITIATE, - &ctx->defaultCred, - NULL, - NULL); - if (GSS_ERROR(major)) - goto cleanup; - } + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_LOCK(&cred->mutex); - cred = ctx->defaultCred; + if (ctx->cred == GSS_C_NO_CREDENTIAL) { + major = gssEapResolveInitiatorCred(minor, cred, target_name, &ctx->cred); + if (GSS_ERROR(major)) + goto cleanup; + + assert(ctx->cred != GSS_C_NO_CREDENTIAL); } - GSSEAP_MUTEX_LOCK(&cred->mutex); + GSSEAP_MUTEX_LOCK(&ctx->cred->mutex); - if ((cred->flags & CRED_FLAG_INITIATE) == 0) { - major = GSS_S_NO_CRED; - *minor = GSSEAP_CRED_USAGE_MISMATCH; - goto cleanup; - } + assert(ctx->cred->flags & CRED_FLAG_RESOLVED); + assert(ctx->cred->flags & CRED_FLAG_INITIATE); if (initialContextToken) { - major = initBegin(minor, cred, ctx, target_name, mech_type, + major = initBegin(minor, ctx, target_name, mech_type, req_flags, time_req, input_chan_bindings); if (GSS_ERROR(major)) goto cleanup; @@ -1006,6 +1000,8 @@ gss_init_sec_context(OM_uint32 *minor, cleanup: if (cred != GSS_C_NO_CREDENTIAL) GSSEAP_MUTEX_UNLOCK(&cred->mutex); + if (ctx->cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_UNLOCK(&ctx->cred->mutex); GSSEAP_MUTEX_UNLOCK(&ctx->mutex); if (GSS_ERROR(major)) diff --git a/mech_eap/set_cred_option.c b/mech_eap/set_cred_option.c index bfffa1f..dd87a1f 100644 --- a/mech_eap/set_cred_option.c +++ b/mech_eap/set_cred_option.c @@ -42,7 +42,7 @@ setCredRadiusConfigFile(OM_uint32 *minor, const gss_OID oid GSSEAP_UNUSED, const gss_buffer_t buffer) { - OM_uint32 major; + OM_uint32 major, tmpMinor; gss_buffer_desc configFileBuffer = GSS_C_EMPTY_BUFFER; if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) { @@ -51,10 +51,8 @@ setCredRadiusConfigFile(OM_uint32 *minor, return major; } - if (cred->radiusConfigFile != NULL) - GSSEAP_FREE(cred->radiusConfigFile); - - cred->radiusConfigFile = (char *)configFileBuffer.value; + gss_release_buffer(&tmpMinor, &cred->radiusConfigFile); + cred->radiusConfigFile = configFileBuffer; *minor = 0; return GSS_S_COMPLETE; @@ -66,7 +64,7 @@ setCredRadiusConfigStanza(OM_uint32 *minor, const gss_OID oid GSSEAP_UNUSED, const gss_buffer_t buffer) { - OM_uint32 major; + OM_uint32 major, tmpMinor; gss_buffer_desc configStanzaBuffer = GSS_C_EMPTY_BUFFER; if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) { @@ -75,10 +73,8 @@ setCredRadiusConfigStanza(OM_uint32 *minor, return major; } - if (cred->radiusConfigStanza != NULL) - GSSEAP_FREE(cred->radiusConfigStanza); - - cred->radiusConfigStanza = (char *)configStanzaBuffer.value; + gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza); + cred->radiusConfigStanza = configStanzaBuffer; *minor = 0; return GSS_S_COMPLETE; diff --git a/mech_eap/util.h b/mech_eap/util.h index 4de00e3..748350d 100644 --- a/mech_eap/util.h +++ b/mech_eap/util.h @@ -76,7 +76,7 @@ extern "C" { #endif #if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -#define GSSEAP_UNUSED __attribute__ ((__unused__)) +#define GSSEAP_UNUSED __attribute__ ((__unused__)) #else #define GSSEAP_UNUSED #endif @@ -87,6 +87,13 @@ makeStringBuffer(OM_uint32 *minor, const char *string, gss_buffer_t buffer); +#define makeStringBufferOrCleanup(src, dst) \ + do { \ + major = makeStringBuffer((minor), (src), (dst));\ + if (GSS_ERROR(major)) \ + goto cleanup; \ + } while (0) + OM_uint32 bufferToString(OM_uint32 *minor, const gss_buffer_t buffer, @@ -97,6 +104,13 @@ duplicateBuffer(OM_uint32 *minor, const gss_buffer_t src, gss_buffer_t dst); +#define duplicateBufferOrCleanup(src, dst) \ + do { \ + major = duplicateBuffer((minor), (src), (dst)); \ + if (GSS_ERROR(major)) \ + goto cleanup; \ + } while (0) + static inline int bufferEqual(const gss_buffer_t b1, const gss_buffer_t b2) { @@ -209,10 +223,12 @@ gssEapContextTime(OM_uint32 *minor, OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred); OM_uint32 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred); +gss_OID +gssEapPrimaryMechForCred(gss_cred_id_t cred); + OM_uint32 gssEapAcquireCred(OM_uint32 *minor, const gss_name_t desiredName, - const gss_buffer_t password, OM_uint32 timeReq, const gss_OID_set desiredMechs, int cred_usage, @@ -220,6 +236,22 @@ gssEapAcquireCred(OM_uint32 *minor, gss_OID_set *pActualMechs, OM_uint32 *timeRec); +OM_uint32 +gssEapSetCredPassword(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_buffer_t password); + +OM_uint32 +gssEapSetCredService(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_name_t target); + +OM_uint32 +gssEapResolveInitiatorCred(OM_uint32 *minor, + const gss_cred_id_t cred, + const gss_name_t target, + gss_cred_id_t *resolvedCred); + int gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech); OM_uint32 @@ -457,6 +489,17 @@ gssEapOidToSaslName(const gss_OID oid); gss_OID gssEapSaslNameToOid(const gss_buffer_t name); +/* util_moonshot.c */ +OM_uint32 +libMoonshotResolveDefaultIdentity(OM_uint32 *minor, + const gss_cred_id_t cred, + gss_name_t *pName); + +OM_uint32 +libMoonshotResolveInitiatorCred(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_name_t targetName); + /* util_name.c */ #define EXPORT_NAME_FLAG_OID 0x1 #define EXPORT_NAME_FLAG_COMPOSITE 0x2 diff --git a/mech_eap/util_context.c b/mech_eap/util_context.c index 5a39424..054fa0f 100644 --- a/mech_eap/util_context.c +++ b/mech_eap/util_context.c @@ -130,7 +130,7 @@ gssEapReleaseContext(OM_uint32 *minor, gssEapReleaseName(&tmpMinor, &ctx->acceptorName); gssEapReleaseOid(&tmpMinor, &ctx->mechanismUsed); sequenceFree(&tmpMinor, &ctx->seqState); - gssEapReleaseCred(&tmpMinor, &ctx->defaultCred); + gssEapReleaseCred(&tmpMinor, &ctx->cred); GSSEAP_MUTEX_DESTROY(&ctx->mutex); diff --git a/mech_eap/util_cred.c b/mech_eap/util_cred.c index 28cb76c..4c8c8c7 100644 --- a/mech_eap/util_cred.c +++ b/mech_eap/util_cred.c @@ -64,6 +64,18 @@ gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred) return GSS_S_COMPLETE; } +static void +zeroAndReleasePassword(gss_buffer_t password) +{ + if (password->value != NULL) { + memset(password->value, 0, password->length); + GSSEAP_FREE(password->value); + } + + password->value = NULL; + password->length = 0; +} + OM_uint32 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred) { @@ -78,16 +90,15 @@ gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred) GSSEAP_KRB_INIT(&krbContext); gssEapReleaseName(&tmpMinor, &cred->name); + gssEapReleaseName(&tmpMinor, &cred->target); - if (cred->password.value != NULL) { - memset(cred->password.value, 0, cred->password.length); - GSSEAP_FREE(cred->password.value); - } + zeroAndReleasePassword(&cred->password); - if (cred->radiusConfigFile != NULL) - GSSEAP_FREE(cred->radiusConfigFile); - if (cred->radiusConfigStanza != NULL) - GSSEAP_FREE(cred->radiusConfigStanza); + gss_release_buffer(&tmpMinor, &cred->radiusConfigFile); + gss_release_buffer(&tmpMinor, &cred->radiusConfigStanza); + gss_release_buffer(&tmpMinor, &cred->caCertificate); + gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint); + gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint); #ifdef GSSEAP_ENABLE_REAUTH if (cred->krbCredCache != NULL) { @@ -110,21 +121,24 @@ gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred) } static OM_uint32 -readDefaultIdentityAndCreds(OM_uint32 *minor, - gss_buffer_t defaultIdentity, - gss_buffer_t defaultCreds) +readStaticIdentityFile(OM_uint32 *minor, + gss_buffer_t defaultIdentity, + gss_buffer_t defaultPassword) { OM_uint32 major, tmpMinor; FILE *fp = NULL; char pwbuf[BUFSIZ], buf[BUFSIZ]; char *ccacheName; struct passwd *pw = NULL, pwd; + int i = 0; defaultIdentity->length = 0; defaultIdentity->value = NULL; - defaultCreds->length = 0; - defaultCreds->value = NULL; + if (defaultPassword != GSS_C_NO_BUFFER) { + defaultPassword->length = 0; + defaultPassword->value = NULL; + } ccacheName = getenv("GSSEAP_IDENTITY"); if (ccacheName == NULL) { @@ -161,16 +175,20 @@ readDefaultIdentityAndCreds(OM_uint32 *minor, break; } - if (defaultIdentity->value == NULL) + if (i == 0) dst = defaultIdentity; - else if (defaultCreds->value == NULL) - dst = defaultCreds; + else if (i == 1) + dst = defaultPassword; else break; - major = duplicateBuffer(minor, &src, dst); - if (GSS_ERROR(major)) - goto cleanup; + if (dst != GSS_C_NO_BUFFER) { + major = duplicateBuffer(minor, &src, dst); + if (GSS_ERROR(major)) + goto cleanup; + } + + i++; } if (defaultIdentity->length == 0) { @@ -188,16 +206,29 @@ cleanup: if (GSS_ERROR(major)) { gss_release_buffer(&tmpMinor, defaultIdentity); - gss_release_buffer(&tmpMinor, defaultCreds); + zeroAndReleasePassword(defaultPassword); } + memset(buf, 0, sizeof(buf)); + return major; } +gss_OID +gssEapPrimaryMechForCred(gss_cred_id_t cred) +{ + gss_OID nameMech = GSS_C_NO_OID; + + if (cred->mechanisms != GSS_C_NO_OID_SET && + cred->mechanisms->count == 1) + nameMech = &cred->mechanisms->elements[0]; + + return nameMech; +} + OM_uint32 gssEapAcquireCred(OM_uint32 *minor, const gss_name_t desiredName, - const gss_buffer_t password, OM_uint32 timeReq GSSEAP_UNUSED, const gss_OID_set desiredMechs, int credUsage, @@ -207,10 +238,6 @@ gssEapAcquireCred(OM_uint32 *minor, { OM_uint32 major, tmpMinor; gss_cred_id_t cred; - gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER; - gss_name_t defaultIdentityName = GSS_C_NO_NAME; - gss_buffer_desc defaultCreds = GSS_C_EMPTY_BUFFER; - gss_OID nameMech = GSS_C_NO_OID; /* XXX TODO validate with changed set_cred_option API */ *pCred = GSS_C_NO_CREDENTIAL; @@ -244,21 +271,6 @@ gssEapAcquireCred(OM_uint32 *minor, if (GSS_ERROR(major)) goto cleanup; - if (cred->mechanisms != GSS_C_NO_OID_SET && - cred->mechanisms->count == 1) - nameMech = &cred->mechanisms->elements[0]; - - if (cred->flags & CRED_FLAG_INITIATE) { - major = readDefaultIdentityAndCreds(minor, &defaultIdentity, &defaultCreds); - if (major == GSS_S_COMPLETE) { - major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME, - nameMech, &defaultIdentityName); - if (GSS_ERROR(major)) - goto cleanup; - } else if (major != GSS_S_CRED_UNAVAIL) - goto cleanup; - } - if (desiredName != GSS_C_NO_NAME) { GSSEAP_MUTEX_LOCK(&desiredName->mutex); @@ -269,78 +281,6 @@ gssEapAcquireCred(OM_uint32 *minor, } GSSEAP_MUTEX_UNLOCK(&desiredName->mutex); - - if (defaultIdentityName != GSS_C_NO_NAME) { - int nameEqual; - - major = gssEapCompareName(minor, desiredName, - defaultIdentityName, &nameEqual); - if (GSS_ERROR(major)) - goto cleanup; - else if (nameEqual) - cred->flags |= CRED_FLAG_DEFAULT_IDENTITY; - } - } else { - if (cred->flags & CRED_FLAG_ACCEPT) { - gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; - char serviceName[5 + MAXHOSTNAMELEN]; - - /* default host-based service is host@localhost */ - memcpy(serviceName, "host@", 5); - if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) { - major = GSS_S_FAILURE; - *minor = GSSEAP_NO_HOSTNAME; - goto cleanup; - } - - nameBuf.value = serviceName; - nameBuf.length = strlen((char *)nameBuf.value); - - major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE, - nameMech, &cred->name); - if (GSS_ERROR(major)) - goto cleanup; - } else if (cred->flags & CRED_FLAG_INITIATE) { - if (defaultIdentityName == GSS_C_NO_NAME) { - major = GSS_S_CRED_UNAVAIL; - *minor = GSSEAP_NO_DEFAULT_IDENTITY; - goto cleanup; - } - - cred->name = defaultIdentityName; - defaultIdentityName = GSS_C_NO_NAME; - } - cred->flags |= CRED_FLAG_DEFAULT_IDENTITY; - } - - assert(cred->name != GSS_C_NO_NAME); - - if (password != GSS_C_NO_BUFFER) { - major = duplicateBuffer(minor, password, &cred->password); - if (GSS_ERROR(major)) - goto cleanup; - - cred->flags |= CRED_FLAG_PASSWORD; - } else if (defaultCreds.value != NULL && - (cred->flags & CRED_FLAG_DEFAULT_IDENTITY)) { - cred->password = defaultCreds; - - defaultCreds.length = 0; - defaultCreds.value = NULL; - - cred->flags |= CRED_FLAG_PASSWORD; - } else if (cred->flags & CRED_FLAG_INITIATE) { - /* - * OK, here we need to ask the supplicant if we have creds or it - * will acquire them, so GS2 can know whether to prompt for a - * password or not. - */ -#if 0 - && !gssEapCanReauthP(cred, GSS_C_NO_NAME, timeReq) -#endif - major = GSS_S_CRED_UNAVAIL; - *minor = GSSEAP_NO_DEFAULT_CRED; - goto cleanup; } if (pActualMechs != NULL) { @@ -360,12 +300,6 @@ gssEapAcquireCred(OM_uint32 *minor, cleanup: if (GSS_ERROR(major)) gssEapReleaseCred(&tmpMinor, &cred); - gssEapReleaseName(&tmpMinor, &defaultIdentityName); - gss_release_buffer(&tmpMinor, &defaultIdentity); - if (defaultCreds.value != NULL) { - memset(defaultCreds.value, 0, defaultCreds.length); - gss_release_buffer(&tmpMinor, &defaultCreds); - } return major; } @@ -390,6 +324,72 @@ gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech) return present; } +static OM_uint32 +staticIdentityFileResolveDefaultIdentity(OM_uint32 *minor, + const gss_cred_id_t cred, + gss_name_t *pName) +{ + OM_uint32 major, tmpMinor; + gss_OID nameMech = gssEapPrimaryMechForCred(cred); + gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER; + + *pName = GSS_C_NO_NAME; + + major = readStaticIdentityFile(minor, &defaultIdentity, GSS_C_NO_BUFFER); + if (major == GSS_S_COMPLETE) { + major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME, + nameMech, pName); + } + + gss_release_buffer(&tmpMinor, &defaultIdentity); + + return major; +} + +static OM_uint32 +gssEapResolveCredIdentity(OM_uint32 *minor, + gss_cred_id_t cred) +{ + OM_uint32 major; + gss_OID nameMech = gssEapPrimaryMechForCred(cred); + + if (cred->name != GSS_C_NO_NAME) { + *minor = 0; + return GSS_S_COMPLETE; + } + + if (cred->flags & CRED_FLAG_ACCEPT) { + gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; + char serviceName[5 + MAXHOSTNAMELEN]; + + /* default host-based service is host@localhost */ + memcpy(serviceName, "host@", 5); + if (gethostname(&serviceName[5], MAXHOSTNAMELEN) != 0) { + *minor = GSSEAP_NO_HOSTNAME; + return GSS_S_FAILURE; + } + + nameBuf.value = serviceName; + nameBuf.length = strlen((char *)nameBuf.value); + + major = gssEapImportName(minor, &nameBuf, GSS_C_NT_HOSTBASED_SERVICE, + nameMech, &cred->name); + if (GSS_ERROR(major)) + return major; + } else if (cred->flags & CRED_FLAG_INITIATE) { +#ifdef HAVE_MOONSHOT_GET_IDENTITY + major = libMoonshotResolveDefaultIdentity(minor, cred, &cred->name); + if (major == GSS_S_CRED_UNAVAIL) +#endif + major = staticIdentityFileResolveDefaultIdentity(minor, cred, &cred->name); + if (major != GSS_S_CRED_UNAVAIL) + return major; + } + + *minor = 0; + return GSS_S_COMPLETE; +} + OM_uint32 gssEapInquireCred(OM_uint32 *minor, gss_cred_id_t cred, @@ -402,9 +402,16 @@ gssEapInquireCred(OM_uint32 *minor, time_t now, lifetime; if (name != NULL) { - major = gssEapDuplicateName(minor, cred->name, name); + major = gssEapResolveCredIdentity(minor, cred); if (GSS_ERROR(major)) - return major; + goto cleanup; + + if (cred->name != GSS_C_NO_NAME) { + major = gssEapDuplicateName(minor, cred->name, name); + if (GSS_ERROR(major)) + goto cleanup; + } else + *name = GSS_C_NO_NAME; } if (cred_usage != NULL) { @@ -429,7 +436,7 @@ gssEapInquireCred(OM_uint32 *minor, else major = gssEapIndicateMechs(minor, mechanisms); if (GSS_ERROR(major)) - return major; + goto cleanup; } if (cred->expiryTime == 0) { @@ -446,12 +453,233 @@ gssEapInquireCred(OM_uint32 *minor, } if (lifetime == 0) { + major = GSS_S_CREDENTIALS_EXPIRED; *minor = GSSEAP_CRED_EXPIRED; - return GSS_S_CREDENTIALS_EXPIRED; + goto cleanup; } major = GSS_S_COMPLETE; *minor = 0; +cleanup: + return major; +} + +OM_uint32 +gssEapSetCredPassword(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_buffer_t password) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc newPassword = GSS_C_EMPTY_BUFFER; + + if (cred->flags & CRED_FLAG_RESOLVED) { + major = GSS_S_FAILURE; + *minor = GSSEAP_CRED_RESOLVED; + goto cleanup; + } + + if (password != GSS_C_NO_BUFFER) { + major = duplicateBuffer(minor, password, &newPassword); + if (GSS_ERROR(major)) + goto cleanup; + + cred->flags |= CRED_FLAG_PASSWORD; + } else { + cred->flags &= ~(CRED_FLAG_PASSWORD); + } + + gss_release_buffer(&tmpMinor, &cred->password); + cred->password = newPassword; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + return major; +} + +static OM_uint32 +gssEapDuplicateCred(OM_uint32 *minor, + const gss_cred_id_t src, + gss_cred_id_t *pDst) +{ + OM_uint32 major, tmpMinor; + gss_cred_id_t dst = GSS_C_NO_CREDENTIAL; + + *pDst = GSS_C_NO_CREDENTIAL; + + major = gssEapAllocCred(minor, &dst); + if (GSS_ERROR(major)) + goto cleanup; + + dst->flags = src->flags; + + if (src->name != GSS_C_NO_NAME) { + major = gssEapDuplicateName(minor, src->name, &dst->name); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (src->target != GSS_C_NO_NAME) { + major = gssEapDuplicateName(minor, src->target, &dst->target); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (src->password.value != NULL) { + major = duplicateBuffer(minor, &src->password, &dst->password); + if (GSS_ERROR(major)) + goto cleanup; + } + + major = duplicateOidSet(minor, src->mechanisms, &dst->mechanisms); + if (GSS_ERROR(major)) + goto cleanup; + + dst->expiryTime = src->expiryTime; + + if (src->radiusConfigFile.value != NULL) + duplicateBufferOrCleanup(&src->radiusConfigFile, &dst->radiusConfigFile); + if (src->radiusConfigStanza.value != NULL) + duplicateBufferOrCleanup(&src->radiusConfigStanza, &dst->radiusConfigStanza); + if (src->caCertificate.value != NULL) + duplicateBufferOrCleanup(&src->caCertificate, &dst->caCertificate); + if (src->subjectNameConstraint.value != NULL) + duplicateBufferOrCleanup(&src->subjectNameConstraint, &dst->subjectNameConstraint); + if (src->subjectAltNameConstraint.value != NULL) + duplicateBufferOrCleanup(&src->subjectAltNameConstraint, &dst->subjectAltNameConstraint); + +#ifdef GSSEAP_ENABLE_REAUTH + /* XXX krbCredCache, reauthCred */ +#endif + + *pDst = dst; + dst = GSS_C_NO_CREDENTIAL; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + gssEapReleaseCred(&tmpMinor, &dst); + + return major; +} + +static OM_uint32 +staticIdentityFileResolveInitiatorCred(OM_uint32 *minor, gss_cred_id_t cred) +{ + OM_uint32 major, tmpMinor; + gss_buffer_desc defaultIdentity = GSS_C_EMPTY_BUFFER; + gss_name_t defaultIdentityName = GSS_C_NO_NAME; + gss_buffer_desc defaultPassword = GSS_C_EMPTY_BUFFER; + int isDefaultIdentity = FALSE; + + major = readStaticIdentityFile(minor, &defaultIdentity, &defaultPassword); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssEapImportName(minor, &defaultIdentity, GSS_C_NT_USER_NAME, + gssEapPrimaryMechForCred(cred), &defaultIdentityName); + if (GSS_ERROR(major)) + goto cleanup; + + if (defaultIdentityName == GSS_C_NO_NAME) { + if (cred->name == GSS_C_NO_NAME) { + major = GSS_S_CRED_UNAVAIL; + *minor = GSSEAP_NO_DEFAULT_IDENTITY; + goto cleanup; + } + } else { + if (cred->name == GSS_C_NO_NAME) { + cred->name = defaultIdentityName; + defaultIdentityName = GSS_C_NO_NAME; + isDefaultIdentity = TRUE; + } else { + major = gssEapCompareName(minor, cred->name, + defaultIdentityName, &isDefaultIdentity); + if (GSS_ERROR(major)) + goto cleanup; + } + } + + if (isDefaultIdentity && + (cred->flags & CRED_FLAG_PASSWORD) == 0) { + major = gssEapSetCredPassword(minor, cred, &defaultPassword); + if (GSS_ERROR(major)) + goto cleanup; + } + +cleanup: + gssEapReleaseName(&tmpMinor, &defaultIdentityName); + zeroAndReleasePassword(&defaultPassword); + gss_release_buffer(&tmpMinor, &defaultIdentity); + + return major; +} + +OM_uint32 +gssEapResolveInitiatorCred(OM_uint32 *minor, + const gss_cred_id_t cred, + const gss_name_t targetName +#ifndef HAVE_MOONSHOT_GET_IDENTITY + GSSEAP_UNUSED +#endif + , + gss_cred_id_t *pResolvedCred) +{ + OM_uint32 major, tmpMinor; + gss_cred_id_t resolvedCred = GSS_C_NO_CREDENTIAL; + + if (cred == GSS_C_NO_CREDENTIAL) { + major = gssEapAcquireCred(minor, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_INITIATE, + &resolvedCred, + NULL, + NULL); + if (GSS_ERROR(major)) + goto cleanup; + } else { + if ((cred->flags & CRED_FLAG_INITIATE) == 0) { + major = GSS_S_NO_CRED; + *minor = GSSEAP_CRED_USAGE_MISMATCH; + goto cleanup; + } + + major = gssEapDuplicateCred(minor, cred, &resolvedCred); + if (GSS_ERROR(major)) + goto cleanup; + } + + if ((resolvedCred->flags & CRED_FLAG_RESOLVED) == 0) { +#ifdef HAVE_MOONSHOT_GET_IDENTITY + major = libMoonshotResolveInitiatorCred(minor, resolvedCred, targetName); + if (major == GSS_S_CRED_UNAVAIL) +#endif + major = staticIdentityFileResolveInitiatorCred(minor, resolvedCred); + if (GSS_ERROR(major)) + goto cleanup; + + if ((resolvedCred->flags & CRED_FLAG_PASSWORD) == 0) { + major = GSS_S_CRED_UNAVAIL; + *minor = GSSEAP_NO_DEFAULT_CRED; + goto cleanup; + } + + resolvedCred->flags |= CRED_FLAG_RESOLVED; + } + + *pResolvedCred = resolvedCred; + resolvedCred = GSS_C_NO_CREDENTIAL; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + gssEapReleaseCred(&tmpMinor, &resolvedCred); + return major; } diff --git a/mech_eap/util_moonshot.c b/mech_eap/util_moonshot.c new file mode 100644 index 0000000..75db452 --- /dev/null +++ b/mech_eap/util_moonshot.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "gssapiP_eap.h" + +#ifdef HAVE_MOONSHOT_GET_IDENTITY +#include + +static OM_uint32 +libMoonshotMapError(OM_uint32 *minor, + MoonshotError **pError) +{ + MoonshotError *error = *pError; + + assert(error != NULL); + + switch (error->code) { + case MOONSHOT_ERROR_UNABLE_TO_START_SERVICE: + *minor = GSSEAP_UNABLE_TO_START_IDENTITY_SERVICE; + break; + case MOONSHOT_ERROR_NO_IDENTITY_SELECTED: + *minor = GSSEAP_NO_IDENTITY_SELECTED; + break; + case MOONSHOT_ERROR_INSTALLATION_ERROR: + *minor = GSSEAP_IDENTITY_SERVICE_INSTALL_ERROR; + break; + case MOONSHOT_ERROR_OS_ERROR: + *minor = GSSEAP_IDENTITY_SERVICE_OS_ERROR; + break; + case MOONSHOT_ERROR_IPC_ERROR: + *minor = GSSEAP_IDENTITY_SERVICE_IPC_ERROR; + break; + default: + *minor = GSSEAP_IDENTITY_SERVICE_UNKNOWN_ERROR; + break; + } + + gssEapSaveStatusInfo(*minor, error->message); + moonshot_error_free(error); + *pError = NULL; + + return GSS_S_CRED_UNAVAIL; +} + +OM_uint32 +libMoonshotResolveDefaultIdentity(OM_uint32 *minor, + const gss_cred_id_t cred, + gss_name_t *pName) +{ + OM_uint32 major, tmpMinor; + gss_OID nameMech = gssEapPrimaryMechForCred(cred); + gss_name_t name = GSS_C_NO_NAME; + gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER; + char *nai = NULL; + char *password = NULL; + char *serverCertificateHash = NULL; + char *caCertificate = NULL; + char *subjectNameConstraint = NULL; + char *subjectAltNameConstraint = NULL; + MoonshotError *error = NULL; + + *pName = GSS_C_NO_NAME; + + if (!moonshot_get_default_identity(&nai, + &password, + &serverCertificateHash, + &caCertificate, + &subjectNameConstraint, + &subjectAltNameConstraint, + &error)) { + if (error->code == MOONSHOT_ERROR_NO_IDENTITY_SELECTED) { + major = GSS_S_CRED_UNAVAIL; + *minor = GSSEAP_NO_DEFAULT_IDENTITY; + moonshot_error_free(error); + } else + major = libMoonshotMapError(minor, &error); + goto cleanup; + } + + tmpBuffer.value = nai; + tmpBuffer.length = strlen(nai); + + major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME, nameMech, &name); + if (GSS_ERROR(major)) + goto cleanup; + + *pName = name; + name = GSS_C_NO_NAME; + +cleanup: + moonshot_free(nai); + moonshot_free(password); + moonshot_free(serverCertificateHash); + moonshot_free(caCertificate); + moonshot_free(subjectNameConstraint); + moonshot_free(subjectAltNameConstraint); + + gssEapReleaseName(&tmpMinor, &name); + + return major; +} + +OM_uint32 +libMoonshotResolveInitiatorCred(OM_uint32 *minor, + gss_cred_id_t cred, + const gss_name_t targetName) +{ + OM_uint32 major, tmpMinor; + gss_OID nameMech = gssEapPrimaryMechForCred(cred); + gss_buffer_desc initiator = GSS_C_EMPTY_BUFFER; + gss_buffer_desc target = GSS_C_EMPTY_BUFFER; + gss_buffer_desc tmpBuffer = GSS_C_EMPTY_BUFFER; + char *nai = NULL; + char *password = NULL; + char *serverCertificateHash = NULL; + char *caCertificate = NULL; + char *subjectNameConstraint = NULL; + char *subjectAltNameConstraint = NULL; + MoonshotError *error = NULL; + + if (cred->name != GSS_C_NO_NAME) { + major = gssEapExportName(minor, cred->name, &initiator); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (targetName != GSS_C_NO_NAME) { + major = gssEapExportName(minor, targetName, &target); + if (GSS_ERROR(major)) + goto cleanup; + } + + if (!moonshot_get_identity((const char *)initiator.value, + (const char *)cred->password.value, + (const char *)target.value, + &nai, + &password, + &serverCertificateHash, + &caCertificate, + &subjectNameConstraint, + &subjectAltNameConstraint, + &error)) { + major = libMoonshotMapError(minor, &error); + goto cleanup; + } + + gssEapReleaseName(&tmpMinor, &cred->name); + + tmpBuffer.value = nai; + tmpBuffer.length = strlen(nai); + + major = gssEapImportName(minor, &tmpBuffer, GSS_C_NT_USER_NAME, + nameMech, &cred->name); + if (GSS_ERROR(major)) + goto cleanup; + + tmpBuffer.value = password; + tmpBuffer.length = strlen(password); + + major = gssEapSetCredPassword(minor, cred, &tmpBuffer); + if (GSS_ERROR(major)) + goto cleanup; + + gss_release_buffer(&tmpMinor, &cred->caCertificate); + gss_release_buffer(&tmpMinor, &cred->subjectNameConstraint); + gss_release_buffer(&tmpMinor, &cred->subjectAltNameConstraint); + + if (serverCertificateHash != NULL) { + size_t len = strlen(serverCertificateHash); + + #define HASH_PREFIX "hash://server/sha256/" + #define HASH_PREFIX_LEN (sizeof(HASH_PREFIX) - 1) + + cred->caCertificate.value = GSSEAP_MALLOC(HASH_PREFIX_LEN + len + 1); + if (cred->caCertificate.value == NULL) { + major = GSS_S_FAILURE; + *minor = ENOMEM; + goto cleanup; + } + + memcpy(cred->caCertificate.value, HASH_PREFIX, HASH_PREFIX_LEN); + memcpy((char *)cred->caCertificate.value + HASH_PREFIX_LEN, serverCertificateHash, len); + + ((char *)cred->caCertificate.value)[HASH_PREFIX_LEN + len] = '\0'; + + cred->caCertificate.length = HASH_PREFIX_LEN + len; + } else if (caCertificate != NULL) { + makeStringBufferOrCleanup(caCertificate, &cred->caCertificate); + } + + if (subjectNameConstraint != NULL) + makeStringBufferOrCleanup(subjectNameConstraint, &cred->subjectNameConstraint); + if (subjectAltNameConstraint != NULL) + makeStringBufferOrCleanup(subjectAltNameConstraint, &cred->subjectAltNameConstraint); + +cleanup: + moonshot_free(nai); + moonshot_free(password); + moonshot_free(serverCertificateHash); + moonshot_free(caCertificate); + moonshot_free(subjectNameConstraint); + moonshot_free(subjectAltNameConstraint); + + gss_release_buffer(&tmpMinor, &initiator); + gss_release_buffer(&tmpMinor, &target); + + return major; +} +#endif /* HAVE_MOONSHOT_GET_IDENTITY */ -- 2.1.4