Сущность технологии СОМ. Библиотека программиста

ОглавлениеДобавить в закладки К обложке

// 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. Следующий фрагмент кода демонстрирует эту технологию, отключая защиту как для интерфейсного заместителя, так и для его администратора заместителей:


Логин
Пароль
Запомнить меня