toolkit/xre/nsWindowsRestart.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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 // This file is not build directly. Instead, it is included in multiple
michael@0 6 // shared objects.
michael@0 7
michael@0 8 #ifdef nsWindowsRestart_cpp
michael@0 9 #error "nsWindowsRestart.cpp is not a header file, and must only be included once."
michael@0 10 #else
michael@0 11 #define nsWindowsRestart_cpp
michael@0 12 #endif
michael@0 13
michael@0 14 #include "nsUTF8Utils.h"
michael@0 15
michael@0 16 #include <shellapi.h>
michael@0 17
michael@0 18 // Needed for CreateEnvironmentBlock
michael@0 19 #include <userenv.h>
michael@0 20 #pragma comment(lib, "userenv.lib")
michael@0 21
michael@0 22 /**
michael@0 23 * Get the length that the string will take and takes into account the
michael@0 24 * additional length if the string needs to be quoted and if characters need to
michael@0 25 * be escaped.
michael@0 26 */
michael@0 27 static int ArgStrLen(const wchar_t *s)
michael@0 28 {
michael@0 29 int backslashes = 0;
michael@0 30 int i = wcslen(s);
michael@0 31 BOOL hasDoubleQuote = wcschr(s, L'"') != nullptr;
michael@0 32 // Only add doublequotes if the string contains a space or a tab
michael@0 33 BOOL addDoubleQuotes = wcspbrk(s, L" \t") != nullptr;
michael@0 34
michael@0 35 if (addDoubleQuotes) {
michael@0 36 i += 2; // initial and final duoblequote
michael@0 37 }
michael@0 38
michael@0 39 if (hasDoubleQuote) {
michael@0 40 while (*s) {
michael@0 41 if (*s == '\\') {
michael@0 42 ++backslashes;
michael@0 43 } else {
michael@0 44 if (*s == '"') {
michael@0 45 // Escape the doublequote and all backslashes preceding the doublequote
michael@0 46 i += backslashes + 1;
michael@0 47 }
michael@0 48
michael@0 49 backslashes = 0;
michael@0 50 }
michael@0 51
michael@0 52 ++s;
michael@0 53 }
michael@0 54 }
michael@0 55
michael@0 56 return i;
michael@0 57 }
michael@0 58
michael@0 59 /**
michael@0 60 * Copy string "s" to string "d", quoting the argument as appropriate and
michael@0 61 * escaping doublequotes along with any backslashes that immediately precede
michael@0 62 * doublequotes.
michael@0 63 * The CRT parses this to retrieve the original argc/argv that we meant,
michael@0 64 * see STDARGV.C in the MSVC CRT sources.
michael@0 65 *
michael@0 66 * @return the end of the string
michael@0 67 */
michael@0 68 static wchar_t* ArgToString(wchar_t *d, const wchar_t *s)
michael@0 69 {
michael@0 70 int backslashes = 0;
michael@0 71 BOOL hasDoubleQuote = wcschr(s, L'"') != nullptr;
michael@0 72 // Only add doublequotes if the string contains a space or a tab
michael@0 73 BOOL addDoubleQuotes = wcspbrk(s, L" \t") != nullptr;
michael@0 74
michael@0 75 if (addDoubleQuotes) {
michael@0 76 *d = '"'; // initial doublequote
michael@0 77 ++d;
michael@0 78 }
michael@0 79
michael@0 80 if (hasDoubleQuote) {
michael@0 81 int i;
michael@0 82 while (*s) {
michael@0 83 if (*s == '\\') {
michael@0 84 ++backslashes;
michael@0 85 } else {
michael@0 86 if (*s == '"') {
michael@0 87 // Escape the doublequote and all backslashes preceding the doublequote
michael@0 88 for (i = 0; i <= backslashes; ++i) {
michael@0 89 *d = '\\';
michael@0 90 ++d;
michael@0 91 }
michael@0 92 }
michael@0 93
michael@0 94 backslashes = 0;
michael@0 95 }
michael@0 96
michael@0 97 *d = *s;
michael@0 98 ++d; ++s;
michael@0 99 }
michael@0 100 } else {
michael@0 101 wcscpy(d, s);
michael@0 102 d += wcslen(s);
michael@0 103 }
michael@0 104
michael@0 105 if (addDoubleQuotes) {
michael@0 106 *d = '"'; // final doublequote
michael@0 107 ++d;
michael@0 108 }
michael@0 109
michael@0 110 return d;
michael@0 111 }
michael@0 112
michael@0 113 /**
michael@0 114 * Creates a command line from a list of arguments. The returned
michael@0 115 * string is allocated with "malloc" and should be "free"d.
michael@0 116 *
michael@0 117 * argv is UTF8
michael@0 118 */
michael@0 119 wchar_t*
michael@0 120 MakeCommandLine(int argc, wchar_t **argv)
michael@0 121 {
michael@0 122 int i;
michael@0 123 int len = 0;
michael@0 124
michael@0 125 // The + 1 of the last argument handles the allocation for null termination
michael@0 126 for (i = 0; i < argc; ++i)
michael@0 127 len += ArgStrLen(argv[i]) + 1;
michael@0 128
michael@0 129 // Protect against callers that pass 0 arguments
michael@0 130 if (len == 0)
michael@0 131 len = 1;
michael@0 132
michael@0 133 wchar_t *s = (wchar_t*) malloc(len * sizeof(wchar_t));
michael@0 134 if (!s)
michael@0 135 return nullptr;
michael@0 136
michael@0 137 wchar_t *c = s;
michael@0 138 for (i = 0; i < argc; ++i) {
michael@0 139 c = ArgToString(c, argv[i]);
michael@0 140 if (i + 1 != argc) {
michael@0 141 *c = ' ';
michael@0 142 ++c;
michael@0 143 }
michael@0 144 }
michael@0 145
michael@0 146 *c = '\0';
michael@0 147
michael@0 148 return s;
michael@0 149 }
michael@0 150
michael@0 151 /**
michael@0 152 * Convert UTF8 to UTF16 without using the normal XPCOM goop, which we
michael@0 153 * can't link to updater.exe.
michael@0 154 */
michael@0 155 static char16_t*
michael@0 156 AllocConvertUTF8toUTF16(const char *arg)
michael@0 157 {
michael@0 158 // UTF16 can't be longer in units than UTF8
michael@0 159 int len = strlen(arg);
michael@0 160 char16_t *s = new char16_t[(len + 1) * sizeof(char16_t)];
michael@0 161 if (!s)
michael@0 162 return nullptr;
michael@0 163
michael@0 164 ConvertUTF8toUTF16 convert(s);
michael@0 165 convert.write(arg, len);
michael@0 166 convert.write_terminator();
michael@0 167 return s;
michael@0 168 }
michael@0 169
michael@0 170 static void
michael@0 171 FreeAllocStrings(int argc, wchar_t **argv)
michael@0 172 {
michael@0 173 while (argc) {
michael@0 174 --argc;
michael@0 175 delete [] argv[argc];
michael@0 176 }
michael@0 177
michael@0 178 delete [] argv;
michael@0 179 }
michael@0 180
michael@0 181
michael@0 182
michael@0 183 /**
michael@0 184 * Launch a child process with the specified arguments.
michael@0 185 * @note argv[0] is ignored
michael@0 186 * @note The form of this function that takes char **argv expects UTF-8
michael@0 187 */
michael@0 188
michael@0 189 BOOL
michael@0 190 WinLaunchChild(const wchar_t *exePath,
michael@0 191 int argc, wchar_t **argv,
michael@0 192 HANDLE userToken = nullptr,
michael@0 193 HANDLE *hProcess = nullptr);
michael@0 194
michael@0 195 BOOL
michael@0 196 WinLaunchChild(const wchar_t *exePath,
michael@0 197 int argc, char **argv,
michael@0 198 HANDLE userToken,
michael@0 199 HANDLE *hProcess)
michael@0 200 {
michael@0 201 wchar_t** argvConverted = new wchar_t*[argc];
michael@0 202 if (!argvConverted)
michael@0 203 return FALSE;
michael@0 204
michael@0 205 for (int i = 0; i < argc; ++i) {
michael@0 206 argvConverted[i] = reinterpret_cast<wchar_t*>(AllocConvertUTF8toUTF16(argv[i]));
michael@0 207 if (!argvConverted[i]) {
michael@0 208 FreeAllocStrings(i, argvConverted);
michael@0 209 return FALSE;
michael@0 210 }
michael@0 211 }
michael@0 212
michael@0 213 BOOL ok = WinLaunchChild(exePath, argc, argvConverted, userToken, hProcess);
michael@0 214 FreeAllocStrings(argc, argvConverted);
michael@0 215 return ok;
michael@0 216 }
michael@0 217
michael@0 218 BOOL
michael@0 219 WinLaunchChild(const wchar_t *exePath,
michael@0 220 int argc,
michael@0 221 wchar_t **argv,
michael@0 222 HANDLE userToken,
michael@0 223 HANDLE *hProcess)
michael@0 224 {
michael@0 225 wchar_t *cl;
michael@0 226 BOOL ok;
michael@0 227
michael@0 228 cl = MakeCommandLine(argc, argv);
michael@0 229 if (!cl) {
michael@0 230 return FALSE;
michael@0 231 }
michael@0 232
michael@0 233 STARTUPINFOW si = {0};
michael@0 234 si.cb = sizeof(STARTUPINFOW);
michael@0 235 si.lpDesktop = L"winsta0\\Default";
michael@0 236 PROCESS_INFORMATION pi = {0};
michael@0 237
michael@0 238 if (userToken == nullptr) {
michael@0 239 ok = CreateProcessW(exePath,
michael@0 240 cl,
michael@0 241 nullptr, // no special security attributes
michael@0 242 nullptr, // no special thread attributes
michael@0 243 FALSE, // don't inherit filehandles
michael@0 244 0, // creation flags
michael@0 245 nullptr, // inherit my environment
michael@0 246 nullptr, // use my current directory
michael@0 247 &si,
michael@0 248 &pi);
michael@0 249 } else {
michael@0 250 // Create an environment block for the process we're about to start using
michael@0 251 // the user's token.
michael@0 252 LPVOID environmentBlock = nullptr;
michael@0 253 if (!CreateEnvironmentBlock(&environmentBlock, userToken, TRUE)) {
michael@0 254 environmentBlock = nullptr;
michael@0 255 }
michael@0 256
michael@0 257 ok = CreateProcessAsUserW(userToken,
michael@0 258 exePath,
michael@0 259 cl,
michael@0 260 nullptr, // no special security attributes
michael@0 261 nullptr, // no special thread attributes
michael@0 262 FALSE, // don't inherit filehandles
michael@0 263 0, // creation flags
michael@0 264 environmentBlock,
michael@0 265 nullptr, // use my current directory
michael@0 266 &si,
michael@0 267 &pi);
michael@0 268
michael@0 269 if (environmentBlock) {
michael@0 270 DestroyEnvironmentBlock(environmentBlock);
michael@0 271 }
michael@0 272 }
michael@0 273
michael@0 274 if (ok) {
michael@0 275 if (hProcess) {
michael@0 276 *hProcess = pi.hProcess; // the caller now owns the HANDLE
michael@0 277 } else {
michael@0 278 CloseHandle(pi.hProcess);
michael@0 279 }
michael@0 280 CloseHandle(pi.hThread);
michael@0 281 } else {
michael@0 282 LPVOID lpMsgBuf = nullptr;
michael@0 283 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
michael@0 284 FORMAT_MESSAGE_FROM_SYSTEM |
michael@0 285 FORMAT_MESSAGE_IGNORE_INSERTS,
michael@0 286 nullptr,
michael@0 287 GetLastError(),
michael@0 288 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
michael@0 289 (LPTSTR) &lpMsgBuf,
michael@0 290 0,
michael@0 291 nullptr);
michael@0 292 wprintf(L"Error restarting: %s\n", lpMsgBuf ? lpMsgBuf : L"(null)");
michael@0 293 if (lpMsgBuf)
michael@0 294 LocalFree(lpMsgBuf);
michael@0 295 }
michael@0 296
michael@0 297 free(cl);
michael@0 298
michael@0 299 return ok;
michael@0 300 }

mercurial