4 Protocol Example

In this scenario, the client wants to translate a group of SIDs to their corresponding names. The client starts the communication by sending an LsarOpenPolicy2 request with the following parameters:

 NTSTATUS
 LsarOpenPolicy2(
     [in,unique,string] wchar_t* SystemName = "arbitrary string",
     [in] PLSAPR_OBJECT_ATTRIBUTES ObjectAttributes,
     [in] ACCESS_MASK DesiredAccess = 0x00000800,
     [out] LSAPR_HANDLE *PolicyHandle
     );

where ObjectAttributes is:

  
 typedef struct _LSAPR_OBJECT_ATTRIBUTES {
     unsigned long Length = 0;
     unsigned char *RootDirectory = NULL;
     PSTRING ObjectName = NULL;
     unsigned long Attributes = 0;
     PLSAPR_SECURITY_DESCRIPTOR SecurityDescriptor = NULL;
     PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService = NULL;
 } LSAPR_OBJECT_ATTRIBUTES, *PLSAPR_OBJECT_ATTRIBUTES;

The server receives this request and performs an access check for the desired access. When successful, the server returns a context handle for the client's use and STATUS_SUCCESS as the return value. That is:

 NTSTATUS = 0x00000000
 LsarOpenPolicy2(
     [in,unique,string] wchar_t* SystemName = {unchanged}
     [in] PLSAPR_OBJECT_ATTRIBUTES ObjectAttributes = {unchanged},
     [in] ACCESS_MASK DesiredAccess = {unchanged},
     [out] LSAPR_HANDLE *PolicyHandle = {context handle}
     );

The client receives this response and sends an LsarLookupSids2 request to translate the batch of SIDs to names with the following parameters:

 NTSTATUS
 LsarLookupSids2(
     [in] LSAPR_HANDLE PolicyHandle = 
             {handle returned by LsarOpenPolicy2},
     [in] PLSAPR_SID_ENUM_BUFFER SidEnumBuffer,
     [out] PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
     [in, out] PLSAPR_TRANSLATED_NAMES_EX TranslatedNames =
             {address of a local variable initialized
              with zeroes},
     [in] LSAP_LOOKUP_LEVEL LookupLevel = LsapLookupWksta,
     [in, out] unsigned long *MappedCount = 
             {address of a local variable initialized to 0},
     [in] unsigned long LookupOptions = 0,
     [in] unsigned long ClientRevision = 2
     );

where SidEnumBuffer is:

  
 typedef struct _LSAPR_SID_ENUM_BUFFER {
     unsigned long Entries = {3};
     [size_is(Entries)] PLSAPR_SID_INFORMATION SidInfo;
 } LSAPR_SID_ENUM_BUFFER, *PLSAPR_SID_ENUM_BUFFER;

and SidInfo array is:

 SidInfo[0] = 
 typedef struct _LSAPR_SID_INFORMATION {
     PRPC_SID Sid = { SID0 };
 } LSAPR_SID_INFORMATION, *PLSAPR_SID_INFORMATION;
  
 SidInfo[1] = 
 typedef struct _LSAPR_SID_INFORMATION {
     PRPC_SID Sid = { SID1 };
 } LSAPR_SID_INFORMATION, *PLSAPR_SID_INFORMATION;
  
 SidInfo[2] = 
 typedef struct _LSAPR_SID_INFORMATION {
     PRPC_SID Sid = { SID2 };
 } LSAPR_SID_INFORMATION, *PLSAPR_SID_INFORMATION;

The server receives this call and performs the translation explained in message processing in section 3.1.4.10. The server prepares the results, and returns them to the caller with a return value of STATUS_SUCCESS. The results might resemble the following:

 NTSTATUS = 0x00000000
 LsarLookupSids2(
     [in] LSAPR_HANDLE PolicyHandle = {unchanged},
     [in] PLSAPR_SID_ENUM_BUFFER SidEnumBuffer = {unchanged},
     [out] PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
     [in, out] PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
     [in] LSAP_LOOKUP_LEVEL LookupLevel = {unchanged},
     [in, out] unsigned long *MappedCount = { 3 },
     [in] unsigned long LookupOptions = {unchanged},
     [in] unsigned long ClientRevision = {unchanged}
     );

where ReferencedDomains is:

 typedef struct _LSAPR_REFERENCED_DOMAIN_LIST {
     unsigned long Entries = { 2 };
     [size_is(Entries)] PLSAPR_TRUST_INFORMATION Domains;
     unsigned long MaxEntries = { 0 };
 } LSAPR_REFERENCED_DOMAIN_LIST, *PLSAPR_REFERENCED_DOMAIN_LIST;

and Domains array is:

 Domains[0] = 
 typedef struct _LSAPR_TRUST_INFORMATION {
     RPC_UNICODE_STRING Name = { "Domain0" };
     PRPC_SID Sid = { DomainSID0 };
 } LSAPR_TRUST_INFORMATION, *PLSAPR_TRUST_INFORMATION;
  
 Domains[1] = 
 typedef struct _LSAPR_TRUST_INFORMATION {
     RPC_UNICODE_STRING Name = { "Domain1" };
     PRPC_SID Sid = { DomainSID1 };
 } LSAPR_TRUST_INFORMATION, *PLSAPR_TRUST_INFORMATION;

TranslatedNames might appear as follows:

 typedef struct _LSAPR_TRANSLATED_NAMES_EX {
     unsigned long Entries = { 3 };
     [size_is(Entries)] PLSAPR_TRANSLATED_NAME_EX Names;
 } LSAPR_TRANSLATED_NAMES_EX, *PLSAPR_TRANSLATED_NAMES_EX;

where Names array is:

 Names[0] = 
 typedef struct _LSAPR_TRANSLATED_NAME_EX {
     SID_NAME_USE Use = { SidTypeUser };
     RPC_UNICODE_STRING Name = { "Name0" };
     long DomainIndex = { 0 };
     unsigned long Flags = { 0 };
 } LSAPR_TRANSLATED_NAME_EX, *PLSAPR_TRANSLATED_NAME_EX;
  
 Names[1] = 
 typedef struct _LSAPR_TRANSLATED_NAME_EX {
     SID_NAME_USE Use = { SidTypeDomain };
     RPC_UNICODE_STRING Name = { "DomainName0" };
     long DomainIndex = { 0 };
     unsigned long Flags = { 0 };
 } LSAPR_TRANSLATED_NAME_EX, *PLSAPR_TRANSLATED_NAME_EX;
  
 Names[2] = 
 typedef struct _LSAPR_TRANSLATED_NAME_EX {
     SID_NAME_USE Use = { SidTypeUser };
     RPC_UNICODE_STRING Name = { "Name3" };
     long DomainIndex = { 1 };
     unsigned long Flags = { 0 };
 } LSAPR_TRANSLATED_NAME_EX, *PLSAPR_TRANSLATED_NAME_EX;

The client receives this response, and extracts the names from the returned information. It then sends an LsarClose request to release the context handle that was opened in the first call:

 NTSTATUS
 LsarClose(
     [in,out] LSAPR_HANDLE *ObjectHandle 
             = {handle returned by LsarOpenPolicy2}
     );

The server receives this call, and releases the handle. It responds to the caller with a return value of STATUS_SUCCESS:

 NTSTATUS = 0x00000000
 LsarClose(
     [in,out] LSAPR_HANDLE *ObjectHandle = {0}
     );
Show: