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.
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. –
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
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/). –