delphi - 我的程序如何检测它是否在特定域上运行?

标签 delphi winapi active-directory dns

我需要根据当前登录用户的位置限制应用程序的特定功能。由于我必须在 Delphi 中实现此逻辑,因此我不希望过度使用完整的 Active Directory/LDAP 查询。

我当前的想法是利用 DsGetDcName,并使用 DOMAIN_CONTROLLER_INFO 结构中返回的 GUID,并将其与硬编码常量进行比较。似乎有理由认为,只有重新创建域,域 GUID 才会更改,因此这将以有限的开销提供我想要的功能。我唯一担心的是我在 MSDN 上找不到任何文档来证实我的假设。

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;

ServerFault 上添加了相关问题按照建议。

Technet 上发现了另一篇有趣的读物这似乎也暗示我是对的,但并没有专门针对域 SID。

最佳答案

在域上创建服务帐户;

获取服务帐户的 GUID 并对其进行加密并将其保存在某个位置(注册表),可能作为企业安装过程的一部分来验证许可协议(protocol)。

启动客户端应用程序时,查询域服务帐户 GUID 并使用保存的 GUID 进行验证。

或者创建您自己的企业“ key ”服务器。

执行 LDAP 查询比执行所有域 Controller 的废话更容易。

关于delphi - 我的程序如何检测它是否在特定域上运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4715512/

相关文章:

c++ - 何时以编程方式卸载 SQL Server Native Client 是安全的?

c# - 在 Active Directory 中找不到锁定属性 (C#)

php - 无法联系 ldap_bind($con, $rdn, $pwd) 上的 LDAP 服务器

delphi - 在新 Hook 的 LoadEr String 方法中读取字符串列表时出现堆栈溢出异常

c++ - 如何使用 C++ 在 Windows 上创建具有 UNICODE 路径的文件

delphi - 如何及时重新绘制 Canvas ?

c++ - C/C++ 使用自动递归文件夹/目录创建复制文件

sql-server - 从 UNIX 服务器使用 Windows 身份验证连接到 SQL Server 数据库

delphi - 在delphi中访问其他.exe数据的最简单方法是什么?

delphi - 挂起子进程