2011-01-17 31 views
5

Tôi có nhu cầu hạn chế các chức năng cụ thể của một ứng dụng dựa trên vị trí của người dùng hiện đang đăng nhập. Như tôi đã thực hiện logic này trong Delphi, tôi không muốn đi overboard với đầy đủ thư mục hoạt động/LDAP truy vấn.Làm cách nào để chương trình của tôi có thể phát hiện xem chương trình có đang chạy trên một miền cụ thể không?

Suy nghĩ của tôi là sử dụng DsGetDcName và sử dụng GUID được trả lại trong cấu trúc DOMAIN_CONTROLLER_INFO và so sánh nó với hằng số được mã hóa cứng. Có vẻ như lý do rằng một tên miền GUID sẽ chỉ thay đổi nếu tên miền được tái tạo, do đó, điều này sẽ cung cấp chức năng mà tôi mong muốn với chi phí giới hạn. Mối quan tâm duy nhất của tôi là tôi không thể tìm thấy bất kỳ tài liệu nào về MSDN xác nhận giả định của tôi.

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; 

Đã thêm câu hỏi có liên quan trên ServerFault như được đề xuất.

Tìm thấy một cách đọc thú vị khác trên Technet cũng có vẻ gợi ý cho tôi là đúng, nhưng không được cụ thể phạm vi tại miền của SID.

+0

Tôi đồng ý rằng GUID sẽ không thay đổi nhưng tôi muốn chỉ ra rằng bạn chắc chắn sẽ nhận được GUID khác nếu bộ điều khiển miền thay đổi. –

+1

Lưu ý rằng tôi đang sử dụng tên miền GUID, không phải là hướng dẫn DC. Như vậy (người ta sẽ nghĩ) nó sẽ yêu cầu demoting/loại bỏ tất cả DC và máy trạm, và di chuyển chúng vào một tên miền mới. Tôi đang theo giả định rằng tên miền GUID được tạo ra khi bạn thúc đẩy các máy chủ đầu tiên đến một bộ điều khiển tên miền, và sau đó nó sống trên cho cuộc sống của tên miền. – jchoover

+0

Ok, xấu của tôi, xin lỗi. Tôi đồng ý với giả định của bạn, thật không may tôi đã không nhìn thấy nó tuyên bố bất cứ nơi nào. Có thể bạn muốn hỏi điều này tại [serverfault] (http://serverfault.com/). –

Trả lời

1

Nếu tôi chính xác hiểu yêu cầu của bạn, API tốt nhất trong trường hợp của bạn là GetUserNameEx. Bạn có thể chọn giá trị của thông số NameFormat của loại EXTENDED_NAME_FORMAT mà bạn có thể xác minh tốt hơn. Một chức năng khác GetComputerNameEx là hữu ích nếu bạn muốn xác minh thêm thông tin về máy tính nơi chương trình đang chạy.

+0

Tuy nhiên, tôi không cố gắng xác thực người dùng trực tiếp tại đây. Mặc dù tôi có thể nhận được nhiều phản hồi khác nhau, nhưng tình trạng hoang tưởng tiềm ẩn mà tôi có là ai đó vẫn có thể tạo một tên miền giả bên trong có cùng tên và kết quả không chính xác. Nếu tôi có thể hạn chế dựa trên Domain SID, tôi sẽ cảm thấy an toàn hơn nhiều (có thể không chính xác). – jchoover

0

tôi có nhu cầu để hạn chế chức năng cụ thể của một ứng dụng dựa trên vị trí của hiện đang đăng nhập trong sử dụng

Nếu bạn đang cố gắng tìm hiểu vị trí của hiện đang đăng nhập người dùng, bạn không nên sử dụng DsGetDcName.

Máy tính của bạn có thể được nối với tên miềnA. Người dùng đăng nhập của bạn có thể từ tên miềnB. Gọi DsGetDcName trên máy tính của bạn không cung cấp cho bạn domainB GUID nhưng nó sẽ cung cấp cho bạn domainA GUID

Vì vậy, tôi nghĩ rằng bạn nên sử dụng LookupAccountName để thay thế. LookupAccountName cung cấp cho bạn SID người dùng hiện đã đăng nhập. Sau đó, bạn có thể trích xuất miền SID từ SID người dùng. Tên miền SID đó thực sự là tên miền mà người dùng này đến từ đó. Để biết chi tiết về cách trích xuất SID miền từ SID người dùng, vui lòng kiểm tra here

Về câu hỏi ban đầu về tính độc đáo của miền GUID, tôi xin lỗi vì tôi không có câu trả lời. AFAIK, không có công cụ nào có sẵn cho phép bạn thay đổi miền SID cũng như GUID. Tôi không chắc chắn làm thế nào để hack vào nó và thay đổi nó.

+0

Tôi đã không xem xét tuyến đường đó, tuy nhiên tên miền SID chỉ được bảo đảm duy nhất trên một doanh nghiệp. Tôi theo ấn tượng rằng một tên miền GUID nên uniqe trên toàn thế giới, như xác suất của một cuộc gọi CoCreateGUID trở về một bản sao GUID là rất rất mỏng. Có lẽ tôi nên sử dụng một sự kết hợp của 2 phương pháp, tên miền GUID kiểm tra để đảm bảo tên miền thích hợp (không phải là ghosted/dummy một), và sau đó sử dụng LookupAccountName để đảm bảo người dùng hiện tại là một thành viên của tên miền đó? – jchoover

+0

@jchoover Vâng, tôi nghĩ tôi hiểu những gì bạn đang lo lắng. Bạn không muốn ai đó thiết lập miền giả với cùng tên miền và cùng một tên miền SID. Như tôi đã nói, tôi không thấy bất kỳ công cụ nào giúp bạn đảm bảo rằng tên miền SID sẽ trông như thế nào. Nếu anh ta có thể thay đổi SID miền (ví dụ: bằng cách thay đổi tệp NTDS.DIT ​​trực tiếp), anh ta có thể sử dụng cùng một mẹo để thay đổi tên miền GUID. Tôi nghĩ rằng bạn chỉ hơn hoang tưởng. Hacker cũng có thể đơn giản tháo rời mã của bạn và vá mã của bạn để kiểm tra với GUID miền của riêng mình. –

+0

@jchoover BTW, tôi đồng ý rằng GUID ít có khả năng giống hệt nhau do tai nạn hơn SID. –

2

Tạo tài khoản dịch vụ trên miền;

Nhận GUID của tài khoản dịch vụ và mã hóa nó và lưu nó ở đâu đó (đăng ký) có thể là một phần của quy trình cài đặt doanh nghiệp để xác thực thỏa thuận cấp phép.

Khi khởi động truy vấn ứng dụng khách cho GUID tài khoản dịch vụ miền và xác thực bằng GUID đã lưu.

Hoặc tạo máy chủ 'khóa' của doanh nghiệp của riêng bạn.

Thực hiện truy vấn LDAP dễ hơn làm tất cả các điều khiển miền.

Các vấn đề liên quan