2011-01-17 14 views
5

Tengo la necesidad de restringir funciones específicas de una aplicación en función de la ubicación del usuario actualmente conectado. Como tengo que implementar esta lógica en Delphi, preferiría no exagerar con las consultas de directorio activo completo/LDAP.¿Cómo puede mi programa detectar si se está ejecutando en un dominio en particular?

Mi idea principal es utilizar DsGetDcName, y usar el GUID devuelto en la estructura DOMAIN_CONTROLLER_INFO y compararlo con una constante codificada. Parece lógico que un GUID de dominio solo cambie si se recrea el dominio, por lo que esto proporcionaría la funcionalidad que deseo con una sobrecarga limitada. Mi única preocupación es que no puedo encontrar documentación en MSDN que confirme mi suposición.

type 
    EAccessDenied = Exception; 
    EInvalidOwner = Exception; 
    EInsufficientBuffer = Exception; 
    ELibraryNotFound = Exception; 

    NET_API_STATUS = Integer; 

    TDomainControllerInfoA = record 
    DomainControllerName: LPSTR; 
    DomainControllerAddress: LPSTR; 
    DomainControllerAddressType: ULONG; 
    DomainGuid: TGUID; 
    DomainName: LPSTR; 
    DnsForestName: LPSTR; 
    Flags: ULONG; 
    DcSiteName: LPSTR; 
    ClientSiteName: LPSTR; 
    end; 
    PDomainControllerInfoA = ^TDomainControllerInfoA; 

const 
    NERR_Success = 0; 

procedure NetCheck(ErrCode: NET_API_STATUS); 
begin 
    if ErrCode <> NERR_Success then 
    begin 
    case ErrCode of 
     ERROR_ACCESS_DENIED: 
     raise EAccessDenied.Create('Access is Denied'); 
     ERROR_INVALID_OWNER: 
     raise EInvalidOwner.Create('Cannot assign the owner of this object.'); 
     ERROR_INSUFFICIENT_BUFFER: 
     raise EInsufficientBuffer.Create('Buffer passed was too small'); 
     else 
     raise Exception.Create('Error Code: ' + IntToStr(ErrCode) + #13 + 
      SysErrorMessage(ErrCode)); 
    end; 
    end; 
end; 

function IsInternalDomain: Boolean; 
var 
    NTNetDsGetDcName: function(ComputerName, DomainName: PChar; DomainGuid: PGUID; SiteName: PChar; Flags: ULONG; var DomainControllerInfo: PDomainControllerInfoA): NET_API_STATUS; stdcall; 
    NTNetApiBufferFree: function (lpBuffer: Pointer): NET_API_STATUS; stdcall; 
    LibHandle: THandle; 
    DomainControllerInfo: PDomainControllerInfoA; 
    ErrMode: Word; 
const 
    NTlib = 'NETAPI32.DLL'; 
    DS_IS_FLAT_NAME = $00010000; 
    DS_RETURN_DNS_NAME = $40000000; 
    INTERNAL_DOMAIN_GUID: TGUID = '{????????-????-????-????-????????????}'; 
begin 
if Win32Platform = VER_PLATFORM_WIN32_NT then 
    begin 
    ErrMode := SetErrorMode(SEM_NOOPENFILEERRORBOX); 
    LibHandle := LoadLibrary(NTlib); 
    SetErrorMode(ErrMode); 
    if LibHandle = 0 then 
     raise ELibraryNotFound.Create('Unable to map library: ' + NTlib); 
    try 
     @NTNetDsGetDcName := GetProcAddress(Libhandle, 'DsGetDcNameA'); 
     @NTNetApiBufferFree  := GetProcAddress(Libhandle,'NetApiBufferFree'); 
     try 
     NetCheck(NTNetDsGetDcName(nil, nil, nil, nil, DS_IS_FLAT_NAME or DS_RETURN_DNS_NAME, DomainControllerInfo)); 
     Result := (DomainControllerInfo.DomainName = 'foo.com') and (CompareMem(@DomainControllerInfo.DomainGuid,@INTERNAL_DOMAIN_GUID, SizeOf(TGuid)));//WideCharToString(pDomain); 
     finally 
     NetCheck(NTNetApiBufferFree(DomainControllerInfo)); 
     end; 
    finally 
     FreeLibrary(LibHandle); 
    end; 
    end 
else 
    Result := False; 
end; 

Agregué una pregunta relacionada en ServerFault según lo sugerido.

He encontrado otra lectura interesante en Technet que también parece insinuar que estoy en lo cierto, pero no tiene un alcance específico en los dominios SID.

+0

Estoy de acuerdo en que el GUID no cambiaría, pero me gustaría señalar que ciertamente recibiría un GUID diferente si cambia el controlador de dominio. –

+1

Observando que estoy usando el GUID de dominio, no el DC GUID. Como tal (uno pensaría) requeriría degradar/eliminar todas las DC y estaciones de trabajo, y migrarlas a un nuevo dominio. Estoy bajo la suposición de que el GUID de dominio se crea cuando promociona el primer servidor a un controlador de dominio, y luego permanece vivo durante la vida del dominio. – jchoover

+0

Ok, mi mal, lo siento. Estoy de acuerdo con su suposición, desafortunadamente no lo he visto en ninguna parte. Tal vez quieras preguntar esto en [serverfault] (http://serverfault.com/). –

Respuesta

1

Si entiendo correctamente su requisito, la mejor API en su caso es GetUserNameEx. Puede elegir el valor del parámetro NameFormat del tipo EXTENDED_NAME_FORMAT que puede verificar mejor. Otra función GetComputerNameEx es útil si además desea verificar la información sobre la computadora donde se está ejecutando el programa.

+0

Sin embargo, no estoy intentando validar al usuario directamente aquí. Si bien pude obtener una variedad de respuestas, la paranoia subyacente que tengo es que alguien podría generar un nombre de dominio interno ficticio con este mismo nombre y obtener resultados incorrectos. Si puedo restringirme en base al SID del Dominio, me sentiría mucho más seguro (tal vez incorrectamente). – jchoover

0

tengo la necesidad de restringir específicos funciones de una aplicación basada en la ubicación de la sesión iniciada de usuario

Si usted está tratando de averiguar la ubicación de la que ha iniciado sesión usuario, no debe utilizar DsGetDcName.

Su computadora se puede unir a domainA. Su usuario de inicio de sesión puede ser domainB. Llamando DsGetDcName de su ordenador no se da dominioB GUID pero le dará dominioA GUID

Por lo tanto, creo que se debe utilizar en lugar LookupAccountName. El LookupAccountName le proporciona el SID del usuario que está conectado actualmente. Luego, puede extraer el SID del dominio del SID del usuario. Ese dominio SID es realmente el dominio de donde proviene este usuario. Para obtener detalles sobre cómo extraer un SID de dominio de un SID de usuario, verifique here

En relación con su pregunta original sobre la singularidad del GUID de dominio, lamento que no tenga respuesta. AFAIK, no hay ninguna herramienta disponible que le permita cambiar el SID del dominio ni el GUID. No estoy seguro de lo difícil que es hackearlo y cambiarlo.

+0

No había considerado esa ruta, sin embargo, solo se garantiza que los SID de dominio son únicos en una sola empresa. Tengo la impresión de que un GUID de dominio debe ser unívoco en todo el mundo, ya que la probabilidad de que una llamada CoCreateGUID devuelva un GUID duplicado es muy pequeña. Tal vez debería usar una combinación de los 2 métodos, la verificación GUID de dominio para asegurar el dominio correcto (no un fantasma/ficticio), y luego utilizar LookupAccountName para asegurarme de que el usuario actual es miembro de ese dominio. – jchoover

+0

@jchoover Sí, creo que entiendo lo que te preocupa. No desea que alguien configure un dominio ficticio con el mismo nombre de dominio y el mismo SID de dominio. Como dije, no veo ninguna herramienta que te ayude a asegurarte de cómo se verá el SID de un dominio. Si puede cambiar el SID del dominio (por ejemplo, cambiando el archivo NTDS.DIT ​​directamente), probablemente también pueda usar el mismo truco para cambiar el GUID del dominio. Creo que estás un poco paranoico. Hacker también puede simplemente desmontar su código y aplicarle un parche a su código para verificarlo contra su propio GUID de dominio. –

+0

@ jchoover Por cierto, estoy de acuerdo en que GUID es menos probable que sea idéntico por accidente que SID. –

2

Cree una cuenta de servicio en el dominio;

Obtenga el GUID de la cuenta de servicio y encripte y guárdelo en algún lugar (registro) tal vez como parte del proceso de instalación de la empresa para validar un acuerdo de licencia.

Al iniciarse la consulta de la aplicación del cliente para el GUID de la cuenta del servicio de dominio y validarlo con el GUID guardado.

O cree su propio servidor 'clave' empresarial.

Hacer una consulta LDAP es más fácil que hacer toda la basura del controlador de dominio.

Cuestiones relacionadas