// RunAsAdminTest.cpp
#define UNICODE
#define WINVER 0x0600
#define _WIN32_WINNT 0x0600
#include <iostream>
#include <memory>
#include <windows.h>
#include <wtsapi32.h>
#include <userenv.h>
#pragma comment(lib, "wtsapi32.lib")
#pragma comment(lib, "userenv.lib")
template<typename F>
class ScopeExitHolder
{
public:
ScopeExitHolder(F f) : deleter(f) {}
~ScopeExitHolder()
{
deleter();
}
// VC++2013はムーブのdefault/deleteに非対応
//ScopeExitHolder(ScopeExitHolder&&) = default;
ScopeExitHolder(const ScopeExitHolder&) = default;
//ScopeExitHolder& operator=(ScopeExitHolder&&) = delete;
ScopeExitHolder& operator=(const ScopeExitHolder&) = delete;
private:
F deleter;
};
enum MakeScopeExitTag {};
template<typename F>
inline ScopeExitHolder<F> operator*(MakeScopeExitTag, F&& f)
{
return std::move(f);
}
void OutputError(const char* function, DWORD error)
{
std::wcout << function << ": " << error << std::endl;
}
#define SCOPE_EXIT_ID2(n) ScopeExit ## n
#define SCOPE_EXIT_ID(n) SCOPE_EXIT_ID2(n)
#define SCOPE_EXIT auto SCOPE_EXIT_ID(__LINE__) \
= MakeScopeExitTag() * [&]()
int wmain(int argc, wchar_t** argv)
{
if (argc <= 1)
{
return 1;
}
try
{
WTS_SESSION_INFO* sessionInfo;
DWORD count;
if (!WTSEnumerateSessions(
WTS_CURRENT_SERVER_HANDLE, 0, 1, &sessionInfo, &count))
{
OutputError("WTSEnumerateSessions", GetLastError());
}
SCOPE_EXIT{ WTSFreeMemory(sessionInfo); };
for (DWORD i = 0; i < count; ++i)
{
if (sessionInfo[i].State != WTSActive)
{
continue;
}
if (sessionInfo[i].SessionId == 0)
{
break;
}
std::cout << "Session: " << sessionInfo[i].SessionId << std::endl;
HANDLE hTokenBase = nullptr;
if (!WTSQueryUserToken(sessionInfo[i].SessionId, &hTokenBase))
{
OutputError("WTSQueryUserToken", GetLastError());
}
SCOPE_EXIT{ CloseHandle(hTokenBase); };
// 本当はここでGetTokenInformation(TokenElevationType)を使い、
// 昇格済みトークンの取得処理が必要かどうか判断すべき。
TOKEN_LINKED_TOKEN tlt = {};
DWORD length = {};
if (!GetTokenInformation(
hTokenBase, TokenLinkedToken, &tlt, sizeof tlt, &length))
{
OutputError(
"GetTokenInformation(TokenLinkedToken)", GetLastError());
}
SCOPE_EXIT{ CloseHandle(tlt.LinkedToken); };
HANDLE hToken;
if (!DuplicateTokenEx(tlt.LinkedToken, MAXIMUM_ALLOWED,
nullptr, SecurityImpersonation, TokenPrimary, &hToken))
{
OutputError("DuplicateTokenEx", GetLastError());
}
SCOPE_EXIT{ CloseHandle(hToken); };
DWORD tokenUserLength;
if (!GetTokenInformation(hToken, TokenUser,
nullptr, 0, &tokenUserLength)
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
OutputError("GetTokenInformation(TokenUser) 1", GetLastError());
}
std::unique_ptr<BYTE[]> buffer(new BYTE[tokenUserLength]);
if (!GetTokenInformation(hToken, TokenUser,
buffer.get(), tokenUserLength, &tokenUserLength))
{
OutputError("GetTokenInformation(TokenUser) 2", GetLastError());
}
auto tokenUser = reinterpret_cast<const TOKEN_USER*>(buffer.get());
DWORD nameLength = 0;
DWORD domainLength = 0;
SID_NAME_USE nameUse;
if (!LookupAccountSid(nullptr, tokenUser->User.Sid,
nullptr, &nameLength, nullptr, &domainLength, &nameUse)
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
OutputError("LookupAccountSid 1", GetLastError());
}
std::unique_ptr<TCHAR[]> name(new TCHAR[nameLength]);
std::unique_ptr<TCHAR[]> domain(new TCHAR[domainLength]);
if (!LookupAccountSid(nullptr, tokenUser->User.Sid,
name.get(), &nameLength, domain.get(), &domainLength, &nameUse))
{
OutputError("LookupAccountSid 2", GetLastError());
}
std::wcout << "User: " << name.get() << std::endl;
std::wcout << "Domain: " << domain.get() << std::endl;
// 移動プロファイルのときが不安
PROFILEINFO profileInfo = { sizeof profileInfo };
profileInfo.lpUserName = name.get();
if (!LoadUserProfile(hToken, &profileInfo))
{
OutputError("LoadUserProfile", GetLastError());
}
SCOPE_EXIT{ UnloadUserProfile(hToken, profileInfo.hProfile); };
void* environment;
if (!CreateEnvironmentBlock(&environment, hToken, FALSE))
{
OutputError("CreateEnvironmentBlock", GetLastError());
}
SCOPE_EXIT{ DestroyEnvironmentBlock(environment); };
STARTUPINFOW si = { sizeof si };
PROCESS_INFORMATION pi = {};
if (!CreateProcessAsUser(hToken, nullptr, argv[1],
nullptr, nullptr, FALSE, CREATE_UNICODE_ENVIRONMENT,
environment, nullptr, &si, &pi))
{
OutputError("CreateProcessAsUser", GetLastError());
}
CloseHandle(pi.hThread);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
break;
}
}
catch (const std::exception& e)
{
std::cerr << "std::exception: " << e.what() << std::endl;
}
} |