2014-01-23 4 views
3

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

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

Это PInvoke для WTSQuerySessionInformation:

[DllImport("Wtsapi32.dll", SetLastError = true)] 
     static extern bool WTSQuerySessionInformation(
      IntPtr hServer, 
      uint sessionId, 
      WTS_INFO_CLASS wtsInfoClass, 
      out IntPtr ppBuffer, 
      out uint pBytesReturned 
     ); 

и это, как мы получаем проверки службы, если пользователь имеет активный сеанс:

WTSEnumerateSessions(IntPtr.Zero, 0, 1, ref pSessionInfo, ref dwCount); 

Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO)); 

Int32 current = (int)pSessionInfo; 
uint bytes = 0; 
for (int i = 0; i < dwCount; i++) 
{ 
    WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO)); 
    if (WTS_CONNECTSTATE_CLASS.WTSActive == si.State) 
    { 
     IntPtr userPtr = IntPtr.Zero; 
     IntPtr domainPtr = IntPtr.Zero; 

     //Check if the active session matches the saved username/domain 
     WTSQuerySessionInformation(IntPtr.Zero, (uint)si.SessionID, WTS_INFO_CLASS.WTSUserName, out userPtr, out bytes); 

     WTSQuerySessionInformation(IntPtr.Zero, (uint)si.SessionID, WTS_INFO_CLASS.WTSDomainName, out domainPtr, out bytes); 

     string sessionUName = Marshal.PtrToStringAnsi(userPtr); 
     string sessionDomain = Marshal.PtrToStringAnsi(domainPtr); 
    } 
} 

Проблема, когда служба детектирует пользовательский сеанс и пытается получить доменное имя, возвращаемое имя отличается от фактического имени домена пользователя, даже если идентификатор сеанса правильный для этого конкретного пользователя.

Если это помогает доменному имени, возвращенному с WTSQuerySessionInformation, является NTLAN_1, который полностью отличается от фактического домена пользователя.

Я хотел бы знать, есть ли что-то неправильное с pInvoke WTSQuerySessionInformation или любым вызовом в вышеуказанном коде. Также хотел бы знать, связан ли домен NTLAN_1 с каким-либо сервисом или приложением RDP любого типа.

EDIT:

После долгих переговоров мне удалось получить результат для LsaEnumerateLogonSessions и LsaGetLogonSessionData, к сожалению, это тот же самый результат, и ни один из перечисленных сессий не имеет ожидаемый доменное имя. Вот список сессий с их уважаемой информацию от LsaEnumerateLogonSessions:

Session: 0 User: MARK *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 2/6/2014 7:34:17 AM 
Session: 0 User: ADMINISTRATOR *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 2/4/2014 7:47:11 AM 
Session: 0 User: ADMINISTRATOR *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 1/27/2014 3:27:33 PM 
Session: 0 User: MCMFILE2$ *** Domain: NTLAN_1 *** Login Type: (5) Service *** Login Time: 1/16/2014 3:52:46 PM 
Session: 0 User: MCM-LR9-YE91K$ *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 2/6/2014 10:52:40 AM 
Session: 0 User: MARK *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 2/6/2014 10:19:39 AM 
Session: 0 User: ADMINISTRATOR *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 1/20/2014 9:57:57 AM 
Session: 0 User: ANONYMOUS LOGON *** Domain: NT AUTHORITY *** Login Type: (3) Network *** Login Time: 1/16/2014 3:53:19 PM 
Session: 1 User: ADMINISTRATOR *** Domain: NTLAN_1 *** Login Type: (2) Interactive *** Login Time: 1/16/2014 3:53:11 PM 
Session: 0 User: LOCAL SERVICE *** Domain: NT AUTHORITY *** Login Type: (5) Service *** Login Time: 1/16/2014 3:52:46 PM 
Session: 0 User: MARK *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 2/6/2014 10:52:40 AM 
Session: 1 User: ADMINISTRATOR *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 2/6/2014 10:52:38 AM 
Session: 0 User: MARK *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 2/6/2014 10:19:39 AM 
Session: 0 User: ADMINISTRATOR *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 1/18/2014 6:20:25 PM 
Session: 0 User: ANONYMOUS LOGON *** Domain: NT AUTHORITY *** Login Type: (3) Network *** Login Time: 1/16/2014 3:53:19 PM 
Session: 0 User: CVSMANAGER_USER *** Domain: MCMFILE2 *** Login Type: (5) Service *** Login Time: 1/16/2014 3:53:09 PM 
Session: 0 User: MCM-LR9-YE91K$ *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 2/6/2014 10:52:40 AM 
Session: 0 User: MARK *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 2/6/2014 10:19:39 AM 
Session: 0 User: DefaultAppPool *** Domain: IIS APPPOOL *** Login Type: (5) Service *** Login Time: 2/6/2014 8:42:47 AM 
Session: 0 User: ADMINISTRATOR *** Domain: NTLAN_1 *** Login Type: (3) Network *** Login Time: 2/4/2014 2:40:40 PM 
Session: 0 User: IUSR *** Domain: NT AUTHORITY *** Login Type: (5) Service *** Login Time: 1/16/2014 3:53:09 PM 
Session: 0 User: MCMFILE2$ *** Domain: NTLAN_1 *** Login Type: (0) 0 *** Login Time: 1/16/2014 3:52:44 PM 

Сеанс в вопросе есть идентификатор сеанса = 1. А из списка он показывает имя домена быть NTLAN_1 вместо фактического домена.

Теперь я заметил что-то странное в своем настольном приложении, которое, я считаю, имеет решающее значение для поиска решения этой проблемы, но я не уверен, что с этим делать.

Теперь мое настольное приложение написано на .NET, поэтому я попытался получить имя пользователя и домен, запустив приложение напрямую. Теперь самое смешное, если я использую встроенную функцию GetUserNameEx и передаю NameUserPrincipal в качестве NameFormat, я могу получить правильную комбинацию имени пользователя/домена. Однако, и это забавная часть, когда я пытаюсь получить доменное имя, используя класс Environment, позвонив по телефону Environment.UserDomainName. Я получаю преступника NTLAN_1. обратите внимание, что как управляемые, так и неуправляемые вызовы выполнялись одним и тем же приложением в одном и том же режиме.

У меня раньше не было такой проблемы, и теперь у меня есть еще несколько пользователей, которые сообщили о той же проблеме, и это начало меня беспокоить.

+0

Интересно, является ли пользователь «олицетворением»? –

+0

Если вы можете добавить диагностический код в свою службу и запустить его на рассматриваемой машине, вы можете попробовать использовать 'WTSQueryUserToken', чтобы получить токен и распаковать его, чтобы узнать, есть ли что-то странное в части домена SID. Вы также можете посмотреть на «TokenSource», «TokenSessionId» и «TokenOrigin» (см. «LsaGetLogonSessionData'), чтобы увидеть, что там происходит что-то странное. –

+0

@HarryJohnston К сожалению, я не могу проверить что-либо на рассматриваемой машине. Но хотелось бы знать, в чем преимущество получения такой информации в моем случае. –

ответ

2

Я, наконец, нашел проблему, этот домен был фактически суффиксом UPN, а не доменом. Я все еще считаю, что это ошибка от MS, так как оба WTSQuerySessionInformation и LsaEnumerateLogonSessions должны возвращать доменное имя, а не суффикс UPN.

Я смог решить проблему, полагаясь на SID учетной записи, а не на комбинацию имени пользователя/домена, и, к счастью, SID тот же, независимо от того, запрашиваете ли вы фактическое доменное имя или суффикс.

Благодаря Harry Johnston за потрясающий комментарий относительно SID.

0

Слишком большой, чтобы добавить комментарий ... надеюсь, это полезно ...

Итак ... это сервис, эффективно запрашивающий локальный или удаленный сервер?

берутся из this MSDN link which describes the WTSQuerySessionInformation function следующих

«указать только WTS_CURRENT_SESSION при получении информации о сеансе на локальном сервере. Если WTS_CURRENT_SESSION указывается при запросе информации о сеансе на удаленном сервере, возвращаемая информация сеанса будет непоследовательной. Не используйте возвращаемые данные ».

То параметр SESSIONID вы проходящее в Кроме того:.

«Чтобы получить идентификатор сессии для текущей сессии, когда Службы удаленных рабочих столов работает, вызовите WTSQuerySessionInformation и указать WTS_CURRENT_SESSION для параметра SESSIONID и WTSSessionId для WTSInfoClass Параметр идентификатора сеанса будет возвращен в параметре ppBuffer. "

Update: попробуйте использовать WTSEnumerateSessionsEx для получения дополнительной информации сеанса с помощью расширенной структуры WTS_SESSION_INFO_1, которая сама по себе содержит имя домена ...

«pDomainName - Указатель на строку с нулевым символом, которая содержит доменное имя пользователя, который вошел в сеанс. Если ни один пользователь не вошел в сеанс, строка содержит NULL. «

Не уверен, что он держит, если пользователь затеняет другой.

+0

Хорошо, как я должен знать тип сеанса? Как вы можете видеть из представленного мной кода, я перечисляю все сеансы, а затем запрашиваю каждый сеанс в списке сессий. –

+0

Он передает 0 в качестве дескриптора сервера, что означает, что он запрашивает локальную машину. Кроме того, он не использует WTS_CURRENT_SESSION. –

+0

@RedSerpent WTSEnumerateSessions дает вам тип сеанса; этот метод API может отображать все локальные и удаленные сеансы для данного сервера, включая их состояние (например, подключенное, отключенное) и тип (локальный, RDP). –

Смежные вопросы