123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- /*
- Inno Setup
- Copyright (C) 1997-2008 Jordan Russell
- Portions by Martijn Laan
- For conditions of distribution and use, see LICENSE.TXT.
- 64-bit helper process
- Compiled on Visual Studio 2005 SP1
- Tested on x64 and IA-64 architectures (Athlon 64 and Merced specifically).
- */
- #define _WIN32_IE 0x0600
- #include <windows.h>
- #include <commctrl.h>
- #include <shlwapi.h>
- #include <aclapi.h>
- #ifndef UNICODE
- #error UNICODE isn't defined
- #endif
- // As of Inno Setup 5.1.11, the helper is no longer used to register
- // DLLs, so avoid linking in support for REQUEST_REGISTER_SERVER.
- #undef IMPLEMENT_REGISTER_SERVER
- #define HELPER_VERSION 105
- // Request commands
- #define REQUEST_PING 1
- #define REQUEST_GRANT_PERMISSION 2
- #ifdef IMPLEMENT_REGISTER_SERVER
- #define REQUEST_REGISTER_SERVER 3
- #endif
- #define REQUEST_REGISTER_TYPE_LIBRARY 4
- // These must be kept in synch with Struct.pas:
- typedef struct {
- SID_IDENTIFIER_AUTHORITY Authority;
- BYTE SubAuthCount;
- DWORD SubAuth[2];
- } TGrantPermissionSid;
- typedef struct {
- TGrantPermissionSid Sid;
- DWORD AccessMask;
- } TGrantPermissionEntry;
- // This value must be kept in synch with Struct.pas:
- #define MAX_GRANT_PERMISSION_ENTRIES 32
- // These must be kept in synch with Helper.pas:
- typedef struct {
- DWORD ObjectType;
- DWORD EntryCount;
- DWORD Inheritance;
- WCHAR ObjectName[4096];
- TGrantPermissionEntry Entries[MAX_GRANT_PERMISSION_ENTRIES];
- } REQUEST_GRANT_PERMISSION_DATA;
- typedef struct {
- BOOL Unregister;
- BOOL FailCriticalErrors;
- WCHAR Filename[4096];
- WCHAR Directory[4096];
- } REQUEST_REGISTER_SERVER_DATA;
- typedef struct {
- BOOL Unregister;
- WCHAR Filename[4096];
- } REQUEST_REGISTER_TYPE_LIBRARY_DATA;
- typedef struct {
- DWORD SequenceNumber;
- DWORD Command;
- DWORD DataSize;
- union {
- BYTE Data[65536];
- REQUEST_GRANT_PERMISSION_DATA GrantPermissionData;
- REQUEST_REGISTER_SERVER_DATA RegisterServerData;
- REQUEST_REGISTER_TYPE_LIBRARY_DATA RegisterTypeLibraryData;
- };
- } REQUEST_DATA;
- typedef struct {
- DWORD SequenceNumber;
- DWORD StatusCode;
- DWORD ErrorCode;
- DWORD DataSize;
- BYTE Data[65536];
- } RESPONSE_DATA;
- static TCHAR SystemDir[MAX_PATH+1];
- static DWORD GrantPermission(const DWORD ObjectType, const LPWSTR ObjectName,
- TGrantPermissionEntry *Entries, const DWORD EntryCount,
- const DWORD Inheritance)
- {
- DWORD ErrorCode;
- PSECURITY_DESCRIPTOR SD;
- PACL Dacl, NewDacl;
- EXPLICIT_ACCESSW ExplicitAccess[MAX_GRANT_PERMISSION_ENTRIES];
- DWORD I;
- // Note: SecureZeroMemory is used because memset/ZeroMemory aren't available
- SecureZeroMemory(&ExplicitAccess, sizeof(ExplicitAccess));
- if (EntryCount > ARRAYSIZE(ExplicitAccess)) {
- return ERROR_INVALID_PARAMETER;
- }
- ErrorCode = GetNamedSecurityInfoW(ObjectName, ObjectType,
- DACL_SECURITY_INFORMATION, NULL, NULL, &Dacl, NULL, &SD);
- if (ErrorCode != ERROR_SUCCESS) {
- return ErrorCode;
- }
- // From here on, use "goto out" instead of "return"
- for (I = 0; I < EntryCount; I++) {
- TGrantPermissionEntry *E = &Entries[I];
- PSID Sid;
- if (!AllocateAndInitializeSid(&E->Sid.Authority, E->Sid.SubAuthCount,
- E->Sid.SubAuth[0], E->Sid.SubAuth[1], 0, 0, 0, 0, 0, 0, &Sid)) {
- ErrorCode = GetLastError();
- if (ErrorCode == 0) ErrorCode = ERROR_INVALID_PARAMETER; // just in case
- goto out;
- }
- 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;
- ExplicitAccess[I].Trustee.ptstrName = Sid;
- }
- ErrorCode = SetEntriesInAclW(EntryCount, ExplicitAccess, Dacl, &NewDacl);
- if (ErrorCode == ERROR_SUCCESS) {
- ErrorCode = SetNamedSecurityInfoW(ObjectName, ObjectType,
- DACL_SECURITY_INFORMATION, NULL, NULL, NewDacl, NULL);
- LocalFree(NewDacl);
- }
- out:
- for (I = 0; I < EntryCount; I++) {
- PSID Sid = ExplicitAccess[I].Trustee.ptstrName;
- if (Sid) FreeSid(Sid);
- }
- LocalFree(SD);
- return ErrorCode;
- }
- #ifdef IMPLEMENT_REGISTER_SERVER
- static DWORD RegisterServer(const BOOL Unregister, const LPWSTR Filename,
- const LPWSTR Directory, const BOOL FailCriticalErrors, DWORD *ErrorCode)
- {
- DWORD retval = 0;
- HRESULT OleInitResult;
- UINT SaveErrorMode;
- HANDLE LibHandle;
- // Initialize OLE. Regsvr32 does this.
- OleInitResult = OleInitialize(NULL);
- if (FAILED(OleInitResult)) {
- *ErrorCode = OleInitResult;
- return 4;
- }
-
- SaveErrorMode = SetErrorMode(FailCriticalErrors ?
- SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS :
- SEM_NOOPENFILEERRORBOX);
- // If no directory was supplied, we use the system directory.
- // Relative paths are assumed to be relative to the system directory.
- SetCurrentDirectory(SystemDir);
- if (*Directory) {
- SetCurrentDirectoryW(Directory);
- }
- LibHandle = LoadLibraryExW(Filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
- if (LibHandle) {
- typedef HRESULT (STDAPICALLTYPE *DLLREGISTERSERVER)(void);
- DLLREGISTERSERVER RegisterServerProc;
- RegisterServerProc = (DLLREGISTERSERVER)GetProcAddress(LibHandle,
- Unregister ? "DllUnregisterServer" : "DllRegisterServer");
- if (RegisterServerProc) {
- *ErrorCode = (*RegisterServerProc)();
- retval = 3;
- } else {
- *ErrorCode = GetLastError();
- retval = 2;
- }
- FreeLibrary(LibHandle);
- } else {
- *ErrorCode = GetLastError();
- retval = 1;
- }
- // Revert the current directory and error mode changes
- SetCurrentDirectory(SystemDir);
- SetErrorMode(SaveErrorMode);
- OleUninitialize();
- return retval;
- }
- #endif
- static DWORD RegisterTypeLibrary(const BOOL Unregister,
- const LPWSTR Filename, DWORD *ErrorCode)
- {
- DWORD retval;
- HRESULT hr;
- ITypeLib *TypeLib;
- TLIBATTR *LibAttr;
- retval = 1;
- hr = LoadTypeLib(Filename, &TypeLib);
- if (hr == S_OK) {
- if (!Unregister) {
- retval = 2;
- hr = RegisterTypeLib(TypeLib, Filename, NULL);
- } else {
- retval = 3;
- hr = TypeLib->lpVtbl->GetLibAttr(TypeLib, &LibAttr);
- if (hr == S_OK) {
- retval = 4;
- hr = UnRegisterTypeLib(&LibAttr->guid, LibAttr->wMajorVerNum,
- LibAttr->wMinorVerNum, LibAttr->lcid, LibAttr->syskind);
- TypeLib->lpVtbl->ReleaseTLibAttr(TypeLib, LibAttr);
- }
- }
- TypeLib->lpVtbl->Release(TypeLib);
- }
- *ErrorCode = hr;
- return retval;
- }
- static void ProcessRequest(REQUEST_DATA *request, RESPONSE_DATA *response)
- {
- response->SequenceNumber = request->SequenceNumber;
- response->StatusCode = 0; // 0 means "didn't execute command"
- response->ErrorCode = 0;
- response->DataSize = 0;
- switch (request->Command) {
- case REQUEST_PING:
- response->StatusCode = 1;
- break;
- case REQUEST_GRANT_PERMISSION:
- {
- // response:
- // StatusCode 1 if request was valid
- // ErrorCode Error code from GrantPermission()
-
- REQUEST_GRANT_PERMISSION_DATA *data = &request->GrantPermissionData;
- if (request->DataSize == sizeof(*data) &&
- data->EntryCount <= ARRAYSIZE(data->Entries)) {
- response->ErrorCode = GrantPermission(data->ObjectType,
- data->ObjectName, data->Entries, data->EntryCount,
- data->Inheritance);
- response->StatusCode = 1;
- }
- }
- break;
- #ifdef IMPLEMENT_REGISTER_SERVER
- case REQUEST_REGISTER_SERVER:
- {
- // response:
- // StatusCode 1 if LoadLibrary failed,
- // 2 if GetProcAddress failed,
- // 3 if Dll(Un)RegisterServer called; possibly succeeded,
- // 4 if OleInitialize failed
- // ErrorCode Error code or HRESULT depending on the StatusCode
- REQUEST_REGISTER_SERVER_DATA *data = &request->RegisterServerData;
- if (request->DataSize == sizeof(*data)) {
- response->StatusCode = RegisterServer(data->Unregister,
- data->Filename, data->Directory, data->FailCriticalErrors,
- &response->ErrorCode);
- }
- }
- break;
- #endif
- case REQUEST_REGISTER_TYPE_LIBRARY:
- {
- // response:
- // StatusCode 1 if LoadTypeLib didn't return S_OK
- // Register only:
- // 2 if RegisterTypeLib called; possibly succeeded
- // Unregister only:
- // 3 if ITypeLib::GetLibAttr didn't return S_OK
- // 4 if UnRegisterTypeLib called; possibly succeeded
- // ErrorCode An HRESULT
- REQUEST_REGISTER_TYPE_LIBRARY_DATA *data = &request->RegisterTypeLibraryData;
- if (request->DataSize == sizeof(*data)) {
- response->StatusCode = RegisterTypeLibrary(data->Unregister,
- data->Filename, &response->ErrorCode);
- }
- }
- break;
- }
- }
- static BOOL WINAPI ConsoleCtrlHandlerRoutine(DWORD dwCtrlType)
- {
- // By default, during shutdown, applications without windows are killed
- // unconditionally. This handler suppresses that default handling, and
- // just ignores the termination request.
- //
- // Note: This can cause a "Process not responding" dialog to appear, but
- // that's still better than dying unconditionally. I don't think it's
- // possible to programmatically abort the shutdown sequence in a
- // non-windowed application. (Windowed applications, of course, can
- // return FALSE in response to WM_QUERYENDSESSION. But we have no message
- // loop so creating a window is not an option.)
- return TRUE;
- }
- /*
- void Test(void)
- {
- TGrantPermissionEntry Entry = { 0 };
- Entry.Sid.Authority.Value[5] = 1;
- Entry.Sid.SubAuthCount = 1;
- Entry.AccessMask = 0x1200A9;
- GrantPermission(SE_FILE_OBJECT, "c:\\testfile.txt", &Entry, 1, 0);
- }
- */
- int Main(void)
- {
- int argc;
- LPWSTR* argv;
- LONGLONG llHandle;
- HANDLE hPipe;
- LONG retval = 0;
- static REQUEST_DATA request;
- static RESPONSE_DATA response;
- // Work around bug in Windows XP Gold & SP1: If the application manifest
- // specifies COMCTL32.DLL version 6.0 (to enable visual styles), we must
- // call InitCommonControls() to ensure that we actually link to
- // COMCTL32.DLL, otherwise calls to MessageBox() fail. (XP SP2 appears
- // to fix this.)
- // NOTE: This workaround was brought over from RegDLL for consistency,
- // but may not actually be needed here since Setup (currently) refuses
- // to spawn Helper on pre-5.02 SP1 versions of Windows.
- InitCommonControls();
- SetErrorMode(SEM_FAILCRITICALERRORS);
- GetSystemDirectory(SystemDir, ARRAYSIZE(SystemDir));
- SetCurrentDirectory(SystemDir);
- // Give us a lower-than-default shutdown priority so that if for some
- // reason a shutdown is initiated while we're running, Windows
- // "shouldn't" try to kill us before Setup.
- SetProcessShutdownParameters(0x100, 0);
- SetConsoleCtrlHandler(ConsoleCtrlHandlerRoutine, TRUE);
- //
- // Get version and message-mode pipe handle from command line
- //
- argv = CommandLineToArgvW(GetCommandLineW(), &argc);
- if (argv == NULL) {
- return MAKELONG(GetLastError(), 1);
- }
- if (argc != 3) {
- return MAKELONG(0, 2);
- }
- if (StrToIntW(argv[1]) != HELPER_VERSION) {
- return MAKELONG(0, 3);
- }
- if (!StrToInt64ExW(argv[2], STIF_SUPPORT_HEX, &llHandle)) {
- return MAKELONG(0, 4);
- }
- hPipe = (HANDLE)(INT_PTR)llHandle;
- //
- // Wait for and process incoming requests
- //
- while (TRUE) {
- DWORD dwBytesRead, dwResponseLength, dwBytesWritten;
- if (!ReadFile(hPipe, &request, sizeof(request), &dwBytesRead, NULL)) {
- // We can normally expect ReadFile to fail with ERROR_BROKEN_PIPE
- // when the client has disconnected.
- // Note: We don't bother handling ERROR_MORE_DATA because the client
- // shouldn't be sending us oversized requests in the first place.
- if (GetLastError() != ERROR_BROKEN_PIPE) {
- retval = MAKELONG(GetLastError(), 5);
- }
- break;
- }
- if (dwBytesRead < FIELD_OFFSET(REQUEST_DATA, Data) ||
- request.DataSize != dwBytesRead - FIELD_OFFSET(REQUEST_DATA, Data)) {
- // Request message is too short or too long
- retval = MAKELONG(0, 6);
- break;
- }
- ProcessRequest(&request, &response);
- dwResponseLength = FIELD_OFFSET(RESPONSE_DATA, Data) + response.DataSize;
- if (!WriteFile(hPipe, &response, dwResponseLength, &dwBytesWritten, NULL)) {
- // WriteFile could fail if the client disconnected for some reason.
- retval = MAKELONG(GetLastError(), 7);
- break;
- }
- if (dwBytesWritten != dwResponseLength) {
- // Should never get here.
- retval = MAKELONG(0, 8);
- break;
- }
- }
- CloseHandle(hPipe);
- return retval;
- }
- int mainCRTStartup(void)
- {
- int retval;
- retval = Main();
-
- // Good idea to call ExitProcess because it'll terminate any other
- // threads the system might've created. A simple "return" won't.
- ExitProcess(retval);
- return retval;
- }
|