SteveL
SteveL

Reputation: 319

Translate SID to name

My Delphi 2010 application needs to add a Windows user to the local Administrators group. I got this part working using NetLocalGroupAddMembers.

Now the application needs to work in localized versions of Windows with other languages. For this I am using the SID with the LsaLookupSids function to get the translated name of the group, but am unable to do it because I don't know how to make the API call.

I would be grateful is someone could please show me how to use the LsaLookupSids function to get the group name ('Administrators' in English US version of Windows) from the SID.

Following is my code:

function AddUser(const username, password: PChar; resetpassword: boolean): boolean; stdcall;
var
  NetApiStatus: NET_API_STATUS;
  UserInfo1003: USER_INFO_1003;
  UserInfo1005: USER_INFO_1005;
  ui: USER_INFO_1;
  grp: String;
  sid: PSID;
  snu: SID_NAME_USE;
  sidsize: LongWord;
  refdomain: PLsaReferencedDomainList; //array [0..MAX_PATH - 1] of char;
  refdomainsize: LongWord;
  sidstring: PChar;
  lgmi3: _LOCALGROUP_MEMBERS_INFO_3;
  reftranname: PLsaTranslatedName;
begin
  if UserExists(username) then begin


    sidstring := PChar('S-1-5-32-544'); //Local Administrators group

    refdomain := AllocMem(SizeOf(refdomain));
    FillChar(refdomain, SizeOf(refdomain), 0);

    reftranname := AllocMem(SizeOf(reftranname));

    sidsize := 0;
    sid := nil;
    sid := AllocMem(Length(sidstring) );
    sid := PChar(sidstring);
    try
      LsaLookupSids(GetPolicyHandle, 1, sid, refdomain, reftranname);
      grp := reftranname^.Name.Buffer;
      showmessage('messg ' + grp);
    finally
      FreeMem(sid, sidsize);
    end;
  end;

Upvotes: 3

Views: 4015

Answers (2)

Remko
Remko

Reputation: 7340

You don't need LsaLookupSids, this is meant for lookup or an array of SID's. Lookup of a single SID is usually done using LookupAccountSid. Example:

uses JwaWindows; // or JwaSddl, JwaWinBase;
    var
      Sid: PSID;
      peUse: DWORD;
      cchDomain: DWORD;
      cchName: DWORD;
      Name: array of Char;
      Domain: array of Char;
    begin
      Sid := nil;
      // First convert String SID to SID
      Win32Check(ConvertStringSidToSid(PChar('S-1-5-32-544'), Sid));

      cchName := 0;
      cchDomain := 0;
      // Get Length
      if (not LookupAccountSid(nil, Sid, nil, cchName, nil, cchDomain, peUse))
        and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
      begin
        SetLength(Name, cchName);
        SetLength(Domain, cchDomain);
        if LookupAccountSid(nil, Sid, @Name[0], cchName, @Domain[0], cchDomain, peUse) then
        begin
           // note: cast to PChar because LookupAccountSid returns zero terminated string
           ShowMessageFmt('%s\%s', [PChar(Domain), PChar(Name)]);
        end;
      end;

      if Assigned(Sid) then
        LocalFree(DWORD(Sid));

or even easier using Jwscl:

uses JwsclSid;

    var
      Sid: TJwSecurityId;
    begin
      Sid := TJwSecurityId.Create('S-1-5-32-544');
      try
        ShowMessage(Sid.GetAccountName);
      finally
        Sid.Free;
      end;

Upvotes: 6

Krystian Bigaj
Krystian Bigaj

Reputation: 1285

Simple example using JCL. You also could same using http://blog.delphi-jedi.net/security-library/ (like TJwSecurityId).

This code does not use LsaLookupSids, but internally LookupAccountSid (but for local group I don't think that it does matter).

uses
  JclSecurity, JclWin32;

// Raises exception in case of invalid ASID or if SID is not found
function GetNameFromSid(ASID: String): String;
var
  lSidLen: DWORD;
  lSid: PSID;
  lName, lDomain: WideString;
begin
  lSidLen := SECURITY_MAX_SID_SIZE;

  lSid := AllocMem(lSidLen);
  try
    StringToSID(ASID, lSid, lSidLen);
    LookupAccountBySid(lSid, lName, lDomain);
    Result := lName;
  finally
    FreeMem(lSid);
  end;
end;

Upvotes: 4

Related Questions