Question:
We’re trying to:
- Get the Logon Windows NT id for an Exchange mail box
- Get the Security Identifier (SID) corresponding to the Windows NT id (using advapi32.dll api’s)
- Map this SID with Assoc-NT-Account (which stores the SID) on Exchange server and get the corresponding mailbox information
I am having difficulty getting the SID (step 2). I am calling LookupAccountName() from advapi32.dll in Visual Basic. The return value of the LookupAccountName iscoming up as 0, but the GetLastError is also returning 0. What could be the problem?
Here is the code I am using:
' Advanced Windows 32 Base API Private Declare Function LookupAccountSid Lib
"advapi32.dll" _ Alias "LookupAccountSidA" (ByVal
lpSystemName As String, _ Sid As Any, ByVal name As String,
cbName As Long, ByVal ReferencedDomainName As String, _ cbReferencedDomainName As Long, peUse As
Integer) As Long Private Declare Function LookupAccountName
Lib "advapi32.dll" _ Alias "LookupAccountNameA" (ByVal
lpSystemName As String, _ ByVal lpAccountName As String,
Sid As Long, cbSid As Long, _ ByVal ReferencedDomainName
As String, cbReferencedDomainName As Long, peUse As Integer) As Long Private Declare Function GetLastError Lib
"kernel32" () As LongPrivate Function GetSID() Dim sUserName As String Dim sDomainName As String Dim sServerName As String Dim SIDSize As Long Dim DNSize As Long Dim SIDData As Long Dim iType As Integer Dim ret_val As Long sUser = "Sharmaan" 'sDomainName = "COMPAQ-GROUP" sServerName = "" DNSize = 255 ret_val = LookupAccountName(sServerName,
sUser, SIDData, SIDSize, sDomainName, DNSize, iType) If ret_val = 0 Then Debug.Print "Last Error:"; GetLastError() Else If DNSize > 0 Then sDomainName = Left$(sDomainName,
DNSize) & "" Else sDomainName = "" End If End If Debug.Print "SID:"; SIDData End FunctionPrivate Sub Form_Load()GetSIDEnd Sub
Answer:
First, never, ever use GetLastError from VB 5.0/6.0. Use Err.LastDllError instead. VB “masks” the errors you get from the actual API calls, so you get back either no error or the incorrect error.
Next, the following code should get you back a byte array of the user’s SID:
Option ExplicitDeclare Function LookupAccountName _ Lib "advapi32.dll" Alias "LookupAccountNameA" _ (ByVal lpSystemName As String, _ ByVal lpAccountName As String, _ sid As Any, _ cbSid As Long, _ ReferencedDomainName As Any, _ cbReferencedDomainName As Long, _ peUse As Integer) As LongPublic Sub Main() GetSid "administrator"End SubPublic Sub GetSid(ByVal xi_strUserName As String) Dim p_intUse As Integer Dim p_strAcctName As String Dim p_strSID_Account As String Dim p_strSID_Domain As String Dim p_strDomainName As String Dim p_lngAcctLength As Long Dim p_lngDomainLength As Long Dim p_lngSID_Length As Long Dim p_lngNumRIDs As Long Dim p_lngRtn As Long Dim p_abytSID() As Byte Dim p_abytDomain() As Byte Dim p_strDomain As String ' Preinitialize p_abytSID array with one ' element. It will be redimmed lated ReDim p_abytSID(1) As Byte p_strAcctName = xi_strUserName p_lngRtn = LookupAccountName(vbNullString, _ p_strAcctName, _ p_abytSID(0), _ p_lngSID_Length, _ p_strDomainName, _ p_lngDomainLength, _ p_intUse) ' Call fails but puts in required buffers size ' in p_lngSID_Length and ' p_lngDomainLength variables ReDim p_abytSID(p_lngSID_Length) As Byte ReDim p_abytDomain(p_lngDomainLength) As Byte p_lngRtn = LookupAccountName(vbNullString, _ p_strAcctName, _ p_abytSID(0), _ p_lngSID_Length, _ p_abytDomain(0), _ p_lngDomainLength, _ p_intUse) p_strDomain = Mid$(StrConv(p_abytDomain, _ vbUnicode), 1, p_lngDomainLength) Debug.Print "Domain Name: " & p_strDomain ' Reset the lengths p_lngAcctLength = 0 p_lngDomainLength = 0 Dim p_lngLoop For p_lngLoop = 0 To 28 Debug.Print p_lngLoop & ": " & _ Hex$(p_abytSID(p_lngLoop)) Next p_lngLoop End Sub