From 1e2b0be24a1d8aade837003521f8a807e2fd900d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Thu, 23 Feb 2012 15:56:50 -0500 Subject: [PATCH 01/10] libfreerdp-auth: split NTLM package, implement AcquireCredentialsHandle --- cunit/test_sspi.c | 47 +++++++--- cunit/test_sspi.h | 1 + include/freerdp/auth/sspi.h | 148 +++++++++++++++++++++++++++++++ libfreerdp-auth/CMakeLists.txt | 3 + libfreerdp-auth/NTLM/ntlm.c | 157 +++++++++++++++++++++++++++++++++ libfreerdp-auth/NTLM/ntlm.h | 32 +++++++ libfreerdp-auth/ntlmssp.c | 59 +------------ libfreerdp-auth/sspi.c | 137 +++++++++++++++++++++++++++- libfreerdp-auth/sspi.h | 43 +++++++++ 9 files changed, 556 insertions(+), 71 deletions(-) create mode 100644 libfreerdp-auth/NTLM/ntlm.c create mode 100644 libfreerdp-auth/NTLM/ntlm.h create mode 100644 libfreerdp-auth/sspi.h diff --git a/cunit/test_sspi.c b/cunit/test_sspi.c index 4c151feec..2cd4d234f 100644 --- a/cunit/test_sspi.c +++ b/cunit/test_sspi.c @@ -44,6 +44,7 @@ int add_sspi_suite(void) add_test_function(EnumerateSecurityPackages); add_test_function(QuerySecurityPackageInfo); add_test_function(AcquireCredentialsHandle); + add_test_function(InitializeSecurityContext); return 0; } @@ -95,6 +96,7 @@ void test_AcquireCredentialsHandle(void) SEC_TIMESTAMP expiration; SEC_AUTH_IDENTITY identity; SECURITY_FUNCTION_TABLE* table; + SEC_PKG_CREDENTIALS_NAMES credential_names; table = InitSecurityInterface(); @@ -111,24 +113,45 @@ void test_AcquireCredentialsHandle(void) if (status == SEC_E_OK) { + status = table->QueryCredentialsAttributes(&credentials, SECPKG_CRED_ATTR_NAMES, &credential_names); + if (status == SEC_E_OK) + { + printf("\nQueryCredentialsAttributes: %s\n", credential_names.sUserName); + } } } +void test_InitializeSecurityContext(void) +{ + uint32 fContextReq; + CTXT_HANDLE context; + uint32 pfContextAttr; + SECURITY_STATUS status; + CRED_HANDLE credentials; + SEC_TIMESTAMP expiration; + SEC_AUTH_IDENTITY identity; + SECURITY_FUNCTION_TABLE* table; + SEC_BUFFER_DESC sec_output_buffer; + table = InitSecurityInterface(); + identity.User = (uint16*) xstrdup(test_User); + identity.UserLength = sizeof(test_User); + identity.Domain = (uint16*) xstrdup(test_Domain); + identity.DomainLength = sizeof(test_Domain); + identity.Password = (uint16*) xstrdup(test_Password); + identity.PasswordLength = sizeof(test_Password); + identity.Flags = SEC_AUTH_IDENTITY_ANSI; + status = table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME, + SECPKG_CRED_OUTBOUND, NULL, &identity, NULL, NULL, &credentials, &expiration); + if (status == SEC_E_OK) + { + fContextReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE; - - - - - - - - - - - - + table->InitializeSecurityContext(&credentials, NULL, NULL, fContextReq, 0, 0, NULL, 0, + &context, &sec_output_buffer, &pfContextAttr, &expiration); + } +} diff --git a/cunit/test_sspi.h b/cunit/test_sspi.h index bcec0fa52..81def91dc 100644 --- a/cunit/test_sspi.h +++ b/cunit/test_sspi.h @@ -26,3 +26,4 @@ int add_sspi_suite(void); void test_EnumerateSecurityPackages(void); void test_QuerySecurityPackageInfo(void); void test_AcquireCredentialsHandle(void); +void test_InitializeSecurityContext(void); diff --git a/include/freerdp/auth/sspi.h b/include/freerdp/auth/sspi.h index fa11f4797..48efcddca 100644 --- a/include/freerdp/auth/sspi.h +++ b/include/freerdp/auth/sspi.h @@ -142,6 +142,154 @@ typedef uint32 SECURITY_STATUS; #define SECPKG_CRED_AUTOLOGON_RESTRICTED 0x00000010 #define SECPKG_CRED_PROCESS_POLICY_ONLY 0x00000020 +/* Security Context Attributes */ + +#define SECPKG_ATTR_SIZES 0 +#define SECPKG_ATTR_NAMES 1 +#define SECPKG_ATTR_LIFESPAN 2 +#define SECPKG_ATTR_DCE_INFO 3 +#define SECPKG_ATTR_STREAM_SIZES 4 +#define SECPKG_ATTR_KEY_INFO 5 +#define SECPKG_ATTR_AUTHORITY 6 +#define SECPKG_ATTR_PROTO_INFO 7 +#define SECPKG_ATTR_PASSWORD_EXPIRY 8 +#define SECPKG_ATTR_SESSION_KEY 9 +#define SECPKG_ATTR_PACKAGE_INFO 10 +#define SECPKG_ATTR_USER_FLAGS 11 +#define SECPKG_ATTR_NEGOTIATION_INFO 12 +#define SECPKG_ATTR_NATIVE_NAMES 13 +#define SECPKG_ATTR_FLAGS 14 +#define SECPKG_ATTR_USE_VALIDATED 15 +#define SECPKG_ATTR_CREDENTIAL_NAME 16 +#define SECPKG_ATTR_TARGET_INFORMATION 17 +#define SECPKG_ATTR_ACCESS_TOKEN 18 +#define SECPKG_ATTR_TARGET 19 +#define SECPKG_ATTR_AUTHENTICATION_ID 20 +#define SECPKG_ATTR_LOGOFF_TIME 21 +#define SECPKG_ATTR_NEGO_KEYS 22 +#define SECPKG_ATTR_PROMPTING_NEEDED 24 +#define SECPKG_ATTR_UNIQUE_BINDINGS 25 +#define SECPKG_ATTR_ENDPOINT_BINDINGS 26 +#define SECPKG_ATTR_CLIENT_SPECIFIED_TARGET 27 +#define SECPKG_ATTR_LAST_CLIENT_TOKEN_STATUS 30 +#define SECPKG_ATTR_NEGO_PKG_INFO 31 +#define SECPKG_ATTR_NEGO_STATUS 32 +#define SECPKG_ATTR_CONTEXT_DELETED 33 + +/* Security Credentials Attributes */ + +#define SECPKG_CRED_ATTR_NAMES 1 + +struct _SEC_PKG_CREDENTIALS_NAMES +{ + char* sUserName; +}; +typedef struct _SEC_PKG_CREDENTIALS_NAMES SEC_PKG_CREDENTIALS_NAMES; + +/* InitializeSecurityContext Flags */ + +#define ISC_REQ_DELEGATE 0x00000001 +#define ISC_REQ_MUTUAL_AUTH 0x00000002 +#define ISC_REQ_REPLAY_DETECT 0x00000004 +#define ISC_REQ_SEQUENCE_DETECT 0x00000008 +#define ISC_REQ_CONFIDENTIALITY 0x00000010 +#define ISC_REQ_USE_SESSION_KEY 0x00000020 +#define ISC_REQ_PROMPT_FOR_CREDS 0x00000040 +#define ISC_REQ_USE_SUPPLIED_CREDS 0x00000080 +#define ISC_REQ_ALLOCATE_MEMORY 0x00000100 +#define ISC_REQ_USE_DCE_STYLE 0x00000200 +#define ISC_REQ_DATAGRAM 0x00000400 +#define ISC_REQ_CONNECTION 0x00000800 +#define ISC_REQ_CALL_LEVEL 0x00001000 +#define ISC_REQ_FRAGMENT_SUPPLIED 0x00002000 +#define ISC_REQ_EXTENDED_ERROR 0x00004000 +#define ISC_REQ_STREAM 0x00008000 +#define ISC_REQ_INTEGRITY 0x00010000 +#define ISC_REQ_IDENTIFY 0x00020000 +#define ISC_REQ_NULL_SESSION 0x00040000 +#define ISC_REQ_MANUAL_CRED_VALIDATION 0x00080000 +#define ISC_REQ_RESERVED1 0x00100000 +#define ISC_REQ_FRAGMENT_TO_FIT 0x00200000 +#define ISC_REQ_FORWARD_CREDENTIALS 0x00400000 +#define ISC_REQ_NO_INTEGRITY 0x00800000 +#define ISC_REQ_USE_HTTP_STYLE 0x01000000 + +#define ISC_RET_DELEGATE 0x00000001 +#define ISC_RET_MUTUAL_AUTH 0x00000002 +#define ISC_RET_REPLAY_DETECT 0x00000004 +#define ISC_RET_SEQUENCE_DETECT 0x00000008 +#define ISC_RET_CONFIDENTIALITY 0x00000010 +#define ISC_RET_USE_SESSION_KEY 0x00000020 +#define ISC_RET_USED_COLLECTED_CREDS 0x00000040 +#define ISC_RET_USED_SUPPLIED_CREDS 0x00000080 +#define ISC_RET_ALLOCATED_MEMORY 0x00000100 +#define ISC_RET_USED_DCE_STYLE 0x00000200 +#define ISC_RET_DATAGRAM 0x00000400 +#define ISC_RET_CONNECTION 0x00000800 +#define ISC_RET_INTERMEDIATE_RETURN 0x00001000 +#define ISC_RET_CALL_LEVEL 0x00002000 +#define ISC_RET_EXTENDED_ERROR 0x00004000 +#define ISC_RET_STREAM 0x00008000 +#define ISC_RET_INTEGRITY 0x00010000 +#define ISC_RET_IDENTIFY 0x00020000 +#define ISC_RET_NULL_SESSION 0x00040000 +#define ISC_RET_MANUAL_CRED_VALIDATION 0x00080000 +#define ISC_RET_RESERVED1 0x00100000 +#define ISC_RET_FRAGMENT_ONLY 0x00200000 +#define ISC_RET_FORWARD_CREDENTIALS 0x00400000 +#define ISC_RET_USED_HTTP_STYLE 0x01000000 + +/* AcceptSecurityContext Flags */ + +#define ASC_REQ_DELEGATE 0x00000001 +#define ASC_REQ_MUTUAL_AUTH 0x00000002 +#define ASC_REQ_REPLAY_DETECT 0x00000004 +#define ASC_REQ_SEQUENCE_DETECT 0x00000008 +#define ASC_REQ_CONFIDENTIALITY 0x00000010 +#define ASC_REQ_USE_SESSION_KEY 0x00000020 +#define ASC_REQ_ALLOCATE_MEMORY 0x00000100 +#define ASC_REQ_USE_DCE_STYLE 0x00000200 +#define ASC_REQ_DATAGRAM 0x00000400 +#define ASC_REQ_CONNECTION 0x00000800 +#define ASC_REQ_CALL_LEVEL 0x00001000 +#define ASC_REQ_EXTENDED_ERROR 0x00008000 +#define ASC_REQ_STREAM 0x00010000 +#define ASC_REQ_INTEGRITY 0x00020000 +#define ASC_REQ_LICENSING 0x00040000 +#define ASC_REQ_IDENTIFY 0x00080000 +#define ASC_REQ_ALLOW_NULL_SESSION 0x00100000 +#define ASC_REQ_ALLOW_NON_USER_LOGONS 0x00200000 +#define ASC_REQ_ALLOW_CONTEXT_REPLAY 0x00400000 +#define ASC_REQ_FRAGMENT_TO_FIT 0x00800000 +#define ASC_REQ_FRAGMENT_SUPPLIED 0x00002000 +#define ASC_REQ_NO_TOKEN 0x01000000 +#define ASC_REQ_PROXY_BINDINGS 0x04000000 +#define ASC_REQ_ALLOW_MISSING_BINDINGS 0x10000000 + +#define ASC_RET_DELEGATE 0x00000001 +#define ASC_RET_MUTUAL_AUTH 0x00000002 +#define ASC_RET_REPLAY_DETECT 0x00000004 +#define ASC_RET_SEQUENCE_DETECT 0x00000008 +#define ASC_RET_CONFIDENTIALITY 0x00000010 +#define ASC_RET_USE_SESSION_KEY 0x00000020 +#define ASC_RET_ALLOCATED_MEMORY 0x00000100 +#define ASC_RET_USED_DCE_STYLE 0x00000200 +#define ASC_RET_DATAGRAM 0x00000400 +#define ASC_RET_CONNECTION 0x00000800 +#define ASC_RET_CALL_LEVEL 0x00002000 +#define ASC_RET_THIRD_LEG_FAILED 0x00004000 +#define ASC_RET_EXTENDED_ERROR 0x00008000 +#define ASC_RET_STREAM 0x00010000 +#define ASC_RET_INTEGRITY 0x00020000 +#define ASC_RET_LICENSING 0x00040000 +#define ASC_RET_IDENTIFY 0x00080000 +#define ASC_RET_NULL_SESSION 0x00100000 +#define ASC_RET_ALLOW_NON_USER_LOGONS 0x00200000 +#define ASC_RET_FRAGMENT_ONLY 0x00800000 +#define ASC_RET_NO_TOKEN 0x01000000 +#define ASC_RET_NO_PROXY_BINDINGS 0x04000000 +#define ASC_RET_MISSING_BINDINGS 0x10000000 + struct _SEC_PKG_INFO { uint32 fCapabilities; diff --git a/libfreerdp-auth/CMakeLists.txt b/libfreerdp-auth/CMakeLists.txt index d89a08e9a..a230e2a53 100644 --- a/libfreerdp-auth/CMakeLists.txt +++ b/libfreerdp-auth/CMakeLists.txt @@ -18,7 +18,10 @@ # limitations under the License. set(FREERDP_AUTH_SRCS + NTLM/ntlm.c + NTLM/ntlm.h sspi.c + sspi.h credssp.c ntlmssp.c) diff --git a/libfreerdp-auth/NTLM/ntlm.c b/libfreerdp-auth/NTLM/ntlm.c new file mode 100644 index 000000000..e914cc66c --- /dev/null +++ b/libfreerdp-auth/NTLM/ntlm.c @@ -0,0 +1,157 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * NTLM Security Package + * + * Copyright 2011-2012 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ntlm.h" +#include "../sspi.h" + +char* NTLM_PACKAGE_NAME = "NTLM"; + +NTLM_CONTEXT* ntlm_ContextNew() +{ + NTLM_CONTEXT* context; + + context = xnew(NTLM_CONTEXT); + + if (context != NULL) + { + + } + + return context; +} + +void ntlm_ContextFree(NTLM_CONTEXT* context) +{ + if (!context) + return; + + xfree(context); +} + +SECURITY_STATUS ntlm_AcquireCredentialsHandle(char* pszPrincipal, char* pszPackage, + uint32 fCredentialUse, void* pvLogonID, void* pAuthData, void* pGetKeyFn, + void* pvGetKeyArgument, CRED_HANDLE* phCredential, SEC_TIMESTAMP* ptsExpiry) +{ + CREDENTIALS* credentials; + SEC_AUTH_IDENTITY* identity; + + if (fCredentialUse == SECPKG_CRED_OUTBOUND) + { + credentials = sspi_CredentialsNew(); + identity = (SEC_AUTH_IDENTITY*) pAuthData; + + memcpy(&(credentials->identity), identity, sizeof(SEC_AUTH_IDENTITY)); + + sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials); + sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME); + + return SEC_E_OK; + } + + return SEC_E_OK; +} + +SECURITY_STATUS ntlm_QueryCredentialsAttributes(CRED_HANDLE* phCredential, uint32 ulAttribute, void* pBuffer) +{ + if (ulAttribute == SECPKG_CRED_ATTR_NAMES) + { + CREDENTIALS* credentials; + SEC_PKG_CREDENTIALS_NAMES* credential_names = (SEC_PKG_CREDENTIALS_NAMES*) pBuffer; + + credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); + + if (credentials->identity.Flags == SEC_AUTH_IDENTITY_ANSI) + credential_names->sUserName = xstrdup((char*) credentials->identity.User); + + return SEC_E_OK; + } + + return SEC_E_UNSUPPORTED_FUNCTION; +} + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375512/ */ + +SECURITY_STATUS ntlm_InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_HANDLE* phContext, + char* pszTargetName, uint32 fContextReq, uint32 Reserved1, uint32 TargetDataRep, + SEC_BUFFER_DESC* pInput, uint32 Reserved2, CTXT_HANDLE* phNewContext, + SEC_BUFFER_DESC* pOutput, uint32* pfContextAttr, SEC_TIMESTAMP* ptsExpiry) +{ + return SEC_E_OK; +} + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa379337/ */ + +SECURITY_STATUS ntlm_QueryContextAttributes(CTXT_HANDLE* phContext, uint32 ulAttribute, void* pBuffer) +{ + return SEC_E_OK; +} + +const SEC_PKG_INFO NTLM_SEC_PKG_INFO = +{ + 0x00082B37, /* fCapabilities */ + 1, /* wVersion */ + 0x000A, /* wRPCID */ + 0x00000B48, /* cbMaxToken */ + "NTLM", /* Name */ + "NTLM Security Package" /* Comment */ +}; + +const SECURITY_FUNCTION_TABLE NTLM_SECURITY_FUNCTION_TABLE = +{ + 1, /* dwVersion */ + NULL, /* EnumerateSecurityPackages */ + NULL, /* Reserved1 */ + ntlm_QueryCredentialsAttributes, /* QueryCredentialsAttributes */ + ntlm_AcquireCredentialsHandle, /* AcquireCredentialsHandle */ + NULL, /* FreeCredentialsHandle */ + NULL, /* Reserved2 */ + ntlm_InitializeSecurityContext, /* InitializeSecurityContext */ + NULL, /* AcceptSecurityContext */ + NULL, /* CompleteAuthToken */ + NULL, /* DeleteSecurityContext */ + NULL, /* ApplyControlToken */ + ntlm_QueryContextAttributes, /* QueryContextAttributes */ + NULL, /* ImpersonateSecurityContext */ + NULL, /* RevertSecurityContext */ + NULL, /* MakeSignature */ + NULL, /* VerifySignature */ + NULL, /* FreeContextBuffer */ + NULL, /* QuerySecurityPackageInfo */ + NULL, /* Reserved3 */ + NULL, /* Reserved4 */ + NULL, /* ExportSecurityContext */ + NULL, /* ImportSecurityContext */ + NULL, /* AddCredentials */ + NULL, /* Reserved8 */ + NULL, /* QuerySecurityContextToken */ + NULL, /* EncryptMessage */ + NULL, /* DecryptMessage */ + NULL, /* SetContextAttributes */ +}; diff --git a/libfreerdp-auth/NTLM/ntlm.h b/libfreerdp-auth/NTLM/ntlm.h new file mode 100644 index 000000000..21d46d3b8 --- /dev/null +++ b/libfreerdp-auth/NTLM/ntlm.h @@ -0,0 +1,32 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * NTLM Security Package + * + * Copyright 2011-2012 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#ifndef FREERDP_AUTH_NTLM_PRIVATE_H +#define FREERDP_AUTH_NTLM_PRIVATE_H + +struct _NTLM_CONTEXT +{ + SEC_AUTH_IDENTITY identity; +}; +typedef struct _NTLM_CONTEXT NTLM_CONTEXT; + +#endif /* FREERDP_AUTH_NTLM_PRIVATE_H */ diff --git a/libfreerdp-auth/ntlmssp.c b/libfreerdp-auth/ntlmssp.c index 8e89e599d..a1383374b 100644 --- a/libfreerdp-auth/ntlmssp.c +++ b/libfreerdp-auth/ntlmssp.c @@ -28,6 +28,8 @@ #include #include +#include "sspi.h" + #include #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W (0) */ @@ -2224,60 +2226,3 @@ void ntlmssp_free(NTLMSSP* ntlmssp) crypto_rc4_free(ntlmssp->recv_rc4_seal); xfree(ntlmssp); } - -/* SSPI */ - -SECURITY_STATUS ntlm_AcquireCredentialsHandle(char* pszPrincipal, char* pszPackage, - uint32 fCredentialUse, void* pvLogonID, void* pAuthData, void* pGetKeyFn, - void* pvGetKeyArgument, CRED_HANDLE* phCredential, SEC_TIMESTAMP* ptsExpiry) -{ - if (fCredentialUse == SECPKG_CRED_OUTBOUND) - { - - } - - return SEC_E_OK; -} - -const SEC_PKG_INFO NTLM_SEC_PKG_INFO = -{ - 0x00082B37, /* fCapabilities */ - 1, /* wVersion */ - 0x000A, /* wRPCID */ - 0x00000B48, /* cbMaxToken */ - "NTLM", /* Name */ - "NTLM Security Package" /* Comment */ -}; - -const SECURITY_FUNCTION_TABLE NTLM_SECURITY_FUNCTION_TABLE = -{ - 1, /* dwVersion */ - NULL, /* EnumerateSecurityPackages */ - NULL, /* Reserved1 */ - NULL, /* QueryCredentialsAttributes */ - ntlm_AcquireCredentialsHandle, /* AcquireCredentialsHandle */ - NULL, /* FreeCredentialsHandle */ - NULL, /* Reserved2 */ - NULL, /* InitializeSecurityContext */ - NULL, /* AcceptSecurityContext */ - NULL, /* CompleteAuthToken */ - NULL, /* DeleteSecurityContext */ - NULL, /* ApplyControlToken */ - NULL, /* QueryContextAttributes */ - NULL, /* ImpersonateSecurityContext */ - NULL, /* RevertSecurityContext */ - NULL, /* MakeSignature */ - NULL, /* VerifySignature */ - NULL, /* FreeContextBuffer */ - NULL, /* QuerySecurityPackageInfo */ - NULL, /* Reserved3 */ - NULL, /* Reserved4 */ - NULL, /* ExportSecurityContext */ - NULL, /* ImportSecurityContext */ - NULL, /* AddCredentials */ - NULL, /* Reserved8 */ - NULL, /* QuerySecurityContextToken */ - NULL, /* EncryptMessage */ - NULL, /* DecryptMessage */ - NULL, /* SetContextAttributes */ -}; diff --git a/libfreerdp-auth/sspi.c b/libfreerdp-auth/sspi.c index ef02e58bb..625532b34 100644 --- a/libfreerdp-auth/sspi.c +++ b/libfreerdp-auth/sspi.c @@ -21,6 +21,8 @@ #include +#include "sspi.h" + /* Authentication Functions: http://msdn.microsoft.com/en-us/library/windows/desktop/aa374731/ */ extern const SEC_PKG_INFO NTLM_SEC_PKG_INFO; @@ -52,6 +54,91 @@ const SECURITY_FUNCTION_TABLE_NAME SECURITY_FUNCTION_TABLE_NAME_LIST[] = #define SEC_HANDLE_LOWER_MAX 0xFFFFFFFF #define SEC_HANDLE_UPPER_MAX 0xFFFFFFFE +CREDENTIALS* sspi_CredentialsNew() +{ + CREDENTIALS* credentials; + + credentials = xnew(CREDENTIALS); + + if (credentials != NULL) + { + + } + + return credentials; +} + +void sspi_CredentialsFree(CREDENTIALS* credentials) +{ + if (!credentials) + return; + + xfree(credentials); +} + +SEC_HANDLE* sspi_SecureHandleAlloc() +{ + SEC_HANDLE* handle = xmalloc(sizeof(SEC_HANDLE)); + memset(handle, 0xFF, sizeof(SEC_HANDLE)); + return handle; +} + +void sspi_SecureHandleInvalidate(SEC_HANDLE* handle) +{ + if (!handle) + return; + + memset(handle, 0xFF, sizeof(SEC_HANDLE)); +} + +void* sspi_SecureHandleGetLowerPointer(SEC_HANDLE* handle) +{ + void* pointer; + + if (!handle) + return NULL; + + pointer = (void*) ~((size_t) handle->dwLower); + + return pointer; +} + +void sspi_SecureHandleSetLowerPointer(SEC_HANDLE* handle, void* pointer) +{ + if (!handle) + return; + + handle->dwLower = (uint32*) (~((size_t) pointer)); +} + +void* sspi_SecureHandleGetUpperPointer(SEC_HANDLE* handle) +{ + void* pointer; + + if (!handle) + return NULL; + + pointer = (void*) ~((size_t) handle->dwUpper); + + return pointer; +} + +void sspi_SecureHandleSetUpperPointer(SEC_HANDLE* handle, void* pointer) +{ + if (!handle) + return; + + handle->dwUpper = (uint32*) (~((size_t) pointer)); +} + +void sspi_SecureHandleFree(SEC_HANDLE* handle) +{ + if (!handle) + return; + + xfree(handle); +} + SECURITY_FUNCTION_TABLE* sspi_GetSecurityFunctionTableByName(const char* Name) { int index; @@ -228,6 +315,18 @@ SECURITY_STATUS ExportSecurityContext(CTXT_HANDLE* phContext, uint32 fFlags, SEC SECURITY_STATUS FreeCredentialsHandle(CRED_HANDLE* phCredential) { + CREDENTIALS* credentials; + + if (!phCredential) + return SEC_E_INVALID_HANDLE; + + credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); + + if (!credentials) + return SEC_E_INVALID_HANDLE; + + sspi_CredentialsFree(credentials); + return SEC_E_OK; } @@ -238,7 +337,23 @@ SECURITY_STATUS ImportSecurityContext(char* pszPackage, SEC_BUFFER* pPackedConte SECURITY_STATUS QueryCredentialsAttributes(CRED_HANDLE* phCredential, uint32 ulAttribute, void* pBuffer) { - return SEC_E_OK; + char* Name; + SECURITY_STATUS status; + SECURITY_FUNCTION_TABLE* table; + + Name = (char*) sspi_SecureHandleGetUpperPointer(phCredential); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableByName(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + status = table->QueryCredentialsAttributes(phCredential, ulAttribute, pBuffer); + + return status; } /* Context Management */ @@ -283,7 +398,25 @@ SECURITY_STATUS InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_HANDLE SEC_BUFFER_DESC* pInput, uint32 Reserved2, CTXT_HANDLE* phNewContext, SEC_BUFFER_DESC* pOutput, uint32* pfContextAttr, SEC_TIMESTAMP* ptsExpiry) { - return SEC_E_OK; + char* Name; + SECURITY_STATUS status; + SECURITY_FUNCTION_TABLE* table; + + Name = (char*) sspi_SecureHandleGetUpperPointer(phCredential); + + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; + + table = sspi_GetSecurityFunctionTableByName(Name); + + if (!table) + return SEC_E_SECPKG_NOT_FOUND; + + status = table->InitializeSecurityContext(phCredential, phContext, + pszTargetName, fContextReq, Reserved1, TargetDataRep, + pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry); + + return status; } SECURITY_STATUS QueryContextAttributes(CTXT_HANDLE* phContext, uint32 ulAttribute, void* pBuffer) diff --git a/libfreerdp-auth/sspi.h b/libfreerdp-auth/sspi.h new file mode 100644 index 000000000..6ea46c55e --- /dev/null +++ b/libfreerdp-auth/sspi.h @@ -0,0 +1,43 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Security Support Provider Interface (SSPI) + * + * Copyright 2012 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_AUTH_SSPI_PRIVATE_H +#define FREERDP_AUTH_SSPI_PRIVATE_H + +#include +#include + +struct _CREDENTIALS +{ + SEC_AUTH_IDENTITY identity; +}; +typedef struct _CREDENTIALS CREDENTIALS; + +CREDENTIALS* sspi_CredentialsNew(); +void sspi_CredentialsFree(CREDENTIALS* credentials); + +SEC_HANDLE* sspi_SecureHandleAlloc(); +void sspi_SecureHandleInvalidate(SEC_HANDLE* handle); +void* sspi_SecureHandleGetLowerPointer(SEC_HANDLE* handle); +void sspi_SecureHandleSetLowerPointer(SEC_HANDLE* handle, void* pointer); +void* sspi_SecureHandleGetUpperPointer(SEC_HANDLE* handle); +void sspi_SecureHandleSetUpperPointer(SEC_HANDLE* handle, void* pointer); +void sspi_SecureHandleFree(SEC_HANDLE* handle); + +#endif /* FREERDP_AUTH_SSPI_PRIVATE_H */ From c036f1172b7979bc9aab70fc55e3604c850287e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Thu, 23 Feb 2012 18:42:54 -0500 Subject: [PATCH 02/10] libfreerdp-locale: fix XKB keymap loading --- libfreerdp-locale/keyboard.c | 2 + libfreerdp-locale/keyboard_xkb.c | 533 ++++++++++++++++--------------- 2 files changed, 275 insertions(+), 260 deletions(-) diff --git a/libfreerdp-locale/keyboard.c b/libfreerdp-locale/keyboard.c index 7e4231b12..e922c0fc5 100644 --- a/libfreerdp-locale/keyboard.c +++ b/libfreerdp-locale/keyboard.c @@ -282,7 +282,9 @@ uint32 freerdp_keyboard_get_rdp_scancode_from_x11_keycode(uint32 keycode, boolea DEBUG_KBD("x11 keycode: %02X -> rdp code: %02X%s", keycode, X11_KEYCODE_TO_RDP_SCANCODE[keycode].code, X11_KEYCODE_TO_RDP_SCANCODE[keycode].extended ? " extended" : ""); + *extended = X11_KEYCODE_TO_RDP_SCANCODE[keycode].extended; + return X11_KEYCODE_TO_RDP_SCANCODE[keycode].code; } diff --git a/libfreerdp-locale/keyboard_xkb.c b/libfreerdp-locale/keyboard_xkb.c index 3ddb7cb01..5b8440e5d 100644 --- a/libfreerdp-locale/keyboard_xkb.c +++ b/libfreerdp-locale/keyboard_xkb.c @@ -25,6 +25,7 @@ extern uint32 RDP_SCANCODE_TO_X11_KEYCODE[256][2]; extern RDP_SCANCODE X11_KEYCODE_TO_RDP_SCANCODE[256]; +extern const VIRTUAL_KEY_CODE VIRTUAL_KEY_CODE_TABLE[256]; extern const uint32 VIRTUAL_KEY_CODE_TO_RDP_SCANCODE_TABLE[256]; #include @@ -34,269 +35,268 @@ extern const uint32 VIRTUAL_KEY_CODE_TO_RDP_SCANCODE_TABLE[256]; #include -VIRTUAL_KEY_CODE_TO_XKB_KEY_NAME VIRTUAL_KEY_CODE_TO_XKB_KEY_NAME_TABLE[] = +VIRTUAL_KEY_CODE_TO_XKB_KEY_NAME VIRTUAL_KEY_CODE_TO_XKB_KEY_NAME_TABLE[256] = { - { 0, "", "" }, - { 0, "", "" }, /* VK_LBUTTON */ - { 0, "", "" }, /* VK_RBUTTON */ - { 0, "", "" }, /* VK_CANCEL */ - { 0, "", "" }, /* VK_MBUTTON */ - { 0, "", "" }, /* VK_XBUTTON1 */ - { 0, "", "" }, /* VK_XBUTTON2 */ - { 0, "", "" }, - { VK_BACK, "BKSP" }, /* VK_BACK */ - { VK_TAB, "TAB" }, /* VK_TAB */ - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, /* VK_CLEAR */ - { VK_RETURN, "RTRN", "KPEN" }, /* VK_RETURN */ - { 0, "", "" }, - { 0, "", "" }, - { VK_SHIFT, "LFSH" }, /* VK_SHIFT */ - { VK_CONTROL, "" }, /* VK_CONTROL */ - { VK_MENU, "LALT" }, /* VK_MENU */ - { 0, "", "PAUS" }, /* VK_PAUSE */ - { VK_CAPITAL, "CAPS" }, /* VK_CAPITAL */ - { 0, "", "" }, /* VK_KANA / VK_HANGUL */ - { 0, "", "" }, - { 0, "", "" }, /* VK_JUNJA */ - { 0, "", "" }, /* VK_FINAL */ - { 0, "", "" }, /* VK_HANJA / VK_KANJI */ - { 0, "", "" }, - { VK_ESCAPE, "ESC" }, /* VK_ESCAPE */ - { 0, "", "" }, /* VK_CONVERT */ - { 0, "", "" }, /* VK_NONCONVERT */ - { 0, "", "" }, /* VK_ACCEPT */ - { 0, "", "" }, /* VK_MODECHANGE */ - { VK_SPACE, "SPCE" }, /* VK_SPACE */ - { 0, "", "PGUP" }, /* VK_PRIOR */ - { 0, "", "PGDN" }, /* VK_NEXT */ - { 0, "", "END" }, /* VK_END */ - { 0, "", "HOME" }, /* VK_HOME */ - { 0, "", "LEFT" }, /* VK_LEFT */ - { 0, "", "UP" }, /* VK_UP */ - { 0, "", "RGHT" }, /* VK_RIGHT */ - { 0, "", "DOWN" }, /* VK_DOWN */ - { 0, "", "" }, /* VK_SELECT */ - { 0, "", "PRSC" }, /* VK_PRINT */ - { 0, "", "" }, /* VK_EXECUTE */ - { 0, "", "" }, /* VK_SNAPSHOT */ - { 0, "", "INS" }, /* VK_INSERT */ - { 0, "", "DELE" }, /* VK_DELETE */ - { 0, "", "" }, /* VK_HELP */ - { VK_KEY_0, "AE10" }, /* VK_KEY_0 */ - { VK_KEY_1, "AE01" }, /* VK_KEY_1 */ - { VK_KEY_2, "AE02" }, /* VK_KEY_2 */ - { VK_KEY_3, "AE03" }, /* VK_KEY_3 */ - { VK_KEY_4, "AE04" }, /* VK_KEY_4 */ - { VK_KEY_5, "AE05" }, /* VK_KEY_5 */ - { VK_KEY_6, "AE06" }, /* VK_KEY_6 */ - { VK_KEY_7, "AE07" }, /* VK_KEY_7 */ - { VK_KEY_8, "AE08" }, /* VK_KEY_8 */ - { VK_KEY_9, "AE09" }, /* VK_KEY_9 */ - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { VK_KEY_A, "AC01" }, /* VK_KEY_A */ - { VK_KEY_B, "AB05" }, /* VK_KEY_B */ - { VK_KEY_C, "AB03" }, /* VK_KEY_C */ - { VK_KEY_D, "AC03" }, /* VK_KEY_D */ - { VK_KEY_E, "AD03" }, /* VK_KEY_E */ - { VK_KEY_F, "AC04" }, /* VK_KEY_F */ - { VK_KEY_G, "AC05" }, /* VK_KEY_G */ - { VK_KEY_H, "AC06" }, /* VK_KEY_H */ - { VK_KEY_I, "AD08" }, /* VK_KEY_I */ - { VK_KEY_J, "AC07" }, /* VK_KEY_J */ - { VK_KEY_K, "AC08" }, /* VK_KEY_K */ - { VK_KEY_L, "AC09" }, /* VK_KEY_L */ - { VK_KEY_M, "AB07" }, /* VK_KEY_M */ - { VK_KEY_N, "AB06" }, /* VK_KEY_N */ - { VK_KEY_O, "AD09" }, /* VK_KEY_O */ - { VK_KEY_P, "AD10" }, /* VK_KEY_P */ - { VK_KEY_Q, "AD01" }, /* VK_KEY_Q */ - { VK_KEY_R, "AD04" }, /* VK_KEY_R */ - { VK_KEY_S, "AC02" }, /* VK_KEY_S */ - { VK_KEY_T, "AD05" }, /* VK_KEY_T */ - { VK_KEY_U, "AD07" }, /* VK_KEY_U */ - { VK_KEY_V, "AB04" }, /* VK_KEY_V */ - { VK_KEY_W, "AD02" }, /* VK_KEY_W */ - { VK_KEY_X, "AB02" }, /* VK_KEY_X */ - { VK_KEY_Y, "AD06" }, /* VK_KEY_Y */ - { VK_KEY_Z, "AB01" }, /* VK_KEY_Z */ - { 0, "", "LWIN" }, /* VK_LWIN */ - { 0, "", "RWIN" }, /* VK_RWIN */ - { 0, "", "COMP" }, /* VK_APPS */ - { 0, "", "" }, - { 0, "", "" }, /* VK_SLEEP */ - { VK_NUMPAD0, "KP0" }, /* VK_NUMPAD0 */ - { VK_NUMPAD1, "KP1" }, /* VK_NUMPAD1 */ - { VK_NUMPAD2, "KP2" }, /* VK_NUMPAD2 */ - { VK_NUMPAD3, "KP3" }, /* VK_NUMPAD3 */ - { VK_NUMPAD4, "KP4" }, /* VK_NUMPAD4 */ - { VK_NUMPAD5, "KP5" }, /* VK_NUMPAD5 */ - { VK_NUMPAD6, "KP6" }, /* VK_NUMPAD6 */ - { VK_NUMPAD7, "KP7" }, /* VK_NUMPAD7 */ - { VK_NUMPAD8, "KP8" }, /* VK_NUMPAD8 */ - { VK_NUMPAD9, "KP9" }, /* VK_NUMPAD9 */ - { VK_MULTIPLY, "KPMU" }, /* VK_MULTIPLY */ - { VK_ADD, "KPAD" }, /* VK_ADD */ - { 0, "", "" }, /* VK_SEPARATOR */ - { VK_SUBTRACT, "KPSU" }, /* VK_SUBTRACT */ - { VK_DECIMAL, "KPDL" }, /* VK_DECIMAL */ - { VK_DIVIDE, "AB10", "KPDV" }, /* VK_DIVIDE */ - { VK_F1, "FK01" }, /* VK_F1 */ - { VK_F2, "FK02" }, /* VK_F2 */ - { VK_F3, "FK03" }, /* VK_F3 */ - { VK_F4, "FK04" }, /* VK_F4 */ - { VK_F5, "FK05" }, /* VK_F5 */ - { VK_F6, "FK06" }, /* VK_F6 */ - { VK_F7, "FK07" }, /* VK_F7 */ - { VK_F8, "FK08" }, /* VK_F8 */ - { VK_F9, "FK09" }, /* VK_F9 */ - { VK_F10, "FK10" }, /* VK_F10 */ - { VK_F11, "FK11" }, /* VK_F11 */ - { VK_F12, "FK12" }, /* VK_F12 */ - { 0, "", "" }, /* VK_F13 */ - { 0, "", "" }, /* VK_F14 */ - { 0, "", "" }, /* VK_F15 */ - { 0, "", "" }, /* VK_F16 */ - { 0, "", "" }, /* VK_F17 */ - { 0, "", "" }, /* VK_F18 */ - { 0, "", "" }, /* VK_F19 */ - { 0, "", "" }, /* VK_F20 */ - { 0, "", "" }, /* VK_F21 */ - { 0, "", "" }, /* VK_F22 */ - { 0, "", "" }, /* VK_F23 */ - { 0, "", "" }, /* VK_F24 */ - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { VK_NUMLOCK, "NMLK" }, /* VK_NUMLOCK */ - { VK_SCROLL, "SCLK" }, /* VK_SCROLL */ - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { VK_LSHIFT, "" }, /* VK_LSHIFT */ - { VK_RSHIFT, "RTSH" }, /* VK_RSHIFT */ - { VK_LCONTROL, "LCTL" }, /* VK_LCONTROL */ - { 0, "", "RCTL" }, /* VK_RCONTROL */ - { VK_LMENU, "" }, /* VK_LMENU */ - { 0, "", "RALT" }, /* VK_RMENU */ - { 0, "", "" }, /* VK_BROWSER_BACK */ - { 0, "", "" }, /* VK_BROWSER_FORWARD */ - { 0, "", "" }, /* VK_BROWSER_REFRESH */ - { 0, "", "" }, /* VK_BROWSER_STOP */ - { 0, "", "" }, /* VK_BROWSER_SEARCH */ - { 0, "", "" }, /* VK_BROWSER_FAVORITES */ - { 0, "", "" }, /* VK_BROWSER_HOME */ - { 0, "", "" }, /* VK_VOLUME_MUTE */ - { 0, "", "" }, /* VK_VOLUME_DOWN */ - { 0, "", "" }, /* VK_VOLUME_UP */ - { 0, "", "" }, /* VK_MEDIA_NEXT_TRACK */ - { 0, "", "" }, /* VK_MEDIA_PREV_TRACK */ - { 0, "", "" }, /* VK_MEDIA_STOP */ - { 0, "", "" }, /* VK_MEDIA_PLAY_PAUSE */ - { 0, "", "" }, /* VK_LAUNCH_MAIL */ - { 0, "", "" }, /* VK_MEDIA_SELECT */ - { 0, "", "" }, /* VK_LAUNCH_APP1 */ - { 0, "", "" }, /* VK_LAUNCH_APP2 */ - { 0, "", "" }, - { 0, "", "" }, - { VK_OEM_1, "AC10" }, /* VK_OEM_1 */ - { VK_OEM_PLUS, "AE12" }, /* VK_OEM_PLUS */ - { VK_OEM_COMMA, "AB08" }, /* VK_OEM_COMMA */ - { VK_OEM_MINUS, "AE11" }, /* VK_OEM_MINUS */ - { VK_OEM_PERIOD, "AB09" }, /* VK_OEM_PERIOD */ - { VK_OEM_2, "AB10" }, /* VK_OEM_2 */ - { VK_OEM_3, "TLDE" }, /* VK_OEM_3 */ - { VK_ABNT_C1, "AB11" }, /* VK_ABNT_C1 */ - { VK_ABNT_C2, "I129" }, /* VK_ABNT_C2 */ - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { VK_OEM_4, "AD11" }, /* VK_OEM_4 */ - { VK_OEM_5, "BKSL" }, /* VK_OEM_5 */ - { VK_OEM_6, "AD12" }, /* VK_OEM_6 */ - { VK_OEM_7, "AC11" }, /* VK_OEM_7 */ - { 0, "", "" }, /* VK_OEM_8 */ - { 0, "", "" }, - { 0, "", "" }, - { VK_OEM_102, "LSGT" }, /* VK_OEM_102 */ - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, /* VK_PROCESSKEY */ - { 0, "", "" }, - { 0, "", "" }, /* VK_PACKET */ - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, - { 0, "", "" }, /* VK_ATTN */ - { 0, "", "" }, /* VK_CRSEL */ - { 0, "", "" }, /* VK_EXSEL */ - { 0, "", "" }, /* VK_EREOF */ - { 0, "", "" }, /* VK_PLAY */ - { 0, "", "" }, /* VK_ZOOM */ - { 0, "", "" }, /* VK_NONAME */ - { 0, "", "" }, /* VK_PA1 */ - { 0, "", "" }, /* VK_OEM_CLEAR */ - { 0, "" } + { 0, "", "" }, + { VK_LBUTTON, "", "" }, /* VK_LBUTTON */ + { VK_RBUTTON, "", "" }, /* VK_RBUTTON */ + { VK_CANCEL, "", "" }, /* VK_CANCEL */ + { VK_MBUTTON, "", "" }, /* VK_MBUTTON */ + { VK_XBUTTON1, "", "" }, /* VK_XBUTTON1 */ + { VK_XBUTTON2, "", "" }, /* VK_XBUTTON2 */ + { 0, "", "" }, + { VK_BACK, "BKSP", "" }, /* VK_BACK */ + { VK_TAB, "TAB", "" }, /* VK_TAB */ + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, /* VK_CLEAR */ + { VK_RETURN, "RTRN", "KPEN" }, /* VK_RETURN */ + { 0, "", "" }, + { 0, "", "" }, + { VK_SHIFT, "LFSH", "" }, /* VK_SHIFT */ + { VK_CONTROL, "", "" }, /* VK_CONTROL */ + { VK_MENU, "LALT", "" }, /* VK_MENU */ + { VK_PAUSE, "", "PAUS" }, /* VK_PAUSE */ + { VK_CAPITAL, "CAPS", "" }, /* VK_CAPITAL */ + { VK_KANA, "", "" }, /* VK_KANA / VK_HANGUL */ + { 0, "", "" }, + { VK_JUNJA, "", "" }, /* VK_JUNJA */ + { VK_FINAL, "", "" }, /* VK_FINAL */ + { VK_KANJI, "", "" }, /* VK_HANJA / VK_KANJI */ + { 0, "", "" }, + { VK_ESCAPE, "ESC", "" }, /* VK_ESCAPE */ + { VK_CONVERT, "", "" }, /* VK_CONVERT */ + { VK_NONCONVERT, "", "" }, /* VK_NONCONVERT */ + { VK_ACCEPT, "", "" }, /* VK_ACCEPT */ + { VK_MODECHANGE, "", "" }, /* VK_MODECHANGE */ + { VK_SPACE, "SPCE", "" }, /* VK_SPACE */ + { VK_PRIOR, "", "PGUP" }, /* VK_PRIOR */ + { VK_NEXT, "", "PGDN" }, /* VK_NEXT */ + { VK_END, "", "END" }, /* VK_END */ + { VK_HOME, "", "HOME" }, /* VK_HOME */ + { VK_LEFT, "", "LEFT" }, /* VK_LEFT */ + { VK_UP, "", "UP" }, /* VK_UP */ + { VK_RIGHT, "", "RGHT" }, /* VK_RIGHT */ + { VK_DOWN, "", "DOWN" }, /* VK_DOWN */ + { VK_SELECT, "", "" }, /* VK_SELECT */ + { VK_PRINT, "", "PRSC" }, /* VK_PRINT */ + { VK_EXECUTE, "", "" }, /* VK_EXECUTE */ + { VK_SNAPSHOT, "", "" }, /* VK_SNAPSHOT */ + { VK_INSERT, "", "INS" }, /* VK_INSERT */ + { VK_DELETE, "", "DELE" }, /* VK_DELETE */ + { VK_HELP, "", "" }, /* VK_HELP */ + { VK_KEY_0, "AE10", "" }, /* VK_KEY_0 */ + { VK_KEY_1, "AE01", "" }, /* VK_KEY_1 */ + { VK_KEY_2, "AE02", "" }, /* VK_KEY_2 */ + { VK_KEY_3, "AE03", "" }, /* VK_KEY_3 */ + { VK_KEY_4, "AE04", "" }, /* VK_KEY_4 */ + { VK_KEY_5, "AE05", "" }, /* VK_KEY_5 */ + { VK_KEY_6, "AE06", "" }, /* VK_KEY_6 */ + { VK_KEY_7, "AE07", "" }, /* VK_KEY_7 */ + { VK_KEY_8, "AE08", "" }, /* VK_KEY_8 */ + { VK_KEY_9, "AE09", "" }, /* VK_KEY_9 */ + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { VK_KEY_A, "AC01", "" }, /* VK_KEY_A */ + { VK_KEY_B, "AB05", "" }, /* VK_KEY_B */ + { VK_KEY_C, "AB03", "" }, /* VK_KEY_C */ + { VK_KEY_D, "AC03", "" }, /* VK_KEY_D */ + { VK_KEY_E, "AD03", "" }, /* VK_KEY_E */ + { VK_KEY_F, "AC04", "" }, /* VK_KEY_F */ + { VK_KEY_G, "AC05", "" }, /* VK_KEY_G */ + { VK_KEY_H, "AC06", "" }, /* VK_KEY_H */ + { VK_KEY_I, "AD08", "" }, /* VK_KEY_I */ + { VK_KEY_J, "AC07", "" }, /* VK_KEY_J */ + { VK_KEY_K, "AC08", "" }, /* VK_KEY_K */ + { VK_KEY_L, "AC09", "" }, /* VK_KEY_L */ + { VK_KEY_M, "AB07", "" }, /* VK_KEY_M */ + { VK_KEY_N, "AB06", "" }, /* VK_KEY_N */ + { VK_KEY_O, "AD09", "" }, /* VK_KEY_O */ + { VK_KEY_P, "AD10", "" }, /* VK_KEY_P */ + { VK_KEY_Q, "AD01", "" }, /* VK_KEY_Q */ + { VK_KEY_R, "AD04", "" }, /* VK_KEY_R */ + { VK_KEY_S, "AC02", "" }, /* VK_KEY_S */ + { VK_KEY_T, "AD05", "" }, /* VK_KEY_T */ + { VK_KEY_U, "AD07", "" }, /* VK_KEY_U */ + { VK_KEY_V, "AB04", "" }, /* VK_KEY_V */ + { VK_KEY_W, "AD02", "" }, /* VK_KEY_W */ + { VK_KEY_X, "AB02", "" }, /* VK_KEY_X */ + { VK_KEY_Y, "AD06", "" }, /* VK_KEY_Y */ + { VK_KEY_Z, "AB01", "" }, /* VK_KEY_Z */ + { VK_LWIN, "", "LWIN" }, /* VK_LWIN */ + { VK_RWIN, "", "RWIN" }, /* VK_RWIN */ + { VK_APPS, "", "COMP" }, /* VK_APPS */ + { 0, "", "" }, + { VK_SLEEP, "", "" }, /* VK_SLEEP */ + { VK_NUMPAD0, "KP0", "" }, /* VK_NUMPAD0 */ + { VK_NUMPAD1, "KP1", "" }, /* VK_NUMPAD1 */ + { VK_NUMPAD2, "KP2", "" }, /* VK_NUMPAD2 */ + { VK_NUMPAD3, "KP3", "" }, /* VK_NUMPAD3 */ + { VK_NUMPAD4, "KP4", "" }, /* VK_NUMPAD4 */ + { VK_NUMPAD5, "KP5", "" }, /* VK_NUMPAD5 */ + { VK_NUMPAD6, "KP6", "" }, /* VK_NUMPAD6 */ + { VK_NUMPAD7, "KP7", "" }, /* VK_NUMPAD7 */ + { VK_NUMPAD8, "KP8", "" }, /* VK_NUMPAD8 */ + { VK_NUMPAD9, "KP9", "" }, /* VK_NUMPAD9 */ + { VK_MULTIPLY, "KPMU", "" }, /* VK_MULTIPLY */ + { VK_ADD, "KPAD", "" }, /* VK_ADD */ + { VK_SEPARATOR, "", "" }, /* VK_SEPARATOR */ + { VK_SUBTRACT, "KPSU", "" }, /* VK_SUBTRACT */ + { VK_DECIMAL, "KPDL", "" }, /* VK_DECIMAL */ + { VK_DIVIDE, "AB10", "KPDV" }, /* VK_DIVIDE */ + { VK_F1, "FK01", "" }, /* VK_F1 */ + { VK_F2, "FK02", "" }, /* VK_F2 */ + { VK_F3, "FK03", "" }, /* VK_F3 */ + { VK_F4, "FK04", "" }, /* VK_F4 */ + { VK_F5, "FK05", "" }, /* VK_F5 */ + { VK_F6, "FK06", "" }, /* VK_F6 */ + { VK_F7, "FK07", "" }, /* VK_F7 */ + { VK_F8, "FK08", "" }, /* VK_F8 */ + { VK_F9, "FK09", "" }, /* VK_F9 */ + { VK_F10, "FK10", "" }, /* VK_F10 */ + { VK_F11, "FK11", "" }, /* VK_F11 */ + { VK_F12, "FK12", "" }, /* VK_F12 */ + { VK_F13, "", "" }, /* VK_F13 */ + { VK_F14, "", "" }, /* VK_F14 */ + { VK_F15, "", "" }, /* VK_F15 */ + { VK_F16, "", "" }, /* VK_F16 */ + { VK_F17, "", "" }, /* VK_F17 */ + { VK_F18, "", "" }, /* VK_F18 */ + { VK_F19, "", "" }, /* VK_F19 */ + { VK_F20, "", "" }, /* VK_F20 */ + { VK_F21, "", "" }, /* VK_F21 */ + { VK_F22, "", "" }, /* VK_F22 */ + { VK_F23, "", "" }, /* VK_F23 */ + { VK_F24, "", "" }, /* VK_F24 */ + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { VK_NUMLOCK, "NMLK", "" }, /* VK_NUMLOCK */ + { VK_SCROLL, "SCLK", "" }, /* VK_SCROLL */ + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { VK_LSHIFT, "", "" }, /* VK_LSHIFT */ + { VK_RSHIFT, "RTSH", "" }, /* VK_RSHIFT */ + { VK_LCONTROL, "LCTL", "" }, /* VK_LCONTROL */ + { VK_RCONTROL, "", "RCTL" }, /* VK_RCONTROL */ + { VK_LMENU, "", "" }, /* VK_LMENU */ + { VK_RMENU, "", "RALT" }, /* VK_RMENU */ + { VK_BROWSER_BACK, "", "" }, /* VK_BROWSER_BACK */ + { VK_BROWSER_FORWARD, "", "" }, /* VK_BROWSER_FORWARD */ + { VK_BROWSER_REFRESH, "", "" }, /* VK_BROWSER_REFRESH */ + { VK_BROWSER_STOP, "", "" }, /* VK_BROWSER_STOP */ + { VK_BROWSER_SEARCH, "", "" }, /* VK_BROWSER_SEARCH */ + { VK_BROWSER_FAVORITES, "", "" }, /* VK_BROWSER_FAVORITES */ + { VK_BROWSER_HOME, "", "" }, /* VK_BROWSER_HOME */ + { VK_VOLUME_MUTE, "", "" }, /* VK_VOLUME_MUTE */ + { VK_VOLUME_DOWN, "", "" }, /* VK_VOLUME_DOWN */ + { VK_VOLUME_UP, "", "" }, /* VK_VOLUME_UP */ + { VK_MEDIA_NEXT_TRACK, "", "" }, /* VK_MEDIA_NEXT_TRACK */ + { VK_MEDIA_PREV_TRACK, "", "" }, /* VK_MEDIA_PREV_TRACK */ + { VK_MEDIA_STOP, "", "" }, /* VK_MEDIA_STOP */ + { VK_MEDIA_PLAY_PAUSE, "", "" }, /* VK_MEDIA_PLAY_PAUSE */ + { VK_LAUNCH_MAIL, "", "" }, /* VK_LAUNCH_MAIL */ + { VK_MEDIA_SELECT, "", "" }, /* VK_MEDIA_SELECT */ + { VK_LAUNCH_APP1, "", "" }, /* VK_LAUNCH_APP1 */ + { VK_LAUNCH_APP2, "", "" }, /* VK_LAUNCH_APP2 */ + { 0, "", "" }, + { 0, "", "" }, + { VK_OEM_1, "AC10", "" }, /* VK_OEM_1 */ + { VK_OEM_PLUS, "AE12", "" }, /* VK_OEM_PLUS */ + { VK_OEM_COMMA, "AB08", "" }, /* VK_OEM_COMMA */ + { VK_OEM_MINUS, "AE11", "" }, /* VK_OEM_MINUS */ + { VK_OEM_PERIOD, "AB09", "" }, /* VK_OEM_PERIOD */ + { VK_OEM_2, "AB10", "" }, /* VK_OEM_2 */ + { VK_OEM_3, "TLDE", "" }, /* VK_OEM_3 */ + { VK_ABNT_C1, "AB11", "" }, /* VK_ABNT_C1 */ + { VK_ABNT_C2, "I129", "" }, /* VK_ABNT_C2 */ + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { VK_OEM_4, "AD11", "" }, /* VK_OEM_4 */ + { VK_OEM_5, "BKSL", "" }, /* VK_OEM_5 */ + { VK_OEM_6, "AD12", "" }, /* VK_OEM_6 */ + { VK_OEM_7, "AC11", "" }, /* VK_OEM_7 */ + { VK_OEM_8, "", "" }, /* VK_OEM_8 */ + { 0, "", "" }, + { 0, "", "" }, + { VK_OEM_102, "LSGT", "" }, /* VK_OEM_102 */ + { 0, "", "" }, + { 0, "", "" }, + { VK_PROCESSKEY, "", "" }, /* VK_PROCESSKEY */ + { 0, "", "" }, + { VK_PACKET, "", "" }, /* VK_PACKET */ + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { 0, "", "" }, + { VK_ATTN, "", "" }, /* VK_ATTN */ + { VK_CRSEL, "", "" }, /* VK_CRSEL */ + { VK_EXSEL, "", "" }, /* VK_EXSEL */ + { VK_EREOF, "", "" }, /* VK_EREOF */ + { VK_PLAY, "", "" }, /* VK_PLAY */ + { VK_ZOOM, "", "" }, /* VK_ZOOM */ + { VK_NONAME, "", "" }, /* VK_NONAME */ + { VK_PA1, "", "" }, /* VK_PA1 */ + { VK_OEM_CLEAR, "", "" }, /* VK_OEM_CLEAR */ + { 0, "", "" } }; /* { 0x54, 0, "" , "LVL3" }, -{ 0x1C, 1, "" , "KPEN" } */ void* freerdp_keyboard_xkb_init() @@ -407,8 +407,10 @@ uint32 detect_keyboard_layout_from_xkb(void* display) int freerdp_keyboard_load_map_from_xkb(void* display) { int i, j; + uint32 vkcode; boolean found; XkbDescPtr xkb; + uint32 scancode; boolean extended; boolean status = false; @@ -426,10 +428,14 @@ int freerdp_keyboard_load_map_from_xkb(void* display) for (j = 0; j < 256; j++) { + if (strlen(xkb_keyname) < 1) + continue; + if (VIRTUAL_KEY_CODE_TO_XKB_KEY_NAME_TABLE[j].xkb_keyname) { if (!strcmp(xkb_keyname, VIRTUAL_KEY_CODE_TO_XKB_KEY_NAME_TABLE[j].xkb_keyname)) { + vkcode = j; extended = false; found = true; break; @@ -440,6 +446,14 @@ int freerdp_keyboard_load_map_from_xkb(void* display) { if (!strcmp(xkb_keyname, VIRTUAL_KEY_CODE_TO_XKB_KEY_NAME_TABLE[j].xkb_keyname_extended)) { + vkcode = j; + + if (VIRTUAL_KEY_CODE_TO_XKB_KEY_NAME_TABLE[j].vkcode != vkcode) + { + printf("error at vkcode %d vs vkcode %d", vkcode, + VIRTUAL_KEY_CODE_TO_XKB_KEY_NAME_TABLE[j].vkcode); + } + extended = true; found = true; break; @@ -449,8 +463,7 @@ int freerdp_keyboard_load_map_from_xkb(void* display) if (found) { - uint32 vkcode = VIRTUAL_KEY_CODE_TO_XKB_KEY_NAME_TABLE[j].vkcode; - uint32 scancode = VIRTUAL_KEY_CODE_TO_RDP_SCANCODE_TABLE[vkcode]; + scancode = VIRTUAL_KEY_CODE_TO_RDP_SCANCODE_TABLE[vkcode]; DEBUG_KBD("%4s: keycode: 0x%02X -> vkcode: 0x%02X -> rdp scancode: 0x%02X %s", xkb_keyname, i, vkcode, scancode, extended ? " extended" : ""); From a99e21ad1f0e63f4efb5f5328ff1d2d29fc2bab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Thu, 23 Feb 2012 21:26:00 -0500 Subject: [PATCH 03/10] libfreerdp-auth: get first NTLM authentication token using SSPI --- cunit/test_sspi.c | 71 +++++++++++- include/freerdp/auth/sspi.h | 31 ++++++ libfreerdp-auth/CMakeLists.txt | 2 + libfreerdp-auth/NTLM/ntlm.c | 30 ++++- libfreerdp-auth/NTLM/ntlm.h | 25 ++++- libfreerdp-auth/NTLM/ntlm_message.c | 164 ++++++++++++++++++++++++++++ libfreerdp-auth/NTLM/ntlm_message.h | 22 ++++ libfreerdp-auth/sspi.c | 12 +- libfreerdp-auth/sspi.h | 1 + 9 files changed, 345 insertions(+), 13 deletions(-) create mode 100644 libfreerdp-auth/NTLM/ntlm_message.c create mode 100644 libfreerdp-auth/NTLM/ntlm_message.h diff --git a/cunit/test_sspi.c b/cunit/test_sspi.c index 2cd4d234f..3198f5f71 100644 --- a/cunit/test_sspi.c +++ b/cunit/test_sspi.c @@ -124,18 +124,33 @@ void test_AcquireCredentialsHandle(void) void test_InitializeSecurityContext(void) { + uint32 cbMaxLen; uint32 fContextReq; + void* output_buffer; CTXT_HANDLE context; uint32 pfContextAttr; SECURITY_STATUS status; CRED_HANDLE credentials; SEC_TIMESTAMP expiration; + SEC_PKG_INFO* pPackageInfo; SEC_AUTH_IDENTITY identity; SECURITY_FUNCTION_TABLE* table; - SEC_BUFFER_DESC sec_output_buffer; + SEC_BUFFER* p_sec_buffer; + SEC_BUFFER output_sec_buffer; + SEC_BUFFER_DESC output_sec_buffer_desc; table = InitSecurityInterface(); + status = QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &pPackageInfo); + + if (status != SEC_E_OK) + { + printf("QuerySecurityPackageInfo status: 0x%08X\n", status); + return; + } + + cbMaxLen = pPackageInfo->cbMaxToken; + identity.User = (uint16*) xstrdup(test_User); identity.UserLength = sizeof(test_User); identity.Domain = (uint16*) xstrdup(test_Domain); @@ -147,11 +162,55 @@ void test_InitializeSecurityContext(void) status = table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME, SECPKG_CRED_OUTBOUND, NULL, &identity, NULL, NULL, &credentials, &expiration); - if (status == SEC_E_OK) + if (status != SEC_E_OK) { - fContextReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE; - - table->InitializeSecurityContext(&credentials, NULL, NULL, fContextReq, 0, 0, NULL, 0, - &context, &sec_output_buffer, &pfContextAttr, &expiration); + printf("AcquireCredentialsHandle status: 0x%08X\n", status); + return; } + + fContextReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE; + + output_buffer = xmalloc(cbMaxLen); + + output_sec_buffer_desc.ulVersion = 0; + output_sec_buffer_desc.cBuffers = 1; + output_sec_buffer_desc.pBuffers = &output_sec_buffer; + + output_sec_buffer.cbBuffer = cbMaxLen; + output_sec_buffer.BufferType = SECBUFFER_TOKEN; + output_sec_buffer.pvBuffer = output_buffer; + + status = table->InitializeSecurityContext(&credentials, NULL, NULL, fContextReq, 0, 0, NULL, 0, + &context, &output_sec_buffer_desc, &pfContextAttr, &expiration); + + if (status != SEC_I_CONTINUE_NEEDED) + { + printf("InitializeSecurityContext status: 0x%08X\n", status); + return; + } + + printf("cBuffers: %d ulVersion: %d\n", output_sec_buffer_desc.cBuffers, output_sec_buffer_desc.ulVersion); + + p_sec_buffer = &output_sec_buffer_desc.pBuffers[0]; + + printf("BufferType: 0x%04X cbBuffer:%d\n", p_sec_buffer->BufferType, p_sec_buffer->cbBuffer); + + freerdp_hexdump((uint8*) p_sec_buffer->pvBuffer, p_sec_buffer->cbBuffer); } + + + + + + + + + + + + + + + + + diff --git a/include/freerdp/auth/sspi.h b/include/freerdp/auth/sspi.h index 48efcddca..178947c36 100644 --- a/include/freerdp/auth/sspi.h +++ b/include/freerdp/auth/sspi.h @@ -136,6 +136,9 @@ typedef uint32 SECURITY_STATUS; #define SEC_I_SIGNATURE_NEEDED 0x0009035C #define SEC_I_NO_RENEGOTIATION 0x00090360 +#define SECURITY_NATIVE_DREP 0x00000010 +#define SECURITY_NETWORK_DREP 0x00000000 + #define SECPKG_CRED_INBOUND 0x00000001 #define SECPKG_CRED_OUTBOUND 0x00000002 #define SECPKG_CRED_BOTH 0x00000003 @@ -335,6 +338,34 @@ typedef struct _SEC_INTEGER SEC_INTEGER; typedef SEC_INTEGER SEC_TIMESTAMP; +#define SECBUFFER_VERSION 0 + +/* Buffer Types */ +#define SECBUFFER_EMPTY 0 +#define SECBUFFER_DATA 1 +#define SECBUFFER_TOKEN 2 +#define SECBUFFER_PKG_PARAMS 3 +#define SECBUFFER_MISSING 4 +#define SECBUFFER_EXTRA 5 +#define SECBUFFER_STREAM_TRAILER 6 +#define SECBUFFER_STREAM_HEADER 7 +#define SECBUFFER_NEGOTIATION_INFO 8 +#define SECBUFFER_PADDING 9 +#define SECBUFFER_STREAM 10 +#define SECBUFFER_MECHLIST 11 +#define SECBUFFER_MECHLIST_SIGNATURE 12 +#define SECBUFFER_TARGET 13 +#define SECBUFFER_CHANNEL_BINDINGS 14 +#define SECBUFFER_CHANGE_PASS_RESPONSE 15 +#define SECBUFFER_TARGET_HOST 16 +#define SECBUFFER_ALERT 17 + +/* Security Buffer Flags */ +#define SECBUFFER_ATTRMASK 0xF0000000 +#define SECBUFFER_READONLY 0x80000000 +#define SECBUFFER_READONLY_WITH_CHECKSUM 0x10000000 +#define SECBUFFER_RESERVED 0x60000000 + struct _SEC_BUFFER { uint32 cbBuffer; diff --git a/libfreerdp-auth/CMakeLists.txt b/libfreerdp-auth/CMakeLists.txt index a230e2a53..85788710c 100644 --- a/libfreerdp-auth/CMakeLists.txt +++ b/libfreerdp-auth/CMakeLists.txt @@ -20,6 +20,8 @@ set(FREERDP_AUTH_SRCS NTLM/ntlm.c NTLM/ntlm.h + NTLM/ntlm_message.c + NTLM/ntlm_message.h sspi.c sspi.h credssp.c diff --git a/libfreerdp-auth/NTLM/ntlm.c b/libfreerdp-auth/NTLM/ntlm.c index e914cc66c..6085b5d0f 100644 --- a/libfreerdp-auth/NTLM/ntlm.c +++ b/libfreerdp-auth/NTLM/ntlm.c @@ -31,6 +31,8 @@ #include "ntlm.h" #include "../sspi.h" +#include "ntlm_message.h" + char* NTLM_PACKAGE_NAME = "NTLM"; NTLM_CONTEXT* ntlm_ContextNew() @@ -41,7 +43,9 @@ NTLM_CONTEXT* ntlm_ContextNew() if (context != NULL) { - + context->ntlm_v2 = false; + context->NegotiateFlags = 0; + context->state = NTLM_STATE_INITIAL; } return context; @@ -103,6 +107,30 @@ SECURITY_STATUS ntlm_InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_H SEC_BUFFER_DESC* pInput, uint32 Reserved2, CTXT_HANDLE* phNewContext, SEC_BUFFER_DESC* pOutput, uint32* pfContextAttr, SEC_TIMESTAMP* ptsExpiry) { + NTLM_CONTEXT* context; + SEC_BUFFER* sec_buffer; + + if (pInput == NULL) + { + context = ntlm_ContextNew(); + + if (!pOutput) + return SEC_E_INVALID_TOKEN; + + if (pOutput->cBuffers < 1) + return SEC_E_INVALID_TOKEN; + + sec_buffer = &pOutput->pBuffers[0]; + + if (sec_buffer->BufferType != SECBUFFER_TOKEN) + return SEC_E_INVALID_TOKEN; + + if (sec_buffer->cbBuffer < 1) + return SEC_E_INSUFFICIENT_MEMORY; + + return ntlm_write_NegotiateMessage(context, sec_buffer); + } + return SEC_E_OK; } diff --git a/libfreerdp-auth/NTLM/ntlm.h b/libfreerdp-auth/NTLM/ntlm.h index 21d46d3b8..390ac50b6 100644 --- a/libfreerdp-auth/NTLM/ntlm.h +++ b/libfreerdp-auth/NTLM/ntlm.h @@ -17,15 +17,32 @@ * limitations under the License. */ -#include -#include - #ifndef FREERDP_AUTH_NTLM_PRIVATE_H #define FREERDP_AUTH_NTLM_PRIVATE_H +#include +#include + +#include "../sspi.h" + +enum _NTLM_STATE +{ + NTLM_STATE_INITIAL, + NTLM_STATE_NEGOTIATE, + NTLM_STATE_CHALLENGE, + NTLM_STATE_AUTHENTICATE, + NTLM_STATE_FINAL +}; +typedef enum _NTLM_STATE NTLM_STATE; + struct _NTLM_CONTEXT { - SEC_AUTH_IDENTITY identity; + boolean ntlm_v2; + NTLM_STATE state; + uint32 NegotiateFlags; + SEC_BUFFER NegotiateMessage; + SEC_BUFFER ChallengeMessage; + SEC_BUFFER AuthenticateMessage; }; typedef struct _NTLM_CONTEXT NTLM_CONTEXT; diff --git a/libfreerdp-auth/NTLM/ntlm_message.c b/libfreerdp-auth/NTLM/ntlm_message.c new file mode 100644 index 000000000..76aa95b4e --- /dev/null +++ b/libfreerdp-auth/NTLM/ntlm_message.c @@ -0,0 +1,164 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * NTLM Security Package (Message) + * + * Copyright 2011-2012 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ntlm.h" +#include "../sspi.h" + +#include + +#include "ntlm_message.h" + +#define NTLMSSP_NEGOTIATE_56 0x80000000 /* W (0) */ +#define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V (1) */ +#define NTLMSSP_NEGOTIATE_128 0x20000000 /* U (2) */ +#define NTLMSSP_RESERVED1 0x10000000 /* r1 (3) */ +#define NTLMSSP_RESERVED2 0x08000000 /* r2 (4) */ +#define NTLMSSP_RESERVED3 0x04000000 /* r3 (5) */ +#define NTLMSSP_NEGOTIATE_VERSION 0x02000000 /* T (6) */ +#define NTLMSSP_RESERVED4 0x01000000 /* r4 (7) */ +#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000 /* S (8) */ +#define NTLMSSP_RESERVEDEQUEST_NON_NT_SESSION_KEY 0x00400000 /* R (9) */ +#define NTLMSSP_RESERVED5 0x00200000 /* r5 (10) */ +#define NTLMSSP_NEGOTIATE_IDENTIFY 0x00100000 /* Q (11) */ +#define NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY 0x00080000 /* P (12) */ +#define NTLMSSP_RESERVED6 0x00040000 /* r6 (13) */ +#define NTLMSSP_TARGET_TYPE_SERVER 0x00020000 /* O (14) */ +#define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000 /* N (15) */ +#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000 /* M (16) */ +#define NTLMSSP_RESERVED7 0x00004000 /* r7 (17) */ +#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000 /* L (18) */ +#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000 /* K (19) */ +#define NTLMSSP_NEGOTIATE_ANONYMOUS 0x00000800 /* J (20) */ +#define NTLMSSP_RESERVED8 0x00000400 /* r8 (21) */ +#define NTLMSSP_NEGOTIATE_NTLM 0x00000200 /* H (22) */ +#define NTLMSSP_RESERVED9 0x00000100 /* r9 (23) */ +#define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080 /* G (24) */ +#define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040 /* F (25) */ +#define NTLMSSP_NEGOTIATE_SEAL 0x00000020 /* E (26) */ +#define NTLMSSP_NEGOTIATE_SIGN 0x00000010 /* D (27) */ +#define NTLMSSP_RESERVED10 0x00000008 /* r10 (28) */ +#define NTLMSSP_REQUEST_TARGET 0x00000004 /* C (29) */ +#define NTLMSSP_NEGOTIATE_OEM 0x00000002 /* B (30) */ +#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001 /* A (31) */ + +#define WINDOWS_MAJOR_VERSION_5 0x05 +#define WINDOWS_MAJOR_VERSION_6 0x06 +#define WINDOWS_MINOR_VERSION_0 0x00 +#define WINDOWS_MINOR_VERSION_1 0x01 +#define WINDOWS_MINOR_VERSION_2 0x02 +#define NTLMSSP_REVISION_W2K3 0x0F + +#define MESSAGE_TYPE_NEGOTIATE 1 +#define MESSAGE_TYPE_CHALLENGE 2 +#define MESSAGE_TYPE_AUTHENTICATE 3 + +static const char NTLM_SIGNATURE[] = "NTLMSSP"; + +/** + * Output VERSION structure.\n + * VERSION @msdn{cc236654} + * @param s + */ + +void ntlm_output_version(STREAM* s) +{ + /* The following version information was observed with Windows 7 */ + + stream_write_uint8(s, WINDOWS_MAJOR_VERSION_6); /* ProductMajorVersion (1 byte) */ + stream_write_uint8(s, WINDOWS_MINOR_VERSION_1); /* ProductMinorVersion (1 byte) */ + stream_write_uint16(s, 7600); /* ProductBuild (2 bytes) */ + stream_write_zero(s, 3); /* Reserved (3 bytes) */ + stream_write_uint8(s, NTLMSSP_REVISION_W2K3); /* NTLMRevisionCurrent (1 byte) */ +} + +SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, SEC_BUFFER* buffer) +{ + STREAM* s; + int length; + uint32 negotiateFlags = 0; + + s = stream_new(0); + stream_attach(s, buffer->pvBuffer, buffer->cbBuffer); + + stream_write(s, NTLM_SIGNATURE, 8); /* Signature (8 bytes) */ + stream_write_uint32(s, MESSAGE_TYPE_NEGOTIATE); /* MessageType */ + + if (context->ntlm_v2) + { + negotiateFlags |= NTLMSSP_NEGOTIATE_56; + negotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH; + negotiateFlags |= NTLMSSP_NEGOTIATE_128; + negotiateFlags |= NTLMSSP_NEGOTIATE_VERSION; + negotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY; + negotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; + negotiateFlags |= NTLMSSP_NEGOTIATE_NTLM; + negotiateFlags |= NTLMSSP_NEGOTIATE_LM_KEY; + negotiateFlags |= NTLMSSP_NEGOTIATE_SEAL; + negotiateFlags |= NTLMSSP_NEGOTIATE_SIGN; + negotiateFlags |= NTLMSSP_REQUEST_TARGET; + negotiateFlags |= NTLMSSP_NEGOTIATE_OEM; + negotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE; + } + else + { + negotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH; + negotiateFlags |= NTLMSSP_NEGOTIATE_128; + negotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY; + negotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; + negotiateFlags |= NTLMSSP_NEGOTIATE_NTLM; + negotiateFlags |= NTLMSSP_NEGOTIATE_SEAL; + negotiateFlags |= NTLMSSP_NEGOTIATE_SIGN; + negotiateFlags |= NTLMSSP_REQUEST_TARGET; + negotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE; + } + + context->NegotiateFlags = negotiateFlags; + + stream_write_uint32(s, negotiateFlags); /* NegotiateFlags (4 bytes) */ + + /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ + + /* DomainNameFields (8 bytes) */ + stream_write_uint16(s, 0); /* DomainNameLen */ + stream_write_uint16(s, 0); /* DomainNameMaxLen */ + stream_write_uint32(s, 0); /* DomainNameBufferOffset */ + + /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ + + /* WorkstationFields (8 bytes) */ + stream_write_uint16(s, 0); /* WorkstationLen */ + stream_write_uint16(s, 0); /* WorkstationMaxLen */ + stream_write_uint32(s, 0); /* WorkstationBufferOffset */ + + if (negotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + { + /* Only present if NTLMSSP_NEGOTIATE_VERSION is set */ + ntlm_output_version(s); + } + + length = s->p - s->data; + buffer->cbBuffer = length; + + //freerdp_blob_alloc(&context->negotiate_message, length); + //memcpy(context->negotiate_message.data, s->data, length); + + context->state = NTLM_STATE_CHALLENGE; + + return SEC_I_CONTINUE_NEEDED; +} diff --git a/libfreerdp-auth/NTLM/ntlm_message.h b/libfreerdp-auth/NTLM/ntlm_message.h new file mode 100644 index 000000000..a7535642b --- /dev/null +++ b/libfreerdp-auth/NTLM/ntlm_message.h @@ -0,0 +1,22 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * NTLM Security Package (Message) + * + * Copyright 2011-2012 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ntlm.h" + +SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, SEC_BUFFER* buffer); diff --git a/libfreerdp-auth/sspi.c b/libfreerdp-auth/sspi.c index 625532b34..58b31103c 100644 --- a/libfreerdp-auth/sspi.c +++ b/libfreerdp-auth/sspi.c @@ -79,16 +79,24 @@ void sspi_CredentialsFree(CREDENTIALS* credentials) SEC_HANDLE* sspi_SecureHandleAlloc() { SEC_HANDLE* handle = xmalloc(sizeof(SEC_HANDLE)); - memset(handle, 0xFF, sizeof(SEC_HANDLE)); + sspi_SecureHandleInit(handle); return handle; } +void sspi_SecureHandleInit(SEC_HANDLE* handle) +{ + if (!handle) + return; + + memset(handle, 0xFF, sizeof(SEC_HANDLE)); +} + void sspi_SecureHandleInvalidate(SEC_HANDLE* handle) { if (!handle) return; - memset(handle, 0xFF, sizeof(SEC_HANDLE)); + sspi_SecureHandleInit(handle); } void* sspi_SecureHandleGetLowerPointer(SEC_HANDLE* handle) diff --git a/libfreerdp-auth/sspi.h b/libfreerdp-auth/sspi.h index 6ea46c55e..50bdee512 100644 --- a/libfreerdp-auth/sspi.h +++ b/libfreerdp-auth/sspi.h @@ -33,6 +33,7 @@ CREDENTIALS* sspi_CredentialsNew(); void sspi_CredentialsFree(CREDENTIALS* credentials); SEC_HANDLE* sspi_SecureHandleAlloc(); +void sspi_SecureHandleInit(SEC_HANDLE* handle); void sspi_SecureHandleInvalidate(SEC_HANDLE* handle); void* sspi_SecureHandleGetLowerPointer(SEC_HANDLE* handle); void sspi_SecureHandleSetLowerPointer(SEC_HANDLE* handle, void* pointer); From b224126cc70beba30e3bdaca87ecb30e60c9733c Mon Sep 17 00:00:00 2001 From: Norbert Federa Date: Fri, 24 Feb 2012 13:44:23 +0100 Subject: [PATCH 04/10] Completed (almost) System Pointer Update (MS-RDPBCGR 2.2.9.1.1.4.3) Todo: - Windows client: wf_Pointer_SetNull and wf_Pointer_SetDefault are just skeletons like all the other wf_Pointer functions. - DirectFB client: only df_Pointer_SetNull is implemented and tested --- client/DirectFB/df_graphics.c | 27 ++++++++++++++++++++++----- client/Windows/wf_graphics.c | 12 ++++++++++++ client/X11/xf_graphics.c | 32 ++++++++++++++++++++++++++++++++ include/freerdp/graphics.h | 8 +++++++- libfreerdp-cache/pointer.c | 12 ++++++++++++ libfreerdp-core/graphics.c | 10 ++++++++++ 6 files changed, 95 insertions(+), 6 deletions(-) diff --git a/client/DirectFB/df_graphics.c b/client/DirectFB/df_graphics.c index 3203a59e8..59ca690c9 100644 --- a/client/DirectFB/df_graphics.c +++ b/client/DirectFB/df_graphics.c @@ -90,18 +90,33 @@ void df_Pointer_Set(rdpContext* context, rdpPointer* pointer) dfi->layer->SetCooperativeLevel(dfi->layer, DLSCL_ADMINISTRATIVE); - result = dfi->layer->SetCursorShape(dfi->layer, + dfi->layer->SetCursorOpacity(dfi->layer, df_pointer ? 255: 0); + + if(df_pointer != NULL) + { + result = dfi->layer->SetCursorShape(dfi->layer, df_pointer->surface, df_pointer->xhot, df_pointer->yhot); - if (result != DFB_OK) - { - DirectFBErrorFatal("SetCursorShape Error", result); - return; + if (result != DFB_OK) + { + DirectFBErrorFatal("SetCursorShape Error", result); + return; + } } dfi->layer->SetCooperativeLevel(dfi->layer, DLSCL_SHARED); } +void df_Pointer_SetNull(rdpContext* context) +{ + df_Pointer_Set(context, NULL); +} + +void df_Pointer_SetDefault(rdpContext* context) +{ + +} + /* Graphics Module */ void df_register_graphics(rdpGraphics* graphics) @@ -114,6 +129,8 @@ void df_register_graphics(rdpGraphics* graphics) pointer->New = df_Pointer_New; pointer->Free = df_Pointer_Free; pointer->Set = df_Pointer_Set; + pointer->SetNull = df_Pointer_SetNull; + pointer->SetDefault = df_Pointer_SetDefault; graphics_register_pointer(graphics, pointer); xfree(pointer); diff --git a/client/Windows/wf_graphics.c b/client/Windows/wf_graphics.c index 715d3c5ce..a79628f1a 100644 --- a/client/Windows/wf_graphics.c +++ b/client/Windows/wf_graphics.c @@ -216,6 +216,16 @@ void wf_Pointer_Set(rdpContext* context, rdpPointer* pointer) } +void wf_Pointer_SetNull(rdpContext* context) +{ + +} + +void wf_Pointer_SetDefault(rdpContext* context) +{ + +} + /* Graphics Module */ void wf_register_graphics(rdpGraphics* graphics) @@ -236,6 +246,8 @@ void wf_register_graphics(rdpGraphics* graphics) pointer.New = wf_Pointer_New; pointer.Free = wf_Pointer_Free; pointer.Set = wf_Pointer_Set; + pointer.SetNull = wf_Pointer_SetNull; + pointer.SetDefault = wf_Pointer_SetDefault; graphics_register_bitmap(graphics, &bitmap); graphics_register_pointer(graphics, &pointer); diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 0f3ab7c79..a761ea65b 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -191,6 +191,36 @@ void xf_Pointer_Set(rdpContext* context, rdpPointer* pointer) if (xfi->window != NULL) XDefineCursor(xfi->display, xfi->window->handle, ((xfPointer*) pointer)->cursor); } + +void xf_Pointer_SetNull(rdpContext* context) +{ + xfInfo* xfi = ((xfContext*) context)->xfi; + static Cursor nullcursor = None; + + if (nullcursor == None) + { + XcursorImage ci; + XcursorPixel xp = 0; + memset(&ci, 0, sizeof(ci)); + ci.version = XCURSOR_IMAGE_VERSION; + ci.size = sizeof(ci); + ci.width = ci.height = 1; + ci.xhot = ci.yhot = 0; + ci.pixels = &xp; + nullcursor = XcursorImageLoadCursor(xfi->display, &ci); + } + if (xfi->window != NULL && nullcursor != None) + XDefineCursor(xfi->display, xfi->window->handle, nullcursor); +} + +void xf_Pointer_SetDefault(rdpContext* context) +{ + xfInfo* xfi = ((xfContext*) context)->xfi; + + if (xfi->window != NULL) + XUndefineCursor(xfi->display, xfi->window->handle); +} + /* Glyph Class */ void xf_Glyph_New(rdpContext* context, rdpGlyph* glyph) @@ -302,6 +332,8 @@ void xf_register_graphics(rdpGraphics* graphics) pointer->New = xf_Pointer_New; pointer->Free = xf_Pointer_Free; pointer->Set = xf_Pointer_Set; + pointer->SetNull = xf_Pointer_SetNull; + pointer->SetDefault = xf_Pointer_SetDefault; graphics_register_pointer(graphics, pointer); xfree(pointer); diff --git a/include/freerdp/graphics.h b/include/freerdp/graphics.h index ab6c0e844..033ff3a23 100644 --- a/include/freerdp/graphics.h +++ b/include/freerdp/graphics.h @@ -81,6 +81,8 @@ FREERDP_API void Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, boole typedef void (*pPointer_New)(rdpContext* context, rdpPointer* pointer); typedef void (*pPointer_Free)(rdpContext* context, rdpPointer* pointer); typedef void (*pPointer_Set)(rdpContext* context, rdpPointer* pointer); +typedef void (*pPointer_SetNull)(rdpContext* context); +typedef void (*pPointer_SetDefault)(rdpContext* context); struct rdp_pointer { @@ -88,7 +90,9 @@ struct rdp_pointer pPointer_New New; /* 1 */ pPointer_Free Free; /* 2 */ pPointer_Set Set; /* 3 */ - uint32 paddingA[16 - 4]; /* 4 */ + pPointer_SetNull SetNull; /* 4*/ + pPointer_SetDefault SetDefault; /* 5 */ + uint32 paddingA[16 - 6]; /* 6 */ uint32 xPos; /* 16 */ uint32 yPos; /* 17 */ @@ -106,6 +110,8 @@ FREERDP_API rdpPointer* Pointer_Alloc(rdpContext* context); FREERDP_API void Pointer_New(rdpContext* context, rdpPointer* pointer); FREERDP_API void Pointer_Free(rdpContext* context, rdpPointer* pointer); FREERDP_API void Pointer_Set(rdpContext* context, rdpPointer* pointer); +FREERDP_API void Pointer_SetNull(rdpContext* context); +FREERDP_API void Pointer_SetDefault(rdpContext* context); /* Glyph Class */ diff --git a/libfreerdp-cache/pointer.c b/libfreerdp-cache/pointer.c index 86d2f30e6..becee2e25 100644 --- a/libfreerdp-cache/pointer.c +++ b/libfreerdp-cache/pointer.c @@ -29,7 +29,19 @@ void update_pointer_position(rdpContext* context, POINTER_POSITION_UPDATE* point void update_pointer_system(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer_system) { + switch (pointer_system->type) + { + case SYSPTR_NULL: + Pointer_SetNull(context); + break; + case SYSPTR_DEFAULT: + Pointer_SetDefault(context); + break; + + default: + printf("Unknown system pointer type (0x%08X)\n", pointer_system->type); + } } void update_pointer_color(rdpContext* context, POINTER_COLOR_UPDATE* pointer_color) diff --git a/libfreerdp-core/graphics.c b/libfreerdp-core/graphics.c index f6b3bab4e..f62c20682 100644 --- a/libfreerdp-core/graphics.c +++ b/libfreerdp-core/graphics.c @@ -128,6 +128,16 @@ void Pointer_Set(rdpContext* context, rdpPointer* pointer) context->graphics->Pointer_Prototype->Set(context, pointer); } +void Pointer_SetNull(rdpContext* context) +{ + context->graphics->Pointer_Prototype->SetNull(context); +} + +void Pointer_SetDefault(rdpContext* context) +{ + context->graphics->Pointer_Prototype->SetDefault(context); +} + void graphics_register_pointer(rdpGraphics* graphics, rdpPointer* pointer) { memcpy(graphics->Pointer_Prototype, pointer, sizeof(rdpPointer)); From a30fbf3905a13128162f54ebf278bb64a5fe82a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 24 Feb 2012 15:00:49 -0500 Subject: [PATCH 05/10] libfreerdp-auth: started FreeContextBuffer() --- cunit/test_sspi.c | 4 + include/freerdp/auth/sspi.h | 5 + libfreerdp-auth/NTLM/ntlm.c | 19 ++- libfreerdp-auth/sspi.c | 244 +++++++++++++++++++++++++----------- libfreerdp-auth/sspi.h | 32 +++++ 5 files changed, 228 insertions(+), 76 deletions(-) diff --git a/cunit/test_sspi.c b/cunit/test_sspi.c index 3198f5f71..5b8d3fc4f 100644 --- a/cunit/test_sspi.c +++ b/cunit/test_sspi.c @@ -29,11 +29,13 @@ int init_sspi_suite(void) { + sspi_GlobalInit(); return 0; } int clean_sspi_suite(void) { + sspi_GlobalFinish(); return 0; } @@ -196,6 +198,8 @@ void test_InitializeSecurityContext(void) printf("BufferType: 0x%04X cbBuffer:%d\n", p_sec_buffer->BufferType, p_sec_buffer->cbBuffer); freerdp_hexdump((uint8*) p_sec_buffer->pvBuffer, p_sec_buffer->cbBuffer); + + table->FreeCredentialsHandle(&credentials); } diff --git a/include/freerdp/auth/sspi.h b/include/freerdp/auth/sspi.h index 178947c36..3ec96b422 100644 --- a/include/freerdp/auth/sspi.h +++ b/include/freerdp/auth/sspi.h @@ -515,4 +515,9 @@ FREERDP_API SECURITY_STATUS EncryptMessage(CTXT_HANDLE* phContext, uint32 fQOP, FREERDP_API SECURITY_STATUS MakeSignature(CTXT_HANDLE* phContext, uint32 fQOP, SEC_BUFFER_DESC* pMessage, uint32 MessageSeqNo); FREERDP_API SECURITY_STATUS VerifySignature(CTXT_HANDLE* phContext, SEC_BUFFER_DESC* pMessage, uint32 MessageSeqNo, uint32* pfQOP); +/* Custom API */ + +void sspi_GlobalInit(); +void sspi_GlobalFinish(); + #endif /* FREERDP_AUTH_SSPI_H */ diff --git a/libfreerdp-auth/NTLM/ntlm.c b/libfreerdp-auth/NTLM/ntlm.c index 6085b5d0f..2e07e97df 100644 --- a/libfreerdp-auth/NTLM/ntlm.c +++ b/libfreerdp-auth/NTLM/ntlm.c @@ -82,6 +82,23 @@ SECURITY_STATUS ntlm_AcquireCredentialsHandle(char* pszPrincipal, char* pszPacka return SEC_E_OK; } +SECURITY_STATUS ntlm_FreeCredentialsHandle(CRED_HANDLE* phCredential) +{ + CREDENTIALS* credentials; + + if (!phCredential) + return SEC_E_INVALID_HANDLE; + + credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); + + if (!credentials) + return SEC_E_INVALID_HANDLE; + + sspi_CredentialsFree(credentials); + + return SEC_E_OK; +} + SECURITY_STATUS ntlm_QueryCredentialsAttributes(CRED_HANDLE* phCredential, uint32 ulAttribute, void* pBuffer) { if (ulAttribute == SECPKG_CRED_ATTR_NAMES) @@ -158,7 +175,7 @@ const SECURITY_FUNCTION_TABLE NTLM_SECURITY_FUNCTION_TABLE = NULL, /* Reserved1 */ ntlm_QueryCredentialsAttributes, /* QueryCredentialsAttributes */ ntlm_AcquireCredentialsHandle, /* AcquireCredentialsHandle */ - NULL, /* FreeCredentialsHandle */ + ntlm_FreeCredentialsHandle, /* FreeCredentialsHandle */ NULL, /* Reserved2 */ ntlm_InitializeSecurityContext, /* InitializeSecurityContext */ NULL, /* AcceptSecurityContext */ diff --git a/libfreerdp-auth/sspi.c b/libfreerdp-auth/sspi.c index 58b31103c..ca6a67724 100644 --- a/libfreerdp-auth/sspi.c +++ b/libfreerdp-auth/sspi.c @@ -54,6 +54,109 @@ const SECURITY_FUNCTION_TABLE_NAME SECURITY_FUNCTION_TABLE_NAME_LIST[] = #define SEC_HANDLE_LOWER_MAX 0xFFFFFFFF #define SEC_HANDLE_UPPER_MAX 0xFFFFFFFE +struct _CONTEXT_BUFFER_ALLOC_ENTRY +{ + void* contextBuffer; + uint32 allocatorIndex; +}; +typedef struct _CONTEXT_BUFFER_ALLOC_ENTRY CONTEXT_BUFFER_ALLOC_ENTRY; + +struct _CONTEXT_BUFFER_ALLOC_TABLE +{ + uint32 cEntries; + uint32 cMaxEntries; + CONTEXT_BUFFER_ALLOC_ENTRY* entries; +}; +typedef struct _CONTEXT_BUFFER_ALLOC_TABLE CONTEXT_BUFFER_ALLOC_TABLE; + +CONTEXT_BUFFER_ALLOC_TABLE ContextBufferAllocTable; + +void sspi_ContextBufferAllocTableNew() +{ + size_t size; + + ContextBufferAllocTable.cEntries = 0; + ContextBufferAllocTable.cMaxEntries = 64; + + size = sizeof(CONTEXT_BUFFER_ALLOC_ENTRY) * ContextBufferAllocTable.cMaxEntries; + + ContextBufferAllocTable.entries = xzalloc(size); +} + +void sspi_ContextBufferAllocTableGrow() +{ + size_t size; + ContextBufferAllocTable.cEntries = 0; + ContextBufferAllocTable.cMaxEntries *= 2; + + size = sizeof(CONTEXT_BUFFER_ALLOC_ENTRY) * ContextBufferAllocTable.cMaxEntries; + + ContextBufferAllocTable.entries = xrealloc(ContextBufferAllocTable.entries, size); + memset((void*) &ContextBufferAllocTable.entries[ContextBufferAllocTable.cMaxEntries / 2], 0, size / 2); +} + +void sspi_ContextBufferAllocTableFree() +{ + ContextBufferAllocTable.cEntries = ContextBufferAllocTable.cMaxEntries = 0; + xfree(ContextBufferAllocTable.entries); +} + +void* sspi_ContextBufferAlloc(uint32 allocatorIndex, size_t size) +{ + int index; + + for (index = 0; index < ContextBufferAllocTable.cMaxEntries; index++) + { + if (ContextBufferAllocTable.entries[index].contextBuffer == NULL) + { + ContextBufferAllocTable.cEntries++; + ContextBufferAllocTable.entries[index].contextBuffer = xzalloc(size); + ContextBufferAllocTable.entries[index].allocatorIndex = allocatorIndex; + return ContextBufferAllocTable.entries[index].contextBuffer; + } + } + + /* no available entry was found, the table needs to be grown */ + + sspi_ContextBufferAllocTableGrow(); + + /* the next call to sspi_ContextBufferAlloc() should now succeed */ + + return sspi_ContextBufferAlloc(allocatorIndex, size); +} + +void FreeContextBuffer_EnumerateSecurityPackages(SEC_PKG_INFO* pPackageInfo); +void FreeContextBuffer_QuerySecurityPackageInfo(SEC_PKG_INFO* pPackageInfo); + +void sspi_ContextBufferFree(void* contextBuffer) +{ + int index; + uint32 allocatorIndex; + + for (index = 0; index < ContextBufferAllocTable.cMaxEntries; index++) + { + if (contextBuffer == ContextBufferAllocTable.entries[index].contextBuffer) + { + allocatorIndex = ContextBufferAllocTable.entries[index].allocatorIndex; + + ContextBufferAllocTable.cEntries--; + ContextBufferAllocTable.entries[index].allocatorIndex = 0; + ContextBufferAllocTable.entries[index].contextBuffer = NULL; + + switch (allocatorIndex) + { + case EnumerateSecurityPackagesIndex: + FreeContextBuffer_EnumerateSecurityPackages((SEC_PKG_INFO*) contextBuffer); + break; + + case QuerySecurityPackageInfoIndex: + FreeContextBuffer_QuerySecurityPackageInfo((SEC_PKG_INFO*) contextBuffer); + break; + } + } + } +} + CREDENTIALS* sspi_CredentialsNew() { CREDENTIALS* credentials; @@ -165,79 +268,29 @@ SECURITY_FUNCTION_TABLE* sspi_GetSecurityFunctionTableByName(const char* Name) return NULL; } +void sspi_GlobalInit() +{ + sspi_ContextBufferAllocTableNew(); +} + +void sspi_GlobalFinish() +{ + sspi_ContextBufferAllocTableFree(); +} + /* Package Management */ SECURITY_STATUS EnumerateSecurityPackages(uint32* pcPackages, SEC_PKG_INFO** ppPackageInfo) { - /* - * Name: Negotiate - * Comment: Microsoft Package Negotiator - * fCapabilities: 0x00083BB3 - * wVersion: 1 - * wRPCID: 0x0009 - * cbMaxToken: 0x00002FE0 - */ - - /* - * Name: NegoExtender - * Comment: NegoExtender Security Package - * fCapabilities: 0x00113913 - * wVersion: 1 - * wRPCID: 0x001E - * cbMaxToken: 0x00002EE0 - */ - - /* - * Name: Kerberos - * Comment: Microsoft Kerberos V1.0 - * fCapabilities: 0x000F3BBF - * wVersion: 1 - * wRPCID: 0x0010 - * cbMaxToken: 0x00002EE0 - */ - - /* - * Name: NTLM - * Comment: NTLM Security Package - * fCapabilities: 0x00082B37 - * wVersion: 1 - * wRPCID: 0x000A - * cbMaxToken: 0x00000B48 - */ - - /* - * Name: Schannel - * Comment: Schannel Security Package - * fCapabilities: 0x000107B3 - * wVersion: 1 - * wRPCID: 0x000E - * cbMaxToken: 0x00006000 - */ - - /* - * Name: TSSSP - * Comment: TS Service Security Package - * fCapabilities: 0x00010230 - * wVersion: 1 - * wRPCID: 0x0016 - * cbMaxToken: 0x000032C8 - */ - - /* - * Name: CREDSSP - * Comment: Microsoft CredSSP Security Provider - * fCapabilities: 0x000110733 - * wVersion: 1 - * wRPCID: 0xFFFF - * cbMaxToken: 0x000090A8 - */ - int index; + size_t size; uint32 cPackages; SEC_PKG_INFO* pPackageInfo; cPackages = sizeof(SEC_PKG_INFO_LIST) / sizeof(SEC_PKG_INFO*); - pPackageInfo = (SEC_PKG_INFO*) xmalloc(sizeof(SEC_PKG_INFO) * cPackages); + size = sizeof(SEC_PKG_INFO) * cPackages; + + pPackageInfo = (SEC_PKG_INFO*) sspi_ContextBufferAlloc(EnumerateSecurityPackagesIndex, size); for (index = 0; index < cPackages; index++) { @@ -255,6 +308,25 @@ SECURITY_STATUS EnumerateSecurityPackages(uint32* pcPackages, SEC_PKG_INFO** ppP return SEC_E_OK; } +void FreeContextBuffer_EnumerateSecurityPackages(SEC_PKG_INFO* pPackageInfo) +{ + int index; + uint32 cPackages; + + cPackages = sizeof(SEC_PKG_INFO_LIST) / sizeof(SEC_PKG_INFO*); + + for (index = 0; index < cPackages; index++) + { + if (pPackageInfo[index].Name) + xfree(pPackageInfo[index].Name); + + if (pPackageInfo[index].Comment) + xfree(pPackageInfo[index].Comment); + } + + xfree(pPackageInfo); +} + SECURITY_FUNCTION_TABLE* InitSecurityInterface(void) { SECURITY_FUNCTION_TABLE* security_function_table; @@ -266,6 +338,7 @@ SECURITY_FUNCTION_TABLE* InitSecurityInterface(void) SECURITY_STATUS QuerySecurityPackageInfo(char* pszPackageName, SEC_PKG_INFO** ppPackageInfo) { int index; + size_t size; uint32 cPackages; SEC_PKG_INFO* pPackageInfo; @@ -275,7 +348,8 @@ SECURITY_STATUS QuerySecurityPackageInfo(char* pszPackageName, SEC_PKG_INFO** pp { if (strcmp(pszPackageName, SEC_PKG_INFO_LIST[index]->Name) == 0) { - pPackageInfo = (SEC_PKG_INFO*) xmalloc(sizeof(SEC_PKG_INFO)); + size = sizeof(SEC_PKG_INFO); + pPackageInfo = (SEC_PKG_INFO*) sspi_ContextBufferAlloc(QuerySecurityPackageInfoIndex, size); pPackageInfo->fCapabilities = SEC_PKG_INFO_LIST[index]->fCapabilities; pPackageInfo->wVersion = SEC_PKG_INFO_LIST[index]->wVersion; @@ -295,6 +369,17 @@ SECURITY_STATUS QuerySecurityPackageInfo(char* pszPackageName, SEC_PKG_INFO** pp return SEC_E_SECPKG_NOT_FOUND; } +void FreeContextBuffer_QuerySecurityPackageInfo(SEC_PKG_INFO* pPackageInfo) +{ + if (pPackageInfo->Name) + xfree(pPackageInfo->Name); + + if (pPackageInfo->Comment) + xfree(pPackageInfo->Comment); + + xfree(pPackageInfo); +} + /* Credential Management */ SECURITY_STATUS AcquireCredentialsHandle(char* pszPrincipal, char* pszPackage, @@ -323,19 +408,26 @@ SECURITY_STATUS ExportSecurityContext(CTXT_HANDLE* phContext, uint32 fFlags, SEC SECURITY_STATUS FreeCredentialsHandle(CRED_HANDLE* phCredential) { - CREDENTIALS* credentials; + char* Name; + SECURITY_STATUS status; + SECURITY_FUNCTION_TABLE* table; - if (!phCredential) - return SEC_E_INVALID_HANDLE; + Name = (char*) sspi_SecureHandleGetUpperPointer(phCredential); - credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); + if (!Name) + return SEC_E_SECPKG_NOT_FOUND; - if (!credentials) - return SEC_E_INVALID_HANDLE; + table = sspi_GetSecurityFunctionTableByName(Name); - sspi_CredentialsFree(credentials); + if (!table) + return SEC_E_SECPKG_NOT_FOUND; - return SEC_E_OK; + if (!(table->FreeCredentialsHandle)) + return SEC_E_UNSUPPORTED_FUNCTION; + + status = table->FreeCredentialsHandle(phCredential); + + return status; } SECURITY_STATUS ImportSecurityContext(char* pszPackage, SEC_BUFFER* pPackedContext, void* pToken, CTXT_HANDLE* phContext) @@ -390,8 +482,10 @@ SECURITY_STATUS DeleteSecurityContext(CTXT_HANDLE* phContext) SECURITY_STATUS FreeContextBuffer(void* pvContextBuffer) { - if (pvContextBuffer != NULL) - xfree(pvContextBuffer); + if (!pvContextBuffer) + return SEC_E_INVALID_HANDLE; + + sspi_ContextBufferFree(pvContextBuffer); return SEC_E_OK; } diff --git a/libfreerdp-auth/sspi.h b/libfreerdp-auth/sspi.h index 50bdee512..1f6c21d07 100644 --- a/libfreerdp-auth/sspi.h +++ b/libfreerdp-auth/sspi.h @@ -41,4 +41,36 @@ void* sspi_SecureHandleGetUpperPointer(SEC_HANDLE* handle); void sspi_SecureHandleSetUpperPointer(SEC_HANDLE* handle, void* pointer); void sspi_SecureHandleFree(SEC_HANDLE* handle); +enum SecurityFunctionTableIndex +{ + EnumerateSecurityPackagesIndex = 1, + Reserved1Index = 2, + QueryCredentialsAttributesIndex = 3, + AcquireCredentialsHandleIndex = 4, + FreeCredentialsHandleIndex = 5, + Reserved2Index = 6, + InitializeSecurityContextIndex = 7, + AcceptSecurityContextIndex = 8, + CompleteAuthTokenIndex = 9, + DeleteSecurityContextIndex = 10, + ApplyControlTokenIndex = 11, + QueryContextAttributesIndex = 12, + ImpersonateSecurityContextIndex = 13, + RevertSecurityContextIndex = 14, + MakeSignatureIndex = 15, + VerifySignatureIndex = 16, + FreeContextBufferIndex = 17, + QuerySecurityPackageInfoIndex = 18, + Reserved3Index = 19, + Reserved4Index = 20, + ExportSecurityContextIndex = 21, + ImportSecurityContextIndex = 22, + AddCredentialsIndex = 23, + Reserved8Index = 24, + QuerySecurityContextTokenIndex = 25, + EncryptMessageIndex = 26, + DecryptMessageIndex = 27, + SetContextAttributesIndex = 28 +}; + #endif /* FREERDP_AUTH_SSPI_PRIVATE_H */ From 0303c7a3d4959c60f8fea6d684a29df96c321afe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 24 Feb 2012 15:35:48 -0500 Subject: [PATCH 06/10] libfreerdp-auth: get FreeContextBuffer to work --- cunit/test_sspi.c | 6 ++++++ libfreerdp-auth/sspi.c | 25 +++++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/cunit/test_sspi.c b/cunit/test_sspi.c index 5b8d3fc4f..d698be47e 100644 --- a/cunit/test_sspi.c +++ b/cunit/test_sspi.c @@ -71,6 +71,8 @@ void test_EnumerateSecurityPackages(void) pPackageInfo[index].Name, pPackageInfo[index].Comment); } } + + FreeContextBuffer(pPackageInfo); } void test_QuerySecurityPackageInfo(void) @@ -145,6 +147,8 @@ void test_InitializeSecurityContext(void) status = QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &pPackageInfo); + printf("pPackageInfo: 0x%08X ppPackageInfo:0x%08X\n", pPackageInfo, &pPackageInfo); + if (status != SEC_E_OK) { printf("QuerySecurityPackageInfo status: 0x%08X\n", status); @@ -200,6 +204,8 @@ void test_InitializeSecurityContext(void) freerdp_hexdump((uint8*) p_sec_buffer->pvBuffer, p_sec_buffer->cbBuffer); table->FreeCredentialsHandle(&credentials); + + FreeContextBuffer(pPackageInfo); } diff --git a/libfreerdp-auth/sspi.c b/libfreerdp-auth/sspi.c index ca6a67724..4b7ae0514 100644 --- a/libfreerdp-auth/sspi.c +++ b/libfreerdp-auth/sspi.c @@ -76,7 +76,7 @@ void sspi_ContextBufferAllocTableNew() size_t size; ContextBufferAllocTable.cEntries = 0; - ContextBufferAllocTable.cMaxEntries = 64; + ContextBufferAllocTable.cMaxEntries = 4; size = sizeof(CONTEXT_BUFFER_ALLOC_ENTRY) * ContextBufferAllocTable.cMaxEntries; @@ -104,14 +104,18 @@ void sspi_ContextBufferAllocTableFree() void* sspi_ContextBufferAlloc(uint32 allocatorIndex, size_t size) { int index; + void* contextBuffer; for (index = 0; index < ContextBufferAllocTable.cMaxEntries; index++) { if (ContextBufferAllocTable.entries[index].contextBuffer == NULL) { + contextBuffer = xzalloc(size); ContextBufferAllocTable.cEntries++; - ContextBufferAllocTable.entries[index].contextBuffer = xzalloc(size); + + ContextBufferAllocTable.entries[index].contextBuffer = contextBuffer; ContextBufferAllocTable.entries[index].allocatorIndex = allocatorIndex; + return ContextBufferAllocTable.entries[index].contextBuffer; } } @@ -125,8 +129,8 @@ void* sspi_ContextBufferAlloc(uint32 allocatorIndex, size_t size) return sspi_ContextBufferAlloc(allocatorIndex, size); } -void FreeContextBuffer_EnumerateSecurityPackages(SEC_PKG_INFO* pPackageInfo); -void FreeContextBuffer_QuerySecurityPackageInfo(SEC_PKG_INFO* pPackageInfo); +void FreeContextBuffer_EnumerateSecurityPackages(void* contextBuffer); +void FreeContextBuffer_QuerySecurityPackageInfo(void* contextBuffer); void sspi_ContextBufferFree(void* contextBuffer) { @@ -137,20 +141,22 @@ void sspi_ContextBufferFree(void* contextBuffer) { if (contextBuffer == ContextBufferAllocTable.entries[index].contextBuffer) { + contextBuffer = ContextBufferAllocTable.entries[index].contextBuffer; allocatorIndex = ContextBufferAllocTable.entries[index].allocatorIndex; ContextBufferAllocTable.cEntries--; + ContextBufferAllocTable.entries[index].allocatorIndex = 0; ContextBufferAllocTable.entries[index].contextBuffer = NULL; switch (allocatorIndex) { case EnumerateSecurityPackagesIndex: - FreeContextBuffer_EnumerateSecurityPackages((SEC_PKG_INFO*) contextBuffer); + FreeContextBuffer_EnumerateSecurityPackages(contextBuffer); break; case QuerySecurityPackageInfoIndex: - FreeContextBuffer_QuerySecurityPackageInfo((SEC_PKG_INFO*) contextBuffer); + FreeContextBuffer_QuerySecurityPackageInfo(contextBuffer); break; } } @@ -308,10 +314,11 @@ SECURITY_STATUS EnumerateSecurityPackages(uint32* pcPackages, SEC_PKG_INFO** ppP return SEC_E_OK; } -void FreeContextBuffer_EnumerateSecurityPackages(SEC_PKG_INFO* pPackageInfo) +void FreeContextBuffer_EnumerateSecurityPackages(void* contextBuffer) { int index; uint32 cPackages; + SEC_PKG_INFO* pPackageInfo = (SEC_PKG_INFO*) contextBuffer; cPackages = sizeof(SEC_PKG_INFO_LIST) / sizeof(SEC_PKG_INFO*); @@ -369,8 +376,10 @@ SECURITY_STATUS QuerySecurityPackageInfo(char* pszPackageName, SEC_PKG_INFO** pp return SEC_E_SECPKG_NOT_FOUND; } -void FreeContextBuffer_QuerySecurityPackageInfo(SEC_PKG_INFO* pPackageInfo) +void FreeContextBuffer_QuerySecurityPackageInfo(void* contextBuffer) { + SEC_PKG_INFO* pPackageInfo = (SEC_PKG_INFO*) contextBuffer; + if (pPackageInfo->Name) xfree(pPackageInfo->Name); From 29bed60b0794c9d7a5da9a092e626f5d302d2e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 24 Feb 2012 17:17:38 -0500 Subject: [PATCH 07/10] libfreerdp-auth: start using new SSPI package optionally --- cunit/test_sspi.c | 2 - libfreerdp-auth/NTLM/ntlm.c | 26 ++- libfreerdp-auth/NTLM/ntlm.h | 20 +++ libfreerdp-auth/NTLM/ntlm_message.c | 246 +++++++++++++++++++++++++++- libfreerdp-auth/credssp.c | 149 +++++++++++++++++ libfreerdp-auth/sspi.c | 12 ++ libfreerdp-auth/sspi.h | 3 + 7 files changed, 453 insertions(+), 5 deletions(-) diff --git a/cunit/test_sspi.c b/cunit/test_sspi.c index d698be47e..493d8e2ae 100644 --- a/cunit/test_sspi.c +++ b/cunit/test_sspi.c @@ -147,8 +147,6 @@ void test_InitializeSecurityContext(void) status = QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &pPackageInfo); - printf("pPackageInfo: 0x%08X ppPackageInfo:0x%08X\n", pPackageInfo, &pPackageInfo); - if (status != SEC_E_OK) { printf("QuerySecurityPackageInfo status: 0x%08X\n", status); diff --git a/libfreerdp-auth/NTLM/ntlm.c b/libfreerdp-auth/NTLM/ntlm.c index 2e07e97df..d04c39aa4 100644 --- a/libfreerdp-auth/NTLM/ntlm.c +++ b/libfreerdp-auth/NTLM/ntlm.c @@ -46,6 +46,7 @@ NTLM_CONTEXT* ntlm_ContextNew() context->ntlm_v2 = false; context->NegotiateFlags = 0; context->state = NTLM_STATE_INITIAL; + context->uniconv = freerdp_uniconv_new(); } return context; @@ -127,7 +128,7 @@ SECURITY_STATUS ntlm_InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_H NTLM_CONTEXT* context; SEC_BUFFER* sec_buffer; - if (pInput == NULL) + if (!pInput) { context = ntlm_ContextNew(); @@ -145,8 +146,31 @@ SECURITY_STATUS ntlm_InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_H if (sec_buffer->cbBuffer < 1) return SEC_E_INSUFFICIENT_MEMORY; + sspi_SecureHandleSetLowerPointer(phNewContext, context); + return ntlm_write_NegotiateMessage(context, sec_buffer); } + else + { + context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext); + + if (!context) + return SEC_E_INVALID_HANDLE; + + if (!pInput) + return SEC_E_INVALID_TOKEN; + + if (pInput->cBuffers < 1) + return SEC_E_INVALID_TOKEN; + + sec_buffer = &pInput->pBuffers[0]; + + if (sec_buffer->BufferType != SECBUFFER_TOKEN) + return SEC_E_INVALID_TOKEN; + + if (sec_buffer->cbBuffer < 1) + return SEC_E_INVALID_TOKEN; + } return SEC_E_OK; } diff --git a/libfreerdp-auth/NTLM/ntlm.h b/libfreerdp-auth/NTLM/ntlm.h index 390ac50b6..8c02338fb 100644 --- a/libfreerdp-auth/NTLM/ntlm.h +++ b/libfreerdp-auth/NTLM/ntlm.h @@ -23,6 +23,8 @@ #include #include +#include + #include "../sspi.h" enum _NTLM_STATE @@ -39,10 +41,28 @@ struct _NTLM_CONTEXT { boolean ntlm_v2; NTLM_STATE state; + UNICONV* uniconv; uint32 NegotiateFlags; SEC_BUFFER NegotiateMessage; SEC_BUFFER ChallengeMessage; SEC_BUFFER AuthenticateMessage; + SEC_BUFFER TargetInfo; + SEC_BUFFER TargetName; + SEC_BUFFER NtChallengeResponse; + SEC_BUFFER LmChallengeResponse; + uint8 Timestamp[8]; + uint8 ServerChallenge[8]; + uint8 ClientChallenge[8]; + uint8 SessionBaseKey[16]; + uint8 KeyExchangeKey[16]; + uint8 RandomSessionKey[16]; + uint8 ExportedSessionKey[16]; + uint8 EncryptedRandomSessionKey[16]; + uint8 ClientSigningKey[16]; + uint8 ClientSealingKey[16]; + uint8 ServerSigningKey[16]; + uint8 ServerSealingKey[16]; + uint8 MessageIntegrityCheck[16]; }; typedef struct _NTLM_CONTEXT NTLM_CONTEXT; diff --git a/libfreerdp-auth/NTLM/ntlm_message.c b/libfreerdp-auth/NTLM/ntlm_message.c index 76aa95b4e..be62c2738 100644 --- a/libfreerdp-auth/NTLM/ntlm_message.c +++ b/libfreerdp-auth/NTLM/ntlm_message.c @@ -21,9 +21,12 @@ #include "../sspi.h" #include +#include #include "ntlm_message.h" +#define WITH_DEBUG_NTLM + #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W (0) */ #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V (1) */ #define NTLMSSP_NEGOTIATE_128 0x20000000 /* U (2) */ @@ -70,6 +73,42 @@ static const char NTLM_SIGNATURE[] = "NTLMSSP"; +static const char* const NTLM_NEGOTIATE_STRINGS[] = +{ + "NTLMSSP_NEGOTIATE_56", + "NTLMSSP_NEGOTIATE_KEY_EXCH", + "NTLMSSP_NEGOTIATE_128", + "NTLMSSP_RESERVED1", + "NTLMSSP_RESERVED2", + "NTLMSSP_RESERVED3", + "NTLMSSP_NEGOTIATE_VERSION", + "NTLMSSP_RESERVED4", + "NTLMSSP_NEGOTIATE_TARGET_INFO", + "NTLMSSP_REQUEST_NON_NT_SESSION_KEY", + "NTLMSSP_RESERVED5", + "NTLMSSP_NEGOTIATE_IDENTIFY", + "NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY", + "NTLMSSP_RESERVED6", + "NTLMSSP_TARGET_TYPE_SERVER", + "NTLMSSP_TARGET_TYPE_DOMAIN", + "NTLMSSP_NEGOTIATE_ALWAYS_SIGN", + "NTLMSSP_RESERVED7", + "NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED", + "NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED", + "NTLMSSP_NEGOTIATE_ANONYMOUS", + "NTLMSSP_RESERVED8", + "NTLMSSP_NEGOTIATE_NTLM", + "NTLMSSP_RESERVED9", + "NTLMSSP_NEGOTIATE_LM_KEY", + "NTLMSSP_NEGOTIATE_DATAGRAM", + "NTLMSSP_NEGOTIATE_SEAL", + "NTLMSSP_NEGOTIATE_SIGN", + "NTLMSSP_RESERVED10", + "NTLMSSP_REQUEST_TARGET", + "NTLMSSP_NEGOTIATE_OEM", + "NTLMSSP_NEGOTIATE_UNICODE" +}; + /** * Output VERSION structure.\n * VERSION @msdn{cc236654} @@ -87,6 +126,25 @@ void ntlm_output_version(STREAM* s) stream_write_uint8(s, NTLMSSP_REVISION_W2K3); /* NTLMRevisionCurrent (1 byte) */ } +void ntlm_print_negotiate_flags(uint32 flags) +{ + int i; + const char* str; + + printf("negotiateFlags \"0x%08X\"{\n", flags); + + for (i = 31; i >= 0; i--) + { + if ((flags >> i) & 1) + { + str = NTLM_NEGOTIATE_STRINGS[(31 - i)]; + printf("\t%s (%d),\n", str, (31 - i)); + } + } + + printf("}\n"); +} + SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, SEC_BUFFER* buffer) { STREAM* s; @@ -150,15 +208,199 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, SEC_BUFFER* b { /* Only present if NTLMSSP_NEGOTIATE_VERSION is set */ ntlm_output_version(s); + +#ifdef WITH_DEBUG_NTLM + printf("Version (length = 8)\n"); + freerdp_hexdump((s->p - 8), 8); + printf("\n"); +#endif } length = s->p - s->data; buffer->cbBuffer = length; - //freerdp_blob_alloc(&context->negotiate_message, length); - //memcpy(context->negotiate_message.data, s->data, length); + sspi_SecBufferAlloc(&context->NegotiateMessage, length); + memcpy(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer); + context->NegotiateMessage.BufferType = buffer->BufferType; + +#ifdef WITH_DEBUG_NTLM + printf("NEGOTIATE_MESSAGE (length = %d)\n", length); + freerdp_hexdump(s->data, length); + printf("\n"); +#endif context->state = NTLM_STATE_CHALLENGE; return SEC_I_CONTINUE_NEEDED; } + +SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* buffer) +{ + uint8* p; + STREAM* s; + int length; + uint8* start_offset; + uint8* payload_offset; + uint16 targetNameLen; + uint16 targetNameMaxLen; + uint32 targetNameBufferOffset; + uint16 targetInfoLen; + uint16 targetInfoMaxLen; + uint32 targetInfoBufferOffset; + + s = stream_new(0); + stream_attach(s, buffer->pvBuffer, buffer->cbBuffer); + + start_offset = s->p - 12; + + /* TargetNameFields (8 bytes) */ + stream_read_uint16(s, targetNameLen); /* TargetNameLen (2 bytes) */ + stream_read_uint16(s, targetNameMaxLen); /* TargetNameMaxLen (2 bytes) */ + stream_read_uint32(s, targetNameBufferOffset); /* TargetNameBufferOffset (4 bytes) */ + + stream_read_uint32(s, context->NegotiateFlags); /* NegotiateFlags (4 bytes) */ + +#ifdef WITH_DEBUG_NTLM + ntlm_print_negotiate_flags(context->NegotiateFlags); +#endif + + stream_read(s, context->ServerChallenge, 8); /* ServerChallenge (8 bytes) */ + stream_seek(s, 8); /* Reserved (8 bytes), should be ignored */ + + /* TargetInfoFields (8 bytes) */ + stream_read_uint16(s, targetInfoLen); /* TargetInfoLen (2 bytes) */ + stream_read_uint16(s, targetInfoMaxLen); /* TargetInfoMaxLen (2 bytes) */ + stream_read_uint32(s, targetInfoBufferOffset); /* TargetInfoBufferOffset (4 bytes) */ + + /* only present if NTLMSSP_NEGOTIATE_VERSION is set */ + + if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + { + stream_seek(s, 8); /* Version (8 bytes), can be ignored */ + } + + /* Payload (variable) */ + payload_offset = s->p; + + if (targetNameLen > 0) + { + p = start_offset + targetNameBufferOffset; + sspi_SecBufferAlloc(&context->TargetName, targetNameLen); + memcpy(context->TargetName.pvBuffer, p, targetNameLen); + +#ifdef WITH_DEBUG_NTLM + printf("TargetName (length = %d, offset = %d)\n", targetNameLen, targetNameBufferOffset); + freerdp_hexdump(context->TargetName.pvBuffer, context->TargetName.cbBuffer); + printf("\n"); +#endif + } + + if (targetInfoLen > 0) + { + p = start_offset + targetInfoBufferOffset; + sspi_SecBufferAlloc(&context->TargetInfo, targetInfoLen); + memcpy(context->TargetInfo.pvBuffer, p, targetInfoLen); + +#ifdef WITH_DEBUG_NTLM + printf("TargetInfo (length = %d, offset = %d)\n", targetInfoLen, targetInfoBufferOffset); + freerdp_hexdump(context->TargetInfo.pvBuffer, context->TargetInfo.cbBuffer); + printf("\n"); +#endif + + if (context->ntlm_v2) + { + s->p = p; + //ntlm_input_av_pairs(context, s); + } + } + + length = (payload_offset - start_offset) + targetNameLen + targetInfoLen; + + sspi_SecBufferAlloc(&context->ChallengeMessage, length); + memcpy(context->ChallengeMessage.pvBuffer, start_offset, length); + +#ifdef WITH_DEBUG_NTLM + printf("CHALLENGE_MESSAGE (length = %d)\n", length); + freerdp_hexdump(context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer); + printf("\n"); +#endif + +#if 0 + + /* AV_PAIRs */ + if (context->ntlm_v2) + ntlmssp_populate_av_pairs(context); + + /* Timestamp */ + ntlm_generate_timestamp(context); + + /* LmChallengeResponse */ + ntlm_compute_lm_v2_response(context); + + if ((context->ntlm_v2) && (context->LmChallengeResponse.cbBuffer > 0)) + memset(context->LmChallengeResponse.pvBuffer, 0, context->LmChallengeResponse.cbBuffer); + + /* NtChallengeResponse */ + ntlm_compute_ntlm_v2_response(context); + + /* KeyExchangeKey */ + ntlm_generate_key_exchange_key(context); + + /* EncryptedRandomSessionKey */ + ntlm_encrypt_random_session_key(context); + + /* Generate signing keys */ + ntlm_generate_client_signing_key(context); + ntlm_generate_server_signing_key(context); + + /* Generate sealing keys */ + ntlm_generate_client_sealing_key(context); + ntlm_generate_server_sealing_key(context); + + /* Initialize RC4 seal state using client sealing key */ + ntlm_init_rc4_seal_states(context); + +#ifdef WITH_DEBUG_NTLM + printf("ClientChallenge\n"); + freerdp_hexdump(context->ClientChallenge, 8); + printf("\n"); + + printf("ServerChallenge\n"); + freerdp_hexdump(context->ServerChallenge, 8); + printf("\n"); + + printf("SessionBaseKey\n"); + freerdp_hexdump(context->SessionBaseKey, 16); + printf("\n"); + + printf("KeyExchangeKey\n"); + freerdp_hexdump(context->KeyExchangeKey, 16); + printf("\n"); + + printf("ExportedSessionKey\n"); + freerdp_hexdump(context->ExportedSessionKey, 16); + printf("\n"); + + printf("RandomSessionKey\n"); + freerdp_hexdump(context->RandomSessionKey, 16); + printf("\n"); + + printf("ClientSignKey\n"); + freerdp_hexdump(context->ClientSigningKey, 16); + printf("\n"); + + printf("ClientSealingKey\n"); + freerdp_hexdump(context->ClientSealingKey, 16); + printf("\n"); + + printf("Timestamp\n"); + freerdp_hexdump(context->Timestamp, 8); + printf("\n"); +#endif + +#endif + + context->state = NTLMSSP_STATE_AUTHENTICATE; + + return SEC_I_CONTINUE_NEEDED; +} diff --git a/libfreerdp-auth/credssp.c b/libfreerdp-auth/credssp.c index c0c77aaa5..969595e27 100644 --- a/libfreerdp-auth/credssp.c +++ b/libfreerdp-auth/credssp.c @@ -29,6 +29,8 @@ #include #include +//#define WITH_SSPI 1 + /** * TSRequest ::= SEQUENCE { * version [0] INTEGER, @@ -142,6 +144,8 @@ int credssp_ntlmssp_server_init(rdpCredssp* credssp) * @return 1 if authentication is successful */ +#ifndef WITH_SSPI + int credssp_client_authenticate(rdpCredssp* credssp) { NTLMSSP* ntlmssp = credssp->ntlmssp; @@ -202,6 +206,151 @@ int credssp_client_authenticate(rdpCredssp* credssp) return 1; } +#else + +#define NTLM_PACKAGE_NAME "NTLM" + +int credssp_client_authenticate(rdpCredssp* credssp) +{ + uint32 cbMaxLen; + uint32 fContextReq; + void* output_buffer; + CTXT_HANDLE context; + uint32 pfContextAttr; + SECURITY_STATUS status; + CRED_HANDLE credentials; + SEC_TIMESTAMP expiration; + SEC_PKG_INFO* pPackageInfo; + SEC_AUTH_IDENTITY identity; + SECURITY_FUNCTION_TABLE* table; + SEC_BUFFER* p_sec_buffer; + SEC_BUFFER output_sec_buffer; + SEC_BUFFER_DESC output_sec_buffer_desc; + SEC_BUFFER input_sec_buffer; + SEC_BUFFER_DESC input_sec_buffer_desc; + rdpSettings* settings = credssp->settings; + + sspi_GlobalInit(); + + if (credssp_ntlmssp_client_init(credssp) == 0) + return 0; + + table = InitSecurityInterface(); + + status = QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &pPackageInfo); + + if (status != SEC_E_OK) + { + printf("QuerySecurityPackageInfo status: 0x%08X\n", status); + return 0; + } + + cbMaxLen = pPackageInfo->cbMaxToken; + + identity.User = (uint16*) xstrdup(settings->username); + identity.UserLength = strlen(settings->username); + + if (settings->domain) + { + identity.Domain = (uint16*) xstrdup(settings->domain); + identity.DomainLength = strlen(settings->domain); + } + else + { + identity.Domain = (uint16*) NULL; + identity.DomainLength = 0; + } + + identity.Password = (uint16*) xstrdup(settings->password); + identity.PasswordLength = strlen(settings->password); + + identity.Flags = SEC_AUTH_IDENTITY_ANSI; + + status = table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME, + SECPKG_CRED_OUTBOUND, NULL, &identity, NULL, NULL, &credentials, &expiration); + + if (status != SEC_E_OK) + { + printf("AcquireCredentialsHandle status: 0x%08X\n", status); + return 0; + } + + fContextReq = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_DELEGATE; + + output_buffer = xmalloc(cbMaxLen); + + printf("First Call to InitializeSecurityContext()\n"); + + output_sec_buffer_desc.ulVersion = 0; + output_sec_buffer_desc.cBuffers = 1; + output_sec_buffer_desc.pBuffers = &output_sec_buffer; + + output_sec_buffer.cbBuffer = cbMaxLen; + output_sec_buffer.BufferType = SECBUFFER_TOKEN; + output_sec_buffer.pvBuffer = output_buffer; + + status = table->InitializeSecurityContext(&credentials, NULL, NULL, fContextReq, 0, 0, NULL, 0, + &context, &output_sec_buffer_desc, &pfContextAttr, &expiration); + + if (status != SEC_I_CONTINUE_NEEDED) + { + printf("InitializeSecurityContext status: 0x%08X\n", status); + return 0; + } + + p_sec_buffer = &output_sec_buffer_desc.pBuffers[0]; + + freerdp_hexdump((uint8*) p_sec_buffer->pvBuffer, p_sec_buffer->cbBuffer); + + credssp->negoToken.data = p_sec_buffer->pvBuffer; + credssp->negoToken.length = p_sec_buffer->cbBuffer; + + /* NTLMSSP NEGOTIATE MESSAGE */ + credssp_send(credssp, &credssp->negoToken, NULL, NULL); + + printf("sent NTLMSSP_NEGOTIATE_MESSAGE\n"); + + /* NTLMSSP CHALLENGE MESSAGE */ + if (credssp_recv(credssp, &credssp->negoToken, NULL, NULL) < 0) + return -1; + + printf("received NTLM CHALLENGE MESSAGE\n"); + + input_sec_buffer_desc.ulVersion = 0; + input_sec_buffer_desc.cBuffers = 1; + input_sec_buffer_desc.pBuffers = &input_sec_buffer; + + input_sec_buffer.cbBuffer = credssp->negoToken.length; + input_sec_buffer.BufferType = SECBUFFER_TOKEN; + input_sec_buffer.pvBuffer = credssp->negoToken.data; + + output_sec_buffer_desc.ulVersion = 0; + output_sec_buffer_desc.cBuffers = 1; + output_sec_buffer_desc.pBuffers = &output_sec_buffer; + + output_sec_buffer.cbBuffer = cbMaxLen; + output_sec_buffer.BufferType = SECBUFFER_TOKEN; + output_sec_buffer.pvBuffer = output_buffer; + + printf("Second Call to InitializeSecurityContext()\n"); + + status = table->InitializeSecurityContext(&credentials, &context, NULL, fContextReq, 0, 0, + &input_sec_buffer_desc, 0, &context, &output_sec_buffer_desc, &pfContextAttr, &expiration); + + if (status != SEC_I_CONTINUE_NEEDED) + { + printf("InitializeSecurityContext status: 0x%08X\n", status); + return 0; + } + + FreeCredentialsHandle(&credentials); + FreeContextBuffer(pPackageInfo); + + return 1; +} + +#endif + /** * Authenticate with client using CredSSP (server). * @param credssp diff --git a/libfreerdp-auth/sspi.c b/libfreerdp-auth/sspi.c index 4b7ae0514..1f2c6fe29 100644 --- a/libfreerdp-auth/sspi.c +++ b/libfreerdp-auth/sspi.c @@ -185,6 +185,18 @@ void sspi_CredentialsFree(CREDENTIALS* credentials) xfree(credentials); } +void sspi_SecBufferAlloc(SEC_BUFFER* sec_buffer, size_t size) +{ + sec_buffer->cbBuffer = size; + sec_buffer->pvBuffer = xzalloc(size); +} + +void sspi_SecBufferFree(SEC_BUFFER* sec_buffer) +{ + sec_buffer->cbBuffer = 0; + xfree(sec_buffer->pvBuffer); +} + SEC_HANDLE* sspi_SecureHandleAlloc() { SEC_HANDLE* handle = xmalloc(sizeof(SEC_HANDLE)); diff --git a/libfreerdp-auth/sspi.h b/libfreerdp-auth/sspi.h index 1f6c21d07..88d49b935 100644 --- a/libfreerdp-auth/sspi.h +++ b/libfreerdp-auth/sspi.h @@ -32,6 +32,9 @@ typedef struct _CREDENTIALS CREDENTIALS; CREDENTIALS* sspi_CredentialsNew(); void sspi_CredentialsFree(CREDENTIALS* credentials); +void sspi_SecBufferAlloc(SEC_BUFFER* sec_buffer, size_t size); +void sspi_SecBufferFree(SEC_BUFFER* sec_buffer); + SEC_HANDLE* sspi_SecureHandleAlloc(); void sspi_SecureHandleInit(SEC_HANDLE* handle); void sspi_SecureHandleInvalidate(SEC_HANDLE* handle); From cd5a4a54fcc5322da90630f5873c5aab34e607fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sat, 25 Feb 2012 09:55:52 -0500 Subject: [PATCH 08/10] libfreerdp-auth: started moving NTLM computation methods --- libfreerdp-auth/CMakeLists.txt | 2 + libfreerdp-auth/NTLM/ntlm.c | 62 ++- libfreerdp-auth/NTLM/ntlm.h | 45 +- libfreerdp-auth/NTLM/ntlm_compute.c | 665 ++++++++++++++++++++++++++++ libfreerdp-auth/NTLM/ntlm_compute.h | 44 ++ libfreerdp-auth/NTLM/ntlm_message.c | 26 +- libfreerdp-auth/NTLM/ntlm_message.h | 6 + libfreerdp-auth/credssp.c | 2 - 8 files changed, 840 insertions(+), 12 deletions(-) create mode 100644 libfreerdp-auth/NTLM/ntlm_compute.c create mode 100644 libfreerdp-auth/NTLM/ntlm_compute.h diff --git a/libfreerdp-auth/CMakeLists.txt b/libfreerdp-auth/CMakeLists.txt index 85788710c..3edbb10ed 100644 --- a/libfreerdp-auth/CMakeLists.txt +++ b/libfreerdp-auth/CMakeLists.txt @@ -20,6 +20,8 @@ set(FREERDP_AUTH_SRCS NTLM/ntlm.c NTLM/ntlm.h + NTLM/ntlm_compute.c + NTLM/ntlm_compute.h NTLM/ntlm_message.c NTLM/ntlm_message.h sspi.c diff --git a/libfreerdp-auth/NTLM/ntlm.c b/libfreerdp-auth/NTLM/ntlm.c index d04c39aa4..2582ac055 100644 --- a/libfreerdp-auth/NTLM/ntlm.c +++ b/libfreerdp-auth/NTLM/ntlm.c @@ -26,7 +26,6 @@ #include #include -#include #include "ntlm.h" #include "../sspi.h" @@ -35,6 +34,58 @@ char* NTLM_PACKAGE_NAME = "NTLM"; +void ntlm_SetContextIdentity(NTLM_CONTEXT* context, SEC_AUTH_IDENTITY* identity) +{ + size_t size; + context->identity.Flags = SEC_AUTH_IDENTITY_UNICODE; + + if (identity->Flags == SEC_AUTH_IDENTITY_ANSI) + { + context->identity.User = (uint16*) freerdp_uniconv_out(context->uniconv, (char*) identity->User, &size); + context->identity.UserLength = (uint32) size; + + if (identity->DomainLength > 0) + { + context->identity.Domain = (uint16*) freerdp_uniconv_out(context->uniconv, (char*) identity->Domain, &size); + context->identity.DomainLength = (uint32) size; + } + else + { + context->identity.Domain = (uint16*) NULL; + context->identity.DomainLength = 0; + } + + context->identity.Password = (uint16*) freerdp_uniconv_out(context->uniconv, (char*) identity->Password, &size); + context->identity.PasswordLength = (uint32) size; + } + else + { + context->identity.User = (uint16*) xmalloc(identity->UserLength); + memcpy(context->identity.User, identity->User, identity->UserLength); + + if (identity->DomainLength > 0) + { + context->identity.Domain = (uint16*) xmalloc(identity->DomainLength); + memcpy(context->identity.Domain, identity->Domain, identity->DomainLength); + } + else + { + context->identity.Domain = (uint16*) NULL; + context->identity.DomainLength = 0; + } + + context->identity.Password = (uint16*) xmalloc(identity->PasswordLength); + memcpy(context->identity.Password, identity->User, identity->PasswordLength); + } +} + +void ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation) +{ + size_t size; + context->Workstation = (uint16*) freerdp_uniconv_out(context->uniconv, Workstation, &size); + context->WorkstationLength = (uint32) size; +} + NTLM_CONTEXT* ntlm_ContextNew() { NTLM_CONTEXT* context; @@ -47,6 +98,7 @@ NTLM_CONTEXT* ntlm_ContextNew() context->NegotiateFlags = 0; context->state = NTLM_STATE_INITIAL; context->uniconv = freerdp_uniconv_new(); + context->av_pairs = (AV_PAIRS*) xzalloc(sizeof(AV_PAIRS)); } return context; @@ -127,11 +179,17 @@ SECURITY_STATUS ntlm_InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_H { NTLM_CONTEXT* context; SEC_BUFFER* sec_buffer; + CREDENTIALS* credentials; if (!pInput) { context = ntlm_ContextNew(); + credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential); + + ntlm_SetContextIdentity(context, &credentials->identity); + ntlm_SetContextWorkstation(context, "WORKSTATION"); + if (!pOutput) return SEC_E_INVALID_TOKEN; @@ -170,6 +228,8 @@ SECURITY_STATUS ntlm_InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_H if (sec_buffer->cbBuffer < 1) return SEC_E_INVALID_TOKEN; + + return ntlm_read_ChallengeMessage(context, sec_buffer); } return SEC_E_OK; diff --git a/libfreerdp-auth/NTLM/ntlm.h b/libfreerdp-auth/NTLM/ntlm.h index 8c02338fb..b0f360e32 100644 --- a/libfreerdp-auth/NTLM/ntlm.h +++ b/libfreerdp-auth/NTLM/ntlm.h @@ -21,7 +21,6 @@ #define FREERDP_AUTH_NTLM_PRIVATE_H #include -#include #include @@ -37,12 +36,54 @@ enum _NTLM_STATE }; typedef enum _NTLM_STATE NTLM_STATE; +struct _AV_PAIR +{ + uint16 length; + uint8* value; +}; +typedef struct _AV_PAIR AV_PAIR; + +struct _AV_PAIRS +{ + AV_PAIR NbComputerName; + AV_PAIR NbDomainName; + AV_PAIR DnsComputerName; + AV_PAIR DnsDomainName; + AV_PAIR DnsTreeName; + AV_PAIR Timestamp; + AV_PAIR Restrictions; + AV_PAIR TargetName; + AV_PAIR ChannelBindings; + uint32 Flags; +}; +typedef struct _AV_PAIRS AV_PAIRS; + +enum _AV_ID +{ + MsvAvEOL, + MsvAvNbComputerName, + MsvAvNbDomainName, + MsvAvDnsComputerName, + MsvAvDnsDomainName, + MsvAvDnsTreeName, + MsvAvFlags, + MsvAvTimestamp, + MsvAvRestrictions, + MsvAvTargetName, + MsvChannelBindings +}; +typedef enum _AV_ID AV_ID; + struct _NTLM_CONTEXT { boolean ntlm_v2; NTLM_STATE state; UNICONV* uniconv; + AV_PAIRS* av_pairs; uint32 NegotiateFlags; + uint16* Workstation; + uint32 WorkstationLength; + SEC_AUTH_IDENTITY identity; SEC_BUFFER NegotiateMessage; SEC_BUFFER ChallengeMessage; SEC_BUFFER AuthenticateMessage; @@ -66,4 +107,6 @@ struct _NTLM_CONTEXT }; typedef struct _NTLM_CONTEXT NTLM_CONTEXT; +#define WITH_DEBUG_NTLM 1 + #endif /* FREERDP_AUTH_NTLM_PRIVATE_H */ diff --git a/libfreerdp-auth/NTLM/ntlm_compute.c b/libfreerdp-auth/NTLM/ntlm_compute.c new file mode 100644 index 000000000..e6840c91f --- /dev/null +++ b/libfreerdp-auth/NTLM/ntlm_compute.c @@ -0,0 +1,665 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * NTLM Security Package (Compute) + * + * Copyright 2011-2012 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ntlm.h" +#include "../sspi.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ntlm_compute.h" + +const char* const AV_PAIRS_STRINGS[] = +{ + "MsvAvEOL", + "MsvAvNbComputerName", + "MsvAvNbDomainName", + "MsvAvDnsComputerName", + "MsvAvDnsDomainName", + "MsvAvDnsTreeName", + "MsvAvFlags", + "MsvAvTimestamp", + "MsvAvRestrictions", + "MsvAvTargetName", + "MsvChannelBindings" +}; + +/** + * Output Restriction_Encoding.\n + * Restriction_Encoding @msdn{cc236647} + * @param NTLM context + */ + +void ntlm_output_restriction_encoding(NTLM_CONTEXT* context) +{ + STREAM* s; + AV_PAIR* restrictions = &context->av_pairs->Restrictions; + + uint8 machineID[32] = + "\x3A\x15\x8E\xA6\x75\x82\xD8\xF7\x3E\x06\xFA\x7A\xB4\xDF\xFD\x43" + "\x84\x6C\x02\x3A\xFD\x5A\x94\xFE\xCF\x97\x0F\x3D\x19\x2C\x38\x20"; + + restrictions->value = xmalloc(48); + restrictions->length = 48; + + s = stream_new(0); + stream_attach(s, restrictions->value, restrictions->length); + + stream_write_uint32(s, 48); /* Size */ + stream_write_zero(s, 4); /* Z4 (set to zero) */ + + /* IntegrityLevel (bit 31 set to 1) */ + stream_write_uint8(s, 1); + stream_write_zero(s, 3); + + stream_write_uint32(s, 0x00002000); /* SubjectIntegrityLevel */ + stream_write(s, machineID, 32); /* MachineID */ + + xfree(s); +} + +/** + * Output TargetName.\n + * @param NTLM context + */ + +void ntlm_output_target_name(NTLM_CONTEXT* context) +{ + STREAM* s; + AV_PAIR* TargetName = &context->av_pairs->TargetName; + + /* + * TODO: No idea what should be set here (observed MsvAvTargetName = MsvAvDnsComputerName or + * MsvAvTargetName should be the name of the service be accessed after authentication) + * here used: "TERMSRV/192.168.0.123" in unicode (Dmitrij Jasnov) + */ + uint8 name[42] = + "\x54\x00\x45\x00\x52\x00\x4d\x00\x53\x00\x52\x00\x56\x00\x2f\x00\x31\x00\x39\x00\x32" + "\x00\x2e\x00\x31\x00\x36\x00\x38\x00\x2e\x00\x30\x00\x2e\x00\x31\x00\x32\x00\x33\x00"; + + TargetName->length = 42; + TargetName->value = (uint8*) xmalloc(TargetName->length); + + s = stream_new(0); + stream_attach(s, TargetName->value, TargetName->length); + + stream_write(s, name, TargetName->length); + + xfree(s); +} + +/** + * Output ChannelBindings.\n + * @param NTLM context + */ + +void ntlm_output_channel_bindings(NTLM_CONTEXT* context) +{ + STREAM* s; + AV_PAIR* ChannelBindings = &context->av_pairs->ChannelBindings; + + ChannelBindings->value = (uint8*) xmalloc(48); + ChannelBindings->length = 16; + + s = stream_new(0); + stream_attach(s, ChannelBindings->value, ChannelBindings->length); + + stream_write_zero(s, 16); /* an all-zero value of the hash is used to indicate absence of channel bindings */ + + xfree(s); +} + +/** + * Input array of AV_PAIRs.\n + * AV_PAIR @msdn{cc236646} + * @param NTLM context + * @param s + */ + +void ntlm_input_av_pairs(NTLM_CONTEXT* context, STREAM* s) +{ + AV_ID AvId; + uint16 AvLen; + uint8* value; + AV_PAIRS* av_pairs = context->av_pairs; + +#ifdef WITH_DEBUG_NTLM + printf("AV_PAIRS = {\n"); +#endif + + do + { + value = NULL; + stream_read_uint16(s, AvId); + stream_read_uint16(s, AvLen); + + if (AvLen > 0) + { + if (AvId != MsvAvFlags) + { + value = xmalloc(AvLen); + stream_read(s, value, AvLen); + } + else + { + stream_read_uint32(s, av_pairs->Flags); + } + } + + switch (AvId) + { + case MsvAvNbComputerName: + av_pairs->NbComputerName.length = AvLen; + av_pairs->NbComputerName.value = value; + break; + + case MsvAvNbDomainName: + av_pairs->NbDomainName.length = AvLen; + av_pairs->NbDomainName.value = value; + break; + + case MsvAvDnsComputerName: + av_pairs->DnsComputerName.length = AvLen; + av_pairs->DnsComputerName.value = value; + break; + + case MsvAvDnsDomainName: + av_pairs->DnsDomainName.length = AvLen; + av_pairs->DnsDomainName.value = value; + break; + + case MsvAvDnsTreeName: + av_pairs->DnsTreeName.length = AvLen; + av_pairs->DnsTreeName.value = value; + break; + + case MsvAvTimestamp: + av_pairs->Timestamp.length = AvLen; + av_pairs->Timestamp.value = value; + break; + + case MsvAvRestrictions: + av_pairs->Restrictions.length = AvLen; + av_pairs->Restrictions.value = value; + break; + + case MsvAvTargetName: + av_pairs->TargetName.length = AvLen; + av_pairs->TargetName.value = value; + break; + + case MsvChannelBindings: + av_pairs->ChannelBindings.length = AvLen; + av_pairs->ChannelBindings.value = value; + break; + + default: + if (value != NULL) + xfree(value); + break; + } + +#ifdef WITH_DEBUG_NTLM + if (AvId < 10) + printf("\tAvId: %s, AvLen: %d\n", AV_PAIRS_STRINGS[AvId], AvLen); + else + printf("\tAvId: %s, AvLen: %d\n", "Unknown", AvLen); + + freerdp_hexdump(value, AvLen); +#endif + } + while (AvId != MsvAvEOL); + +#ifdef WITH_DEBUG_NTLM + printf("}\n"); +#endif +} + +/** + * Output array of AV_PAIRs.\n + * AV_PAIR @msdn{cc236646} + * @param NTLM context + * @param s + */ + +void ntlm_output_av_pairs(NTLM_CONTEXT* context, STREAM* s) +{ + AV_PAIRS* av_pairs = context->av_pairs; + + if (av_pairs->NbDomainName.length > 0) + { + stream_write_uint16(s, MsvAvNbDomainName); /* AvId */ + stream_write_uint16(s, av_pairs->NbDomainName.length); /* AvLen */ + stream_write(s, av_pairs->NbDomainName.value, av_pairs->NbDomainName.length); /* Value */ + } + + if (av_pairs->NbComputerName.length > 0) + { + stream_write_uint16(s, MsvAvNbComputerName); /* AvId */ + stream_write_uint16(s, av_pairs->NbComputerName.length); /* AvLen */ + stream_write(s, av_pairs->NbComputerName.value, av_pairs->NbComputerName.length); /* Value */ + } + + if (av_pairs->DnsDomainName.length > 0) + { + stream_write_uint16(s, MsvAvDnsDomainName); /* AvId */ + stream_write_uint16(s, av_pairs->DnsDomainName.length); /* AvLen */ + stream_write(s, av_pairs->DnsDomainName.value, av_pairs->DnsDomainName.length); /* Value */ + } + + if (av_pairs->DnsComputerName.length > 0) + { + stream_write_uint16(s, MsvAvDnsComputerName); /* AvId */ + stream_write_uint16(s, av_pairs->DnsComputerName.length); /* AvLen */ + stream_write(s, av_pairs->DnsComputerName.value, av_pairs->DnsComputerName.length); /* Value */ + } + + if (av_pairs->DnsTreeName.length > 0) + { + stream_write_uint16(s, MsvAvDnsTreeName); /* AvId */ + stream_write_uint16(s, av_pairs->DnsTreeName.length); /* AvLen */ + stream_write(s, av_pairs->DnsTreeName.value, av_pairs->DnsTreeName.length); /* Value */ + } + + if (av_pairs->Timestamp.length > 0) + { + stream_write_uint16(s, MsvAvTimestamp); /* AvId */ + stream_write_uint16(s, av_pairs->Timestamp.length); /* AvLen */ + stream_write(s, av_pairs->Timestamp.value, av_pairs->Timestamp.length); /* Value */ + } + + if (av_pairs->Flags > 0) + { + stream_write_uint16(s, MsvAvFlags); /* AvId */ + stream_write_uint16(s, 4); /* AvLen */ + stream_write_uint32(s, av_pairs->Flags); /* Value */ + } + + if (av_pairs->Restrictions.length > 0) + { + stream_write_uint16(s, MsvAvRestrictions); /* AvId */ + stream_write_uint16(s, av_pairs->Restrictions.length); /* AvLen */ + stream_write(s, av_pairs->Restrictions.value, av_pairs->Restrictions.length); /* Value */ + } + + if (av_pairs->ChannelBindings.length > 0) + { + stream_write_uint16(s, MsvChannelBindings); /* AvId */ + stream_write_uint16(s, av_pairs->ChannelBindings.length); /* AvLen */ + stream_write(s, av_pairs->ChannelBindings.value, av_pairs->ChannelBindings.length); /* Value */ + } + + if (av_pairs->TargetName.length > 0) + { + stream_write_uint16(s, MsvAvTargetName); /* AvId */ + stream_write_uint16(s, av_pairs->TargetName.length); /* AvLen */ + stream_write(s, av_pairs->TargetName.value, av_pairs->TargetName.length); /* Value */ + } + + /* This indicates the end of the AV_PAIR array */ + stream_write_uint16(s, MsvAvEOL); /* AvId */ + stream_write_uint16(s, 0); /* AvLen */ + + if (context->ntlm_v2) + { + stream_write_zero(s, 8); + } +} + +/** + * Populate array of AV_PAIRs.\n + * AV_PAIR @msdn{cc236646} + * @param NTLM context + */ + +void ntlm_populate_av_pairs(NTLM_CONTEXT* context) +{ + STREAM* s; + AV_PAIRS* av_pairs = context->av_pairs; + + /* MsvAvFlags */ + av_pairs->Flags = 0x00000002; /* Indicates the present of a Message Integrity Check (MIC) */ + + /* Restriction_Encoding */ + ntlm_output_restriction_encoding(context); + + /* TargetName */ + ntlm_output_target_name(context); + + /* ChannelBindings */ + ntlm_output_channel_bindings(context); + + s = stream_new(context->TargetInfo.cbBuffer); + ntlm_output_av_pairs(context, s); + + sspi_SecBufferAlloc(&context->TargetInfo, s->p - s->data); + memcpy(context->TargetInfo.pvBuffer, s->data, context->TargetInfo.cbBuffer); + + xfree(s); +} + +/** + * Print array of AV_PAIRs.\n + * AV_PAIR @msdn{cc236646} + * @param NTLM context + */ + +void ntlm_print_av_pairs(NTLM_CONTEXT* context) +{ + AV_PAIRS* av_pairs = context->av_pairs; + + printf("AV_PAIRS = {\n"); + + if (av_pairs->NbDomainName.length > 0) + { + printf("\tAvId: MsvAvNbDomainName AvLen: %d\n", av_pairs->NbDomainName.length); + freerdp_hexdump(av_pairs->NbDomainName.value, av_pairs->NbDomainName.length); + } + + if (av_pairs->NbComputerName.length > 0) + { + printf("\tAvId: MsvAvNbComputerName AvLen: %d\n", av_pairs->NbComputerName.length); + freerdp_hexdump(av_pairs->NbComputerName.value, av_pairs->NbComputerName.length); + } + + if (av_pairs->DnsDomainName.length > 0) + { + printf("\tAvId: MsvAvDnsDomainName AvLen: %d\n", av_pairs->DnsDomainName.length); + freerdp_hexdump(av_pairs->DnsDomainName.value, av_pairs->DnsDomainName.length); + } + + if (av_pairs->DnsComputerName.length > 0) + { + printf("\tAvId: MsvAvDnsComputerName AvLen: %d\n", av_pairs->DnsComputerName.length); + freerdp_hexdump(av_pairs->DnsComputerName.value, av_pairs->DnsComputerName.length); + } + + if (av_pairs->DnsTreeName.length > 0) + { + printf("\tAvId: MsvAvDnsTreeName AvLen: %d\n", av_pairs->DnsTreeName.length); + freerdp_hexdump(av_pairs->DnsTreeName.value, av_pairs->DnsTreeName.length); + } + + if (av_pairs->Timestamp.length > 0) + { + printf("\tAvId: MsvAvTimestamp AvLen: %d\n", av_pairs->Timestamp.length); + freerdp_hexdump(av_pairs->Timestamp.value, av_pairs->Timestamp.length); + } + + if (av_pairs->Flags > 0) + { + printf("\tAvId: MsvAvFlags AvLen: %d\n", 4); + printf("0x%08X\n", av_pairs->Flags); + } + + if (av_pairs->Restrictions.length > 0) + { + printf("\tAvId: MsvAvRestrictions AvLen: %d\n", av_pairs->Restrictions.length); + freerdp_hexdump(av_pairs->Restrictions.value, av_pairs->Restrictions.length); + } + + if (av_pairs->ChannelBindings.length > 0) + { + printf("\tAvId: MsvChannelBindings AvLen: %d\n", av_pairs->ChannelBindings.length); + freerdp_hexdump(av_pairs->ChannelBindings.value, av_pairs->ChannelBindings.length); + } + + if (av_pairs->TargetName.length > 0) + { + printf("\tAvId: MsvAvTargetName AvLen: %d\n", av_pairs->TargetName.length); + freerdp_hexdump(av_pairs->TargetName.value, av_pairs->TargetName.length); + } + + printf("}\n"); +} + +/** + * Free array of AV_PAIRs.\n + * AV_PAIR @msdn{cc236646} + * @param NTLM context + */ + +void ntlm_free_av_pairs(NTLM_CONTEXT* context) +{ + AV_PAIRS* av_pairs = context->av_pairs; + + if (av_pairs != NULL) + { + if (av_pairs->NbComputerName.value != NULL) + xfree(av_pairs->NbComputerName.value); + if (av_pairs->NbDomainName.value != NULL) + xfree(av_pairs->NbDomainName.value); + if (av_pairs->DnsComputerName.value != NULL) + xfree(av_pairs->DnsComputerName.value); + if (av_pairs->DnsDomainName.value != NULL) + xfree(av_pairs->DnsDomainName.value); + if (av_pairs->DnsTreeName.value != NULL) + xfree(av_pairs->DnsTreeName.value); + if (av_pairs->Timestamp.value != NULL) + xfree(av_pairs->Timestamp.value); + if (av_pairs->Restrictions.value != NULL) + xfree(av_pairs->Restrictions.value); + if (av_pairs->TargetName.value != NULL) + xfree(av_pairs->TargetName.value); + if (av_pairs->ChannelBindings.value != NULL) + xfree(av_pairs->ChannelBindings.value); + + xfree(av_pairs); + } + + context->av_pairs = NULL; +} + +/** + * Get current time, in tenths of microseconds since midnight of January 1, 1601. + * @param[out] timestamp 64-bit little-endian timestamp + */ + +void ntlm_current_time(uint8* timestamp) +{ + uint64 time64; + + /* Timestamp (8 bytes), represented as the number of tenths of microseconds since midnight of January 1, 1601 */ + time64 = time(NULL) + 11644473600LL; /* Seconds since January 1, 1601 */ + time64 *= 10000000; /* Convert timestamp to tenths of a microsecond */ + + memcpy(timestamp, &time64, 8); /* Copy into timestamp in little-endian */ +} + +/** + * Generate timestamp for AUTHENTICATE_MESSAGE. + * @param NTLM context + */ + +void ntlm_generate_timestamp(NTLM_CONTEXT* context) +{ + ntlm_current_time(context->Timestamp); + + if (context->ntlm_v2) + { + if (context->av_pairs->Timestamp.length == 8) + { + memcpy(context->av_pairs->Timestamp.value, context->Timestamp, 8); + return; + } + } + else + { + if (context->av_pairs->Timestamp.length != 8) + { + context->av_pairs->Timestamp.length = 8; + context->av_pairs->Timestamp.value = xmalloc(context->av_pairs->Timestamp.length); + } + + memcpy(context->av_pairs->Timestamp.value, context->Timestamp, 8); + } +} + +void ntlm_compute_ntlm_hash(uint16* password, uint32 length, char* hash) +{ + /* NTLMv1("password") = 8846F7EAEE8FB117AD06BDD830B7586C */ + + MD4_CTX md4_ctx; + + /* Password needs to be in unicode */ + + /* Apply the MD4 digest algorithm on the password in unicode, the result is the NTLM hash */ + + MD4_Init(&md4_ctx); + MD4_Update(&md4_ctx, password, length); + MD4_Final((void*) hash, &md4_ctx); +} + +void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash) +{ + char* p; + SEC_BUFFER buffer; + char ntlm_hash[16]; + + sspi_SecBufferAlloc(&buffer, context->identity.UserLength + context->identity.DomainLength); + p = (char*) buffer.pvBuffer; + + /* First, compute the NTLMv1 hash of the password */ + ntlm_compute_ntlm_hash(context->identity.Password, context->identity.PasswordLength, ntlm_hash); + + /* Concatenate(Uppercase(username),domain)*/ + memcpy(p, context->identity.User, context->identity.UserLength); + freerdp_uniconv_uppercase(context->uniconv, p, context->identity.UserLength / 2); + + memcpy(&p[context->identity.UserLength], context->identity.Domain, context->identity.DomainLength); + + /* Compute the HMAC-MD5 hash of the above value using the NTLMv1 hash as the key, the result is the NTLMv2 hash */ + HMAC(EVP_md5(), (void*) ntlm_hash, 16, buffer.pvBuffer, buffer.cbBuffer, (void*) hash, NULL); + + sspi_SecBufferFree(&buffer); +} + +void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) +{ + char* response; + char value[16]; + char ntlm_v2_hash[16]; + + /* Compute the NTLMv2 hash */ + ntlm_compute_ntlm_v2_hash(context, ntlm_v2_hash); + + /* Concatenate the server and client challenges */ + memcpy(value, context->ServerChallenge, 8); + memcpy(&value[8], context->ClientChallenge, 8); + + sspi_SecBufferAlloc(&context->LmChallengeResponse, 24); + response = (char*) context->LmChallengeResponse.pvBuffer; + + /* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */ + HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, (void*) value, 16, (void*) response, NULL); + + /* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response (24 bytes) */ + memcpy(&response[16], context->ClientChallenge, 8); +} + +/** + * Compute NTLMv2 Response.\n + * NTLMv2_RESPONSE @msdn{cc236653}\n + * NTLMv2 Authentication @msdn{cc236700} + * @param NTLM context + */ + +void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) +{ + uint8* blob; + uint8 ntlm_v2_hash[16]; + uint8 nt_proof_str[16]; + SEC_BUFFER ntlm_v2_temp; + SEC_BUFFER ntlm_v2_temp_chal; + + sspi_SecBufferAlloc(&ntlm_v2_temp, context->TargetInfo.cbBuffer + 28); + + memset(ntlm_v2_temp.pvBuffer, '\0', ntlm_v2_temp.cbBuffer); + blob = (uint8*) ntlm_v2_temp.pvBuffer; + + /* Compute the NTLMv2 hash */ + ntlm_compute_ntlm_v2_hash(context, (char*) ntlm_v2_hash); + +#ifdef WITH_DEBUG_NTLM + printf("Password (length = %d)\n", context->identity.PasswordLength); + freerdp_hexdump((uint8*) context->identity.Password, context->identity.PasswordLength); + printf("\n"); + + printf("Username (length = %d)\n", context->identity.UserLength); + freerdp_hexdump((uint8*) context->identity.User, context->identity.UserLength); + printf("\n"); + + printf("Domain (length = %d)\n", context->identity.DomainLength); + freerdp_hexdump((uint8*) context->identity.Domain, context->identity.DomainLength); + printf("\n"); + + printf("Workstation (length = %d)\n", context->WorkstationLength); + freerdp_hexdump((uint8*) context->Workstation, context->WorkstationLength); + printf("\n"); + + printf("NTOWFv2, NTLMv2 Hash\n"); + freerdp_hexdump(ntlm_v2_hash, 16); + printf("\n"); +#endif + + /* Construct temp */ + blob[0] = 1; /* RespType (1 byte) */ + blob[1] = 1; /* HighRespType (1 byte) */ + /* Reserved1 (2 bytes) */ + /* Reserved2 (4 bytes) */ + memcpy(&blob[8], context->av_pairs->Timestamp.value, 8); /* Timestamp (8 bytes) */ + memcpy(&blob[16], context->ClientChallenge, 8); /* ClientChallenge (8 bytes) */ + /* Reserved3 (4 bytes) */ + memcpy(&blob[28], context->TargetInfo.pvBuffer, context->TargetInfo.cbBuffer); + +#ifdef WITH_DEBUG_NTLM + printf("NTLMv2 Response Temp Blob\n"); + freerdp_hexdump(ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); + printf("\n"); +#endif + + /* Concatenate server challenge with temp */ + sspi_SecBufferAlloc(&ntlm_v2_temp_chal, ntlm_v2_temp.cbBuffer + 8); + blob = (uint8*) ntlm_v2_temp_chal.pvBuffer; + memcpy(blob, context->ServerChallenge, 8); + memcpy(&blob[8], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); + + HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, ntlm_v2_temp_chal.pvBuffer, + ntlm_v2_temp_chal.cbBuffer, (void*) nt_proof_str, NULL); + + /* NtChallengeResponse, Concatenate NTProofStr with temp */ + sspi_SecBufferAlloc(&context->NtChallengeResponse, ntlm_v2_temp.cbBuffer + 16); + blob = (uint8*) context->NtChallengeResponse.pvBuffer; + memcpy(blob, nt_proof_str, 16); + memcpy(&blob[16], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); + + /* Compute SessionBaseKey, the HMAC-MD5 hash of NTProofStr using the NTLMv2 hash as the key */ + HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, (void*) nt_proof_str, 16, (void*) context->SessionBaseKey, NULL); + + sspi_SecBufferFree(&ntlm_v2_temp); + sspi_SecBufferFree(&ntlm_v2_temp_chal); +} diff --git a/libfreerdp-auth/NTLM/ntlm_compute.h b/libfreerdp-auth/NTLM/ntlm_compute.h new file mode 100644 index 000000000..5b484d555 --- /dev/null +++ b/libfreerdp-auth/NTLM/ntlm_compute.h @@ -0,0 +1,44 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * NTLM Security Package (Compute) + * + * Copyright 2011-2012 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_AUTH_NTLM_COMPUTE_H +#define FREERDP_AUTH_NTLM_COMPUTE_H + +#include "ntlm.h" + +void ntlm_output_restriction_encoding(NTLM_CONTEXT* context); +void ntlm_output_target_name(NTLM_CONTEXT* context); +void ntlm_output_channel_bindings(NTLM_CONTEXT* context); + +void ntlm_input_av_pairs(NTLM_CONTEXT* context, STREAM* s); +void ntlm_output_av_pairs(NTLM_CONTEXT* context, STREAM* s); +void ntlm_populate_av_pairs(NTLM_CONTEXT* context); +void ntlm_print_av_pairs(NTLM_CONTEXT* context); +void ntlm_free_av_pairs(NTLM_CONTEXT* context); + +void ntlm_current_time(uint8* timestamp); +void ntlm_generate_timestamp(NTLM_CONTEXT* context); + +void ntlm_compute_ntlm_hash(uint16* password, uint32 length, char* hash); +void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash); +void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context); +void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context); + +#endif /* FREERDP_AUTH_NTLM_COMPUTE_H */ + diff --git a/libfreerdp-auth/NTLM/ntlm_message.c b/libfreerdp-auth/NTLM/ntlm_message.c index be62c2738..96b094fda 100644 --- a/libfreerdp-auth/NTLM/ntlm_message.c +++ b/libfreerdp-auth/NTLM/ntlm_message.c @@ -23,9 +23,9 @@ #include #include -#include "ntlm_message.h" +#include "ntlm_compute.h" -#define WITH_DEBUG_NTLM +#include "ntlm_message.h" #define NTLMSSP_NEGOTIATE_56 0x80000000 /* W (0) */ #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000 /* V (1) */ @@ -239,6 +239,8 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* bu uint8* p; STREAM* s; int length; + char signature[8]; + uint32 messageType; uint8* start_offset; uint8* payload_offset; uint16 targetNameLen; @@ -251,6 +253,15 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* bu s = stream_new(0); stream_attach(s, buffer->pvBuffer, buffer->cbBuffer); + stream_read(s, signature, 8); + stream_read_uint32(s, messageType); + + if (memcmp(signature, NTLM_SIGNATURE, 8) != 0) + { + printf("Unexpected NTLM signature: %s, expected:%s\n", signature, NTLM_SIGNATURE); + return SEC_E_INVALID_TOKEN; + } + start_offset = s->p - 12; /* TargetNameFields (8 bytes) */ @@ -310,7 +321,7 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* bu if (context->ntlm_v2) { s->p = p; - //ntlm_input_av_pairs(context, s); + ntlm_input_av_pairs(context, s); } } @@ -325,11 +336,9 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* bu printf("\n"); #endif -#if 0 - /* AV_PAIRs */ if (context->ntlm_v2) - ntlmssp_populate_av_pairs(context); + ntlm_populate_av_pairs(context); /* Timestamp */ ntlm_generate_timestamp(context); @@ -337,12 +346,13 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* bu /* LmChallengeResponse */ ntlm_compute_lm_v2_response(context); - if ((context->ntlm_v2) && (context->LmChallengeResponse.cbBuffer > 0)) + if (context->ntlm_v2) memset(context->LmChallengeResponse.pvBuffer, 0, context->LmChallengeResponse.cbBuffer); /* NtChallengeResponse */ ntlm_compute_ntlm_v2_response(context); +#if 0 /* KeyExchangeKey */ ntlm_generate_key_exchange_key(context); @@ -400,7 +410,7 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* bu #endif - context->state = NTLMSSP_STATE_AUTHENTICATE; + context->state = NTLM_STATE_AUTHENTICATE; return SEC_I_CONTINUE_NEEDED; } diff --git a/libfreerdp-auth/NTLM/ntlm_message.h b/libfreerdp-auth/NTLM/ntlm_message.h index a7535642b..e3505e993 100644 --- a/libfreerdp-auth/NTLM/ntlm_message.h +++ b/libfreerdp-auth/NTLM/ntlm_message.h @@ -17,6 +17,12 @@ * limitations under the License. */ +#ifndef FREERDP_AUTH_NTLM_MESSAGE_H +#define FREERDP_AUTH_NTLM_MESSAGE_H + #include "ntlm.h" SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, SEC_BUFFER* buffer); +SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* buffer); + +#endif /* FREERDP_AUTH_NTLM_MESSAGE_H */ diff --git a/libfreerdp-auth/credssp.c b/libfreerdp-auth/credssp.c index 969595e27..706645f3f 100644 --- a/libfreerdp-auth/credssp.c +++ b/libfreerdp-auth/credssp.c @@ -300,8 +300,6 @@ int credssp_client_authenticate(rdpCredssp* credssp) p_sec_buffer = &output_sec_buffer_desc.pBuffers[0]; - freerdp_hexdump((uint8*) p_sec_buffer->pvBuffer, p_sec_buffer->cbBuffer); - credssp->negoToken.data = p_sec_buffer->pvBuffer; credssp->negoToken.length = p_sec_buffer->cbBuffer; From a795b9ced3564af8e3deff8ac5b7b21abcd3e495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sat, 25 Feb 2012 10:20:12 -0500 Subject: [PATCH 09/10] libfreerdp-auth: client signing and sealing --- libfreerdp-auth/NTLM/ntlm.h | 5 + libfreerdp-auth/NTLM/ntlm_compute.c | 217 ++++++++++++++++++++++++++++ libfreerdp-auth/NTLM/ntlm_compute.h | 14 ++ libfreerdp-auth/NTLM/ntlm_message.c | 3 - 4 files changed, 236 insertions(+), 3 deletions(-) diff --git a/libfreerdp-auth/NTLM/ntlm.h b/libfreerdp-auth/NTLM/ntlm.h index b0f360e32..fbb07e0f4 100644 --- a/libfreerdp-auth/NTLM/ntlm.h +++ b/libfreerdp-auth/NTLM/ntlm.h @@ -21,6 +21,7 @@ #define FREERDP_AUTH_NTLM_PRIVATE_H #include +#include #include @@ -79,7 +80,11 @@ struct _NTLM_CONTEXT boolean ntlm_v2; NTLM_STATE state; UNICONV* uniconv; + int send_seq_num; + int recv_seq_num; AV_PAIRS* av_pairs; + CryptoRc4 send_rc4_seal; + CryptoRc4 recv_rc4_seal; uint32 NegotiateFlags; uint16* Workstation; uint32 WorkstationLength; diff --git a/libfreerdp-auth/NTLM/ntlm_compute.c b/libfreerdp-auth/NTLM/ntlm_compute.c index e6840c91f..4aeabf3bf 100644 --- a/libfreerdp-auth/NTLM/ntlm_compute.c +++ b/libfreerdp-auth/NTLM/ntlm_compute.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,13 @@ const char* const AV_PAIRS_STRINGS[] = "MsvChannelBindings" }; +static const char lm_magic[] = "KGS!@#$%"; + +static const char client_sign_magic[] = "session key to client-to-server signing key magic constant"; +static const char server_sign_magic[] = "session key to server-to-client signing key magic constant"; +static const char client_seal_magic[] = "session key to client-to-server sealing key magic constant"; +static const char server_seal_magic[] = "session key to server-to-client sealing key magic constant"; + /** * Output Restriction_Encoding.\n * Restriction_Encoding @msdn{cc236647} @@ -663,3 +671,212 @@ void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) sspi_SecBufferFree(&ntlm_v2_temp); sspi_SecBufferFree(&ntlm_v2_temp_chal); } + +/** + * Encrypt the given plain text using RC4 and the given key. + * @param key RC4 key + * @param length text length + * @param plaintext plain text + * @param ciphertext cipher text + */ + +void ntlm_rc4k(uint8* key, int length, uint8* plaintext, uint8* ciphertext) +{ + CryptoRc4 rc4; + + /* Initialize RC4 cipher with key */ + rc4 = crypto_rc4_init((void*) key, 16); + + /* Encrypt plaintext with key */ + crypto_rc4(rc4, length, (void*) plaintext, (void*) ciphertext); + + /* Free RC4 Cipher */ + crypto_rc4_free(rc4); +} + +/** + * Generate client challenge (8-byte nonce). + * @param NTLM context + */ + +void ntlm_generate_client_challenge(NTLM_CONTEXT* context) +{ + /* ClientChallenge is used in computation of LMv2 and NTLMv2 responses */ + crypto_nonce(context->ClientChallenge, 8); +} + +/** + * Generate server challenge (8-byte nonce). + * @param NTLM context + */ + +void ntlm_generate_server_challenge(NTLM_CONTEXT* context) +{ + crypto_nonce(context->ServerChallenge, 8); +} + +/** + * Generate KeyExchangeKey (the 128-bit SessionBaseKey).\n + * @msdn{cc236710} + * @param NTLM context + */ + +void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context) +{ + /* In NTLMv2, KeyExchangeKey is the 128-bit SessionBaseKey */ + memcpy(context->KeyExchangeKey, context->SessionBaseKey, 16); +} + +/** + * Generate RandomSessionKey (16-byte nonce). + * @param NTLM context + */ + +void ntlm_generate_random_session_key(NTLM_CONTEXT* context) +{ + crypto_nonce(context->RandomSessionKey, 16); +} + +/** + * Generate ExportedSessionKey (the RandomSessionKey, exported) + * @param NTLM context + */ + +void ntlm_generate_exported_session_key(NTLM_CONTEXT* context) +{ + memcpy(context->ExportedSessionKey, context->RandomSessionKey, 16); +} + +/** + * Encrypt RandomSessionKey (RC4-encrypted RandomSessionKey, using KeyExchangeKey as the key). + * @param NTLM context + */ + +void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context) +{ + /* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the KeyExchangeKey */ + ntlm_rc4k(context->KeyExchangeKey, 16, context->RandomSessionKey, context->EncryptedRandomSessionKey); +} + +/** + * Generate signing key.\n + * @msdn{cc236711} + * @param exported_session_key ExportedSessionKey + * @param sign_magic Sign magic string + * @param signing_key Destination signing key + */ + +void ntlm_generate_signing_key(uint8* exported_session_key, SEC_BUFFER* sign_magic, uint8* signing_key) +{ + int length; + uint8* value; + CryptoMd5 md5; + + length = 16 + sign_magic->cbBuffer; + value = (uint8*) xmalloc(length); + + /* Concatenate ExportedSessionKey with sign magic */ + memcpy(value, exported_session_key, 16); + memcpy(&value[16], sign_magic->pvBuffer, sign_magic->cbBuffer); + + md5 = crypto_md5_init(); + crypto_md5_update(md5, value, length); + crypto_md5_final(md5, signing_key); + + xfree(value); +} + +/** + * Generate client signing key (ClientSigningKey).\n + * @msdn{cc236711} + * @param NTLM context + */ + +void ntlm_generate_client_signing_key(NTLM_CONTEXT* context) +{ + SEC_BUFFER sign_magic; + sign_magic.pvBuffer = (void*) client_sign_magic; + sign_magic.cbBuffer = sizeof(client_sign_magic); + ntlm_generate_signing_key(context->ExportedSessionKey, &sign_magic, context->ClientSigningKey); +} + +/** + * Generate server signing key (ServerSigningKey).\n + * @msdn{cc236711} + * @param NTLM context + */ + +void ntlm_generate_server_signing_key(NTLM_CONTEXT* context) +{ + SEC_BUFFER sign_magic; + sign_magic.pvBuffer = (void*) server_sign_magic; + sign_magic.cbBuffer = sizeof(server_sign_magic); + ntlm_generate_signing_key(context->ExportedSessionKey, &sign_magic, context->ServerSigningKey); +} + +/** + * Generate sealing key.\n + * @msdn{cc236712} + * @param exported_session_key ExportedSessionKey + * @param seal_magic Seal magic string + * @param sealing_key Destination sealing key + */ + +void ntlm_generate_sealing_key(uint8* exported_session_key, SEC_BUFFER* seal_magic, uint8* sealing_key) +{ + uint8* p; + CryptoMd5 md5; + SEC_BUFFER buffer; + + sspi_SecBufferAlloc(&buffer, 16 + seal_magic->cbBuffer); + p = (uint8*) buffer.pvBuffer; + + /* Concatenate ExportedSessionKey with seal magic */ + memcpy(p, exported_session_key, 16); + memcpy(&p[16], seal_magic->pvBuffer, seal_magic->cbBuffer); + + md5 = crypto_md5_init(); + crypto_md5_update(md5, buffer.pvBuffer, buffer.cbBuffer); + crypto_md5_final(md5, sealing_key); + + sspi_SecBufferFree(&buffer); +} + +/** + * Generate client sealing key (ClientSealingKey).\n + * @msdn{cc236712} + * @param NTLM context + */ + +void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context) +{ + SEC_BUFFER seal_magic; + seal_magic.pvBuffer = (void*) client_seal_magic; + seal_magic.cbBuffer = sizeof(client_seal_magic); + ntlm_generate_signing_key(context->ExportedSessionKey, &seal_magic, context->ClientSealingKey); +} + +/** + * Generate server sealing key (ServerSealingKey).\n + * @msdn{cc236712} + * @param NTLM context + */ + +void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context) +{ + SEC_BUFFER seal_magic; + seal_magic.pvBuffer = (void*) server_seal_magic; + seal_magic.cbBuffer = sizeof(server_seal_magic); + ntlm_generate_signing_key(context->ExportedSessionKey, &seal_magic, context->ServerSealingKey); +} + +/** + * Initialize RC4 stream cipher states for sealing. + * @param NTLM context + */ + +void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context) +{ + context->send_rc4_seal = crypto_rc4_init(context->ClientSealingKey, 16); + context->recv_rc4_seal = crypto_rc4_init(context->ServerSealingKey, 16); +} diff --git a/libfreerdp-auth/NTLM/ntlm_compute.h b/libfreerdp-auth/NTLM/ntlm_compute.h index 5b484d555..fc4e78b3c 100644 --- a/libfreerdp-auth/NTLM/ntlm_compute.h +++ b/libfreerdp-auth/NTLM/ntlm_compute.h @@ -40,5 +40,19 @@ void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash); void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context); void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context); +void ntlm_rc4k(uint8* key, int length, uint8* plaintext, uint8* ciphertext); +void ntlm_generate_client_challenge(NTLM_CONTEXT* context); +void ntlm_generate_server_challenge(NTLM_CONTEXT* context); +void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context); +void ntlm_generate_random_session_key(NTLM_CONTEXT* context); +void ntlm_generate_exported_session_key(NTLM_CONTEXT* context); +void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context); + +void ntlm_generate_client_signing_key(NTLM_CONTEXT* context); +void ntlm_generate_server_signing_key(NTLM_CONTEXT* context); +void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context); +void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context); +void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context); + #endif /* FREERDP_AUTH_NTLM_COMPUTE_H */ diff --git a/libfreerdp-auth/NTLM/ntlm_message.c b/libfreerdp-auth/NTLM/ntlm_message.c index 96b094fda..ec5e13b64 100644 --- a/libfreerdp-auth/NTLM/ntlm_message.c +++ b/libfreerdp-auth/NTLM/ntlm_message.c @@ -352,7 +352,6 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* bu /* NtChallengeResponse */ ntlm_compute_ntlm_v2_response(context); -#if 0 /* KeyExchangeKey */ ntlm_generate_key_exchange_key(context); @@ -406,8 +405,6 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* bu printf("Timestamp\n"); freerdp_hexdump(context->Timestamp, 8); printf("\n"); -#endif - #endif context->state = NTLM_STATE_AUTHENTICATE; From b723baf2af6c58ac82afdfe88c298bcef90efcb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sat, 25 Feb 2012 11:48:08 -0500 Subject: [PATCH 10/10] libfreerdp-auth: started authenticate message --- libfreerdp-auth/NTLM/ntlm.c | 24 ++- libfreerdp-auth/NTLM/ntlm_compute.c | 17 ++ libfreerdp-auth/NTLM/ntlm_compute.h | 2 + libfreerdp-auth/NTLM/ntlm_message.c | 261 ++++++++++++++++++++++++++++ libfreerdp-auth/NTLM/ntlm_message.h | 1 + libfreerdp-auth/credssp.c | 29 +++- 6 files changed, 329 insertions(+), 5 deletions(-) diff --git a/libfreerdp-auth/NTLM/ntlm.c b/libfreerdp-auth/NTLM/ntlm.c index 2582ac055..dd32c0964 100644 --- a/libfreerdp-auth/NTLM/ntlm.c +++ b/libfreerdp-auth/NTLM/ntlm.c @@ -181,7 +181,9 @@ SECURITY_STATUS ntlm_InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_H SEC_BUFFER* sec_buffer; CREDENTIALS* credentials; - if (!pInput) + context = sspi_SecureHandleGetLowerPointer(phContext); + + if (!context) { context = ntlm_ContextNew(); @@ -190,6 +192,11 @@ SECURITY_STATUS ntlm_InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_H ntlm_SetContextIdentity(context, &credentials->identity); ntlm_SetContextWorkstation(context, "WORKSTATION"); + sspi_SecureHandleSetLowerPointer(phNewContext, context); + } + + if ((!pInput) || (context->state == NTLM_STATE_AUTHENTICATE)) + { if (!pOutput) return SEC_E_INVALID_TOKEN; @@ -204,9 +211,15 @@ SECURITY_STATUS ntlm_InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_H if (sec_buffer->cbBuffer < 1) return SEC_E_INSUFFICIENT_MEMORY; - sspi_SecureHandleSetLowerPointer(phNewContext, context); + if (context->state == NTLM_STATE_INITIAL) + context->state = NTLM_STATE_NEGOTIATE; - return ntlm_write_NegotiateMessage(context, sec_buffer); + if (context->state == NTLM_STATE_NEGOTIATE) + return ntlm_write_NegotiateMessage(context, sec_buffer); + else if (context->state == NTLM_STATE_AUTHENTICATE) + return ntlm_write_AuthenticateMessage(context, sec_buffer); + + return SEC_E_OUT_OF_SEQUENCE; } else { @@ -229,7 +242,10 @@ SECURITY_STATUS ntlm_InitializeSecurityContext(CRED_HANDLE* phCredential, CTXT_H if (sec_buffer->cbBuffer < 1) return SEC_E_INVALID_TOKEN; - return ntlm_read_ChallengeMessage(context, sec_buffer); + if (context->state == NTLM_STATE_CHALLENGE) + return ntlm_read_ChallengeMessage(context, sec_buffer); + + return SEC_E_OUT_OF_SEQUENCE; } return SEC_E_OK; diff --git a/libfreerdp-auth/NTLM/ntlm_compute.c b/libfreerdp-auth/NTLM/ntlm_compute.c index 4aeabf3bf..2ce267107 100644 --- a/libfreerdp-auth/NTLM/ntlm_compute.c +++ b/libfreerdp-auth/NTLM/ntlm_compute.c @@ -880,3 +880,20 @@ void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context) context->send_rc4_seal = crypto_rc4_init(context->ClientSealingKey, 16); context->recv_rc4_seal = crypto_rc4_init(context->ServerSealingKey, 16); } + +void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context) +{ + HMAC_CTX hmac_ctx; + + /* + * Compute the HMAC-MD5 hash of ConcatenationOf(NEGOTIATE_MESSAGE, + * CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE) using the ExportedSessionKey + */ + + HMAC_CTX_init(&hmac_ctx); + HMAC_Init_ex(&hmac_ctx, context->ExportedSessionKey, 16, EVP_md5(), NULL); + HMAC_Update(&hmac_ctx, context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer); + HMAC_Update(&hmac_ctx, context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer); + HMAC_Update(&hmac_ctx, context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer); + HMAC_Final(&hmac_ctx, context->MessageIntegrityCheck, NULL); +} diff --git a/libfreerdp-auth/NTLM/ntlm_compute.h b/libfreerdp-auth/NTLM/ntlm_compute.h index fc4e78b3c..40ca6b2f2 100644 --- a/libfreerdp-auth/NTLM/ntlm_compute.h +++ b/libfreerdp-auth/NTLM/ntlm_compute.h @@ -54,5 +54,7 @@ void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context); void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context); void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context); +void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context); + #endif /* FREERDP_AUTH_NTLM_COMPUTE_H */ diff --git a/libfreerdp-auth/NTLM/ntlm_message.c b/libfreerdp-auth/NTLM/ntlm_message.c index ec5e13b64..dbf43b4d3 100644 --- a/libfreerdp-auth/NTLM/ntlm_message.c +++ b/libfreerdp-auth/NTLM/ntlm_message.c @@ -411,3 +411,264 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* bu return SEC_I_CONTINUE_NEEDED; } + +/** + * Send NTLMSSP AUTHENTICATE_MESSAGE.\n + * AUTHENTICATE_MESSAGE @msdn{cc236643} + * @param NTLM context + * @param buffer + */ + +SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, SEC_BUFFER* buffer) +{ + STREAM* s; + int length; + uint8* mic_offset = NULL; + uint32 negotiateFlags = 0; + + uint16 DomainNameLen; + uint16 UserNameLen; + uint16 WorkstationLen; + uint16 LmChallengeResponseLen; + uint16 NtChallengeResponseLen; + uint16 EncryptedRandomSessionKeyLen; + + uint32 PayloadBufferOffset; + uint32 DomainNameBufferOffset; + uint32 UserNameBufferOffset; + uint32 WorkstationBufferOffset; + uint32 LmChallengeResponseBufferOffset; + uint32 NtChallengeResponseBufferOffset; + uint32 EncryptedRandomSessionKeyBufferOffset; + + uint8* UserNameBuffer; + uint8* DomainNameBuffer; + uint8* WorkstationBuffer; + uint8* EncryptedRandomSessionKeyBuffer; + + WorkstationLen = context->WorkstationLength; + WorkstationBuffer = (uint8*) context->Workstation; + + s = stream_new(0); + stream_attach(s, buffer->pvBuffer, buffer->cbBuffer); + + if (context->ntlm_v2 < 1) + WorkstationLen = 0; + + DomainNameLen = context->identity.DomainLength; + DomainNameBuffer = (uint8*) context->identity.Domain; + + UserNameLen = context->identity.UserLength; + UserNameBuffer = (uint8*) context->identity.User; + + LmChallengeResponseLen = context->LmChallengeResponse.cbBuffer; + NtChallengeResponseLen = context->NtChallengeResponse.cbBuffer; + + EncryptedRandomSessionKeyLen = 16; + EncryptedRandomSessionKeyBuffer = context->EncryptedRandomSessionKey; + + if (context->ntlm_v2) + { + /* observed: 35 82 88 e2 (0xE2888235) */ + negotiateFlags |= NTLMSSP_NEGOTIATE_56; + negotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH; + negotiateFlags |= NTLMSSP_NEGOTIATE_128; + negotiateFlags |= NTLMSSP_NEGOTIATE_VERSION; + negotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO; + negotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY; + negotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; + negotiateFlags |= NTLMSSP_NEGOTIATE_NTLM; + negotiateFlags |= NTLMSSP_NEGOTIATE_SEAL; + negotiateFlags |= NTLMSSP_NEGOTIATE_SIGN; + negotiateFlags |= NTLMSSP_REQUEST_TARGET; + negotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE; + } + else + { + negotiateFlags |= NTLMSSP_NEGOTIATE_KEY_EXCH; + negotiateFlags |= NTLMSSP_NEGOTIATE_128; + negotiateFlags |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY; + negotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; + negotiateFlags |= NTLMSSP_NEGOTIATE_NTLM; + negotiateFlags |= NTLMSSP_NEGOTIATE_SEAL; + negotiateFlags |= NTLMSSP_NEGOTIATE_SIGN; + negotiateFlags |= NTLMSSP_REQUEST_TARGET; + negotiateFlags |= NTLMSSP_NEGOTIATE_UNICODE; + } + + if (context->ntlm_v2) + PayloadBufferOffset = 80; /* starting buffer offset */ + else + PayloadBufferOffset = 64; /* starting buffer offset */ + + if (negotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + PayloadBufferOffset += 8; + + DomainNameBufferOffset = PayloadBufferOffset; + UserNameBufferOffset = DomainNameBufferOffset + DomainNameLen; + WorkstationBufferOffset = UserNameBufferOffset + UserNameLen; + LmChallengeResponseBufferOffset = WorkstationBufferOffset + WorkstationLen; + NtChallengeResponseBufferOffset = LmChallengeResponseBufferOffset + LmChallengeResponseLen; + EncryptedRandomSessionKeyBufferOffset = NtChallengeResponseBufferOffset + NtChallengeResponseLen; + + stream_write(s, NTLM_SIGNATURE, 8); /* Signature (8 bytes) */ + stream_write_uint32(s, MESSAGE_TYPE_AUTHENTICATE); /* MessageType */ + + /* LmChallengeResponseFields (8 bytes) */ + stream_write_uint16(s, LmChallengeResponseLen); /* LmChallengeResponseLen */ + stream_write_uint16(s, LmChallengeResponseLen); /* LmChallengeResponseMaxLen */ + stream_write_uint32(s, LmChallengeResponseBufferOffset); /* LmChallengeResponseBufferOffset */ + + /* NtChallengeResponseFields (8 bytes) */ + stream_write_uint16(s, NtChallengeResponseLen); /* NtChallengeResponseLen */ + stream_write_uint16(s, NtChallengeResponseLen); /* NtChallengeResponseMaxLen */ + stream_write_uint32(s, NtChallengeResponseBufferOffset); /* NtChallengeResponseBufferOffset */ + + /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ + + /* DomainNameFields (8 bytes) */ + stream_write_uint16(s, DomainNameLen); /* DomainNameLen */ + stream_write_uint16(s, DomainNameLen); /* DomainNameMaxLen */ + stream_write_uint32(s, DomainNameBufferOffset); /* DomainNameBufferOffset */ + + /* UserNameFields (8 bytes) */ + stream_write_uint16(s, UserNameLen); /* UserNameLen */ + stream_write_uint16(s, UserNameLen); /* UserNameMaxLen */ + stream_write_uint32(s, UserNameBufferOffset); /* UserNameBufferOffset */ + + /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ + + /* WorkstationFields (8 bytes) */ + stream_write_uint16(s, WorkstationLen); /* WorkstationLen */ + stream_write_uint16(s, WorkstationLen); /* WorkstationMaxLen */ + stream_write_uint32(s, WorkstationBufferOffset); /* WorkstationBufferOffset */ + + /* EncryptedRandomSessionKeyFields (8 bytes) */ + stream_write_uint16(s, EncryptedRandomSessionKeyLen); /* EncryptedRandomSessionKeyLen */ + stream_write_uint16(s, EncryptedRandomSessionKeyLen); /* EncryptedRandomSessionKeyMaxLen */ + stream_write_uint32(s, EncryptedRandomSessionKeyBufferOffset); /* EncryptedRandomSessionKeyBufferOffset */ + + stream_write_uint32(s, negotiateFlags); /* NegotiateFlags (4 bytes) */ + +#ifdef WITH_DEBUG_NTLM + ntlm_print_negotiate_flags(negotiateFlags); +#endif + + if (negotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + { + /* Only present if NTLMSSP_NEGOTIATE_VERSION is set */ + ntlm_output_version(s); + +#ifdef WITH_DEBUG_NTLM + printf("Version (length = 8)\n"); + freerdp_hexdump((s->p - 8), 8); + printf("\n"); +#endif + } + + if (context->ntlm_v2) + { + /* Message Integrity Check */ + mic_offset = s->p; + stream_write_zero(s, 16); + } + + /* DomainName */ + if (DomainNameLen > 0) + { + stream_write(s, DomainNameBuffer, DomainNameLen); +#ifdef WITH_DEBUG_NTLM + printf("DomainName (length = %d, offset = %d)\n", DomainNameLen, DomainNameBufferOffset); + freerdp_hexdump(DomainNameBuffer, DomainNameLen); + printf("\n"); +#endif + } + + /* UserName */ + stream_write(s, UserNameBuffer, UserNameLen); + +#ifdef WITH_DEBUG_NTLM + printf("UserName (length = %d, offset = %d)\n", UserNameLen, UserNameBufferOffset); + freerdp_hexdump(UserNameBuffer, UserNameLen); + printf("\n"); +#endif + + /* Workstation */ + if (WorkstationLen > 0) + { + stream_write(s, WorkstationBuffer, WorkstationLen); +#ifdef WITH_DEBUG_NTLM + printf("Workstation (length = %d, offset = %d)\n", WorkstationLen, WorkstationBufferOffset); + freerdp_hexdump(WorkstationBuffer, WorkstationLen); + printf("\n"); +#endif + } + + /* LmChallengeResponse */ + stream_write(s, context->LmChallengeResponse.pvBuffer, LmChallengeResponseLen); + +#ifdef WITH_DEBUG_NTLM + printf("LmChallengeResponse (length = %d, offset = %d)\n", LmChallengeResponseLen, LmChallengeResponseBufferOffset); + freerdp_hexdump(context->LmChallengeResponse.pvBuffer, LmChallengeResponseLen); + printf("\n"); +#endif + + /* NtChallengeResponse */ + stream_write(s, context->NtChallengeResponse.pvBuffer, NtChallengeResponseLen); + +#ifdef WITH_DEBUG_NTLM + if (context->ntlm_v2) + { + ntlm_print_av_pairs(context); + + printf("targetInfo (length = %d)\n", context->TargetInfo.cbBuffer); + freerdp_hexdump(context->TargetInfo.pvBuffer, context->TargetInfo.cbBuffer); + printf("\n"); + } +#endif + +#ifdef WITH_DEBUG_NTLM + printf("NtChallengeResponse (length = %d, offset = %d)\n", NtChallengeResponseLen, NtChallengeResponseBufferOffset); + freerdp_hexdump(context->NtChallengeResponse.pvBuffer, NtChallengeResponseLen); + printf("\n"); +#endif + + /* EncryptedRandomSessionKey */ + stream_write(s, EncryptedRandomSessionKeyBuffer, EncryptedRandomSessionKeyLen); + +#ifdef WITH_DEBUG_NTLM + printf("EncryptedRandomSessionKey (length = %d, offset = %d)\n", EncryptedRandomSessionKeyLen, EncryptedRandomSessionKeyBufferOffset); + freerdp_hexdump(EncryptedRandomSessionKeyBuffer, EncryptedRandomSessionKeyLen); + printf("\n"); +#endif + + length = s->p - s->data; + sspi_SecBufferAlloc(&context->AuthenticateMessage, length); + memcpy(context->AuthenticateMessage.pvBuffer, s->data, length); + + if (context->ntlm_v2) + { + /* Message Integrity Check */ + ntlm_compute_message_integrity_check(context); + + s->p = mic_offset; + stream_write(s, context->MessageIntegrityCheck, 16); + s->p = s->data + length; + +#ifdef WITH_DEBUG_NTLM + printf("MessageIntegrityCheck (length = 16)\n"); + freerdp_hexdump(mic_offset, 16); + printf("\n"); +#endif + } + +#ifdef WITH_DEBUG_NTLM + printf("AUTHENTICATE_MESSAGE (length = %d)\n", length); + freerdp_hexdump(s->data, length); + printf("\n"); +#endif + + context->state = NTLM_STATE_FINAL; + + return SEC_I_COMPLETE_NEEDED; +} diff --git a/libfreerdp-auth/NTLM/ntlm_message.h b/libfreerdp-auth/NTLM/ntlm_message.h index e3505e993..7f9b19b33 100644 --- a/libfreerdp-auth/NTLM/ntlm_message.h +++ b/libfreerdp-auth/NTLM/ntlm_message.h @@ -24,5 +24,6 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, SEC_BUFFER* buffer); SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, SEC_BUFFER* buffer); +SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, SEC_BUFFER* buffer); #endif /* FREERDP_AUTH_NTLM_MESSAGE_H */ diff --git a/libfreerdp-auth/credssp.c b/libfreerdp-auth/credssp.c index 706645f3f..a1938a7d0 100644 --- a/libfreerdp-auth/credssp.c +++ b/libfreerdp-auth/credssp.c @@ -318,8 +318,8 @@ int credssp_client_authenticate(rdpCredssp* credssp) input_sec_buffer_desc.cBuffers = 1; input_sec_buffer_desc.pBuffers = &input_sec_buffer; - input_sec_buffer.cbBuffer = credssp->negoToken.length; input_sec_buffer.BufferType = SECBUFFER_TOKEN; + input_sec_buffer.cbBuffer = credssp->negoToken.length; input_sec_buffer.pvBuffer = credssp->negoToken.data; output_sec_buffer_desc.ulVersion = 0; @@ -341,6 +341,33 @@ int credssp_client_authenticate(rdpCredssp* credssp) return 0; } + input_sec_buffer_desc.ulVersion = 0; + input_sec_buffer_desc.cBuffers = 1; + input_sec_buffer_desc.pBuffers = &input_sec_buffer; + + input_sec_buffer.BufferType = SECBUFFER_TOKEN; + input_sec_buffer.cbBuffer = output_sec_buffer_desc.pBuffers[0].cbBuffer; + input_sec_buffer.pvBuffer = output_sec_buffer_desc.pBuffers[0].pvBuffer; + + output_sec_buffer_desc.ulVersion = 0; + output_sec_buffer_desc.cBuffers = 1; + output_sec_buffer_desc.pBuffers = &output_sec_buffer; + + output_sec_buffer.BufferType = SECBUFFER_TOKEN; + output_sec_buffer.cbBuffer = credssp->negoToken.length; + output_sec_buffer.pvBuffer = credssp->negoToken.data; + + printf("Third Call to InitializeSecurityContext()\n"); + + status = table->InitializeSecurityContext(&credentials, &context, NULL, fContextReq, 0, 0, + &input_sec_buffer_desc, 0, &context, &output_sec_buffer_desc, &pfContextAttr, &expiration); + + if (status != SEC_I_COMPLETE_NEEDED) + { + printf("InitializeSecurityContext status: 0x%08X\n", status); + return 0; + } + FreeCredentialsHandle(&credentials); FreeContextBuffer(pPackageInfo);