/* * Author: NoMachine * Copyright (c) 2009, 2013 NoMachine * All rights reserved * * Author: Manoj Ampalam * Simplified code to just perform local user logon * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS intERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define WINVER 0x501 #define UMDF_USING_NTSTATUS #include #define SECURITY_WIN32 #include #include #include #include #include #include "..\misc_internal.h" #define Unsigned unsigned #define Char char #define Int int #define Long long #define Not(value) ((value) == 0) #define PKG_NAME "SSH-LSA" #define PKG_NAME_SIZE sizeof(PKG_NAME) #define MAX_ACCOUNT_NAME_SIZE (256 * 2) #define VERSION "4.0.346" typedef VOID(WINAPI *RtlInitUnicodeStringPtr) (PUNICODE_STRING, PCWSTR SourceString); #define FAIL(CONDITION) if(CONDITION) goto fail #define NTFAIL(NTFUNC) if((ntStat = (NTFUNC))) goto fail RtlInitUnicodeStringPtr RtlInitUnicodeString = NULL; HMODULE NtDll = NULL; LSA_SECPKG_FUNCTION_TABLE LsaApi; NTSTATUS LsaAllocUnicodeString(PUNICODE_STRING *lsaStr, USHORT maxLen) { NTSTATUS ntStat = STATUS_NO_MEMORY; FAIL(lsaStr == NULL); *lsaStr = (PUNICODE_STRING)LsaApi.AllocateLsaHeap(sizeof(UNICODE_STRING)); FAIL((*lsaStr) == NULL); (*lsaStr)->Buffer = (WCHAR *)LsaApi.AllocateLsaHeap(sizeof(maxLen)); (*lsaStr)->Length = 0; (*lsaStr)->MaximumLength = maxLen; FAIL((*lsaStr)->Buffer == NULL); ntStat = 0; fail: if (ntStat) { if (lsaStr && (*lsaStr)) { LsaApi.FreeLsaHeap((*lsaStr)->Buffer); LsaApi.FreeLsaHeap((*lsaStr)); } } return ntStat; } void LsaFreeUnicodeString(PUNICODE_STRING lsaStr) { if (lsaStr) { if (lsaStr->Buffer) LsaApi.FreeLsaHeap(lsaStr->Buffer); LsaApi.FreeLsaHeap(lsaStr); } } NTSTATUS FillUnicodeString(UNICODE_STRING *lsaStr, const Char *str) { NTSTATUS ntStat = STATUS_NO_MEMORY; size_t cbSize = 0; FAIL(lsaStr == NULL); FAIL(lsaStr->Buffer == NULL); FAIL(str == NULL); cbSize = strlen(str); FAIL(cbSize >= lsaStr->MaximumLength); _swprintf(lsaStr->Buffer, L"%hs", str); lsaStr->Length = (USHORT)(cbSize * 2); lsaStr->Buffer[cbSize * 2] = 0x0000; ntStat = STATUS_SUCCESS; fail: return ntStat; } NTSTATUS NTAPI LsaApCallPackagePassthrough(PLSA_CLIENT_REQUEST request, PVOID submitBuf, PVOID clientBufBase, ULONG submitBufSize, PVOID *outBuf, PULONG outBufSize, PNTSTATUS status) { return STATUS_NOT_IMPLEMENTED; } NTSTATUS NTAPI LsaApCallPackageUntrusted(PLSA_CLIENT_REQUEST request, PVOID submitBuf, PVOID clientBufBase, ULONG submitBufSize, PVOID *outBuf, PULONG outBufSize, PNTSTATUS status) { return STATUS_NOT_IMPLEMENTED; } NTSTATUS NTAPI LsaApCallPackage(PLSA_CLIENT_REQUEST request, PVOID submitBuf, PVOID clientBufBase, ULONG submitBufSize, PVOID *outBuf, PULONG outBufSize, PNTSTATUS status) { return STATUS_NOT_IMPLEMENTED; } NTSTATUS NTAPI LsaApInitializePackage(ULONG pkgId, PLSA_SECPKG_FUNCTION_TABLE func, PLSA_STRING database, PLSA_STRING confident, PLSA_STRING *pkgName) { memcpy(&LsaApi, func, sizeof(LsaApi)); *pkgName = (PLSA_STRING)LsaApi.AllocateLsaHeap(sizeof(LSA_STRING)); (*pkgName)->Buffer = (PCHAR)LsaApi.AllocateLsaHeap(PKG_NAME_SIZE); /* fill buffer with package name */ memcpy((*pkgName)->Buffer, PKG_NAME, PKG_NAME_SIZE); (*pkgName)->Length = PKG_NAME_SIZE - 1; (*pkgName)->MaximumLength = PKG_NAME_SIZE; return STATUS_SUCCESS; } int LsaCopySid(PSID *dst, PSID src) { int exitCode = 1; DWORD size = 0; FAIL(IsValidSid(src) == FALSE); size = GetLengthSid(src); *dst = LsaApi.AllocateLsaHeap(size); memcpy(*dst, src, size); exitCode = 0; fail: return exitCode; } int LsaAllocTokenInfo(PLSA_TOKEN_INFORMATION_V1 *info, HANDLE token) { int exitCode = 1; DWORD cbSize = 0; DWORD i = 0; PTOKEN_USER pUserToken = NULL; PTOKEN_GROUPS pGroupsToken = NULL; PTOKEN_OWNER pOwnerToken = NULL; PTOKEN_PRIMARY_GROUP pPrimaryGroupToken = NULL; PLSA_TOKEN_INFORMATION_V1 tokenInfo; *info = (PLSA_TOKEN_INFORMATION_V1) LsaApi.AllocateLsaHeap(sizeof(LSA_TOKEN_INFORMATION_V1)); FAIL(*info == NULL); tokenInfo = *info; GetTokenInformation(token, TokenUser, NULL, 0, &cbSize); pUserToken = (PTOKEN_USER)LocalAlloc(LPTR, cbSize); FAIL(GetTokenInformation(token, TokenUser, pUserToken, cbSize, &cbSize) == FALSE); tokenInfo->User.User.Attributes = pUserToken->User.Attributes; FAIL(LsaCopySid(&tokenInfo->User.User.Sid, pUserToken->User.Sid)); GetTokenInformation(token, TokenGroups, NULL, 0, &cbSize); pGroupsToken = (PTOKEN_GROUPS)LocalAlloc(LPTR, cbSize); FAIL(GetTokenInformation(token, TokenGroups, pGroupsToken, cbSize, &cbSize) == FALSE); cbSize = pGroupsToken->GroupCount * sizeof(SID_AND_ATTRIBUTES) + sizeof(DWORD); tokenInfo->Groups = (PTOKEN_GROUPS)LsaApi.AllocateLsaHeap(cbSize); tokenInfo->Groups->GroupCount = pGroupsToken->GroupCount; for (i = 0; i < pGroupsToken->GroupCount; i++) { FAIL(LsaCopySid(&tokenInfo->Groups->Groups[i].Sid, pGroupsToken->Groups[i].Sid)); tokenInfo->Groups->Groups[i].Attributes = pGroupsToken->Groups[i].Attributes; } GetTokenInformation(token, TokenPrivileges, NULL, 0, &cbSize); tokenInfo->Privileges = (PTOKEN_PRIVILEGES)LsaApi.AllocateLsaHeap(cbSize); FAIL(GetTokenInformation(token, TokenPrivileges, tokenInfo->Privileges, cbSize, &cbSize) == FALSE); GetTokenInformation(token, TokenOwner, NULL, 0, &cbSize); pOwnerToken = (PTOKEN_OWNER)LocalAlloc(LPTR, cbSize); FAIL(GetTokenInformation(token, TokenOwner, pOwnerToken, cbSize, &cbSize) == FALSE); FAIL(LsaCopySid(&tokenInfo->Owner.Owner, pOwnerToken->Owner)); GetTokenInformation(token, TokenPrimaryGroup, NULL, 0, &cbSize); pPrimaryGroupToken = (PTOKEN_PRIMARY_GROUP)LocalAlloc(LPTR, cbSize); FAIL(GetTokenInformation(token, TokenPrimaryGroup, pPrimaryGroupToken, cbSize, &cbSize) == FALSE); FAIL(LsaCopySid(&tokenInfo->PrimaryGroup.PrimaryGroup, pPrimaryGroupToken->PrimaryGroup)); tokenInfo->DefaultDacl.DefaultDacl = NULL; tokenInfo->ExpirationTime.HighPart = 0x7fffffff; tokenInfo->ExpirationTime.LowPart = 0xffffffff; exitCode = 0; fail: LsaApi.FreeLsaHeap(pUserToken); LsaApi.FreeLsaHeap(pGroupsToken); LsaApi.FreeLsaHeap(pOwnerToken); LsaApi.FreeLsaHeap(pPrimaryGroupToken); return exitCode; } NTSTATUS NTAPI LsaApLogonUser(PLSA_CLIENT_REQUEST request, SECURITY_LOGON_TYPE logonType, PVOID authData, PVOID clientAuthData, ULONG authDataSize, PVOID *profile, PULONG profileSize, PLUID logonId, PNTSTATUS subStat, PLSA_TOKEN_INFORMATION_TYPE tokenInfoType, PVOID *tokenInfo, PLSA_UNICODE_STRING *accountName, PLSA_UNICODE_STRING *authority) { NTSTATUS ntStat = STATUS_LOGON_FAILURE; int exitCode = 1; wchar_t *inUserName = NULL; WCHAR samUserBuf[MAX_ACCOUNT_NAME_SIZE + 1]; SECURITY_STRING samUser; UNICODE_STRING *flatName = NULL; UCHAR *userAuth = NULL; ULONG userAuthSize; wchar_t homeDir[PATH_MAX]; TOKEN_SOURCE tokenSource; HANDLE token = NULL; HANDLE clientToken = NULL; SECPKG_CLIENT_INFO clientInfo; inUserName = (wchar_t *)authData; NTFAIL(LsaApi.GetClientInfo(&clientInfo)); FAIL(Not(clientInfo.HasTcbPrivilege)); NTFAIL(LsaAllocUnicodeString(authority, MAX_ACCOUNT_NAME_SIZE)); NTFAIL(LsaAllocUnicodeString(accountName, MAX_ACCOUNT_NAME_SIZE)); NTFAIL(LsaAllocUnicodeString(&flatName, MAX_ACCOUNT_NAME_SIZE)); lstrcpyW(samUserBuf, inUserName); samUserBuf[MAX_ACCOUNT_NAME_SIZE] = 0x00; RtlInitUnicodeString((PUNICODE_STRING)&samUser, samUserBuf); NTFAIL(LsaApi.GetAuthDataForUser(&samUser, SecNameFlat, NULL, &userAuth, &userAuthSize, flatName)); memcpy(tokenSource.SourceName, "_sshlsa_", 8); AllocateLocallyUniqueId(&tokenSource.SourceIdentifier); NTFAIL(LsaApi.ConvertAuthDataToToken(userAuth, userAuthSize, SecurityDelegation, &tokenSource, Network, *authority, &token, logonId, *accountName, subStat)); NTFAIL(LsaApi.AllocateClientBuffer(request, PATH_MAX * sizeof(wchar_t), profile)); *profileSize = PATH_MAX; NTFAIL(LsaApi.CopyToClientBuffer(request, PATH_MAX * sizeof(wchar_t), *profile, homeDir)); PLSA_TOKEN_INFORMATION_V1 outTokenInfo; FAIL(LsaAllocTokenInfo(&outTokenInfo, token)); *tokenInfoType = LsaTokenInformationV1; *tokenInfo = outTokenInfo; NTFAIL(LsaApi.DuplicateHandle(token, &clientToken)); ntStat = STATUS_SUCCESS; exitCode = 0; fail: if (exitCode) { ntStat = STATUS_LOGON_FAILURE; CloseHandle(clientToken); LsaApi.DeleteLogonSession(logonId); *profileSize = 0; } CloseHandle(token); LsaFreeUnicodeString(flatName); return ntStat; } VOID NTAPI LsaApLogonTerminated(PLUID logonId) { } BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpRes) { BOOL exitCode = FALSE; switch (dwReason) { case DLL_PROCESS_ATTACH: { NtDll = GetModuleHandle("ntdll.dll"); FAIL(NtDll == NULL); RtlInitUnicodeString = (RtlInitUnicodeStringPtr) GetProcAddress(NtDll, "RtlInitUnicodeString"); FAIL(RtlInitUnicodeString == NULL); break; } case DLL_PROCESS_DETACH: FreeModule(NtDll); } exitCode = TRUE; fail: if (exitCode == FALSE) FreeModule(NtDll); return exitCode; }