871 lines
24 KiB
C++
871 lines
24 KiB
C++
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
service.c
|
||
|
||
Abstract:
|
||
|
||
This file provides access to the service control
|
||
manager for starting, stopping, adding, and removing
|
||
services.
|
||
|
||
Environment:
|
||
|
||
WIN32 User Mode
|
||
|
||
Author:
|
||
|
||
Wesley Witt (wesw) 17-Feb-1996
|
||
|
||
--*/
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
|
||
#include "faxocm.h"
|
||
|
||
#include <ntsecapi.h>
|
||
#include <lm.h>
|
||
|
||
|
||
|
||
NTSTATUS
|
||
OpenPolicy(
|
||
LPWSTR ServerName, // machine to open policy on (Unicode)
|
||
DWORD DesiredAccess, // desired access to policy
|
||
PLSA_HANDLE PolicyHandle // resultant policy handle
|
||
);
|
||
|
||
BOOL
|
||
GetAccountSid(
|
||
LPWSTR SystemName, // where to lookup account
|
||
LPWSTR AccountName, // account of interest
|
||
PSID *Sid // resultant buffer containing SID
|
||
);
|
||
|
||
NTSTATUS
|
||
SetPrivilegeOnAccount(
|
||
LSA_HANDLE PolicyHandle, // open policy handle
|
||
PSID AccountSid, // SID to grant privilege to
|
||
LPWSTR PrivilegeName, // privilege to grant (Unicode)
|
||
BOOL bEnable // enable or disable
|
||
);
|
||
|
||
void
|
||
InitLsaString(
|
||
PLSA_UNICODE_STRING LsaString, // destination
|
||
LPWSTR String // source (Unicode)
|
||
);
|
||
|
||
void
|
||
DisplayNtStatus(
|
||
LPSTR szAPI, // pointer to function name (ANSI)
|
||
NTSTATUS Status // NTSTATUS error value
|
||
);
|
||
|
||
void
|
||
DisplayWinError(
|
||
LPSTR szAPI, // pointer to function name (ANSI)
|
||
DWORD WinError // DWORD WinError
|
||
);
|
||
|
||
#define RTN_OK 0
|
||
#define RTN_USAGE 1
|
||
#define RTN_ERROR 13
|
||
|
||
//
|
||
// If you have the ddk, include ntstatus.h.
|
||
//
|
||
#ifndef STATUS_SUCCESS
|
||
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
|
||
#endif
|
||
|
||
|
||
BOOL
|
||
GetDefaultDomainName(
|
||
LPWSTR DomainName
|
||
)
|
||
{
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
NTSTATUS NtStatus;
|
||
DWORD err = 0;
|
||
LSA_HANDLE LsaPolicyHandle = NULL;
|
||
PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo = NULL;
|
||
|
||
|
||
//
|
||
// Open a handle to the local machine's LSA policy object.
|
||
//
|
||
|
||
InitializeObjectAttributes( &ObjectAttributes, // object attributes
|
||
NULL, // name
|
||
0L, // attributes
|
||
NULL, // root directory
|
||
NULL ); // security descriptor
|
||
|
||
NtStatus = LsaOpenPolicy( NULL, // system name
|
||
&ObjectAttributes, // object attributes
|
||
POLICY_EXECUTE, // access mask
|
||
&LsaPolicyHandle ); // policy handle
|
||
|
||
if( !NT_SUCCESS( NtStatus ) )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Query the domain information from the policy object.
|
||
//
|
||
NtStatus = LsaQueryInformationPolicy( LsaPolicyHandle,
|
||
PolicyAccountDomainInformation,
|
||
(PVOID *) &DomainInfo );
|
||
|
||
if (!NT_SUCCESS(NtStatus))
|
||
{
|
||
LsaClose(LsaPolicyHandle);
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
(void) LsaClose(LsaPolicyHandle);
|
||
|
||
//
|
||
// Copy the domain name into our cache, and
|
||
//
|
||
|
||
CopyMemory( DomainName,
|
||
DomainInfo->DomainName.Buffer,
|
||
DomainInfo->DomainName.Length );
|
||
|
||
//
|
||
// Null terminate it appropriately
|
||
//
|
||
|
||
DomainName[DomainInfo->DomainName.Length / sizeof(WCHAR)] = L'\0';
|
||
|
||
//
|
||
// Clean up
|
||
//
|
||
LsaFreeMemory( (PVOID)DomainInfo );
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
LPWSTR
|
||
GetMachineName(
|
||
LPWSTR AccountName
|
||
)
|
||
{
|
||
LSA_HANDLE PolicyHandle = NULL;
|
||
WCHAR DomainName[128];
|
||
WCHAR LocalComputerName[128];
|
||
LPWSTR MachineName = NULL;
|
||
LPWSTR p;
|
||
LPWSTR DCName = NULL;
|
||
NET_API_STATUS NetStatus;
|
||
UNICODE_STRING NameStrings;
|
||
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL;
|
||
PLSA_TRANSLATED_SID LsaSids = NULL;
|
||
PUSER_MODALS_INFO_1 Modals = NULL;
|
||
DWORD Size;
|
||
NTSTATUS Status;
|
||
|
||
|
||
//
|
||
// get the domain name
|
||
//
|
||
|
||
p = wcschr( AccountName, L'\\' );
|
||
if (p) {
|
||
*p = 0;
|
||
wcscpy( DomainName, AccountName );
|
||
*p = L'\\';
|
||
} else {
|
||
wcscpy( DomainName, AccountName );
|
||
}
|
||
|
||
//
|
||
// Open the policy on the target machine.
|
||
//
|
||
Status = OpenPolicy(
|
||
NULL,
|
||
POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
|
||
&PolicyHandle
|
||
);
|
||
if (Status != STATUS_SUCCESS) {
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// lookup the domain name for the account
|
||
//
|
||
|
||
InitLsaString( &NameStrings, AccountName );
|
||
|
||
Status = LsaLookupNames(
|
||
PolicyHandle,
|
||
1,
|
||
&NameStrings,
|
||
&ReferencedDomains,
|
||
&LsaSids
|
||
);
|
||
if (Status != STATUS_SUCCESS) {
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// get the local computer name
|
||
//
|
||
|
||
Size = sizeof(LocalComputerName);
|
||
if (!GetComputerName( LocalComputerName, &Size )) {
|
||
goto exit;
|
||
}
|
||
|
||
//
|
||
// see if we are tring to set a local account
|
||
//
|
||
|
||
if (wcscmp( LocalComputerName, ReferencedDomains->Domains->Name.Buffer ) != 0) {
|
||
|
||
//
|
||
// see what part of the domain we are attempting to set
|
||
//
|
||
|
||
NetStatus = NetUserModalsGet( NULL, 1, (LPBYTE*) &Modals );
|
||
if (NetStatus != NERR_Success) {
|
||
goto exit;
|
||
}
|
||
|
||
if (Modals->usrmod1_role != UAS_ROLE_PRIMARY) {
|
||
|
||
//
|
||
// we know we are remote, so get the real dc name
|
||
//
|
||
|
||
NetStatus = NetGetDCName( NULL, DomainName, (LPBYTE*) &DCName );
|
||
if (NetStatus != NERR_Success) {
|
||
goto exit;
|
||
}
|
||
|
||
MachineName = StringDup( DCName );
|
||
|
||
}
|
||
}
|
||
|
||
|
||
exit:
|
||
if (Modals) {
|
||
NetApiBufferFree( Modals );
|
||
}
|
||
if (DCName) {
|
||
NetApiBufferFree( DCName );
|
||
}
|
||
if (ReferencedDomains) {
|
||
LsaFreeMemory( ReferencedDomains );
|
||
}
|
||
if (LsaSids) {
|
||
LsaFreeMemory( LsaSids );
|
||
}
|
||
if (PolicyHandle) {
|
||
LsaClose( PolicyHandle );
|
||
}
|
||
|
||
return MachineName;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
SetServiceSecurity(
|
||
LPWSTR AccountName
|
||
)
|
||
{
|
||
LSA_HANDLE PolicyHandle;
|
||
PSID pSid;
|
||
NTSTATUS Status;
|
||
int iRetVal=RTN_ERROR;
|
||
LPWSTR MachineName;
|
||
WCHAR NewAccountName[512];
|
||
|
||
|
||
if (AccountName[0] == L'.') {
|
||
if (GetDefaultDomainName( NewAccountName )) {
|
||
wcscat( NewAccountName, &AccountName[1] );
|
||
AccountName = NewAccountName;
|
||
}
|
||
}
|
||
|
||
//
|
||
// try to get the correct machine name
|
||
//
|
||
MachineName = GetMachineName( AccountName );
|
||
|
||
//
|
||
// Open the policy on the target machine.
|
||
//
|
||
Status = OpenPolicy(
|
||
MachineName,
|
||
POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
|
||
&PolicyHandle
|
||
);
|
||
if (Status != STATUS_SUCCESS) {
|
||
return RTN_ERROR;
|
||
}
|
||
|
||
//
|
||
// Obtain the SID of the user/group.
|
||
// Note that we could target a specific machine, but we don't.
|
||
// Specifying NULL for target machine searches for the SID in the
|
||
// following order: well-known, Built-in and local, primary domain,
|
||
// trusted domains.
|
||
//
|
||
if(GetAccountSid(
|
||
MachineName, // target machine
|
||
AccountName,// account to obtain SID
|
||
&pSid // buffer to allocate to contain resultant SID
|
||
)) {
|
||
//
|
||
// We only grant the privilege if we succeeded in obtaining the
|
||
// SID. We can actually add SIDs which cannot be looked up, but
|
||
// looking up the SID is a good sanity check which is suitable for
|
||
// most cases.
|
||
|
||
//
|
||
// Grant the SeServiceLogonRight to users represented by pSid.
|
||
//
|
||
if((Status=SetPrivilegeOnAccount(
|
||
PolicyHandle, // policy handle
|
||
pSid, // SID to grant privilege
|
||
L"SeServiceLogonRight", // Unicode privilege
|
||
TRUE // enable the privilege
|
||
)) == STATUS_SUCCESS) {
|
||
iRetVal=RTN_OK;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Close the policy handle.
|
||
//
|
||
LsaClose(PolicyHandle);
|
||
|
||
//
|
||
// Free memory allocated for SID.
|
||
//
|
||
if(pSid != NULL) MemFree(pSid);
|
||
|
||
return iRetVal;
|
||
}
|
||
|
||
|
||
void
|
||
InitLsaString(
|
||
PLSA_UNICODE_STRING LsaString,
|
||
LPWSTR 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);
|
||
}
|
||
|
||
NTSTATUS
|
||
OpenPolicy(
|
||
LPWSTR ServerName,
|
||
DWORD DesiredAccess,
|
||
PLSA_HANDLE PolicyHandle
|
||
)
|
||
{
|
||
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
|
||
LSA_UNICODE_STRING ServerString;
|
||
PLSA_UNICODE_STRING Server = NULL;
|
||
|
||
//
|
||
// Always initialize the object attributes to all zeroes.
|
||
//
|
||
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
|
||
|
||
if (ServerName != NULL) {
|
||
//
|
||
// Make a LSA_UNICODE_STRING out of the LPWSTR passed in
|
||
//
|
||
InitLsaString(&ServerString, ServerName);
|
||
Server = &ServerString;
|
||
}
|
||
|
||
//
|
||
// Attempt to open the policy.
|
||
//
|
||
return LsaOpenPolicy(
|
||
Server,
|
||
&ObjectAttributes,
|
||
DesiredAccess,
|
||
PolicyHandle
|
||
);
|
||
}
|
||
|
||
/*++
|
||
This function attempts to obtain a SID representing the supplied
|
||
account on the supplied system.
|
||
|
||
If the function succeeds, the return value is TRUE. A buffer is
|
||
allocated which contains the SID representing the supplied account.
|
||
This buffer should be freed when it is no longer needed by calling
|
||
HeapFree(GetProcessHeap(), 0, buffer)
|
||
|
||
If the function fails, the return value is FALSE. Call GetLastError()
|
||
to obtain extended error information.
|
||
--*/
|
||
|
||
BOOL
|
||
GetAccountSid(
|
||
LPWSTR SystemName,
|
||
LPWSTR AccountName,
|
||
PSID *Sid
|
||
)
|
||
{
|
||
LPWSTR ReferencedDomain=NULL;
|
||
DWORD cbSid=128; // initial allocation attempt
|
||
DWORD cbReferencedDomain=32; // initial allocation size
|
||
SID_NAME_USE peUse;
|
||
BOOL bSuccess=FALSE; // assume this function will fail
|
||
|
||
__try {
|
||
|
||
//
|
||
// initial memory allocations
|
||
//
|
||
if((*Sid=MemAlloc(cbSid)) == NULL) __leave;
|
||
if((ReferencedDomain=(LPWSTR)MemAlloc(cbReferencedDomain)) == NULL) __leave;
|
||
|
||
//
|
||
// Obtain the SID of the specified account on the specified system.
|
||
//
|
||
while(!LookupAccountName(
|
||
SystemName, // machine to lookup account on
|
||
AccountName, // account to lookup
|
||
*Sid, // SID of interest
|
||
&cbSid, // size of SID
|
||
ReferencedDomain, // domain account was found on
|
||
&cbReferencedDomain,
|
||
&peUse
|
||
)) {
|
||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||
//
|
||
// reallocate memory
|
||
//
|
||
if((*Sid=HeapReAlloc(
|
||
GetProcessHeap(),
|
||
0,
|
||
*Sid,
|
||
cbSid
|
||
)) == NULL) __leave;
|
||
|
||
if((ReferencedDomain=(LPWSTR)HeapReAlloc(
|
||
GetProcessHeap(),
|
||
0,
|
||
ReferencedDomain,
|
||
cbReferencedDomain
|
||
)) == NULL) __leave;
|
||
}
|
||
else __leave;
|
||
}
|
||
|
||
//
|
||
// Indicate success.
|
||
//
|
||
bSuccess=TRUE;
|
||
|
||
} // finally
|
||
__finally {
|
||
|
||
//
|
||
// Cleanup and indicate failure, if appropriate.
|
||
//
|
||
|
||
MemFree(ReferencedDomain);
|
||
|
||
if(!bSuccess) {
|
||
if(*Sid != NULL) {
|
||
MemFree(*Sid);
|
||
*Sid = NULL;
|
||
}
|
||
}
|
||
|
||
} // finally
|
||
|
||
return bSuccess;
|
||
}
|
||
|
||
NTSTATUS
|
||
SetPrivilegeOnAccount(
|
||
LSA_HANDLE PolicyHandle, // open policy handle
|
||
PSID AccountSid, // SID to grant privilege to
|
||
LPWSTR PrivilegeName, // privilege to grant (Unicode)
|
||
BOOL bEnable // enable or disable
|
||
)
|
||
{
|
||
LSA_UNICODE_STRING PrivilegeString;
|
||
|
||
//
|
||
// Create a LSA_UNICODE_STRING for the privilege name.
|
||
//
|
||
InitLsaString(&PrivilegeString, PrivilegeName);
|
||
|
||
//
|
||
// grant or revoke the privilege, accordingly
|
||
//
|
||
if(bEnable) {
|
||
return LsaAddAccountRights(
|
||
PolicyHandle, // open policy handle
|
||
AccountSid, // target SID
|
||
&PrivilegeString, // privileges
|
||
1 // privilege count
|
||
);
|
||
}
|
||
else {
|
||
return LsaRemoveAccountRights(
|
||
PolicyHandle, // open policy handle
|
||
AccountSid, // target SID
|
||
FALSE, // do not disable all rights
|
||
&PrivilegeString, // privileges
|
||
1 // privilege count
|
||
);
|
||
}
|
||
}
|
||
|
||
PSID WorldSid = NULL;
|
||
SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
|
||
PACL gDacl = NULL,gSacl = NULL;
|
||
PSID gGroup = NULL,gOwner = NULL;
|
||
|
||
|
||
|
||
BOOL
|
||
MakeAbsoluteCopyFromRelative(
|
||
PSECURITY_DESCRIPTOR psdOriginal,
|
||
PSECURITY_DESCRIPTOR* ppsdNew
|
||
)
|
||
{
|
||
// we have to find out whether the original is already self-relative
|
||
SECURITY_DESCRIPTOR_CONTROL sdc = 0;
|
||
PSECURITY_DESCRIPTOR psdAbsoluteCopy = NULL;
|
||
DWORD dwRevision = 0;
|
||
DWORD cb = 0;
|
||
PACL Dacl = NULL, Sacl = NULL;
|
||
|
||
BOOL bDefaulted;
|
||
PSID Owner = NULL, Group = NULL;
|
||
|
||
DWORD dwDaclSize = 0;
|
||
BOOL bDaclPresent = FALSE;
|
||
DWORD dwSaclSize = 0;
|
||
BOOL bSaclPresent = FALSE;
|
||
|
||
DWORD dwOwnerSize = 0;
|
||
DWORD dwPrimaryGroupSize = 0;
|
||
|
||
if( !IsValidSecurityDescriptor( psdOriginal ) ) {
|
||
return FALSE;
|
||
}
|
||
|
||
if( !GetSecurityDescriptorControl( psdOriginal, &sdc, &dwRevision ) ) {
|
||
DWORD err = GetLastError();
|
||
goto cleanup;
|
||
}
|
||
|
||
if( sdc & SE_SELF_RELATIVE ) {
|
||
// the original is in self-relative format, build an absolute copy
|
||
|
||
// get the dacl
|
||
if( !GetSecurityDescriptorDacl(
|
||
psdOriginal, // address of security descriptor
|
||
&bDaclPresent, // address of flag for presence of disc. ACL
|
||
&Dacl, // address of pointer to ACL
|
||
&bDefaulted // address of flag for default disc. ACL
|
||
)
|
||
) {
|
||
goto cleanup;
|
||
}
|
||
|
||
// get the sacl
|
||
if( !GetSecurityDescriptorSacl(
|
||
psdOriginal, // address of security descriptor
|
||
&bSaclPresent, // address of flag for presence of disc. ACL
|
||
&Sacl, // address of pointer to ACL
|
||
&bDefaulted // address of flag for default disc. ACL
|
||
)
|
||
) {
|
||
goto cleanup;
|
||
}
|
||
|
||
// get the owner
|
||
if( !GetSecurityDescriptorOwner(
|
||
psdOriginal, // address of security descriptor
|
||
&Owner, // address of pointer to owner security
|
||
// identifier (SID)
|
||
&bDefaulted // address of flag for default
|
||
)
|
||
) {
|
||
goto cleanup;
|
||
}
|
||
|
||
// get the group
|
||
if( !GetSecurityDescriptorGroup(
|
||
psdOriginal, // address of security descriptor
|
||
&Group, // address of pointer to owner security
|
||
// identifier (SID)
|
||
&bDefaulted // address of flag for default
|
||
)
|
||
) {
|
||
goto cleanup;
|
||
}
|
||
|
||
// get required buffer size
|
||
cb = 0;
|
||
MakeAbsoluteSD(
|
||
psdOriginal, // address of self-relative SD
|
||
psdAbsoluteCopy, // address of absolute SD
|
||
&cb, // address of size of absolute SD
|
||
NULL, // address of discretionary ACL
|
||
&dwDaclSize, // address of size of discretionary ACL
|
||
NULL, // address of system ACL
|
||
&dwSaclSize, // address of size of system ACL
|
||
NULL, // address of owner SID
|
||
&dwOwnerSize, // address of size of owner SID
|
||
NULL, // address of primary-group SID
|
||
&dwPrimaryGroupSize // address of size of group SID
|
||
);
|
||
|
||
// alloc the memory
|
||
psdAbsoluteCopy = (PSECURITY_DESCRIPTOR) MemAlloc( cb );
|
||
Dacl = (PACL) MemAlloc( dwDaclSize );
|
||
Sacl = (PACL) MemAlloc( dwSaclSize );
|
||
Owner = (PSID) MemAlloc( dwOwnerSize );
|
||
Group = (PSID) MemAlloc( dwPrimaryGroupSize );
|
||
|
||
if(NULL == psdAbsoluteCopy ||
|
||
NULL == Dacl ||
|
||
NULL == Sacl ||
|
||
NULL == Owner ||
|
||
NULL == Group
|
||
) {
|
||
goto cleanup;
|
||
}
|
||
|
||
// make the copy
|
||
if( !MakeAbsoluteSD(
|
||
psdOriginal, // address of self-relative SD
|
||
psdAbsoluteCopy, // address of absolute SD
|
||
&cb, // address of size of absolute SD
|
||
Dacl, // address of discretionary ACL
|
||
&dwDaclSize, // address of size of discretionary ACL
|
||
Sacl, // address of system ACL
|
||
&dwSaclSize, // address of size of system ACL
|
||
Owner, // address of owner SID
|
||
&dwOwnerSize, // address of size of owner SID
|
||
Group, // address of primary-group SID
|
||
&dwPrimaryGroupSize // address of size of group SID
|
||
)
|
||
) {
|
||
goto cleanup;
|
||
}
|
||
} else {
|
||
// the original is in absolute format, fail
|
||
goto cleanup;
|
||
}
|
||
|
||
*ppsdNew = psdAbsoluteCopy;
|
||
|
||
// paranoia check
|
||
if( !IsValidSecurityDescriptor( *ppsdNew ) ) {
|
||
goto cleanup;
|
||
}
|
||
if( !IsValidSecurityDescriptor( psdOriginal ) ) {
|
||
goto cleanup;
|
||
}
|
||
|
||
gDacl = Dacl;
|
||
gSacl = Sacl;
|
||
gOwner = Owner;
|
||
gGroup = Group;
|
||
|
||
return(TRUE);
|
||
|
||
cleanup:
|
||
if( Dacl != NULL && bDaclPresent == TRUE ) {
|
||
MemFree((PVOID) Dacl );
|
||
Dacl = NULL;
|
||
}
|
||
if( Sacl != NULL && bSaclPresent == TRUE ) {
|
||
MemFree((PVOID) Sacl );
|
||
Sacl = NULL;
|
||
}
|
||
if( Owner != NULL ) {
|
||
MemFree((PVOID) Owner );
|
||
Owner = NULL;
|
||
}
|
||
if( Group != NULL ) {
|
||
MemFree((PVOID) Group );
|
||
Group = NULL;
|
||
}
|
||
if( psdAbsoluteCopy != NULL ) {
|
||
MemFree((PVOID) psdAbsoluteCopy );
|
||
psdAbsoluteCopy = NULL;
|
||
}
|
||
|
||
return (FALSE);
|
||
}
|
||
|
||
|
||
BOOL
|
||
SetServiceWorldAccessMask(
|
||
SC_HANDLE hService,
|
||
DWORD AccessMask
|
||
)
|
||
{
|
||
BOOL Rval = FALSE;
|
||
DWORD Size = 0;
|
||
PSECURITY_DESCRIPTOR sd = NULL, sdnew = NULL;
|
||
BOOL DaclPresent = FALSE;
|
||
PACL Dacl = NULL;
|
||
BOOL DaclDefaulted = FALSE;
|
||
PACCESS_ALLOWED_ACE Ace = NULL;
|
||
BOOL bEveryoneFound = FALSE;
|
||
DWORD cbAcl, cbAce;
|
||
PACL DaclNew = NULL;
|
||
DWORD i;
|
||
|
||
if (WorldSid == NULL) {
|
||
if (!AllocateAndInitializeSid( &WorldAuthority, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &WorldSid )) {
|
||
goto exit;
|
||
}
|
||
}
|
||
|
||
if (!QueryServiceObjectSecurity( hService, DACL_SECURITY_INFORMATION, &sd, 0, &Size ) &&
|
||
GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
|
||
(sd = (PSECURITY_DESCRIPTOR) MemAlloc( Size )) &&
|
||
QueryServiceObjectSecurity( hService, DACL_SECURITY_INFORMATION, sd, Size, &Size ))
|
||
{
|
||
if (GetSecurityDescriptorDacl( sd, &DaclPresent, &Dacl, &DaclDefaulted )) {
|
||
if (!IsValidSecurityDescriptor(sd)) {
|
||
goto exit;
|
||
}
|
||
cbAcl = sizeof (ACL);
|
||
for (i=0; i<Dacl->AceCount; i++) {
|
||
if (GetAce( Dacl, i, (LPVOID*)&Ace )) {
|
||
if (EqualSid( WorldSid, &(Ace->SidStart))) {
|
||
Ace->Mask |= AccessMask;
|
||
bEveryoneFound = TRUE;
|
||
}
|
||
cbAce = sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD); // add this ACE's SID length
|
||
cbAce += GetLengthSid (Ace);
|
||
// add the length of each ACE to the total ACL length
|
||
cbAcl += cbAce;
|
||
}
|
||
}
|
||
|
||
if (!MakeAbsoluteCopyFromRelative( sd, &sdnew )){
|
||
goto exit;
|
||
}
|
||
|
||
if (!bEveryoneFound) {
|
||
|
||
// subtract ACE.SidStart from the size
|
||
cbAce = sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD); // add this ACE's SID length
|
||
cbAce += GetLengthSid (WorldSid);
|
||
// add the length of each ACE to the total ACL length
|
||
cbAcl += cbAce;
|
||
|
||
DaclNew = (PACL) MemAlloc( cbAcl *4 );
|
||
if (!DaclNew) {
|
||
goto exit;
|
||
}
|
||
|
||
if (!InitializeAcl(DaclNew, cbAcl*4, ACL_REVISION )) {
|
||
goto exit;
|
||
}
|
||
|
||
if (!IsValidAcl(DaclNew)) {
|
||
goto exit;
|
||
}
|
||
|
||
for (i = 0; i< Dacl->AceCount; i++) {
|
||
if (GetAce( Dacl, i, (LPVOID*)&Ace )) {
|
||
if (!AddAccessAllowedAce(
|
||
DaclNew,
|
||
ACL_REVISION,
|
||
Ace->Mask,
|
||
&(Ace->SidStart)
|
||
)) {
|
||
goto exit;
|
||
}
|
||
|
||
if (!IsValidAcl(DaclNew)) {
|
||
goto exit;
|
||
}
|
||
} else {
|
||
goto exit;
|
||
}
|
||
|
||
}
|
||
if (!AddAccessAllowedAce(
|
||
DaclNew, // pointer to access-control list
|
||
ACL_REVISION, // ACL revision level
|
||
SERVICE_QUERY_STATUS | AccessMask, // access mask
|
||
WorldSid // pointer to security identifier);
|
||
)) {
|
||
goto exit;
|
||
}
|
||
|
||
|
||
|
||
if (!IsValidAcl(DaclNew) ||
|
||
!IsValidSecurityDescriptor(sdnew) ||
|
||
!SetSecurityDescriptorDacl(
|
||
sdnew,
|
||
TRUE,
|
||
DaclNew,
|
||
FALSE )) {
|
||
goto exit;
|
||
}
|
||
|
||
}
|
||
|
||
if (IsValidSecurityDescriptor( sdnew ) &&
|
||
SetServiceObjectSecurity( hService, DACL_SECURITY_INFORMATION, sdnew )) {
|
||
Rval = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
exit:
|
||
MemFree( sd );
|
||
|
||
MemFree( sdnew );
|
||
|
||
MemFree( DaclNew );
|
||
|
||
MemFree( gDacl );
|
||
MemFree( gSacl );
|
||
MemFree( gGroup );
|
||
MemFree( gOwner );
|
||
|
||
return Rval;
|
||
}
|
||
|