Моникер повышения уровня COM
Моникер повышения прав COM позволяет приложениям, работающим под контролем учетных записей пользователей (UAC), активировать классы COM с повышенными привилегиями. Дополнительные сведения см. в разделе Принцип минимальных привилегий.
Когда следует использовать Моникер повышения высоты
Моникер повышения прав используется для активации класса COM для выполнения определенной и ограниченной функции, требующей повышенных привилегий, таких как изменение даты и времени системы.
Для повышения привилегий требуется участие как класса COM, так и его клиента. Класс COM должен быть настроен для поддержки повышения прав, аннотировав его запись в реестре, как указано в разделе "Требования". Клиент COM должен запрашивать повышение прав с помощью идентификатора повышения.
Идентификатор повышения привилегий не предназначен для обеспечения совместимости приложений. Например, если вы хотите запустить устаревшее COM-приложение, например WinWord как сервер с повышенными привилегиями, необходимо настроить исполняемый файл COM-клиента, чтобы требовать повышение прав, а не активировать класс устаревшего приложения с моникером повышения прав. Когда клиент COM с повышенными привилегиями вызывает CoCreateInstance с помощью clSID устаревшего приложения, состояние клиента с повышенными привилегиями будет передаваться в процесс сервера.
Не все функции COM совместимы с повышенными правами. Функциональные возможности, которые не будут работать, включают:
- Повышение прав не происходит от клиента к удаленному COM-серверу. Если клиент активирует удаленный COM-сервер с моникером повышения прав, сервер не будет повышен, даже если он поддерживает повышение прав.
- Если класс COM с повышенными привилегиями использует олицетворение во время вызова COM, он может потерять свои повышенные привилегии во время олицетворения.
- Если COM сервер с повышенными привилегиями регистрирует класс в таблице работающих объектов (ROT), этот класс не будет доступен для клиентов без повышенных привилегий.
- Процесс, повышенный с помощью механизма UAC, не загружает классы на пользователя во время активации COM. Для com-приложений это означает, что классы COM приложения должны быть установлены в кусте реестра HKEY_LOCAL_MACHINE, если приложение должно использоваться как не привилегированными, так и привилегированными учетными записями. Классы COM приложения должны быть установлены только в HKEY_USERS hive, если приложение никогда не используется привилегированными учетными записями.
- Перетаскивание не допускается из приложений без повышенных привилегий в приложения с повышенными привилегиями.
Требования
Чтобы использовать моникер повышения для активации COM-класса, класс должен быть настроен на запуск от имени инициирующего пользователя или с идентификацией приложения "Активировать как активатор". Если класс настроен для запуска под любым другим идентификатором, активация возвращает ошибку CO_E_RUNAS_VALUE_MUST_BE_AAA.
Класс также должен быть аннотирован с понятным отображаемым именем, совместимым с многоязычным пользовательским интерфейсом (MUI). Для этого требуется следующая запись реестра:
HKEY_LOCAL_MACHINE\Software\Classes\CLSID
{CLSID}
LocalizedString = displayName
Если эта запись отсутствует, активация возвращает ошибку CO_E_MISSING_DISPLAYNAME. Если файл MUI отсутствует, возвращается код ошибки из функции RegLoadMUIStringW.
Опционально, чтобы указать значок приложения, отображаемый пользовательским интерфейсом UAC, добавьте следующий ключ реестра:
HKEY_LOCAL_MACHINE\Software\Classes\CLSID
{CLSID}
Elevation
IconReference = applicationIcon
IconReference использует тот же формат, что и LocalizedString:
@ pathtobinary,-resourcenumber
Кроме того, компонент COM должен быть подписан для отображения значка.
Класс COM также должен быть аннотирован как LUA-Enabled. Для этого требуется следующая запись реестра:
HKEY_LOCAL_MACHINE\Software\Classes\CLSID
{CLSID}
Elevation
Enabled = 1
Если эта запись отсутствует, активация возвращает ошибку CO_E_ELEVATION_DISABLED.
Обратите внимание, что эти записи должны существовать в HKEY_LOCAL_MACHINE кусте, а не в HKEY_CURRENT_USER или HKEY_USERS кусте. Это предотвращает повышение уровня COM-классов пользователями, у которых нет привилегий для их регистрации.
Моникер повышения прав и пользовательский интерфейс повышения прав
Если у клиента уже есть повышенные права, использование индикатора повышения не приведет к отображению интерфейса повышения.
Как использовать индикатор высоты
Моникер повышения привилегий — это стандартный моникер COM, аналогичный моникеру сеанса, секции или очереди. Он направляет запрос активации на указанный сервер с указанным уровнем повышения прав. Идентификатор CLSID, который будет активирован, отображается в строке имени.
Метка повышения уровня поддерживает следующие токены уровня выполнения:
- Администратор
- Самый высокий
Синтаксис для этого выглядит следующим образом:
Elevation:Administrator!new:{guid}
Elevation:Highest!new:{guid}
Предыдущий синтаксис использует моникер "new" для возврата экземпляра класса COM, указанного guid. Обратите внимание, что моникер "new" внутренне использует интерфейс IClassFactory для получения объекта класса, а затем вызывает IClassFactory::CreateInstance.
Моникер повышения уровня привилегий также можно использовать для получения объекта класса, реализующего IClassFactory. Затем вызывающий вызывает CreateInstance для получения экземпляра объекта. Синтаксис для этого выглядит следующим образом:
Elevation:Administrator!clsid:{guid}
Пример кода
В следующем примере кода показано, как использовать моникер повышения привилегий. Предполагается, что вы уже инициализировали COM в текущем потоке.
HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, __out void ** ppv)
{
BIND_OPTS3 bo;
WCHAR wszCLSID[50];
WCHAR wszMonikerName[300];
StringFromGUID2(rclsid, wszCLSID, sizeof(wszCLSID)/sizeof(wszCLSID[0]));
HRESULT hr = StringCchPrintf(wszMonikerName, sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:Administrator!new:%s", wszCLSID);
if (FAILED(hr))
return hr;
memset(&bo, 0, sizeof(bo));
bo.cbStruct = sizeof(bo);
bo.hwnd = hwnd;
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
return CoGetObject(wszMonikerName, &bo, riid, ppv);
}
BIND_OPTS3 является новым в Windows Vista. Он является производным от BIND_OPTS2.
Единственным дополнением является переменная HWND, hwnd. Этот хэндл, если применимо, представляет окно, которое становится владельцем пользовательского интерфейса повышения прав.
Если hwnd равен NULL, COM вызовет функцию GetActiveWindow, чтобы найти дескриптор окна, связанный с текущим потоком. Это может произойти, если клиент является скриптом, который не может заполнить структуру BIND_OPTS3. В этом случае COM попытается использовать окно, связанное с потоком скрипта.
Повышение высоты надThe-Shoulder (OTS)
Опосредованное повышение привилегий (OTS) относится к сценарию, в котором клиент запускает COM-сервер с учетными данными администратора, а не своими собственными. (Термин "через плечо" означает, что администратор следит за плечом клиента, как клиент запускает сервер.)
Этот сценарий может вызвать проблему для вызовов COM на сервере, так как сервер может не вызывать CoInitializeSecurity явно (то есть программно) или неявно (то есть декларативно с помощью реестра). Для таких серверов COM вычисляет дескриптор безопасности, позволяющий выполнять вызовы COM только SELF, SYSTEM и Buildin\Administrators. Это соглашение не будет работать в сценариях OTS. Вместо этого сервер должен вызывать CoInitializeSecurity( явно или неявно) и указать ACL, который включает идентификатор безопасности интерактивной группы и СИСТЕМУ.
В следующем примере кода показано, как создать дескриптор безопасности (SD) с SID интерактивной группы.
BOOL GetAccessPermissionsForLUAServer(SECURITY_DESCRIPTOR **ppSD)
{
// Local call permissions to IU, SY
LPWSTR lpszSDDL = L"O:BAG:BAD:(A;;0x3;;;IU)(A;;0x3;;;SY)";
SECURITY_DESCRIPTOR *pSD;
*ppSD = NULL;
if (ConvertStringSecurityDescriptorToSecurityDescriptorW(lpszSDDL, SDDL_REVISION_1, (PSECURITY_DESCRIPTOR *)&pSD, NULL))
{
*ppSD = pSD;
return TRUE;
}
return FALSE;
}
В следующем примере кода показано, как вызывать CoInitializeSecurity неявно с помощью SD из предыдущего примера кода:
// hKey is the HKCR\AppID\{GUID} key
BOOL SetAccessPermissions(HKEY hkey, PSECURITY_DESCRIPTOR pSD)
{
BOOL bResult = FALSE;
DWORD dwLen = GetSecurityDescriptorLength(pSD);
LONG lResult;
lResult = RegSetValueExA(hkey,
"AccessPermission",
0,
REG_BINARY,
(BYTE*)pSD,
dwLen);
if (lResult != ERROR_SUCCESS) goto done;
bResult = TRUE;
done:
return bResult;
}
В следующем примере кода показано, как вызывать CoInitializeSecurity явным образом с помощью приведенного выше SD:
// Absolute SD values
PSECURITY_DESCRIPTOR pAbsSD = NULL;
DWORD AbsSdSize = 0;
PACL pAbsAcl = NULL;
DWORD AbsAclSize = 0;
PACL pAbsSacl = NULL;
DWORD AbsSaclSize = 0;
PSID pAbsOwner = NULL;
DWORD AbsOwnerSize = 0;
PSID pAbsGroup = NULL;
DWORD AbsGroupSize = 0;
MakeAbsoluteSD (
pSD,
pAbsSD,
&AbsSdSize,
pAbsAcl,
&AbsAclSize,
pAbsSacl,
&AbsSaclSize,
pAbsOwner,
&AbsOwnerSize,
pAbsGroup,
&AbsGroupSize
);
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
pAbsSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, AbsSdSize);
pAbsAcl = (PACL)LocalAlloc(LMEM_FIXED, AbsAclSize);
pAbsSacl = (PACL)LocalAlloc(LMEM_FIXED, AbsSaclSize);
pAbsOwner = (PSID)LocalAlloc(LMEM_FIXED, AbsOwnerSize);
pAbsGroup = (PSID)LocalAlloc(LMEM_FIXED, AbsGroupSize);
if ( ! (pAbsSD && pAbsAcl && pAbsSacl && pAbsOwner && pAbsGroup))
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
if ( ! MakeAbsoluteSD(
pSD,
pAbsSD,
&AbsSdSize,
pAbsAcl,
&AbsAclSize,
pAbsSacl,
&AbsSaclSize,
pAbsOwner,
&AbsOwnerSize,
pAbsGroup,
&AbsGroupSize
))
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
goto Cleanup;
}
// Call CoInitializeSecurity .
Разрешения COM и обязательные метки доступа
Windows Vista представляет понятие обязательных меток доступа в дескрипторах безопасности. Метка определяет, могут ли клиенты получить доступ на выполнение к COM-объекту. Метка указана в системном списке управления доступом (SACL) дескриптора безопасности. В Windows Vista COM поддерживает метку SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP. SACLs в разрешениях COM не учитываются в операционных системах перед Windows Vista.
По состоянию на Windows Vista dcomcnfg.exe не поддерживает изменение уровня целостности (IL) в разрешениях COM. Он должен быть установлен программным способом.
В следующем примере кода показано, как создать дескриптор безопасности COM с меткой, которая позволяет запрашивать запуск и активацию от всех клиентов LOW IL. Обратите внимание, что метки допустимы для разрешений на запуск, активацию и вызов. Таким образом, можно написать COM-сервер, который запрещает запуск, активацию или вызовы от клиентов с определенным IL. Дополнительные сведения о уровнях целостности см. в разделе "Общие сведения о механизме целостности Windows Vista" в "Понимание и работа в защищенном режиме Internet Explorer".
BOOL GetLaunchActPermissionsWithIL (SECURITY_DESCRIPTOR **ppSD)
{
// Allow World Local Launch/Activation permissions. Label the SD for LOW IL Execute UP
LPWSTR lpszSDDL = L"O:BAG:BAD:(A;;0xb;;;WD)S:(ML;;NX;;;LW)";
if (ConvertStringSecurityDescriptorToSecurityDescriptorW(lpszSDDL, SDDL_REVISION_1, (PSECURITY_DESCRIPTOR *)&pSD, NULL))
{
*ppSD = pSD;
return TRUE;
}
}
BOOL SetLaunchActPermissions(HKEY hkey, PSECURITY_DESCRIPTOR pSD)
{
BOOL bResult = FALSE;
DWORD dwLen = GetSecurityDescriptorLength(pSD);
LONG lResult;
lResult = RegSetValueExA(hkey,
"LaunchPermission",
0,
REG_BINARY,
(BYTE*)pSD,
dwLen);
if (lResult != ERROR_SUCCESS) goto done;
bResult = TRUE;
done:
return bResult;
};
CoCreateInstance и уровни целостности
Поведение CoCreateInstance изменилось в Windows Vista, чтобы предотвратить привязку клиентов Low IL к COM-серверам по умолчанию. Сервер должен явно разрешить такие привязки, указав SACL. Изменения в CoCreateInstance приведены следующим образом:
- При запуске процесса COM-сервера в токене процесса сервера устанавливается уровень целостности (IL) клиентского или серверного маркера, в зависимости от того, какой уровень ниже.
- По умолчанию COM предотвращает привязку клиентов Low IL к запущенным экземплярам любых COM-серверов. Чтобы разрешить привязку, дескриптор безопасности запуска и активации COM-сервера должен содержать saCL, указывающий метку Low IL (см. предыдущий раздел примера кода для создания такого дескриптора безопасности).
Повышенные серверы и регистрация ROT
Если COM-сервер хочет зарегистрироваться в запущенной таблице объектов (ROT) и предоставить доступ к регистрации любому клиенту, он должен использовать флаг ROTFLAGS_ALLOWANYCLIENT. COM-сервер "Активировать как активатор" не может указать ROTFLAGS_ALLOWANYCLIENT, так как диспетчер управления службами DCOM (DCOMSCM) проводит проверку спуфинга по этому флагу. Таким образом, в Windows Vista COM добавляет поддержку новой записи реестра, которая позволяет серверу указать, что регистрация ROT доступна любому клиенту:
HKEY_LOCAL_MACHINE\Software\Classes\AppID
{APPID}
ROTFlags
Единственное допустимое значение для этой записи REG_DWORD:
ROTREGFLAGS_ALLOWANYCLIENT 0x1
Запись должна существовать в ветке HKEY_LOCAL_MACHINE.
Эта запись предоставляет сервер "Активация в качестве Активатора" с той же функциональностью, которую ROTFLAGS_ALLOWANYCLIENT предоставляет для сервера RunAs.
Связанные разделы