/* * Copyright 2005 Kai Blin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * This file implements the NTLM security provider. * FIXME: So far, this beast doesn't do anything. */ #include #include #include "windef.h" #include "winbase.h" #include "sspi.h" #include "secur32_priv.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(secur32); static char ntlm_name_A[] = "NTLM"; static WCHAR ntlm_name_W[] = {'N', 'T', 'L', 'M', 0}; /*********************************************************************** * QueryCredentialsAttributesA */ static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesA( PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer) { SECURITY_STATUS ret; TRACE("(%p, %ld, %p)\n", phCredential, ulAttribute, pBuffer); if(ulAttribute == SECPKG_ATTR_NAMES) { FIXME("SECPKG_CRED_ATTR_NAMES: stub\n"); ret = SEC_E_UNSUPPORTED_FUNCTION; } else ret = SEC_E_UNSUPPORTED_FUNCTION; return ret; } /*********************************************************************** * QueryCredentialsAttributesW */ static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW( PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer) { SECURITY_STATUS ret; TRACE("(%p, %ld, %p)\n", phCredential, ulAttribute, pBuffer); if(ulAttribute == SECPKG_ATTR_NAMES) { FIXME("SECPKG_CRED_ATTR_NAMES: stub\n"); ret = SEC_E_UNSUPPORTED_FUNCTION; } else ret = SEC_E_UNSUPPORTED_FUNCTION; return ret; } static SECURITY_STATUS ntlm_AcquireCredentialsHandle(ULONG fCredentialsUse, PCredHandle phCredential, PTimeStamp ptsExpiry) { SECURITY_STATUS ret; if(fCredentialsUse == SECPKG_CRED_BOTH) { ret = SEC_E_NO_CREDENTIALS; } else { /* Ok, just store the direction like schannel does for now. * FIXME: This should probably do something useful later on */ phCredential->dwUpper = fCredentialsUse; phCredential->dwLower = 0; /* Same here, shamelessly stolen from schannel.c */ if (ptsExpiry) ptsExpiry->QuadPart = 0; ret = SEC_E_OK; } return ret; } /*********************************************************************** * AcquireCredentialsHandleA */ static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA( SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse, PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) { TRACE("(%s, %s, 0x%08lx, %p, %p, %p, %p, %p, %p)\n", debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse, pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); return ntlm_AcquireCredentialsHandle(fCredentialUse, phCredential, ptsExpiry); } /*********************************************************************** * AcquireCredentialsHandleW */ static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW( SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse, PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn, PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry) { TRACE("(%s, %s, 0x%08lx, %p, %p, %p, %p, %p, %p)\n", debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse, pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry); return ntlm_AcquireCredentialsHandle(fCredentialUse, phCredential, ptsExpiry); } /*********************************************************************** * InitializeSecurityContextA */ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA( PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) { SECURITY_STATUS ret; TRACE("%p %p %s %ld %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext, debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); if(phCredential){ ret = SEC_E_UNSUPPORTED_FUNCTION; } else { ret = SEC_E_INVALID_HANDLE; } return ret; } /*********************************************************************** * InitializeSecurityContextW */ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, PSecBufferDesc pInput,ULONG Reserved2, PCtxtHandle phNewContext, PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) { SECURITY_STATUS ret; TRACE("%p %p %s %ld %ld %ld %p %ld %p %p %p %p\n", phCredential, phContext, debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput, Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry); if (phCredential) { ret = SEC_E_UNSUPPORTED_FUNCTION; } else { ret = SEC_E_INVALID_HANDLE; } return ret; } /*********************************************************************** * AcceptSecurityContext */ static SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext( PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput, ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext, PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry) { SECURITY_STATUS ret; TRACE("%p %p %p %ld %ld %p %p %p %p\n", phCredential, phContext, pInput, fContextReq, TargetDataRep, phNewContext, pOutput, pfContextAttr, ptsExpiry); if (phCredential) { ret = SEC_E_UNSUPPORTED_FUNCTION; } else { ret = SEC_E_INVALID_HANDLE; } return ret; } /*********************************************************************** * CompleteAuthToken */ static SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext, PSecBufferDesc pToken) { SECURITY_STATUS ret; TRACE("%p %p\n", phContext, pToken); if (phContext) { ret = SEC_E_UNSUPPORTED_FUNCTION; } else { ret = SEC_E_INVALID_HANDLE; } return ret; } /*********************************************************************** * DeleteSecurityContext */ static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext) { SECURITY_STATUS ret; TRACE("%p\n", phContext); if (phContext) { ret = SEC_E_UNSUPPORTED_FUNCTION; } else { ret = SEC_E_INVALID_HANDLE; } return ret; } /*********************************************************************** * ApplyControlToken */ static SECURITY_STATUS SEC_ENTRY ntlm_ApplyControlToken(PCtxtHandle phContext, PSecBufferDesc pInput) { SECURITY_STATUS ret; TRACE("%p %p\n", phContext, pInput); if (phContext) { ret = SEC_E_UNSUPPORTED_FUNCTION; } else { ret = SEC_E_INVALID_HANDLE; } return ret; } /*********************************************************************** * QueryContextAttributesW */ static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, unsigned long ulAttribute, void *pBuffer) { SECURITY_STATUS ret; /* FIXME: From reading wrapper.h, I think the dwUpper part of a context is * the SecurePackage part and the dwLower part is the actual context * handle. It should be easy to extract the context attributes from that. */ TRACE("%p %ld %p\n", phContext, ulAttribute, pBuffer); if (phContext) { ret = SEC_E_UNSUPPORTED_FUNCTION; } else { ret = SEC_E_INVALID_HANDLE; } return ret; } /*********************************************************************** * QueryContextAttributesA */ static SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext, unsigned long ulAttribute, void *pBuffer) { return ntlm_QueryContextAttributesW(phContext, ulAttribute, pBuffer); } /*********************************************************************** * ImpersonateSecurityContext */ static SECURITY_STATUS SEC_ENTRY ntlm_ImpersonateSecurityContext(PCtxtHandle phContext) { SECURITY_STATUS ret; TRACE("%p\n", phContext); if (phContext) { ret = SEC_E_UNSUPPORTED_FUNCTION; } else { ret = SEC_E_INVALID_HANDLE; } return ret; } /*********************************************************************** * RevertSecurityContext */ static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext) { SECURITY_STATUS ret; TRACE("%p\n", phContext); if (phContext) { ret = SEC_E_UNSUPPORTED_FUNCTION; } else { ret = SEC_E_INVALID_HANDLE; } return ret; } /*********************************************************************** * MakeSignature */ static SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo) { SECURITY_STATUS ret; TRACE("%p %ld %p %ld\n", phContext, fQOP, pMessage, MessageSeqNo); if (phContext) { ret = SEC_E_UNSUPPORTED_FUNCTION; } else { ret = SEC_E_INVALID_HANDLE; } return ret; } /*********************************************************************** * VerifySignature */ static SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP) { SECURITY_STATUS ret; TRACE("%p %p %ld %p\n", phContext, pMessage, MessageSeqNo, pfQOP); if (phContext) { ret = SEC_E_UNSUPPORTED_FUNCTION; } else { ret = SEC_E_INVALID_HANDLE; } return ret; } static SecurityFunctionTableA negoTableA = { 1, NULL, /* EnumerateSecurityPackagesA */ ntlm_QueryCredentialsAttributesA, /* QueryCredentialsAttributesA */ ntlm_AcquireCredentialsHandleA, /* AcquireCredentialsHandleA */ FreeCredentialsHandle, /* FreeCredentialsHandle */ NULL, /* Reserved2 */ ntlm_InitializeSecurityContextA, /* InitializeSecurityContextA */ ntlm_AcceptSecurityContext, /* AcceptSecurityContext */ ntlm_CompleteAuthToken, /* CompleteAuthToken */ ntlm_DeleteSecurityContext, /* DeleteSecurityContext */ ntlm_ApplyControlToken, /* ApplyControlToken */ ntlm_QueryContextAttributesA, /* QueryContextAttributesA */ ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ ntlm_RevertSecurityContext, /* RevertSecurityContext */ ntlm_MakeSignature, /* MakeSignature */ ntlm_VerifySignature, /* VerifySignature */ FreeContextBuffer, /* FreeContextBuffer */ NULL, /* QuerySecurityPackageInfoA */ NULL, /* Reserved3 */ NULL, /* Reserved4 */ NULL, /* ExportSecurityContext */ NULL, /* ImportSecurityContextA */ NULL, /* AddCredentialsA */ NULL, /* Reserved8 */ NULL, /* QuerySecurityContextToken */ NULL, /* EncryptMessage */ NULL, /* DecryptMessage */ NULL, /* SetContextAttributesA */ }; static SecurityFunctionTableW negoTableW = { 1, NULL, /* EnumerateSecurityPackagesW */ ntlm_QueryCredentialsAttributesW, /* QueryCredentialsAttributesW */ ntlm_AcquireCredentialsHandleW, /* AcquireCredentialsHandleW */ FreeCredentialsHandle, /* FreeCredentialsHandle */ NULL, /* Reserved2 */ ntlm_InitializeSecurityContextW, /* InitializeSecurityContextW */ ntlm_AcceptSecurityContext, /* AcceptSecurityContext */ ntlm_CompleteAuthToken, /* CompleteAuthToken */ ntlm_DeleteSecurityContext, /* DeleteSecurityContext */ ntlm_ApplyControlToken, /* ApplyControlToken */ ntlm_QueryContextAttributesW, /* QueryContextAttributesW */ ntlm_ImpersonateSecurityContext, /* ImpersonateSecurityContext */ ntlm_RevertSecurityContext, /* RevertSecurityContext */ ntlm_MakeSignature, /* MakeSignature */ ntlm_VerifySignature, /* VerifySignature */ FreeContextBuffer, /* FreeContextBuffer */ NULL, /* QuerySecurityPackageInfoW */ NULL, /* Reserved3 */ NULL, /* Reserved4 */ NULL, /* ExportSecurityContext */ NULL, /* ImportSecurityContextW */ NULL, /* AddCredentialsW */ NULL, /* Reserved8 */ NULL, /* QuerySecurityContextToken */ NULL, /* EncryptMessage */ NULL, /* DecryptMessage */ NULL, /* SetContextAttributesW */ }; static WCHAR ntlm_comment_W[] = { 'N', 'T', 'L', 'M', ' ', 'S', 'e', 'c', 'u', 'r', 'i', 't', 'y', ' ', 'P', 'a', 'c', 'k', 'a', 'g', 'e',0}; static CHAR ntlm_comment_A[] = "NTLM Security Package"; void SECUR32_initNTLMSP(void) { SecureProvider *provider = SECUR32_addProvider(&negoTableA, &negoTableW, NULL); /* According to Windows, NTLM has the following capabilities. */ static const LONG caps = SECPKG_FLAG_INTEGRITY | SECPKG_FLAG_PRIVACY | SECPKG_FLAG_TOKEN_ONLY | SECPKG_FLAG_CONNECTION | SECPKG_FLAG_MULTI_REQUIRED | SECPKG_FLAG_IMPERSONATION | SECPKG_FLAG_ACCEPT_WIN32_NAME | SECPKG_FLAG_READONLY_WITH_CHECKSUM; static const USHORT version = 1; static const USHORT rpcid = 10; static const ULONG max_token = 12000; const SecPkgInfoW infoW = { caps, version, rpcid, max_token, ntlm_name_W, ntlm_comment_W}; const SecPkgInfoA infoA = { caps, version, rpcid, max_token, ntlm_name_A, ntlm_comment_A}; SECUR32_addPackages(provider, 1L, &infoA, &infoW); }