SecurityFunc.pas 7.7 KB

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