Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Win7, UAC и получение корректного пути к AppData User'а  (Прочитано 22510 раз)
0 Пользователей и 1 Гость смотрят эту тему.
dark_rain
Помогающий

ua
Offline Offline
Пол: Мужской

« : 26-10-2011 15:59 » 

Итак господа имеем следующее:
Приложение, которое при запуске под Win7, под User требует прав Admin - выскакивает окошко UAC, я ввожу пароль, оно запускается от Admin естественно. Не вдаваясь в логику приложения скажу, что оно запрашивает определенные файлы из AppData, путь к AppData формируется ф-цией
Код: (C++)
SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, appDataDir)
и так как приложение запущенно от Admin, все пишется/читаеться в/из AppData  Admin'a. Пробороздив просторы MSDN я выяснил, что третий параметр передаваемый в ф-цию есть HANDLE hToken  и если передать туда тоукен User, то все пути для него корректно пропишутся. Получить тоукен можно ф-циями OpenProcessToken(); или LogonUser (); но так как приложение запущенно от Admin мне всегда (тем или иным способом) возвращается его тоукен.   

Господа, помогите красиво выйти из ситуации и получить корректный путь для работы моего приложения независимо от того, что оно требует Admin прав.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 27-10-2011 13:27 » 

Что-то тут напутано.

Права администратора вовсе не означают работу приложения под учётной записью администратора. Работа идёт под учётной записью запустившего приложение пользователя.

Функция SHGetFolderPath в MSDN объявлена как deprecated (устаревшая и нерекомендуемая для использования, оставленная для обратной совместимости). Для операционных систем от Vista и выше рекомендуется использовать функцию SHGetKnownFolderPath.

Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
zubr
Гость
« Ответ #2 : 27-10-2011 13:35 » 

Тут дело в флаге CSIDL_FLAG_CREATE. Этот флаг означает, что должен создаваться каталог, на что у юзера нет полномочий. Но возникает вопрос - зачем создавать каталог AppData, если он уже есть в системе и юзер его удалить не может и даже админ его удалить не может.
dark_rain, убери флаг CSIDL_FLAG_CREATE и будет тебе счастье.
Записан
dark_rain
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #3 : 27-10-2011 15:23 » 

Цитата
Права администратора вовсе не означают работу приложения под учётной записью администратора. Работа идёт под учётной записью запустившего приложение пользователя.
Если приложение запущено от имени Admin, то все ф-ции типа GetCurrentUser и etc возвращают Admin.

Цитата
Тут дело в флаге CSIDL_FLAG_CREATE. Этот флаг означает, что должен создаваться каталог, на что у юзера нет полномочий.
Улыбаюсь Если бы все было так просто... Приложение завернуто в инсталяху, Setup Factory 7, а это априори подразумевает то, что User мало прав для ее выполнения.

Таким вот образом решил получить токен реальный, но под Win7, пока что, не корректно работает, пока смотрю.
Код: (C++)
   PROCESSENTRY32 entry;
  entry.dwSize = sizeof(PROCESSENTRY32);

  HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
  HANDLE hProcess;
  HANDLE processToken;
  if (Process32First(snapshot, &entry) == TRUE)
  {
    while (Process32Next(snapshot, &entry) == TRUE)
    {
      if(_wcsicmp(entry.szExeFile, _T("explorer.exe")) == 0)
      {  
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, entry.th32ProcessID);
       
        bool result = OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &processToken);
        if (!result)
        {
          DWORD err = GetLastError();
          return 0;
        }

        CloseHandle(hProcess);
      }
    }
  }  
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 27-10-2011 18:19 » 

dark_rain, подход рискованный для серверных операционок, у них могут быть параллельные сессии, параллельно работающие пользователи и, соответственно, несколько процессов explorer - не угадаешь, который свой. Для правильного поиска ещё нужно получать SessionID текущего процесса и сравнивать его с SessionID, возвращаемым Process32First/Next.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
dark_rain
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #5 : 27-10-2011 19:16 » 

Dimka, учту твои замечания, реализовать их не сложно и будет более надежно. Под вистой все работает нормально, а под 7 все равно не хочет. Завтра буде ковырять, о результатах отпишу.

П.С. Чертовы хиппи придумали этот UAC, он уже плешь мне в голове проел. Жаль
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 27-10-2011 20:50 » 

Цитата: dark_rain
и если передать туда тоукен User, то все пути для него корректно пропишутся. Получить тоукен можно ф-циями OpenProcessToken(); или LogonUser ()
Мне кажется, это какая-то достаточно вольная трактовка MSDN. Хотя бы потому, что token как результат LogonUser отличается от token как результата OpenProcessToken.

Цитата: MSDN SHGetFolderPath
hToken [in]
Type: HANDLE

An access token that can be used to represent a particular user.

Microsoft Windows 2000 and earlier: Always set this parameter to NULL.

Windows XP and later: This parameter is usually set to NULL, but you might need to assign a non-NULL value to hToken for those folders that can have multiple users but are treated as belonging to a single user. The most commonly used folder of this type is Documents.

The calling process is responsible for correct impersonation when hToken is non-NULL. The calling process must have appropriate security privileges for the particular user, including TOKEN_QUERY and TOKEN_IMPERSONATE, and the user's registry hive must be currently mounted. See Access Control for further discussion of access control issues.

Assigning the hToken parameter a value of -1 indicates the Default User. This enables clients of SHGetFolderPath to find folder locations (such as the Desktop folder) for the Default User. The Default User user profile is duplicated when any new user account is created, and includes special folders such as My Documents and Desktop. Any items added to the Default User folder also appear in any new user account.
В связи с данным текстом сразу возникает ряд вопросов:
1) Пробовал ли ты вместо token подставить -1 (так называемый pseudohandle) для упомянутого "Default User"?
2) Как я понимаю "Windows 2000 and earlier" ты не поддерживаешь?
3) "The calling process is responsible for correct impersonation when hToken is non-NULL" - где ты выполняешь Impersonate? (Они бывают разные - тут надо поэкспериментировать.)
3) Где у тебя упомянутая привилегия TOKEN_IMPERSONATE? (И если будешь делать Impersonate, для это ещё надо выполнять DuplicateToken.)
4) Надеюсь, что "user's registry hive must be currently mounted" соблюдается.

И всё-таки, почему не SHGetKnownFolderPath? Тоже из-за служебной учётной записи инсталлятора?

P.S. Мне тоже этот UAC примерно 1,5 месяца плешь проедал при попытке добиться, чтобы Windows Service, работающий от Local System, делал то, что должен, в частности, имел бы доступ к DirectX и сетевым shared folders. MS считает, что service'ам это ни к чему. Жаль
« Последнее редактирование: 27-10-2011 20:53 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
dark_rain
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #7 : 28-10-2011 06:05 » 

Цитата
И всё-таки, почему не SHGetKnownFolderPath?
Я переделал, все равно не корректно работает, проблема осталась той же. Буду на работе - приведу код.
Записан
zubr
Гость
« Ответ #8 : 28-10-2011 06:48 » 

В 7-ке UAC можно программно убить, правда способ хакерский.
А если по теме, мне вообще непонятны вышеобозначенные заморочки.
Я уже ранее вроде отвечал, чтобы не было проблем с разными пользователями и их полномочиями, надо все действия, которые должны выполняться под админом, выделить в отдельный процесс и запускать его под админом. Остальные действия выполняются под юзером, в том числе определение каталога AppData и запись в него. Что касается инсталлятора Setup Factory 7 - не знаю, не пользовался им. Сам в основном пользуюсь InnoSetup - бесплатный, легкий, удобный инсталлятор. По крайней мере у него есть возможность запускать и отслеживать другие процессы. Если у Setup Factory 7 таких возможностей нет, то в топку его.
Записан
dark_rain
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #9 : 28-10-2011 12:07 » 

Итак, господп, привожу код моего метода, поправьте, что я делаю не так?
Код: (C++)
boost::filesystem::path DataDirPath(void) const
{

  // Get application data directory.
  PROCESSENTRY32 entry;
  entry.dwSize = sizeof(PROCESSENTRY32);

  HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
  HANDLE hProcess;
  HANDLE processToken;
  HANDLE duplicatedToken;
  if (Process32First(snapshot, &entry) == TRUE)
  {
    while (Process32Next(snapshot, &entry) == TRUE)
    {
      if(_wcsicmp(entry.szExeFile, _T("explorer.exe")) == 0)
      {  
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, entry.th32ProcessID);
       
        BOOL result = OpenProcessToken(hProcess, TOKEN_IMPERSONATE | TOKEN_QUERY, &processToken);
        if (!result)
        {
          DWORD err = GetLastError();
        }
        DuplicateToken(processToken, SecurityImpersonation, &duplicatedToken);
        CloseHandle(hProcess);
      }
    }
  }
 
 

  wchar_t* appDataDir = NULL;
    CHECK_COM_ERROR(SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DONT_VERIFY, duplicatedToken, &appDataDir));
    boost::filesystem::path path(appDataDir);
return path;
}
Записан
zubr
Гость
« Ответ #10 : 28-10-2011 13:03 » 

1. Как минимум, я не вижу здесь проверок:
-Сработал ли Process32First
-Найден ли процесс explorer.exe
-Валидный ли хендл возвращает OpenProcess
-Валидный ли токен возвращает OpenProcessToken
-Если не валидный - какой код ошибки
-Валидный ли DuplicateToken
2. Если токен валидный, а ошибку выдает SHGetKnownFolderPath, то какую?
« Последнее редактирование: 28-10-2011 13:07 от zubr » Записан
dark_rain
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #11 : 28-10-2011 16:38 » 

Путем танцем с бубном заработало,  сам не знаю как, но я сделал это Улыбаюсь Всем успешных выходных, спасибо огромное за оказанную помощь, господа.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #12 : 29-10-2011 12:11 » 

dark_rain, и как выглядит рабочий вариант?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
dark_rain
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #13 : 31-10-2011 09:11 » 

Dimka,  сделал метод, который проверяет на Vista и выше, сделал проверку на админа, если админ то выполнять все эти действия, обернул в try-catch, в кетче поставил запись того, что неправильно в лог. Собственно и все.

Добавлено через 8 часов, 15 минут и 28 секунд:
Похоже я поторопился радоваться господа. Жаль
Как проверить следующие вещи?
-Валидный ли хендл возвращает OpenProcess
-Валидный ли токен возвращает OpenProcessToken
« Последнее редактирование: 31-10-2011 17:26 от dark_rain » Записан
zubr
Гость
« Ответ #14 : 31-10-2011 17:32 » 

Цитата
OpenProcess Function

Return Value
If the function succeeds, the return value is an open handle to the specified process.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.
MSDN

Цитата
OpenProcessToken Function

Return Value
If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.
MSDN
Записан
dark_rain
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #15 : 31-10-2011 17:33 » 

Понятно, спасибо.
Записан
zubr
Гость
« Ответ #16 : 31-10-2011 17:37 » 

dark_rain, извини за нескромный вопрос, как ты пишешь программу/ы используя WinAPI, не смотря при этом в MSDN?
Записан
dark_rain
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #17 : 31-10-2011 17:45 » 

Ну в общем OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, entry.th32ProcessID); вылетает с кодом 5  (доступ запрещен), а как следствие OpenProcessToken(hProcess, TOKEN_IMPERSONATE | TOKEN_QUERY, &processToken); вылетает с кодом 6 (дескриптор невалиден). Помогите, пожалуйста,  разрешить проблему.
Записан
zubr
Гость
« Ответ #18 : 31-10-2011 18:37 » 

Попробуй добавить привилегию "SeDebugPrivilege"  своему процессу, который пытается получить хендл процесса explorer.
Смотри в строну функций LookupPrivilegeValue, AdjustTokenPrivileges. В msdn есть пример добавления привилегий.
Записан
dark_rain
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #19 : 31-10-2011 20:05 » 

dark_rain, извини за нескромный вопрос, как ты пишешь программу/ы используя WinAPI, не смотря при этом в MSDN?
Да смотрю я, просто опыта разработки у меня всего-то два месяца. Отсюда и вопросы такие глупые.

По написанному тобой в последнем посте:
 AdjustTokenPrivileges function - один из параметров __in       HANDLE TokenHandle Мне нужно передавать туда токен моего процесса, не explorer.exe?

http://msdn.microsoft.com/en-us/library/aa446619(VS.85).aspx нашел вот этот пример, пока разбираюсь, что к чему. Если я правильно тебя понял, то он способен решить мои проблемы.
Записан
zubr
Гость
« Ответ #20 : 31-10-2011 22:14 » 

Цитата
Мне нужно передавать туда токен моего процесса, не explorer.exe?
Да, твоего - GetCurrentProcess. Чтобы повысить привилегии твоего процесса.
Записан
dark_rain
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #21 : 01-11-2011 12:19 » 

Хрень какая-то, господа:
Код: (C++)
 
HANDLE currentProcToken;
HANDLE currentProcHandle = GetCurrentProcess();
BOOL openResult = OpenProcessToken(currentProcHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &currentProcToken);

После выполнения GetCurrentProcess в currentProcHandle остаеться значение "0x7756c905", а OpenProcessToken возвращает ноль, с ошибкой @err,hr 0x00000006 The handle is invalid. Где ошибка, что не так?


Добавлено через 8 минут и 7 секунд:
Перезагрузил машину со студией, схавало. После обновления студия странно себя ведет....
« Последнее редактирование: 01-11-2011 13:22 от dark_rain » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #22 : 01-11-2011 13:50 » 

dark_rain, если почитать MSDN, обнаружится, что GetCurrentProcess возвращает псевдо-хэндл процесса - условный хэндл, означающий "текущий". Но OpenProcessToken требует реальный хэндл. Попробуй получить PID процесса (GetCurrentProcessId), а затем через него получить хэндл процесса (OpenProcess).
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
zubr
Гость
« Ответ #23 : 01-11-2011 16:12 » 

1.
Цитата
OpenProcessToken Function

ProcessHandle
A handle to the process whose access token is opened. The process must have the PROCESS_QUERY_INFORMATION access permission.
Где тут написано, что псевдохендл не подходит?
2.
Цитата
GetCurrentProcess Function

Remarks
A pseudo handle is a special constant, currently (HANDLE)-1, that is interpreted as the current process handle. For compatibility with future operating systems, it is best to call GetCurrentProcess instead of hard-coding this constant value. The calling process can use a pseudo handle to specify its own process whenever a process handle is required. Pseudo handles are not inherited by child processes.

This handle has the maximum possible access to the process object. For systems that support security descriptors, this is the maximum access allowed by the security descriptor for the calling process. For systems that do not support security descriptors, this is PROCESS_ALL_ACCESS. For more information, see Process Security and Access Rights.

A process can create a "real" handle to itself that is valid in the context of other processes, or that can be inherited by other processes, by specifying the pseudo handle as the source handle in a call to the DuplicateHandle function. A process can also use the OpenProcess function to open a real handle to itself.

The pseudo handle need not be closed when it is no longer needed. Calling the CloseHandle function with a pseudo handle has no effect. If the pseudo handle is duplicated by DuplicateHandle, the duplicate handle must be closed.
Ключевая фраза:
Цитата
This handle has the maximum possible access to the process object. For systems that support security descriptors, this is the maximum access allowed by the security descriptor for the calling process. For systems that do not support security descriptors, this is PROCESS_ALL_ACCESS. For more information, see Process Security and Access Rights.
Как я понимаю, для данной задачи хендл наследовать не надо.
3. Я реализовывал добавление привилегий процессу, используя именно GetCurrentProcess - и все нормально работает. Тестировал в системах Win2000 - Win7, x86/64
Записан
dark_rain
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #24 : 01-11-2011 16:47 » new

zubr, спасибо, вроде прокатило. Вылезли некие другие нюансы, но это уже отдельная история Улыбаюсь Завтра буду ковырять. сейчас получает токен реального юзера и передает в функцию.   

Добавлено через 1 день, 22 часа, 30 минут и 10 секунд:
Господа, всем чрезмерно благодарен.
« Последнее редактирование: 03-11-2011 15:17 от dark_rain » Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines