2011-10-03 7 views
7

Estoy buscando una forma de extraer el SID de la computadora usando el código Delphi. Hay una herramienta llamada PsGetSid de SysInternals que hace esto, pero no puedo usarlo en mi aplicación. Busqué un código de ejemplo en Google y no pude encontrar uno.¿Cómo extraer el SID de la computadora/máquina?

¿Cómo puedo lograr esto en Delphi?

Por favor ayuda.

Respuesta

8

Esta es una muestra usando el LookupAccountName La función de WinAPi como @MikeKwan sugiere.

{$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

Prefiero usar Win API en lugar de WMI cuando sea posible y esto es exactamente lo que necesitaba. ¡Gracias! – Ran

+0

GetLocalComputerName devuelve datos incorrectos: si GetComputerName API tiene éxito nSize contiene el número o TCHAR, copiado en el búfer de salida (var resultado). Por lo tanto uno tiene que hacer setLength (resultado, nSize) en el éxito –

+2

Creo que debería agregarse al final de 'SIDToString': ' LocalFree (HLocal (StringSid)); ' –

0

Lo puede obtener con LookupAccountName. Pase en NULL para el primer parámetro y el nombre de la máquina para el segundo.

+0

El nombre de la máquina que se debe pasar es el mismo que se obtiene de GetComputerName() o debería estar en algún otro formato? – Ran

3

Puede usar la clase WMI Win32_Account, extrayendo el SID de la máquina desde un SID de la cuenta de usuario.

por ejemplo para una cuenta de usuario en el que el SID es

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

El SID de la máquina será

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

Comprobar esta muestra

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. 
Cuestiones relacionadas