【发布时间】:2011-01-17 16:37:21
【问题描述】:
我需要根据当前登录用户的位置来限制应用程序的特定功能。因为我必须在 Delphi 中实现这个逻辑,所以我不希望过度使用完整的活动目录/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 不会更改,但我想指出,如果域控制器发生更改,您肯定会收到不同的 GUID。
-
注意我使用的是域 GUID,而不是 DC guid。因此(有人会认为)它需要降级/删除所有 DC 和工作站,并将它们迁移到新域。我假设域 GUID 是在您将第一台服务器提升为域控制器时创建的,然后它在域的生命周期内一直存在。
-
好吧,我的错,对不起。我同意你的假设,不幸的是我没有在任何地方看到它。也许您想通过serverfault 提问。
标签: delphi winapi active-directory dns