mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1208 lines
32 KiB
1208 lines
32 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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 <iphlpapi.h>
|
|
#include <winsock2.h>
|
|
#include <ntsecapi.h>
|
|
|
|
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<MIB_IPADDRTABLE*>(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<BYTE*>(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<BOOL>(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;
|
|
}
|
|
|