other-licenses/nsis/Contrib/ServicesHelper/Services.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include <windows.h>
michael@0 6 #include "../../../../toolkit/mozapps/update/common/pathhash.h"
michael@0 7
michael@0 8 #pragma comment(lib, "advapi32.lib")
michael@0 9
michael@0 10 typedef struct _stack_t {
michael@0 11 struct _stack_t *next;
michael@0 12 TCHAR text[MAX_PATH];
michael@0 13 } stack_t;
michael@0 14
michael@0 15 int popstring(stack_t **stacktop, LPTSTR str, int len);
michael@0 16 void pushstring(stack_t **stacktop, LPCTSTR str, int len);
michael@0 17
michael@0 18 /**
michael@0 19 * Determines if the specified service exists or not
michael@0 20 *
michael@0 21 * @param serviceName The name of the service to check
michael@0 22 * @param exists Whether or not the service exists
michael@0 23 * @return TRUE if there were no errors
michael@0 24 */
michael@0 25 static BOOL
michael@0 26 IsServiceInstalled(LPCWSTR serviceName, BOOL &exists)
michael@0 27 {
michael@0 28 exists = FALSE;
michael@0 29
michael@0 30 // Get a handle to the local computer SCM database with full access rights.
michael@0 31 SC_HANDLE serviceManager = OpenSCManager(NULL, NULL,
michael@0 32 SC_MANAGER_ENUMERATE_SERVICE);
michael@0 33 if (!serviceManager) {
michael@0 34 return FALSE;
michael@0 35 }
michael@0 36
michael@0 37 SC_HANDLE serviceHandle = OpenServiceW(serviceManager,
michael@0 38 serviceName,
michael@0 39 SERVICE_QUERY_CONFIG);
michael@0 40 if (!serviceHandle && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) {
michael@0 41 CloseServiceHandle(serviceManager);
michael@0 42 return FALSE;
michael@0 43 }
michael@0 44
michael@0 45 if (serviceHandle) {
michael@0 46 CloseServiceHandle(serviceHandle);
michael@0 47 exists = TRUE;
michael@0 48 }
michael@0 49
michael@0 50 CloseServiceHandle(serviceManager);
michael@0 51 return TRUE;
michael@0 52 }
michael@0 53
michael@0 54 /**
michael@0 55 * Determines if the specified service is installed or not
michael@0 56 *
michael@0 57 * @param stacktop A pointer to the top of the stack
michael@0 58 * @param variables A pointer to the NSIS variables
michael@0 59 * @return 0 if the service does not exist
michael@0 60 * 1 if the service does exist
michael@0 61 * -1 if there was an error.
michael@0 62 */
michael@0 63 extern "C" void __declspec(dllexport)
michael@0 64 IsInstalled(HWND hwndParent, int string_size,
michael@0 65 TCHAR *variables, stack_t **stacktop, void *extra)
michael@0 66 {
michael@0 67 TCHAR tmp[MAX_PATH] = { L'\0' };
michael@0 68 WCHAR serviceName[MAX_PATH] = { '\0' };
michael@0 69 popstring(stacktop, tmp, MAX_PATH);
michael@0 70
michael@0 71 #if !defined(UNICODE)
michael@0 72 MultiByteToWideChar(CP_ACP, 0, tmp, -1, serviceName, MAX_PATH);
michael@0 73 #else
michael@0 74 wcscpy(serviceName, tmp);
michael@0 75 #endif
michael@0 76
michael@0 77 BOOL serviceInstalled;
michael@0 78 if (!IsServiceInstalled(serviceName, serviceInstalled)) {
michael@0 79 pushstring(stacktop, TEXT("-1"), 3);
michael@0 80 } else {
michael@0 81 pushstring(stacktop, serviceInstalled ? TEXT("1") : TEXT("0"), 2);
michael@0 82 }
michael@0 83 }
michael@0 84
michael@0 85 /**
michael@0 86 * Stops the specified service.
michael@0 87 *
michael@0 88 * @param serviceName The name of the service to stop
michael@0 89 * @return TRUE if the operation was successful
michael@0 90 */
michael@0 91 static BOOL
michael@0 92 StopService(LPCWSTR serviceName)
michael@0 93 {
michael@0 94 // Get a handle to the local computer SCM database with full access rights.
michael@0 95 SC_HANDLE serviceManager = OpenSCManager(NULL, NULL,
michael@0 96 SC_MANAGER_ENUMERATE_SERVICE);
michael@0 97 if (!serviceManager) {
michael@0 98 return FALSE;
michael@0 99 }
michael@0 100
michael@0 101 SC_HANDLE serviceHandle = OpenServiceW(serviceManager,
michael@0 102 serviceName,
michael@0 103 SERVICE_STOP);
michael@0 104 if (!serviceHandle) {
michael@0 105 CloseServiceHandle(serviceManager);
michael@0 106 return FALSE;
michael@0 107 }
michael@0 108
michael@0 109 //Stop the service so it deletes faster and so the uninstaller
michael@0 110 // can actually delete its EXE.
michael@0 111 DWORD totalWaitTime = 0;
michael@0 112 SERVICE_STATUS status;
michael@0 113 static const int maxWaitTime = 1000 * 60; // Never wait more than a minute
michael@0 114 BOOL stopped = FALSE;
michael@0 115 if (ControlService(serviceHandle, SERVICE_CONTROL_STOP, &status)) {
michael@0 116 do {
michael@0 117 Sleep(status.dwWaitHint);
michael@0 118 // + 10 milliseconds to make sure we always approach maxWaitTime
michael@0 119 totalWaitTime += (status.dwWaitHint + 10);
michael@0 120 if (status.dwCurrentState == SERVICE_STOPPED) {
michael@0 121 stopped = true;
michael@0 122 break;
michael@0 123 } else if (totalWaitTime > maxWaitTime) {
michael@0 124 break;
michael@0 125 }
michael@0 126 } while (QueryServiceStatus(serviceHandle, &status));
michael@0 127 }
michael@0 128
michael@0 129 CloseServiceHandle(serviceHandle);
michael@0 130 CloseServiceHandle(serviceManager);
michael@0 131 return stopped;
michael@0 132 }
michael@0 133
michael@0 134 /**
michael@0 135 * Stops the specified service
michael@0 136 *
michael@0 137 * @param stacktop A pointer to the top of the stack
michael@0 138 * @param variables A pointer to the NSIS variables
michael@0 139 * @return 1 if the service was stopped, 0 on error
michael@0 140 */
michael@0 141 extern "C" void __declspec(dllexport)
michael@0 142 Stop(HWND hwndParent, int string_size,
michael@0 143 TCHAR *variables, stack_t **stacktop, void *extra)
michael@0 144 {
michael@0 145 TCHAR tmp[MAX_PATH] = { L'\0' };
michael@0 146 WCHAR serviceName[MAX_PATH] = { '\0' };
michael@0 147
michael@0 148 popstring(stacktop, tmp, MAX_PATH);
michael@0 149
michael@0 150 #if !defined(UNICODE)
michael@0 151 MultiByteToWideChar(CP_ACP, 0, tmp, -1, serviceName, MAX_PATH);
michael@0 152 #else
michael@0 153 wcscpy(serviceName, tmp);
michael@0 154 #endif
michael@0 155
michael@0 156 if (StopService(serviceName)) {
michael@0 157 pushstring(stacktop, TEXT("1"), 2);
michael@0 158 } else {
michael@0 159 pushstring(stacktop, TEXT("0"), 2);
michael@0 160 }
michael@0 161 }
michael@0 162
michael@0 163 /**
michael@0 164 * Determines a unique registry path from a file or directory path
michael@0 165 *
michael@0 166 * @param stacktop A pointer to the top of the stack
michael@0 167 * @param variables A pointer to the NSIS variables
michael@0 168 * @return The unique registry path or an empty string on error
michael@0 169 */
michael@0 170 extern "C" void __declspec(dllexport)
michael@0 171 PathToUniqueRegistryPath(HWND hwndParent, int string_size,
michael@0 172 TCHAR *variables, stack_t **stacktop,
michael@0 173 void *extra)
michael@0 174 {
michael@0 175 TCHAR tmp[MAX_PATH] = { L'\0' };
michael@0 176 WCHAR installBasePath[MAX_PATH] = { '\0' };
michael@0 177 popstring(stacktop, tmp, MAX_PATH);
michael@0 178
michael@0 179 #if !defined(UNICODE)
michael@0 180 MultiByteToWideChar(CP_ACP, 0, tmp, -1, installBasePath, MAX_PATH);
michael@0 181 #else
michael@0 182 wcscpy(installBasePath, tmp);
michael@0 183 #endif
michael@0 184
michael@0 185 WCHAR registryPath[MAX_PATH + 1] = { '\0' };
michael@0 186 if (CalculateRegistryPathFromFilePath(installBasePath, registryPath)) {
michael@0 187 pushstring(stacktop, registryPath, wcslen(registryPath) + 1);
michael@0 188 } else {
michael@0 189 pushstring(stacktop, TEXT(""), 1);
michael@0 190 }
michael@0 191 }
michael@0 192
michael@0 193 BOOL WINAPI
michael@0 194 DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
michael@0 195 {
michael@0 196 return TRUE;
michael@0 197 }
michael@0 198
michael@0 199 /**
michael@0 200 * Removes an element from the top of the NSIS stack
michael@0 201 *
michael@0 202 * @param stacktop A pointer to the top of the stack
michael@0 203 * @param str The string to pop to
michael@0 204 * @param len The max length
michael@0 205 * @return 0 on success
michael@0 206 */
michael@0 207 int popstring(stack_t **stacktop, TCHAR *str, int len)
michael@0 208 {
michael@0 209 // Removes the element from the top of the stack and puts it in the buffer
michael@0 210 stack_t *th;
michael@0 211 if (!stacktop || !*stacktop) {
michael@0 212 return 1;
michael@0 213 }
michael@0 214
michael@0 215 th = (*stacktop);
michael@0 216 lstrcpyn(str,th->text, len);
michael@0 217 *stacktop = th->next;
michael@0 218 GlobalFree((HGLOBAL)th);
michael@0 219 return 0;
michael@0 220 }
michael@0 221
michael@0 222 /**
michael@0 223 * Adds an element to the top of the NSIS stack
michael@0 224 *
michael@0 225 * @param stacktop A pointer to the top of the stack
michael@0 226 * @param str The string to push on the stack
michael@0 227 * @param len The length of the string to push on the stack
michael@0 228 * @return 0 on success
michael@0 229 */
michael@0 230 void pushstring(stack_t **stacktop, const TCHAR *str, int len)
michael@0 231 {
michael@0 232 stack_t *th;
michael@0 233 if (!stacktop) {
michael@0 234 return;
michael@0 235 }
michael@0 236
michael@0 237 th = (stack_t*)GlobalAlloc(GPTR, sizeof(stack_t) + len);
michael@0 238 lstrcpyn(th->text, str, len);
michael@0 239 th->next = *stacktop;
michael@0 240 *stacktop = th;
michael@0 241 }

mercurial