[local, object, uuid(0000013E-0000-0000-C000-000000000046)]
interface IServerSecurity : IUnknown {
// get caller's security settings
// получаем установки защиты вызывающей программы
HRESULT QueryBlanket( [out] DWORD *pAuthnSvc,
// authentication pkg
// модуль аутентификации
[out] DWORD *pAuthzSvc,
// authorization pkg
// модуль авторизации
[out] OLECHAR **pServerName,
// server principal
// серверный принципал
[out] DWORD *pAuthnLevel,
// authentication level
// уровень аутентификации
[out] DWORD *pImpLevel,
// impersonation level
// уровень заимствования прав
[out] void *pPrivs,
// client principal
// клиентский принципал
[out] DWORD *pCaps
// EOAC flags
// флаги EOAC
);
// start running with credentials of caller
// начинаем выполнение с полномочиями вызывающей программы
HRESULT ImpersonateClent(void);
// stop running with credentials of caller
// заканчиваем выполнение с полномочиями вызывающей программы
HRESULT RevertToSelf(void);
// test for Impersonation
// тест для заимствования прав BOOL
IsImpersonating(void);
}
IServerSecurity::QueryBlanket возвращает установки полной защиты, фактически использованные для текущего ORPC-вызова (которые могут несколько отличаться от клиентских установок благодаря специфическому для SSP повышению уровней). Как было в случае с IClientSecurity::QueryBlanket , функции IServerSecurity::QueryBlanket также разрешается передавать нуль вместо неиспользуемых параметров. Ниже приведен пример реализации метода, которая гарантирует, что вызывающая программа обеспечила возможность шифрования перед обработкой вызова:
STDMETHODIMP Gorilla::SwingFromTree(/*(in]*/ long nTreeID) {
// get current call context
// получаем контекст текущего вызова IServerSecurity *pss = 0;
HRESULT hr = CoGetCallContext(IID_IServerSecurity, (void**)&pss);
DWORD dwAuthnLevel;
if (SUCCEEDED(hr)) {
// get authentication level of current call
// получаем уровень аутентификации текущего вызова
hr = pss->QueryBlanket(0, 0, 0, &dwAuthnLevel, 0, 0, 0);
pss->Release(); }
// verify proper authentication level
// проверяем правильность уровня аутентификации
if (FAILED(hr) || dwAuthnLevel != RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
hr = APE_E_NOPUBLICTREE;
else hr = this->ActuallySwingFromTree(nTreeID);
return hr;
}
Как было в случае с IClientSecurity , каждый метод IServerSecurity доступен в качестве удобной API-функции. Приводимая ниже реализация метода использует удобную подпрограмму вместо явного вызова интерфейса IServerSecurity
STDMETHODIMP Gorilla::SwingFromTree(/*[in]*/ long nTreeID) {
DWORD dwAuthnLevel;
// get authentication level of current call
// получаем уровень аутентификации текущего вызова
HRESULT hr = CoQueryClientBlanket(0, 0, 0, &dwAuthnLevel, 0, 0, 0);
// verify proper authentication level
// проверяем правильность уровня аутентификации
if (FAILED(hr) || dwAuthnLevel != RPC_C_AUTHN_LEVEL_РКТ_PRIVACY)
hr = АРЕ_Е_NOPUBLICTREE;
else hr = this->ActuallySwingFromTree(nTreeID);
return hr;
}
И снова мы видим, что последняя версия требует меньше кода и поэтому вероятность ошибок в ней меньше.
Метод IServerSecurity::QueryBlanket также позволяет разработчику объекта находить идентификатор защиты вызывающей программы через параметр pPrivs . Как и в случае с полномочиями, передаваемыми в IClientSecurity::SetBlanket , точный формат этого идентификатора является специфическим для конкретного модуля защиты. Для NTLM этот формат является просто строкой вида Authority\AccountName
Следующая реализация метода отыскивает идентификатор защиты вызывающей программы с помощью API-функции CoQueryClientBlanket :
STDMETHODIMP Gorilla::EatBanana() {
OLECHAR *pwszClientPrincipal = 0;
// get security identifier of caller
// получаем идентификатор защиты вызывающей программы
HRESULT hr = CoQueryClientBlanket(0, 0, 0, 0, 0, (void**)&pwszClientPrincipal, 0);
// log user name
// регистрируем имя пользователя
if (SUCCEEDED(hr)) {
this->LogCallerIDToFile(pwszClientPrincipal);
hr = this->ActuallyEatBanana();
}
return hr;
}
При вызове CoQueryClientBlanket для успешного возвращения идентификатора защиты вызывающей программы последняя должна определить:
По крайней мере RPC_C_IMP_LEVEL_IDENTIFY как автоматический (или явный) уровень заимствования прав;
По крайней мере RPC_C_AUTHN_LEVEL_CONNECT как автоматический (или явный) уровень аутентификации.
Если вызывающая программа явно изменила вызывающий принципал в установках полной защиты заместителя с помощью функции COAUTHIDENTITY , то вместо него будет возвращено имя явно заданного принципала.
Точно так же, как можно полностью контролировать установки защиты, использующиеся при вызове метода с помощью интерфейса IClientSecurity , представляется полезным контролировать установки защиты, использованные при вызове на активацию. К сожалению, активационные вызовы являются глобальными API-функциями, не имеющими соответствующего администратора заместителей, откуда можно было бы получить интерфейс IClientSecurity . Для того чтобы позволить вызывающим программам задавать установки защиты для активационных вызовов, каждый активационный вызов принимает структуру СОSERVERINFO :
Читать дальше