// +build windows
package sys_windows

foreign import advapi32 "system:Advapi32.lib"

HCRYPTPROV :: distinct HANDLE

@(default_calling_convention="system")
foreign advapi32 {
	@(link_name = "SystemFunction036")
	RtlGenRandom :: proc(RandomBuffer: ^u8, RandomBufferLength: ULONG) -> BOOLEAN ---
	OpenProcessToken :: proc(ProcessHandle: HANDLE,
	                         DesiredAccess: DWORD,
	                         TokenHandle: ^HANDLE) -> BOOL ---

	OpenThreadToken :: proc(ThreadHandle:  HANDLE,
	                        DesiredAccess: DWORD,
	                        OpenAsSelf:    BOOL,
	                        TokenHandle:   ^HANDLE) -> BOOL ---

	GetTokenInformation :: proc (
		TokenHandle: HANDLE,
		TokenInformationClass: TOKEN_INFORMATION_CLASS,
		TokenInformation: LPVOID,
		TokenInformationLength: DWORD,
		ReturnLength: PDWORD,
	) -> BOOL ---

	CryptAcquireContextW :: proc(hProv: ^HCRYPTPROV, szContainer, szProvider: wstring, dwProvType, dwFlags: DWORD) -> DWORD ---
	CryptGenRandom       :: proc(hProv: HCRYPTPROV, dwLen: DWORD, buf: LPVOID) -> DWORD ---
	CryptReleaseContext  :: proc(hProv: HCRYPTPROV, dwFlags: DWORD) -> DWORD ---
}

// Necessary to create a token to impersonate a user with for CreateProcessAsUser
@(default_calling_convention="system")
foreign advapi32 {
	LogonUserW :: proc(
		lpszUsername: LPCWSTR,
		lpszDomain: LPCWSTR,
		lpszPassword: LPCWSTR,
		dwLogonType: Logon32_Type,
		dwLogonProvider: Logon32_Provider,
		phToken: ^HANDLE,
	) -> BOOL ---

	// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-lookupaccountnamew
	// To look up the SID to use with DeleteProfileW.
	LookupAccountNameW :: proc(
		lpSystemName: wstring,
		lpAccountName: wstring,
		Sid: ^SID,
		cbSid: ^DWORD,
		ReferencedDomainName: wstring,
		cchReferencedDomainName: ^DWORD,
		peUse: PSID_NAME_USE,
	) -> BOOL ---

	LookupAccountSidW :: proc (
		lpSystemName: LPCWSTR,
		Sid: PSID,
		Name: LPWSTR,
		cchName: LPDWORD,
		ReferencedDomainName: LPWSTR,
		cchReferencedDomainName: LPDWORD,
		peUse: PSID_NAME_USE,
	) -> BOOL ---

	CreateProcessWithLogonW :: proc(
		lpUsername: wstring,
		lpDomain: wstring,
		lpPassword: wstring,
		dwLogonFlags: DWORD,
		lpApplicationName: wstring,
		lpCommandLine: wstring,
		dwCreationFlags: DWORD,
		lpEnvironment: LPVOID,
		lpCurrentDirectory: wstring,
		lpStartupInfo: LPSTARTUPINFOW,
		lpProcessInformation: LPPROCESS_INFORMATION,
	) -> BOOL ---

	// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessasuserw
	CreateProcessAsUserW :: proc(
		hToken: HANDLE,
		lpApplicationName: wstring,
		lpCommandLine: wstring,
		lpProcessAttributes: LPSECURITY_ATTRIBUTES,
		lpThreadAttributes: LPSECURITY_ATTRIBUTES,
		bInheritHandles: BOOL,
		dwCreationFlags: DWORD,
		lpEnvironment: LPVOID,
		lpCurrentDirectory: wstring,
		lpStartupInfo: LPSTARTUPINFOW,
		lpProcessInformation: LPPROCESS_INFORMATION,
	) -> BOOL ---

	RegCreateKeyExW :: proc(
		hKey: HKEY,
		lpSubKey: LPCWSTR,
		Reserved: DWORD,
		lpClass: LPWSTR,
		dwOptions: DWORD,
		samDesired: REGSAM,
		lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
		phkResult: PHKEY,
		lpdwDisposition: LPDWORD,
	) -> LSTATUS ---

	RegOpenKeyW :: proc(
		hKey: HKEY,
		lpSubKey: LPCWSTR,
		phkResult: PHKEY,
	) -> LSTATUS ---

	RegOpenKeyExW :: proc(
		hKey: HKEY,
		lpSubKey: LPCWSTR,
		ulOptions: DWORD,
		samDesired: REGSAM,
		phkResult: PHKEY,
	) -> LSTATUS ---

	RegCloseKey :: proc(
		hKey: HKEY,
	) -> LSTATUS ---

	RegGetValueW :: proc(
		hkey: HKEY,
		lpSubKey: LPCWSTR,
		lpValue: LPCWSTR,
		dwFlags: DWORD,
		pdwType: LPDWORD,
		pvData: PVOID,
		pcbData: LPDWORD,
	) -> LSTATUS ---

	RegSetValueExW :: proc(
		hKey: HKEY,
		lpValueName: LPCWSTR,
		Reserved: DWORD,
		dwType: DWORD,
		lpData: ^BYTE,
		cbData: DWORD,
	) -> LSTATUS ---

	RegSetKeyValueW :: proc(
		hKey: HKEY,
		lpSubKey: LPCWSTR,
		lpValueName: LPCWSTR,
		dwType: DWORD,
		lpData: LPCVOID,
		cbData: DWORD,
	) -> LSTATUS ---

	GetFileSecurityW :: proc(
		lpFileName: LPCWSTR,
		RequestedInformation: SECURITY_INFORMATION,
		pSecurityDescriptor: PSECURITY_DESCRIPTOR,
		nLength: DWORD,
		lpnLengthNeeded: LPDWORD,
	) -> BOOL ---

	DuplicateToken :: proc(
		ExistingTokenHandle: HANDLE,
		ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL,
		DuplicateTokenHandle: PHANDLE,
	) -> BOOL ---

	MapGenericMask :: proc(
		AccessMask: PDWORD,
		GenericMapping: PGENERIC_MAPPING,
	) ---

	AccessCheck :: proc(
		pSecurityDescriptor: PSECURITY_DESCRIPTOR,
		ClientToken: HANDLE,
		DesiredAccess: DWORD,
		GenericMapping: PGENERIC_MAPPING,
		PrivilegeSet: PPRIVILEGE_SET,
		PrivilegeSetLength: LPDWORD,
		GrantedAccess: LPDWORD,
		AccessStatus: LPBOOL,
	) -> BOOL ---
}

PTOKEN_INFORMATION_CLASS :: ^TOKEN_INFORMATION_CLASS
TOKEN_INFORMATION_CLASS :: enum i32 {
	TokenUser = 1,
	TokenGroups,
	TokenPrivileges,
	TokenOwner,
	TokenPrimaryGroup,
	TokenDefaultDacl,
	TokenSource,
	TokenType,
	TokenImpersonationLevel,
	TokenStatistics,
	TokenRestrictedSids,
	TokenSessionId,
	TokenGroupsAndPrivileges,
	TokenSessionReference,
	TokenSandBoxInert,
	TokenAuditPolicy,
	TokenOrigin,
	TokenElevationType,
	TokenLinkedToken,
	TokenElevation,
	TokenHasRestrictions,
	TokenAccessInformation,
	TokenVirtualizationAllowed,
	TokenVirtualizationEnabled,
	TokenIntegrityLevel,
	TokenUIAccess,
	TokenMandatoryPolicy,
	TokenLogonSid,
	TokenIsAppContainer,
	TokenCapabilities,
	TokenAppContainerSid,
	TokenAppContainerNumber,
	TokenUserClaimAttributes,
	TokenDeviceClaimAttributes,
	TokenRestrictedUserClaimAttributes,
	TokenRestrictedDeviceClaimAttributes,
	TokenDeviceGroups,
	TokenRestrictedDeviceGroups,
	TokenSecurityAttributes,
	TokenIsRestricted,
	TokenProcessTrustLevel,
	TokenPrivateNameSpace,
	TokenSingletonAttributes,
	TokenBnoIsolation,
	TokenChildProcessFlags,
	TokenIsLessPrivilegedAppContainer,
	TokenIsSandboxed,
	TokenIsAppSilo,
	TokenLoggingInformation,
	MaxTokenInfoClass,
}

PSID_NAME_USE :: ^SID_NAME_USE
SID_NAME_USE :: enum i32 {
	SidTypeUser = 1,
	SidTypeGroup,
	SidTypeDomain,
	SidTypeAlias,
	SidTypeWellKnownGroup,
	SidTypeDeletedAccount,
	SidTypeInvalid,
	SidTypeUnknown,
	SidTypeComputer,
	SidTypeLabel,
	SidTypeLogonSession,
}

PTOKEN_USER :: ^TOKEN_USER
TOKEN_USER :: struct {
	User: SID_AND_ATTRIBUTES,
}

PSID_AND_ATTRIBUTES :: ^SID_AND_ATTRIBUTES
SID_AND_ATTRIBUTES :: struct {
	Sid: rawptr,
	Attributes: ULONG,
}

PTOKEN_TYPE :: ^TOKEN_TYPE
TOKEN_TYPE :: enum {
	TokenPrimary = 1,
	TokenImpersonation = 2,
}

PTOKEN_STATISTICS :: ^TOKEN_STATISTICS
TOKEN_STATISTICS :: struct {
	TokenId: LUID,
	AuthenticationId: LUID,
	ExpirationTime: LARGE_INTEGER,
	TokenType: TOKEN_TYPE,
	ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL,
	DynamicCharged: DWORD,
	DynamicAvailable: DWORD,
	GroupCount: DWORD,
	PrivilegeCount: DWORD,
	ModifiedId: LUID,
}


TOKEN_SOURCE_LENGTH :: 8
PTOKEN_SOURCE :: ^TOKEN_SOURCE
TOKEN_SOURCE :: struct {
	SourceName: [TOKEN_SOURCE_LENGTH]CHAR,
	SourceIdentifier: LUID,
}


PTOKEN_PRIVILEGES :: ^TOKEN_PRIVILEGES
TOKEN_PRIVILEGES :: struct {
	PrivilegeCount: DWORD,
	Privileges: [0]LUID_AND_ATTRIBUTES,
}

PTOKEN_PRIMARY_GROUP :: ^TOKEN_PRIMARY_GROUP
TOKEN_PRIMARY_GROUP :: struct {
	PrimaryGroup: PSID,
}

PTOKEN_OWNER :: ^TOKEN_OWNER
TOKEN_OWNER :: struct {
	Owner: PSID,
}

PTOKEN_GROUPS_AND_PRIVILEGES :: ^TOKEN_GROUPS_AND_PRIVILEGES
TOKEN_GROUPS_AND_PRIVILEGES :: struct {
	SidCount: DWORD,
	SidLength: DWORD,
	Sids: PSID_AND_ATTRIBUTES,
	RestrictedSidCount: DWORD,
	RestrictedSidLength: DWORD,
	RestrictedSids: PSID_AND_ATTRIBUTES,
	PrivilegeCount: DWORD,
	PrivilegeLength: DWORD,
	Privileges: PLUID_AND_ATTRIBUTES,
	AuthenticationId: LUID,
}

PTOKEN_DEFAULT_DACL :: ^TOKEN_DEFAULT_DACL
TOKEN_DEFAULT_DACL :: struct {
	DefaultDacl: PACL,
}

PACL :: ^ACL
ACL :: struct {
	AclRevision: BYTE,
	Sbz1: BYTE,
	AclSize: WORD,
	AceCount: WORD,
	Sbz2: WORD,
}
