Сущность технологии СОМ. Библиотека программиста - Дональд Бокс
- Дата:20.06.2024
- Категория: Компьютеры и Интернет / Программирование
- Название: Сущность технологии СОМ. Библиотека программиста
- Автор: Дональд Бокс
- Просмотров:3
- Комментариев:0
Шрифт:
Интервал:
Закладка:
OLECHAR *Domain;
// Domain/Machine name
// имя домена/машины
ULONG DomainLength;
// wcslen(Domain)
// длина имени домена
OLECHAR *Password;
// cleartext password
// пароль открытым текстом
ULONG PasswordLength;
// wcslen(Password)
// длина пароля
ULONG Flags;
// must be SEC_WINNT_AUTH_IDENTITY_UNICODE
// должно быть SEC_WINNT_AUTH_IDENTITY_UNICODE
} COAUTHIDENTITY;
Эта структура позволяет клиентам делать вызовы методов COM как любым принципалам защиты, при условии, что они знают открытые тексты паролей для желаемой учетной записи[1]. Если вместо указателя на явную структуру COAUTHIDENTITY передается нулевой указатель, то каждый внешний вызов будет делаться с использованием полномочий вызывающего процесса[2].
Чаще всего метод IClientSecurity::SetBlanket применяется для повышения уровня аутентификации отдельного заместителя. Следующий код демонстрирует эту технологию:
HRESULT Encrypt(IApe *pApe) {
IClientSecurity *pcs = 0;
// ask proxy manager for IClientSecurity interface
// запрашиваем интерфейс IClientSecurity у администратора заместителей
HRESULT hr = pApe->QueryInterface(IID_IClientSecurity, (void**)&pcs);
if (SUCCEEDED(hr)) {
hr = pcs->SetBlanket(pApe, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, 0, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IDENTIFY, 0, EOAC_NONE);
pcs->Release();
}
return hr;
}
В идеале вызывающая программа передаст этой функции скопированный интерфейсный заместитель. В противном случае с целью проведения операции копирования эту функцию можно было бы изменить следующим образом:
HRESULT DupeAndEncrypt(IApe *pApe, IApe * &rpSecretApe) {
rpSecretApe = 0;
IClientSecurity *pcs = 0;
// ask proxy manager for IClientSecurity interface
// запрашиваем интерфейс IClientSecurity у администратора заместителей
HRESULT hr = pApe->QueryInterface(IID_IClientSecurity, (void**)&pcs);
if (SUCCEEDED(hr)) {
hr = pcs->CopyProxy(pApe, (IUnknown**)&rpSecretApe);
if (SUCCEEDED(hr))
hr = pcs->SetBlanket (rpSecretApe, RPC_AUUTHN_WINNT, RPC_C_AUTHZ_NONE, 0, RPC_С_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IDENTIFY, 0, EOAC_NONE);
pcs->Release();
}
return hr;
}
Для удобства в COM API предусмотрены оберточные функции вокруг каждого из трех методов IClientSecurity , которые изнутри вызывают QueryInterface для нахождения соответствующего интерфейса IClientSecurity и затем вызывают нужный метод:
// get security settings for interface proxy pProxy
// получаем установки защиты для интерфейсного заместителя
pProxy HRESULT CoQueryProxyBlanket([in] IUnknown *pProxy, [out] DWORD *pAuthnSvc, [out] DWORD *pAuthzSvc, [out] OLECHAR **pServerPrincName, [out] DWORD *pAuthnLevel, [out] DWORD *pImpLevel, [out] void **pAuthInfo, [out] DWORD *Capabilities);
// change security settings for interface proxy pProxy
// изменяем установки защиты для интерфейсного заместителя
pProxy HRESULT CoSetProxyBlanket([in] IUnknown *pProxy, [in] DWORD AuthnSvc, [in] DWORD AuthzSvc, [in] OLECHAR *pServerPrincName, [in] DWORD AuthnLevel, [in] DWORD ImpLevel, [in] void *pAuthInfo, [in] DWORD Capabilities);
// duplicate an interface proxy
// копируем интерфейсный заместитель
HRESULT CoCopyProxy([in] IUnknown *pProxy, [out] IUnknown **ppCopy);
Следующий код представляет собой модифицированную версию предыдущей функции, где используются эти удобные процедуры:
HRESULT DupeAndEncrypt(IApe *pApe, IАре *ArpSecretApe) {
rpSecretApe = 0; HRESULT hr = СоСоруProxy(pApe, (IUnknown**)&rpSecretApe);
if (SUCCEEDED(hr))
hr = CoSetProxyBlanket(rpSecretApe, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, 0, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IDENTIFY, 0, EOAC_NONE);
return hr;
}
Первая версия несколько эффективнее, так как для нахождения интерфейса IClientSecurity в ней использован только один вызов QueryInterface. Для последней версии требуется меньше кода, поэтому и вероятность ошибок в ней меньше.
Важно отметить, что методы IClientSecurity могут применяться только в тех интерфейсах, которые используют интерфейсные заместители. Это означает, что те интерфейсы, которые реализованы локально администратором заместителей (например, IMultiQI, IClientSecurity), не могут использоваться с методами IClientSecurity. Интерфейс IUnknown – это особый случай. IUnknown фактически является локальным интерфейсом, реализованным администратором заместителей. Однако администратору заместителей часто требуется связаться с апартаментом сервера для запроса новых интерфейсов и для освобождения ресурсов, хранящихся в соответствующем администраторе заглушек. Эта связь осуществляется через закрытый интерфейс IRemUnknown, который реализуется библиотекой COM отдельно внутри каждого апартамента. Разработчики могут контролировать полную защиту, использованную для этих вызовов IRemUnknown путем передачи реализации IUnknown администратора заместителей в IClientSecurity::SetBlanket (подобно интерфейсному заместителю, администратор заместителей использует общие для процесса автоматические установки защиты в случае, если функция SetBlanket не вызывается)[3]. Поскольку все интерфейсные заместители агрегированы администратором заместителей, то это, в сущности, означает, что вызовы IClientSecurity::SetBlanket на какой-либо определенный интерфейсный заместитель не влияют на функции QueryInterface, AddRef и Release. Скорее, на них влияют установки, примененные к реализации IUnknown администратором заместителей. Для того чтобы получить указатель на реализацию IUnknown администратором заместителей, можно просто запросить с помощью QueryInterface интерфейсный заместитель для IID_IUnknown. Следующий фрагмент кода демонстрирует эту технологию, отключая защиту как для интерфейсного заместителя, так и для его администратора заместителей:
void TurnOffAllSecurity(IApe *pApe) {
IUnknown *pUnkProxyManager = 0;
// get a pointer to the proxy manager
// получаем указатель на администратор заместителей
HRESULT hr = pApe->QueryInterface(IID_IUnknown, (void**)&pUnkProxyManager);
assert(SUCCEEDED(hr));
// set blanket for proxy manager
// устанавливаем защиту для администратора заместителей
hr = CoSetProxyBlanket(pUnkProxyManager, RPC_C_AUTHN_NONE, RPC_C_AUTHZ_NONE, О, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS, 0, EOAC_NONE);
assert(SUCCEEDED(hr));
// set blanket for interface proxy
// устанавливаем защиту для интерфейсного заместителя
hr = CoSetProxyBlanket(pApe, RPC_C_AUTHN_NONE, RPC_C_AUTHZ_NONE, 0, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_ANONYMOUS, 0, EOAC_NONE);
assert(SUCCEEDED(hr));
// release temporary pointer to proxy manager
// освобождаем временный указатель на администратор заместителей
pUnkProxyManager->Release();
}
Хотя представляется возможным установить и запросить защиту для администратора заместителей, невозможно скопировать администратор заместителей с помощью IClientSecurity::CopyProxy, так как это нарушило бы правила идентификации COM.
Когда ORPC-запрос направляется интерфейсной заглушке, COM создает объект контекста вызова (call context object), представляющий различные аспекты вызова, в том числе установки защиты того интерфейсного заместителя, который отправил этот запрос. COM связывает этот контекстный объект с потоком, который будет выполнять вызов метода. Библиотека COM выставляет API-функцию CoGetCallContext, позволяющую реализациям метода получить контекст для текущего вызова метода:
HRESULT CoGetCallContext ([in] REFIID riid, [out, iid_is(riid)] void **ppv);
В Windows NT 4.0 единственным интерфейсом, доступным для контекстного объекта вызова, является интерфейс IServerSecurity:
[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
- Аквариум. (Новое издание, исправленное и переработанное) - Виктор Суворов (Резун) - Шпионский детектив
- Права на результаты интеллектуальной деятельности и средства индивидуализации: Комментарий к части четвертой Гражданского кодекса Российской Федерации - Вадим Погуляев - Юриспруденция
- У меня есть идея! Что дальше? - Михаил Соболев - О бизнесе популярно
- Ориентирование - К. М. Станич - Современные любовные романы
- Проект 365 - Константин Рочев - Поэзия