Как моя программа может определить, работает ли она на определенном домене? - PullRequest
5 голосов
/ 17 января 2011

У меня есть необходимость ограничить определенные функции приложения в зависимости от местоположения текущего пользователя, вошедшего в систему. Поскольку я должен реализовать эту логику в Delphi, я бы предпочел не переусердствовать с полностью активными запросами каталогов / LDAP.

Моя настоящая мысль - использовать DsGetDcName и использовать GUID, возвращенный в структуре DOMAIN_CONTROLLER_INFO, и сравнить его с жестко закодированной константой. Кажется, причина того, что 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 домена.

Ответы [ 3 ]

2 голосов
/ 24 марта 2011

Создайте учетную запись службы в домене;

Получите GUID учетной записи службы, зашифруйте ее и сохраните где-нибудь (реестр), возможно, в рамках процесса установки предприятия для проверки лицензионного соглашения.

При запуске клиентского приложения запросите GUID учетной записи службы домена и подтвердите его с сохраненным GUID.

Или создайте свой собственный корпоративный «ключевой» сервер.

Выполнение запроса LDAP проще, чем всякое дерьмо на контроллере домена.

1 голос
/ 18 января 2011

Если я правильно понимаю ваше требование, лучшим API в вашем случае будет GetUserNameEx .Вы можете выбрать значение параметра NameFormat типа EXTENDED_NAME_FORMAT , которое вы можете лучше проверить.Другая функция GetComputerNameEx полезна, если вы хотите дополнительно проверить информацию о компьютере, на котором запущена программа.

0 голосов
/ 18 января 2011

У меня есть необходимость ограничить определенные функции приложения в зависимости от местоположения текущего пользователя, вошедшего в систему

Если вы пытаетесь узнать местоположение текущего пользователя, вошедшего в систему пользователь , вы не должны использовать DsGetDcName .

Ваш компьютер может быть присоединен к domainA .Ваш логин может быть от domainB .Вызов DsGetDcName на вашем компьютере не даст вам GUID доменаB , но даст вам GUID доменаA

Поэтому, я думаю, вы должны использовать LookupAccountName вместо. LookupAccountName отображает текущий зарегистрированный SID пользователя.Затем вы можете извлечь SID домена из SID пользователя.Этот домен SID действительно является доменом, откуда этот пользователь пришел.Для получения подробной информации о том, как извлечь SID домена из SID пользователя, пожалуйста, проверьте здесь

Относительно вашего исходного вопроса об уникальности GUID домена, я сожалею, что я нена это нет ответа.AFAIK, нет доступных инструментов, позволяющих изменить SID домена или GUID.Я не уверен, как трудно взломать и изменить его.

...