C-C++ Code Example: Granting Additional Access Rights
Applies To: Windows 10, Windows 7, Windows 8, Windows 8.1, Windows Server 2008, Windows Server 2008 R2, Windows Server 2012, Windows Server 2012 R2, Windows Server Technical Preview, Windows Vista
The following example provides two application-defined functions that can be used to grant members of the Everyone group the access rights for receiving messages from an existing queue specified by the user.
The first function, QLetEveryoneRead, receives the computer name and queue name specified by the user as input parameters and calls MQGetQueueSecurity with the SecurityInformation parameter set to DACL_SECURITY_INFORMATION to obtain the discretionary access control list (DACL) from the queue's security descriptor and store it in a security descriptor buffer. MQGetQueueSecurity can be used to obtain security information for a public queue on the local or a remote computer, or for a private queue on the local computer.
The second function, ModifyDaclInfo, obtains the security identifier (SID) of the Everyone group, retrieves the DACL from the security descriptor buffer, and stores it in an ACL structure. The function next retrieves the individual access control entries(ACEs) from the ACL structure until it finds the ACE of the Everyone group by comparing their SIDs to the SID of the Everyone group. Then the function replaces this ACE with a new ACE that allows members of the Everyone group to receive messages from the queue and uses the modified DACL to set the DACL in the security descriptor of the queue.
For information about queue security, see Access Control.
An application using these functions must include the Windows.h, Stdio.h, and Mq.h header files.
To retrieve the queue's DACL and store it in a security descriptor buffer
- Validate the input strings.
Note
It is the responsibility of the caller to ensure that these strings contain only valid characters and are null-terminated.
Define the variables needed to obtain the format name.
Define the variables needed to retrieve information from the queue's security descriptor.
Generate the complete path name of the queue from the computer name and queue name passed to the function.
Call MQPathNameToFormatName to obtain the public or private format name of the queue from its path name. This format name is used to obtain the information from the queue's security descriptor. Note that a direct format name can be used to obtain information from the security descriptor of a local private queue only.
In a loop, call MQGetQueueSecurity twice with the SecurityInformation parameter set to DACL_SECURITY_INFORMATION to obtain the discretionary access control list (DACL) from the queue's security descriptor. The first call is made with a one-byte buffer to find out the size of the buffer needed. The second call, which is made after memory is allocated for the self-relative SECURITY_DESCRIPTOR structure needed to store the information, retrieves the component of security information requested (the DACL) and stores it in the security descriptor buffer.
Call the second function described in this example (ModifyDaclInfo) to retrieve the DACL from the security descriptor buffer, modify it, and set the modified DACL in the security descriptor of the queue.
Free the memory allocated for the security descriptor buffer.
Code Example
The following code example can be run on computers with Windows NT® 4.0, Windows® 2000, and newer operating systems that have Message Queuing installed.
HRESULT QLetEveryoneRead(
LPCWSTR wszComputerName,
LPCWSTR wszQueueName
)
{
// Validate the input strings.
if (wszComputerName == NULL || wszQueueName == NULL)
{
return MQ_ERROR_INVALID_PARAMETER;
}
// Define the variables needed to obtain the format name.
DWORD dwPathNameLength = 0;
WCHAR * wszPathName = NULL;
DWORD dwFormatNameBufferLength = 256; // Format name buffer length
WCHAR wszFormatNameBuffer[256]; // Format name buffer
// Define structures and variables to retrieve security information.
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL; // Pointer to the security descriptor buffer
DWORD dwBufferLength = 1;
DWORD dwBufferLengthNeeded = 1;
HRESULT hr; // Define results
// Generate the complete path name of the queue.
dwPathNameLength = wcslen(wszComputerName) + wcslen(wszQueueName) + 2;
wszPathName = new WCHAR[dwPathNameLength];
if (wszPathName == NULL)
{
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
memset(wszPathName, 0, dwPathNameLength*sizeof(WCHAR));
// ************************************
// You must concatenate wszComputerName, "\", and wszQueueName into
// the wszPathName buffer.
// wszPathName = wszComputerName + "\" + wszQueueName
// If the computer name and queue name are to large for the buffer,
// return MQ_ERROR.
// ************************************
wszPathName[dwPathNameLength - 1] = L'\0';
// Obtain the queue's format name from its path name.
hr = MQPathNameToFormatName(
wszPathName,
wszFormatNameBuffer,
&dwFormatNameBufferLength
);
if (FAILED(hr))
{
wprintf(L"The call to MQPathNameToFormatName failed. Error code: 0x%X\n", hr);
delete [] wszPathName;
return hr;
}
// Display some header information and free the memory allocated for the path name buffer.
wprintf(L"Retrieving queue security information for %s...\n\n", wszPathName );
delete [] wszPathName;
// Retrieve the DACL from the queue's security descriptor.
for ( ; ; )
{
pSecurityDescriptor = (PSECURITY_DESCRIPTOR) new byte[dwBufferLength];
hr = MQGetQueueSecurity(
wszFormatNameBuffer,
DACL_SECURITY_INFORMATION, // Retrieving only the DACL
pSecurityDescriptor,
dwBufferLength,
&dwBufferLengthNeeded
);
if (SUCCEEDED(hr))
{
break;
}
if (hr == MQ_ERROR_SECURITY_DESCRIPTOR_TOO_SMALL)
{
// Allocate the memory needed for the security descriptor buffer.
delete [] pSecurityDescriptor;
dwBufferLength = dwBufferLengthNeeded;
pSecurityDescriptor = (PSECURITY_DESCRIPTOR) new byte[dwBufferLength];
if(pSecurityDescriptor == NULL)
{
wprintf(L"Memory could not be allocated for the security descriptor buffer.\n" );
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
memset(pSecurityDescriptor, 0, dwBufferLength);
wprintf(L"Allocated %d bytes for the security descriptor buffer starting at address %d.\n",
dwBufferLength, pSecurityDescriptor);
continue;
}
wprintf(L"The call to MQGetQueueSecurity failed. Error code: 0x%X\n", hr);
delete [] pSecurityDescriptor;
return hr;
}
hr = ModifyDaclInfo(
pSecurityDescriptor,
wszFormatNameBuffer
);
if (FAILED(hr))
{
wprintf(L"ModifyDaclInfo failed. Error code: 0x%X\n", hr);
}
else hr = MQ_OK;
//Free the memory allocated for the security descriptor buffer.
delete [] pSecurityDescriptor;
return hr;
}
To modify the DACL in the queue's security descriptor
Validate the input parameters.
Call AllocateAndInitializeSid to obtain the SID of the Everyone group. In the parameters passed to AllocateAndInitializeSid, the number of subauthorities in the SID is set to 1, and the value of the first subauthority is set to SECURITY_WORLD_RID.
Call GetSecurityDescriptorDacl to obtain a pointer to the DACL in the security descriptor. If the security descriptor contains a DACL, the function sets pDacl to the address of the DACL in the security descriptor buffer. If the security descriptor does not contain a DACL, the function sets pDacl to NULL.
Call GetAclInformation to retrieve information about the DACL in an ACL_SIZE_INFORMATION structure. This information includes the number of ACEs in the DACL.
In a loop, call GetAce to retrieve a pointer to each successive ACE in the DACL and call EqualSid to compare the SID in the SidStart member of the ACE with the SID of the Everyone group until the ACE for the Everyone group is found.
Allocate memory for an ACCESS_ALLOWED_ACE structure that can hold the SID of the Everyone group, set the values of the Header.AceType and Header.AceSize members, and copy the modified access mask and the SID to the new ACE.
Note that an ACCESS_ALLOWED_ACE structure is defined with a SidStart member that contains only the first DWORD of the SID. Contiguous memory must be allocated directly after the SidStart member to accommodate the remaining bytes of the SID. To determine the amount of memory needed for the structure, the size of the SID less the size of a DWORD is added to the size of the ACCESS_ALLOWED_ACE structure.
Call DeleteAce to remove the old ACE from the DACL and then call AddAce to insert the new ACE in its place.
Call InitializeSecurityDescriptor to initialize a new SECURITY_DESCRIPTOR structure in the absolute format. An absolute SECURITY_DESCRIPTOR structure contains pointers to the security information associated with the queue. A self-relative SECURITY_DESCRIPTOR structure stores all the security information in a contiguous block of memory.
Call SetSecurityDescriptorDacl to insert the modified DACL into the new absolute SECURITY_DESCRIPTOR structure and then call MQSetQueueSecurity with this structure to set the DACL in the queue's security descriptor.
Free the memory allocated for the SID and the new ACCESS_ALLOWED_ACE structure.
Code Example
HRESULT ModifyDaclInfo(
PSECURITY_DESCRIPTOR pSecurityDescriptor,
LPCWSTR wszFormatName
)
{
// Validate the input parameters.
if (pSecurityDescriptor == NULL || wszFormatName == NULL)
{
return MQ_ERROR_INVALID_PARAMETER;
}
PSID pEveryoneSid = NULL;
SID_IDENTIFIER_AUTHORITY WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
DWORD dwSidSize = 0;
PACL pDacl = NULL;
ACL_SIZE_INFORMATION aclsizeinfo;
ACCESS_ALLOWED_ACE * pOldAce = NULL;
ACCESS_ALLOWED_ACE * pNewAce = NULL;
DWORD cAce;
SECURITY_DESCRIPTOR sdNew;
DWORD dwErrorCode = 0;
HRESULT hr = MQ_OK;
// Obtain the SID of the Everyone group.
SID_IDENTIFIER_AUTHORITY WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
if (AllocateAndInitializeSid(
&WorldAuth, // Top-level SID authority
1, // Number of subauthorities
SECURITY_WORLD_RID, // Subauthority value
0,
0,
0,
0,
0,
0,
0,
&pEveryoneSid // SID returned as OUT parameter
) == FALSE)
{
dwErrorCode = GetLastError();
wprintf(L"AllocateAndInitializeSid failed. GetLastError returned: %d\n", dwErrorCode);
return HRESULT_FROM_WIN32(dwErrorCode);
}
// Retrieve the DACL from the security descriptor buffer.
BOOL fDaclPresent = FALSE;
BOOL fDaclDefaulted = TRUE;
if (GetSecurityDescriptorDacl(
pSecurityDescriptor,
&fDaclPresent,
&pDacl,
&fDaclDefaulted
) == FALSE)
{
dwErrorCode = GetLastError();
wprintf(L"GetSecurityDescriptorDacl failed. GetLastError returned: %d\n", dwErrorCode);
return HRESULT_FROM_WIN32(dwErrorCode);
}
// Check whether no DACL or a NULL DACL was retrieved from the security descriptor buffer.
if ((fDaclPresent == FALSE) || (pDacl == NULL))
{
wprintf(L"No DACL was found (all access is denied), or a NULL DACL (unrestricted access) was found.\n");
return MQ_OK;
}
// Retrieve the ACL_SIZE_INFORMATION structure containing the number of ACEs in the DACL.
if (GetAclInformation(
pDacl,
&aclsizeinfo,
sizeof(aclsizeinfo),
AclSizeInformation
) == FALSE)
{
dwErrorCode = GetLastError();
wprintf(L"GetAclInformation failed. GetLastError returned: %d\n", dwErrorCode);
return HRESULT_FROM_WIN32(dwErrorCode);
}
// Loop through the ACEs to find the ACE for the Everyone group.
for (cAce = 0; cAce < aclsizeinfo.AceCount && hr == MQ_OK; cAce++)
{
// Retrieve the security information in the ACE.
if (GetAce(
pDacl, // Pointer to the DACL
cAce, // Index of the ACE in the DACL
(LPVOID*)&pOldAce // Pointer to an ACE structure
) == FALSE)
{
wprintf(L"GetAce failed. GetLastError returned: %d\n", GetLastError());
continue;
}
// Compare the SID in the ACE with the SID of the Everyone group.
if (EqualSid((PSID)&pOldAce->SidStart, pEveryoneSid))
{
// Allocate memory for a new ACE, set the values of
// Header.AceType and Header.AceSize in the new ACE,
// and copy the modified mask and the SID to the new ACE.
dwSidSize = GetLengthSid((PSID)&pOldAce->SidStart);
DWORD dwAceSize = sizeof(ACCESS_ALLOWED_ACE) + dwSidSize - sizeof(DWORD);
pNewAce = (ACCESS_ALLOWED_ACE*) new BYTE[dwAceSize];
memset(pNewAce, 0, dwAceSize);
pNewAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
pNewAce->Header.AceSize = (WORD)dwAceSize;
pNewAce->Mask = pOldAce->Mask | MQSEC_RECEIVE_MESSAGE;
if (CopySid(
dwSidSize,
(PSID)&pNewAce->SidStart,
(PSID)&pOldAce->SidStart
) == FALSE)
{
dwErrorCode = GetLastError();
wprintf(L"CopySid failed. GetLastError returned: %d\n", dwErrorCode);
hr = HRESULT_FROM_WIN32(dwErrorCode);
break;
}
// Delete the old ACE from the DACL.
if (DeleteAce(
pDacl, // Pointer to the DACL
cAce // Index of the ACE in the DACL
) == FALSE)
{
dwErrorCode = GetLastError();
wprintf(L"DeleteAce failed. GetLastError returned: %d\n", dwErrorCode);
hr = HRESULT_FROM_WIN32(dwErrorCode);
break;
}
// Insert the modified ACE into the DACL.
if (AddAce(
pDacl, // Pointer to the DACL
ACL_REVISION, // For ACCESS_ALLOWED_ACE_TYPE
cAce, // Index of the ACE
pNewAce, // Pointer to the new ACE
dwAceSize // Length of the new ACE
) == FALSE)
{
dwErrorCode = GetLastError();
wprintf(L"AddAce failed. GetLastError returned: %d\n", dwErrorCode);
hr = HRESULT_FROM_WIN32(dwErrorCode);
break;
}
// Initialize a new absolute SECURITY_DESCRIPTOR structure.
if (InitializeSecurityDescriptor(
&sdNew,
SECURITY_DESCRIPTOR_REVISION // Required constant
) == FALSE)
{
dwErrorCode = GetLastError();
wprintf(L"InitializeSecurityDescriptor failed. GetLastError returned: %d\n", dwErrorCode);
hr = HRESULT_FROM_WIN32(dwErrorCode);
break;
}
// Insert the modified DACL into the new absolute
// SECURITY_DESCRIPTOR structure.
if (SetSecurityDescriptorDacl(
&sdNew,
TRUE,
pDacl,
FALSE
) == FALSE)
{
dwErrorCode = GetLastError();
wprintf(L"SetSecurityDescriptorDacl failed. GetLastError returned: %d\n", dwErrorCode);
hr = HRESULT_FROM_WIN32(dwErrorCode);
break;
}
// Use the absolute SECURITY_DESCRIPTOR structure containing the modified
// DACL to set the DACL in the queue's security descriptor.
hr = MQSetQueueSecurity(
wszFormatName,
DACL_SECURITY_INFORMATION,
&sdNew
);
if (FAILED(hr))
{
wprintf(L"The call to MQSetQueueSecurity failed. Error code: 0x%X\n", hr);
}
break;
}
}
// Free the memory allocated for buffers.
delete [] pNewAce;
FreeSid(pEveryoneSid);
return hr;
}