Search code examples
c#winapipinvoke

Retrieving privilege name from LUID


I am writing a method for finding out the privilege name associated with a given LUID. The following is the code for the same :

private string PrivilegeName(LUID luid)
{
    StringBuilder sbuilder = new StringBuilder();
    int nameLength = 0;
    IntPtr ptrToLuid = Marshal.AllocHGlobal(Marshal.SizeOf(luid));
    Marshal.StructureToPtr(luid, ptrToLuid, true);
    if(!InvokeAPI.LookupPrivilegeName(null, ptrToLuid, null, ref nameLength))
    {
        Console.WriteLine("Unable to lookup value.");
        Console.WriteLine(Marshal.GetLastWin32Error());
        Marshal.FreeHGlobal(ptrToLuid);
        return null;
    }
    sbuilder.EnsureCapacity(nameLength + 1);

    InvokeAPI.LookupPrivilegeName(null, ptrToLuid, sbuilder, ref nameLength);
    Marshal.FreeHGlobal(ptrToLuid);

    return sbuilder.ToString();
}

For reference my LUID structure looks like this

[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
    public UInt32 LowPart;
    public Int32 HighPart;
}

While executing this code I get a ERROR_INSUFFICIENT_BUFFER (122) instead of the privilege name associated with the LUID.

Could someone help me out on what I am missing in the above code that prevents me from retrieving the privilege name ?


Solution

  • Written "better" pinvoke, written inside a comment an explanation of the error. Written inside comments the funny handling of lengths of LookupPrivilegeName.

    // https://www.pinvoke.net/default.aspx/advapi32.lookupprivilegename
    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool LookupPrivilegeName(
        string lpSystemName,
        ref LUID lpLuid,
        StringBuilder lpName,
        ref int cchName);
    
    private static string PrivilegeName(LUID luid)
    {
        StringBuilder sbuilder = new StringBuilder();
        int nameLength = 0;
    
        LookupPrivilegeName(null, ref luid, sbuilder, ref nameLength);
    
        // Will always fail with nameLength == 0. We simply check that nameLength != 0
        if (nameLength == 0)
        {
            Console.WriteLine("Unable to lookup value.");
            Console.WriteLine(Marshal.GetLastWin32Error());
            return null;
        }
    
        // On "failure" (that is really a success, only we get 
        // just the length), nameLength is the length required 
        // for the buffer, including the \0
        sbuilder.EnsureCapacity(nameLength);
    
        // On a success of this second call, nameLength is the 
        // "real" length of the name, excluding the \0
        // so on a success, now nameLength = oldNameLength - 1
        // Don't ask, it is absurd... Classical case where the 
        // Windows API are quite random in their handling of 
        // buffer lengths
        if (!LookupPrivilegeName(null, ref luid, sbuilder, ref nameLength))
        {
            Console.WriteLine("Unable to lookup value.");
            Console.WriteLine(Marshal.GetLastWin32Error());
            return null;
        }
    
        return sbuilder.ToString();
    }