Home | History | Annotate | Download | only in policy
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <shlobj.h>
      6 #include <wtsapi32.h>
      7 #pragma comment(lib, "wtsapi32.lib")
      8 
      9 #include "chrome/browser/policy/policy_path_parser.h"
     10 
     11 #include "base/command_line.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "base/win/registry.h"
     15 #include "chrome/common/chrome_switches.h"
     16 #include "policy/policy_constants.h"
     17 
     18 namespace {
     19 
     20 // Checks if the registry key exists in the given hive and expands any
     21 // variables in the string.
     22 bool LoadUserDataDirPolicyFromRegistry(HKEY hive,
     23                                        const std::wstring& key_name,
     24                                        base::FilePath* user_data_dir) {
     25   std::wstring value;
     26 
     27   base::win::RegKey policy_key(hive,
     28                                policy::kRegistryChromePolicyKey,
     29                                KEY_READ);
     30   if (policy_key.ReadValue(key_name.c_str(), &value) == ERROR_SUCCESS) {
     31     *user_data_dir =
     32         base::FilePath(policy::path_parser::ExpandPathVariables(value));
     33     return true;
     34   }
     35   return false;
     36 }
     37 
     38 const WCHAR* kMachineNamePolicyVarName = L"${machine_name}";
     39 const WCHAR* kUserNamePolicyVarName = L"${user_name}";
     40 const WCHAR* kWinDocumentsFolderVarName = L"${documents}";
     41 const WCHAR* kWinLocalAppDataFolderVarName = L"${local_app_data}";
     42 const WCHAR* kWinRoamingAppDataFolderVarName = L"${roaming_app_data}";
     43 const WCHAR* kWinProfileFolderVarName = L"${profile}";
     44 const WCHAR* kWinProgramDataFolderVarName = L"${global_app_data}";
     45 const WCHAR* kWinProgramFilesFolderVarName = L"${program_files}";
     46 const WCHAR* kWinWindowsFolderVarName = L"${windows}";
     47 const WCHAR* kWinClientName = L"${client_name}";
     48 
     49 struct WinFolderNamesToCSIDLMapping {
     50   const WCHAR* name;
     51   int id;
     52 };
     53 
     54 // Mapping from variable names to Windows CSIDL ids.
     55 const WinFolderNamesToCSIDLMapping win_folder_mapping[] = {
     56     { kWinWindowsFolderVarName,        CSIDL_WINDOWS},
     57     { kWinProgramFilesFolderVarName,   CSIDL_PROGRAM_FILES},
     58     { kWinProgramDataFolderVarName,    CSIDL_COMMON_APPDATA},
     59     { kWinProfileFolderVarName,        CSIDL_PROFILE},
     60     { kWinLocalAppDataFolderVarName,   CSIDL_LOCAL_APPDATA},
     61     { kWinRoamingAppDataFolderVarName, CSIDL_APPDATA},
     62     { kWinDocumentsFolderVarName,      CSIDL_PERSONAL}
     63 };
     64 
     65 }  // namespace
     66 
     67 namespace policy {
     68 
     69 namespace path_parser {
     70 
     71 // Replaces all variable occurances in the policy string with the respective
     72 // system settings values.
     73 base::FilePath::StringType ExpandPathVariables(
     74     const base::FilePath::StringType& untranslated_string) {
     75   base::FilePath::StringType result(untranslated_string);
     76   if (result.length() == 0)
     77     return result;
     78   // Sanitize quotes in case of any around the whole string.
     79   if (result.length() > 1 &&
     80       ((result[0] == L'"' && result[result.length() - 1] == L'"') ||
     81        (result[0] == L'\'' && result[result.length() - 1] == L'\''))) {
     82     // Strip first and last char which should be matching quotes now.
     83     result = result.substr(1, result.length() - 2);
     84   }
     85   // First translate all path variables we recognize.
     86   for (int i = 0; i < arraysize(win_folder_mapping); ++i) {
     87     size_t position = result.find(win_folder_mapping[i].name);
     88     if (position != std::wstring::npos) {
     89       WCHAR path[MAX_PATH];
     90       ::SHGetSpecialFolderPath(0, path, win_folder_mapping[i].id, false);
     91       std::wstring path_string(path);
     92       result.replace(position, wcslen(win_folder_mapping[i].name), path_string);
     93     }
     94   }
     95   // Next translate other windows specific variables.
     96   size_t position = result.find(kUserNamePolicyVarName);
     97   if (position != std::wstring::npos) {
     98     DWORD return_length = 0;
     99     ::GetUserName(NULL, &return_length);
    100     if (return_length != 0) {
    101       scoped_ptr<WCHAR[]> username(new WCHAR[return_length]);
    102       ::GetUserName(username.get(), &return_length);
    103       std::wstring username_string(username.get());
    104       result.replace(position, wcslen(kUserNamePolicyVarName), username_string);
    105     }
    106   }
    107   position = result.find(kMachineNamePolicyVarName);
    108   if (position != std::wstring::npos) {
    109     DWORD return_length = 0;
    110     ::GetComputerNameEx(ComputerNamePhysicalDnsHostname, NULL, &return_length);
    111     if (return_length != 0) {
    112       scoped_ptr<WCHAR[]> machinename(new WCHAR[return_length]);
    113       ::GetComputerNameEx(ComputerNamePhysicalDnsHostname,
    114                           machinename.get(), &return_length);
    115       std::wstring machinename_string(machinename.get());
    116       result.replace(
    117           position, wcslen(kMachineNamePolicyVarName), machinename_string);
    118     }
    119   }
    120   position = result.find(kWinClientName);
    121   if (position != std::wstring::npos) {
    122     LPWSTR buffer = NULL;
    123     DWORD buffer_length = 0;
    124     if (::WTSQuerySessionInformation(WTS_CURRENT_SERVER, WTS_CURRENT_SESSION,
    125                                      WTSClientName,
    126                                      &buffer, &buffer_length)) {
    127       std::wstring clientname_string(buffer);
    128       result.replace(position, wcslen(kWinClientName), clientname_string);
    129       ::WTSFreeMemory(buffer);
    130     }
    131   }
    132 
    133   return result;
    134 }
    135 
    136 void CheckUserDataDirPolicy(base::FilePath* user_data_dir) {
    137   DCHECK(user_data_dir);
    138   // We are running as Chrome Frame if we were invoked with user-data-dir,
    139   // chrome-frame, and automation-channel switches.
    140   CommandLine* command_line = CommandLine::ForCurrentProcess();
    141   const bool is_chrome_frame =
    142       !user_data_dir->empty() &&
    143       command_line->HasSwitch(switches::kChromeFrame) &&
    144       command_line->HasSwitch(switches::kAutomationClientChannelID);
    145 
    146   // In the case of Chrome Frame, the last path component of the user-data-dir
    147   // provided on the command line must be preserved since it is specific to
    148   // CF's host.
    149   base::FilePath cf_host_dir;
    150   if (is_chrome_frame)
    151     cf_host_dir = user_data_dir->BaseName();
    152 
    153   // Policy from the HKLM hive has precedence over HKCU so if we have one here
    154   // we don't have to try to load HKCU.
    155   const char* key_name_ascii = (is_chrome_frame ? policy::key::kGCFUserDataDir :
    156                                 policy::key::kUserDataDir);
    157   std::wstring key_name(ASCIIToWide(key_name_ascii));
    158   if (LoadUserDataDirPolicyFromRegistry(HKEY_LOCAL_MACHINE, key_name,
    159                                         user_data_dir) ||
    160       LoadUserDataDirPolicyFromRegistry(HKEY_CURRENT_USER, key_name,
    161                                         user_data_dir)) {
    162     // A Group Policy value was loaded.  Append the Chrome Frame host directory
    163     // if relevant.
    164     if (is_chrome_frame)
    165       *user_data_dir = user_data_dir->Append(cf_host_dir);
    166   }
    167 }
    168 
    169 }  // namespace path_parser
    170 
    171 }  // namespace policy
    172