Piszę program, którego jednym z zadań jest logowanie się na konto administracyjne. Wygląda to tak, że gdy zwykły użytkownik go uruchomi, program loguje się na podane (zapisane w konfiguracji) dane administratora komputera. Logowanie jako inny użytkownik wykonuję poprzez: CreateProcessWithLogonW. Gdy jest to Vista itd. z właczonym UAC, program dodatkowo podnosi sobie uprawnienia za pomocą funkcji ShellExecuteEx (z opcją lpVerb = "runas"). W ten sposób otrzymuję pełne prawa administratora programu na koncie użytkownika. Całą tą akcję nazwę "podniesieniem przywilejów"
Proces po podniesieniu przywilejów (w zdarzeniu OnCreate) ma poprawnie przyznane uprawnienia: SE_RESTORE_NAME i SE_BACKUP_NAME za pomocą LookupPrivilegeValue i AdjustTokenPrivileges
KOD cpp: UKRYJ
//Pobieranie tokena, ładowanie profilu i uruchamianie nowego procesu z profilem użytkownika
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
char szUserName[MAX_PATH]=""; //dla pobrania nazwy użytkownika
char szUserProfile[MAX_PATH]=""; //dla pobrania katalogu użytkownika
DWORD dwSize;
TCHAR SpecDir[MAX_PATH], SpecDir2[MAX_PATH]; //dla katalogów specjalnych
LPVOID lpvEnv; //dla środowiska
HANDLE hToken; //dla Tokena
DWORD dwPID = Edit4->Text.ToInt(); //PID procesu dawcy, który uuruchomiony jest na koncie zwykłego użytkownika
if ((hProcess = OpenProcess(MAXIMUM_ALLOWED /*PROCESS_QUERY_INFORMATION*/, FALSE, dwPID)) == 0) ShowMessage("OpenProcess " + (String)GetLastError()); //otwieram proces programu, który był uruchomiony przez użytkownika jako pierwszy - dawca organów
if (!OpenProcessToken(hProcess,MAXIMUM_ALLOWED /*TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_READ|TOKEN_WRITE | TOKEN_IMPERSONATE*/, &hToken)) ShowMessage("OpenProcessToken "+ (String)GetLastError()); //otwieram token tegoż procesu
if(!ImpersonateLoggedOnUser(hToken)) ShowMessage("ImpersonateLoggedOnUser "+(String)GetLastError()); //wykonuje przypisanie tokenu konta dawcy dla bieżacego wątku
dwSize = sizeof(szUserName);
GetUserName(szUserName,&dwSize); //nazwa uzytkownika - z konta dawcy
dwSize = sizeof(szUserProfile);
if(!GetUserProfileDirectory(hToken, szUserProfile, &dwSize)) //pobieranie nazwy katalogu głównego uzytkownika, np. c:\users\Somebody - z konta dawcy
ShowMessage("GetUserProfileDirectory "+(String)GetLastError());
SHGetFolderPath(NULL, CSIDL_DESKTOP,hToken,0,SpecDir); //pobieram lokalizacje pulpitu uzytkownika - konta dawcy
SHGetSpecialFolderPath( NULL, SpecDir2, CSIDL_PERSONAL , 0); //pobieram lokalizacje katalogu dokumentów uzytkownika - konta dawcy
ShowMessage("GetUserProfileDirectory: "+(String)szUserProfile+
"\n"+"GetUserName: "+(String)szUserName+
"\n"+"SHGetFolderPath: "+(String)SpecDir+
"\n"+"SHGetSpecialFolderPath: "+(String)SpecDir2+
"\n"+"TEMP: "+getenv("TEMP")); //kontrola pobranych informacji
if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE)) ShowMessage(L"CreateEnvironmentBlock " + (String)GetLastError()); //pobieram zmienne srodowiskowe uzytkownika - z konta dawcy
PROFILEINFO profile; //struktura profilu
ZeroMemory(&profile,sizeof(profile));
profile.dwSize=sizeof(profile);
profile.lpDefaultPath=szUserProfile; //nazwa profilu
profile.lpUserName = szUserName; //nazwa usera
//profile.dwFlags = PI_NOUI;
if(!RevertToSelf()) ShowMessage("RevertToSelf "+(String)GetLastError());
if(!LoadUserProfile(hToken,&profile)) ShowMessage("LoadUserProfile "+(String)GetLastError()); //ładuje profil uzytkownika
if(CreateProcess(NULL,ParamStr(0).t_str(),NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, lpvEnv, NULL, &si, &pi)) //uruchamiam proces z profilem
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
char szUserName[MAX_PATH]=""; //dla pobrania nazwy użytkownika
char szUserProfile[MAX_PATH]=""; //dla pobrania katalogu użytkownika
DWORD dwSize;
TCHAR SpecDir[MAX_PATH], SpecDir2[MAX_PATH]; //dla katalogów specjalnych
LPVOID lpvEnv; //dla środowiska
HANDLE hToken; //dla Tokena
DWORD dwPID = Edit4->Text.ToInt(); //PID procesu dawcy, który uuruchomiony jest na koncie zwykłego użytkownika
if ((hProcess = OpenProcess(MAXIMUM_ALLOWED /*PROCESS_QUERY_INFORMATION*/, FALSE, dwPID)) == 0) ShowMessage("OpenProcess " + (String)GetLastError()); //otwieram proces programu, który był uruchomiony przez użytkownika jako pierwszy - dawca organów
if (!OpenProcessToken(hProcess,MAXIMUM_ALLOWED /*TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY |TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_READ|TOKEN_WRITE | TOKEN_IMPERSONATE*/, &hToken)) ShowMessage("OpenProcessToken "+ (String)GetLastError()); //otwieram token tegoż procesu
if(!ImpersonateLoggedOnUser(hToken)) ShowMessage("ImpersonateLoggedOnUser "+(String)GetLastError()); //wykonuje przypisanie tokenu konta dawcy dla bieżacego wątku
dwSize = sizeof(szUserName);
GetUserName(szUserName,&dwSize); //nazwa uzytkownika - z konta dawcy
dwSize = sizeof(szUserProfile);
if(!GetUserProfileDirectory(hToken, szUserProfile, &dwSize)) //pobieranie nazwy katalogu głównego uzytkownika, np. c:\users\Somebody - z konta dawcy
ShowMessage("GetUserProfileDirectory "+(String)GetLastError());
SHGetFolderPath(NULL, CSIDL_DESKTOP,hToken,0,SpecDir); //pobieram lokalizacje pulpitu uzytkownika - konta dawcy
SHGetSpecialFolderPath( NULL, SpecDir2, CSIDL_PERSONAL , 0); //pobieram lokalizacje katalogu dokumentów uzytkownika - konta dawcy
ShowMessage("GetUserProfileDirectory: "+(String)szUserProfile+
"\n"+"GetUserName: "+(String)szUserName+
"\n"+"SHGetFolderPath: "+(String)SpecDir+
"\n"+"SHGetSpecialFolderPath: "+(String)SpecDir2+
"\n"+"TEMP: "+getenv("TEMP")); //kontrola pobranych informacji
if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE)) ShowMessage(L"CreateEnvironmentBlock " + (String)GetLastError()); //pobieram zmienne srodowiskowe uzytkownika - z konta dawcy
PROFILEINFO profile; //struktura profilu
ZeroMemory(&profile,sizeof(profile));
profile.dwSize=sizeof(profile);
profile.lpDefaultPath=szUserProfile; //nazwa profilu
profile.lpUserName = szUserName; //nazwa usera
//profile.dwFlags = PI_NOUI;
if(!RevertToSelf()) ShowMessage("RevertToSelf "+(String)GetLastError());
if(!LoadUserProfile(hToken,&profile)) ShowMessage("LoadUserProfile "+(String)GetLastError()); //ładuje profil uzytkownika
if(CreateProcess(NULL,ParamStr(0).t_str(),NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, lpvEnv, NULL, &si, &pi)) //uruchamiam proces z profilem
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Po drodze nie ma błędów.
Efek całosci jest taki, że na programie z podniesionymi przywilejami na Windows XP 32b i Windows 7 64b - pokazują się poprawnie wartości zmiennych środowiskowych i lokalizacji katalogów specjalnych zwykłego uzytkownika (dawcy), natomiast na Windows 8 64b i Server 2008 R2 - pokazują się tylko zmienne środowiskowe. Dla katalogów specjalnych pokazują się "krzaki".
Pytanie, czy robię coś zle? Jak poprawnie ładować profil innego użytkownika w kontekście: admin pobiera profil użytkownika?






