15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Как получить текущее имя пользователя и имя домена в Windows NT

Иногда приложению требуется знать имя пользователя и имя домена для текущего потока. Эта статья демонстрирует, как сделать это в Windows NT при помощи security функций в Win32 Application Programming Interface (API).

До Windows NT, считалось, что поток запускается под учётной записью пользователя, залогинившегося в интерактивном режим. Однако, Windows NT позволяет потокам запускаться под разными учётными записями. Например, поток, запущенный как сервис, имеет имя домена AUTHORITY и имя пользователя SYSTEM, Это значит, что сервисы запускаются с правами системы.

Если необходимо получить как имя пользователя так и имя домена для текущего потока, то сначала, при помощи функции GetTokenInformation надо распаковать пользовательский идентификатор (SID) из потока. А затем вызвать функцию LookupAccountSid, чтобы получить имя учётной записи и имя домена, связанные с этим SID. Нижеприведённый пример, демонстрирует данную технологию.

32-битные функции, упомянутые выше не доступны в Microsoft Windows 95 или Microsoft Windows 98. Чтобы получить имя и домен залогинившегося пользователя в Windows 95 или Windows 98, Вам необходимо вызвать функцию 16-битного LAN Менеджера. Как это делается, можно узнать в статье из Microsoft Knowledge Base:

Q155698 Как получить текущее имя пользователя и домена в Windows 95 и Windows 98

 

ЗАМЕЧАНИЕ: Если требуется только имя пользователя, то можно использовать функцию GetUserName, которая прекрасно работает в Windows 95, Windows 98, Windows NT, и Windows 2000.

Пример кода

Следующий пример демонстрирует, как программно получить имя пользователя и имя домена в Windows NT:

//**********************************************************************
// 
//  ФУНКЦИЯ:     GetCurrentUserAndDomain - это функция, определяющая
//                имя пользователя и имя домена учётной записи,
//                связанной с вызывающим потоком.
// 
//  ПАРАМЕТРЫ:   szUser - буфер, который получает имя пользователя
//                pcchUser - размер szUser в символах
//                szDomain - буфер, принимающий имя домена
//                pcchDomain - размер szDomain в символах
// 
//  ВОЗВРАЩАЕМЫЕ ЗНАЧЕНИЯ: TRUE если функция выполнена успешно. Иначе, FALSE
//                и GetLastError() вернёт код ошибки.
// 
//                Если любой из буферов слишком маленький, то
//                GetLastError() вернёт ERROR_INSUFFICIENT_BUFFER,
//                а pcchUser и pcchDomain будут откорректированы в
//                соответствии с требуемыми размерами.
// 
//**********************************************************************

BOOL GetCurrentUserAndDomain(PTSTR szUser, PDWORD pcchUser, 
      PTSTR szDomain, PDWORD pcchDomain) {

   BOOL         fSuccess = FALSE;
   HANDLE       hToken   = NULL;
   PTOKEN_USER  ptiUser  = NULL;
   DWORD        cbti     = 0;
   SID_NAME_USE snu;

   __try {

      // Получаем маркёр доступа вызывающего потока.
      if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,
            &hToken)) {

         if (GetLastError() != ERROR_NO_TOKEN)
            __leave;

         // Если маркёра потока не существует, то запрашиваем маркёр процесса.
         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, 
               &hToken))
            __leave;
      }

      // Получаем размер информации о пользователе в маркёре.
      if (GetTokenInformation(hToken, TokenUser, NULL, 0, &cbti)) {

         // Если длина буфера равна нулю, то ошибка.
         __leave;
   
      } else {

         // Если длина буфера равна нулю, то ошибка.
         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
            __leave;
      }

      // Распределяем буфер для информации о пользователе в маркёре.
      ptiUser = (PTOKEN_USER) HeapAlloc(GetProcessHeap(), 0, cbti);
      if (!ptiUser)
         __leave;

      // Получаем информацию о пользователе из маркёра.
      if (!GetTokenInformation(hToken, TokenUser, ptiUser, cbti, &cbti))
         __leave;

      // Получаем имя пользователя и имя домена по пользовательскому SID.
      if (!LookupAccountSid(NULL, ptiUser->User.Sid, szUser, pcchUser, 
            szDomain, pcchDomain, &snu))
         __leave;
      
      fSuccess = TRUE;

   } __finally {

      // Освобождаем ресурсы.
      if (hToken)
         CloseHandle(hToken);

      if (ptiUser)
         HeapFree(GetProcessHeap(), 0, ptiUser);
   }

   return fSuccess;
}