Inno-Setup-issrc/Projects/Src/Setup.SecurityFunc.pas
2025-05-20 13:35:14 +02:00

217 lines
7.8 KiB
ObjectPascal

unit Setup.SecurityFunc;
{
Inno Setup
Copyright (C) 1997-2024 Jordan Russell
Portions by Martijn Laan
For conditions of distribution and use, see LICENSE.TXT.
Functions for altering ACLs on files & registry keys
}
interface
uses
Windows, SysUtils, Shared.CommonFunc, Shared.Struct;
function GrantPermissionOnFile(const DisableFsRedir: Boolean; Filename: String;
const Entries: TGrantPermissionEntry; const EntryCount: Integer): Boolean;
function GrantPermissionOnKey(const RegView: TRegView; const RootKey: HKEY;
const Subkey: String; const Entries: TGrantPermissionEntry;
const EntryCount: Integer): Boolean;
implementation
uses
PathFunc, SetupLdrAndSetup.Messages, SetupLdrAndSetup.InstFunc, Setup.LoggingFunc,
SetupLdrAndSetup.RedirFunc, Setup.Helper;
function InternalGrantPermission(const ObjectType: DWORD; const ObjectName: String;
const Entries: TGrantPermissionEntry; const EntryCount: Integer;
const Inheritance: DWORD): DWORD;
{ Grants the specified access to the specified object. Returns ERROR_SUCCESS if
successful. }
type
PPSID = ^PSID;
PPACL = ^PACL;
PTrusteeW = ^TTrusteeW;
TTrusteeW = record
pMultipleTrustee: PTrusteeW;
MultipleTrusteeOperation: DWORD; { MULTIPLE_TRUSTEE_OPERATION }
TrusteeForm: DWORD; { TRUSTEE_FORM }
TrusteeType: DWORD; { TRUSTEE_TYPE }
ptstrName: PWideChar;
end;
TExplicitAccessW = record
grfAccessPermissions: DWORD;
grfAccessMode: DWORD; { ACCESS_MODE }
grfInheritance: DWORD;
Trustee: TTrusteeW;
end;
PArrayOfExplicitAccessW = ^TArrayOfExplicitAccessW;
TArrayOfExplicitAccessW = array[0..999999] of TExplicitAccessW;
const
GRANT_ACCESS = 1;
TRUSTEE_IS_SID = 0;
TRUSTEE_IS_UNKNOWN = 0;
var
AdvApiHandle: HMODULE;
GetNamedSecurityInfoW: function(pObjectName: PWideChar; ObjectType: DWORD;
SecurityInfo: SECURITY_INFORMATION; ppsidOwner, ppsidGroup: PPSID;
ppDacl, ppSacl: PPACL; var ppSecurityDescriptor: PSECURITY_DESCRIPTOR): DWORD;
stdcall;
SetNamedSecurityInfoW: function(pObjectName: PWideChar; ObjectType: DWORD;
SecurityInfo: SECURITY_INFORMATION; ppsidOwner, ppsidGroup: PSID;
ppDacl, ppSacl: PACL): DWORD; stdcall;
SetEntriesInAclW: function(cCountOfExplicitEntries: ULONG;
const pListOfExplicitEntries: TExplicitAccessW; OldAcl: PACL;
var NewAcl: PACL): DWORD; stdcall;
SD: PSECURITY_DESCRIPTOR;
Dacl, NewDacl: PACL;
ExplicitAccess: PArrayOfExplicitAccessW;
E: ^TGrantPermissionEntry;
I: Integer;
Sid: PSID;
begin
AdvApiHandle := GetModuleHandle(advapi32);
GetNamedSecurityInfoW := GetProcAddress(AdvApiHandle, PAnsiChar('GetNamedSecurityInfoW'));
SetNamedSecurityInfoW := GetProcAddress(AdvApiHandle, PAnsiChar('SetNamedSecurityInfoW'));
SetEntriesInAclW := GetProcAddress(AdvApiHandle, PAnsiChar('SetEntriesInAclW'));
if (@GetNamedSecurityInfoW = nil) or (@SetNamedSecurityInfoW = nil) or
(@SetEntriesInAclW = nil) then begin
Result := ERROR_PROC_NOT_FOUND;
Exit;
end;
ExplicitAccess := nil;
Result := GetNamedSecurityInfoW(PChar(ObjectName), ObjectType,
DACL_SECURITY_INFORMATION, nil, nil, @Dacl, nil, SD);
if Result <> ERROR_SUCCESS then
Exit;
try
{ Note: Dacl will be nil if GetNamedSecurityInfo is called on a FAT partition.
Be careful not to dereference a nil pointer. }
ExplicitAccess := AllocMem(EntryCount * SizeOf(ExplicitAccess[0]));
E := @Entries;
for I := 0 to EntryCount-1 do begin
if not AllocateAndInitializeSid(E.Sid.Authority, E.Sid.SubAuthCount,
E.Sid.SubAuth[0], E.Sid.SubAuth[1], 0, 0, 0, 0, 0, 0, Sid) then begin
Result := GetLastError;
if Result = ERROR_SUCCESS then { just in case... }
Result := ERROR_INVALID_PARAMETER;
Exit;
end;
ExplicitAccess[I].grfAccessPermissions := E.AccessMask;
ExplicitAccess[I].grfAccessMode := GRANT_ACCESS;
ExplicitAccess[I].grfInheritance := Inheritance;
ExplicitAccess[I].Trustee.TrusteeForm := TRUSTEE_IS_SID;
ExplicitAccess[I].Trustee.TrusteeType := TRUSTEE_IS_UNKNOWN;
PSID(ExplicitAccess[I].Trustee.ptstrName) := Sid;
Inc(E);
end;
Result := SetEntriesInAclW(EntryCount, ExplicitAccess[0], Dacl, NewDacl);
if Result <> ERROR_SUCCESS then
Exit;
try
Result := SetNamedSecurityInfoW(PChar(ObjectName), ObjectType,
DACL_SECURITY_INFORMATION, nil, nil, NewDacl, nil);
finally
LocalFree(HLOCAL(NewDacl));
end;
finally
if Assigned(ExplicitAccess) then begin
for I := EntryCount-1 downto 0 do begin
Sid := PSID(ExplicitAccess[I].Trustee.ptstrName);
if Assigned(Sid) then
FreeSid(Sid);
end;
FreeMem(ExplicitAccess);
end;
LocalFree(HLOCAL(SD));
end;
end;
function GrantPermission(const Use64BitHelper: Boolean; const ObjectType: DWORD;
const ObjectName: String; const Entries: TGrantPermissionEntry;
const EntryCount: Integer; const Inheritance: DWORD): DWORD;
{ Invokes either the internal GrantPermission function or the one inside the
64-bit helper, depending on the setting of Use64BitHelper }
begin
try
if Use64BitHelper then
Result := HelperGrantPermission(ObjectType, ObjectName, Entries,
EntryCount, Inheritance)
else
Result := InternalGrantPermission(ObjectType, ObjectName, Entries,
EntryCount, Inheritance);
except
{ If the helper interface (or even InternalGrantPermission) raises an
exception, don't propagate it. Just log it and return an error code, as
that's what the caller is expecting on failure. }
Log('Exception while setting permissions:' + SNewLine + GetExceptMessage);
Result := ERROR_GEN_FAILURE;
end;
end;
const
OBJECT_INHERIT_ACE = 1;
CONTAINER_INHERIT_ACE = 2;
function GrantPermissionOnFile(const DisableFsRedir: Boolean; Filename: String;
const Entries: TGrantPermissionEntry; const EntryCount: Integer): Boolean;
{ Grants the specified access to the specified file/directory. Returns True if
successful. On failure, the thread's last error code is set. }
const
SE_FILE_OBJECT = 1;
var
Attr, Inheritance, ErrorCode: DWORD;
begin
{ Expand filename if needed because the 64-bit helper may not have the same
current directory as us }
Filename := PathExpand(Filename);
Attr := GetFileAttributesRedir(DisableFsRedir, Filename);
if Attr = INVALID_FILE_ATTRIBUTES then begin
Result := False;
Exit;
end;
if Attr and FILE_ATTRIBUTE_DIRECTORY <> 0 then
Inheritance := OBJECT_INHERIT_ACE or CONTAINER_INHERIT_ACE
else
Inheritance := 0;
ErrorCode := GrantPermission(DisableFsRedir, SE_FILE_OBJECT, Filename, Entries,
EntryCount, Inheritance);
SetLastError(ErrorCode);
Result := (ErrorCode = ERROR_SUCCESS);
end;
function GrantPermissionOnKey(const RegView: TRegView; const RootKey: HKEY;
const Subkey: String; const Entries: TGrantPermissionEntry;
const EntryCount: Integer): Boolean;
{ Grants the specified access to the specified registry key. Returns True if
successful. On failure, the thread's last error code is set. }
const
SE_REGISTRY_KEY = 4;
var
ObjName: String;
ErrorCode: DWORD;
begin
case RootKey of
HKEY_CLASSES_ROOT: ObjName := 'CLASSES_ROOT';
HKEY_CURRENT_USER: ObjName := 'CURRENT_USER';
HKEY_LOCAL_MACHINE: ObjName := 'MACHINE';
HKEY_USERS: ObjName := 'USERS';
else
{ Other root keys are not supported by Get/SetNamedSecurityInfo }
SetLastError(ERROR_INVALID_PARAMETER);
Result := False;
Exit;
end;
ObjName := ObjName + '\' + Subkey;
ErrorCode := GrantPermission(RegView = rv64Bit, SE_REGISTRY_KEY, ObjName,
Entries, EntryCount, CONTAINER_INHERIT_ACE);
SetLastError(ErrorCode);
Result := (ErrorCode = ERROR_SUCCESS);
end;
end.