C-C++ Code Example: Validating Authentication

 

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

This example provides an application-defined function that peeks at the PROPID_M_AUTHENTICATED_EX property of all the messages in a known queue, displaying the type of signature that was used to sign any messages that requested authentication.

For information on how Message Queuing authenticates messages, see Message Authentication.

This example uses the PROPID_M_AUTHENTICATED_EX property (introduced in MSMQ 2.0) to validate authentication and to determine what type of signature was used to sign the message. Receiving applications using earlier versions of Message Queuing must use the PROPID_M_AUTHENTICATED property that can only validate that authentication was requested.

To validate authentication

  1. Define the constants, variables, and structures needed by the function.

  2. Specify PROPID_M_AUTHENTICATED_EX.

  3. Initialize the MQMSGPROPS structure.

  4. Generate a format name for opening the queue.

Note

wcslen properly handles only null-terminated strings. This code example does not verify that the strings passed to it are null-terminated. It is the responsibility of the caller to ensure that the strings passed are null-terminated.

  1. Call MQOpenQueue to open the queue with receive access. Receive access allows the application to peek at or remove the messages in the queue.

  2. Call MQCreateCursor to create the cursor for navigating the queue. The returned cursor handle is used in the calls to read messages.

  3. Call MQReceiveMessage with peek access to peek at the first message in the queue. This call also initializes the cursor so that the cursor points at the first message in the queue.

  4. In a loop structure, continue to call MQReceiveMessage to peek at each message in the queue.

  5. Call MQCloseQueue and MQCloseCursor to free the resources.

Code Example

The following code example requires MSMQ 2.0 or later.

HRESULT ValidatingAuthentication(  
                                 WCHAR * wszQueueName,  
                                 WCHAR * wszComputerName  
                                 )  
{  
  
  // Validate the input strings.  
  if (wszQueueName == NULL || wszComputerName == NULL)  
  {  
    return MQ_ERROR_INVALID_PARAMETER;  
  }  
  
  // Define constants, variables, and structures.  
  const int NUMBEROFPROPERTIES = 5;                   // Number of properties  
  DWORD cPropId = 0;                                  // Property counter  
  
  MQMSGPROPS msgProps;  
  MSGPROPID aMsgPropId[NUMBEROFPROPERTIES];  
  MQPROPVARIANT aMsgPropVar[NUMBEROFPROPERTIES];  
  HRESULT aMsgStatus[NUMBEROFPROPERTIES];  
  
  // Specify the message properties to be retrieved.  
  aMsgPropId[cPropId] = PROPID_M_AUTHENTICATED_EX;    // Property ID  
  aMsgPropVar[cPropId].vt = VT_NULL;                  // Type indicator  
  cPropId++;  
  
  // Initialize the MQMSGPROPS structure.  
  msgProps.cProp = cPropId;                          // Number of message properties  
  msgProps.aPropID = aMsgPropId;                     // IDs of the message properties  
  msgProps.aPropVar = aMsgPropVar;                   // Values of the message properties  
  msgProps.aStatus = aMsgStatus;                     // Error reports  
  
  // Generate a format name from the queue name and the computer name.  
  WCHAR * wszFormatName = NULL;  
  DWORD dwFormatNameLength = 0;  
  dwFormatNameLength = wcslen(wszQueueName) + wcslen(wszComputerName) + 12;  
  wszFormatName = new WCHAR[dwFormatNameLength];  
  if (wszFormatName == NULL)  
  {  
    return MQ_ERROR_INSUFFICIENT_RESOURCES;  
  }  
  memset(wszFormatName, 0, dwFormatNameLength*sizeof(WCHAR));  
  // ************************************  
  // You must concatenate "DIRECT=OS:", wszComputerName, "\", and   
  // wszQueueName into the wszFormatName buffer.  
  // wszFormatName = "DIRECT=OS:" + wszComputerName + "\" +    
  // wszQueueName  
  // If the format name is too long for the buffer, return FALSE.  
  // ************************************  
  
  // Open the queue to read messages.  
  HRESULT hr = MQ_OK;                                         // Return code  
  HANDLE hQueue = NULL;                               // Queue handle  
  hr = MQOpenQueue(  
                   wszFormatName,                     // Format name of the queue  
                   MQ_RECEIVE_ACCESS,                 // Access mode  
                   MQ_DENY_RECEIVE_SHARE,             // Share mode  
                   &hQueue                            // [out] Queue handle  
                   );  
  
  // Free the memory that was allocated for the format name string.  
  delete [] wszFormatName;  
  
  // Handle any error returned by MQOpenQueue.  
  if (FAILED(hr))  
  {  
    return hr;  
  }  
  
  // Create the cursor used to navigate through the queue.  
  HANDLE hCursor = NULL;                              // Cursor handle  
  hr = MQCreateCursor(  
                      hQueue,                         // Queue handle  
                      &hCursor                        // [out] Cursor handle  
                      );  
  if (FAILED(hr))  
  {  
    MQCloseQueue(hQueue);  
    return hr;  
  }  
  
  // Peek at the first message in the queue.  
  hr = MQReceiveMessage(  
                        hQueue,                       // Queue handle  
                        0,                            // Maximum time (msec) to read the message  
                        MQ_ACTION_PEEK_CURRENT,       // Receive action  
                        &msgProps,                    // Message property structure  
                        NULL,                         // No OVERLAPPED structure  
                        NULL,                         // No callback function  
                        hCursor,                      // Cursor handle  
                        MQ_NO_TRANSACTION             // Not in a transaction  
                        );  
  if (FAILED(hr))  
  {  
    MQCloseCursor(hCursor);  
    MQCloseQueue(hQueue);  
    return hr;  
  }  
  
  // Peek at all messages in the queue and check whether   
  // authentication was requested.  
  
  while (SUCCEEDED(hr))  
  {  
    switch(msgProps.aPropVar[0].bVal)  
      {  
      case MQMSG_AUTHENTICATION_NOT_REQUESTED:   
        wprintf(L"Not an authenticated message.\n");  
        break;  
  
      case MQMSG_AUTHENTICATED_SIG10:  
        wprintf(L"Authenticated message. Signed with an MSMQ 1.0 signature.\n");  
        break;  
  
      case MQMSG_AUTHENTICATED_SIG20:  
        wprintf(L"Authenticated message. Signed with an MSMQ 2.0 signature.\n");  
        break;  
  
      case MQMSG_AUTHENTICATED_SIG30:  
        wprintf(L"Authenticated message. Signed with an MSMQ 3.0 multiple-destination digital signature.\n");  
        break;  
  
      case MQMSG_AUTHENTICATED_SIGXML:  
        wprintf(L"Authenticated message. Signed with an XML digital signature.\n");  
        break;  
     }  
  
    hr = MQReceiveMessage(  
                          hQueue,                     // Queue handle  
                          0,                          // Maximum time (msec) to read message  
                          MQ_ACTION_PEEK_NEXT,        // Receive action  
                          &msgProps,                  // Message property structure  
                          NULL,                       // No OVERLAPPED structure  
                          NULL,                       // No callback function  
                          hCursor,                    // Cursor handle  
                          MQ_NO_TRANSACTION           // Not in a transaction  
                          );  
  }  
  
  // Close the cursor and the queue.  
  hr = MQCloseCursor(hCursor);  
  if (FAILED(hr))  
  {  
    MQCloseQueue(hQueue);  
    return hr;  
  }  
  
  hr = MQCloseQueue(hQueue);  
  return hr;  
}