//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1998. // // File: N C A C S . C P P // // Contents: Installation support for ACS service // // Notes: // // Author: RameshPa 02/12/98 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "ncxbase.h" #include "ncerror.h" #include "ncreg.h" #include "ncacs.h" #include "ncsvc.h" #include "netoc.h" #include "ncnetcfg.h" #include "resource.h" #include #include #include extern const WCHAR c_szSvcRsvp[]; static const WCHAR c_szTcpIp[] = L"TcpIp"; static const WCHAR c_szAfd[] = L"Afd"; static const WCHAR c_szAcsService[] = L"AcsService"; static const WCHAR c_szRegKeyRsvpParams[] = L"System\\CurrentControlSet\\Services\\RSVP\\Parameters\\"; static const WCHAR c_szRegKeyRsvpSubnet1[] = L"System\\CurrentControlSet\\Services\\RSVP\\Parameters\\Subnet\\Subnet1\\"; static const WCHAR c_szRegKeyRsvpSubnet[] = L"System\\CurrentControlSet\\Services\\RSVP\\Parameters\\Subnet\\"; static const WCHAR c_szRegKeyRsvpAdapters[]= L"System\\CurrentControlSet\\Services\\RSVP\\Parameters\\Adapters\\"; static const WCHAR c_szRegKeyRsvpPcmConfig[]= L"System\\CurrentControlSet\\Services\\RSVP\\PCM Config\\"; static const WCHAR c_szRegKeyRsvpMsidlpm[] = L"System\\CurrentControlSet\\Services\\RSVP\\MSIDLPM\\"; //$ REVIEW : RameshPa : 02/13/98 : Is this defined anywhere? const DWORD dwKilo = 1024; const DWORD dwMega = (1024 * dwKilo); const DWORD dwGiga = (1024 * dwMega); static const WCHAR c_szIpHlpApiDllName[] = L"IpHlpApi"; static const CHAR c_szaGetIpAddrTable[] = "GetIpAddrTable"; typedef DWORD (*GETIPADDRTABLE)( OUT PMIB_IPADDRTABLE pIpAddrTable, IN OUT PDWORD pdwSize, IN BOOL bOrder); struct ACS_SUBNET_REG_DATA { DWORD dwSubnetIpAddress; // This is in host order DWORD dwDSBMPriority; DWORD dwMaxRSVPBandwidth; DWORD dwMaxTotalPeakRate; DWORD dwMaxTokenBucketRatePerFlow; DWORD dwMaxPeakRatePerFlow; DWORD dwIAmDsbmRefreshInterval; DWORD dwDSBMDeadInterval; BOOL fRunAsDSBM; }; // Subnet registry keys // static const WCHAR c_szRunAsDSBM[] = L"Run as DSBM"; static const WCHAR c_szSubnetIPAddress[] = L"Subnet IP Address"; static const WCHAR c_szMaxPeakRate[] = L"Maximum peak rate per flow"; static const WCHAR c_szMaxRSVPBandwidth[] = L"Maximum RSVP bandwidth"; static const WCHAR c_szMaxTokenBucket[] = L"Maximum token bucket rate per flow"; static const WCHAR c_szMaxTotalPeakRate[] = L"Maximum total peak rate"; static const WCHAR c_szIAmDsbmRefresh[] = L"I_AM_DSBM Refresh Interval"; static const WCHAR c_szDSBMDeadInterval[] = L"DSBM Dead Interval"; static const WCHAR c_szDSBMPriority[] = L"DSBM Priority"; // Default general property sheet values // const BOOL c_fRunAsDSBMDef = TRUE; // Default subnet values // const DWORD c_dwIpAddressDef = 0; static const WCHAR c_szIpAddressDef[] = L"0.0.0.0"; const DWORD c_dwMaxPeakRateDef = 0xFFFFFFFF; const DWORD c_dwMaxRSVPBandwidthDef = 0; const DWORD c_dwMaxTokenBucketDef = 0xFFFFFFFF; const DWORD c_dwMaxTotalPeakRateDef = 0xFFFFFFFF; const DWORD c_dwIAmDsbmRefreshDef = 5; const DWORD c_dwDSBMDeadIntervalDef = 15; const DWORD c_dwDSBMPriorityDef = 4; // General values // 127.0.0.0, host order // const DWORD c_dwLocalSubnet = 0x7f000000; const DWORD c_dwNullSubnet = 0x00000000; static const VALUETABLE c_avtAcsSubnet[] = { {c_szSubnetIPAddress, REG_IP, offsetof(ACS_SUBNET_REG_DATA, dwSubnetIpAddress), (BYTE*)(&c_szIpAddressDef)}, {c_szMaxPeakRate, REG_DWORD, offsetof(ACS_SUBNET_REG_DATA, dwMaxPeakRatePerFlow), (BYTE*)(&c_dwMaxPeakRateDef)}, {c_szMaxRSVPBandwidth, REG_DWORD, offsetof(ACS_SUBNET_REG_DATA, dwMaxRSVPBandwidth), (BYTE*)(&c_dwMaxRSVPBandwidthDef)}, {c_szMaxTokenBucket, REG_DWORD, offsetof(ACS_SUBNET_REG_DATA, dwMaxTokenBucketRatePerFlow), (BYTE*)(&c_dwMaxTokenBucketDef)}, {c_szMaxTotalPeakRate, REG_DWORD, offsetof(ACS_SUBNET_REG_DATA, dwMaxTotalPeakRate), (BYTE*)(&c_dwMaxTotalPeakRateDef)}, {c_szIAmDsbmRefresh, REG_DWORD, offsetof(ACS_SUBNET_REG_DATA, dwIAmDsbmRefreshInterval), (BYTE*)(&c_dwIAmDsbmRefreshDef)}, {c_szDSBMDeadInterval, REG_DWORD, offsetof(ACS_SUBNET_REG_DATA, dwDSBMDeadInterval), (BYTE*)(&c_dwDSBMDeadIntervalDef)}, {c_szDSBMPriority, REG_DWORD, offsetof(ACS_SUBNET_REG_DATA, dwDSBMPriority), (BYTE*)(&c_dwDSBMPriorityDef)}, {c_szRunAsDSBM, REG_BOOL, offsetof(ACS_SUBNET_REG_DATA, fRunAsDSBM), (BYTE*) &c_fRunAsDSBMDef}, }; //+--------------------------------------------------------------------------- // // Function: OpenPolicy // // Purpose: This routine opens the policy object on the local computer // // Arguments: PolicyHandle - Pointer to the opended handle // // Returns: ERROR_SUCCESS if successful, Win32 error otherwise. // // Notes: The retruned PolicyHandle must be closed by the caller // DWORD OpenPolicy( PLSA_HANDLE PolicyHandle ) { NTSTATUS Status; DWORD Error; LSA_OBJECT_ATTRIBUTES ObjectAttributes; SECURITY_QUALITY_OF_SERVICE QualityOfService; QualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); QualityOfService.ImpersonationLevel = SecurityImpersonation; QualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; QualityOfService.EffectiveOnly = FALSE; // // The two fields that must be set are length and the quality of service. // ObjectAttributes.Length = sizeof(LSA_OBJECT_ATTRIBUTES); ObjectAttributes.RootDirectory = NULL; ObjectAttributes.ObjectName = NULL; ObjectAttributes.Attributes = 0; ObjectAttributes.SecurityDescriptor = NULL; ObjectAttributes.SecurityQualityOfService = &QualityOfService; // // Attempt to open the policy for all access on the local machine // Status = LsaOpenPolicy( NULL, &ObjectAttributes, POLICY_ALL_ACCESS, PolicyHandle ); Error = LsaNtStatusToWinError(Status); return(Error); } //+--------------------------------------------------------------------------- // // Function: InitLsaString // // Purpose: This routine intializes LSA_UNICODE_STRING given an UNICODE string0 // // Arguments: LsaString // String // // Returns: // // Notes: // void InitLsaString( PLSA_UNICODE_STRING LsaString, PWSTR String ) { DWORD StringLength; if (String == NULL) { LsaString->Buffer = NULL; LsaString->Length = 0; LsaString->MaximumLength = 0; return; } StringLength = wcslen(String); LsaString->Buffer = String; LsaString->Length = (USHORT) StringLength * sizeof(WCHAR); LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR); } //+--------------------------------------------------------------------------- // // Function: InitLsaString // // Purpose: This routine intializes LSA_UNICODE_STRING given an UNICODE string0 // // Arguments: LsaString // String // // Returns: // // Notes: // PSID GetAccountSid( LSA_HANDLE PolicyHandle, PWSTR AccountName ) { DWORD NewSidLength; DWORD SubAuthorityCount; PSID Sid; PSID DomainSid; NTSTATUS Status; PLSA_TRANSLATED_SID TranslatedSid; PLSA_REFERENCED_DOMAIN_LIST Domains; LSA_UNICODE_STRING AccountString; // // Convert the string to a LSA_UNICODE_STRING // InitLsaString( &AccountString, AccountName ); // // Call the LSA to lookup the name // Status = LsaLookupNames( PolicyHandle, 1, &AccountString, &Domains, &TranslatedSid ); if (!SUCCEEDED(Status)) return(NULL); // // Build a SID from the Domain SID and account RID // DomainSid = Domains->Domains[TranslatedSid->DomainIndex].Sid; // // Compute the length of the new SID. This is the length required for the // number of subauthorities in the domain sid plus one for the user RID. // SubAuthorityCount = *GetSidSubAuthorityCount(DomainSid); NewSidLength = GetSidLengthRequired( (UCHAR) (SubAuthorityCount + 1) ); Sid = LocalAlloc(0,NewSidLength); if (Sid == NULL) { LsaFreeMemory(Domains); LsaFreeMemory(TranslatedSid); return(NULL); } // // Build the SID by copying the domain SID and, increasing the sub- // authority count in the new sid by one, and setting the last // subauthority to be the relative id of the user. // CopySid( NewSidLength, Sid, DomainSid ); *GetSidSubAuthorityCount(Sid) = (UCHAR) SubAuthorityCount + 1; *GetSidSubAuthority(Sid, SubAuthorityCount) = TranslatedSid->RelativeId; LsaFreeMemory(Domains); LsaFreeMemory(TranslatedSid); return(Sid); } //+--------------------------------------------------------------------------- // // Function: AddUserRightToAccount // // Purpose: This routine grants the SE_TCB_NAME right to the specified user // account on the local machine // // Arguments: PolicyHandle // AccountName // // Returns: ERROR_SUCCESS if the right was granted successfully // Win32 error otherwise // // Notes: // DWORD AddUserRightToAccount( PWSTR AccountName ) { DWORD Error; NTSTATUS Status; PSID AccountSid = NULL; LSA_HANDLE PolicyHandle; LSA_UNICODE_STRING UserRightString; // Get a LSA policy handle to manipulate user rights Error = OpenPolicy ( &PolicyHandle ); if ( Error ) return Error; // Get the SID for the account AccountSid = GetAccountSid( PolicyHandle, AccountName ); if (AccountSid == NULL) { LsaClose ( &PolicyHandle ); return(ERROR_NOT_ENOUGH_MEMORY); } // // Create a LSA_UNICODE_STRING for the right name // InitLsaString( &UserRightString, SE_TCB_NAME ); // Grant the right Status = LsaAddAccountRights( PolicyHandle, AccountSid, &UserRightString, 1 ); Error = LsaNtStatusToWinError(Status); LocalFree( AccountSid ); LsaClose ( &PolicyHandle ); return(Error); } //+--------------------------------------------------------------------------- // // Function: AddUserRightToAccount // // Purpose: This routine removes the SE_TCB_NAME right to the specified user // account on the local machine // // Arguments: PolicyHandle // AccountName // // Returns: ERROR_SUCCESS if the right was rmoved successfully // Win32 error otherwise // // Notes: // DWORD RemoveUserRightFromAccount( PWSTR AccountName ) { NTSTATUS Status; DWORD Error; PSID AccountSid; LSA_HANDLE PolicyHandle; LSA_UNICODE_STRING UserRightString; // Get a LSA policy handle to manipulate user rights Error = OpenPolicy ( &PolicyHandle ); if ( Error ) return Error; AccountSid = GetAccountSid( PolicyHandle, AccountName ); if (AccountSid == NULL) { LsaClose ( &PolicyHandle ); return(ERROR_NOT_ENOUGH_MEMORY); } // // Create a LSA_UNICODE_STRING for the right name // InitLsaString( &UserRightString, SE_TCB_NAME ); Status = LsaRemoveAccountRights( PolicyHandle, AccountSid, FALSE, // don't remove all rights &UserRightString, 1 ); Error = LsaNtStatusToWinError(Status); LocalFree(AccountSid); LsaClose ( &PolicyHandle ); return(Error); } //+--------------------------------------------------------------------------- // // Function: HrGetAcsServiceAccountName // // Purpose: This routine returns the AcsService account name in the // DomainName\UserName format. DomainName is obtained from // the current logon domain. // // Arguments: lpwNtAccountName - Buffer to return the account name. // // Returns: S_OK If the account name was generated // Win32 error otherwise // // Notes: // HRESULT HrGetAcsServiceAccountName ( PWSTR lpwNtAccountName ) { DWORD dwErr; HRESULT hr; PWSTR lpwDomain = NULL; PWSTR lpwDcName = NULL; LPBYTE lpbUserInfo = NULL; NETSETUP_JOIN_STATUS js; lpwNtAccountName[0] = 0; // Get the name of the DC for the logged on domain dwErr = NetGetDCName ( NULL, NULL, (LPBYTE *) &lpwDcName ); if ( dwErr ) { hr = HRESULT_FROM_WIN32(dwErr); goto Exit; } // Next get user info to verify that there is a user // account for AcsService dwErr = NetUserGetInfo ( lpwDcName, c_szAcsService, 2, &lpbUserInfo ); if ( dwErr ) { hr = HRESULT_FROM_WIN32(dwErr); goto Exit; } // Find out the name of the domain into which this compter // is currently logged on to dwErr = NetGetJoinInformation ( NULL, &lpwDomain, &js ); if ( dwErr ) { hr = HRESULT_FROM_WIN32(dwErr); goto Exit; } if ( js != NetSetupDomainName ) { hr = NETCFG_E_NOT_JOINED; goto Exit; } // Generate the account name by concatenating domain name and "AcsService" wcscpy ( lpwNtAccountName, lpwDomain ); wcscat ( lpwNtAccountName, L"\\" ); wcscat ( lpwNtAccountName, c_szAcsService ); hr = S_OK; Exit: if ( lpwDcName ) NetApiBufferFree ( lpwDcName ); if ( lpbUserInfo ) NetApiBufferFree ( lpbUserInfo ); if ( lpwDomain ) NetApiBufferFree ( lpwDomain ); TraceError("HrGetAcsServiceAccountName", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrSetAcsServiceRights // // Purpose: This routine adds the AcsService account to the administrators group // on the local computer and grants SE_TCB_NAME right also // // Arguments: // // Returns: S_OK Success // Win32 error otherwise // // Notes: // HRESULT HrSetAcsServiceRights( ) { DWORD dwErr; HRESULT hr; WCHAR szAcsUserName[UNLEN+GNLEN+2]; PWSTR lpwAcsUserName; LOCALGROUP_MEMBERS_INFO_3 localgroup_members; // First get the user name of AcsService in the format // DomainName\UserName hr = ::HrGetAcsServiceAccountName ( szAcsUserName ); if ( hr ) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_ACCOUNT_NAME); goto Exit; } if ( !szAcsUserName[0] ) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_ACCOUNT_NAME); goto Exit; } // Add AcsService account to be a local administrator localgroup_members.lgrmi3_domainandname = szAcsUserName; dwErr = NetLocalGroupAddMembers( NULL, // PDC name L"Administrators", // group name 3, // passing in name (LPBYTE)&localgroup_members, // Buffer 1 ); // count passed in if ( dwErr ) { if ( dwErr == ERROR_MEMBER_IN_ALIAS ) { hr = S_OK; dwErr = 0; } else { hr = HRESULT_FROM_WIN32(dwErr); goto Exit; } } // Grant SE_TCB_NAME "Act as part of Operating system" right to AcsService dwErr = AddUserRightToAccount( szAcsUserName ); if ( dwErr ) { hr = HRESULT_FROM_WIN32( dwErr ); goto Exit; } hr = S_OK; Exit: TraceError ( "HrSetAcsServiceRights", hr ); return hr; } //+--------------------------------------------------------------------------- // // Function: HrRemoveAcsServiceRights // // Purpose: This routine removes the AcsService account from the administrators group // on the local computer and removes SE_TCB_NAME right. // // Arguments: // // Returns: S_OK Success // Win32 error otherwise // // Notes: // HRESULT HrRemoveAcsServiceRights( ) { DWORD dwErr; HRESULT hr; WCHAR szAcsUserName[UNLEN+GNLEN+2]; LOCALGROUP_MEMBERS_INFO_3 localgroup_members; // First get the user name of AcsService in the format // DomainName\UserName hr = ::HrGetAcsServiceAccountName ( szAcsUserName ); if ( hr ) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_ACCOUNT_NAME); goto Exit; } if ( !szAcsUserName[0] ) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_ACCOUNT_NAME); goto Exit; } // Remove AcsService account to be a local administrator localgroup_members.lgrmi3_domainandname = szAcsUserName; dwErr = NetLocalGroupDelMembers( NULL, // PDC name L"Administrators", // group name 3, // passing in name (LPBYTE)&localgroup_members, // Buffer 1 ); // count passed in if ( dwErr ) { if ( dwErr == ERROR_MEMBER_NOT_IN_ALIAS ) { hr = S_OK; dwErr = 0; } else { hr = HRESULT_FROM_WIN32(dwErr); goto Exit; } } // Grant "Act as part of Operating system" right to AcsService dwErr = RemoveUserRightFromAccount( szAcsUserName ); if ( dwErr ) { hr = HRESULT_FROM_WIN32( dwErr ); goto Exit; } hr = S_OK; Exit: TraceError ( "HrRemoveAcsServiceRights", hr ); return hr; } //+--------------------------------------------------------------------------- // // Function: HrGetIpAddrTable // // Purpose: Gets the address table of the subnets that machine can see // // Arguments: ppmiat - Where to return the allocated address table // // Returns: S_OK if successful, Win32 error otherwise. // // Notes: The result must be freed by the caller // HRESULT HrGetIpAddrTable(MIB_IPADDRTABLE** ppmiat) { HRESULT hr = S_OK; DWORD dwErr = NO_ERROR; HMODULE hIpHelpApi = NULL; GETIPADDRTABLE pfnGetIpAddrTable = NULL; AssertSz(ppmiat , "HrGetIpAddrTable doesn't have a ppmiat"); // Make sure we have our function loaded // hr = ::HrLoadLibAndGetProc( c_szIpHlpApiDllName, c_szaGetIpAddrTable, &hIpHelpApi, (FARPROC*)&pfnGetIpAddrTable); if (SUCCEEDED(hr)) { DWORD dwAddrCount = 0; AssertSz(pfnGetIpAddrTable, "We should have a pfnGetIpAddrTable"); // Find out how big a buffer we need. // dwErr = pfnGetIpAddrTable(*ppmiat, &dwAddrCount, FALSE); hr = HRESULT_FROM_WIN32(dwErr); // Allocate the buffer of the correct size // if ((NO_ERROR == dwErr) || (ERROR_INSUFFICIENT_BUFFER == dwErr)) { UINT cbTable = 0; // Create the buffer // cbTable = (sizeof(MIB_IPADDRTABLE) + (sizeof(MIB_IPADDRROW) * (dwAddrCount))); *ppmiat = reinterpret_cast(new BYTE [cbTable]); // Try a second time with the correct buffer // dwErr = pfnGetIpAddrTable(*ppmiat, &dwAddrCount, FALSE); hr = HRESULT_FROM_WIN32(dwErr); } // Unload the DLL // (VOID)::FreeLibrary(hIpHelpApi); } TraceErrorOptional("HrGetIpAddrTable", hr, (HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) == hr)); return hr; } //+--------------------------------------------------------------------------- // // Function: HrFindFirstSubnet // // Purpose: Finds the first available subnet on the system to be used as // the default entry in the registry. If a subnet cannot be found // 000.000.000.000 is used. // // Arguments: pdwSubnet - Where to return the subnet // // Returns: Error code // // Notes: // HRESULT HrFindFirstSubnet(DWORD* pdwSubnet) { HRESULT hr = S_OK; MIB_IPADDRTABLE* ppmiat = NULL; // Get our list of address entries // hr = HrGetIpAddrTable(&ppmiat); if (SUCCEEDED(hr)) { MIB_IPADDRROW* pmiarTemp = ppmiat->table; DWORD dwIpAddrCount = ppmiat->dwNumEntries; DWORD dwSubnet = 0x0; while (dwIpAddrCount--) { // Find out what the sub net is // dwSubnet = (pmiarTemp->dwAddr & pmiarTemp->dwMask); // The APIs return the value in network order, and we want to // store the data in host order, so we have to convert the // address // dwSubnet = ntohl(dwSubnet); // Don't add invalid subnets to the list // if ((c_dwLocalSubnet != dwSubnet) && (c_dwNullSubnet != dwSubnet)) { // We found one!! // *pdwSubnet = dwSubnet; break; } // Look at the next entry // pmiarTemp++; } // Free the allocated memory // delete ppmiat; } TraceError("HrFindFirstSubnet", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrWriteAcsSubnetDataToReg // // Purpose: Writes out the subnet information to the registry // // Arguments: pasrdSubnet - The data that has to be written // // Returns: Error code // // Notes: // HRESULT HrWriteAcsSubnetDataToReg(ACS_SUBNET_REG_DATA* pasrdSubnet) { HRESULT hr = S_OK; HKEY hkeySubnet = NULL; DWORD dwDisposition = 0x0; hr = ::HrRegCreateKeyEx( HKEY_LOCAL_MACHINE, c_szRegKeyRsvpSubnet, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeySubnet, &dwDisposition); if (SUCCEEDED(hr)) { // Write out the parameters // hr = ::HrRegWriteValueTable( hkeySubnet, celems(c_avtAcsSubnet), c_avtAcsSubnet, reinterpret_cast(pasrdSubnet), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS); ::RegSafeCloseKey(hkeySubnet); } TraceError("HrWriteAcsSubnetDataToReg", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrWriteAcsRegistryData // // Purpose: Writes to the registry all of ACS's default parameters // // Arguments: pnocd - The option component information that is // needed to get an INetCfg instance // pasrdSubnet - The subnet information // palrdLog - The logging information // // Returns: Error code // // Notes: // HRESULT HrWriteAcsRegistryData( PNETOCDATA pnocd ) { HRESULT hr = S_OK; ACS_SUBNET_REG_DATA asrdSubnet = { 0 }; // See if we can find a subnet // hr = ::HrFindFirstSubnet(&(asrdSubnet.dwSubnetIpAddress)); if (SUCCEEDED(hr)) { // Default subnet values // asrdSubnet.dwDSBMPriority = c_dwDSBMPriorityDef; asrdSubnet.dwMaxPeakRatePerFlow = c_dwMaxPeakRateDef; asrdSubnet.dwMaxRSVPBandwidth = c_dwMaxRSVPBandwidthDef; asrdSubnet.dwMaxTokenBucketRatePerFlow = c_dwMaxTokenBucketDef; asrdSubnet.dwMaxTotalPeakRate = c_dwMaxTotalPeakRateDef; asrdSubnet.dwIAmDsbmRefreshInterval = c_dwIAmDsbmRefreshDef; asrdSubnet.dwDSBMDeadInterval = c_dwDSBMDeadIntervalDef; asrdSubnet.fRunAsDSBM = c_fRunAsDSBMDef; hr = ::HrWriteAcsSubnetDataToReg(&asrdSubnet); if (SUCCEEDED(hr)) { ::HrWriteAcsRegistryData(pnocd); } } TraceError("HrWriteAcsRegistryData", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrChangeRsvpService // // Purpose: Change some RSVP service parameters // // Arguments: szDisplayName - The new display name // dwStartType - The new start type // fStartService - If the service should be started // // Returns: Error code // // Notes: // HRESULT HrChangeRsvpService( const WCHAR* szDisplayName, DWORD dwStartType, BOOL fStartService) { HRESULT hr = S_OK; CServiceManager scm; CService svc; // Open the RSVP service with a lock on the service controller. // hr = scm.HrOpenService(&svc, c_szSvcRsvp, NO_LOCK); if (SUCCEEDED(hr)) { hr = scm.HrAddServiceDependency ( c_szSvcRsvp, c_szTcpIp ); if (SUCCEEDED(hr)) { hr = scm.HrAddServiceDependency ( c_szSvcRsvp, c_szAfd ); if (SUCCEEDED(hr)) { // Set the new start type // hr = svc.HrSetStartType(dwStartType); if (SUCCEEDED(hr)) { // Change the display name // hr = svc.HrSetDisplayName(szDisplayName); if (SUCCEEDED(hr) && fStartService) { // Unlock the Service Control Manager so that we can // start the service. // // scm.Unlock(); // Start up the service // hr = scm.HrStartServiceNoWait(c_szSvcRsvp); } } } } } TraceError("HrChangeRsvpService", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrInstallACS // // Purpose: Called when ACS service is being installed. Handles all of the // additional installation for ACS beyond that of the INF file. // // Arguments: // pnocd [in] Pointer to NETOC data. // // Returns: S_OK if successful, Win32 error otherwise. // // Notes: // HRESULT HrInstallACS(PNETOCDATA pnocd) { HRESULT hr = S_OK; #ifdef NEVER // For NT 5.0 beta 2, setting rights for AcsService user name will not be done as this // is introducing significant delay. // Make AcsService to be local admin and grant SE_TCB_NAME right hr = ::HrSetAcsServiceRights(); if (SUCCEEDED(hr)) { // Display a message box asking the user to change the logon name NcMsgBox( g_ocmData.hwnd, IDS_OC_CAPTION, IDS_OC_ACS_CHG_LOGON, MB_ICONSTOP | MB_OK); } #endif // NEVER // Ignoring any error from changing rights and continue with the // setup so that ACS will run in Resouce only mode. // Change the RSVP service parameters hr = ::HrChangeRsvpService( ::SzLoadIds(IDS_OC_ACS_SERVICE_NAME), SERVICE_AUTO_START, TRUE); TraceError("HrInstallACS", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrRemoveACS // // Purpose: Handles additional removal requirements for ACS Service // component. // // hwnd [in] Parent window for displaying UI. // poc [in] Pointer to optional component being installed. // // Returns: S_OK if successful, Win32 error otherwise. // // Notes: // HRESULT HrRemoveACS(PNETOCDATA pnocd) { HRESULT hr = S_OK; #ifdef NEVER // For NT 5.0 beta 2, Removing AcsService user right will not be done as this // is introducing significant delay. // Drop the membership from local admins and remove SE_TCB_NAME right (VOID)::HrRemoveAcsServiceRights (); #endif // NEVER // // Clean out the adapters and subnet reg keys (if present) // (VOID)::HrRegDeleteKeyTree(HKEY_LOCAL_MACHINE, c_szRegKeyRsvpAdapters); (VOID)::HrRegDeleteKeyTree(HKEY_LOCAL_MACHINE, c_szRegKeyRsvpSubnet1); (VOID)::HrRegDeleteKeyTree(HKEY_LOCAL_MACHINE, c_szRegKeyRsvpSubnet); // Put the name back the way it should be // (VOID)::HrChangeRsvpService( ::SzLoadIds(IDS_OC_RSVP_SERVICE_NAME), SERVICE_DEMAND_START, FALSE); TraceError("HrRemoveACS", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrOcExtACS // // Purpose: NetOC external message handler // // Arguments: // pnocd [] // uMsg [] // wParam [] // lParam [] // // Returns: // // Author: danielwe 17 Sep 1998 // // Notes: // HRESULT HrOcExtACS(PNETOCDATA pnocd, UINT uMsg, WPARAM wParam, LPARAM lParam) { HRESULT hr = S_OK; Assert(pnocd); switch (uMsg) { case NETOCM_POST_INSTALL: hr = HrOcAcsOnInstall(pnocd); break; case NETOCM_QUERY_CHANGE_SEL_STATE: hr = HrOcAcsOnQueryChangeSelState(pnocd, static_cast(wParam)); break; } TraceError("HrOcExtACS", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrOcAcsOnInstall // // Purpose: Called by optional components installer code to handle // additional installation requirements for ACS Server // // Arguments: // pnocd [in] Pointer to NETOC data // // Returns: S_OK if successful, Win32 error otherwise. // // Notes: // HRESULT HrOcAcsOnInstall(PNETOCDATA pnocd) { HRESULT hr = S_OK; if (IT_INSTALL == pnocd->eit) { hr = HrInstallACS(pnocd); } else if (IT_REMOVE == pnocd->eit) { hr = HrRemoveACS(pnocd); } TraceError("HrOcAcsOnInstall", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrOcAcsOnQueryChangeSelState // // Purpose: Handles the request of the OC framework of whether or not // the user should be allowed to install ACS on this host. // // Arguments: // pnocd [in] NetOC Data // fShowUi [in] TRUE if UI should be shown, FALSE if not // // Returns: S_OK if install is allowed, S_FALSE if not, Win32 error // otherwise // // Author: rameshpa 23 April 1998 // // Notes: // HRESULT HrOcAcsOnQueryChangeSelState(PNETOCDATA pnocd, BOOL fShowUi) { HRESULT hr = S_OK; #ifdef NEVER // For NT 5.0 beta 2, checking for user name will not be done as this // is introducing significant delay. WCHAR szAcsUserName[UNLEN+GNLEN+2]; Assert(pnocd); Assert(g_ocmData.hwnd); // See if AcsService account exists in this domain or not hr = HrGetAcsServiceAccountName(szAcsUserName); if ( FAILED(hr) || !szAcsUserName[0] ) { if (fShowUi) { NcMsgBox( g_ocmData.hwnd, IDS_OC_CAPTION, IDS_OC_NO_ACS_USER_ACCOUNT, MB_ICONSTOP | MB_OK); } // Allow ACS setup to continue, as ACS will default to // Resource only hr = S_FALSE; } TraceError("HrOcAcsOnQueryChangeSelState", hr); #endif // NEVER return hr; }