# HG changeset patch # User weijun # Date 1526262903 -28800 # Node ID 543279c75f1a059d1977e7db24398582bc5b9de3 # Parent 5eb8262e8c5fba2aca58dda5c560a710914187cc First working version diff -r 5eb8262e8c5f -r 543279c75f1a make/lib/Lib-java.security.jgss.gmk --- a/make/lib/Lib-java.security.jgss.gmk Mon May 14 13:05:11 2018 +0800 +++ b/make/lib/Lib-java.security.jgss.gmk Mon May 14 09:55:03 2018 +0800 @@ -66,6 +66,19 @@ )) TARGETS += $(BUILD_LIBW2K_LSA_AUTH) + BUILD_LIBSSPI_BRIDGE_SRC := $(call FindSrcDirsForLib, $(MODULE), sspi_bridge) + + $(eval $(call SetupJdkLibrary, BUILD_LIBSSPI_BRIDGE, \ + NAME := sspi_bridge, \ + SRC := $(BUILD_LIBSSPI_BRIDGE_SRC), \ + OPTIMIZATION := LOW, \ + CFLAGS := $(CFLAGS_JDKLIB) \ + -I$(TOPDIR)/src/java.security.jgss/share/native/libj2gss, \ + LDFLAGS := $(LDFLAGS_JDKLIB) \ + $(call SET_SHARED_LIBRARY_ORIGIN) \ + )) + + TARGETS += $(BUILD_LIBSSPI_BRIDGE) endif ifeq ($(OPENJDK_TARGET_OS), macosx) diff -r 5eb8262e8c5f -r 543279c75f1a src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java --- a/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java Mon May 14 13:05:11 2018 +0800 +++ b/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java Mon May 14 09:55:03 2018 +0800 @@ -96,6 +96,8 @@ "libgssapi_krb5.dylib", "/usr/lib/sasl2/libgssapiv2.2.so", }; + } else if (osname.contains("Windows")) { + gssLibs = new String[] { "sspi_bridge.dll" }; } } else { gssLibs = new String[]{ defaultLib }; diff -r 5eb8262e8c5f -r 543279c75f1a src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp Mon May 14 09:55:03 2018 +0800 @@ -0,0 +1,792 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#define UNICODE +#define _UNICODE + +#include +#include +#include +#include +#include + +#define GSS_DLL_FILE +#include "gssapi.h" + +#define SECURITY_WIN32 +#include + +#pragma comment(lib, "secur32.lib") + +//#define DEBUG + +#ifdef DEBUG +TCHAR _bb[256]; +#define SEC_SUCCESS(Status) ((Status) >= 0 ? TRUE: (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,0,ss,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),_bb,256,0),printf("SECURITY_STATUS: (%lx) %ls\n",ss,_bb),FALSE)) +#define P fprintf(stdout, "SSPI (%ld): \n", __LINE__); fflush(stdout); +#define PP(s) fprintf(stdout, "SSPI (%ld): ", __LINE__); fprintf(stdout, "%s\n", s); fflush(stdout) +#define PP1(s,n) fprintf(stdout, "SSPI (%ld): ", __LINE__); fprintf(stdout, s, n); fflush(stdout) +#define PP2(s,n1,n2) fprintf(stdout, "SSPI (%ld): ", __LINE__); fprintf(stdout, s, n1, n2); fflush(stdout) +#define PP3(s,n1,n2,n3) fprintf(stdout, "SSPI (%ld): ", __LINE__); fprintf(stdout, s, n1, n2, n3); fflush(stdout) +BOOL debug = TRUE; +#else +#define SEC_SUCCESS(Status) ((Status) >= 0) +#define P +#define PP(s) +#define PP1(s,n) +#define PP2(s,n1,n2) +#define PP3(s,n1,n2,n3) +BOOL debug = FALSE; +#endif + +char KRB5_OID[9] = {(char)0x2a, (char)0x86, (char)0x48, (char)0x86, (char)0xf7, (char)0x12, (char)0x01, (char)0x02, (char)0x02}; +char KRB5_U2U_OID[10] = {(char)0x2a, (char)0x86, (char)0x48, (char)0x86, (char)0xf7, (char)0x12, (char)0x01, (char)0x02, (char)0x02, (char)0x03}; +char SPNEGO_OID[6] = {(char)0x2b, (char)0x06, (char)0x01, (char)0x05, (char)0x05, (char)0x02}; +char USER_NAME_OID[10] = {(char)0x2a, (char)0x86, (char)0x48, (char)0x86, (char)0xf7, (char)0x12, (char)0x01, (char)0x02, (char)0x01, (char)0x01}; +char HOST_SERVICE_NAME_OID[10] = {(char)0x2a, (char)0x86, (char)0x48, (char)0x86, (char)0xf7, (char)0x12, (char)0x01, (char)0x02, (char)0x01, (char)0x04}; + +typedef struct { + TCHAR PackageName[20]; + CredHandle* phCred; + struct _SecHandle hCtxt; + DWORD cbMaxMessage; + SecPkgContext_Sizes SecPkgContextSizes; +} Context; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +__declspec(dllexport) OM_uint32 gss_release_name + (OM_uint32 *minor_status, + gss_name_t *name) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_import_name + (OM_uint32 *minor_status, + gss_buffer_t input_name_buffer, + gss_OID input_name_type, + gss_name_t *output_name) { + SecPkgCredentials_Names* names = new SecPkgCredentials_Names(); + int len = (int)input_name_buffer->length; + names->sUserName = new SEC_WCHAR[len + 1]; + MultiByteToWideChar(CP_ACP, 0, (LPSTR)input_name_buffer->value, len, names->sUserName, len); + names->sUserName[len] = 0; + if (input_name_type->length == 10 && !memcmp(input_name_type->elements, HOST_SERVICE_NAME_OID, 10)) { + for (int i = 0; i < len; i++) { + if (names->sUserName[i] == '@') { + names->sUserName[i] = '/'; + } + } + } + *output_name = (gss_name_t) names; + return GSS_S_COMPLETE; +} + +__declspec(dllexport) OM_uint32 gss_compare_name + (OM_uint32 *minor_status, + gss_name_t name1, + gss_name_t name2, + int *name_equal) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_canonicalize_name + (OM_uint32 *minor_status, + gss_name_t input_name, + gss_OID mech_type, + gss_name_t *output_name) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_export_name + (OM_uint32 *minor_status, + gss_name_t input_name, + gss_buffer_t exported_name) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_display_name + (OM_uint32 *minor_status, + gss_name_t input_name, + gss_buffer_t output_name_buffer, + gss_OID *output_name_type) { + SecPkgCredentials_Names* names = (SecPkgCredentials_Names*)input_name; + int len = (int)wcslen(names->sUserName); + char* buffer = new char[len+1]; + WideCharToMultiByte(CP_ACP, 0, names->sUserName, len, buffer, len, NULL, NULL); + buffer[len] = 0; + output_name_buffer->length = len+1; + output_name_buffer->value = buffer; + PP1("Name found: %ls\n", names->sUserName); + PP2("%d [%s]", len, buffer); + if (output_name_type != NULL) { + gss_OID_desc* oid = new gss_OID_desc(); + oid->length = (OM_uint32)strlen(USER_NAME_OID); + oid->elements = strdup(USER_NAME_OID); + *output_name_type = oid; + } + return GSS_S_COMPLETE; +} + +long TimeStampToLong(TimeStamp *time) { + ULARGE_INTEGER *a, *b; + FILETIME fnow; + GetSystemTimeAsFileTime(&fnow); + a = (ULARGE_INTEGER*)time; + b = (ULARGE_INTEGER*)&fnow; + PP1("Difference %ld\n", (long)((a->QuadPart - b->QuadPart) / 10000000)); + return (long)((a->QuadPart - b->QuadPart) / 10000000); +} + +__declspec(dllexport) OM_uint32 gss_acquire_cred + (OM_uint32 *minor_status, + gss_name_t desired_name, + OM_uint32 time_req, + gss_OID_set desired_mech, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) { + if (desired_name != NULL) { + return GSS_S_FAILURE; // Only support default cred + } + SECURITY_STATUS ss; + CredHandle* cred = new CredHandle(); + TimeStamp ts; + cred_usage = 0; + PP1("AcquireCredentialsHandle with %d\n", cred_usage); + ss = AcquireCredentialsHandle( + NULL, + L"Kerberos", + cred_usage == 0 ? SECPKG_CRED_BOTH : + (cred_usage == 1 ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND), + NULL, + NULL, + NULL, + NULL, + cred, + &ts + ); + + actual_mechs = &desired_mech; + *output_cred_handle = (void*)cred; + if (time_rec != NULL) { + *time_rec = TimeStampToLong(&ts); + } + + return GSS_S_COMPLETE; +} + +__declspec(dllexport) OM_uint32 gss_release_cred + (OM_uint32 *minor_status, + gss_cred_id_t *cred_handle) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_inquire_cred + (OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + gss_name_t *name, + OM_uint32 *lifetime, + gss_cred_usage_t *cred_usage, + gss_OID_set *mechanisms) { + CredHandle* cred = (CredHandle*)cred_handle; + SECURITY_STATUS ss; + if (name) { + SecPkgCredentials_Names* names = new SecPkgCredentials_Names(); + ss = QueryCredentialsAttributes(cred, SECPKG_CRED_ATTR_NAMES, names); + *name = (gss_name_t) names; + } + // Others inquiries not supported yet + return GSS_S_COMPLETE; +} + +__declspec(dllexport) OM_uint32 gss_import_sec_context + (OM_uint32 *minor_status, + gss_buffer_t interprocess_token, + gss_ctx_id_t *context_handle) { + return GSS_S_FAILURE; +} + +void FillContextAfterEstablished(Context *pc) { + QueryContextAttributes(&pc->hCtxt, SECPKG_ATTR_SIZES, + &pc->SecPkgContextSizes); +} + +SECURITY_STATUS GenClientContext( + Context *pc, + int flag, + BYTE *pIn, + size_t cbIn, + BYTE *pOut, + size_t *pcbOut, + BOOL *pfDone, + ULONG *pOutFlag, + TCHAR *pszTarget) { + SECURITY_STATUS ss; + TimeStamp Lifetime; + SecBufferDesc OutBuffDesc; + SecBuffer OutSecBuff; + SecBufferDesc InBuffDesc; + SecBuffer InSecBuff; + + OutBuffDesc.ulVersion = SECBUFFER_VERSION; + OutBuffDesc.cBuffers = 1; + OutBuffDesc.pBuffers = &OutSecBuff; + + OutSecBuff.cbBuffer = (ULONG)*pcbOut; + OutSecBuff.BufferType = SECBUFFER_TOKEN; + OutSecBuff.pvBuffer = pOut; + + PP2("TARGET: %ls %ls\n", pszTarget, pc->PackageName); + PP2("flag: %x [%ls]\n", flag, pszTarget); + if (pIn) { + InBuffDesc.ulVersion = SECBUFFER_VERSION; + InBuffDesc.cBuffers = 1; + InBuffDesc.pBuffers = &InSecBuff; + + InSecBuff.cbBuffer = (ULONG)cbIn; + InSecBuff.BufferType = SECBUFFER_TOKEN; + InSecBuff.pvBuffer = pIn; + + ss = InitializeSecurityContext( + pc->phCred, + &pc->hCtxt, + pszTarget, + flag, + 0, + SECURITY_NATIVE_DREP, + &InBuffDesc, + 0, + &pc->hCtxt, + &OutBuffDesc, + pOutFlag, + &Lifetime); + } else { + if (!pc->phCred) { + PP("No credentials provided, acquire automatically"); + ss = AcquireCredentialsHandle( + NULL, + pc->PackageName, + SECPKG_CRED_OUTBOUND, + NULL, + NULL, + NULL, + NULL, + pc->phCred, + &Lifetime); + PP("end"); + if (!(SEC_SUCCESS(ss))) { + PP("Failed"); + return ss; + } + } else { + PP("Credentials OK"); + } + ss = InitializeSecurityContext( + pc->phCred, + NULL, + pszTarget, + flag, + 0, + SECURITY_NATIVE_DREP, + NULL, + 0, + &pc->hCtxt, + &OutBuffDesc, + pOutFlag, + &Lifetime); + } + + if (!SEC_SUCCESS(ss)) { + PP("InitializeSecurityContext Failed"); + return ss; + } + //------------------------------------------------------------------- + // If necessary, complete the token. + + if ((SEC_I_COMPLETE_NEEDED == ss) + || (SEC_I_COMPLETE_AND_CONTINUE == ss)) { + ss = CompleteAuthToken(&pc->hCtxt, &OutBuffDesc); + if (!SEC_SUCCESS(ss)) { + return ss; + } + } + + *pcbOut = OutSecBuff.cbBuffer; + + *pfDone = !((SEC_I_CONTINUE_NEEDED == ss) || + (SEC_I_COMPLETE_AND_CONTINUE == ss)); + + return ss; +} + +Context* NewContext(TCHAR* PackageName) { + SECURITY_STATUS ss; + PSecPkgInfo pkgInfo; + + Context* out = (Context*)malloc(sizeof(Context)); + ss = QuerySecurityPackageInfo( + PackageName, + &pkgInfo); + if (!SEC_SUCCESS(ss)) { + return NULL; + } + out->phCred = NULL; + out->cbMaxMessage = pkgInfo->cbMaxToken; + PP2(" QuerySecurityPackageInfo %ls goes %ld\n", PackageName, out->cbMaxMessage); + wcscpy(out->PackageName, PackageName); + FreeContextBuffer(pkgInfo); + return out; +} + +int flagSspi2Gss(int fin) { + int fout = 0; + if (fin & ISC_REQ_MUTUAL_AUTH) fout |= GSS_C_MUTUAL_FLAG; + if (fin & ISC_REQ_CONFIDENTIALITY) fout |= GSS_C_CONF_FLAG; + if (fin & ISC_REQ_DELEGATE) fout |= GSS_C_DELEG_FLAG; + if (fin & ISC_REQ_INTEGRITY) fout |= GSS_C_INTEG_FLAG; + if (fin & ISC_REQ_REPLAY_DETECT) fout |= GSS_C_REPLAY_FLAG; + if (fin & ISC_REQ_SEQUENCE_DETECT) fout |= GSS_C_SEQUENCE_FLAG; + return fout; +} + +int flagGss2Sspi(int fin) { + int fout = 0; + if (fin & GSS_C_MUTUAL_FLAG) fout |= ISC_RET_MUTUAL_AUTH; + if (fin & GSS_C_CONF_FLAG) fout |= ISC_RET_CONFIDENTIALITY; + if (fin & GSS_C_DELEG_FLAG) fout |= ISC_RET_DELEGATE; + if (fin & GSS_C_INTEG_FLAG) fout |= ISC_RET_INTEGRITY; + if (fin & GSS_C_REPLAY_FLAG) fout |= ISC_RET_REPLAY_DETECT; + if (fin & GSS_C_SEQUENCE_FLAG) fout |= ISC_RET_SEQUENCE_DETECT; + return fout; +} + +__declspec(dllexport) OM_uint32 gss_init_sec_context + (OM_uint32 *minor_status, + gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t *context_handle, + gss_name_t target_name, + gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) { + SECURITY_STATUS ss; + + Context* pc; + if (input_token->length == 0) { + pc = NewContext(L"Kerberos"); + pc->phCred = (CredHandle*)initiator_cred_handle; + *context_handle = (gss_ctx_id_t) pc; + } else { + pc = (Context*)*context_handle; + } + + output_token->length = pc->cbMaxMessage; + output_token->value = new char[pc->cbMaxMessage]; + + DWORD outFlag; + TCHAR outName[100]; + + OM_uint32 minor; + gss_buffer_desc tn; + gss_display_name(&minor, target_name, &tn, NULL); + MultiByteToWideChar(CP_ACP, 0, (LPCCH)tn.value, (int)tn.length, outName, (int)tn.length); + outName[tn.length] = 0; + + BOOL pfDone; + ss = GenClientContext( + pc, flagGss2Sspi(req_flags), + (BYTE*)input_token->value, input_token->length, + (BYTE*)output_token->value, &(output_token->length), + &pfDone, &outFlag, + (TCHAR*)outName); + if (ss == SEC_E_OK) FillContextAfterEstablished(pc); + outFlag = flagSspi2Gss(outFlag); + + if (!SEC_SUCCESS(ss)) { + return GSS_S_FAILURE; + } + + *ret_flags = (OM_uint32)outFlag; + if (ss == SEC_I_CONTINUE_NEEDED) { + return GSS_S_CONTINUE_NEEDED; + } else { + *ret_flags |= GSS_C_PROT_READY_FLAG; + return GSS_S_COMPLETE; + } +} + +__declspec(dllexport) OM_uint32 gss_accept_sec_context + (OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_cred_id_t acceptor_cred_handle, + gss_buffer_t input_token, + gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_inquire_context + (OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_name_t *src_name, + gss_name_t *targ_name, + OM_uint32 *lifetime_rec, + gss_OID *mech_type, + OM_uint32 *ctx_flags, + int *locally_initiated, + int *open) { + Context* pc = (Context*) context_handle; + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_delete_sec_context + (OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_context_time + (OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + OM_uint32 *time_rec) { + Context* pc = (Context*) context_handle; + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_wrap_size_limit + (OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size) { + Context* pc = (Context*) context_handle; + *max_input_size = pc->cbMaxMessage; + return GSS_S_COMPLETE; +} + +__declspec(dllexport) OM_uint32 gss_export_sec_context + (OM_uint32 *minor_status, + gss_ctx_id_t *context_handle, + gss_buffer_t interprocess_token) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_get_mic + (OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_qop_t qop_req, + gss_buffer_t message_buffer, + gss_buffer_t msg_token) { + + Context* pc = (Context*) context_handle; + + SECURITY_STATUS ss; + SecBufferDesc BuffDesc; + SecBuffer SecBuff[2]; + + BuffDesc.cBuffers = 2; + BuffDesc.pBuffers = SecBuff; + BuffDesc.ulVersion = SECBUFFER_VERSION; + + SecBuff[0].BufferType = SECBUFFER_DATA; + SecBuff[0].cbBuffer = (ULONG)message_buffer->length; + SecBuff[0].pvBuffer = message_buffer->value; + + SecBuff[1].BufferType = SECBUFFER_TOKEN; + SecBuff[1].cbBuffer = pc->SecPkgContextSizes.cbMaxSignature; + SecBuff[1].pvBuffer = msg_token->value = malloc(SecBuff[1].cbBuffer); + + ss = MakeSignature(&pc->hCtxt, 0, &BuffDesc, 0); + + if (!SEC_SUCCESS(ss)) { + free(SecBuff[1].pvBuffer); + return GSS_S_FAILURE; + } + + msg_token->length = SecBuff[1].cbBuffer; + return GSS_S_COMPLETE; +} + +__declspec(dllexport) OM_uint32 gss_verify_mic + (OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t message_buffer, + gss_buffer_t token_buffer, + gss_qop_t *qop_state) { + Context* pc = (Context*) context_handle; + + SECURITY_STATUS ss; + SecBufferDesc BuffDesc; + SecBuffer SecBuff[2]; + ULONG qop; + + BuffDesc.ulVersion = 0; + BuffDesc.cBuffers = 2; + BuffDesc.pBuffers = SecBuff; + + SecBuff[0].BufferType = SECBUFFER_TOKEN; + SecBuff[0].cbBuffer = (ULONG)token_buffer->length; + SecBuff[0].pvBuffer = token_buffer->value; + + SecBuff[1].BufferType = SECBUFFER_DATA; + SecBuff[1].cbBuffer = (ULONG)message_buffer->length; + SecBuff[1].pvBuffer = message_buffer->value; + + ss = VerifySignature(&pc->hCtxt, &BuffDesc, 0, &qop); + *qop_state = qop; + + if (ss == SEC_E_OK) { + return GSS_S_COMPLETE; + } else if (ss == SEC_E_OUT_OF_SEQUENCE) { + return GSS_S_UNSEQ_TOKEN; + } else { + return GSS_S_BAD_SIG; + } +} + +__declspec(dllexport) OM_uint32 gss_wrap + (OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer) { + + Context* pc = (Context*) context_handle; + + SECURITY_STATUS ss; + SecBufferDesc BuffDesc; + SecBuffer SecBuff[3]; + + BuffDesc.ulVersion = SECBUFFER_VERSION; + BuffDesc.cBuffers = 3; + BuffDesc.pBuffers = SecBuff; + + SecBuff[0].BufferType = SECBUFFER_TOKEN; + SecBuff[0].cbBuffer = pc->SecPkgContextSizes.cbSecurityTrailer; + output_message_buffer->value = SecBuff[0].pvBuffer = malloc(pc->SecPkgContextSizes.cbSecurityTrailer + + input_message_buffer->length + pc->SecPkgContextSizes.cbBlockSize);; + + SecBuff[1].BufferType = SECBUFFER_DATA; + SecBuff[1].cbBuffer = (ULONG)input_message_buffer->length; + SecBuff[1].pvBuffer = malloc(SecBuff[1].cbBuffer); + memcpy(SecBuff[1].pvBuffer, input_message_buffer->value, input_message_buffer->length); + + SecBuff[2].BufferType = SECBUFFER_PADDING; + SecBuff[2].cbBuffer = pc->SecPkgContextSizes.cbBlockSize; + SecBuff[2].pvBuffer = malloc(SecBuff[2].cbBuffer); + + ss = EncryptMessage(&pc->hCtxt, conf_req_flag ? 0 : SECQOP_WRAP_NO_ENCRYPT, &BuffDesc, 0); + *conf_state = conf_req_flag; + + if (!SEC_SUCCESS(ss)) { + free(SecBuff[0].pvBuffer); + free(SecBuff[1].pvBuffer); + free(SecBuff[2].pvBuffer); + return GSS_S_FAILURE; + } + + memcpy((PBYTE)SecBuff[0].pvBuffer + SecBuff[0].cbBuffer, SecBuff[1].pvBuffer, + SecBuff[1].cbBuffer); + memcpy((PBYTE)SecBuff[0].pvBuffer + SecBuff[0].cbBuffer + SecBuff[1].cbBuffer, + SecBuff[2].pvBuffer, SecBuff[2].cbBuffer); + + output_message_buffer->length = SecBuff[1].cbBuffer + SecBuff[0].cbBuffer + + SecBuff[2].cbBuffer; + free(SecBuff[1].pvBuffer); + free(SecBuff[2].pvBuffer); + + return GSS_S_COMPLETE; +} + +__declspec(dllexport) OM_uint32 gss_unwrap + (OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t *qop_state) { + Context* pc = (Context*) context_handle; + + SECURITY_STATUS ss; + SecBufferDesc BuffDesc; + SecBuffer SecBuff[2]; + ULONG ulQop = 0; + + BuffDesc.cBuffers = 2; + BuffDesc.pBuffers = SecBuff; + BuffDesc.ulVersion = SECBUFFER_VERSION; + + SecBuff[0].BufferType = SECBUFFER_STREAM; + SecBuff[0].cbBuffer = (ULONG)input_message_buffer->length; + output_message_buffer->value = SecBuff[0].pvBuffer = malloc(input_message_buffer->length); + memcpy(SecBuff[0].pvBuffer, input_message_buffer->value, input_message_buffer->length); + + SecBuff[1].BufferType = SECBUFFER_DATA; + SecBuff[1].cbBuffer = 0; + SecBuff[1].pvBuffer = NULL; + + ss = DecryptMessage(&pc->hCtxt, &BuffDesc, 0, &ulQop); + if (!SEC_SUCCESS(ss)) { + free(SecBuff[0].pvBuffer); + return GSS_S_FAILURE; + } + output_message_buffer->length = SecBuff[1].cbBuffer; + output_message_buffer->value = SecBuff[1].pvBuffer; + *conf_state = ulQop == SECQOP_WRAP_NO_ENCRYPT ? 0 : 1; + return GSS_S_COMPLETE; +} + +__declspec(dllexport) OM_uint32 gss_indicate_mechs + (OM_uint32 *minor_status, + gss_OID_set *mech_set) { + gss_OID_set_desc *copy; + OM_uint32 minor = 0; + OM_uint32 major = GSS_S_COMPLETE; + int n = 0; + int i = 0; + BOOLEAN hasSpnego = false, hasKerberos = false; + + ULONG ccPackages; + PSecPkgInfo packages; + EnumerateSecurityPackages(&ccPackages, &packages); + PP1("EnumerateSecurityPackages returns %ld\n", ccPackages); + // TODO: only return Kerberos, so no need to check input later + PSecPkgInfo pkgInfo; + SECURITY_STATUS ss = QuerySecurityPackageInfo(L"Negotiate", &pkgInfo); + if (ss == SEC_E_OK) { + // n++; + // hasSpnego = true; + } + ss = QuerySecurityPackageInfo(L"Kerberos", &pkgInfo); + if (ss == SEC_E_OK) { + n++; + hasKerberos = true; + } + + if ((copy = new gss_OID_set_desc[1]) == NULL) { + major = GSS_S_FAILURE; + goto done; + } + + if ((copy->elements = new gss_OID_desc[n]) == NULL) { + major = GSS_S_FAILURE; + goto done; + } + + if (hasKerberos) { + gss_OID_desc *out = ©->elements[i]; + if ((out->elements = new char[sizeof(KRB5_OID)]) == NULL) { + major = GSS_S_FAILURE; + goto done; + } + (void) memcpy(out->elements, KRB5_OID, sizeof(KRB5_OID)); + out->length = sizeof(KRB5_OID); + i++; + } + if (hasSpnego) { + gss_OID_desc *out = ©->elements[i]; + char in[6] = { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x02 }; + if ((out->elements = new char[sizeof(in)]) == NULL) { + major = GSS_S_FAILURE; + goto done; + } + (void) memcpy(out->elements, in, sizeof(in)); + out->length = sizeof(in); + i++; + } + copy->count = i; + + *mech_set = copy; +done: + if (major != GSS_S_COMPLETE) { + // (void) generic_gss_release_oid_set(&minor, ©); + } + + return (major); +} + +__declspec(dllexport) OM_uint32 gss_inquire_names_for_mech + (OM_uint32 *minor_status, + const gss_OID mechanism, + gss_OID_set *name_types) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_add_oid_set_member + (OM_uint32 *minor_status, + gss_OID member_oid, + gss_OID_set *oid_set) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_display_status + (OM_uint32 *minor_status, + OM_uint32 status_value, + int status_type, + gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_create_empty_oid_set + (OM_uint32 *minor_status, + gss_OID_set *oid_set) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_release_oid_set + (OM_uint32 *minor_status, + gss_OID_set *set) { + return GSS_S_FAILURE; +} + +__declspec(dllexport) OM_uint32 gss_release_buffer + (OM_uint32 *minor_status, + gss_buffer_t buffer) { + return GSS_S_FAILURE; +} + +#ifdef __cplusplus +} +#endif