/*++ Copyright (c) 1996 Microsoft Corporation © 1998 Seagate Software, Inc. All rights reserved. Module Name: HsmConn.cpp Abstract: This is the main implementation of the HsmConn dll. This dll provides functions for accessing Directory Services and for connecting to our services. Author: Rohde Wakefield [rohde] 21-Oct-1996 Revision History: --*/ #include "stdafx.h" #include #include #include // Required by SECURITY.H #define SECURITY_WIN32 #include // HsmConnPoint objects are used only here #include "hsmservr.h" // // Tracing information // #define WSB_TRACE_IS WSB_TRACE_BIT_HSMCONN // // _Module instantiation for ATL // CComModule _Module; ///////////////////////////////////////////////////////////////////////////// #define REG_PATH OLESTR("SOFTWARE\\Microsoft\\RemoteStorage") #define REG_USE_DS OLESTR("UseDirectoryServices") // Local data static OLECHAR CNEqual[] = L"CN="; static OLECHAR ComputersNodeName[] = L"Computers"; static OLECHAR DCsNodeName[] = L"Domain Controllers"; static OLECHAR ContainerType[] = L"Container"; static OLECHAR DisplaySpecifierName[] = L"displaySpecifier"; static OLECHAR GuidAttrName[] = L"remoteStorageGUID"; static OLECHAR RsDisplaySpecifierName[] = L"remoteStorageServicePoint-Display"; static OLECHAR RsNodeName[] = L"RemoteStorage"; static OLECHAR RsNodeType[] = L"remoteStorageServicePoint"; static OLECHAR ServiceBindAttrName[] = L"serviceBindingInformation"; static OLECHAR ServiceBindValue[] = L"Rsadmin.msc /ds "; static ADS_ATTR_INFO aaInfo[2]; // For use in IDirectoryObject static ADSVALUE adsValue[2]; // For use in IDirectoryObject static OLECHAR DomainName[MAX_COMPUTERNAME_LENGTH]; static BOOL DSIsWritable = FALSE; // Default to "NO" static BOOL UseDirectoryServices = FALSE; // Default to "NO" #if defined(HSMCONN_DEBUG) // We use this and OutputDebugString when we can't use our normal // tracing. OLECHAR dbg_string[200]; #endif extern "C" { // Local functions static void GetDSState(void); static HRESULT HsmConnectToServer(HSMCONN_TYPE type, const OLECHAR * Server, REFIID riid, void ** ppv); static const OLECHAR *HsmConnTypeAsString(HSMCONN_TYPE type); static GUID HsmConnTypeToGuid(IN HSMCONN_TYPE type); static HRESULT HsmGetComputerNode(const OLECHAR * compName, IADsContainer **pContainer); static HRESULT HsmGetDsChild(IADsContainer * pContainer, const OLECHAR * Name, REFIID riid, void **ppv); BOOL WINAPI DllMain ( IN HINSTANCE hInst, IN ULONG ulReason, LPVOID /*lpReserved*/ ) /*++ Routine Description: This routine is called whenever a new process and thread attaches to this DLL. Its purpose is to initialize the _Module object, necessary for ATL. Arguments: hInst - HINSTANCE of this dll. ulReason - Context of the attaching/detaching Return Value: non-zero - success 0 - prevent action --*/ { switch ( ulReason ) { case DLL_PROCESS_ATTACH: // // Initialize the ATL module, and prevent // any of the additional threads from sending // notifications through // _Module.Init ( 0, hInst ); DisableThreadLibraryCalls ( hInst ); GetDSState(); break; case DLL_PROCESS_DETACH: // // Tell ATL module to terminate // _Module.Term ( ); break; } return ( TRUE ); } static HRESULT HsmConnectToServer ( IN HSMCONN_TYPE type, IN const OLECHAR * Server, IN REFIID riid, OUT void ** ppv ) /*++ Routine Description: Given a generic server (connected via HsmConnPoint class) connect to it and return back the requested interface 'riid'. Arguments: type - Type of server to connect Server - Name of machine on which server is running. riid - The interface type to return. ppv - Returned interface pointer of the Server. Return Value: S_OK - Connection made, Success. E_NOINTERFACE - Requested interface not supported by Server. E_POINTER - ppv is not a valid pointer. E_OUTOFMEMORY - Low memory condition prevented connection. HSM_E_NOT_READY - Engine is not running or not initialized yet FSA_E_NOT_READY - Fsa is not running or not initialized yet --*/ { WsbTraceIn ( L"HsmConnectToServer", L"type = '%ls' , Server = '%ls', riid = '%ls', ppv = 0x%p", HsmConnTypeAsString ( type ), Server, WsbStringCopy ( WsbGuidAsString ( riid ) ), ppv ); HRESULT hr = S_OK; try { // // Ensure parameters are valid // WsbAssert ( 0 != Server, E_POINTER ); WsbAssert ( 0 != ppv, E_POINTER ); // // We will specify the provided HSM as the machine to contact, // so Construct a COSERVERINFO with Server. // REFCLSID rclsid = CLSID_HsmConnPoint; COSERVERINFO csi; memset ( &csi, 0, sizeof ( csi ) ); csi.pwszName = (OLECHAR *) Server; // must cast to remove constness // // Build a MULTI_QI structure to obtain desired interface (necessary for // CoCreateInstanceEx). In our case, we need only one interface. // MULTI_QI mqi[1]; memset ( mqi, 0, sizeof ( mqi ) ); mqi[0].pIID = &IID_IHsmConnPoint; // // The HsmConnPoint object ic created in the scope of the main HSM service and // provides access for HSM server objects // WsbAffirmHr( CoCreateInstanceEx ( rclsid, 0, CLSCTX_SERVER, &csi, 1, mqi ) ); // // Put returned interfaces in smart pointers so we // don't leak a reference in case off throw // CComPtr pConn; if( SUCCEEDED( mqi[0].hr ) ) { pConn = (IHsmConnPoint *)(mqi[0].pItf); (mqi[0].pItf)->Release( ); hr = mqi[0].hr; #if 0 // This is now done at the COM process-wide security layer /* NOTE: In case that a per-connection security will be require, the method CheckAccess should be implemented in CHsmConnPoint */ // // Check the security first // WsbAffirmHr( mqi[1].hr ); WsbAffirmHr( pServer->CheckAccess( WSB_ACCESS_TYPE_ADMINISTRATOR ) ); #endif // get the server object itself switch (type) { case HSMCONN_TYPE_HSM: { WsbAffirmHr( pConn->GetEngineServer((IHsmServer **)ppv) ); break; } case HSMCONN_TYPE_FSA: case HSMCONN_TYPE_RESOURCE: { WsbAffirmHr( pConn->GetFsaServer((IFsaServer **)ppv) ); break; } default: { WsbThrow ( E_INVALIDARG ); break; } } } else { // Make sure interface pointer is safe (NULL) when failing *ppv = 0; } } WsbCatchAndDo ( hr, // Make sure interface pointer is safe (NULL) when failing *ppv = 0; ) // WsbCatchAndDo WsbTraceOut ( L"HsmConnectToServer", L"HRESULT = %ls, *ppv = %ls", WsbHrAsString ( hr ), WsbPtrToPtrAsString ( ppv ) ); return ( hr ); } HRESULT HsmGetComputerNameFromADsPath( IN const OLECHAR * szADsPath, OUT OLECHAR ** pszComputerName ) /*++ Routine Description: Extract the computer name from the ADs path of the RemoteStorage node. The assumption here is that the full ADs path will contain this substring: "CN=RemoteStorage,CN=computername,CN=Computers" where computername is what we want to return. Arguments: szADsPath - The ADs path. pszComputerName - The returned computer name. Return Value: S_OK - Computer name returned OK. --*/ { HRESULT hr = S_FALSE; WCHAR* pContainerNode; WCHAR* pRSNode; WsbTraceIn(OLESTR("HsmGetComputerNameFromADsPath"), OLESTR("AdsPath = <%ls>"), szADsPath); // Find the RemoteStorage node name and the computers node name // in the ADs path. If the machine is a DC, then we have to // check for a "Domain Controllers" level instead. *pszComputerName = NULL; pRSNode = wcsstr(szADsPath, RsNodeName); pContainerNode = wcsstr(szADsPath, ComputersNodeName); if(!pContainerNode) { pContainerNode = wcsstr(szADsPath, DCsNodeName); } if (pRSNode && pContainerNode && pRSNode < pContainerNode) { WCHAR* pWc; // Find the "CN=" before the computer name pWc = wcsstr(pRSNode, CNEqual); if (pWc && pWc < pContainerNode) { WCHAR* pComma; // Skip the "CN=" pWc += wcslen(CNEqual); // Find the "," after the computer name pComma = wcschr(pWc, OLECHAR(',')); // Extract the computer name if (pWc < pContainerNode && pComma && pComma < pContainerNode) { int len; len = (int)(pComma - pWc); // Remove '$' from end of name??? if (0 < len && OLECHAR('$') == pWc[len - 1]) { len--; } *pszComputerName = static_cast(WsbAlloc( (len + 1) * sizeof(WCHAR))); if (*pszComputerName) { wcsncpy(*pszComputerName, pWc, len); (*pszComputerName)[len] = 0; hr = S_OK; } } } } WsbTraceOut (OLESTR("HsmGetComputerNameFromADsPath"), OLESTR("HRESULT = %ls, Computername = <%ls>"), WsbHrAsString(hr), (*pszComputerName ? *pszComputerName : OLESTR(""))); return(hr); } static HRESULT HsmGetComputerNode( const OLECHAR * Name, IADsContainer **ppContainer ) /*++ Routine Description: Return the computer node for the given computer name in the current Domain Arguments: Name - Computer name. ppContainer - Returned interface pointer of the node. Return Value: S_OK - Success. --*/ { HRESULT hr = S_OK; WsbTraceIn ( L"HsmGetComputerNode", L"Name = <%ls>", Name); try { WsbAssert(UseDirectoryServices, E_NOTIMPL); WCHAR ComputerDn[MAX_PATH]; CWsbStringPtr temp; ULONG ulen; // Construct the SamCompatible (whatever that means) name temp = DomainName; temp.Append("\\"); temp.Append(Name); temp.Append("$"); WsbTrace(L"HsmGetComputerNode: Domain\\computer = <%ls>\n", static_cast(temp)); // Translate that name to a fully qualified one ulen = MAX_PATH; ComputerDn[0] = WCHAR('\0'); if (TranslateName(temp, NameSamCompatible, NameFullyQualifiedDN, ComputerDn, &ulen)) { WsbTrace(L"HsmGetComputerNode: ComputerDn = <%ls>\n", ComputerDn); // Get the computer node temp = "LDAP://"; temp.Append(ComputerDn); WsbTrace(L"HsmGetComputerNode: calling ADsGetObject with <%ls>\n", static_cast(temp)); WsbAffirmHr(ADsGetObject(temp, IID_IADsContainer, (void**)ppContainer)); } else { DWORD err = GetLastError(); WsbTrace(L"HsmGetComputerNode: TranslateName failed; ComputerDn = <%ls>, err = %ld\n", ComputerDn, err); if (err) { WsbThrow(HRESULT_FROM_WIN32(err)); } else { WsbThrow(E_UNEXPECTED); } } WsbTrace(OLESTR("HsmGetComputerNode: got computer node\n")); } WsbCatch( hr ) WsbTraceOut ( L"HsmGetComputerNode", L"HRESULT = %ls, *ppContainer = '%ls'", WsbHrAsString ( hr ), WsbPtrToPtrAsString ( (void**)ppContainer ) ); return ( hr ); } static HRESULT HsmGetDsChild ( IN IADsContainer * pContainer, IN const OLECHAR * Name, IN REFIID riid, OUT void ** ppv ) /*++ Routine Description: This routine returns back the requested child node. Arguments: pContainer - The parent container. Name - The childs name (i.e. value of Name attribute or CN=Name) riid - Desired interface to return. ppv - Returned interface. Return Value: S_OK - Connection made, Success. E_POINTER - Invalid pointer passed in as parameter. E_* - Error --*/ { WsbTraceIn ( L"HsmGetDsChild", L"pContainer = '0x%p', Name = '%ls', riid = '%ls', ppv = '0x%p'", pContainer, Name, WsbGuidAsString ( riid ), ppv ); HRESULT hr = S_OK; try { CWsbStringPtr lName; CComPtr pDispatch; // Validate params WsbAssert ( 0 != pContainer, E_POINTER ); WsbAssert ( 0 != Name, E_POINTER ); WsbAssert ( 0 != ppv, E_POINTER ); WsbAssert(UseDirectoryServices, E_NOTIMPL); // Check to see if the child exists lName = Name; hr = pContainer->GetObject(NULL, lName, &pDispatch); if (FAILED(hr)) { hr = S_OK; lName.Prepend(CNEqual); WsbAffirmHr(pContainer->GetObject(NULL, lName, &pDispatch)); } // Convert to the correct interface WsbAffirmHr(pDispatch->QueryInterface(riid, ppv)); } WsbCatch( hr ) WsbTraceOut ( L"HsmGetDsChild", L"HRESULT = %ls, *ppv = '%ls'", WsbHrAsString ( hr ), WsbPtrToPtrAsString ( ppv ) ); return ( hr ); } static const OLECHAR * HsmConnTypeAsString ( IN HSMCONN_TYPE type ) /*++ Routine Description: Gives back a static string representing the connection type. Note return type is strictly ANSI. This is intentional to make macro work possible. Arguments: type - the type to return a string for. Return Value: NULL - invalid type passed in. Otherwise, a valid char *. --*/ { #define STRINGIZE(_str) (OLESTR( #_str )) #define RETURN_STRINGIZED_CASE(_case) \ case _case: \ return ( STRINGIZE( _case ) ); // // Do the Switch // switch ( type ) { RETURN_STRINGIZED_CASE( HSMCONN_TYPE_HSM ); RETURN_STRINGIZED_CASE( HSMCONN_TYPE_FSA ); RETURN_STRINGIZED_CASE( HSMCONN_TYPE_FILTER ); RETURN_STRINGIZED_CASE( HSMCONN_TYPE_RESOURCE ); default: return ( OLESTR("Invalid Value") ); } } static GUID HsmConnTypeToGuid(IN HSMCONN_TYPE type) { GUID serverGuid = GUID_NULL; switch ( type ) { case HSMCONN_TYPE_HSM: serverGuid = CLSID_HsmServer; break; case HSMCONN_TYPE_FSA: case HSMCONN_TYPE_RESOURCE: serverGuid = CLSID_CFsaServerNTFS; break; } return(serverGuid); } HRESULT HsmConnectFromName ( IN HSMCONN_TYPE type, IN const OLECHAR * Name, IN REFIID riid, OUT void ** ppv ) /*++ Routine Description: When given an name, connect and return the object representing the Server, providing the specified interface. Arguments: type - The type of service / object we are connecting too. Name - UNICODE string describing the Server to connect to. riid - The interface type to return. ppv - Returned interface pointer of the Server. Return Value: S_OK - Connection made, Success. E_NOINTERFACE - Requested interface not supported by Server. E_POINTER - ppv or Name is not a valid pointer. E_OUTOFMEMORY - Low memory condition prevented connection. E_INVALIDARG - The given name does not corespond to a known Server. --*/ { WsbTraceIn ( L"HsmConnectFromName", L"type = '%ls', Name = '%ls', riid = '%ls', ppv = 0x%p", HsmConnTypeAsString ( type ), Name, WsbGuidAsString ( riid ), ppv ); WsbTrace(OLESTR("HsmConnectFromName: UseDirectoryServices = %ls\n"), WsbBoolAsString(UseDirectoryServices)); HRESULT hr = S_OK; try { BOOLEAN done = FALSE; // // Ensure parameters are valid // WsbAssert ( 0 != Name, E_POINTER ); WsbAssert ( 0 != ppv, E_POINTER ); if (!done) { // Try without Directory Services CWsbStringPtr ComputerName = Name; int i; // Get the computer/server name i = wcscspn(Name, OLESTR("\\")); ComputerName[i] = 0; if (HSMCONN_TYPE_RESOURCE == type) { CWsbStringPtr Path; OLECHAR * rscName; CComPtr pFsaResource; CComPtr pFsaServer; WsbAffirmHr(HsmConnectToServer(type, ComputerName, IID_IFsaServer, (void**)&pFsaServer)); // Determine if we have a logical name or a sticky name format. // The logical name is a format like ("server\NTFS\d") and a sticky name // format is like ("server\NTFS\Volume{GUID}\"). // Find the start of the last section and determine if there is only a single // character after it or not. rscName = wcsstr ( Name, L"NTFS\\" ); WsbAssert ( 0 != rscName, E_INVALIDARG ); // Now point just past the "NTFS\" part of the string. So we are pointing at // either a single character, indicating the drive, or the "Volume{GUID}\". rscName += 5; Path = rscName; if (wcslen (rscName) == 1) { // Logical name ("server\NTFS\d") so convert to path and find resource WsbAffirmHr(Path.Append(":\\")); WsbAffirmHr(pFsaServer->FindResourceByPath(Path, &pFsaResource)); } else { // Sticky name ("server\NTFS\Volume{GUID}\") so find resource for it. WsbAffirmHr(pFsaServer->FindResourceByStickyName(Path, &pFsaResource)); } WsbAffirmHr(pFsaResource->QueryInterface(riid, ppv)); } else { WsbAffirmHr(HsmConnectToServer(type, ComputerName, riid, ppv)); } } } WsbCatch ( hr ) WsbTraceOut ( L"HsmConnectFromName", L"HRESULT = %ls, *ppv = %ls", WsbHrAsString ( hr ), WsbPtrToPtrAsString ( ppv ) ); return ( hr ); } HRESULT HsmConnectFromId ( IN HSMCONN_TYPE type, IN REFGUID rguid, IN REFIID riid, OUT void ** ppv ) /*++ Routine Description: Connects to the specified service or object. See HSMCONN_TYPE for the types of services and objects. Arguments: type - The type of service / object we are connecting too. rguid - The unique ID of the service / object to connect too. riid - The interface type to return. ppv - Returned interface pointer of the HSM Server. Return Value: S_OK - Connection made, Success. E_NOINTERFACE - Requested interface not supported by HSM Server. E_POINTER - ppv or Hsm is not a valid pointer. E_OUTOFMEMORY - Low memory condition prevented connection. E_INVALIDARG - The given ID and type do not correspond to a known service or object. --*/ { WsbTraceIn ( L"HsmConnectFromId", L"type = '%ls', rguid = '%ls', riid = '%ls', ppv = 0x%p", HsmConnTypeAsString ( type ), WsbStringCopy ( WsbGuidAsString ( rguid ) ), WsbStringCopy ( WsbGuidAsString ( riid ) ), ppv ); WsbTrace(OLESTR("HsmConnectFromId: UseDirectoryServices = %ls\n"), WsbBoolAsString(UseDirectoryServices)); HRESULT hr = S_OK; try { BOOLEAN DSUsed = FALSE; CWsbVariant guidVariant; CComPtr < IADs > pObject; CWsbStringPtr serverName; CWsbVariant serverVariant; // // Ensure parameters are valid // WsbAssert ( 0 != ppv, E_POINTER ); switch ( type ) { case HSMCONN_TYPE_HSM: case HSMCONN_TYPE_FSA: case HSMCONN_TYPE_FILTER: if (DSUsed) { } else { WsbAffirmHr( WsbGetComputerName( serverName ) ); } // // Connect to the server // WsbAffirmHr ( HsmConnectToServer ( type, serverName, riid, ppv ) ); break; case HSMCONN_TYPE_RESOURCE: { CComPtr< IFsaServer > pFsaServer; GUID serverGuid; serverGuid = HsmConnTypeToGuid(type); WsbAffirmHr ( HsmConnectFromId ( HSMCONN_TYPE_FSA, serverGuid, IID_IFsaServer, (void**)&pFsaServer ) ); CComPtr< IFsaResource > pFsaResource; WsbAffirmHr ( pFsaServer->FindResourceById ( rguid, &pFsaResource ) ); WsbAffirmHr ( pFsaResource->QueryInterface ( riid, ppv ) ); } break; default: WsbThrow ( E_INVALIDARG ); } } WsbCatch ( hr ) WsbTraceOut ( L"HsmConnectFromId", L"HRESULT = %ls, *ppv = %ls", WsbHrAsString ( hr ), WsbPtrToPtrAsString ( ppv ) ); return ( hr ); } HRESULT HsmPublish ( IN HSMCONN_TYPE type, IN const OLECHAR * Name, IN REFGUID rguidObjectId, IN const OLECHAR * Server, IN REFGUID rguid ) /*++ Routine Description: Publish (i.e. store) information about the service/object in Directory Services. Arguments: type - The type of service/object. Name - Name (possibly preceded by a subpath) of the Service/Object. rguidObjectId - The ID that the object is known by. Server - The server (computer name) on which the service actually exists. For resources, this will be NULL since it is implicit in the FSA specified by rguid. rguid - For resources, the ID of the FSA. For services, the CLSID of the service's class factory ie. CLSID_HsmServer. Return Value: S_OK - Connection made, Success. E_POINTER - Name or Server is not a valid pointer. E_OUTOFMEMORY - Low memory condition prevented connection. --*/ { HRESULT hr = S_OK; WsbTraceIn ( L"HsmPublish", L"type = '%ls', Name = '%ls', rguidObjectId = '%ls', Server = '%ls', rguid = '%ls'", HsmConnTypeAsString ( type ), Name, WsbStringCopy ( WsbGuidAsString ( rguidObjectId ) ), Server, WsbStringCopy ( WsbGuidAsString ( rguid ) ) ); WsbTrace(OLESTR("HsmPublish: UseDirectoryServices = %ls\n"), WsbBoolAsString(UseDirectoryServices)); try { // // Ensure parameters are valid // WsbAssert ( 0 != Name, E_POINTER ); WsbAssert ( ( HSMCONN_TYPE_RESOURCE == type ) || ( 0 != Server ), E_POINTER ); // Perhaps we should output a log event if the DS is not writable // We now only publish the Engine service. Perhaps in the future we // will publish additional information if (HSMCONN_TYPE_HSM == type && UseDirectoryServices && DSIsWritable) { CWsbStringPtr pathToName; try { DWORD aSet; CWsbStringPtr guidString(rguidObjectId); HRESULT hrGetNode; CComPtr pComputer; CComPtr pDispatch; CComPtr pDirObj; CComPtr pNode; // Save the node name for the event log message pathToName = Name; pathToName.Append("\\"); pathToName.Append(RsNodeName); // Get the computer node WsbAffirmHr(HsmGetComputerNode(Name, &pComputer)); // See if we're already published hrGetNode = HsmGetDsChild(pComputer, RsNodeName, IID_IADs, (void**)&pNode); // If not, add our node if (HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT) == hrGetNode) { CWsbBstrPtr relPath(RsNodeName); relPath.Prepend(CNEqual); WsbAffirmHr(pComputer->Create(RsNodeType, relPath, &pDispatch)); WsbAffirmHr(pDispatch->QueryInterface(IID_IADs, (void**)&pNode)); // Force info out of cache WsbAffirmHr(pNode->SetInfo()); } else { WsbAffirmHr(hrGetNode); } // Set the GUID & ServiceBinding values adsValue[0].dwType = ADSTYPE_CASE_IGNORE_STRING; adsValue[0].CaseIgnoreString = (WCHAR*)guidString; aaInfo[0].pszAttrName = GuidAttrName; aaInfo[0].dwControlCode = ADS_ATTR_UPDATE; aaInfo[0].dwADsType = ADSTYPE_CASE_IGNORE_STRING; aaInfo[0].pADsValues = &adsValue[0]; aaInfo[0].dwNumValues = 1; adsValue[1].dwType = ADSTYPE_CASE_IGNORE_STRING; adsValue[1].CaseIgnoreString = ServiceBindValue; aaInfo[1].pszAttrName = ServiceBindAttrName; aaInfo[1].dwControlCode = ADS_ATTR_UPDATE; aaInfo[1].dwADsType = ADSTYPE_CASE_IGNORE_STRING; aaInfo[1].pADsValues = &adsValue[1]; aaInfo[1].dwNumValues = 1; WsbAffirmHr(pNode->QueryInterface(IID_IDirectoryObject, (void**)&pDirObj)); WsbAffirmHr(pDirObj->SetObjectAttributes(aaInfo, 2, &aSet)); WsbTrace(L"HsmPublish: after SetObjectAttributes, aSet = %ld\n", aSet); WsbLogEvent(WSB_MESSAGE_PUBLISH_IN_DS, 0, NULL, static_cast(pathToName), NULL); } WsbCatchAndDo(hr, WsbLogEvent(WSB_MESSAGE_PUBLISH_FAILED, 0, NULL, static_cast(pathToName), NULL); hr = S_OK; // Don't stop service just for this ) } } WsbCatch ( hr ) WsbTraceOut ( L"HsmPublish", L"HRESULT = %ls", WsbHrAsString ( hr ) ); return ( hr ); } // GetDSState - determine if we're using Directory Services or not static void GetDSState(void) { BOOL CheckForDS = TRUE; DOMAIN_CONTROLLER_INFO * dc_info; DWORD size; OLECHAR vstr[32]; DWORD status; UseDirectoryServices = FALSE; // Should we attempt to use directory services in this module? // (Setting the registry value to "0" allows us to avoid Directory // Services completely if (S_OK == WsbGetRegistryValueString(NULL, REG_PATH, REG_USE_DS, vstr, 32, &size)) { OLECHAR *stop; ULONG value; value = wcstoul(vstr, &stop, 10 ); if (0 == value) { CheckForDS = FALSE; } } // Get the account domain name WsbGetAccountDomainName(DomainName, MAX_COMPUTERNAME_LENGTH ); #if defined(HSMCONN_DEBUG) swprintf(dbg_string, L"Account domain name = <%ls>\n", DomainName); OutputDebugString(dbg_string); #endif // Check if Directory Services is available if (CheckForDS) { status = DsGetDcName(NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED | DS_IS_FLAT_NAME | DS_RETURN_FLAT_NAME, &dc_info); #if defined(HSMCONN_DEBUG) swprintf(dbg_string, L"DsGetDcName status = %d\n", status); OutputDebugString(dbg_string); #endif if (NO_ERROR == status) { #if defined(HSMCONN_DEBUG) swprintf(dbg_string, L"dc_info->DomainName = <%ls>\n", dc_info->DomainName); OutputDebugString(dbg_string); #endif if (dc_info->Flags & DS_DS_FLAG) { wcscpy(DomainName, dc_info->DomainName); UseDirectoryServices = TRUE; if (dc_info->Flags & DS_WRITABLE_FLAG) { DSIsWritable = TRUE; } } NetApiBufferFree(dc_info); } } #if defined(HSMCONN_DEBUG) swprintf(dbg_string, L"dHsmConn - GetDSState: UseDirectoryServices = %ls\n", WsbBoolAsString(UseDirectoryServices)); OutputDebugString(dbg_string); #endif } } // extern "C"