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.
1706 lines
47 KiB
1706 lines
47 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
security.c
|
|
|
|
Abstract:
|
|
|
|
Data and routines for managing API security in the server service.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 28-Aug-1991
|
|
|
|
Revision History:
|
|
|
|
05/00 (dkruse) - Added code to handle upgrading SD's and RestrictAnonymous changes
|
|
|
|
--*/
|
|
|
|
#include "srvsvcp.h"
|
|
#include "ssreg.h"
|
|
|
|
#include <lmsname.h>
|
|
#include <netlibnt.h>
|
|
|
|
#include <debugfmt.h>
|
|
|
|
#include <seopaque.h>
|
|
#include <sertlp.h>
|
|
#include <sddl.h>
|
|
|
|
//
|
|
// Global security objects.
|
|
//
|
|
// ConfigInfo - NetServerGetInfo, NetServerSetInfo
|
|
// Connection - NetConnectionEnum
|
|
// Disk - NetServerDiskEnum
|
|
// File - NetFile APIs
|
|
// Session - NetSession APIs
|
|
// Share - NetShare APIs (file, print, and admin types)
|
|
// Statistics - NetStatisticsGet, NetStatisticsClear
|
|
//
|
|
|
|
SRVSVC_SECURITY_OBJECT SsConfigInfoSecurityObject = {0};
|
|
SRVSVC_SECURITY_OBJECT SsConnectionSecurityObject = {0};
|
|
SRVSVC_SECURITY_OBJECT SsDiskSecurityObject;
|
|
SRVSVC_SECURITY_OBJECT SsFileSecurityObject = {0};
|
|
SRVSVC_SECURITY_OBJECT SsSessionSecurityObject = {0};
|
|
SRVSVC_SECURITY_OBJECT SsShareFileSecurityObject = {0};
|
|
SRVSVC_SECURITY_OBJECT SsSharePrintSecurityObject = {0};
|
|
SRVSVC_SECURITY_OBJECT SsShareAdminSecurityObject = {0};
|
|
SRVSVC_SECURITY_OBJECT SsShareConnectSecurityObject = {0};
|
|
SRVSVC_SECURITY_OBJECT SsShareAdmConnectSecurityObject = {0};
|
|
SRVSVC_SECURITY_OBJECT SsStatisticsSecurityObject = {0};
|
|
SRVSVC_SECURITY_OBJECT SsDefaultShareSecurityObject = {0};
|
|
SRVSVC_SECURITY_OBJECT SsTransportEnumSecurityObject = {0};
|
|
BOOLEAN SsRestrictNullSessions = FALSE;
|
|
BOOLEAN SsUpgradeSecurityDescriptors = FALSE;
|
|
BOOLEAN SsRegenerateSecurityDescriptors = FALSE;
|
|
BOOLEAN SsRegenerateSessionSecurityDescriptor = FALSE;
|
|
|
|
GENERIC_MAPPING SsConfigInfoMapping = {
|
|
STANDARD_RIGHTS_READ | // Generic read
|
|
SRVSVC_CONFIG_USER_INFO_GET |
|
|
SRVSVC_CONFIG_ADMIN_INFO_GET,
|
|
STANDARD_RIGHTS_WRITE | // Generic write
|
|
SRVSVC_CONFIG_INFO_SET,
|
|
STANDARD_RIGHTS_EXECUTE, // Generic execute
|
|
SRVSVC_CONFIG_ALL_ACCESS // Generic all
|
|
};
|
|
|
|
GENERIC_MAPPING SsConnectionMapping = {
|
|
STANDARD_RIGHTS_READ | // Generic read
|
|
SRVSVC_CONNECTION_INFO_GET,
|
|
STANDARD_RIGHTS_WRITE | // Generic write
|
|
0,
|
|
STANDARD_RIGHTS_EXECUTE, // Generic execute
|
|
SRVSVC_CONNECTION_ALL_ACCESS // Generic all
|
|
};
|
|
|
|
GENERIC_MAPPING SsDiskMapping = {
|
|
STANDARD_RIGHTS_READ | // Generic read
|
|
SRVSVC_DISK_ENUM,
|
|
STANDARD_RIGHTS_WRITE | // Generic write
|
|
0,
|
|
STANDARD_RIGHTS_EXECUTE, // Generic execute
|
|
SRVSVC_DISK_ALL_ACCESS // Generic all
|
|
};
|
|
|
|
GENERIC_MAPPING SsFileMapping = {
|
|
STANDARD_RIGHTS_READ | // Generic read
|
|
SRVSVC_FILE_INFO_GET,
|
|
STANDARD_RIGHTS_WRITE | // Generic write
|
|
SRVSVC_FILE_CLOSE,
|
|
STANDARD_RIGHTS_EXECUTE, // Generic execute
|
|
SRVSVC_FILE_ALL_ACCESS // Generic all
|
|
};
|
|
|
|
GENERIC_MAPPING SsSessionMapping = {
|
|
STANDARD_RIGHTS_READ | // Generic read
|
|
SRVSVC_SESSION_USER_INFO_GET |
|
|
SRVSVC_SESSION_ADMIN_INFO_GET,
|
|
STANDARD_RIGHTS_WRITE | // Generic write
|
|
SRVSVC_SESSION_DELETE,
|
|
STANDARD_RIGHTS_EXECUTE, // Generic execute
|
|
SRVSVC_SESSION_ALL_ACCESS // Generic all
|
|
};
|
|
|
|
GENERIC_MAPPING SsShareMapping = {
|
|
STANDARD_RIGHTS_READ | // Generic read
|
|
SRVSVC_SHARE_USER_INFO_GET |
|
|
SRVSVC_SHARE_ADMIN_INFO_GET,
|
|
STANDARD_RIGHTS_WRITE | // Generic write
|
|
SRVSVC_SHARE_INFO_SET,
|
|
STANDARD_RIGHTS_EXECUTE | // Generic execute
|
|
SRVSVC_SHARE_CONNECT,
|
|
SRVSVC_SHARE_ALL_ACCESS // Generic all
|
|
};
|
|
|
|
GENERIC_MAPPING SsShareConnectMapping = GENERIC_SHARE_CONNECT_MAPPING;
|
|
|
|
GENERIC_MAPPING SsStatisticsMapping = {
|
|
STANDARD_RIGHTS_READ | // Generic read
|
|
SRVSVC_STATISTICS_GET,
|
|
STANDARD_RIGHTS_WRITE, // Generic write
|
|
STANDARD_RIGHTS_EXECUTE, // Generic execute
|
|
SRVSVC_STATISTICS_ALL_ACCESS // Generic all
|
|
};
|
|
|
|
//
|
|
// Forward declarations.
|
|
//
|
|
|
|
NET_API_STATUS
|
|
CreateSecurityObject (
|
|
PSRVSVC_SECURITY_OBJECT SecurityObject,
|
|
LPTSTR ObjectName,
|
|
PGENERIC_MAPPING Mapping,
|
|
PACE_DATA AceData,
|
|
ULONG AceDataLength,
|
|
BOOLEAN bUpgradeSD
|
|
);
|
|
|
|
NET_API_STATUS
|
|
CreateConfigInfoSecurityObject (
|
|
VOID
|
|
);
|
|
|
|
NET_API_STATUS
|
|
CreateConnectionSecurityObject (
|
|
VOID
|
|
);
|
|
|
|
NET_API_STATUS
|
|
CreateDiskSecurityObject (
|
|
VOID
|
|
);
|
|
|
|
NET_API_STATUS
|
|
CreateFileSecurityObject (
|
|
VOID
|
|
);
|
|
|
|
NET_API_STATUS
|
|
CreateSessionSecurityObject (
|
|
VOID
|
|
);
|
|
|
|
NET_API_STATUS
|
|
CreateShareSecurityObjects (
|
|
VOID
|
|
);
|
|
|
|
NET_API_STATUS
|
|
CreateStatisticsSecurityObject (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
DeleteSecurityObject (
|
|
PSRVSVC_SECURITY_OBJECT SecurityObject
|
|
);
|
|
|
|
NET_API_STATUS
|
|
CheckNullSessionAccess(
|
|
VOID
|
|
);
|
|
|
|
BOOLEAN
|
|
AppendAllowedAceToSelfRelativeSD(
|
|
DWORD AceFlags,
|
|
DWORD AccessMask,
|
|
PSID pNewSid,
|
|
PISECURITY_DESCRIPTOR pOldSD,
|
|
PSECURITY_DESCRIPTOR* ppNewSD
|
|
);
|
|
|
|
BOOLEAN
|
|
DoesAclContainSid(
|
|
PACL pAcl,
|
|
PSID pSid,
|
|
OPTIONAL ACCESS_MASK* pMask
|
|
);
|
|
|
|
NTSTATUS
|
|
QueryRegDWord(
|
|
PCWSTR Path,
|
|
PCWSTR ValueName,
|
|
LPDWORD lpResult
|
|
);
|
|
|
|
NTSTATUS
|
|
SetRegDWord(
|
|
ULONG RelativeTo,
|
|
PCWSTR Path,
|
|
PCWSTR ValueName,
|
|
DWORD Value
|
|
);
|
|
|
|
|
|
NET_API_STATUS
|
|
SsCreateSecurityObjects (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets up the objects that will be used for security in the server
|
|
service APIs.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NO_ERROR or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS status;
|
|
NTSTATUS NtStatus;
|
|
DWORD dwUpgrade;
|
|
DWORD dwOldRestrictAnonymous;
|
|
DWORD dwRegenerateSessionSD;
|
|
BOOLEAN bUpdateRestrictAnonymous = FALSE;
|
|
|
|
// Check whether we need to upgrade security descriptors
|
|
// If the key exists, the upgrade has been done
|
|
NtStatus = QueryRegDWord( FULL_SECURITY_REGISTRY_PATH, ANONYMOUS_UPGRADE_NAME, &dwUpgrade );
|
|
if( !NT_SUCCESS(NtStatus) )
|
|
{
|
|
SsUpgradeSecurityDescriptors = TRUE;
|
|
}
|
|
|
|
//
|
|
// Check whether or not to restrict null session access.
|
|
//
|
|
status = CheckNullSessionAccess();
|
|
if (status != NO_ERROR) {
|
|
return(status);
|
|
}
|
|
|
|
//
|
|
// Check whether we need to regenerate the SD's because our RestrictAnonymous value changed
|
|
//
|
|
NtStatus = QueryRegDWord( FULL_SECURITY_REGISTRY_PATH, SAVED_ANONYMOUS_RESTRICTION_NAME, &dwOldRestrictAnonymous );
|
|
if( NT_SUCCESS(NtStatus) )
|
|
{
|
|
if( dwOldRestrictAnonymous != (DWORD)SsRestrictNullSessions )
|
|
{
|
|
SsRegenerateSecurityDescriptors = TRUE;
|
|
bUpdateRestrictAnonymous = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bUpdateRestrictAnonymous = TRUE;
|
|
if( !SsUpgradeSecurityDescriptors )
|
|
{
|
|
SsRegenerateSecurityDescriptors = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check whether we need to regenerate the session security descriptor
|
|
// because of removing null session access. This should be done only once
|
|
// after upgrade to .NET server 2003 (or above).
|
|
//
|
|
|
|
NtStatus = QueryRegDWord( FULL_SECURITY_REGISTRY_PATH,
|
|
SESSION_SD_REGENERATED_NAME,
|
|
&dwRegenerateSessionSD );
|
|
|
|
if( !NT_SUCCESS(NtStatus) )
|
|
{
|
|
SsRegenerateSessionSecurityDescriptor = TRUE;
|
|
|
|
//
|
|
// Delete the existing registry key for the session security descriptor,
|
|
// so that it is forced to be regenerated. Ignore if its not present.
|
|
//
|
|
|
|
NtStatus = RtlDeleteRegistryValue( RTL_REGISTRY_SERVICES,
|
|
SHARES_DEFAULT_SECURITY_REGISTRY_PATH,
|
|
SRVSVC_SESSION_OBJECT
|
|
);
|
|
|
|
if ( ( !NT_SUCCESS(NtStatus) ) &&
|
|
(NtStatus != STATUS_OBJECT_NAME_NOT_FOUND) ) {
|
|
return NetpNtStatusToApiStatus(NtStatus);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Create ConfigInfo security object.
|
|
//
|
|
|
|
status = CreateConfigInfoSecurityObject( );
|
|
if ( status != NO_ERROR ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Create Connection security object.
|
|
//
|
|
|
|
status = CreateConnectionSecurityObject( );
|
|
if ( status != NO_ERROR ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Create Disk security object.
|
|
//
|
|
|
|
status = CreateDiskSecurityObject( );
|
|
if ( status != NO_ERROR ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Create File security object.
|
|
//
|
|
|
|
status = CreateFileSecurityObject( );
|
|
if ( status != NO_ERROR ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Create Session security object.
|
|
//
|
|
|
|
status = CreateSessionSecurityObject( );
|
|
if ( status != NO_ERROR ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Create Share security object.
|
|
//
|
|
|
|
status = CreateShareSecurityObjects( );
|
|
if ( status != NO_ERROR ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Create Statistics security object.
|
|
//
|
|
|
|
status = CreateStatisticsSecurityObject( );
|
|
if ( status != NO_ERROR ) {
|
|
return status;
|
|
}
|
|
|
|
// We upgraded them, so we don't need to do it anymore
|
|
// Mark that in the registry
|
|
if( SsUpgradeSecurityDescriptors )
|
|
{
|
|
NtStatus = SetRegDWord( RTL_REGISTRY_SERVICES, ABBREVIATED_SECURITY_REGISTRY_PATH, ANONYMOUS_UPGRADE_NAME, (DWORD)1 );
|
|
if( !NT_SUCCESS(NtStatus) )
|
|
{
|
|
return NetpNtStatusToApiStatus(NtStatus);
|
|
}
|
|
}
|
|
|
|
// Update the database value to the new one if necessary, or add it the first time
|
|
if( bUpdateRestrictAnonymous )
|
|
{
|
|
NtStatus = SetRegDWord( RTL_REGISTRY_SERVICES, ABBREVIATED_SECURITY_REGISTRY_PATH, SAVED_ANONYMOUS_RESTRICTION_NAME, (DWORD)SsRestrictNullSessions );
|
|
if( !NT_SUCCESS(NtStatus) )
|
|
{
|
|
return NetpNtStatusToApiStatus(NtStatus);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create the new key to indicate that regeneration has been done
|
|
//
|
|
if ( SsRegenerateSessionSecurityDescriptor ) {
|
|
|
|
NtStatus = SetRegDWord( RTL_REGISTRY_SERVICES,
|
|
ABBREVIATED_SECURITY_REGISTRY_PATH,
|
|
SESSION_SD_REGENERATED_NAME,
|
|
(DWORD)1 );
|
|
|
|
if( !NT_SUCCESS(NtStatus) ) {
|
|
return NetpNtStatusToApiStatus(NtStatus);
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // SsCreateSecurityObjects
|
|
|
|
|
|
VOID
|
|
SsDeleteSecurityObjects (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes server service security objects.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Delete ConfigInfo security objects.
|
|
//
|
|
|
|
DeleteSecurityObject( &SsConfigInfoSecurityObject );
|
|
DeleteSecurityObject( &SsTransportEnumSecurityObject );
|
|
|
|
//
|
|
// Delete Connection security object.
|
|
//
|
|
|
|
DeleteSecurityObject( &SsConnectionSecurityObject );
|
|
|
|
//
|
|
// Delete Disk security object
|
|
//
|
|
|
|
DeleteSecurityObject( &SsDiskSecurityObject );
|
|
|
|
//
|
|
// Delete File security object.
|
|
//
|
|
|
|
DeleteSecurityObject( &SsFileSecurityObject );
|
|
|
|
//
|
|
// Delete Session security object.
|
|
//
|
|
|
|
DeleteSecurityObject( &SsSessionSecurityObject );
|
|
|
|
//
|
|
// Delete Share security objects.
|
|
//
|
|
|
|
DeleteSecurityObject( &SsShareFileSecurityObject );
|
|
DeleteSecurityObject( &SsSharePrintSecurityObject );
|
|
DeleteSecurityObject( &SsShareAdminSecurityObject );
|
|
DeleteSecurityObject( &SsShareConnectSecurityObject );
|
|
DeleteSecurityObject( &SsShareAdmConnectSecurityObject );
|
|
DeleteSecurityObject( &SsDefaultShareSecurityObject );
|
|
|
|
|
|
//
|
|
// Delete Statistics security object.
|
|
//
|
|
|
|
DeleteSecurityObject( &SsStatisticsSecurityObject );
|
|
|
|
return;
|
|
|
|
} // SsDeleteSecurityObjects
|
|
|
|
|
|
NET_API_STATUS
|
|
SsCheckAccess (
|
|
IN PSRVSVC_SECURITY_OBJECT SecurityObject,
|
|
IN ACCESS_MASK DesiredAccess
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls NetpAccessCheckAndAudit to verify that the caller of an API
|
|
has the necessary access to perform the requested operation.
|
|
|
|
Arguments:
|
|
|
|
SecurityObject - a pointer to the server service security object
|
|
that describes the security on the relevant object.
|
|
|
|
DesiredAccess - the access needed to perform the requested operation.
|
|
|
|
Return Value:
|
|
|
|
NET_API_STATUS - NO_ERROR or reason for failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
NET_API_STATUS error;
|
|
|
|
IF_DEBUG(SECURITY) {
|
|
SS_PRINT(( "SsCheckAccess: validating object " FORMAT_LPTSTR ", "
|
|
"access %lx\n",
|
|
SecurityObject->ObjectName, DesiredAccess ));
|
|
}
|
|
|
|
error = NetpAccessCheckAndAudit(
|
|
SERVER_DISPLAY_NAME,
|
|
SecurityObject->ObjectName,
|
|
SecurityObject->SecurityDescriptor,
|
|
DesiredAccess,
|
|
SecurityObject->Mapping
|
|
);
|
|
|
|
if ( error != NO_ERROR ) {
|
|
IF_DEBUG(ACCESS_DENIED) {
|
|
SS_PRINT(( "SsCheckAccess: NetpAccessCheckAndAudit failed for "
|
|
"object " FORMAT_LPTSTR ", access %lx: %ld\n",
|
|
SecurityObject->ObjectName, DesiredAccess, error ));
|
|
}
|
|
} else {
|
|
IF_DEBUG(SECURITY) {
|
|
SS_PRINT(( "SsCheckAccess: allowed access for " FORMAT_LPTSTR ", "
|
|
"access %lx\n",
|
|
SecurityObject->ObjectName, DesiredAccess ));
|
|
}
|
|
}
|
|
|
|
return error;
|
|
|
|
} // SsCheckAccess
|
|
|
|
|
|
NET_API_STATUS
|
|
CreateSecurityObject (
|
|
PSRVSVC_SECURITY_OBJECT SecurityObject,
|
|
LPTSTR ObjectName,
|
|
PGENERIC_MAPPING Mapping,
|
|
PACE_DATA AceData,
|
|
ULONG AceDataLength,
|
|
BOOLEAN bUpgradeSD
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Set up security object.
|
|
//
|
|
|
|
SecurityObject->ObjectName = ObjectName;
|
|
SecurityObject->Mapping = Mapping;
|
|
|
|
//
|
|
// Create security descriptor. If we can load it from the registry, then use it.
|
|
// Else use the compiled-in value
|
|
//
|
|
|
|
// Get the existing SD from the registry, unless we are supposed to regenerate them due to RestrictAnonymous changing
|
|
if( SsRegenerateSecurityDescriptors || !SsGetDefaultSdFromRegistry( ObjectName, &SecurityObject->SecurityDescriptor ) ) {
|
|
|
|
status = NetpCreateSecurityObject(
|
|
AceData,
|
|
AceDataLength,
|
|
SsData.SsLmsvcsGlobalData->LocalSystemSid,
|
|
SsData.SsLmsvcsGlobalData->LocalSystemSid,
|
|
Mapping,
|
|
&SecurityObject->SecurityDescriptor
|
|
);
|
|
|
|
if( NT_SUCCESS( status ) ) {
|
|
//
|
|
// Write the value to the registry, since it wasn't there already.
|
|
// Ignore any errors.
|
|
//
|
|
SsWriteDefaultSdToRegistry( ObjectName, SecurityObject->SecurityDescriptor );
|
|
|
|
} else {
|
|
|
|
IF_DEBUG(INITIALIZATION_ERRORS) {
|
|
SS_PRINT(( "CreateSecurityObject: failed to create " FORMAT_LPTSTR
|
|
" object: %lx\n", ObjectName, status ));
|
|
}
|
|
|
|
return NetpNtStatusToApiStatus( status );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( bUpgradeSD )
|
|
{
|
|
// We need to check if the security descriptor needs to be updated
|
|
PACL pAcl;
|
|
BOOL bDaclPresent, bDaclDefault;
|
|
ACCESS_MASK AccessMask;
|
|
|
|
if( !GetSecurityDescriptorDacl( SecurityObject->SecurityDescriptor, &bDaclPresent, &pAcl, &bDaclDefault ) )
|
|
{
|
|
return ERROR_INVALID_ACL;
|
|
}
|
|
|
|
if( bDaclPresent )
|
|
{
|
|
// If they have authenticated users set, but they're not restricting NULL sessions, add in the World and the Anonymous token.
|
|
// If they have the World set but not Anonymous and we're not restricting NULL sessions, add Anonymous
|
|
// Note that DoesAclContainSid does NOT alter AccessMask if the Sid is not contained, so we can rest assured that if the condition
|
|
// is satisfied, AccessMask will contain a valid value.
|
|
if( ( DoesAclContainSid( pAcl, SsData.SsLmsvcsGlobalData->AuthenticatedUserSid, &AccessMask ) ||
|
|
DoesAclContainSid( pAcl, SsData.SsLmsvcsGlobalData->WorldSid, &AccessMask ) ) &&
|
|
!SsRestrictNullSessions )
|
|
{
|
|
PSECURITY_DESCRIPTOR pNewSD;
|
|
|
|
|
|
if( !DoesAclContainSid( pAcl, SsData.SsLmsvcsGlobalData->WorldSid, NULL ) )
|
|
{
|
|
if( !AppendAllowedAceToSelfRelativeSD( 0, AccessMask, SsData.SsLmsvcsGlobalData->WorldSid, SecurityObject->SecurityDescriptor, &pNewSD ) )
|
|
{
|
|
return NetpNtStatusToApiStatus( STATUS_INVALID_SECURITY_DESCR );
|
|
}
|
|
|
|
MIDL_user_free( SecurityObject->SecurityDescriptor );
|
|
SecurityObject->SecurityDescriptor = pNewSD;
|
|
|
|
if( !GetSecurityDescriptorDacl( SecurityObject->SecurityDescriptor, &bDaclPresent, &pAcl, &bDaclDefault ) )
|
|
{
|
|
return ERROR_INVALID_ACL;
|
|
}
|
|
}
|
|
|
|
if( !DoesAclContainSid( pAcl, SsData.SsLmsvcsGlobalData->AnonymousLogonSid, NULL ) )
|
|
{
|
|
if( !AppendAllowedAceToSelfRelativeSD( 0, AccessMask, SsData.SsLmsvcsGlobalData->AnonymousLogonSid, SecurityObject->SecurityDescriptor, &pNewSD ) )
|
|
{
|
|
return NetpNtStatusToApiStatus( STATUS_INVALID_SECURITY_DESCR );
|
|
}
|
|
|
|
MIDL_user_free( SecurityObject->SecurityDescriptor );
|
|
SecurityObject->SecurityDescriptor = pNewSD;
|
|
}
|
|
|
|
// Write the updated SID to the registry
|
|
SsWriteDefaultSdToRegistry( ObjectName, SecurityObject->SecurityDescriptor );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
IF_DEBUG(INITIALIZATION) {
|
|
SS_PRINT(( "CreateSecurityObject: created " FORMAT_LPTSTR " object.\n",
|
|
ObjectName ));
|
|
}
|
|
|
|
return NO_ERROR;
|
|
|
|
} // CreateSecurityObject
|
|
|
|
|
|
NET_API_STATUS
|
|
CreateConfigInfoSecurityObject (
|
|
VOID
|
|
)
|
|
{
|
|
PACE_DATA pAceData;
|
|
ULONG AceSize;
|
|
NET_API_STATUS netStatus;
|
|
|
|
//
|
|
// Required access for getting and setting server information.
|
|
//
|
|
|
|
ACE_DATA ConfigInfoAceData[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->LocalSystemSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_CONFIG_USER_INFO_GET | SRVSVC_CONFIG_POWER_INFO_GET,
|
|
&SsData.SsLmsvcsGlobalData->AliasPowerUsersSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_CONFIG_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->WorldSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_CONFIG_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->AnonymousLogonSid}
|
|
};
|
|
|
|
ACE_DATA ConfigInfoAceDataRestricted[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->LocalSystemSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_CONFIG_USER_INFO_GET | SRVSVC_CONFIG_POWER_INFO_GET,
|
|
&SsData.SsLmsvcsGlobalData->AliasPowerUsersSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_CONFIG_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->AuthenticatedUserSid}
|
|
};
|
|
|
|
ACE_DATA TransportEnumAceData[] = {
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->LocalSystemSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_CONFIG_USER_INFO_GET | SRVSVC_CONFIG_POWER_INFO_GET,
|
|
&SsData.SsLmsvcsGlobalData->AliasPowerUsersSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_CONFIG_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->AuthenticatedUserSid}
|
|
};
|
|
|
|
if( SsRestrictNullSessions )
|
|
{
|
|
pAceData = ConfigInfoAceDataRestricted;
|
|
AceSize = sizeof(ConfigInfoAceDataRestricted)/sizeof(ACE_DATA);
|
|
}
|
|
else
|
|
{
|
|
pAceData = ConfigInfoAceData;
|
|
AceSize = sizeof(ConfigInfoAceData)/sizeof(ACE_DATA);
|
|
}
|
|
|
|
//
|
|
// Create ConfigInfo security object.
|
|
//
|
|
|
|
netStatus = CreateSecurityObject(
|
|
&SsConfigInfoSecurityObject,
|
|
SRVSVC_CONFIG_INFO_OBJECT,
|
|
&SsConfigInfoMapping,
|
|
pAceData,
|
|
AceSize,
|
|
SsUpgradeSecurityDescriptors
|
|
);
|
|
|
|
if( netStatus != NO_ERROR )
|
|
{
|
|
return netStatus;
|
|
}
|
|
|
|
pAceData = TransportEnumAceData;
|
|
AceSize = sizeof(TransportEnumAceData)/sizeof(ACE_DATA);
|
|
|
|
return CreateSecurityObject(
|
|
&SsTransportEnumSecurityObject,
|
|
SRVSVC_TRANSPORT_INFO_OBJECT,
|
|
&SsConfigInfoMapping,
|
|
pAceData,
|
|
AceSize,
|
|
SsUpgradeSecurityDescriptors
|
|
);
|
|
} // CreateConfigInfoSecurityObject
|
|
|
|
|
|
NET_API_STATUS
|
|
CreateConnectionSecurityObject (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Required access for getting and setting Connection information.
|
|
//
|
|
|
|
ACE_DATA ConnectionAceData[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_CONNECTION_INFO_GET, &SsData.SsLmsvcsGlobalData->AliasPrintOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_CONNECTION_INFO_GET, &SsData.SsLmsvcsGlobalData->AliasPowerUsersSid}
|
|
};
|
|
|
|
//
|
|
// Create Connection security object.
|
|
//
|
|
|
|
return CreateSecurityObject(
|
|
&SsConnectionSecurityObject,
|
|
SRVSVC_CONNECTION_OBJECT,
|
|
&SsConnectionMapping,
|
|
ConnectionAceData,
|
|
sizeof(ConnectionAceData) / sizeof(ACE_DATA),
|
|
SsUpgradeSecurityDescriptors
|
|
);
|
|
|
|
return NO_ERROR;
|
|
|
|
} // CreateConnectionSecurityObject
|
|
|
|
|
|
NET_API_STATUS
|
|
CreateDiskSecurityObject (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Required access for doing Disk enums
|
|
//
|
|
|
|
ACE_DATA DiskAceData[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid}
|
|
};
|
|
|
|
//
|
|
// Create Disk security object.
|
|
//
|
|
|
|
return CreateSecurityObject(
|
|
&SsDiskSecurityObject,
|
|
SRVSVC_DISK_OBJECT,
|
|
&SsDiskMapping,
|
|
DiskAceData,
|
|
sizeof(DiskAceData) / sizeof(ACE_DATA),
|
|
SsUpgradeSecurityDescriptors
|
|
);
|
|
|
|
} // CreateDiskSecurityObject
|
|
|
|
|
|
NET_API_STATUS
|
|
CreateFileSecurityObject (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Required access for getting and setting File information.
|
|
//
|
|
|
|
ACE_DATA FileAceData[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasPowerUsersSid}
|
|
};
|
|
|
|
//
|
|
// Create File security object.
|
|
//
|
|
|
|
return CreateSecurityObject(
|
|
&SsFileSecurityObject,
|
|
SRVSVC_FILE_OBJECT,
|
|
&SsFileMapping,
|
|
FileAceData,
|
|
sizeof(FileAceData) / sizeof(ACE_DATA),
|
|
SsUpgradeSecurityDescriptors
|
|
);
|
|
|
|
} // CreateFileSecurityObject
|
|
|
|
|
|
NET_API_STATUS
|
|
CreateSessionSecurityObject (
|
|
VOID
|
|
)
|
|
{
|
|
PACE_DATA pAceData;
|
|
ULONG AceSize;
|
|
|
|
//
|
|
// Required access for getting and setting session information.
|
|
//
|
|
|
|
//
|
|
// For the NetSessionEnum api, we need 'out of the box' security,
|
|
// irrespective of the RestrictAnonymous key. So, never allow access to
|
|
// null sessions.
|
|
//
|
|
|
|
ACE_DATA SessionAceData[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasPowerUsersSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SESSION_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->AuthenticatedUserSid}
|
|
};
|
|
|
|
//
|
|
// Create Session security object.
|
|
// Note that since we do not want to give access to everybody in any case,
|
|
// we pass in FALSE instead of SsUpgradeSecurityDescriptors.
|
|
//
|
|
|
|
return CreateSecurityObject(
|
|
&SsSessionSecurityObject,
|
|
SRVSVC_SESSION_OBJECT,
|
|
&SsSessionMapping,
|
|
SessionAceData,
|
|
sizeof(SessionAceData) / sizeof(ACE_DATA),
|
|
FALSE
|
|
);
|
|
|
|
} // CreateSessionSecurityObject
|
|
|
|
|
|
NET_API_STATUS
|
|
CreateShareSecurityObjects (
|
|
VOID
|
|
)
|
|
{
|
|
NET_API_STATUS status;
|
|
PACE_DATA pAceData;
|
|
ULONG AceSize;
|
|
|
|
//
|
|
// Required access for getting and setting share information.
|
|
//
|
|
|
|
|
|
ACE_DATA ShareFileAceData[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasPowerUsersSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->WorldSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->AnonymousLogonSid}
|
|
};
|
|
ACE_DATA ShareFileAceDataRestricted[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasPowerUsersSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->AuthenticatedUserSid}
|
|
};
|
|
|
|
ACE_DATA SharePrintAceData[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasPrintOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasPowerUsersSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->WorldSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->AnonymousLogonSid}
|
|
};
|
|
ACE_DATA SharePrintAceDataRestricted[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasPrintOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasPowerUsersSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->AuthenticatedUserSid}
|
|
};
|
|
|
|
ACE_DATA ShareAdminAceData[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_ADMIN_INFO_GET,
|
|
&SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_ADMIN_INFO_GET,
|
|
&SsData.SsLmsvcsGlobalData->AliasPowerUsersSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->WorldSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->AnonymousLogonSid}
|
|
};
|
|
ACE_DATA ShareAdminAceDataRestricted[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_ADMIN_INFO_GET,
|
|
&SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_ADMIN_INFO_GET,
|
|
&SsData.SsLmsvcsGlobalData->AliasPowerUsersSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_USER_INFO_GET, &SsData.SsLmsvcsGlobalData->AuthenticatedUserSid}
|
|
};
|
|
|
|
//
|
|
// note for connect we always use WorldSid for backwards compat.
|
|
//
|
|
|
|
ACE_DATA ShareConnectAceData[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasBackupOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_CONNECT, &SsData.SsLmsvcsGlobalData->WorldSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_SHARE_CONNECT, &SsData.SsLmsvcsGlobalData->AnonymousLogonSid}
|
|
};
|
|
|
|
ACE_DATA ShareAdmConnectAceData[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasBackupOpsSid}
|
|
};
|
|
|
|
//
|
|
// Create Share security objects.
|
|
//
|
|
|
|
if (!SsGetDefaultSdFromRegistry(
|
|
SRVSVC_DEFAULT_SHARE_OBJECT,
|
|
&SsDefaultShareSecurityObject.SecurityDescriptor)) {
|
|
|
|
SsDefaultShareSecurityObject.SecurityDescriptor = NULL;
|
|
}
|
|
|
|
if( SsRestrictNullSessions )
|
|
{
|
|
pAceData = ShareFileAceDataRestricted;
|
|
AceSize = sizeof(ShareFileAceDataRestricted)/sizeof(ACE_DATA);
|
|
}
|
|
else
|
|
{
|
|
pAceData = ShareFileAceData;
|
|
AceSize = sizeof(ShareFileAceData)/sizeof(ACE_DATA);
|
|
}
|
|
status = CreateSecurityObject(
|
|
&SsShareFileSecurityObject,
|
|
SRVSVC_SHARE_FILE_OBJECT,
|
|
&SsShareMapping,
|
|
pAceData,
|
|
AceSize,
|
|
SsUpgradeSecurityDescriptors
|
|
);
|
|
if ( status != NO_ERROR ) {
|
|
return status;
|
|
}
|
|
|
|
|
|
if( SsRestrictNullSessions )
|
|
{
|
|
pAceData = SharePrintAceDataRestricted;
|
|
AceSize = sizeof(SharePrintAceDataRestricted)/sizeof(ACE_DATA);
|
|
}
|
|
else
|
|
{
|
|
pAceData = SharePrintAceData;
|
|
AceSize = sizeof(SharePrintAceData)/sizeof(ACE_DATA);
|
|
}
|
|
status = CreateSecurityObject(
|
|
&SsSharePrintSecurityObject,
|
|
SRVSVC_SHARE_PRINT_OBJECT,
|
|
&SsShareMapping,
|
|
pAceData,
|
|
AceSize,
|
|
SsUpgradeSecurityDescriptors
|
|
);
|
|
|
|
if ( status != NO_ERROR ) {
|
|
return status;
|
|
}
|
|
|
|
if( SsRestrictNullSessions )
|
|
{
|
|
pAceData = ShareAdminAceDataRestricted;
|
|
AceSize = sizeof(ShareAdminAceDataRestricted)/sizeof(ACE_DATA);
|
|
}
|
|
else
|
|
{
|
|
pAceData = ShareAdminAceData;
|
|
AceSize = sizeof(ShareAdminAceData)/sizeof(ACE_DATA);
|
|
}
|
|
status = CreateSecurityObject(
|
|
&SsShareAdminSecurityObject,
|
|
SRVSVC_SHARE_ADMIN_OBJECT,
|
|
&SsShareMapping,
|
|
pAceData,
|
|
AceSize,
|
|
SsUpgradeSecurityDescriptors
|
|
);
|
|
if ( status != NO_ERROR ) {
|
|
return status;
|
|
}
|
|
|
|
pAceData = ShareConnectAceData;
|
|
AceSize = sizeof(ShareConnectAceData)/sizeof(ACE_DATA);
|
|
|
|
// Make sure the upgrade happens for this one. The upgrade
|
|
// will not happen if RA != 0. We force RA=0 for this one case.
|
|
{
|
|
BOOLEAN restrictNullSession = SsRestrictNullSessions;
|
|
SsRestrictNullSessions = FALSE;
|
|
|
|
status = CreateSecurityObject(
|
|
&SsShareConnectSecurityObject,
|
|
SRVSVC_SHARE_CONNECT_OBJECT,
|
|
&SsShareConnectMapping,
|
|
pAceData,
|
|
AceSize,
|
|
SsUpgradeSecurityDescriptors
|
|
);
|
|
if ( status != NO_ERROR ) {
|
|
return status;
|
|
}
|
|
|
|
SsRestrictNullSessions = restrictNullSession;
|
|
}
|
|
|
|
return CreateSecurityObject(
|
|
&SsShareAdmConnectSecurityObject,
|
|
SRVSVC_SHARE_ADM_CONNECT_OBJECT,
|
|
&SsShareConnectMapping,
|
|
ShareAdmConnectAceData,
|
|
sizeof(ShareAdmConnectAceData) / sizeof(ACE_DATA),
|
|
SsUpgradeSecurityDescriptors
|
|
);
|
|
|
|
} // CreateShareSecurityObjects
|
|
|
|
|
|
NET_API_STATUS
|
|
CreateStatisticsSecurityObject (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Required access for getting and setting Statistics information.
|
|
//
|
|
|
|
ACE_DATA StatisticsAceData[] = {
|
|
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasAdminsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
GENERIC_ALL, &SsData.SsLmsvcsGlobalData->AliasSystemOpsSid},
|
|
{ACCESS_ALLOWED_ACE_TYPE, 0, 0,
|
|
SRVSVC_STATISTICS_GET, &SsData.SsLmsvcsGlobalData->LocalSid}
|
|
};
|
|
|
|
//
|
|
// Create Statistics security object.
|
|
//
|
|
|
|
return CreateSecurityObject(
|
|
&SsStatisticsSecurityObject,
|
|
SRVSVC_STATISTICS_OBJECT,
|
|
&SsStatisticsMapping,
|
|
StatisticsAceData,
|
|
sizeof(StatisticsAceData) / sizeof(ACE_DATA),
|
|
SsUpgradeSecurityDescriptors
|
|
);
|
|
|
|
} // CreateStatisticsSecurityObject
|
|
|
|
|
|
VOID
|
|
DeleteSecurityObject (
|
|
PSRVSVC_SECURITY_OBJECT SecurityObject
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
if ( SecurityObject->SecurityDescriptor != NULL ) {
|
|
|
|
status = NetpDeleteSecurityObject(
|
|
&SecurityObject->SecurityDescriptor
|
|
);
|
|
SecurityObject->SecurityDescriptor = NULL;
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
IF_DEBUG(TERMINATION_ERRORS) {
|
|
SS_PRINT(( "DeleteSecurityObject: failed to delete "
|
|
FORMAT_LPTSTR " object: %X\n",
|
|
SecurityObject->ObjectName,
|
|
status ));
|
|
}
|
|
} else {
|
|
IF_DEBUG(TERMINATION) {
|
|
SS_PRINT(( "DeleteSecurityObject: deleted " FORMAT_LPTSTR
|
|
" object.\n",
|
|
SecurityObject->ObjectName ));
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} // DeleteSecurityObject
|
|
|
|
|
|
NET_API_STATUS
|
|
CheckNullSessionAccess(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks to see if we should restict null session access.
|
|
in the registry under system\currentcontrolset\Control\Lsa\
|
|
RestrictAnonymous indicating whether or not to restrict access.
|
|
If access is restricted then you need to be an authenticated user to
|
|
get DOMAIN_LIST_ACCOUNTS or GROUP_LIST_MEMBERS or ALIAS_LIST_MEMBERS
|
|
access.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR - the routine completed sucesfully.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus;
|
|
UNICODE_STRING KeyName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE KeyHandle;
|
|
UCHAR Buffer[100];
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
|
|
ULONG KeyValueLength = 100;
|
|
ULONG ResultLength;
|
|
PULONG Flag;
|
|
|
|
SsRestrictNullSessions = FALSE;
|
|
|
|
//
|
|
// Open the Lsa key in the registry
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&KeyName,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa"
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
NtStatus = NtOpenKey(
|
|
&KeyHandle,
|
|
KEY_READ,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
RtlInitUnicodeString(
|
|
&KeyName,
|
|
L"RestrictAnonymous"
|
|
);
|
|
|
|
NtStatus = NtQueryValueKey(
|
|
KeyHandle,
|
|
&KeyName,
|
|
KeyValuePartialInformation,
|
|
KeyValueInformation,
|
|
KeyValueLength,
|
|
&ResultLength
|
|
);
|
|
|
|
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
|
|
//
|
|
// Check that the data is the correct size and type - a ULONG.
|
|
//
|
|
|
|
if ((KeyValueInformation->DataLength >= sizeof(ULONG)) &&
|
|
(KeyValueInformation->Type == REG_DWORD)) {
|
|
|
|
|
|
Flag = (PULONG) KeyValueInformation->Data;
|
|
|
|
if (*Flag >= 1) {
|
|
SsRestrictNullSessions = TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if( NtStatus == STATUS_OBJECT_NAME_NOT_FOUND )
|
|
{
|
|
// No key means RestrictAnonymous = 0
|
|
NtStatus = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
NtClose(KeyHandle);
|
|
|
|
Cleanup:
|
|
|
|
if( !NT_SUCCESS(NtStatus) )
|
|
{
|
|
return NetpNtStatusToApiStatus(NtStatus);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
BOOLEAN
|
|
DoesAclContainSid(
|
|
PACL pAcl,
|
|
PSID pSid,
|
|
OPTIONAL ACCESS_MASK* pMask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This walks the given Acl to see if it contains the desired SID. If it does,
|
|
we optionally also return the AccessMask associated with that SID.
|
|
|
|
NOTE: If the value is not found, this routine should NOT touch the pMask variable.
|
|
|
|
Arguments:
|
|
|
|
pAcl - A pointer to the ACL we're checking
|
|
pSid - The SID we're looking for
|
|
pMask [optional] - Where we fill in the Access Mask if they want to know it.
|
|
|
|
Return Value:
|
|
|
|
TRUE - the routine completed sucesfully.
|
|
FALSE - the routine encountered an error
|
|
|
|
--*/
|
|
{
|
|
ACE_HEADER* pAceHeader;
|
|
ACL_SIZE_INFORMATION AclSize;
|
|
PSID pAceSid;
|
|
WORD wCount;
|
|
|
|
if( !GetAclInformation( pAcl, &AclSize, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation ) )
|
|
return FALSE;
|
|
|
|
for( wCount=0; wCount < AclSize.AceCount; wCount++ )
|
|
{
|
|
if( !GetAce( pAcl, wCount, &pAceHeader ) )
|
|
return FALSE;
|
|
|
|
switch( pAceHeader->AceType )
|
|
{
|
|
case ACCESS_ALLOWED_ACE_TYPE:
|
|
{
|
|
ACCESS_ALLOWED_ACE* pAce = (ACCESS_ALLOWED_ACE*)pAceHeader;
|
|
pAceSid = &(pAce->SidStart);
|
|
|
|
if( EqualSid( pAceSid, pSid ) )
|
|
{
|
|
if( pMask )
|
|
{
|
|
*pMask = pAce->Mask;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
|
|
{
|
|
ACCESS_ALLOWED_OBJECT_ACE* pAce = (ACCESS_ALLOWED_OBJECT_ACE*)pAceHeader;
|
|
pAceSid = &(pAce->SidStart);
|
|
|
|
if( EqualSid( pAceSid, pSid ) )
|
|
{
|
|
if( pMask )
|
|
{
|
|
*pMask = pAce->Mask;
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ACCESS_DENIED_OBJECT_ACE_TYPE:
|
|
case ACCESS_DENIED_ACE_TYPE:
|
|
case SYSTEM_AUDIT_ACE_TYPE:
|
|
case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
AppendAllowedAceToSelfRelativeSD(
|
|
DWORD AceFlags,
|
|
DWORD AccessMask,
|
|
PSID pNewSid,
|
|
PISECURITY_DESCRIPTOR pOldSD,
|
|
PSECURITY_DESCRIPTOR* ppNewSD
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a new Security Descriptor that contains the original SD plus
|
|
appends the new SID (with the given Access). The final SD is in Self-Relative form.
|
|
|
|
Arguments:
|
|
|
|
AceFlags - The flags associated with this ACE in the SD
|
|
AccessMask - The AccessMask for this ACE
|
|
pNewSid - The SID for this ACE
|
|
pOldSD - The original Security Descriptor
|
|
ppNewSid - OUT pointer to the newly allocated Security Descriptor
|
|
|
|
Return Value:
|
|
|
|
TRUE - the routine completed sucesfully.
|
|
FALSE - the routine encountered an error
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN bSelfRelative;
|
|
SECURITY_DESCRIPTOR NewSDBuffer;
|
|
PISECURITY_DESCRIPTOR pNewSD, pSelfRelativeSD;
|
|
NTSTATUS Status;
|
|
BOOLEAN bResult = FALSE;
|
|
PACL pAcl, pNewAcl;
|
|
DWORD dwNewAclSize;
|
|
DWORD dwRelativeSDLength;
|
|
PSID pSid;
|
|
|
|
pNewAcl = NULL;
|
|
pSelfRelativeSD = NULL;
|
|
|
|
// Make sure it is self relative
|
|
if( !RtlpAreControlBitsSet( pOldSD, SE_SELF_RELATIVE ) )
|
|
return FALSE;
|
|
|
|
// Convert it to absolute
|
|
pNewSD = &NewSDBuffer;
|
|
Status = RtlCreateSecurityDescriptor( pNewSD, SECURITY_DESCRIPTOR_REVISION );
|
|
if( !NT_SUCCESS(Status) )
|
|
goto Cleanup;
|
|
|
|
// Copy in the new information
|
|
pNewSD->Control = pOldSD->Control;
|
|
RtlpClearControlBits( pNewSD, SE_SELF_RELATIVE );
|
|
|
|
pSid = RtlpOwnerAddrSecurityDescriptor( pOldSD );
|
|
if( pSid )
|
|
{
|
|
pNewSD->Owner = pSid;
|
|
}
|
|
|
|
pSid = RtlpGroupAddrSecurityDescriptor( pOldSD );
|
|
if( pSid )
|
|
{
|
|
pNewSD->Group = pSid;
|
|
}
|
|
|
|
pAcl = RtlpSaclAddrSecurityDescriptor( pOldSD );
|
|
if( pAcl )
|
|
{
|
|
pNewSD->Sacl = pAcl;
|
|
}
|
|
|
|
// Assemble the new ACL
|
|
pAcl = RtlpDaclAddrSecurityDescriptor( pOldSD );
|
|
if( !pAcl )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
dwNewAclSize = pAcl->AclSize + sizeof(KNOWN_ACE) + GetLengthSid( pNewSid );
|
|
pNewAcl = MIDL_user_allocate( dwNewAclSize );
|
|
if( !pNewAcl )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Copy the old information in
|
|
RtlCopyMemory( pNewAcl, pAcl, pAcl->AclSize );
|
|
pNewAcl->AclSize = (USHORT)dwNewAclSize;
|
|
|
|
// Add in the new ACE
|
|
if( !AddAccessAllowedAceEx( pNewAcl, ACL_REVISION, AceFlags, AccessMask, pNewSid ) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Set the new DACL in the SD
|
|
Status = RtlSetDaclSecurityDescriptor( pNewSD, TRUE, pNewAcl, FALSE );
|
|
if( !NT_SUCCESS(Status) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
dwRelativeSDLength = 0;
|
|
|
|
// Get the size of the self relative SD
|
|
Status = RtlMakeSelfRelativeSD( pNewSD, NULL, &dwRelativeSDLength );
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
// No way we can succeed here
|
|
ASSERT(FALSE);
|
|
goto Cleanup;
|
|
}
|
|
|
|
pSelfRelativeSD = MIDL_user_allocate( dwRelativeSDLength );
|
|
if( !pSelfRelativeSD )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
Status = RtlMakeSelfRelativeSD( pNewSD, pSelfRelativeSD, &dwRelativeSDLength );
|
|
if( !NT_SUCCESS(Status) )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
// All set. Let it be set and go.
|
|
*ppNewSD = pSelfRelativeSD;
|
|
bResult = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
if( pNewAcl )
|
|
{
|
|
MIDL_user_free( pNewAcl );
|
|
pNewAcl = NULL;
|
|
}
|
|
if( !bResult )
|
|
{
|
|
if( pSelfRelativeSD )
|
|
{
|
|
MIDL_user_free( pSelfRelativeSD );
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
QueryRegDWord(
|
|
PCWSTR Path,
|
|
PCWSTR ValueName,
|
|
LPDWORD lpResult
|
|
)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
UNICODE_STRING KeyName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE KeyHandle;
|
|
UCHAR Buffer[100];
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
|
|
ULONG KeyValueLength = 100;
|
|
ULONG ResultLength;
|
|
PULONG pValue;
|
|
|
|
//
|
|
// Open the Lsa key in the registry
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&KeyName,
|
|
Path
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
NtStatus = NtOpenKey(
|
|
&KeyHandle,
|
|
KEY_READ,
|
|
&ObjectAttributes
|
|
);
|
|
|
|
if (!NT_SUCCESS(NtStatus)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
RtlInitUnicodeString(
|
|
&KeyName,
|
|
ValueName
|
|
);
|
|
|
|
NtStatus = NtQueryValueKey(
|
|
KeyHandle,
|
|
&KeyName,
|
|
KeyValuePartialInformation,
|
|
KeyValueInformation,
|
|
KeyValueLength,
|
|
&ResultLength
|
|
);
|
|
|
|
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
|
|
//
|
|
// Check that the data is the correct size and type - a ULONG.
|
|
//
|
|
|
|
if ((KeyValueInformation->DataLength >= sizeof(ULONG)) &&
|
|
(KeyValueInformation->Type == REG_DWORD)) {
|
|
|
|
|
|
pValue = (PULONG) KeyValueInformation->Data;
|
|
*lpResult = (*pValue);
|
|
}
|
|
|
|
}
|
|
NtClose(KeyHandle);
|
|
|
|
Cleanup:
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
SetRegDWord(
|
|
ULONG RelativeTo,
|
|
PCWSTR Path,
|
|
PCWSTR ValueName,
|
|
DWORD Value
|
|
)
|
|
{
|
|
return RtlWriteRegistryValue( RelativeTo, Path, ValueName, REG_DWORD, (PVOID)(&Value), sizeof(DWORD) );
|
|
}
|
|
|
|
|