2011-10-03 13 views
7

Sto cercando un modo per estrarre il SID del computer usando il codice Delphi. C'è uno strumento chiamato PsGetSid di SysInternals che fa questo, ma non posso usarlo nella mia applicazione. Ho cercato un esempio di codice in Google e non sono riuscito a trovarne uno.Come estrarre il SID computer/macchina?

Come posso ottenere questo risultato in Delphi?

Per favore aiuto.

risposta

8

Questo è un esempio utilizzando il LookupAccountName Funzione WinAPi come suggerito da @MikeKwan.

{$APPTYPE CONSOLE} 

uses 
    Windows, 
    SysUtils; 


function ConvertSidToStringSid(Sid: PSID; out StringSid: PChar): BOOL; stdcall; external 'ADVAPI32.DLL' name {$IFDEF UNICODE} 'ConvertSidToStringSidW'{$ELSE} 'ConvertSidToStringSidA'{$ENDIF}; 

function SIDToString(ASID: PSID): string; 
var 
    StringSid : PChar; 
begin 
    if not ConvertSidToStringSid(ASID, StringSid) then 
    RaiseLastWin32Error; 

    Result := string(StringSid); 
end; 

function GetLocalComputerName: string; 
var 
    nSize: DWORD; 
begin 
    nSize := MAX_COMPUTERNAME_LENGTH + 1; 
    SetLength(Result, nSize); 
    if not GetComputerName(PChar(Result), {var}nSize) then 
    begin 
    Result := ''; 
    Exit; 
    end; 

    SetLength(Result, nSize); 
end; 

function GetComputerSID:string; 
var 
    Sid: PSID; 
    cbSid: DWORD; 
    cbReferencedDomainName : DWORD; 
    ReferencedDomainName: string; 
    peUse: SID_NAME_USE; 
    Success: BOOL; 
    lpSystemName : string; 
    lpAccountName: string; 
begin 
    Sid:=nil; 
    try 
    lpSystemName:=''; 
    lpAccountName:=GetLocalComputerName; 

    cbSid := 0; 
    cbReferencedDomainName := 0; 
    // First call to LookupAccountName to get the buffer sizes. 
    Success := LookupAccountName(PChar(lpSystemName), PChar(lpAccountName), nil, cbSid, nil, cbReferencedDomainName, peUse); 
    if (not Success) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then 
    begin 
     SetLength(ReferencedDomainName, cbReferencedDomainName); 
     Sid := AllocMem(cbSid); 
     // Second call to LookupAccountName to get the SID. 
     Success := LookupAccountName(PChar(lpSystemName), PChar(lpAccountName), Sid, cbSid, PChar(ReferencedDomainName), cbReferencedDomainName, peUse); 
     if not Success then 
     begin 
     FreeMem(Sid); 
     Sid := nil; 
     RaiseLastOSError; 
     end 
     else 
     Result := SIDToString(Sid); 
    end 
    else 
     RaiseLastOSError; 
    finally 
    if Assigned(Sid) then 
    FreeMem(Sid); 
    end; 
end; 


begin 
try 
    Writeln(GetComputerSID); 
except 
    on E:Exception do 
     Writeln(E.Classname, ':', E.Message); 
end; 
Writeln('Press Enter to exit'); 
Readln; 
end. 
+0

Preferisco usare l'API Win invece di WMI quando è possibile e questo è esattamente ciò di cui avevo bisogno. Grazie! – Ran

+0

GetLocalComputerName restituisce dati non corretti: se API GetComputerName ha esito positivo nSize contiene il numero o TCHARs, copiati nel buffer di output (risultato var). Quindi si deve fare setLength (result, nSize) in caso di successo –

+2

Penso che ci dovrebbe essere aggiunto alla fine di 'SIDToString': ' LocalFree (HLocal (StringSid)); ' –

0

È possibile acquistarlo con LookupAccountName. Passare in NULL per il primo parametro e il nome della macchina per il secondo.

+0

il nome della macchina che deve essere passato è lo stesso che si ottiene da GetComputerName() o dovrebbe essere in qualche altro formato? – Ran

3

È possibile utilizzare la classe WMI Win32_Account, estrarre il SID della macchina da un SID dell'account utente.

ad esempio per un account utente in cui il SID è

S-1-5-21-1299824301-1797996836-594316699-1009 

The Machine SID sarà

S-1-5-21-1299824301-1797996836-594316699 

controllare questo campione

program GetWMI_Info; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils, 
    ActiveX, 
    ComObj, 
    Variants; 

function GetComputerSID:string; 
const 
    WbemUser   =''; 
    WbemPassword  =''; 
    WbemComputer  ='localhost'; 
    wbemFlagForwardOnly = $00000020; 
var 
    FSWbemLocator : OLEVariant; 
    FWMIService : OLEVariant; 
    FWbemObjectSet: OLEVariant; 
    FWbemObject : OLEVariant; 
    oEnum   : IEnumvariant; 
    iValue  : LongWord; 
begin; 
    FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator'); 
    FWMIService := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword); 
    FWbemObjectSet:= FWMIService.ExecQuery('SELECT SID FROM Win32_Account Where SIDType=1','WQL',wbemFlagForwardOnly); 
    oEnum   := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant; 
    if oEnum.Next(1, FWbemObject, iValue) = 0 then 
    begin 
    Result:=FWbemObject.SID; 
    Result:=Copy(Result,1,LastDelimiter('-',Result)-1); 
    FWbemObject:=Unassigned; 
    end; 
end; 


begin 
try 
    CoInitialize(nil); 
    try 
     Writeln(GetComputerSID); 
    finally 
     CoUninitialize; 
    end; 
except 
    on E:EOleException do 
     Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode])); 
    on E:Exception do 
     Writeln(E.Classname, ':', E.Message); 
end; 
Writeln('Press Enter to exit'); 
Readln; 
end.