mirror of
				https://github.com/PowerShell/Win32-OpenSSH.git
				synced 2025-10-31 03:34:16 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			358 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			358 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Author: NoMachine <developers@nomachine.com>
 | |
|  * Copyright (c) 2009, 2013 NoMachine
 | |
|  * All rights reserved
 | |
|  *
 | |
|  * Author: Manoj Ampalam <manojamp@microsoft.com>
 | |
|  * 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 <windows.h>
 | |
| #define SECURITY_WIN32
 | |
| #include <security.h>
 | |
| #include <Ntsecapi.h>
 | |
| #include <NTSecPkg.h>
 | |
| #include <ntstatus.h>
 | |
| #include <stdio.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[MAX_PATH];
 | |
| 	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, MAX_PATH * sizeof(wchar_t), profile));
 | |
| 	*profileSize = MAX_PATH;
 | |
| 	NTFAIL(LsaApi.CopyToClientBuffer(request, MAX_PATH * 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;
 | |
| }
 |