Setup.SecurityFunc.pas 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. unit Setup.SecurityFunc;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2024 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Functions for altering ACLs on files & registry keys
  8. }
  9. interface
  10. uses
  11. Windows, SysUtils, Shared.CommonFunc, Shared.Struct;
  12. function GrantPermissionOnFile(const DisableFsRedir: Boolean; Filename: String;
  13. const Entries: TGrantPermissionEntry; const EntryCount: Integer): Boolean;
  14. function GrantPermissionOnKey(const RegView: TRegView; const RootKey: HKEY;
  15. const Subkey: String; const Entries: TGrantPermissionEntry;
  16. const EntryCount: Integer): Boolean;
  17. implementation
  18. uses
  19. PathFunc, SetupLdrAndSetup.Messages, SetupLdrAndSetup.InstFunc, Setup.LoggingFunc,
  20. SetupLdrAndSetup.RedirFunc, Setup.Helper;
  21. function InternalGrantPermission(const ObjectType: DWORD; const ObjectName: String;
  22. const Entries: TGrantPermissionEntry; const EntryCount: Integer;
  23. const Inheritance: DWORD): DWORD;
  24. { Grants the specified access to the specified object. Returns ERROR_SUCCESS if
  25. successful. }
  26. type
  27. PPSID = ^PSID;
  28. PPACL = ^PACL;
  29. PTrusteeW = ^TTrusteeW;
  30. TTrusteeW = record
  31. pMultipleTrustee: PTrusteeW;
  32. MultipleTrusteeOperation: DWORD; { MULTIPLE_TRUSTEE_OPERATION }
  33. TrusteeForm: DWORD; { TRUSTEE_FORM }
  34. TrusteeType: DWORD; { TRUSTEE_TYPE }
  35. ptstrName: PWideChar;
  36. end;
  37. TExplicitAccessW = record
  38. grfAccessPermissions: DWORD;
  39. grfAccessMode: DWORD; { ACCESS_MODE }
  40. grfInheritance: DWORD;
  41. Trustee: TTrusteeW;
  42. end;
  43. PArrayOfExplicitAccessW = ^TArrayOfExplicitAccessW;
  44. TArrayOfExplicitAccessW = array[0..999999] of TExplicitAccessW;
  45. const
  46. GRANT_ACCESS = 1;
  47. TRUSTEE_IS_SID = 0;
  48. TRUSTEE_IS_UNKNOWN = 0;
  49. var
  50. AdvApiHandle: HMODULE;
  51. GetNamedSecurityInfoW: function(pObjectName: PWideChar; ObjectType: DWORD;
  52. SecurityInfo: SECURITY_INFORMATION; ppsidOwner, ppsidGroup: PPSID;
  53. ppDacl, ppSacl: PPACL; var ppSecurityDescriptor: PSECURITY_DESCRIPTOR): DWORD;
  54. stdcall;
  55. SetNamedSecurityInfoW: function(pObjectName: PWideChar; ObjectType: DWORD;
  56. SecurityInfo: SECURITY_INFORMATION; ppsidOwner, ppsidGroup: PSID;
  57. ppDacl, ppSacl: PACL): DWORD; stdcall;
  58. SetEntriesInAclW: function(cCountOfExplicitEntries: ULONG;
  59. const pListOfExplicitEntries: TExplicitAccessW; OldAcl: PACL;
  60. var NewAcl: PACL): DWORD; stdcall;
  61. SD: PSECURITY_DESCRIPTOR;
  62. Dacl, NewDacl: PACL;
  63. ExplicitAccess: PArrayOfExplicitAccessW;
  64. E: ^TGrantPermissionEntry;
  65. I: Integer;
  66. Sid: PSID;
  67. begin
  68. AdvApiHandle := GetModuleHandle(advapi32);
  69. GetNamedSecurityInfoW := GetProcAddress(AdvApiHandle, PAnsiChar('GetNamedSecurityInfoW'));
  70. SetNamedSecurityInfoW := GetProcAddress(AdvApiHandle, PAnsiChar('SetNamedSecurityInfoW'));
  71. SetEntriesInAclW := GetProcAddress(AdvApiHandle, PAnsiChar('SetEntriesInAclW'));
  72. if (@GetNamedSecurityInfoW = nil) or (@SetNamedSecurityInfoW = nil) or
  73. (@SetEntriesInAclW = nil) then begin
  74. Result := ERROR_PROC_NOT_FOUND;
  75. Exit;
  76. end;
  77. ExplicitAccess := nil;
  78. Result := GetNamedSecurityInfoW(PChar(ObjectName), ObjectType,
  79. DACL_SECURITY_INFORMATION, nil, nil, @Dacl, nil, SD);
  80. if Result <> ERROR_SUCCESS then
  81. Exit;
  82. try
  83. { Note: Dacl will be nil if GetNamedSecurityInfo is called on a FAT partition.
  84. Be careful not to dereference a nil pointer. }
  85. ExplicitAccess := AllocMem(EntryCount * SizeOf(ExplicitAccess[0]));
  86. E := @Entries;
  87. for I := 0 to EntryCount-1 do begin
  88. if not AllocateAndInitializeSid(E.Sid.Authority, E.Sid.SubAuthCount,
  89. E.Sid.SubAuth[0], E.Sid.SubAuth[1], 0, 0, 0, 0, 0, 0, Sid) then begin
  90. Result := GetLastError;
  91. if Result = ERROR_SUCCESS then { just in case... }
  92. Result := ERROR_INVALID_PARAMETER;
  93. Exit;
  94. end;
  95. ExplicitAccess[I].grfAccessPermissions := E.AccessMask;
  96. ExplicitAccess[I].grfAccessMode := GRANT_ACCESS;
  97. ExplicitAccess[I].grfInheritance := Inheritance;
  98. ExplicitAccess[I].Trustee.TrusteeForm := TRUSTEE_IS_SID;
  99. ExplicitAccess[I].Trustee.TrusteeType := TRUSTEE_IS_UNKNOWN;
  100. PSID(ExplicitAccess[I].Trustee.ptstrName) := Sid;
  101. Inc(E);
  102. end;
  103. Result := SetEntriesInAclW(EntryCount, ExplicitAccess[0], Dacl, NewDacl);
  104. if Result <> ERROR_SUCCESS then
  105. Exit;
  106. try
  107. Result := SetNamedSecurityInfoW(PChar(ObjectName), ObjectType,
  108. DACL_SECURITY_INFORMATION, nil, nil, NewDacl, nil);
  109. finally
  110. LocalFree(HLOCAL(NewDacl));
  111. end;
  112. finally
  113. if Assigned(ExplicitAccess) then begin
  114. for I := EntryCount-1 downto 0 do begin
  115. Sid := PSID(ExplicitAccess[I].Trustee.ptstrName);
  116. if Assigned(Sid) then
  117. FreeSid(Sid);
  118. end;
  119. FreeMem(ExplicitAccess);
  120. end;
  121. LocalFree(HLOCAL(SD));
  122. end;
  123. end;
  124. function GrantPermission(const Use64BitHelper: Boolean; const ObjectType: DWORD;
  125. const ObjectName: String; const Entries: TGrantPermissionEntry;
  126. const EntryCount: Integer; const Inheritance: DWORD): DWORD;
  127. { Invokes either the internal GrantPermission function or the one inside the
  128. 64-bit helper, depending on the setting of Use64BitHelper }
  129. begin
  130. try
  131. if Use64BitHelper then
  132. Result := HelperGrantPermission(ObjectType, ObjectName, Entries,
  133. EntryCount, Inheritance)
  134. else
  135. Result := InternalGrantPermission(ObjectType, ObjectName, Entries,
  136. EntryCount, Inheritance);
  137. except
  138. { If the helper interface (or even InternalGrantPermission) raises an
  139. exception, don't propagate it. Just log it and return an error code, as
  140. that's what the caller is expecting on failure. }
  141. Log('Exception while setting permissions:' + SNewLine + GetExceptMessage);
  142. Result := ERROR_GEN_FAILURE;
  143. end;
  144. end;
  145. const
  146. OBJECT_INHERIT_ACE = 1;
  147. CONTAINER_INHERIT_ACE = 2;
  148. function GrantPermissionOnFile(const DisableFsRedir: Boolean; Filename: String;
  149. const Entries: TGrantPermissionEntry; const EntryCount: Integer): Boolean;
  150. { Grants the specified access to the specified file/directory. Returns True if
  151. successful. On failure, the thread's last error code is set. }
  152. const
  153. SE_FILE_OBJECT = 1;
  154. var
  155. Attr, Inheritance, ErrorCode: DWORD;
  156. begin
  157. { Expand filename if needed because the 64-bit helper may not have the same
  158. current directory as us }
  159. Filename := PathExpand(Filename);
  160. Attr := GetFileAttributesRedir(DisableFsRedir, Filename);
  161. if Attr = INVALID_FILE_ATTRIBUTES then begin
  162. Result := False;
  163. Exit;
  164. end;
  165. if Attr and FILE_ATTRIBUTE_DIRECTORY <> 0 then
  166. Inheritance := OBJECT_INHERIT_ACE or CONTAINER_INHERIT_ACE
  167. else
  168. Inheritance := 0;
  169. ErrorCode := GrantPermission(DisableFsRedir, SE_FILE_OBJECT, Filename, Entries,
  170. EntryCount, Inheritance);
  171. SetLastError(ErrorCode);
  172. Result := (ErrorCode = ERROR_SUCCESS);
  173. end;
  174. function GrantPermissionOnKey(const RegView: TRegView; const RootKey: HKEY;
  175. const Subkey: String; const Entries: TGrantPermissionEntry;
  176. const EntryCount: Integer): Boolean;
  177. { Grants the specified access to the specified registry key. Returns True if
  178. successful. On failure, the thread's last error code is set. }
  179. const
  180. SE_REGISTRY_KEY = 4;
  181. var
  182. ObjName: String;
  183. ErrorCode: DWORD;
  184. begin
  185. case RootKey of
  186. HKEY_CLASSES_ROOT: ObjName := 'CLASSES_ROOT';
  187. HKEY_CURRENT_USER: ObjName := 'CURRENT_USER';
  188. HKEY_LOCAL_MACHINE: ObjName := 'MACHINE';
  189. HKEY_USERS: ObjName := 'USERS';
  190. else
  191. { Other root keys are not supported by Get/SetNamedSecurityInfo }
  192. SetLastError(ERROR_INVALID_PARAMETER);
  193. Result := False;
  194. Exit;
  195. end;
  196. ObjName := ObjName + '\' + Subkey;
  197. ErrorCode := GrantPermission(RegView = rv64Bit, SE_REGISTRY_KEY, ObjName,
  198. Entries, EntryCount, CONTAINER_INHERIT_ACE);
  199. SetLastError(ErrorCode);
  200. Result := (ErrorCode = ERROR_SUCCESS);
  201. end;
  202. end.