/*++ // Copyright (c) 1995-2001 Microsoft Corporation, All Rights Reserved Module Name: COMINIT.CPP Abstract: WMI COM Helper functions History: --*/ #include "precomp.h" #include #define _COMINIT_CPP_ #include "cominit.h" #include BOOL WINAPI DoesContainCredentials( COAUTHIDENTITY* pAuthIdentity ) { try { if ( NULL != pAuthIdentity && COLE_DEFAULT_AUTHINFO != pAuthIdentity) { return ( pAuthIdentity->UserLength != 0 || pAuthIdentity->PasswordLength != 0 ); } return FALSE; } catch(...) { return FALSE; } } HRESULT WINAPI WbemSetProxyBlanket( IUnknown *pInterface, DWORD dwAuthnSvc, DWORD dwAuthzSvc, OLECHAR *pServerPrincName, DWORD dwAuthLevel, DWORD dwImpLevel, RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities, bool fIgnoreUnk ) { IUnknown * pUnk = NULL; IClientSecurity * pCliSec = NULL; HRESULT sc = pInterface->QueryInterface(IID_IUnknown, (void **) &pUnk); if(sc != S_OK) return sc; sc = pInterface->QueryInterface(IID_IClientSecurity, (void **) &pCliSec); if(sc != S_OK) { pUnk->Release(); return sc; } /* * Can't set pAuthInfo if cloaking requested, as cloaking implies * that the current proxy identity in the impersonated thread (rather * than the credentials supplied explicitly by the RPC_AUTH_IDENTITY_HANDLE) * is to be used. * See MSDN info on CoSetProxyBlanket for more details. */ if (dwCapabilities & (EOAC_STATIC_CLOAKING | EOAC_DYNAMIC_CLOAKING)) pAuthInfo = NULL; sc = pCliSec->SetBlanket(pInterface, dwAuthnSvc, dwAuthzSvc, pServerPrincName, dwAuthLevel, dwImpLevel, pAuthInfo, dwCapabilities); pCliSec->Release(); pCliSec = NULL; // If we are not explicitly told to ignore the IUnknown, then we should // check the auth identity structure. This performs a heuristic which // assumes a COAUTHIDENTITY structure. If the structure is not one, we're // wrapped with a try/catch in case we AV (this should be benign since // we're not writing to memory). if ( !fIgnoreUnk && DoesContainCredentials( (COAUTHIDENTITY*) pAuthInfo ) ) { sc = pUnk->QueryInterface(IID_IClientSecurity, (void **) &pCliSec); if(sc == S_OK) { sc = pCliSec->SetBlanket(pUnk, dwAuthnSvc, dwAuthzSvc, pServerPrincName, dwAuthLevel, dwImpLevel, pAuthInfo, dwCapabilities); pCliSec->Release(); } else if (sc == 0x80004002) sc = S_OK; } pUnk->Release(); return sc; } // Helper class we can keep a static instance of and ensure that when a module unloads, // the dll handle is freed. class CLibHandle { public: CLibHandle() : m_hInstance( NULL ) {}; ~CLibHandle(); HINSTANCE GetHandle( void ) { return m_hInstance; } void SetHandle( HINSTANCE hInst ) { m_hInstance = hInst; } private: HINSTANCE m_hInstance; }; CLibHandle::~CLibHandle() { if ( NULL == m_hInstance ) return; OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if(!GetVersionEx(&os)) return; // should never happen // if not nt, then we can crash by freeing the library, so only do it if nt! if(os.dwPlatformId == VER_PLATFORM_WIN32_NT) FreeLibrary( m_hInstance ); return; } // The OLE32 library has been loaded to access the functions above // for DCOM calls. // =============================================================== // Static object that will destruct and free the handle to // g_hOle32 when the module exits memory. static CLibHandle g_LibHandleOle32; // DCOM check has been performed = TRUE. // ===================================== static BOOL g_bInitialized = FALSE; BOOL WINAPI InitComInit() { UINT uSize; BOOL bRetCode = FALSE; HANDLE hMut; if(g_bInitialized) { return TRUE; } do { hMut = CreateMutex(NULL, TRUE, _T("COMINIT_INITIALING")); if(hMut == INVALID_HANDLE_VALUE) { Sleep(50); } } while(hMut == INVALID_HANDLE_VALUE); if(g_bInitialized) { CloseHandle(hMut); return TRUE; } LPTSTR pszSysDir = new _TCHAR[ MAX_PATH+10 ]; if(pszSysDir == NULL) { CloseHandle(hMut); return FALSE; } uSize = GetSystemDirectory(pszSysDir, MAX_PATH); if(uSize > MAX_PATH) { delete[] pszSysDir; pszSysDir = new _TCHAR[ uSize +10 ]; if(pszSysDir == NULL) { CloseHandle(hMut); return FALSE; } uSize = GetSystemDirectory(pszSysDir, uSize); } lstrcat(pszSysDir, _T("\\ole32.dll")); HINSTANCE hOle32 = LoadLibraryEx(pszSysDir, NULL, 0); delete pszSysDir; if(hOle32 != NULL) { bRetCode = TRUE; (FARPROC&)g_pfnCoInitializeEx = GetProcAddress(hOle32, "CoInitializeEx"); if(!g_pfnCoInitializeEx) { FreeLibrary(hOle32); hOle32 = NULL; bRetCode = FALSE; } // This handle will now automagically be freed when the Dll // is unloaded from memory. g_LibHandleOle32.SetHandle( hOle32 ); (FARPROC&)g_pfnCoCreateInstanceEx = GetProcAddress(g_LibHandleOle32.GetHandle(), "CoCreateInstanceEx"); (FARPROC&)g_pfnCoGetCallContext = GetProcAddress(g_LibHandleOle32.GetHandle(), "CoGetCallContext"); (FARPROC&)g_pfnCoSwitchCallContext = GetProcAddress(g_LibHandleOle32.GetHandle(), "CoSwitchCallContext"); } g_bInitialized = TRUE; CloseHandle(hMut); return bRetCode; } BOOL WINAPI IsDcomEnabled() { InitComInit(); if(g_LibHandleOle32.GetHandle()) { // DCOM has been detected. // ======================= return TRUE; } else { // DCOM was not detected. // ====================== return FALSE; } } HRESULT WINAPI InitializeCom() { if(IsDcomEnabled()) { return g_pfnCoInitializeEx(0, COINIT_MULTITHREADED); } return CoInitialize(0); } HRESULT WINAPI InitializeSecurity( PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc, SOLE_AUTHENTICATION_SERVICE *asAuthSvc, void *pReserved1, DWORD dwAuthnLevel, DWORD dwImpLevel, void *pReserved2, DWORD dwCapabilities, void *pReserved3) { // Get CoInitializeSecurity from ole32.dll // ======================================= if(g_LibHandleOle32.GetHandle() == NULL) { return E_FAIL; } typedef HRESULT (STDAPICALLTYPE *PFN_COINITIALIZESECURITY)( PSECURITY_DESCRIPTOR, DWORD, SOLE_AUTHENTICATION_SERVICE*, void*, DWORD, DWORD, RPC_AUTH_IDENTITY_HANDLE, DWORD, void*); PFN_COINITIALIZESECURITY pfnCoInitializeSecurity = (PFN_COINITIALIZESECURITY) GetProcAddress(g_LibHandleOle32.GetHandle(), "CoInitializeSecurity"); if(pfnCoInitializeSecurity == NULL) { return S_FALSE; } // Initialize security // =================== return pfnCoInitializeSecurity(pSecDesc, cAuthSvc, asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2, dwCapabilities, pReserved3); } DWORD WINAPI WbemWaitForMultipleObjects(DWORD nCount, HANDLE* ahHandles, DWORD dwMilli) { MSG msg; DWORD dwRet; while(1) { dwRet = MsgWaitForMultipleObjects(nCount, ahHandles, FALSE, dwMilli, QS_SENDMESSAGE); if(dwRet == (WAIT_OBJECT_0 + nCount)) { while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { DispatchMessage(&msg); } continue; } else { break; } } return dwRet; } DWORD WINAPI WbemWaitForSingleObject(HANDLE hHandle, DWORD dwMilli) { return WbemWaitForMultipleObjects(1, &hHandle, dwMilli); } BOOL WINAPI WbemTryEnterCriticalSection(CRITICAL_SECTION* pcs) { // TBD properly!! if(pcs->LockCount >= 0) return FALSE; else { EnterCriticalSection(pcs); return TRUE; } } HRESULT WINAPI WbemCoCreateInstance(REFCLSID rclsid, IUnknown* pUnkOuter, DWORD dwClsContext, REFIID riid, void** ppv) { if(!IsDcomEnabled()) { dwClsContext &= ~CLSCTX_REMOTE_SERVER; } return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv); } HRESULT WINAPI WbemCoGetClassObject(REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO* pServerInfo, REFIID riid, void** ppv) { if(!IsDcomEnabled()) { dwClsContext &= ~CLSCTX_REMOTE_SERVER; } return CoGetClassObject(rclsid, dwClsContext, pServerInfo, riid, ppv); } HRESULT WINAPI WbemCoGetCallContext(REFIID riid, void** ppv) { if(!IsDcomEnabled()) { *ppv = NULL; return E_NOTIMPL; } else { return (*g_pfnCoGetCallContext)(riid, ppv); } } HRESULT WINAPI WbemCoSwitchCallContext( IUnknown *pNewObject, IUnknown **ppOldObject ) { if(!IsDcomEnabled()) { return E_NOTIMPL; } else { return (*g_pfnCoSwitchCallContext)(pNewObject, ppOldObject); } } //*************************************************************************** // // SCODE DetermineLoginType // // DESCRIPTION: // // Examines the Authority and User argument and determines the authentication // type and possibly extracts the domain name from the user arugment in the // NTLM case. For NTLM, the domain can be at the end of the authentication // string, or in the front of the user name, ex; "redmond\a-davj" // // PARAMETERS: // // ConnType Returned with the connection type, ie wbem, ntlm // AuthArg Output, contains the domain name // UserArg Output, user name // Authority Input // User Input // // RETURN VALUE: // // S_OK all is well // else error listed in WBEMSVC.H // //*************************************************************************** SCODE WINAPI DetermineLoginType(BSTR & AuthArg, BSTR & UserArg,BSTR & Authority,BSTR & User) { // Determine the connection type by examining the Authority string if(!(Authority == NULL || wcslen(Authority) == 0 || !_wcsnicmp(Authority, L"NTLMDOMAIN:",11))) return WBEM_E_INVALID_PARAMETER; // The ntlm case is more complex. There are four cases // 1) Authority = NTLMDOMAIN:name" and User = "User" // 2) Authority = NULL and User = "User" // 3) Authority = "NTLMDOMAIN:" User = "domain\user" // 4) Authority = NULL and User = "domain\user" // first step is to determine if there is a backslash in the user name somewhere between the // second and second to last character WCHAR * pSlashInUser = NULL; if(User) { WCHAR * pEnd = User + wcslen(User) - 1; for(pSlashInUser = User; pSlashInUser <= pEnd; pSlashInUser++) if(*pSlashInUser == L'\\') // dont think forward slash is allowed! break; if(pSlashInUser > pEnd) pSlashInUser = NULL; } if(Authority && wcslen(Authority) > 11) { if(pSlashInUser) return WBEM_E_INVALID_PARAMETER; AuthArg = SysAllocString(Authority + 11); if(User) UserArg = SysAllocString(User); return S_OK; } else if(pSlashInUser) { DWORD_PTR iDomLen = pSlashInUser-User; WCHAR cTemp[MAX_PATH]; wcsncpy(cTemp, User, iDomLen); cTemp[iDomLen] = 0; AuthArg = SysAllocString(cTemp); if(wcslen(pSlashInUser+1)) UserArg = SysAllocString(pSlashInUser+1); } else if(User) UserArg = SysAllocString(User); return S_OK; } //*************************************************************************** // // SCODE DetermineLoginTypeEx // // DESCRIPTION: // // Extended version that supports Kerberos. To do so, the authority string // must start with Kerberos: and the other parts be compatible with the normal // login. Ie, user should be domain\user. // // PARAMETERS: // // AuthArg Output, contains the domain name // UserArg Output, user name // PrincipalArg Output, user name // Authority Input // User Input // // RETURN VALUE: // // S_OK all is well // else error listed in WBEMSVC.H // //*************************************************************************** SCODE WINAPI DetermineLoginTypeEx(BSTR & AuthArg, BSTR & UserArg,BSTR & PrincipalArg, BSTR & Authority,BSTR & User) { // Normal case, just let existing code handle it if(Authority == NULL || _wcsnicmp(Authority, L"KERBEROS:",9)) return DetermineLoginType(AuthArg, UserArg, Authority, User); if(!IsKerberosAvailable()) return WBEM_E_INVALID_PARAMETER; PrincipalArg = SysAllocString(&Authority[9]); BSTR tempArg = NULL; return DetermineLoginType(AuthArg, UserArg, tempArg, User); } //*************************************************************************** // // bool bIsNT // // DESCRIPTION: // // Returns true if running windows NT. // // RETURN VALUE: // // see description. // //*************************************************************************** bool WINAPI bIsNT(void) { OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if(!GetVersionEx(&os)) return FALSE; // should never happen return os.dwPlatformId == VER_PLATFORM_WIN32_NT; } //*************************************************************************** // // bool IsKeberosAvailable // // DESCRIPTION: // // Returns true if Kerberos is available. // // RETURN VALUE: // // see description. // //*************************************************************************** BOOL WINAPI IsKerberosAvailable(void) { OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if(!GetVersionEx(&os)) return FALSE; // should never happen // IMPORTANT!! This will need to be chanted if Kerberos is ever ported to 98 return ( os.dwPlatformId == VER_PLATFORM_WIN32_NT ) && ( os.dwMajorVersion >= 5 ) ; } //*************************************************************************** // // bool IsAuthenticated // // DESCRIPTION: // // This routine is used by clients in check if an interface pointer is using // authentication. // // PARAMETERS: // // pFrom the interface to be tested. // // RETURN VALUE: // // S_OK all is well // else error listed in WBEMSVC.H // //*************************************************************************** bool WINAPI IsAuthenticated(IUnknown * pFrom) { bool bAuthenticate = true; if(pFrom == NULL) return true; IClientSecurity * pFromSec = NULL; SCODE sc = pFrom->QueryInterface(IID_IClientSecurity, (void **) &pFromSec); if(sc == S_OK) { DWORD dwAuthnSvc, dwAuthzSvc, dwAuthnLevel, dwImpLevel, dwCapabilities; sc = pFromSec->QueryBlanket(pFrom, &dwAuthnSvc, &dwAuthzSvc, NULL, &dwAuthnLevel, &dwImpLevel, NULL, &dwCapabilities); if (sc == 0x800706d2 || (sc == S_OK && dwAuthnLevel == RPC_C_AUTHN_LEVEL_NONE)) bAuthenticate = false; pFromSec->Release(); } return bAuthenticate; } //*************************************************************************** // // SCODE GetAuthImp // // DESCRIPTION: // // Gets the authentication and impersonation levels for a current interface. // // PARAMETERS: // // pFrom the interface to be tested. // pdwAuthLevel // // RETURN VALUE: // // S_OK all is well // else error listed in WBEMSVC.H // //*************************************************************************** SCODE WINAPI GetAuthImp(IUnknown * pFrom, DWORD * pdwAuthLevel, DWORD * pdwImpLevel) { if(pFrom == NULL || pdwAuthLevel == NULL || pdwImpLevel == NULL) return WBEM_E_INVALID_PARAMETER; IClientSecurity * pFromSec = NULL; SCODE sc = pFrom->QueryInterface(IID_IClientSecurity, (void **) &pFromSec); if(sc == S_OK) { DWORD dwAuthnSvc, dwAuthzSvc, dwCapabilities; sc = pFromSec->QueryBlanket(pFrom, &dwAuthnSvc, &dwAuthzSvc, NULL, pdwAuthLevel, pdwImpLevel, NULL, &dwCapabilities); // Special case of going to a win9x share level box if (sc == 0x800706d2) { *pdwAuthLevel = RPC_C_AUTHN_LEVEL_NONE; *pdwImpLevel = RPC_C_IMP_LEVEL_IDENTIFY; sc = S_OK; } pFromSec->Release(); } return sc; } //*************************************************************************** // // SCODE SetInterfaceSecurity // // DESCRIPTION: // // This routine is used by clients in order to set the identity to be used by a connection. // // PARAMETERS: // // pInterface Interface to be set // pDomain Input, domain // pUser Input, user name // pPassword Input, password. // pFrom Input, if not NULL, then the authentication level of this interface // is used // bAuthArg If pFrom is NULL, then this is the authentication level // RETURN VALUE: // // S_OK all is well // else error listed in WBEMSVC.H // //*************************************************************************** HRESULT WINAPI SetInterfaceSecurity(IUnknown * pInterface, LPWSTR pAuthority, LPWSTR pUser, LPWSTR pPassword, IUnknown * pFrom, bool bAuthArg) { SCODE sc; if(!IsDcomEnabled()) // For the anon pipes clients, dont even bother return S_OK; if(pInterface == NULL) return WBEM_E_INVALID_PARAMETER; // Check the source pointer to determine if we are running in a non authenticated mode which // would be the case when connected to a Win9X box which is using share level security bool bAuthenticate = true; if(pFrom) bAuthenticate = IsAuthenticated(pFrom); else bAuthenticate = bAuthArg; // If we are doing trivial case, just pass in a null authenication structure which is used // if the current logged in user's credentials are OK. if((pAuthority == NULL || wcslen(pAuthority) < 1) && (pUser == NULL || wcslen(pUser) < 1) && (pPassword == NULL || wcslen(pPassword) < 1)) return SetInterfaceSecurity(pInterface, NULL, bAuthenticate); // If user, or Authority was passed in, the we need to create an authority argument for the login COAUTHIDENTITY authident; BSTR AuthArg = NULL, UserArg = NULL; sc = DetermineLoginType(AuthArg, UserArg, pAuthority, pUser); if(sc != S_OK) return sc; memset((void *)&authident,0,sizeof(COAUTHIDENTITY)); if(bIsNT()) { if(UserArg) { authident.UserLength = wcslen(UserArg); authident.User = (LPWSTR)UserArg; } if(AuthArg) { authident.DomainLength = wcslen(AuthArg); authident.Domain = (LPWSTR)AuthArg; } if(pPassword) { authident.PasswordLength = wcslen(pPassword); authident.Password = (LPWSTR)pPassword; } authident.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; sc = SetInterfaceSecurity(pInterface, &authident, bAuthenticate); } else { char szUser[MAX_PATH], szAuthority[MAX_PATH], szPassword[MAX_PATH]; // Fill in the indentity structure if(UserArg) { wcstombs(szUser, UserArg, MAX_PATH); authident.UserLength = strlen(szUser); authident.User = (LPWSTR)szUser; } if(AuthArg) { wcstombs(szAuthority, AuthArg, MAX_PATH); authident.DomainLength = strlen(szAuthority); authident.Domain = (LPWSTR)szAuthority; } if(pPassword) { wcstombs(szPassword, pPassword, MAX_PATH); authident.PasswordLength = strlen(szPassword); authident.Password = (LPWSTR)szPassword; } authident.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; sc = SetInterfaceSecurity(pInterface, &authident, bAuthenticate); } if(UserArg) SysFreeString(UserArg); if(AuthArg) SysFreeString(AuthArg); return sc; } //*************************************************************************** // // SCODE SetInterfaceSecurity // // DESCRIPTION: // // This routine is used by clients in order to set the identity to be used by a connection. // // PARAMETERS: // // pInterface Interface to be set // pDomain Input, domain // pUser Input, user name // pPassword Input, password. // pFrom Input, if not NULL, then the authentication level of this interface // is used // bAuthArg If pFrom is NULL, then this is the authentication level // RETURN VALUE: // // S_OK all is well // else error listed in WBEMSVC.H // //*************************************************************************** HRESULT WINAPI SetInterfaceSecurity(IUnknown * pInterface, LPWSTR pAuthority, LPWSTR pUser, LPWSTR pPassword, DWORD dwAuthLevel, DWORD dwImpLevel, DWORD dwCapabilities) { SCODE sc; if(!IsDcomEnabled()) // For the anon pipes clients, dont even bother return S_OK; if(pInterface == NULL) return WBEM_E_INVALID_PARAMETER; // If we are doing trivial case, just pass in a null authenication structure which is used // if the current logged in user's credentials are OK. if((pAuthority == NULL || wcslen(pAuthority) < 1) && (pUser == NULL || wcslen(pUser) < 1) && (pPassword == NULL || wcslen(pPassword) < 1)) { sc = WbemSetProxyBlanket(pInterface, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, dwAuthLevel, dwImpLevel, NULL, dwCapabilities); return sc; } // If user, or Authority was passed in, the we need to create an authority argument for the login COAUTHIDENTITY authident; BSTR AuthArg = NULL, UserArg = NULL, PrincipalArg = NULL; sc = DetermineLoginTypeEx(AuthArg, UserArg, PrincipalArg, pAuthority, pUser); if(sc != S_OK) return sc; memset((void *)&authident,0,sizeof(COAUTHIDENTITY)); if(bIsNT()) { if(UserArg) { authident.UserLength = wcslen(UserArg); authident.User = (LPWSTR)UserArg; } if(AuthArg) { authident.DomainLength = wcslen(AuthArg); authident.Domain = (LPWSTR)AuthArg; } if(pPassword) { authident.PasswordLength = wcslen(pPassword); authident.Password = (LPWSTR)pPassword; } authident.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; } else { char szUser[MAX_PATH], szAuthority[MAX_PATH], szPassword[MAX_PATH]; // Fill in the indentity structure if(UserArg) { wcstombs(szUser, UserArg, MAX_PATH); authident.UserLength = strlen(szUser); authident.User = (LPWSTR)szUser; } if(AuthArg) { wcstombs(szAuthority, AuthArg, MAX_PATH); authident.DomainLength = strlen(szAuthority); authident.Domain = (LPWSTR)szAuthority; } if(pPassword) { wcstombs(szPassword, pPassword, MAX_PATH); authident.PasswordLength = strlen(szPassword); authident.Password = (LPWSTR)szPassword; } authident.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; } sc = WbemSetProxyBlanket(pInterface, (PrincipalArg) ? 16 : RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, PrincipalArg, dwAuthLevel, dwImpLevel, (dwAuthLevel >= RPC_C_AUTHN_LEVEL_CONNECT) ? &authident : NULL, dwCapabilities); if(UserArg) SysFreeString(UserArg); if(AuthArg) SysFreeString(AuthArg); if(PrincipalArg) SysFreeString(PrincipalArg); return sc; } //*************************************************************************** // // SCODE SetInterfaceSecurity // // DESCRIPTION: // // This routine is used by clients in order to set the identity to be used by a connection. // // PARAMETERS: // // pInterface Interface to be set // pauthident Structure with the identity info already set. // // RETURN VALUE: // // S_OK all is well // //*************************************************************************** HRESULT WINAPI SetInterfaceSecurity(IUnknown * pInterface, COAUTHIDENTITY * pauthident, bool bAuthenticate) { if(pInterface == NULL) return WBEM_E_INVALID_PARAMETER; SCODE sc; sc = WbemSetProxyBlanket(pInterface, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, (bAuthenticate) ? RPC_C_AUTHN_LEVEL_DEFAULT : RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, (bAuthenticate) ? pauthident : NULL, EOAC_NONE); return sc; } void GetCurrentValue(IUnknown * pFrom,DWORD & dwAuthenticationArg, DWORD & dwAuthorizationArg) { if(pFrom == NULL) return; IClientSecurity * pFromSec = NULL; SCODE sc = pFrom->QueryInterface(IID_IClientSecurity, (void **) &pFromSec); if(sc == S_OK) { DWORD dwAuthnSvc, dwAuthzSvc; sc = pFromSec->QueryBlanket(pFrom, &dwAuthnSvc, &dwAuthzSvc, NULL, NULL, NULL, NULL, NULL); if (sc == S_OK) { dwAuthenticationArg = dwAuthnSvc; dwAuthorizationArg = dwAuthzSvc; } pFromSec->Release(); } } //*************************************************************************** // // SCODE SetInterfaceSecurityEx // // DESCRIPTION: // // This routine is used by clients in order to set the identity to be used by a connection. // // PARAMETERS: // // pInterface Interface to be set // pAuthority Input, authority // pUser Input, user name // pPassword Input, password. // dwAuthLevel Input, Authorization Level // dwImpLevel Input, Impersonation Level // dwCapabilities Input, Capability settings // ppAuthIdent Output, Allocated AuthIdentity if applicable, caller must free // manually (can use the FreeAuthInfo function). // pPrincipal Output, Principal calculated from supplied data Caller must // free using SysFreeString. // GetInfoFirst if true, the authentication and authorization are retrived via // QueryBlanket. // // RETURN VALUE: // // S_OK all is well // else error listed in WBEMSVC.H // //*************************************************************************** HRESULT WINAPI SetInterfaceSecurityEx(IUnknown * pInterface, LPWSTR pAuthority, LPWSTR pUser, LPWSTR pPassword, DWORD dwAuthLevel, DWORD dwImpLevel, DWORD dwCapabilities, COAUTHIDENTITY** ppAuthIdent, BSTR* pPrincipal, bool GetInfoFirst) { SCODE sc; DWORD dwAuthenticationArg = RPC_C_AUTHN_WINNT; DWORD dwAuthorizationArg = RPC_C_AUTHZ_NONE; if(!IsDcomEnabled()) // For the anon pipes clients, dont even bother return S_OK; if( pInterface == NULL || NULL == ppAuthIdent || NULL == pPrincipal ) return WBEM_E_INVALID_PARAMETER; if(GetInfoFirst) GetCurrentValue(pInterface, dwAuthenticationArg, dwAuthorizationArg); // If we are doing trivial case, just pass in a null authenication structure which is used // if the current logged in user's credentials are OK. if((pAuthority == NULL || wcslen(pAuthority) < 1) && (pUser == NULL || wcslen(pUser) < 1) && (pPassword == NULL || wcslen(pPassword) < 1)) { sc = WbemSetProxyBlanket(pInterface, dwAuthenticationArg, dwAuthorizationArg, NULL, dwAuthLevel, dwImpLevel, NULL, dwCapabilities); return sc; } // If user, or Authority was passed in, the we need to create an authority argument for the login BSTR AuthArg = NULL, UserArg = NULL, PrincipalArg = NULL; sc = DetermineLoginTypeEx(AuthArg, UserArg, PrincipalArg, pAuthority, pUser); if(sc != S_OK) { return sc; } // Handle an allocation failure COAUTHIDENTITY* pAuthIdent = NULL; // We will only need this structure if we are not cloaking and we want at least // connect level authorization if ( !( dwCapabilities & (EOAC_STATIC_CLOAKING | EOAC_DYNAMIC_CLOAKING) ) && (dwAuthLevel >= RPC_C_AUTHN_LEVEL_CONNECT) ) { sc = WbemAllocAuthIdentity( UserArg, pPassword, AuthArg, &pAuthIdent ); } if ( SUCCEEDED( sc ) ) { sc = WbemSetProxyBlanket(pInterface, (PrincipalArg) ? 16 : dwAuthenticationArg, dwAuthorizationArg, PrincipalArg, dwAuthLevel, dwImpLevel, pAuthIdent, dwCapabilities); // We will store relevant values as necessary if ( SUCCEEDED( sc ) ) { *ppAuthIdent = pAuthIdent; *pPrincipal = PrincipalArg; } else { WbemFreeAuthIdentity( pAuthIdent ); } } if(UserArg) SysFreeString(UserArg); if(AuthArg) SysFreeString(AuthArg); // Only free if we failed if(PrincipalArg && FAILED( sc )) { SysFreeString(PrincipalArg); } return sc; } //*************************************************************************** // // SCODE SetInterfaceSecurityEx // // DESCRIPTION: // // This routine is used by clients in order to set the identity to be used by a connection. // // PARAMETERS: // // pInterface Interface to be set // pAuthIdent Input, Preset COAUTHIDENTITY structure pointer. // pPrincipal Input, Preset principal argument // dwAuthLevel Input, Authorization Level // dwImpLevel Input, Impersonation Level // dwCapabilities Input, Capability settings // GetInfoFirst if true, the authentication and authorization are retrived via // QueryBlanket. // RETURN VALUE: // // S_OK all is well // else error listed in WBEMSVC.H // //*************************************************************************** HRESULT WINAPI SetInterfaceSecurityEx(IUnknown * pInterface, COAUTHIDENTITY* pAuthIdent, BSTR pPrincipal, DWORD dwAuthLevel, DWORD dwImpLevel, DWORD dwCapabilities, bool GetInfoFirst) { DWORD dwAuthenticationArg = RPC_C_AUTHN_WINNT; DWORD dwAuthorizationArg = RPC_C_AUTHZ_NONE; if(!IsDcomEnabled()) // For the anon pipes clients, dont even bother return S_OK; if(pInterface == NULL) return WBEM_E_INVALID_PARAMETER; if(GetInfoFirst) GetCurrentValue(pInterface, dwAuthenticationArg, dwAuthorizationArg); // The complicated values should have already been precalced. // Note : For auth level, we have to check for the 'RPC_C_AUTHN_LEVEL_DEFAULT' (=0) value as well, // as after negotiation with the server it might result in something high that does need // the identity structure !! return WbemSetProxyBlanket(pInterface, (pPrincipal) ? 16 : dwAuthenticationArg, dwAuthorizationArg, pPrincipal, dwAuthLevel, dwImpLevel, ((dwAuthLevel == RPC_C_AUTHN_LEVEL_DEFAULT) || (dwAuthLevel >= RPC_C_AUTHN_LEVEL_CONNECT)) ? pAuthIdent : NULL, dwCapabilities); } //*************************************************************************** // // HRESULT WbemAllocAuthIdentity // // DESCRIPTION: // // Walks a COAUTHIDENTITY structure and CoTaskMemAllocs the member data and the // structure. // // PARAMETERS: // // pUser Input // pPassword Input // pDomain Input // ppAuthInfo Output, Newly allocated structure // // RETURN VALUE: // // S_OK all is well // //*************************************************************************** HRESULT WINAPI WbemAllocAuthIdentity( LPCWSTR pUser, LPCWSTR pPassword, LPCWSTR pDomain, COAUTHIDENTITY** ppAuthIdent ) { if ( NULL == ppAuthIdent ) { return WBEM_E_INVALID_PARAMETER; } // Handle an allocation failure COAUTHIDENTITY* pAuthIdent = NULL; pAuthIdent = (COAUTHIDENTITY*) CoTaskMemAlloc( sizeof(COAUTHIDENTITY) ); if ( NULL == pAuthIdent ) { return WBEM_E_OUT_OF_MEMORY; } memset((void *)pAuthIdent,0,sizeof(COAUTHIDENTITY)); if(bIsNT()) { // Allocate needed memory and copy in data. Cleanup if anything goes wrong if ( NULL != pUser ) { pAuthIdent->User = (LPWSTR) CoTaskMemAlloc( ( wcslen(pUser) + 1 ) * sizeof( WCHAR ) ); if ( NULL == pAuthIdent->User ) { WbemFreeAuthIdentity( pAuthIdent ); return WBEM_E_OUT_OF_MEMORY; } pAuthIdent->UserLength = wcslen(pUser); wcscpy( pAuthIdent->User, pUser ); } if ( NULL != pDomain ) { pAuthIdent->Domain = (LPWSTR) CoTaskMemAlloc( ( wcslen(pDomain) + 1 ) * sizeof( WCHAR ) ); if ( NULL == pAuthIdent->Domain ) { WbemFreeAuthIdentity( pAuthIdent ); return WBEM_E_OUT_OF_MEMORY; } pAuthIdent->DomainLength = wcslen(pDomain); wcscpy( pAuthIdent->Domain, pDomain ); } if ( NULL != pPassword ) { pAuthIdent->Password = (LPWSTR) CoTaskMemAlloc( ( wcslen(pPassword) + 1 ) * sizeof( WCHAR ) ); if ( NULL == pAuthIdent->Password ) { WbemFreeAuthIdentity( pAuthIdent ); return WBEM_E_OUT_OF_MEMORY; } pAuthIdent->PasswordLength = wcslen(pPassword); wcscpy( pAuthIdent->Password, pPassword ); } pAuthIdent->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; } else { size_t nBufferLength; // Allocate needed memory and copy in data. Cleanup if anything goes wrong if ( NULL != pUser ) { // How many characters do we need? nBufferLength = wcstombs( NULL, pUser, 0 ) + 1; pAuthIdent->User = (LPWSTR) CoTaskMemAlloc( nBufferLength ); if ( NULL == pAuthIdent->User ) { WbemFreeAuthIdentity( pAuthIdent ); return WBEM_E_OUT_OF_MEMORY; } pAuthIdent->UserLength = wcslen(pUser); wcstombs( (LPSTR) pAuthIdent->User, pUser, nBufferLength ); } if ( NULL != pDomain ) { // How many characters do we need? nBufferLength = wcstombs( NULL, pDomain, 0 ) + 1; pAuthIdent->Domain = (LPWSTR) CoTaskMemAlloc( nBufferLength ); if ( NULL == pAuthIdent->Domain ) { WbemFreeAuthIdentity( pAuthIdent ); return WBEM_E_OUT_OF_MEMORY; } pAuthIdent->DomainLength = wcslen(pDomain); wcstombs( (LPSTR) pAuthIdent->Domain, pDomain, nBufferLength ); } if ( NULL != pPassword ) { // How many characters do we need? nBufferLength = wcstombs( NULL, pPassword, 0 ) + 1; pAuthIdent->Password = (LPWSTR) CoTaskMemAlloc( nBufferLength ); if ( NULL == pAuthIdent->Password ) { WbemFreeAuthIdentity( pAuthIdent ); return WBEM_E_OUT_OF_MEMORY; } pAuthIdent->PasswordLength = wcslen(pPassword); wcstombs( (LPSTR) pAuthIdent->Password, pPassword, nBufferLength ); } pAuthIdent->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; } *ppAuthIdent = pAuthIdent; return S_OK; } //*************************************************************************** // // HRESULT WbemFreeAuthIdentity // // DESCRIPTION: // // Walks a COAUTHIDENTITY structure and CoTaskMemFrees the member data and the // structure. // // PARAMETERS: // // pAuthInfo Structure to free // // RETURN VALUE: // // S_OK all is well // //*************************************************************************** HRESULT WINAPI WbemFreeAuthIdentity( COAUTHIDENTITY* pAuthIdentity ) { // Make sure we have a pointer, then walk the structure members and // cleanup. if ( NULL != pAuthIdentity ) { if ( NULL != pAuthIdentity->User ) { CoTaskMemFree( pAuthIdentity->User ); } if ( NULL != pAuthIdentity->Password ) { CoTaskMemFree( pAuthIdentity->Password ); } if ( NULL != pAuthIdentity->Domain ) { CoTaskMemFree( pAuthIdentity->Domain ); } CoTaskMemFree( pAuthIdentity ); } return S_OK; } //*************************************************************************** // // HRESULT WbemCoQueryClientBlanket // HRESULT WbemCoImpersonateClient( void) // HRESULT WbemCoRevertToSelf( void) // // DESCRIPTION: // // These routine wrap some common dcom functions. They are wrapped just in // case the code is running on nt 3.51. // // PARAMETERS: // // pInterface Interface to be set // pauthident Structure with the identity info already set. // // RETURN VALUE: // // S_OK all is well // //*************************************************************************** HRESULT WINAPI WbemCoQueryClientBlanket( /* [out] */ DWORD __RPC_FAR *pAuthnSvc, /* [out] */ DWORD __RPC_FAR *pAuthzSvc, /* [out] */ OLECHAR __RPC_FAR *__RPC_FAR *pServerPrincName, /* [out] */ DWORD __RPC_FAR *pAuthnLevel, /* [out] */ DWORD __RPC_FAR *pImpLevel, /* [out] */ void __RPC_FAR *__RPC_FAR *pPrivs, /* [out] */ DWORD __RPC_FAR *pCapabilities) { IServerSecurity * pss = NULL; SCODE sc = WbemCoGetCallContext(IID_IServerSecurity, (void**)&pss); if(S_OK == sc) { pss->QueryBlanket(pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel, pPrivs, pCapabilities); pss->Release(); } return sc; } HRESULT WINAPI WbemCoImpersonateClient( void) { IServerSecurity * pss = NULL; SCODE sc = WbemCoGetCallContext(IID_IServerSecurity, (void**)&pss); if(S_OK == sc) { sc = pss->ImpersonateClient(); pss->Release(); } return sc; } bool WINAPI WbemIsImpersonating(void) { bool bRet = false; IServerSecurity * pss = NULL; SCODE sc = WbemCoGetCallContext(IID_IServerSecurity, (void**)&pss); if(S_OK == sc) { bRet = (pss->IsImpersonating() == TRUE); pss->Release(); } return bRet; } HRESULT WINAPI WbemCoRevertToSelf( void) { IServerSecurity * pss = NULL; SCODE sc = WbemCoGetCallContext(IID_IServerSecurity, (void**)&pss); if(S_OK == sc) { sc = pss->RevertToSelf(); pss->Release(); } return sc; } void WINAPI CloseStuff() { if(g_LibHandleOle32.GetHandle()) { FreeLibrary(g_LibHandleOle32.GetHandle()); g_LibHandleOle32.SetHandle( NULL ); g_bInitialized = FALSE; } } // Encryption/Decryption helpers void EncryptWCHARString( WCHAR* pwszString, ULONG nNumChars ) { if ( NULL != pwszString ) { for ( ULONG x = 0; x < nNumChars; x++ ) { pwszString[x] += 1; } } } void DecryptWCHARString( WCHAR* pwszString, ULONG nNumChars ) { if ( NULL != pwszString ) { for ( ULONG x = 0; x < nNumChars; x++ ) { pwszString[x] -= 1; } } } void EncryptAnsiString( char* pszString, ULONG nNumChars ) { if ( NULL != pszString ) { for ( ULONG x = 0; x < nNumChars; x++ ) { pszString[x] += 1; } } } void DecryptAnsiString( char* pszString, ULONG nNumChars ) { if ( NULL != pszString ) { for ( ULONG x = 0; x < nNumChars; x++ ) { pszString[x] -= 1; } } } //*************************************************************************** // // SCODE EncryptCredentials // // DESCRIPTION: // // This routine is used to encrypt the supplied authidentity structure. // // PARAMETERS: // // pAuthIdent Structure to encrypt. // // RETURN VALUE: // // S_OK all is well // else error listed in WBEMSVC.H // //*************************************************************************** HRESULT WINAPI EncryptCredentials( COAUTHIDENTITY* pAuthIdent ) { HRESULT hr = WBEM_S_NO_ERROR; if ( NULL != pAuthIdent ) { // ANSI or WCHAR if ( pAuthIdent->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI ) { EncryptAnsiString( (char*) pAuthIdent->User, pAuthIdent->UserLength ); EncryptAnsiString( (char*) pAuthIdent->Domain, pAuthIdent->DomainLength ); EncryptAnsiString( (char*) pAuthIdent->Password, pAuthIdent->PasswordLength ); } else { EncryptWCHARString( pAuthIdent->User, pAuthIdent->UserLength ); EncryptWCHARString( pAuthIdent->Domain, pAuthIdent->DomainLength ); EncryptWCHARString( pAuthIdent->Password, pAuthIdent->PasswordLength ); } } return hr; } //*************************************************************************** // // SCODE DecryptCredentials // // DESCRIPTION: // // This routine is used to decrypt the supplied authidentity structure. The // structure must have been encrypted by EncryptCredentials // // PARAMETERS: // // pAuthIdent Structure to decrypt. // // RETURN VALUE: // // S_OK all is well // else error listed in WBEMSVC.H // //*************************************************************************** HRESULT WINAPI DecryptCredentials( COAUTHIDENTITY* pAuthIdent ) { HRESULT hr = WBEM_S_NO_ERROR; if ( NULL != pAuthIdent ) { // ANSI or WCHAR if ( pAuthIdent->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI ) { DecryptAnsiString( (char*) pAuthIdent->User, pAuthIdent->UserLength ); DecryptAnsiString( (char*) pAuthIdent->Domain, pAuthIdent->DomainLength ); DecryptAnsiString( (char*) pAuthIdent->Password, pAuthIdent->PasswordLength ); } else { DecryptWCHARString( pAuthIdent->User, pAuthIdent->UserLength ); DecryptWCHARString( pAuthIdent->Domain, pAuthIdent->DomainLength ); DecryptWCHARString( pAuthIdent->Password, pAuthIdent->PasswordLength ); } } return hr; } //*************************************************************************** // // SCODE SetInterfaceSecurityEncrypt // // DESCRIPTION: // // This routine is used by clients in order to set the identity to be used by a connection. // The returned AuthIdentity structure will be encrypted before returning. // // PARAMETERS: // // pInterface Interface to be set // pAuthority Input, authority // pUser Input, user name // pPassword Input, password. // dwAuthLevel Input, Authorization Level // dwImpLevel Input, Impersonation Level // dwCapabilities Input, Capability settings // ppAuthIdent Output, Allocated AuthIdentity if applicable, caller must free // manually (can use the FreeAuthInfo function). // pPrincipal Output, Principal calculated from supplied data Caller must // free using SysFreeString. // GetInfoFirst if true, the authentication and authorization are retrived via // QueryBlanket. // // RETURN VALUE: // // S_OK all is well // else error listed in WBEMSVC.H // //*************************************************************************** HRESULT WINAPI SetInterfaceSecurityEncrypt(IUnknown * pInterface, LPWSTR pDomain, LPWSTR pUser, LPWSTR pPassword, DWORD dwAuthLevel, DWORD dwImpLevel, DWORD dwCapabilities, COAUTHIDENTITY** ppAuthIdent, BSTR* ppPrinciple, bool GetInfoFirst ) { HRESULT hr = SetInterfaceSecurityEx( pInterface, pDomain, pUser, pPassword, dwAuthLevel, dwImpLevel, dwCapabilities, ppAuthIdent, ppPrinciple, GetInfoFirst ); if ( SUCCEEDED( hr ) ) { if ( NULL != ppAuthIdent ) { hr = EncryptCredentials( *ppAuthIdent ); } } return hr; } //*************************************************************************** // // SCODE SetInterfaceSecurityDecrypt // // DESCRIPTION: // // This routine is used by clients in order to set the identity to be used by a connection. // It will unencrypt and reencrypt the auth identity structure in place. // // PARAMETERS: // // pInterface Interface to be set // pAuthIdent Input, Preset COAUTHIDENTITY structure pointer. // pPrincipal Input, Preset principal argument // dwAuthLevel Input, Authorization Level // dwImpLevel Input, Impersonation Level // dwCapabilities Input, Capability settings // GetInfoFirst if true, the authentication and authorization are retrived via // QueryBlanket. // RETURN VALUE: // // S_OK all is well // else error listed in WBEMSVC.H // //*************************************************************************** HRESULT WINAPI SetInterfaceSecurityDecrypt(IUnknown * pInterface, COAUTHIDENTITY* pAuthIdent, BSTR pPrincipal, DWORD dwAuthLevel, DWORD dwImpLevel, DWORD dwCapabilities, bool GetInfoFirst ) { // Decrypt first HRESULT hr = DecryptCredentials( pAuthIdent ); if ( SUCCEEDED( hr ) ) { hr = SetInterfaceSecurityEx( pInterface, pAuthIdent, pPrincipal, dwAuthLevel, dwImpLevel, dwCapabilities, GetInfoFirst ); hr = EncryptCredentials( pAuthIdent ); } return hr; }