/*++ Copyright (c) 1996 Microsoft Corporation Module Name: security.c Abstract: This module provides security for the service. Author: Wesley Witt (wesw) 2-Dec-1996 Revision History: --*/ #include "faxsvc.h" #pragma hdrstop // // do this to avoid dragging in ntrtl.h since we already include some stuff // from ntrtl.h // NTSYSAPI BOOLEAN NTAPI RtlValidRelativeSecurityDescriptor ( IN PSECURITY_DESCRIPTOR SecurityDescriptorInput, IN ULONG SecurityDescriptorLength, IN SECURITY_INFORMATION RequiredInformation ); // // Number of ACEs currently defined for fax. // #define FAX_ACE_COUNT 26 typedef struct _FAX_SECURITY { LPCTSTR RegKey; PSECURITY_DESCRIPTOR SecurityDescriptor; PGENERIC_MAPPING GenericMapping; DWORD AceCount; DWORD AceIdx[FAX_ACE_COUNT]; DWORD StringResource; // Resource Id of friendly name } FAX_SECURITY, *PFAX_SECURITY; typedef struct _ACE_DATA { ACCESS_MASK AccessMask; PSID *Sid; UCHAR AceType; UCHAR AceFlags; } ACE_DATA, *PACE_DATA; typedef struct _ACE { ACE_HEADER Header; ACCESS_MASK Mask; // // The SID follows in the buffer // } ACE, *PACE; // // Universal well known SIDs // PSID NullSid; PSID WorldSid; PSID LocalSid; PSID CreatorOwnerSid; PSID CreatorGroupSid; // // SIDs defined by NT // PSID DialupSid; PSID NetworkSid; PSID BatchSid; PSID InteractiveSid; PSID ServiceSid; PSID LocalSystemSid; PSID AliasAdminsSid; PSID AliasUsersSid; PSID AliasGuestsSid; PSID AliasPowerUsersSid; PSID AliasAccountOpsSid; PSID AliasSystemOpsSid; PSID AliasPrintOpsSid; PSID AliasBackupOpsSid; PSID AliasReplicatorSid; // Note - Georgeje // // The number of security descriptors has been reduced from six // to one. The tables in security.c have been left in place in // case we need to add more security descriptos later. GENERIC_MAPPING FaxGenericMapping[] = { { STANDARD_RIGHTS_READ, STANDARD_RIGHTS_WRITE, STANDARD_RIGHTS_EXECUTE, STANDARD_RIGHTS_REQUIRED } }; // // Indexes for the ACE Data Array: // // ACE 0 - unused // ACE 1 - ADMIN Full // ACE 2 - ADMIN Read // ACE 3 - ADMIN Read Write // ACE 4 - ADMIN Read Write Delete // ACE 5 - Creator Full // ACE 6 - Creator Read Write // ACE 7 - World Full // ACE 8 - World Read // ACE 9 - World Read Write // ACE 10 - World Read Write Delete // ACE 11 - PowerUser Full // ACE 12 - PowerUser Read Write // ACE 13 - PowerUser Read Write Delete // ACE 14 - System Ops Full // ACE 15 - System Ops Read Write // ACE 16 - System Ops Read Write Delete // ACE 17 - System Full // ACE 18 - System Read Write // ACE 19 - System Read // ACE 20 - ADMIN Read Write Execute // ACE 21 - Interactive User Full // ACE 22 - Interactive User Read // ACE 23 - Interactive User Read Write // ACE 24 - Interactive User Read Write Delete // ACE 25 - Normal Users Read / Write // FAX_SECURITY FaxSecurity[] = { { REGVAL_CONFIG_SET, NULL, &FaxGenericMapping[0], 5, {1,5,9,11,17}, IDS_SET_CONFIG } }; #define FaxSecurityCount (sizeof(FaxSecurity)/sizeof(FAX_SECURITY)) // // Array of ACEs to be applied to fax. They will be // initialized during program startup based on the data in the // FaxAceDataTable. The index of each element corresponds to the // ordinals used in the [ACL] section of perms.inf. // PACE AcesForFax[FAX_ACE_COUNT]; // // Array that contains the size of each ACE in the // array AceSizesForFax. These sizes are needed // in order to allocate a buffer of the right size // when we build an ACL. // ULONG AceSizesForFax[FAX_ACE_COUNT]; // // Table describing the data to put into each ACE for fax. // // This table will be read during initialization and used to construct a // series of ACEs. The index of each ACE in the FaxAces array defined below // corresponds to fax ordinals used in the ACL section of perms.inf // ACE_DATA AceDataTableForFax[FAX_ACE_COUNT] = { // // Index 0 is unused // { 0,NULL,0,0 }, // // // ACE 1 - ADMIN Full // (for fax) // { FAX_ALL_ACCESS, &AliasAdminsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 2 - ADMIN Read // (for fax) // { FAX_READ, &AliasAdminsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 3 - ADMIN Read Write // (for fax) // { FAX_READ | FAX_WRITE, &AliasAdminsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 4 - ADMIN Read Write Delete // (for fax) // { FAX_READ | FAX_WRITE | FAX_JOB_MANAGE, &AliasAdminsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 5 - Creator Full // (for fax) // { FAX_ALL_ACCESS, &CreatorOwnerSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 6 - Creator Read Write // (for fax) // { FAX_READ | FAX_WRITE, &CreatorOwnerSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 7 - World Full // (for fax) // { FAX_ALL_ACCESS, &WorldSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 8 - World Read // (for fax) // { FAX_READ, &WorldSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 9 - World Read Write // (for fax) // { FAX_READ | FAX_WRITE, &WorldSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 10 - World Read Write Delete // (for fax) // { FAX_READ | FAX_WRITE | FAX_JOB_MANAGE, &WorldSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 11 - PowerUser Full // (for fax) // { FAX_ALL_ACCESS, &AliasPowerUsersSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 12 - PowerUser Read Write // (for fax) // { FAX_READ | FAX_WRITE, &AliasPowerUsersSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 13 - PowerUser Read Write Delete // (for fax) // { FAX_READ | FAX_WRITE | FAX_JOB_MANAGE, &AliasPowerUsersSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 14 - System Ops Full // (for fax) // { FAX_ALL_ACCESS, &AliasSystemOpsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 15 - System Ops Read Write // (for fax) // { FAX_READ | FAX_WRITE, &AliasSystemOpsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 16 - System Ops Read Write Delete // (for fax) // { FAX_READ | FAX_WRITE | FAX_JOB_MANAGE, &AliasSystemOpsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 17 - System Full // (for fax) // { FAX_ALL_ACCESS, &LocalSystemSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 18 - System Read Write // (for fax) // { FAX_READ | FAX_WRITE| FAX_JOB_MANAGE, &LocalSystemSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 19 - System Read // (for fax) // { FAX_READ, &LocalSystemSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 20 - ADMIN Read Write Execute // (for fax) // { FAX_READ | FAX_WRITE, &AliasAdminsSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 21 - Interactive User Full // (for fax) // { FAX_ALL_ACCESS, &InteractiveSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 22 - Interactive User Read // (for fax) // { FAX_READ, &InteractiveSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 23 - Interactive User Read Write // (for fax) // { FAX_READ | FAX_WRITE, &InteractiveSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 24 - Interactive User Read Write Delete // (for fax) // { FAX_READ | FAX_WRITE| FAX_JOB_MANAGE, &InteractiveSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, // // ACE 25 - Normal Users Read / Write // (for fax) // { FAX_READ | FAX_WRITE, &AliasUsersSid, ACCESS_ALLOWED_ACE_TYPE, CONTAINER_INHERIT_ACE }, }; static CRITICAL_SECTION CsSecurity; static BOOL CsInit = FALSE; DWORD InitializeSids( VOID ); VOID TearDownSids( VOID ); DWORD InitializeAces( IN OUT PACE_DATA DataTable, IN OUT PACE* AcesArray, IN OUT PULONG AceSizesArray, IN ULONG ArrayCount ); VOID TearDownAces( IN OUT PACE* AcesArray, IN ULONG ArrayCount ); DWORD InitializeSids( VOID ) /*++ Routine Description: This function initializes the global variables used by and exposed by security. Arguments: None. Return Value: Win32 error indicating outcome. --*/ { SID_IDENTIFIER_AUTHORITY NullSidAuthority = SECURITY_NULL_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY LocalSidAuthority = SECURITY_LOCAL_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; BOOL b = TRUE; // // Ensure the SIDs are in a well-known state // NullSid = NULL; WorldSid = NULL; LocalSid = NULL; CreatorOwnerSid = NULL; CreatorGroupSid = NULL; DialupSid = NULL; NetworkSid = NULL; BatchSid = NULL; InteractiveSid = NULL; ServiceSid = NULL; LocalSystemSid = NULL; AliasAdminsSid = NULL; AliasUsersSid = NULL; AliasGuestsSid = NULL; AliasPowerUsersSid = NULL; AliasAccountOpsSid = NULL; AliasSystemOpsSid = NULL; AliasPrintOpsSid = NULL; AliasBackupOpsSid = NULL; AliasReplicatorSid = NULL; // // Allocate and initialize the universal SIDs // b = b && AllocateAndInitializeSid( &NullSidAuthority, 1, SECURITY_NULL_RID, 0,0,0,0,0,0,0, &NullSid ); b = b && AllocateAndInitializeSid( &WorldSidAuthority, 1, SECURITY_WORLD_RID, 0,0,0,0,0,0,0, &WorldSid ); b = b && AllocateAndInitializeSid( &LocalSidAuthority, 1, SECURITY_LOCAL_RID, 0,0,0,0,0,0,0, &LocalSid ); b = b && AllocateAndInitializeSid( &CreatorSidAuthority, 1, SECURITY_CREATOR_OWNER_RID, 0,0,0,0,0,0,0, &CreatorOwnerSid ); b = b && AllocateAndInitializeSid( &CreatorSidAuthority, 1, SECURITY_CREATOR_GROUP_RID, 0,0,0,0,0,0,0, &CreatorGroupSid ); // // Allocate and initialize the NT defined SIDs // b = b && AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_DIALUP_RID, 0,0,0,0,0,0,0, &DialupSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_NETWORK_RID, 0,0,0,0,0,0,0, &NetworkSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_BATCH_RID, 0,0,0,0,0,0,0, &BatchSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_INTERACTIVE_RID, 0,0,0,0,0,0,0, &InteractiveSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_SERVICE_RID, 0,0,0,0,0,0,0, &ServiceSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0,0,0,0,0,0,0, &LocalSystemSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0, &AliasAdminsSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS, 0,0,0,0,0,0, &AliasUsersSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS, 0,0,0,0,0,0, &AliasGuestsSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0,0,0,0,0,0, &AliasPowerUsersSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ACCOUNT_OPS, 0,0,0,0,0,0, &AliasAccountOpsSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_SYSTEM_OPS, 0,0,0,0,0,0, &AliasSystemOpsSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_PRINT_OPS, 0,0,0,0,0,0, &AliasPrintOpsSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_BACKUP_OPS, 0,0,0,0,0,0, &AliasBackupOpsSid ); b = b && AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_REPLICATOR, 0,0,0,0,0,0, &AliasReplicatorSid ); if(!b) { TearDownSids(); } return(b ? NO_ERROR : GetLastError() ? GetLastError() : 1 ); } VOID TearDownSids( VOID ) { if(NullSid) { FreeSid(NullSid); } if(WorldSid) { FreeSid(WorldSid); } if(LocalSid) { FreeSid(LocalSid); } if(CreatorOwnerSid) { FreeSid(CreatorOwnerSid); } if(CreatorGroupSid) { FreeSid(CreatorGroupSid); } if(DialupSid) { FreeSid(DialupSid); } if(NetworkSid) { FreeSid(NetworkSid); } if(BatchSid) { FreeSid(BatchSid); } if(InteractiveSid) { FreeSid(InteractiveSid); } if(ServiceSid) { FreeSid(ServiceSid); } if(LocalSystemSid) { FreeSid(LocalSystemSid); } if(AliasAdminsSid) { FreeSid(AliasAdminsSid); } if(AliasUsersSid) { FreeSid(AliasUsersSid); } if(AliasGuestsSid) { FreeSid(AliasGuestsSid); } if(AliasPowerUsersSid) { FreeSid(AliasPowerUsersSid); } if(AliasAccountOpsSid) { FreeSid(AliasAccountOpsSid); } if(AliasSystemOpsSid) { FreeSid(AliasSystemOpsSid); } if(AliasPrintOpsSid) { FreeSid(AliasPrintOpsSid); } if(AliasBackupOpsSid) { FreeSid(AliasBackupOpsSid); } if(AliasReplicatorSid) { FreeSid(AliasReplicatorSid); } } DWORD InitializeAces( IN OUT PACE_DATA DataTable, IN OUT PACE* AcesArray, IN OUT PULONG AceSizesArray, IN ULONG ArrayCount ) /*++ Routine Description: Initializes the array of ACEs as described in the DataTable Arguments: DataTable - Pointer to the array that contains the data describing each ACE. AcesArray - Array that will contain the ACEs. AceSizesArray - Array that contains the sizes for each ACE. ArrayCount - Number of elements in each array. Return Value: Win32 error code indicating outcome. --*/ { unsigned u; DWORD Length; DWORD rc; BOOL b; DWORD SidLength; // // Initialize to a known state. // ZeroMemory(AcesArray,ArrayCount*sizeof(PACE)); // // Create ACEs for each item in the data table. // This involves merging the ace data with the SID data, which // are initialized in an earlier step. // for(u=1; uHeader.AceType = DataTable[u].AceType; AcesArray[u]->Header.AceFlags = DataTable[u].AceFlags; AcesArray[u]->Header.AceSize = (WORD)Length; AcesArray[u]->Mask = DataTable[u].AccessMask; b = CopySid( SidLength, // Length - sizeof(ACE) + sizeof(ULONG), (PUCHAR)AcesArray[u] + sizeof(ACE), *(DataTable[u].Sid) ); if(!b) { rc = GetLastError(); TearDownAces(AcesArray, ArrayCount); return(rc); } } return(NO_ERROR); } VOID TearDownAces( IN OUT PACE* AcesArray, IN ULONG ArrayCount ) /*++ Routine Description: Destroys the array of ACEs as described in the DataTable Arguments: None Return Value: None --*/ { unsigned u; for(u=1; u= FaxSecurityCount) { return FALSE; } // // Impersonate the client. // if ((rc = RpcImpersonateClient(NULL)) != RPC_S_OK) { return FALSE; } EnterCriticalSection( &CsSecurity ); // // Open the impersonated token. // if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &ClientToken )) { rc = GetLastError(); goto exit; } // // purify the access mask // MapGenericMask( &DesiredAccess, FaxSecurity[SecurityType].GenericMapping ); // // Check if the client has the required access. // PrivilegeSetSize = sizeof(PrivilegeSet); if (!AccessCheck( FaxSecurity[SecurityType].SecurityDescriptor, ClientToken, DesiredAccess, FaxSecurity[SecurityType].GenericMapping, (PPRIVILEGE_SET) PrivilegeSet, &PrivilegeSetSize, &GrantedAccess, &AccessStatus ) ) { rc = GetLastError(); goto exit; } if (!AccessStatus) { rc = GetLastError(); goto exit; } rc = 0; exit: RpcRevertToSelf(); if (ClientToken) { CloseHandle( ClientToken ); } if (rc != 0) { DebugPrint(( TEXT("FaxSvcAccessCheck() failed to authenticate, 0x%08x, 0x%08x\n"), SecurityType, DesiredAccess )); } LeaveCriticalSection( &CsSecurity ); return rc == 0; } PVOID MyGetTokenInformation( HANDLE hToken, TOKEN_INFORMATION_CLASS TokenInformationClass ) { PVOID TokenInformation = NULL; DWORD Size = 0; if (!GetTokenInformation( hToken, TokenInformationClass, NULL, 0, &Size ) && GetLastError() == ERROR_INSUFFICIENT_BUFFER && (TokenInformation = MemAlloc( Size )) && GetTokenInformation( hToken, TokenInformationClass, TokenInformation, Size, &Size )) { return TokenInformation; } MemFree( TokenInformation ); return NULL; } DWORD InitializeFaxSecurityDescriptors( VOID ) { #define BUFFER_SIZE 4096 DWORD i,j; DWORD rc = ERROR_SUCCESS; DWORD Ace; DWORD Size; HKEY hKey = NULL; DWORD Disposition; LPBYTE Buffer = NULL; BYTE AclBuffer[512]; SECURITY_DESCRIPTOR SecurityDescriptor; DWORD Type; PACL Acl; HANDLE ServiceToken; PTOKEN_OWNER Owner; PTOKEN_GROUPS Groups; PSECURITY_DESCRIPTOR AbsSD; DWORD AbsSdSize = 0; DWORD DaclSize = 0; DWORD SaclSize = 0; DWORD OwnerSize = 0; DWORD GroupSize = 0; PACL pAbsDacl = NULL; PACL pAbsSacl = NULL; PSID pAbsOwner = NULL; PSID pAbsGroup = NULL; if (!CsInit) { InitializeCriticalSection( &CsSecurity ); CsInit = TRUE; } // // Initialize SIDs // rc = InitializeSids(); if (rc != NO_ERROR) { goto exit; } // // Initialize Fax ACEs // rc = InitializeAces( AceDataTableForFax, AcesForFax, AceSizesForFax, FAX_ACE_COUNT ); if (rc != NO_ERROR) { goto exit; } if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &ServiceToken )) { rc = GetLastError(); goto exit; } Owner = MyGetTokenInformation( ServiceToken, TokenOwner ); if (!Owner) { rc = ERROR_NOT_ENOUGH_MEMORY; goto exit; } Groups = MyGetTokenInformation( ServiceToken, TokenGroups ); if (!Groups) { rc = ERROR_NOT_ENOUGH_MEMORY; goto exit; } CloseHandle( ServiceToken ); rc = RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGKEY_FAX_SECURITY, 0, TEXT(""), 0, KEY_ALL_ACCESS, NULL, &hKey, &Disposition ); if (rc != ERROR_SUCCESS) { goto exit; } Buffer = (LPBYTE) MemAlloc( BUFFER_SIZE ); if (!Buffer) { rc = ERROR_NOT_ENOUGH_MEMORY; goto exit; } for (i=0; iHeader.AceSize )) { rc = GetLastError(); goto exit; } } // // Add the ACL to the security descriptor as the DACL // if (!SetSecurityDescriptorDacl( &SecurityDescriptor, TRUE, Acl, FALSE )) { rc = GetLastError(); goto exit; } // // set the owner // if (!SetSecurityDescriptorOwner( &SecurityDescriptor, Owner->Owner, FALSE )) { rc = GetLastError(); goto exit; } // // set the groups // for (j=0; jGroupCount; j++) { if (!SetSecurityDescriptorGroup( &SecurityDescriptor, Groups->Groups[j].Sid, FALSE )) { rc = GetLastError(); goto exit; } } // // make the security descriptor self relative // Size = BUFFER_SIZE; if (!MakeSelfRelativeSD( &SecurityDescriptor, (PSECURITY_DESCRIPTOR) Buffer, &Size )) { rc = GetLastError(); goto exit; } // // store the security descriptor in the registry // Size = GetSecurityDescriptorLength( (PSECURITY_DESCRIPTOR) Buffer ); FaxSecurity[i].SecurityDescriptor = (PSECURITY_DESCRIPTOR) MemAlloc( Size ); if (!FaxSecurity[i].SecurityDescriptor) { rc = ERROR_NOT_ENOUGH_MEMORY; goto exit; } CopyMemory( FaxSecurity[i].SecurityDescriptor, Buffer, Size ); rc = RegSetValueEx( hKey, FaxSecurity[i].RegKey, 0, REG_BINARY, (LPBYTE) FaxSecurity[i].SecurityDescriptor, Size ); if (rc) { goto exit; } } exit: if (hKey) { RegCloseKey( hKey ); } if (Buffer) { MemFree( Buffer ); } if (Owner) { MemFree( Owner ); } if (Groups) { MemFree( Groups ); } return rc; } LPWSTR GetClientUserName( VOID ) { WCHAR UserName[128]; DWORD Size; if (RpcImpersonateClient(NULL) != RPC_S_OK) { return NULL; } Size = sizeof(UserName) / sizeof(WCHAR); if (!GetUserName( UserName, &Size )) { RpcRevertToSelf(); return NULL; } RpcRevertToSelf(); return StringDup( UserName ); } error_status_t FAX_GetSecurityDescriptorCount( IN handle_t FaxHandle, OUT LPDWORD Count ) /*++ Routine Description: Arguments: Return Value: --*/ { *Count = FaxSecurityCount; return ERROR_SUCCESS; } error_status_t FAX_SetSecurityDescriptor( IN handle_t FaxHandle, IN const LPBYTE Buffer, IN DWORD BufferSize ) { DWORD rVal = ERROR_SUCCESS; PFAX_SECURITY_DESCRIPTOR FaxSecDesc = (PFAX_SECURITY_DESCRIPTOR) Buffer; HKEY hKey; DWORD Disposition; DWORD SecDescBufferSize; if (!FaxSvcAccessCheck( SEC_CONFIG_SET, FAX_CONFIG_SET )) { return ERROR_ACCESS_DENIED; } // Check that the buffer is large enough to hold a FAX_SECURITY_DESCRIPTOR if (BufferSize < sizeof (FAX_SECURITY_DESCRIPTOR)) { return ERROR_INVALID_PARAMETER; } if (FaxSecDesc->Id > FaxSecurityCount) { return ERROR_INVALID_CATEGORY; } // Check that the offset is within the buffer. if (PtrToUlong(FaxSecDesc->SecurityDescriptor) >= BufferSize) { return ERROR_INVALID_PARAMETER; } // Calculate the size of the security descriptor buffer for validation SecDescBufferSize = BufferSize - PtrToUlong(FaxSecDesc->SecurityDescriptor); FaxSecDesc->SecurityDescriptor = (PSECURITY_DESCRIPTOR) FixupString(Buffer, FaxSecDesc->SecurityDescriptor); // Validate the passed security descriptor. if (!RtlValidRelativeSecurityDescriptor(FaxSecDesc->SecurityDescriptor, SecDescBufferSize, 0)) { return ERROR_INVALID_DATA; } rVal = RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGKEY_FAX_SECURITY, 0, TEXT(""), 0, KEY_ALL_ACCESS, NULL, &hKey, &Disposition ); if (rVal != ERROR_SUCCESS) { return rVal; } rVal = RegSetValueEx( hKey, FaxSecurity[FaxSecDesc->Id].RegKey, 0, REG_BINARY, (LPBYTE) FaxSecDesc->SecurityDescriptor, GetSecurityDescriptorLength( FaxSecDesc->SecurityDescriptor ) ); if (FaxSecurity[FaxSecDesc->Id].SecurityDescriptor) { MemFree( FaxSecurity[FaxSecDesc->Id].SecurityDescriptor ); } rVal = InitializeFaxSecurityDescriptors(); RegCloseKey( hKey ); return rVal; } error_status_t FAX_GetSecurityDescriptor( IN handle_t FaxHandle, IN DWORD Id, OUT LPBYTE *Buffer, OUT LPDWORD BufferSize ) /*++ Routine Description: Retrieves the FAX configuration from the FAX server. The SizeOfStruct in the FaxConfig argument MUST be set to a value == sizeof(FAX_CONFIGURATION). If the BufferSize is not big enough, return an error and set BytesNeeded to the required size. Arguments: FaxHandle - FAX handle obtained from FaxConnectFaxServer. Buffer - Pointer to a FAX_CONFIGURATION structure. BufferSize - Size of Buffer BytesNeeded - Number of bytes needed Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { error_status_t rVal = ERROR_SUCCESS; PFAX_SECURITY_DESCRIPTOR FaxSecDesc; ULONG_PTR Offset; LPWSTR FriendlyName; DWORD DescLength; HKEY hKey; DWORD Type; DWORD Size; DWORD Disposition; if (!FaxSvcAccessCheck( SEC_CONFIG_QUERY, FAX_CONFIG_QUERY )) { return ERROR_ACCESS_DENIED; } if (Id > FaxSecurityCount) { return ERROR_INVALID_CATEGORY; } rVal = RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGKEY_FAX_SECURITY, 0, TEXT(""), 0, KEY_ALL_ACCESS, NULL, &hKey, &Disposition ); if (rVal != ERROR_SUCCESS) { return rVal; } FriendlyName = GetString( FaxSecurity[Id].StringResource ); // // count up the number of bytes needed // rVal = RegQueryValueEx( hKey, FaxSecurity[Id].RegKey, 0, &Type, NULL, &DescLength ); if (rVal != ERROR_SUCCESS) { goto exit; } Offset = sizeof(FAX_SECURITY_DESCRIPTOR); *BufferSize = (DWORD)(Offset + DescLength + (wcslen(FriendlyName) + 1) * sizeof(WCHAR)); *Buffer = MemAlloc( *BufferSize ); if (*Buffer == NULL) { rVal = ERROR_NOT_ENOUGH_MEMORY; goto exit; } FaxSecDesc = (PFAX_SECURITY_DESCRIPTOR) *Buffer; FaxSecDesc->Id = Id; StoreString( FriendlyName, (PULONG_PTR)&FaxSecDesc->FriendlyName, *Buffer, &Offset ); rVal = RegQueryValueEx( hKey, FaxSecurity[Id].RegKey, 0, &Type, *Buffer + Offset, &Size ); FaxSecDesc->SecurityDescriptor = (LPBYTE) Offset; exit: RegCloseKey( hKey ); return rVal; } BOOL PostClientMessage( PFAX_CLIENT_DATA ClientData, PFAX_EVENT FaxEvent ) /*++ Routine Description: attempts to post a message to client on another windowstation and desktop Arguments: ClientData - pointer to a FAX_CLIENT_DATA structure. FaxEvent - pointer to a FAX_EVENT structure. Return Value: TRUE - Success FALSE - Failure, call GetLastError() for more error information. --*/ { HWINSTA hWindowStation, hOldWindowStation=NULL; HDESK hDesktop, hOldDesktop=NULL; BOOL bStatus = FALSE; // // need to restore windowstation and desktop // if (! (hOldWindowStation = GetProcessWindowStation()) ) { DebugPrint(( TEXT("GetProcessWindowStation failed, ec = %d\n"), GetLastError() )); return FALSE; } if (! (hOldDesktop = GetThreadDesktop( GetCurrentThreadId() )) ) { DebugPrint(( TEXT("GetThreadDesktop failed, ec = %d\n"), GetLastError() )); return FALSE; } // // impersonate the client // if (! SetThreadToken( NULL, ClientData->hClientToken ) ) { DebugPrint(( TEXT("SetThreadToken failed, ec = %d\n"), GetLastError() )); return FALSE; } // // get a handle to the windowstation, switch to new windowstation // if (! (hWindowStation = OpenWindowStation(ClientData->WindowStation, FALSE, //bInherit, WINSTA_READATTRIBUTES | WINSTA_WRITEATTRIBUTES)) ) { DebugPrint(( TEXT("OpenWindowStation failed, ec = %d\n"), GetLastError() )); goto exit; } if (! SetProcessWindowStation( hWindowStation ) ) { DebugPrint(( TEXT("SetProcessWindowStation failed, ec = %d\n"), GetLastError() )); goto exit; } // // get a handle to the desktop, switch to new desktop // if (! (hDesktop = OpenDesktop(ClientData->Desktop, 0, FALSE, DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS)) ) { DebugPrint(( TEXT("OpenDesktop failed, ec = %d\n"), GetLastError() )); goto exit; } if (! SetThreadDesktop( hDesktop ) ) { DebugPrint(( TEXT("SetThreadDesktop failed, ec = %d\n"), GetLastError() )); goto exit; } // // post the message to the proper window if it exits // if (! IsWindow( ClientData->hWnd )) { DebugPrint(( TEXT("Hwnd %x doesn't exist on current desktop\n"), ClientData->hWnd )); goto exit; } if (! PostMessage( ClientData->hWnd, ClientData->MessageStart + FaxEvent->EventId, (WPARAM)FaxEvent->DeviceId, (LPARAM)FaxEvent->JobId )) { DebugPrint(( TEXT("PostMessage failed, ec = %d\n"), GetLastError() )); goto exit; } bStatus = TRUE; exit: // // revert to old thread context (NULL means stop impersonating) // SetThreadToken( NULL, NULL ); if (hOldWindowStation) { SetProcessWindowStation( hOldWindowStation ); CloseWindowStation( hWindowStation ); } if (hOldDesktop) { SetThreadDesktop( hOldDesktop ); CloseDesktop( hDesktop ); } return bStatus; } BOOL BuildSecureSD( OUT PSECURITY_DESCRIPTOR *SDIn ) /*++ Routine Description: builds a secure security descriptor to be used in securing a globally named object. Our "secure" SD's DACL consists of the following permissions: Authenticated users get "generic read" access. Administrators get "generic all" access. Arguments: SDIn - pointer to the PSECURITY_DESCRIPTOR to be created. Return Value: TRUE - Success, the SECURITY_DESCRIPTOR was created successfully. The caller is responsible for freeing the SECURITY_DESCRIPTOR --*/ { SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; PSID AuthenticatedUsers; PSID BuiltInAdministrators; PSECURITY_DESCRIPTOR Sd = NULL; ACL *Acl; ULONG AclSize; BOOL RetVal = TRUE; *SDIn = NULL; // // Allocate and initialize the required SIDs // if (!AllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0, &BuiltInAdministrators)) { return(FALSE); } if (!AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_AUTHENTICATED_USER_RID, 0,0,0,0,0,0,0, &AuthenticatedUsers)) { RetVal = FALSE; goto e0; } // // "- sizeof (ULONG)" represents the SidStart field of the // ACCESS_ALLOWED_ACE. Since we're adding the entire length of the // SID, this field is counted twice. // AclSize = sizeof (ACL) + (2 * (sizeof (ACCESS_ALLOWED_ACE) - sizeof (ULONG))) + GetLengthSid(AuthenticatedUsers) + GetLengthSid(BuiltInAdministrators); Sd = MemAlloc(SECURITY_DESCRIPTOR_MIN_LENGTH + AclSize); if (!Sd) { RetVal = FALSE; goto e1; } Acl = (ACL *)((BYTE *)Sd + SECURITY_DESCRIPTOR_MIN_LENGTH); if (!InitializeAcl(Acl, AclSize, ACL_REVISION)) { RetVal = FALSE; goto e2; } else if (!AddAccessAllowedAce(Acl, ACL_REVISION, SYNCHRONIZE | GENERIC_READ, AuthenticatedUsers)) { // Failed to build the ACE granting "Authenticated users" // (SYNCHRONIZE | GENERIC_READ) access. RetVal = FALSE; goto e2; } else if (!AddAccessAllowedAce(Acl, ACL_REVISION, GENERIC_ALL, BuiltInAdministrators)) { // Failed to build the ACE granting "Built-in Administrators" // GENERIC_ALL access. RetVal = FALSE; goto e2; } else if (!InitializeSecurityDescriptor(Sd, SECURITY_DESCRIPTOR_REVISION)) { RetVal = FALSE; goto e2; } else if (!SetSecurityDescriptorDacl(Sd, TRUE, Acl, FALSE)) { // error RetVal = FALSE; goto e2; } if (!IsValidSecurityDescriptor(Sd)) { DebugPrint(( TEXT("invalid security descriptor, ec = %d\n"), GetLastError() )); RetVal = FALSE; goto e2; } // // success // *SDIn = Sd; goto e1; e2: MemFree(Sd); e1: FreeSid(AuthenticatedUsers); e0: FreeSid(BuiltInAdministrators); return(RetVal); }