Helper.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /*
  2. Inno Setup
  3. Copyright (C) 1997-2008 Jordan Russell
  4. Portions by Martijn Laan
  5. For conditions of distribution and use, see LICENSE.TXT.
  6. 64-bit helper process
  7. Compiled on Visual Studio 2005 SP1
  8. Tested on x64 and IA-64 architectures (Athlon 64 and Merced specifically).
  9. */
  10. #define _WIN32_IE 0x0600
  11. #include <windows.h>
  12. #include <commctrl.h>
  13. #include <shlwapi.h>
  14. #include <aclapi.h>
  15. #ifndef UNICODE
  16. #error UNICODE isn't defined
  17. #endif
  18. // As of Inno Setup 5.1.11, the helper is no longer used to register
  19. // DLLs, so avoid linking in support for REQUEST_REGISTER_SERVER.
  20. #undef IMPLEMENT_REGISTER_SERVER
  21. #define HELPER_VERSION 105
  22. // Request commands
  23. #define REQUEST_PING 1
  24. #define REQUEST_GRANT_PERMISSION 2
  25. #ifdef IMPLEMENT_REGISTER_SERVER
  26. #define REQUEST_REGISTER_SERVER 3
  27. #endif
  28. #define REQUEST_REGISTER_TYPE_LIBRARY 4
  29. // These must be kept in synch with Struct.pas:
  30. typedef struct {
  31. SID_IDENTIFIER_AUTHORITY Authority;
  32. BYTE SubAuthCount;
  33. DWORD SubAuth[2];
  34. } TGrantPermissionSid;
  35. typedef struct {
  36. TGrantPermissionSid Sid;
  37. DWORD AccessMask;
  38. } TGrantPermissionEntry;
  39. // This value must be kept in synch with Struct.pas:
  40. #define MAX_GRANT_PERMISSION_ENTRIES 32
  41. // These must be kept in synch with Helper.pas:
  42. typedef struct {
  43. DWORD ObjectType;
  44. DWORD EntryCount;
  45. DWORD Inheritance;
  46. WCHAR ObjectName[4096];
  47. TGrantPermissionEntry Entries[MAX_GRANT_PERMISSION_ENTRIES];
  48. } REQUEST_GRANT_PERMISSION_DATA;
  49. typedef struct {
  50. BOOL Unregister;
  51. BOOL FailCriticalErrors;
  52. WCHAR Filename[4096];
  53. WCHAR Directory[4096];
  54. } REQUEST_REGISTER_SERVER_DATA;
  55. typedef struct {
  56. BOOL Unregister;
  57. WCHAR Filename[4096];
  58. } REQUEST_REGISTER_TYPE_LIBRARY_DATA;
  59. typedef struct {
  60. DWORD SequenceNumber;
  61. DWORD Command;
  62. DWORD DataSize;
  63. union {
  64. BYTE Data[65536];
  65. REQUEST_GRANT_PERMISSION_DATA GrantPermissionData;
  66. REQUEST_REGISTER_SERVER_DATA RegisterServerData;
  67. REQUEST_REGISTER_TYPE_LIBRARY_DATA RegisterTypeLibraryData;
  68. };
  69. } REQUEST_DATA;
  70. typedef struct {
  71. DWORD SequenceNumber;
  72. DWORD StatusCode;
  73. DWORD ErrorCode;
  74. DWORD DataSize;
  75. BYTE Data[65536];
  76. } RESPONSE_DATA;
  77. static TCHAR SystemDir[MAX_PATH+1];
  78. static DWORD GrantPermission(const DWORD ObjectType, const LPWSTR ObjectName,
  79. TGrantPermissionEntry *Entries, const DWORD EntryCount,
  80. const DWORD Inheritance)
  81. {
  82. DWORD ErrorCode;
  83. PSECURITY_DESCRIPTOR SD;
  84. PACL Dacl, NewDacl;
  85. EXPLICIT_ACCESSW ExplicitAccess[MAX_GRANT_PERMISSION_ENTRIES];
  86. DWORD I;
  87. // Note: SecureZeroMemory is used because memset/ZeroMemory aren't available
  88. SecureZeroMemory(&ExplicitAccess, sizeof(ExplicitAccess));
  89. if (EntryCount > ARRAYSIZE(ExplicitAccess)) {
  90. return ERROR_INVALID_PARAMETER;
  91. }
  92. ErrorCode = GetNamedSecurityInfoW(ObjectName, ObjectType,
  93. DACL_SECURITY_INFORMATION, NULL, NULL, &Dacl, NULL, &SD);
  94. if (ErrorCode != ERROR_SUCCESS) {
  95. return ErrorCode;
  96. }
  97. // From here on, use "goto out" instead of "return"
  98. for (I = 0; I < EntryCount; I++) {
  99. TGrantPermissionEntry *E = &Entries[I];
  100. PSID Sid;
  101. if (!AllocateAndInitializeSid(&E->Sid.Authority, E->Sid.SubAuthCount,
  102. E->Sid.SubAuth[0], E->Sid.SubAuth[1], 0, 0, 0, 0, 0, 0, &Sid)) {
  103. ErrorCode = GetLastError();
  104. if (ErrorCode == 0) ErrorCode = ERROR_INVALID_PARAMETER; // just in case
  105. goto out;
  106. }
  107. ExplicitAccess[I].grfAccessPermissions = E->AccessMask;
  108. ExplicitAccess[I].grfAccessMode = GRANT_ACCESS;
  109. ExplicitAccess[I].grfInheritance = Inheritance;
  110. ExplicitAccess[I].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  111. ExplicitAccess[I].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
  112. ExplicitAccess[I].Trustee.ptstrName = Sid;
  113. }
  114. ErrorCode = SetEntriesInAclW(EntryCount, ExplicitAccess, Dacl, &NewDacl);
  115. if (ErrorCode == ERROR_SUCCESS) {
  116. ErrorCode = SetNamedSecurityInfoW(ObjectName, ObjectType,
  117. DACL_SECURITY_INFORMATION, NULL, NULL, NewDacl, NULL);
  118. LocalFree(NewDacl);
  119. }
  120. out:
  121. for (I = 0; I < EntryCount; I++) {
  122. PSID Sid = ExplicitAccess[I].Trustee.ptstrName;
  123. if (Sid) FreeSid(Sid);
  124. }
  125. LocalFree(SD);
  126. return ErrorCode;
  127. }
  128. #ifdef IMPLEMENT_REGISTER_SERVER
  129. static DWORD RegisterServer(const BOOL Unregister, const LPWSTR Filename,
  130. const LPWSTR Directory, const BOOL FailCriticalErrors, DWORD *ErrorCode)
  131. {
  132. DWORD retval = 0;
  133. HRESULT OleInitResult;
  134. UINT SaveErrorMode;
  135. HANDLE LibHandle;
  136. // Initialize OLE. Regsvr32 does this.
  137. OleInitResult = OleInitialize(NULL);
  138. if (FAILED(OleInitResult)) {
  139. *ErrorCode = OleInitResult;
  140. return 4;
  141. }
  142. SaveErrorMode = SetErrorMode(FailCriticalErrors ?
  143. SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS :
  144. SEM_NOOPENFILEERRORBOX);
  145. // If no directory was supplied, we use the system directory.
  146. // Relative paths are assumed to be relative to the system directory.
  147. SetCurrentDirectory(SystemDir);
  148. if (*Directory) {
  149. SetCurrentDirectoryW(Directory);
  150. }
  151. LibHandle = LoadLibraryExW(Filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  152. if (LibHandle) {
  153. typedef HRESULT (STDAPICALLTYPE *DLLREGISTERSERVER)(void);
  154. DLLREGISTERSERVER RegisterServerProc;
  155. RegisterServerProc = (DLLREGISTERSERVER)GetProcAddress(LibHandle,
  156. Unregister ? "DllUnregisterServer" : "DllRegisterServer");
  157. if (RegisterServerProc) {
  158. *ErrorCode = (*RegisterServerProc)();
  159. retval = 3;
  160. } else {
  161. *ErrorCode = GetLastError();
  162. retval = 2;
  163. }
  164. FreeLibrary(LibHandle);
  165. } else {
  166. *ErrorCode = GetLastError();
  167. retval = 1;
  168. }
  169. // Revert the current directory and error mode changes
  170. SetCurrentDirectory(SystemDir);
  171. SetErrorMode(SaveErrorMode);
  172. OleUninitialize();
  173. return retval;
  174. }
  175. #endif
  176. static DWORD RegisterTypeLibrary(const BOOL Unregister,
  177. const LPWSTR Filename, DWORD *ErrorCode)
  178. {
  179. DWORD retval;
  180. HRESULT hr;
  181. ITypeLib *TypeLib;
  182. TLIBATTR *LibAttr;
  183. retval = 1;
  184. hr = LoadTypeLib(Filename, &TypeLib);
  185. if (hr == S_OK) {
  186. if (!Unregister) {
  187. retval = 2;
  188. hr = RegisterTypeLib(TypeLib, Filename, NULL);
  189. } else {
  190. retval = 3;
  191. hr = TypeLib->lpVtbl->GetLibAttr(TypeLib, &LibAttr);
  192. if (hr == S_OK) {
  193. retval = 4;
  194. hr = UnRegisterTypeLib(&LibAttr->guid, LibAttr->wMajorVerNum,
  195. LibAttr->wMinorVerNum, LibAttr->lcid, LibAttr->syskind);
  196. TypeLib->lpVtbl->ReleaseTLibAttr(TypeLib, LibAttr);
  197. }
  198. }
  199. TypeLib->lpVtbl->Release(TypeLib);
  200. }
  201. *ErrorCode = hr;
  202. return retval;
  203. }
  204. static void ProcessRequest(REQUEST_DATA *request, RESPONSE_DATA *response)
  205. {
  206. response->SequenceNumber = request->SequenceNumber;
  207. response->StatusCode = 0; // 0 means "didn't execute command"
  208. response->ErrorCode = 0;
  209. response->DataSize = 0;
  210. switch (request->Command) {
  211. case REQUEST_PING:
  212. response->StatusCode = 1;
  213. break;
  214. case REQUEST_GRANT_PERMISSION:
  215. {
  216. // response:
  217. // StatusCode 1 if request was valid
  218. // ErrorCode Error code from GrantPermission()
  219. REQUEST_GRANT_PERMISSION_DATA *data = &request->GrantPermissionData;
  220. if (request->DataSize == sizeof(*data) &&
  221. data->EntryCount <= ARRAYSIZE(data->Entries)) {
  222. response->ErrorCode = GrantPermission(data->ObjectType,
  223. data->ObjectName, data->Entries, data->EntryCount,
  224. data->Inheritance);
  225. response->StatusCode = 1;
  226. }
  227. }
  228. break;
  229. #ifdef IMPLEMENT_REGISTER_SERVER
  230. case REQUEST_REGISTER_SERVER:
  231. {
  232. // response:
  233. // StatusCode 1 if LoadLibrary failed,
  234. // 2 if GetProcAddress failed,
  235. // 3 if Dll(Un)RegisterServer called; possibly succeeded,
  236. // 4 if OleInitialize failed
  237. // ErrorCode Error code or HRESULT depending on the StatusCode
  238. REQUEST_REGISTER_SERVER_DATA *data = &request->RegisterServerData;
  239. if (request->DataSize == sizeof(*data)) {
  240. response->StatusCode = RegisterServer(data->Unregister,
  241. data->Filename, data->Directory, data->FailCriticalErrors,
  242. &response->ErrorCode);
  243. }
  244. }
  245. break;
  246. #endif
  247. case REQUEST_REGISTER_TYPE_LIBRARY:
  248. {
  249. // response:
  250. // StatusCode 1 if LoadTypeLib didn't return S_OK
  251. // Register only:
  252. // 2 if RegisterTypeLib called; possibly succeeded
  253. // Unregister only:
  254. // 3 if ITypeLib::GetLibAttr didn't return S_OK
  255. // 4 if UnRegisterTypeLib called; possibly succeeded
  256. // ErrorCode An HRESULT
  257. REQUEST_REGISTER_TYPE_LIBRARY_DATA *data = &request->RegisterTypeLibraryData;
  258. if (request->DataSize == sizeof(*data)) {
  259. response->StatusCode = RegisterTypeLibrary(data->Unregister,
  260. data->Filename, &response->ErrorCode);
  261. }
  262. }
  263. break;
  264. }
  265. }
  266. static BOOL WINAPI ConsoleCtrlHandlerRoutine(DWORD dwCtrlType)
  267. {
  268. // By default, during shutdown, applications without windows are killed
  269. // unconditionally. This handler suppresses that default handling, and
  270. // just ignores the termination request.
  271. //
  272. // Note: This can cause a "Process not responding" dialog to appear, but
  273. // that's still better than dying unconditionally. I don't think it's
  274. // possible to programmatically abort the shutdown sequence in a
  275. // non-windowed application. (Windowed applications, of course, can
  276. // return FALSE in response to WM_QUERYENDSESSION. But we have no message
  277. // loop so creating a window is not an option.)
  278. return TRUE;
  279. }
  280. /*
  281. void Test(void)
  282. {
  283. TGrantPermissionEntry Entry = { 0 };
  284. Entry.Sid.Authority.Value[5] = 1;
  285. Entry.Sid.SubAuthCount = 1;
  286. Entry.AccessMask = 0x1200A9;
  287. GrantPermission(SE_FILE_OBJECT, "c:\\testfile.txt", &Entry, 1, 0);
  288. }
  289. */
  290. int Main(void)
  291. {
  292. int argc;
  293. LPWSTR* argv;
  294. LONGLONG llHandle;
  295. HANDLE hPipe;
  296. LONG retval = 0;
  297. static REQUEST_DATA request;
  298. static RESPONSE_DATA response;
  299. // Work around bug in Windows XP Gold & SP1: If the application manifest
  300. // specifies COMCTL32.DLL version 6.0 (to enable visual styles), we must
  301. // call InitCommonControls() to ensure that we actually link to
  302. // COMCTL32.DLL, otherwise calls to MessageBox() fail. (XP SP2 appears
  303. // to fix this.)
  304. // NOTE: This workaround was brought over from RegDLL for consistency,
  305. // but may not actually be needed here since Setup (currently) refuses
  306. // to spawn Helper on pre-5.02 SP1 versions of Windows.
  307. InitCommonControls();
  308. SetErrorMode(SEM_FAILCRITICALERRORS);
  309. GetSystemDirectory(SystemDir, ARRAYSIZE(SystemDir));
  310. SetCurrentDirectory(SystemDir);
  311. // Give us a lower-than-default shutdown priority so that if for some
  312. // reason a shutdown is initiated while we're running, Windows
  313. // "shouldn't" try to kill us before Setup.
  314. SetProcessShutdownParameters(0x100, 0);
  315. SetConsoleCtrlHandler(ConsoleCtrlHandlerRoutine, TRUE);
  316. //
  317. // Get version and message-mode pipe handle from command line
  318. //
  319. argv = CommandLineToArgvW(GetCommandLineW(), &argc);
  320. if (argv == NULL) {
  321. return MAKELONG(GetLastError(), 1);
  322. }
  323. if (argc != 3) {
  324. return MAKELONG(0, 2);
  325. }
  326. if (StrToIntW(argv[1]) != HELPER_VERSION) {
  327. return MAKELONG(0, 3);
  328. }
  329. if (!StrToInt64ExW(argv[2], STIF_SUPPORT_HEX, &llHandle)) {
  330. return MAKELONG(0, 4);
  331. }
  332. hPipe = (HANDLE)(INT_PTR)llHandle;
  333. //
  334. // Wait for and process incoming requests
  335. //
  336. while (TRUE) {
  337. DWORD dwBytesRead, dwResponseLength, dwBytesWritten;
  338. if (!ReadFile(hPipe, &request, sizeof(request), &dwBytesRead, NULL)) {
  339. // We can normally expect ReadFile to fail with ERROR_BROKEN_PIPE
  340. // when the client has disconnected.
  341. // Note: We don't bother handling ERROR_MORE_DATA because the client
  342. // shouldn't be sending us oversized requests in the first place.
  343. if (GetLastError() != ERROR_BROKEN_PIPE) {
  344. retval = MAKELONG(GetLastError(), 5);
  345. }
  346. break;
  347. }
  348. if (dwBytesRead < FIELD_OFFSET(REQUEST_DATA, Data) ||
  349. request.DataSize != dwBytesRead - FIELD_OFFSET(REQUEST_DATA, Data)) {
  350. // Request message is too short or too long
  351. retval = MAKELONG(0, 6);
  352. break;
  353. }
  354. ProcessRequest(&request, &response);
  355. dwResponseLength = FIELD_OFFSET(RESPONSE_DATA, Data) + response.DataSize;
  356. if (!WriteFile(hPipe, &response, dwResponseLength, &dwBytesWritten, NULL)) {
  357. // WriteFile could fail if the client disconnected for some reason.
  358. retval = MAKELONG(GetLastError(), 7);
  359. break;
  360. }
  361. if (dwBytesWritten != dwResponseLength) {
  362. // Should never get here.
  363. retval = MAKELONG(0, 8);
  364. break;
  365. }
  366. }
  367. CloseHandle(hPipe);
  368. return retval;
  369. }
  370. int mainCRTStartup(void)
  371. {
  372. int retval;
  373. retval = Main();
  374. // Good idea to call ExitProcess because it'll terminate any other
  375. // threads the system might've created. A simple "return" won't.
  376. ExitProcess(retval);
  377. return retval;
  378. }