toolkit/mozapps/update/common/uachelper.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include <windows.h>
     6 #include <wtsapi32.h>
     7 #include "uachelper.h"
     8 #include "updatelogging.h"
    10 // See the MSDN documentation with title: Privilege Constants
    11 // At the time of this writing, this documentation is located at: 
    12 // http://msdn.microsoft.com/en-us/library/windows/desktop/bb530716%28v=vs.85%29.aspx
    13 LPCTSTR UACHelper::PrivsToDisable[] = { 
    14   SE_ASSIGNPRIMARYTOKEN_NAME,
    15   SE_AUDIT_NAME,
    16   SE_BACKUP_NAME,
    17   // CreateProcess will succeed but the app will fail to launch on some WinXP 
    18   // machines if SE_CHANGE_NOTIFY_NAME is disabled.  In particular this happens
    19   // for limited user accounts on those machines.  The define is kept here as a
    20   // reminder that it should never be re-added.  
    21   // This permission is for directory watching but also from MSDN: "This
    22   // privilege also causes the system to skip all traversal access checks."
    23   // SE_CHANGE_NOTIFY_NAME,
    24   SE_CREATE_GLOBAL_NAME,
    25   SE_CREATE_PAGEFILE_NAME,
    26   SE_CREATE_PERMANENT_NAME,
    27   SE_CREATE_SYMBOLIC_LINK_NAME,
    28   SE_CREATE_TOKEN_NAME,
    29   SE_DEBUG_NAME,
    30   SE_ENABLE_DELEGATION_NAME,
    31   SE_IMPERSONATE_NAME,
    32   SE_INC_BASE_PRIORITY_NAME,
    33   SE_INCREASE_QUOTA_NAME,
    34   SE_INC_WORKING_SET_NAME,
    35   SE_LOAD_DRIVER_NAME,
    36   SE_LOCK_MEMORY_NAME,
    37   SE_MACHINE_ACCOUNT_NAME,
    38   SE_MANAGE_VOLUME_NAME,
    39   SE_PROF_SINGLE_PROCESS_NAME,
    40   SE_RELABEL_NAME,
    41   SE_REMOTE_SHUTDOWN_NAME,
    42   SE_RESTORE_NAME,
    43   SE_SECURITY_NAME,
    44   SE_SHUTDOWN_NAME,
    45   SE_SYNC_AGENT_NAME,
    46   SE_SYSTEM_ENVIRONMENT_NAME,
    47   SE_SYSTEM_PROFILE_NAME,
    48   SE_SYSTEMTIME_NAME,
    49   SE_TAKE_OWNERSHIP_NAME,
    50   SE_TCB_NAME,
    51   SE_TIME_ZONE_NAME,
    52   SE_TRUSTED_CREDMAN_ACCESS_NAME,
    53   SE_UNDOCK_NAME,
    54   SE_UNSOLICITED_INPUT_NAME
    55 };
    57 /**
    58  * Opens a user token for the given session ID
    59  *
    60  * @param  sessionID  The session ID for the token to obtain
    61  * @return A handle to the token to obtain which will be primary if enough
    62  *         permissions exist.  Caller should close the handle.
    63  */
    64 HANDLE
    65 UACHelper::OpenUserToken(DWORD sessionID)
    66 {
    67   HMODULE module = LoadLibraryW(L"wtsapi32.dll");
    68   HANDLE token = nullptr;
    69   decltype(WTSQueryUserToken)* wtsQueryUserToken = 
    70     (decltype(WTSQueryUserToken)*) GetProcAddress(module, "WTSQueryUserToken");
    71   if (wtsQueryUserToken) {
    72     wtsQueryUserToken(sessionID, &token);
    73   }
    74   FreeLibrary(module);
    75   return token;
    76 }
    78 /**
    79  * Opens a linked token for the specified token.
    80  *
    81  * @param  token The token to get the linked token from
    82  * @return A linked token or nullptr if one does not exist.
    83  *         Caller should close the handle.
    84  */
    85 HANDLE
    86 UACHelper::OpenLinkedToken(HANDLE token)
    87 {
    88   // Magic below...
    89   // UAC creates 2 tokens.  One is the restricted token which we have.
    90   // the other is the UAC elevated one. Since we are running as a service
    91   // as the system account we have access to both.
    92   TOKEN_LINKED_TOKEN tlt;
    93   HANDLE hNewLinkedToken = nullptr;
    94   DWORD len;
    95   if (GetTokenInformation(token, (TOKEN_INFORMATION_CLASS)TokenLinkedToken, 
    96                           &tlt, sizeof(TOKEN_LINKED_TOKEN), &len)) {
    97     token = tlt.LinkedToken;
    98     hNewLinkedToken = token;
    99   }
   100   return hNewLinkedToken;
   101 }
   104 /**
   105  * Enables or disables a privilege for the specified token.
   106  *
   107  * @param  token  The token to adjust the privilege on.
   108  * @param  priv   The privilege to adjust.
   109  * @param  enable Whether to enable or disable it
   110  * @return TRUE if the token was adjusted to the specified value.
   111  */
   112 BOOL 
   113 UACHelper::SetPrivilege(HANDLE token, LPCTSTR priv, BOOL enable)
   114 {
   115   LUID luidOfPriv;
   116   if (!LookupPrivilegeValue(nullptr, priv, &luidOfPriv)) {
   117     return FALSE; 
   118   }
   120   TOKEN_PRIVILEGES tokenPriv;
   121   tokenPriv.PrivilegeCount = 1;
   122   tokenPriv.Privileges[0].Luid = luidOfPriv;
   123   tokenPriv.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
   125   SetLastError(ERROR_SUCCESS);
   126   if (!AdjustTokenPrivileges(token, false, &tokenPriv,
   127                              sizeof(tokenPriv), nullptr, nullptr)) {
   128     return FALSE; 
   129   } 
   131   return GetLastError() == ERROR_SUCCESS;
   132 }
   134 /**
   135  * For each privilege that is specified, an attempt will be made to 
   136  * drop the privilege. 
   137  * 
   138  * @param  token         The token to adjust the privilege on. 
   139  *         Pass nullptr for current token.
   140  * @param  unneededPrivs An array of unneeded privileges.
   141  * @param  count         The size of the array
   142  * @return TRUE if there were no errors
   143  */
   144 BOOL
   145 UACHelper::DisableUnneededPrivileges(HANDLE token, 
   146                                      LPCTSTR *unneededPrivs, 
   147                                      size_t count)
   148 {
   149   HANDLE obtainedToken = nullptr;
   150   if (!token) {
   151     // Note: This handle is a pseudo-handle and need not be closed
   152     HANDLE process = GetCurrentProcess();
   153     if (!OpenProcessToken(process, TOKEN_ALL_ACCESS_P, &obtainedToken)) {
   154       LOG_WARN(("Could not obtain token for current process, no "
   155                 "privileges changed. (%d)", GetLastError()));
   156       return FALSE;
   157     }
   158     token = obtainedToken;
   159   }
   161   BOOL result = TRUE;
   162   for (size_t i = 0; i < count; i++) {
   163     if (SetPrivilege(token, unneededPrivs[i], FALSE)) {
   164       LOG(("Disabled unneeded token privilege: %s.",
   165            unneededPrivs[i]));
   166     } else {
   167       LOG(("Could not disable token privilege value: %s. (%d)",
   168            unneededPrivs[i], GetLastError()));
   169       result = FALSE;
   170     }
   171   }
   173   if (obtainedToken) {
   174     CloseHandle(obtainedToken);
   175   }
   176   return result;
   177 }
   179 /**
   180  * Disables privileges for the specified token.
   181  * The privileges to disable are in PrivsToDisable.
   182  * In the future there could be new privs and we are not sure if we should
   183  * explicitly disable these or not. 
   184  * 
   185  * @param  token The token to drop the privilege on.
   186  *         Pass nullptr for current token.
   187  * @return TRUE if there were no errors
   188  */
   189 BOOL
   190 UACHelper::DisablePrivileges(HANDLE token)
   191 {
   192   static const size_t PrivsToDisableSize = 
   193     sizeof(UACHelper::PrivsToDisable) / sizeof(UACHelper::PrivsToDisable[0]);
   195   return DisableUnneededPrivileges(token, UACHelper::PrivsToDisable, 
   196                                    PrivsToDisableSize);
   197 }
   199 /**
   200  * Check if the current user can elevate.
   201  *
   202  * @return true if the user can elevate.
   203  *         false otherwise.
   204  */
   205 bool
   206 UACHelper::CanUserElevate()
   207 {
   208   HANDLE token;
   209   if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
   210     return false;
   211   }
   213   TOKEN_ELEVATION_TYPE elevationType;
   214   DWORD len;
   215   bool canElevate = GetTokenInformation(token, TokenElevationType,
   216                                         &elevationType,
   217                                         sizeof(elevationType), &len) &&
   218                     (elevationType == TokenElevationTypeLimited);
   219   CloseHandle(token);
   221   return canElevate;
   222 }

mercurial