2014-02-17 4 views
1

Я уже искал долго, но не могли найти рабочее решение еще :-(CreateProcessAsUser контекст пользователя

Я создал службу, которая запускает окно клиента на каждого пользователя войти в систему на компьютере, используя CreateProcessAsUser (http://www.pinvoke.net/default.aspx/advapi32/createprocessasuser.html), WTSEnumerateSessions и так далее ...

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

у меня есть проблема заключается в том, что мне нужно, чтобы этот клиент хранил временные файлы в профиле пользователя. начиная с небольшого файла журнала, чтобы я мог отслеживать любые ошибки, которые могут возникнуть у моего пользователя. К сожалению, я не могу сохранить временную папку пользователя, потому что клиент как-то работает в контексте LocalSystem, хотя WindowsIdentity показывает правильного пользователя: System.IO.Path.GetTempPath() всегда возвращает «C: \ Windows \ Temp», но мой пользовательский не имеют административных прав, поэтому они не могут писать там ... Кроме того, я планировал сохранить настройки в реестре текущего пользователя, который тоже не работает. Я думаю, что это связано с неправильным временным путем каким-то образом.

Я также пробовал CreateEnvironmentBlock (http://www.pinvoke.net/default.aspx/userenv/CreateEnvironmentBlock.html), но я не мог заставить его работать, и где-то я нашел статью, в которой говорится, что это больше не будет работать на Vista или выше, поэтому я прекратил исследовать ее.

Для тестирования я создал небольшую форму тест просто делает это:

 MessageBox.Show("Temp: " + System.IO.Path.GetTempPath() + Environment.NewLine + "User: " + WindowsIdentity.GetCurrent().Name, "Before impersonation"); 

     WindowsIdentity currentUserId = WindowsIdentity.GetCurrent(); 
     WindowsImpersonationContext impersonatedUser = currentUserId.Impersonate(); 

     MessageBox.Show("Temp: " + System.IO.Path.GetTempPath() + Environment.NewLine + "User: " + WindowsIdentity.GetCurrent().Name, "After impersonation"); 

Это один всегда показывает те же результаты до и после перевоплощения: «Temp: C: \ Windows \ Temp пользователя: testdomain \ TestUser ":-(

Если это помогает здесь моя функция, чтобы начать процесс (маркер пользователя поставляется WTSEnumerateSessions) - это, конечно, работает только под контексте Localsystem в:

public static Process StartProcessAsUser(IntPtr UserToken, string App, string AppPath, string AppParameters) 
    { 
     Process ResultProcess = null; 

     IntPtr hDupedToken = IntPtr.Zero; 
     NativeProcessAPI.PROCESS_INFORMATION oProcessInformation = new NativeProcessAPI.PROCESS_INFORMATION(); 

     try 
     { 
      NativeProcessAPI.SECURITY_ATTRIBUTES oSecurityAttributes = new NativeProcessAPI.SECURITY_ATTRIBUTES(); 
      oSecurityAttributes.Length = Marshal.SizeOf(oSecurityAttributes); 

      bool result = NativeProcessAPI.DuplicateTokenEx(
        UserToken, 
        NativeProcessAPI.GENERIC_ALL_ACCESS, 
        ref oSecurityAttributes, 
        (int)NativeProcessAPI.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, 
        (int)NativeProcessAPI.TOKEN_TYPE.TokenPrimary, 
        ref hDupedToken 
       ); 

      if (!result) 
      { 
       return null; 
      } 

      NativeProcessAPI.STARTUPINFO oStartupInfo = new NativeProcessAPI.STARTUPINFO(); 
      oStartupInfo.cb = Marshal.SizeOf(oStartupInfo); 
      oStartupInfo.lpDesktop = String.Empty; 

      result = NativeProcessAPI.CreateProcessAsUser(
           hDupedToken, 
           null, 
           App + " " + AppParameters, 
           ref oSecurityAttributes, ref oSecurityAttributes, 
           false, 0, IntPtr.Zero, 
           AppPath, ref oStartupInfo, ref oProcessInformation 
          ); 

      if (result) 
      { 
       try 
       { 
        int ProcessID = oProcessInformation.dwProcessID; 

        try 
        { 
         ResultProcess = System.Diagnostics.Process.GetProcessById(ProcessID); 
        } 
        catch 
        { 
         ResultProcess = null; 
        } 
       } 
       catch (Exception ex) 
       { 
        ResultProcess = null; 
       } 
      } 
     } 
     catch 
     { 
      ResultProcess = null; 
     } 
     finally 
     { 
      if (oProcessInformation.hProcess != IntPtr.Zero) 
       NativeProcessAPI.CloseHandle(oProcessInformation.hProcess); 
      if (oProcessInformation.hThread != IntPtr.Zero) 
       NativeProcessAPI.CloseHandle(oProcessInformation.hThread); 
      if (hDupedToken != IntPtr.Zero) 
       NativeProcessAPI.CloseHandle(hDupedToken); 
     } 

     return ResultProcess; 
    } 

Любые идеи о том, как я мог бы запускать свои процессы в контекстах пользователя, а не в контексте LocalSystem?

Большое спасибо!

+0

Вы проверили переменную среды% USERPFORILE%? 'Environment.GetEnvironmentVariable (« USERPROFILE », EnvironmentVariableTarget.User)' – MrPaulch

+2

Цитата из MSDN: «CreateProcessAsUser не загружает указанный профиль пользователя в раздел реестра HKEY_USERS.Поэтому для доступа к информации в разделе реестра HKEY_CURRENT_USER вы должны загрузить информацию профиля пользователя в HKEY_USERS с помощью функции LoadUserProfile перед вызовом CreateProcessAsUser. Обязательно вызовите UnloadUserProfile после выхода нового процесса. » –

+0

Спасибо за ваши ответы ... Я попробовал Environment.GetEnvironmentVariable (« USERPROFILE », EnvironmentVariableTarget.User), но он возвращает пустую строку – Vibrationz

ответ

0

Ok Я нашел обходной путь: я перешел на использование в ПОЛЬЗОВАТЕЛЯХ улей вместо CURRENT_USER улья с помощью SID, представленной WindowsIdentity:

Microsoft.Win32.Registry.Users.OpenSubKey(System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString() + ..., true) 

Это прекрасно работает, хотя он чувствует себя немного неудобно, чтобы получить среду переменные от пользователя «окружающей среды» и «летучие среды» путь в реестре, а не только с помощью встроенных функций .NET в ...

Но спасибо за вашу помощь ;-)

EDIT: Я не буду отмечать это как ответ, потому что это: а) мое собственное решение и b) просто обходное решение

0

Оставив это здесь для кого-то еще, интересующегося, как это сделать: CreateEnvironmentBlock - это то, что вам нужно использовать.

DuplicateTokenEx(userToken, MAXIMUM_ALLOWED | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, IntPtr.Zero, SecurityIdentification, TokenPrimary, out dupUserToken); 
CreateEnvironmentBlock(out envBlock, dupUserToken, false); 
CreateProcessAsUserW(dupUserToken, null, cmdLine, IntPtr.Zero, IntPtr.Zero, false, 
      (uint)(CreateProcessFlags.CREATE_NEW_CONSOLE | CreateProcessFlags.CREATE_UNICODE_ENVIRONMENT), 
      envBlock, processDir, ref startupInfo, out procInfo); 
Смежные вопросы