Path: blob/master/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp
41152 views
/*1* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425// This library is client-side only, and only supports the default credentials.26// It speaks krb5 and SPNEGO. NTLM is excluded from SPNEGO negotiation.27//28// This library can be built directly with the following command:29// cl -I %OPENJDK%\src\java.security.jgss\share\native\libj2gss\ sspi.cpp \30// -link -dll -out:sspi_bridge.dll3132#define UNICODE33#define _UNICODE3435#include <windows.h>36#include <stdlib.h>37#include <stdio.h>38#include <string.h>39#include <Strsafe.h>40#include <ntsecapi.h>41#include <new>4243#define GSS_DLL_FILE44#include <gssapi.h>4546#define SECURITY_WIN3247#include <sspi.h>4849#pragma comment(lib, "secur32.lib")5051// Otherwise an exception will be thrown52#define new new (std::nothrow)5354// A debugging macro55#define PP(fmt, ...) \56if (trace) { \57fprintf(stderr, "[SSPI:%ld] "fmt"\n", __LINE__, ##__VA_ARGS__); \58fflush(stderr); \59}60#define SEC_SUCCESS(status) ((*minor_status = (status)), (status) >= SEC_E_OK)6162#ifdef __cplusplus63extern "C" {64#endif /* __cplusplus */6566// When SSPI_BRIDGE_TRACE is set, debug info goes to stderr. The value is ignored.67char* trace = getenv("SSPI_BRIDGE_TRACE");6869void70dump(const char* title, PBYTE data, size_t len)71{72if (trace) {73fprintf(stderr, "==== %s ====\n", title);74for (size_t i = 0; i < len; i++) {75if (i != 0 && i % 16 == 0) {76fprintf(stderr, "\n");77}78fprintf(stderr, "%02X ", *(data + i) & 0xff);79}80fprintf(stderr, "\n");81}82}8384gss_OID_desc KRB5_OID = {9, (void*)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};85gss_OID_desc SPNEGO_OID = {6, (void*)"\x2b\x06\x01\x05\x05\x02"};86gss_OID_desc USER_NAME_OID = {10, (void*)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x01"};87gss_OID_desc KRB5_NAME_OID = {10, (void*)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"};88gss_OID_desc HOST_SERVICE_NAME_OID = {10, (void*)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"};89gss_OID_desc EXPORT_NAME_OID = {6, (void*)"\x2b\x06\x01\x05\x06\x04"};9091struct gss_name_struct {92SEC_WCHAR* name;93};9495struct gss_ctx_id_struct {96CredHandle* phCred;97CtxtHandle hCtxt;98SecPkgContext_Sizes SecPkgContextSizes;99SecPkgContext_NativeNames nnames;100BOOLEAN established;101BOOLEAN isSPNEGO;102BOOLEAN isLocalCred;103OM_uint32 flags;104};105106struct gss_cred_id_struct {107CredHandle* phCredK;108CredHandle* phCredS;109long time;110};111112/* This section holds supporting functions that are not exported */113114static OM_uint32115seconds_until(int inputIsUTC, TimeStamp *time)116{117// time is local time118LARGE_INTEGER uiLocal;119FILETIME now;120GetSystemTimeAsFileTime(&now);121if (!inputIsUTC) {122FILETIME nowLocal;123if (FileTimeToLocalFileTime(&now, &nowLocal) == 0) {124return -1;125}126now = nowLocal;127}128uiLocal.HighPart = now.dwHighDateTime;129uiLocal.LowPart = now.dwLowDateTime;130if (time->QuadPart < uiLocal.QuadPart) {131return 0;132}133ULONGLONG diff = (time->QuadPart - uiLocal.QuadPart) / 10000000;134if (diff > (ULONGLONG)~(OM_uint32)0) {135return GSS_C_INDEFINITE;136}137return (OM_uint32)diff;138}139140static void141show_time(char* label, TimeStamp* ts)142{143if (trace) {144SYSTEMTIME stLocal;145FileTimeToSystemTime((FILETIME*)ts, &stLocal);146147// Build a string showing the date and time.148PP("%s: %02d/%02d/%d %02d:%02d %uld", label,149stLocal.wMonth, stLocal.wDay, stLocal.wYear,150stLocal.wHour, stLocal.wMinute,151seconds_until(1, ts));152}153}154155// isSPNEGO: true, SPNEGO. false, Kerberos.156static gss_ctx_id_t157new_context(BOOLEAN isSPNEGO)158{159gss_ctx_id_t out = new gss_ctx_id_struct;160if (out == NULL) {161return NULL;162}163out->phCred = NULL;164out->hCtxt.dwLower = out->hCtxt.dwUpper = NULL;165out->established = FALSE;166out->SecPkgContextSizes.cbMaxSignature167= out->SecPkgContextSizes.cbBlockSize168= out->SecPkgContextSizes.cbSecurityTrailer169= 0;170out->nnames.sClientName = out->nnames.sServerName = NULL;171out->isSPNEGO = isSPNEGO;172out->isLocalCred = FALSE;173return out;174}175176static gss_cred_id_t177new_cred()178{179gss_cred_id_t out = new gss_cred_id_struct;180if (out) {181out->phCredK = out->phCredS = NULL;182out->time = 0L;183}184return out;185}186187static int188flag_sspi_to_gss(int fin)189{190int fout = 0;191if (fin & ISC_REQ_MUTUAL_AUTH) fout |= GSS_C_MUTUAL_FLAG;192if (fin & ISC_REQ_CONFIDENTIALITY) fout |= GSS_C_CONF_FLAG;193if (fin & ISC_REQ_DELEGATE) fout |= GSS_C_DELEG_FLAG;194if (fin & ISC_REQ_INTEGRITY) fout |= GSS_C_INTEG_FLAG;195if (fin & ISC_REQ_REPLAY_DETECT) fout |= GSS_C_REPLAY_FLAG;196if (fin & ISC_REQ_SEQUENCE_DETECT) fout |= GSS_C_SEQUENCE_FLAG;197return fout;198}199200static int201flag_gss_to_sspi(int fin)202{203int fout = 0;204if (fin & GSS_C_MUTUAL_FLAG) fout |= ISC_RET_MUTUAL_AUTH;205if (fin & GSS_C_CONF_FLAG) fout |= ISC_RET_CONFIDENTIALITY;206if (fin & GSS_C_DELEG_FLAG) fout |= ISC_RET_DELEGATE;207if (fin & GSS_C_INTEG_FLAG) fout |= ISC_RET_INTEGRITY;208if (fin & GSS_C_REPLAY_FLAG) fout |= ISC_RET_REPLAY_DETECT;209if (fin & GSS_C_SEQUENCE_FLAG) fout |= ISC_RET_SEQUENCE_DETECT;210return fout;211}212213static BOOLEAN214is_same_oid(gss_const_OID o2, gss_const_OID o1)215{216return o1 && o2 && o1->length == o2->length217&& !memcmp(o1->elements, o2->elements, o2->length);218}219220static BOOLEAN221has_oid(gss_const_OID_set set, gss_const_OID oid)222{223for (size_t i = 0; i < set->count; i++) {224if (is_same_oid(&set->elements[i], oid)) {225return TRUE;226}227}228return FALSE;229}230231static void232show_oid(gss_const_OID mech)233{234if (trace) {235if (is_same_oid(mech, &KRB5_OID)) {236PP("Kerberos mech");237} else if (is_same_oid(mech, &SPNEGO_OID)) {238PP("SPNEGO mech");239} else if (is_same_oid(mech, &USER_NAME_OID)) {240PP("NT_USER_NAME name-type");241} else if (is_same_oid(mech, &KRB5_NAME_OID)) {242PP("KRB5_NAME name-type");243} else if (is_same_oid(mech, &HOST_SERVICE_NAME_OID)) {244PP("NT_HOSTBASED_SERVICE name-type");245} else if (is_same_oid(mech, &EXPORT_NAME_OID)) {246PP("NT_EXPORT_NAME name-type");247} else {248dump("UNKNOWN OID", (PBYTE)mech->elements, mech->length);249}250}251}252253static void254show_oid_set(gss_const_OID_set mechs)255{256if (trace) {257if (mechs == NULL) {258PP("OID set is NULL");259return;260}261PP("gss_OID_set.count is %d", (int)mechs->count);262for (size_t i = 0; i < mechs->count; i++) {263show_oid(&mechs->elements[i]);264}265}266}267268// Add realm to a name if there was none.269// Returns a newly allocated name.270static WCHAR*271get_full_name(WCHAR* input)272{273// input has realm, no need to add one274for (int i = 0;; i++) {275if (!input[i]) { // the end276break;277}278if (input[i] == L'\\') { // escaped279i++;280continue;281}282if (input[i] == L'@') {283return _wcsdup(input);284}285}286287// Always use the default domain288WCHAR* realm = _wgetenv(L"USERDNSDOMAIN");289if (realm == NULL) {290realm = L"";291}292293size_t oldlen = wcslen(input);294size_t newlen = oldlen + 1 + wcslen(realm) + 1;295296WCHAR* fullname = new WCHAR[newlen];297if (!fullname) {298return NULL;299}300wcscpy_s(fullname, newlen, input);301wcscat_s(fullname, newlen, L"@");302wcscat_s(fullname, newlen, realm);303304PP("get_full_name returns %ls", fullname);305return fullname;306}307308/* End support section */309310/* This section holds GSS-API exported functions */311312#define CHECK_OUTPUT(x) if (!x) return GSS_S_CALL_INACCESSIBLE_WRITE;313#define CHECK_BUFFER(b) if (!b || !b->value) return GSS_S_CALL_INACCESSIBLE_READ;314#define CHECK_OID(o) if (!o || !o->elements) return GSS_S_CALL_INACCESSIBLE_READ;315#define CHECK_NAME(n) if (!n || !(n->name)) return GSS_S_BAD_NAME;316#define CHECK_CONTEXT(c) if (!c) return GSS_S_NO_CONTEXT;317#define CHECK_CRED(c) if (!c || (!(cred_handle->phCredK) && !(cred_handle->phCredS))) \318return GSS_S_NO_CRED;319320__declspec(dllexport) OM_uint32321gss_release_name(OM_uint32 *minor_status,322gss_name_t *name)323{324PP(">>>> Calling gss_release_name %p...", *name);325if (name != NULL && *name != GSS_C_NO_NAME) {326if ((*name)->name != NULL) {327delete[] (*name)->name;328}329delete *name;330*name = GSS_C_NO_NAME;331}332return GSS_S_COMPLETE;333}334335__declspec(dllexport) OM_uint32336gss_import_name(OM_uint32 *minor_status,337gss_const_buffer_t input_name_buffer,338gss_const_OID input_name_type,339gss_name_t *output_name)340{341PP(">>>> Calling gss_import_name...");342CHECK_BUFFER(input_name_buffer)343CHECK_OUTPUT(output_name)344345int len = (int)input_name_buffer->length;346LPSTR input = (LPSTR)input_name_buffer->value;347if (input_name_type != NULL348&& is_same_oid(input_name_type, &EXPORT_NAME_OID)) {349if (len < 4 || input[0] != 4 || input[1] != 1 || input[2] != 0) {350return GSS_S_FAILURE;351}352int mechLen = (int)input[3]; /* including 06 len */353len -= mechLen + 8; /* 4 header bytes, and an int32 length after OID */354if (len <= 0) {355return GSS_S_FAILURE;356}357// Reject if mech is not krb5358if (mechLen - 2!= KRB5_OID.length ||359memcmp(input + 6, KRB5_OID.elements, mechLen - 2)) {360return GSS_S_FAILURE;;361}362input = input + mechLen + 8;363}364365SEC_WCHAR* value = new SEC_WCHAR[len + 1];366if (value == NULL) {367goto err;368}369370len = MultiByteToWideChar(CP_UTF8, 0, input, len, value, len+1);371if (len == 0) {372goto err;373}374value[len] = 0;375376PP("import_name from %ls", value);377378if (len > 33 && !wcscmp(value+len-33, L"@WELLKNOWN:ORG.H5L.REFERALS-REALM")) {379// Remove the wellknown referrals realms380value[len-33] = 0;381len -= 33;382} else if (value[len-1] == L'@') {383// Remove the empty realm. It might come from an NT_EXPORT_NAME.384value[len-1] = 0;385len--;386}387if (len == 0) {388goto err;389}390391if (input_name_type != NULL392&& is_same_oid(input_name_type, &HOST_SERVICE_NAME_OID)) {393// HOST_SERVICE_NAME_OID takes the form of service@host.394for (int i = 0; i < len; i++) {395if (value[i] == L'\\') {396i++;397continue;398}399if (value[i] == L'@') {400value[i] = L'/';401break;402}403}404PP("Host-based service now %ls", value);405}406PP("import_name to %ls", value);407gss_name_struct* name = new gss_name_struct;408if (name == NULL) {409goto err;410}411name->name = value;412*output_name = (gss_name_t) name;413return GSS_S_COMPLETE;414err:415if (value != NULL) {416delete[] value;417}418return GSS_S_FAILURE;419}420421__declspec(dllexport) OM_uint32422gss_compare_name(OM_uint32 *minor_status,423gss_const_name_t name1,424gss_const_name_t name2,425int *name_equal)426{427PP(">>>> Calling gss_compare_name...");428CHECK_NAME(name1)429CHECK_NAME(name2)430CHECK_OUTPUT(name_equal)431432*name_equal = 0;433434SEC_WCHAR* n1 = name1->name;435SEC_WCHAR* n2 = name2->name;436PP("Comparing %ls and %ls", n1, n2);437438int l1 = lstrlen(n1);439int l2 = lstrlen(n2);440int r1 = l1; // position of @ or the end if none441int r2 = l2;442int i;443444for (i = 0; i < l1; i++) {445if (n1[i] == L'\\') {446i++;447continue;448}449if (n1[i] == L'@') {450r1 = i;451break;452}453}454455for (i = 0; i < l2; i++) {456if (n2[i] == L'\\') {457i++;458continue;459}460if (n2[i] == L'@') {461r2 = i;462break;463}464}465466if (l1 < l2 && l1 != r2467|| l2 < l1 && l2 != r1) {468return GSS_S_COMPLETE; // different469}470471if (l1 > l2) {472l1 = l2; // choose the smaller one. longer=smaller @ ...473}474475// Two names are equal if they are the same or one has no realm and476// one has realm but they have the same name. If both have realm but477// different, they are treated different even if the names are the same.478// Note: the default name concept is not used here.479// Principal names on Windows are case-insensitive, both user name480// and service principal name.481if (CompareStringEx(LOCALE_NAME_SYSTEM_DEFAULT, NORM_IGNORECASE,482n1, l1, n2, l1, NULL, NULL, 0) == CSTR_EQUAL) {483*name_equal = 1;484}485return GSS_S_COMPLETE;486}487488__declspec(dllexport) OM_uint32489gss_canonicalize_name(OM_uint32 *minor_status,490gss_const_name_t input_name,491gss_const_OID mech_type,492gss_name_t *output_name)493{494PP(">>>> Calling gss_canonicalize_name...");495CHECK_NAME(input_name)496CHECK_OID(mech_type)497CHECK_OUTPUT(output_name)498499if (!is_same_oid(mech_type, &KRB5_OID)) {500PP("Cannot canonicalize to non-krb5 OID");501return GSS_S_BAD_MECH;502}503gss_name_t names2 = new gss_name_struct;504if (names2 == NULL) {505return GSS_S_FAILURE;506}507names2->name = get_full_name(input_name->name);508if (names2->name == NULL) {509delete names2;510return GSS_S_FAILURE;511}512*output_name = names2;513return GSS_S_COMPLETE;514}515516__declspec(dllexport) OM_uint32517gss_export_name(OM_uint32 *minor_status,518gss_const_name_t input_name,519gss_buffer_t exported_name)520{521PP(">>>> Calling gss_export_name...");522CHECK_NAME(input_name)523CHECK_OUTPUT(exported_name)524525OM_uint32 result = GSS_S_FAILURE;526SEC_WCHAR* name = input_name->name;527SEC_WCHAR* fullname = get_full_name(name);528if (!fullname) {529goto err;530}531PP("Make fullname: %ls -> %ls", name, fullname);532int len;533size_t namelen = wcslen(fullname);534if (namelen > 255) {535goto err;536}537len = (int)namelen;538// We only deal with not-so-long names.539// 04 01 00 ** 06 ** OID len:int32 name540int mechLen = KRB5_OID.length;541char* buffer = new char[10 + mechLen + len];542if (buffer == NULL) {543goto err;544}545buffer[0] = 4;546buffer[1] = 1;547buffer[2] = 0;548buffer[3] = 2 + mechLen;549buffer[4] = 6;550buffer[5] = mechLen;551memcpy_s(buffer + 6, mechLen, KRB5_OID.elements, mechLen);552buffer[6 + mechLen] = buffer[7 + mechLen] = buffer[8 + mechLen] = 0;553buffer[9 + mechLen] = (char)len;554len = WideCharToMultiByte(CP_UTF8, 0, fullname, len,555buffer+10+mechLen, len, NULL, NULL);556if (len == 0) {557delete[] buffer;558goto err;559}560exported_name->length = 10 + mechLen + len;561exported_name->value = buffer;562result = GSS_S_COMPLETE;563err:564if (fullname != name) {565delete[] fullname;566}567return result;568}569570__declspec(dllexport) OM_uint32571gss_display_name(OM_uint32 *minor_status,572gss_const_name_t input_name,573gss_buffer_t output_name_buffer,574gss_OID *output_name_type)575{576PP(">>>> Calling gss_display_name...");577CHECK_NAME(input_name)578CHECK_OUTPUT(output_name_buffer)579580SEC_WCHAR* names = input_name->name;581int len = (int)wcslen(names);582char* buffer = new char[4*len+1];583if (buffer == NULL) {584return GSS_S_FAILURE;585}586len = WideCharToMultiByte(CP_UTF8, 0, names, len, buffer, 4*len, NULL, NULL);587if (len == 0) {588delete[] buffer;589return GSS_S_FAILURE;590}591buffer[len] = 0;592output_name_buffer->length = len;593output_name_buffer->value = buffer;594PP("Name found: %ls -> %d [%s]", names, len, buffer);595if (output_name_type != NULL) {596*output_name_type = &KRB5_NAME_OID;597}598return GSS_S_COMPLETE;599}600601__declspec(dllexport) OM_uint32602gss_acquire_cred(OM_uint32 *minor_status,603gss_const_name_t desired_name,604OM_uint32 time_req,605gss_const_OID_set desired_mechs,606gss_cred_usage_t cred_usage,607gss_cred_id_t *output_cred_handle,608gss_OID_set *actual_mechs,609OM_uint32 *time_rec)610{611PP(">>>> Calling gss_acquire_cred...");612CHECK_OUTPUT(output_cred_handle)613614SECURITY_STATUS ss;615TimeStamp ts;616ts.QuadPart = 0;617cred_usage = 0;618PP("AcquireCredentialsHandle with %d %p", cred_usage, desired_mechs);619show_oid_set(desired_mechs);620621BOOLEAN reqKerberos, reqSPNEGO;622623if (!desired_mechs) {624reqKerberos = reqSPNEGO = TRUE;625} else {626if (has_oid(desired_mechs, &KRB5_OID)) {627PP("reqKerberos");628reqKerberos = TRUE;629}630if (has_oid(desired_mechs, &SPNEGO_OID)) {631PP("reqSPNEGO");632reqSPNEGO = TRUE;633}634if (!reqSPNEGO && !reqKerberos) {635return GSS_S_BAD_MECH;636}637}638639if (actual_mechs) {640*actual_mechs = GSS_C_NO_OID_SET;641}642643gss_cred_id_t cred = new_cred();644if (cred == NULL) {645goto err;646}647648if (reqKerberos) {649cred->phCredK = new CredHandle;650if (cred->phCredK == NULL) {651goto err;652}653ss = AcquireCredentialsHandle(654NULL,655L"Kerberos",656cred_usage == 0 ? SECPKG_CRED_BOTH :657(cred_usage == 1 ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND),658NULL,659NULL,660NULL,661NULL,662cred->phCredK,663&ts);664if (!(SEC_SUCCESS(ss))) {665delete cred->phCredK;666cred->phCredK = NULL;667goto err;668}669}670671if (reqSPNEGO) {672cred->phCredS = new CredHandle;673if (cred->phCredS == NULL) {674goto err;675}676SEC_WINNT_AUTH_IDENTITY_EX auth;677ZeroMemory(&auth, sizeof(auth));678auth.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;679auth.Length = sizeof(auth);680auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;681auth.PackageList = (unsigned short*)L"Kerberos";682auth.PackageListLength = 8;683ss = AcquireCredentialsHandle(684NULL,685L"Negotiate",686cred_usage == 0 ? SECPKG_CRED_BOTH :687(cred_usage == 1 ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND),688NULL,689&auth,690NULL,691NULL,692cred->phCredS,693&ts);694if (!(SEC_SUCCESS(ss))) {695delete cred->phCredS;696cred->phCredS = NULL;697goto err;698}699}700701if (actual_mechs) {702if (gss_create_empty_oid_set(minor_status, actual_mechs)) {703goto err;704}705if (reqKerberos) {706if (gss_add_oid_set_member(minor_status, &KRB5_OID, actual_mechs)) {707goto err;708}709}710if (reqSPNEGO) {711if (gss_add_oid_set_member(minor_status, &SPNEGO_OID, actual_mechs)) {712goto err;713}714}715}716717*output_cred_handle = (gss_cred_id_t)cred;718719// Note: ts here is weirdly huge, maybe because LSA retains the720// password and can re-acquire a TGT at anytime. It will be721// GSSCredential.INDEFINITE_LIFETIME.722show_time("cred expiration", &ts);723cred->time = seconds_until(1, &ts);724if (time_rec != NULL) {725*time_rec = cred->time;726}727728// Since only default cred is supported, if there is a desired_name,729// we must make sure it is the same as the realname of the default cred.730if (desired_name != NULL) {731PP("Acquiring cred with a name. Check if it's me.");732gss_name_t realname;733if (gss_inquire_cred(minor_status, *output_cred_handle, &realname,734NULL, NULL, NULL) != GSS_S_COMPLETE) {735PP("Cannot get owner name of default creds");736goto err;737}738SEC_WCHAR* rnames = realname->name;739SEC_WCHAR* dnames = desired_name->name;740int equals = 0;741gss_compare_name(minor_status, realname, desired_name, &equals);742gss_release_name(minor_status, &realname);743PP("Comparing result: %d", equals);744if (!equals) {745goto err;746}747}748749return GSS_S_COMPLETE;750err:751if (cred) {752OM_uint32 dummy;753gss_release_cred(&dummy, &cred);754}755if (actual_mechs) {756OM_uint32 dummy;757gss_release_oid_set(&dummy, actual_mechs);758}759return GSS_S_FAILURE;760}761762__declspec(dllexport) OM_uint32763gss_release_cred(OM_uint32 *minor_status,764gss_cred_id_t *cred_handle)765{766PP(">>>> Calling gss_release_cred...");767if (cred_handle && *cred_handle) {768if ((*cred_handle)->phCredK) {769FreeCredentialsHandle((*cred_handle)->phCredK);770delete (*cred_handle)->phCredK;771}772if ((*cred_handle)->phCredS) {773FreeCredentialsHandle((*cred_handle)->phCredS);774delete (*cred_handle)->phCredS;775}776delete *cred_handle;777*cred_handle = GSS_C_NO_CREDENTIAL;778}779return GSS_S_COMPLETE;780}781782__declspec(dllexport) OM_uint32783gss_inquire_cred(OM_uint32 *minor_status,784gss_const_cred_id_t cred_handle,785gss_name_t *name,786OM_uint32 *lifetime,787gss_cred_usage_t *cred_usage,788gss_OID_set *mechanisms)789{790PP(">>>> Calling gss_inquire_cred...");791CHECK_CRED(cred_handle)792793CredHandle* cred = cred_handle->phCredK794? cred_handle->phCredK795: cred_handle->phCredS;796SECURITY_STATUS ss;797if (name) {798*name = GSS_C_NO_NAME;799SecPkgCredentials_Names snames;800ss = QueryCredentialsAttributes(cred, SECPKG_CRED_ATTR_NAMES, &snames);801if (!SEC_SUCCESS(ss)) {802return GSS_S_FAILURE;803}804SEC_WCHAR* names = new SEC_WCHAR[lstrlen(snames.sUserName) + 1];805if (names == NULL) {806return GSS_S_FAILURE;807}808StringCchCopy(names, lstrlen(snames.sUserName) + 1, snames.sUserName);809FreeContextBuffer(snames.sUserName);810PP("Allocate new name at %p", names);811gss_name_t name1 = new gss_name_struct;812if (name1 == NULL) {813delete[] names;814return GSS_S_FAILURE;815}816name1->name = names;817*name = (gss_name_t) name1;818}819if (lifetime) {820*lifetime = cred_handle->time;821}822if (cred_usage) {823*cred_usage = 1; // We only support INITIATE_ONLY now824}825if (mechanisms) {826// Useless for Java827}828// Others inquiries not supported yet829return GSS_S_COMPLETE;830}831832__declspec(dllexport) OM_uint32833gss_import_sec_context(OM_uint32 *minor_status,834gss_const_buffer_t interprocess_token,835gss_ctx_id_t *context_handle)836{837// Not transferable, return FAILURE838PP(">>>> Calling UNIMPLEMENTED gss_import_sec_context...");839*minor_status = 0;840return GSS_S_FAILURE;841}842843__declspec(dllexport) OM_uint32844gss_init_sec_context(OM_uint32 *minor_status,845gss_const_cred_id_t initiator_cred_handle,846gss_ctx_id_t *context_handle,847gss_const_name_t target_name,848gss_const_OID mech_type,849OM_uint32 req_flags,850OM_uint32 time_req,851gss_const_channel_bindings_t input_chan_bindings,852gss_const_buffer_t input_token,853gss_OID *actual_mech_type,854gss_buffer_t output_token,855OM_uint32 *ret_flags,856OM_uint32 *time_rec)857{858PP(">>>> Calling gss_init_sec_context...");859CHECK_NAME(target_name)860CHECK_OUTPUT(output_token)861862SECURITY_STATUS ss;863TimeStamp lifeTime;864SecBufferDesc inBuffDesc;865SecBuffer inSecBuff;866SecBufferDesc outBuffDesc;867SecBuffer outSecBuff;868BOOLEAN isSPNEGO = is_same_oid(mech_type, &SPNEGO_OID);869CredHandle* newCred = NULL;870871gss_ctx_id_t pc;872873output_token->length = 0;874output_token->value = NULL;875876BOOLEAN firstTime = (*context_handle == GSS_C_NO_CONTEXT);877PP("First time? %d", firstTime);878if (firstTime) {879pc = new_context(isSPNEGO);880if (pc == NULL) {881return GSS_S_FAILURE;882}883*context_handle = (gss_ctx_id_t) pc;884} else {885pc = *context_handle;886}887888if (pc == NULL) {889return GSS_S_NO_CONTEXT;890}891892DWORD outFlag;893TCHAR outName[100];894895OM_uint32 minor;896gss_buffer_desc tn;897gss_display_name(&minor, target_name, &tn, NULL);898int len = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)tn.value, (int)tn.length,899outName, sizeof(outName) - 1);900if (len == 0) {901goto err;902}903outName[len] = 0;904905int flag = flag_gss_to_sspi(req_flags) | ISC_REQ_ALLOCATE_MEMORY;906907outBuffDesc.ulVersion = SECBUFFER_VERSION;908outBuffDesc.cBuffers = 1;909outBuffDesc.pBuffers = &outSecBuff;910911outSecBuff.BufferType = SECBUFFER_TOKEN;912913if (!firstTime) {914inBuffDesc.ulVersion = SECBUFFER_VERSION;915inBuffDesc.cBuffers = 1;916inBuffDesc.pBuffers = &inSecBuff;917918inSecBuff.BufferType = SECBUFFER_TOKEN;919inSecBuff.cbBuffer = (ULONG)input_token->length;920inSecBuff.pvBuffer = input_token->value;921} else if (!pc->phCred) {922if (isSPNEGO && initiator_cred_handle923&& initiator_cred_handle->phCredS) {924PP("Find SPNEGO credentials");925pc->phCred = initiator_cred_handle->phCredS;926pc->isLocalCred = FALSE;927} else if (!isSPNEGO && initiator_cred_handle928&& initiator_cred_handle->phCredK) {929PP("Find Kerberos credentials");930pc->phCred = initiator_cred_handle->phCredK;931pc->isLocalCred = FALSE;932} else {933PP("No credentials provided, acquire myself");934newCred = new CredHandle;935if (!newCred) {936goto err;937}938SEC_WINNT_AUTH_IDENTITY_EX auth;939ZeroMemory(&auth, sizeof(auth));940auth.Version = SEC_WINNT_AUTH_IDENTITY_VERSION;941auth.Length = sizeof(auth);942auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;943auth.PackageList = (unsigned short*)L"Kerberos";944auth.PackageListLength = 8;945ss = AcquireCredentialsHandle(946NULL,947isSPNEGO ? L"Negotiate" : L"Kerberos",948SECPKG_CRED_OUTBOUND,949NULL,950isSPNEGO ? &auth : NULL,951NULL,952NULL,953newCred,954&lifeTime);955if (!(SEC_SUCCESS(ss))) {956goto err;957}958pc->phCred = newCred;959pc->isLocalCred = TRUE;960}961}962ss = InitializeSecurityContext(963pc->phCred,964firstTime ? NULL : &pc->hCtxt,965outName,966flag,9670,968SECURITY_NATIVE_DREP,969firstTime ? NULL : &inBuffDesc,9700,971&pc->hCtxt,972&outBuffDesc,973&outFlag,974&lifeTime);975976if (!SEC_SUCCESS(ss)) {977PP("InitializeSecurityContext failed");978goto err;979}980981pc->flags = *ret_flags = flag_sspi_to_gss(outFlag);982983// Ignore the result of the next call. Might fail before context established.984QueryContextAttributes(985&pc->hCtxt, SECPKG_ATTR_SIZES, &pc->SecPkgContextSizes);986PP("cbMaxSignature: %ld. cbBlockSize: %ld. cbSecurityTrailer: %ld",987pc->SecPkgContextSizes.cbMaxSignature,988pc->SecPkgContextSizes.cbBlockSize,989pc->SecPkgContextSizes.cbSecurityTrailer);990991output_token->length = outSecBuff.cbBuffer;992if (outSecBuff.cbBuffer) {993// No idea how user would free the data. Let's duplicate one.994output_token->value = new char[outSecBuff.cbBuffer];995if (!output_token->value) {996FreeContextBuffer(outSecBuff.pvBuffer);997goto err;998}999memcpy(output_token->value, outSecBuff.pvBuffer, outSecBuff.cbBuffer);1000FreeContextBuffer(outSecBuff.pvBuffer);1001}10021003if (ss == SEC_I_CONTINUE_NEEDED) {1004return GSS_S_CONTINUE_NEEDED;1005} else {1006pc->established = true;1007ss = QueryContextAttributes(&pc->hCtxt, SECPKG_ATTR_NATIVE_NAMES, &pc->nnames);1008if (!SEC_SUCCESS(ss)) {1009goto err;1010}1011PP("Names. %ls %ls", pc->nnames.sClientName, pc->nnames.sServerName);1012*ret_flags |= GSS_C_PROT_READY_FLAG;1013return GSS_S_COMPLETE;1014}1015err:1016if (newCred) {1017delete newCred;1018}1019if (firstTime) {1020OM_uint32 dummy;1021gss_delete_sec_context(&dummy, context_handle, GSS_C_NO_BUFFER);1022}1023if (output_token->value) {1024gss_release_buffer(NULL, output_token);1025}1026output_token = GSS_C_NO_BUFFER;1027return GSS_S_FAILURE;1028}10291030__declspec(dllexport) OM_uint321031gss_accept_sec_context(OM_uint32 *minor_status,1032gss_ctx_id_t *context_handle,1033gss_const_cred_id_t acceptor_cred_handle,1034gss_const_buffer_t input_token,1035gss_const_channel_bindings_t input_chan_bindings,1036gss_name_t *src_name,1037gss_OID *mech_type,1038gss_buffer_t output_token,1039OM_uint32 *ret_flags,1040OM_uint32 *time_rec,1041gss_cred_id_t *delegated_cred_handle)1042{1043PP(">>>> Calling UNIMPLEMENTED gss_accept_sec_context...");1044PP("gss_accept_sec_context is not supported in this initiator-only library");1045return GSS_S_FAILURE;1046}10471048__declspec(dllexport) OM_uint321049gss_inquire_context(OM_uint32 *minor_status,1050gss_const_ctx_id_t context_handle,1051gss_name_t *src_name,1052gss_name_t *targ_name,1053OM_uint32 *lifetime_rec,1054gss_OID *mech_type,1055OM_uint32 *ctx_flags,1056int *locally_initiated,1057int *open)1058{1059PP(">>>> Calling gss_inquire_context...");1060CHECK_CONTEXT(context_handle)10611062gss_name_t n1 = NULL;1063gss_name_t n2 = NULL;1064if (!context_handle->established) {1065return GSS_S_NO_CONTEXT;1066}1067if (src_name != NULL) {1068n1 = new gss_name_struct;1069if (n1 == NULL) {1070goto err;1071}1072n1->name = new SEC_WCHAR[lstrlen(context_handle->nnames.sClientName) + 1];1073if (n1->name == NULL) {1074goto err;1075}1076PP("Allocate new name at %p", n1->name);1077StringCchCopy(n1->name, lstrlen(context_handle->nnames.sClientName) + 1,1078context_handle->nnames.sClientName);1079*src_name = (gss_name_t) n1;1080}1081if (targ_name != NULL) {1082n2 = new gss_name_struct;1083if (n2 == NULL) {1084goto err;1085}1086n2->name = new SEC_WCHAR[lstrlen(context_handle->nnames.sServerName) + 1];1087if (n2->name == NULL) {1088goto err;1089}1090PP("Allocate new name at %p", n2->name);1091StringCchCopy(n2->name, lstrlen(context_handle->nnames.sServerName) + 1,1092context_handle->nnames.sServerName);1093*targ_name = (gss_name_t) n2;1094}1095if (lifetime_rec != NULL) {1096SecPkgContext_Lifespan ls;1097SECURITY_STATUS ss;1098ss = QueryContextAttributes(1099(PCtxtHandle)&context_handle->hCtxt,1100SECPKG_ATTR_LIFESPAN,1101&ls);1102if (!SEC_SUCCESS(ss)) {1103goto err;1104}1105*lifetime_rec = seconds_until(0, &ls.tsExpiry);1106}1107if (mech_type != NULL) {1108*mech_type = context_handle->isSPNEGO1109? &SPNEGO_OID : &KRB5_OID;1110}1111if (ctx_flags != NULL) {1112*ctx_flags = context_handle->flags;1113}1114if (locally_initiated != NULL) {1115// We are always initiator1116*locally_initiated = 1;1117}1118return GSS_S_COMPLETE;1119err:1120if (n1 != NULL) {1121if (n1->name != NULL) {1122delete[] n1->name;1123}1124delete n1;1125n1 = NULL;1126}1127if (n2 != NULL) {1128if (n2->name != NULL) {1129delete[] n2->name;1130}1131delete n2;1132n2 = NULL;1133}1134return GSS_S_FAILURE;1135}11361137__declspec(dllexport) OM_uint321138gss_delete_sec_context(OM_uint32 *minor_status,1139gss_ctx_id_t *context_handle,1140gss_buffer_t output_token)1141{1142PP(">>>> Calling gss_delete_sec_context...");1143CHECK_CONTEXT(context_handle)11441145DeleteSecurityContext(&(*context_handle)->hCtxt);1146if ((*context_handle)->isLocalCred && (*context_handle)->phCred != NULL) {1147FreeCredentialsHandle((*context_handle)->phCred);1148(*context_handle)->phCred = NULL;1149}1150if ((*context_handle)->nnames.sClientName != NULL) {1151FreeContextBuffer((*context_handle)->nnames.sClientName);1152(*context_handle)->nnames.sClientName = NULL;1153}1154if ((*context_handle)->nnames.sServerName != NULL) {1155FreeContextBuffer((*context_handle)->nnames.sServerName);1156(*context_handle)->nnames.sServerName = NULL;1157}1158delete (*context_handle);1159*context_handle = GSS_C_NO_CONTEXT;1160return GSS_S_COMPLETE;1161}11621163__declspec(dllexport) OM_uint321164gss_context_time(OM_uint32 *minor_status,1165gss_const_ctx_id_t context_handle,1166OM_uint32 *time_rec)1167{1168PP(">>>> Calling IMPLEMENTED gss_context_time...");1169CHECK_CONTEXT(context_handle)1170CHECK_OUTPUT(time_rec)11711172SECURITY_STATUS ss;1173SecPkgContext_Lifespan ls;1174ss = QueryContextAttributes(1175(PCtxtHandle)&context_handle->hCtxt,1176SECPKG_ATTR_LIFESPAN,1177&ls);1178if (ss == SEC_E_OK) {1179*time_rec = seconds_until(0, &ls.tsExpiry);1180show_time("context start", &ls.tsStart);1181show_time("context expiry", &ls.tsExpiry);1182return *time_rec == 0 ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;1183} else {1184return GSS_S_FAILURE;1185}1186}11871188__declspec(dllexport) OM_uint321189gss_wrap_size_limit(OM_uint32 *minor_status,1190gss_const_ctx_id_t context_handle,1191int conf_req_flag,1192gss_qop_t qop_req,1193OM_uint32 req_output_size,1194OM_uint32 *max_input_size)1195{1196PP(">>>> Calling gss_wrap_size_limit...");1197CHECK_CONTEXT(context_handle)1198CHECK_OUTPUT(max_input_size)11991200*max_input_size = req_output_size1201- context_handle->SecPkgContextSizes.cbSecurityTrailer1202- context_handle->SecPkgContextSizes.cbBlockSize;1203return GSS_S_COMPLETE;1204}12051206__declspec(dllexport) OM_uint321207gss_export_sec_context(OM_uint32 *minor_status,1208gss_ctx_id_t *context_handle,1209gss_buffer_t interprocess_token)1210{1211PP(">>>> Calling UNIMPLEMENTED gss_export_sec_context...");1212return GSS_S_FAILURE;1213}12141215__declspec(dllexport) OM_uint321216gss_get_mic(OM_uint32 *minor_status,1217gss_const_ctx_id_t context_handle,1218gss_qop_t qop_req,1219gss_const_buffer_t message_buffer,1220gss_buffer_t msg_token)1221{1222PP(">>>> Calling gss_get_mic...");1223CHECK_CONTEXT(context_handle)1224CHECK_BUFFER(message_buffer)1225CHECK_OUTPUT(msg_token)12261227SECURITY_STATUS ss;1228SecBufferDesc buffDesc;1229SecBuffer secBuff[2];12301231buffDesc.cBuffers = 2;1232buffDesc.pBuffers = secBuff;1233buffDesc.ulVersion = SECBUFFER_VERSION;12341235secBuff[0].BufferType = SECBUFFER_DATA;1236secBuff[0].cbBuffer = (ULONG)message_buffer->length;1237secBuff[0].pvBuffer = message_buffer->value;12381239secBuff[1].BufferType = SECBUFFER_TOKEN;1240secBuff[1].cbBuffer = context_handle->SecPkgContextSizes.cbMaxSignature;1241secBuff[1].pvBuffer = msg_token->value = new char[secBuff[1].cbBuffer];12421243if (!secBuff[1].pvBuffer) {1244goto err;1245}12461247ss = MakeSignature((PCtxtHandle)&context_handle->hCtxt, 0, &buffDesc, 0);12481249if (!SEC_SUCCESS(ss)) {1250goto err;1251}12521253msg_token->length = secBuff[1].cbBuffer;1254return GSS_S_COMPLETE;12551256err:1257msg_token->length = 0;1258msg_token->value = NULL;1259if (secBuff[1].pvBuffer) {1260delete[] secBuff[1].pvBuffer;1261}1262return GSS_S_FAILURE;1263}12641265__declspec(dllexport) OM_uint321266gss_verify_mic(OM_uint32 *minor_status,1267gss_const_ctx_id_t context_handle,1268gss_const_buffer_t message_buffer,1269gss_const_buffer_t token_buffer,1270gss_qop_t *qop_state)1271{1272PP(">>>> Calling gss_verify_mic...");1273CHECK_CONTEXT(context_handle)1274CHECK_BUFFER(message_buffer)1275CHECK_BUFFER(token_buffer)12761277SECURITY_STATUS ss;1278SecBufferDesc buffDesc;1279SecBuffer secBuff[2];1280ULONG qop;12811282buffDesc.ulVersion = SECBUFFER_VERSION;1283buffDesc.cBuffers = 2;1284buffDesc.pBuffers = secBuff;12851286secBuff[0].BufferType = SECBUFFER_TOKEN;1287secBuff[0].cbBuffer = (ULONG)token_buffer->length;1288secBuff[0].pvBuffer = token_buffer->value;12891290secBuff[1].BufferType = SECBUFFER_DATA;1291secBuff[1].cbBuffer = (ULONG)message_buffer->length;1292secBuff[1].pvBuffer = message_buffer->value;12931294ss = VerifySignature((PCtxtHandle)&context_handle->hCtxt, &buffDesc, 0, &qop);1295if (qop_state) {1296*qop_state = qop;1297}12981299if (ss == SEC_E_OK) {1300return GSS_S_COMPLETE;1301} else if (ss == SEC_E_OUT_OF_SEQUENCE) {1302return GSS_S_UNSEQ_TOKEN;1303} else {1304return GSS_S_BAD_SIG;1305}1306}13071308__declspec(dllexport) OM_uint321309gss_wrap(OM_uint32 *minor_status,1310gss_const_ctx_id_t context_handle,1311int conf_req_flag,1312gss_qop_t qop_req,1313gss_const_buffer_t input_message_buffer,1314int *conf_state,1315gss_buffer_t output_message_buffer)1316{1317PP(">>>> Calling gss_wrap...");1318CHECK_CONTEXT(context_handle)1319CHECK_BUFFER(input_message_buffer)1320CHECK_OUTPUT(output_message_buffer)13211322SECURITY_STATUS ss;1323SecBufferDesc buffDesc;1324SecBuffer secBuff[3];13251326buffDesc.ulVersion = SECBUFFER_VERSION;1327buffDesc.cBuffers = 3;1328buffDesc.pBuffers = secBuff;13291330secBuff[0].BufferType = SECBUFFER_TOKEN;1331secBuff[0].cbBuffer = context_handle->SecPkgContextSizes.cbSecurityTrailer;1332output_message_buffer->value = secBuff[0].pvBuffer = malloc(1333context_handle->SecPkgContextSizes.cbSecurityTrailer1334+ input_message_buffer->length1335+ context_handle->SecPkgContextSizes.cbBlockSize);;1336if (!output_message_buffer->value) {1337goto err;1338}13391340secBuff[1].BufferType = SECBUFFER_DATA;1341secBuff[1].cbBuffer = (ULONG)input_message_buffer->length;1342secBuff[1].pvBuffer = malloc(secBuff[1].cbBuffer);1343if (!secBuff[1].pvBuffer) {1344goto err;1345}1346memcpy_s(secBuff[1].pvBuffer, secBuff[1].cbBuffer,1347input_message_buffer->value, input_message_buffer->length);13481349secBuff[2].BufferType = SECBUFFER_PADDING;1350secBuff[2].cbBuffer = context_handle->SecPkgContextSizes.cbBlockSize;1351secBuff[2].pvBuffer = malloc(secBuff[2].cbBuffer);1352if (!secBuff[2].pvBuffer) {1353goto err;1354}13551356ss = EncryptMessage((PCtxtHandle)&context_handle->hCtxt,1357conf_req_flag ? 0 : SECQOP_WRAP_NO_ENCRYPT,1358&buffDesc, 0);1359if (conf_state) {1360*conf_state = conf_req_flag;1361}13621363if (!SEC_SUCCESS(ss)) {1364goto err;1365}13661367memcpy_s((PBYTE)secBuff[0].pvBuffer + secBuff[0].cbBuffer,1368input_message_buffer->length + context_handle->SecPkgContextSizes.cbBlockSize,1369secBuff[1].pvBuffer,1370secBuff[1].cbBuffer);1371memcpy_s((PBYTE)secBuff[0].pvBuffer + secBuff[0].cbBuffer + secBuff[1].cbBuffer,1372context_handle->SecPkgContextSizes.cbBlockSize,1373secBuff[2].pvBuffer,1374secBuff[2].cbBuffer);13751376output_message_buffer->length = secBuff[0].cbBuffer + secBuff[1].cbBuffer1377+ secBuff[2].cbBuffer;1378free(secBuff[1].pvBuffer);1379free(secBuff[2].pvBuffer);13801381return GSS_S_COMPLETE;13821383err:1384if (secBuff[0].pvBuffer) {1385free(secBuff[0].pvBuffer);1386}1387if (secBuff[1].pvBuffer) {1388free(secBuff[1].pvBuffer);1389}1390if (secBuff[2].pvBuffer) {1391free(secBuff[2].pvBuffer);1392}1393output_message_buffer->length = 0;1394output_message_buffer->value = NULL;1395return GSS_S_FAILURE;1396}13971398__declspec(dllexport) OM_uint321399gss_unwrap(OM_uint32 *minor_status,1400gss_const_ctx_id_t context_handle,1401gss_const_buffer_t input_message_buffer,1402gss_buffer_t output_message_buffer,1403int *conf_state,1404gss_qop_t *qop_state)1405{1406PP(">>>> Calling gss_unwrap...");1407CHECK_CONTEXT(context_handle)1408CHECK_BUFFER(input_message_buffer)1409CHECK_OUTPUT(output_message_buffer)14101411SECURITY_STATUS ss;1412SecBufferDesc buffDesc;1413SecBuffer secBuff[2];1414ULONG ulQop = 0;14151416buffDesc.cBuffers = 2;1417buffDesc.pBuffers = secBuff;1418buffDesc.ulVersion = SECBUFFER_VERSION;14191420secBuff[0].BufferType = SECBUFFER_STREAM;1421secBuff[0].cbBuffer = (ULONG)input_message_buffer->length;1422secBuff[0].pvBuffer = malloc(input_message_buffer->length);14231424if (!secBuff[0].pvBuffer) {1425goto err;1426}14271428memcpy_s(secBuff[0].pvBuffer, input_message_buffer->length,1429input_message_buffer->value, input_message_buffer->length);14301431secBuff[1].BufferType = SECBUFFER_DATA;1432secBuff[1].cbBuffer = 0;1433secBuff[1].pvBuffer = NULL;14341435ss = DecryptMessage((PCtxtHandle)&context_handle->hCtxt, &buffDesc, 0, &ulQop);1436if (qop_state) {1437*qop_state = ulQop;1438}1439if (!SEC_SUCCESS(ss)) {1440goto err;1441}14421443// Must allocate a new memory block so client can release it correctly1444output_message_buffer->length = secBuff[1].cbBuffer;1445output_message_buffer->value = new char[secBuff[1].cbBuffer];14461447if (!output_message_buffer->value) {1448goto err;1449}14501451memcpy_s(output_message_buffer->value, secBuff[1].cbBuffer,1452secBuff[1].pvBuffer, secBuff[1].cbBuffer);1453*conf_state = ulQop == SECQOP_WRAP_NO_ENCRYPT ? 0 : 1;14541455free(secBuff[0].pvBuffer);1456return GSS_S_COMPLETE;14571458err:1459if (secBuff[0].pvBuffer) {1460free(secBuff[0].pvBuffer);1461}1462output_message_buffer->length = 0;1463output_message_buffer->value = NULL;1464return GSS_S_FAILURE;1465}14661467__declspec(dllexport) OM_uint321468gss_indicate_mechs(OM_uint32 *minor_status,1469gss_OID_set *mech_set)1470{1471PP(">>>> Calling gss_indicate_mechs...");1472OM_uint32 major = GSS_S_COMPLETE;14731474ULONG ccPackages;1475PSecPkgInfo packages;1476EnumerateSecurityPackages(&ccPackages, &packages);1477PP("EnumerateSecurityPackages returns %ld", ccPackages);1478for (unsigned int i = 0; i < ccPackages; i++) {1479PP("#%d: %ls, %ls\n", i, packages[i].Name, packages[i].Comment);1480}1481FreeContextBuffer(packages);14821483// Hardcode kerberos and SPNEGO support1484major = gss_create_empty_oid_set(minor_status, mech_set);1485if (major != GSS_S_COMPLETE) {1486goto done;1487}14881489major = gss_add_oid_set_member(minor_status, &KRB5_OID, mech_set);1490if (major != GSS_S_COMPLETE) {1491goto done;1492}14931494major = gss_add_oid_set_member(minor_status, &SPNEGO_OID, mech_set);1495if (major != GSS_S_COMPLETE) {1496goto done;1497}14981499done:15001501if (major != GSS_S_COMPLETE) {1502gss_release_oid_set(minor_status, mech_set);1503}15041505return major;1506}15071508__declspec(dllexport) OM_uint321509gss_inquire_names_for_mech(OM_uint32 *minor_status,1510gss_const_OID mechanism,1511gss_OID_set *name_types)1512{1513PP(">>>> Calling gss_inquire_names_for_mech...");1514CHECK_OID(mechanism)15151516if (gss_create_empty_oid_set(minor_status, name_types)) {1517return GSS_S_FAILURE;1518}1519if (gss_add_oid_set_member(minor_status, &USER_NAME_OID, name_types)) {1520goto err;1521}1522if (gss_add_oid_set_member(minor_status, &HOST_SERVICE_NAME_OID, name_types)) {1523goto err;1524}1525if (!is_same_oid(mechanism, &SPNEGO_OID)) {1526if (gss_add_oid_set_member(minor_status, &EXPORT_NAME_OID, name_types)) {1527goto err;1528}1529}1530return GSS_S_COMPLETE;1531err:1532gss_release_oid_set(minor_status, name_types);1533return GSS_S_FAILURE;1534}15351536__declspec(dllexport) OM_uint321537gss_add_oid_set_member(OM_uint32 *minor_status,1538gss_const_OID member_oid,1539gss_OID_set *oid_set)1540{1541PP(">>>> Calling gss_add_oid_set_member...");1542CHECK_OID(member_oid)1543CHECK_OUTPUT(oid_set)154415451546int count = (int)(*oid_set)->count;1547for (int i = 0; i < count; i++) {1548if (is_same_oid(&(*oid_set)->elements[i], member_oid)) {1549// already there1550return GSS_S_COMPLETE;1551}1552}1553gss_OID existing = (*oid_set)->elements;1554gss_OID newcopy = new gss_OID_desc[count + 1];1555if (newcopy == NULL) {1556return GSS_S_FAILURE;1557}1558if (existing) {1559memcpy_s(newcopy, (count + 1) * sizeof(gss_OID_desc),1560existing, count * sizeof(gss_OID_desc));1561}1562newcopy[count].length = member_oid->length;1563newcopy[count].elements = new char[member_oid->length];1564if (newcopy[count].elements == NULL) {1565delete[] newcopy;1566return GSS_S_FAILURE;1567}1568memcpy_s(newcopy[count].elements, member_oid->length,1569member_oid->elements, member_oid->length);1570(*oid_set)->elements = newcopy;1571(*oid_set)->count++;1572if (existing) {1573delete[] existing;1574}15751576return GSS_S_COMPLETE;1577}15781579__declspec(dllexport) OM_uint321580gss_display_status(OM_uint32 *minor_status,1581OM_uint32 status_value,1582int status_type,1583gss_const_OID mech_type,1584OM_uint32 *message_context,1585gss_buffer_t status_string)1586{1587PP(">>>> Calling gss_display_status...");1588TCHAR msg[256];1589int len = FormatMessage(1590FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,15910, status_value,1592MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),1593msg, 256, 0);1594if (len > 0) {1595status_string->value = new char[len + 20];1596if (!status_string->value) {1597status_string = GSS_C_NO_BUFFER;1598return GSS_S_FAILURE;1599}1600status_string->length = sprintf_s(1601(LPSTR)status_string->value, len + 19,1602"(%lx) %ls", status_value, msg);1603} else {1604status_string->value = new char[33];1605if (!status_string->value) {1606status_string = GSS_C_NO_BUFFER;1607return GSS_S_FAILURE;1608}1609status_string->length = sprintf_s(1610(LPSTR)status_string->value, 32,1611"status is %lx", status_value);1612}1613if (status_string->length <= 0) {1614gss_release_buffer(NULL, status_string);1615status_string = GSS_C_NO_BUFFER;1616return GSS_S_FAILURE;1617} else {1618return GSS_S_COMPLETE;1619}1620}16211622__declspec(dllexport) OM_uint321623gss_create_empty_oid_set(OM_uint32 *minor_status,1624gss_OID_set *oid_set)1625{1626PP(">>>> Calling gss_create_empty_oid_set...");1627CHECK_OUTPUT(oid_set)16281629if (*oid_set = new gss_OID_set_desc) {1630memset(*oid_set, 0, sizeof(gss_OID_set_desc));1631return GSS_S_COMPLETE;1632}1633return GSS_S_FAILURE;1634}16351636__declspec(dllexport) OM_uint321637gss_release_oid_set(OM_uint32 *minor_status,1638gss_OID_set *set)1639{1640PP(">>>> Calling gss_release_oid_set...");1641if (set == NULL || *set == GSS_C_NO_OID_SET) {1642return GSS_S_COMPLETE;1643}1644for (size_t i = 0; i < (*set)->count; i++) {1645delete[] (*set)->elements[i].elements;1646}1647delete[] (*set)->elements;1648delete *set;1649*set = GSS_C_NO_OID_SET;1650return GSS_S_COMPLETE;1651}16521653__declspec(dllexport) OM_uint321654gss_release_buffer(OM_uint32 *minor_status,1655gss_buffer_t buffer)1656{1657PP(">>>> Calling gss_release_buffer...");1658if (buffer == NULL || buffer == GSS_C_NO_BUFFER) {1659return GSS_S_COMPLETE;1660}1661if (buffer->value) {1662delete[] buffer->value;1663buffer->value = NULL;1664}1665buffer->length = 0;1666return GSS_S_COMPLETE;1667}16681669/* End implemented section */16701671#ifdef __cplusplus1672}1673#endif167416751676