15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <tchar.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shellapi.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/sandbox_poc/sandbox.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/sandbox_poc/main_ui_window.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/sandbox.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/win/src/sandbox_factory.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Prototype allowed for functions to be called in the POC
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef void(__cdecl *lpfnInit)(HANDLE);
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ParseCommandLine(wchar_t * command_line,
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      std::string * dll_name,
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      std::string * entry_point,
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      base::string16 * log_file) {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dll_name);
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(entry_point);
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(log_file);
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dll_name || !entry_point || !log_file)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LPWSTR *arg_list;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int arg_count;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We expect the command line to contain: EntryPointName "DLLPath" "LogPath"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: Double quotes are required, even if long path name not used
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: LogPath can be blank, but still requires the double quotes
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  arg_list = CommandLineToArgvW(command_line, &arg_count);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL == arg_list || arg_count < 4) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     return false;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 entry_point_wide = arg_list[1];
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 dll_name_wide = arg_list[2];
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *entry_point = std::string(entry_point_wide.begin(), entry_point_wide.end());
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *dll_name    = std::string(dll_name_wide.begin(), dll_name_wide.end());
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *log_file    = arg_list[3];
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Free memory allocated for CommandLineToArgvW arguments.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LocalFree(arg_list);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int APIENTRY _tWinMain(HINSTANCE instance, HINSTANCE, wchar_t* command_line,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       int show_command) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UNREFERENCED_PARAMETER(command_line);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sandbox::BrokerServices* broker_service =
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sandbox::SandboxFactory::GetBrokerServices();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sandbox::ResultCode result;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This application starts as the broker; an application with a UI that
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // spawns an instance of itself (called a 'target') inside the sandbox.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Before spawning a hidden instance of itself, the application will have
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // asked the user which DLL the spawned instance should load and passes
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that as command line argument to the spawned instance.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We check here to see if we can retrieve a pointer to the BrokerServices,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which is not possible if we are running inside the sandbox under a
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // restricted token so it also tells us which mode we are in. If we can
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // retrieve the pointer, then we are the broker, otherwise we are the target
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that the broker launched.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (NULL != broker_service) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Yes, we are the broker so we need to initialize and show the UI
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (0 != (result = broker_service->Init())) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::MessageBox(NULL, L"Failed to initialize the BrokerServices object",
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   L"Error during initialization", MB_ICONERROR);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 1;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    wchar_t exe_name[MAX_PATH];
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (0 == GetModuleFileName(NULL, exe_name, MAX_PATH - 1)) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::MessageBox(NULL, L"Failed to get name of current EXE",
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   L"Error during initialization", MB_ICONERROR);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 1;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The CreateMainWindowAndLoop() call will not return until the user closes
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the application window (or selects File\Exit).
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MainUIWindow window;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window.CreateMainWindowAndLoop(instance,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   exe_name,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   show_command,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   broker_service);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Cannot exit until we have cleaned up after all the targets we have
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // created
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    broker_service->WaitForAllTargets();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This is an instance that has been spawned inside the sandbox by the
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // broker, so we need to parse the command line to figure out which DLL to
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // load and what entry point to call
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sandbox::TargetServices* target_service
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        = sandbox::SandboxFactory::GetTargetServices();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (NULL == target_service) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(finnur): write the failure to the log file
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We cannot display messageboxes inside the sandbox unless access to
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the desktop handle has been granted to us, and we don't have a
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // console window to write to. Therefore we need to have the broker
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // grant us access to a handle to a logfile and write the error that
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // occurred into the log before continuing
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return -1;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Debugging the spawned application can be tricky, because DebugBreak()
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and _asm int 3 cause the app to terminate (due to a flag in the job
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // object), MessageBoxes() will not be displayed unless we have been granted
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that privilege and the target finishes its business so quickly we cannot
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // attach to it quickly enough. Therefore, you can uncomment the
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // following line and attach (w. msdev or windbg) as the target is sleeping
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sleep(10000);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (sandbox::SBOX_ALL_OK != (result = target_service->Init())) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(finnur): write the initialization error to the log file
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return -2;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Parse the command line to find out what we need to call
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string dll_name, entry_point;
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 log_file;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ParseCommandLine(GetCommandLineW(),
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &dll_name,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &entry_point,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &log_file)) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(finnur): write the failure to the log file
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return -3;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Open the pipe to transfert the log output
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HANDLE pipe = ::CreateFile(log_file.c_str(),
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               GENERIC_WRITE,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               FILE_SHARE_READ | FILE_SHARE_WRITE,
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               NULL,  // Default security attributes.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               CREATE_ALWAYS,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               FILE_ATTRIBUTE_NORMAL,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               NULL);  // No template
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (INVALID_HANDLE_VALUE == pipe) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return -4;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We now know what we should load, so load it
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HMODULE dll_module = ::LoadLibraryA(dll_name.c_str());
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dll_module == NULL) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(finnur): write the failure to the log file
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return -5;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Initialization is finished, so we can enter lock-down mode
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    target_service->LowerToken();
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    lpfnInit init_function =
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        (lpfnInit) ::GetProcAddress(dll_module, entry_point.c_str());
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!init_function) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(finnur): write the failure to the log file
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::FreeLibrary(dll_module);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CloseHandle(pipe);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return -6;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   // Transfer control to the entry point in the DLL requested
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    init_function(pipe);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseHandle(pipe);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Sleep(1000);  // Give a change to the debug output to arrive before the
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  // end of the process
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::FreeLibrary(dll_module);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
183