Created
January 27, 2014 09:13
-
-
Save RavuAlHemio/8645421 to your computer and use it in GitHub Desktop.
runas-stdio: A variant of runas which takes all its parameters as UTF-8 strings via stdio.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Released into the public domain. | |
| // http://creativecommons.org/publicdomain/zero/1.0/ | |
| #include <string> | |
| #include <cstdio> | |
| #include <fcntl.h> | |
| #include <io.h> | |
| #include <windows.h> | |
| /** The name of the program, taken from wargv[0]. */ | |
| static const wchar_t *progname = L"runas-stdio"; | |
| static std::wstring widen(std::string str) | |
| { | |
| if (str.length() == 0) | |
| { | |
| return std::wstring(); | |
| } | |
| // what's the size? | |
| int size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), static_cast<int>(str.length()), nullptr, 0); | |
| if (size == 0) | |
| { | |
| fwprintf(stderr, L"%ls: Failed to deduce buffer size for wide string: %lu\n", progname, GetLastError()); | |
| abort(); | |
| } | |
| std::wstring ret(static_cast<unsigned int>(size), L'\0'); | |
| if (MultiByteToWideChar(CP_UTF8, 0, str.c_str(), static_cast<int>(str.length()), &ret[0], static_cast<int>(ret.size())) != size) | |
| { | |
| fwprintf(stderr, L"%ls: Failed to convert UTF-8 string to wide string: %lu\n", progname, GetLastError()); | |
| abort(); | |
| } | |
| return ret; | |
| } | |
| static std::string readUntilNul(const wchar_t *readingWhat) | |
| { | |
| std::string ret; | |
| int c; | |
| for (;;) | |
| { | |
| c = fgetc(stdin); | |
| if (c == '\0') | |
| { | |
| break; | |
| } | |
| else if (c == EOF) | |
| { | |
| fwprintf(stderr, L"%ls: Encountered error or EOF while reading \n", readingWhat); | |
| abort(); | |
| } | |
| else | |
| { | |
| ret += static_cast<char>(c); | |
| } | |
| } | |
| return ret; | |
| } | |
| int wmain(int argc, wchar_t **wargv) | |
| { | |
| if (argc > 0 && wargv != nullptr && wargv[0] != nullptr && wargv[0][0] != L'\0') | |
| { | |
| progname = wargv[0]; | |
| } | |
| if (argc > 1) | |
| { | |
| fwprintf(stderr, | |
| L"\n" | |
| L"Usage: %ls\n" | |
| L"\n" | |
| L"Send the following information in UTF-8 on stdin:\n" | |
| L"1. The username (DOMAIN\\User or [email protected]).\n" | |
| L"2. A NUL byte.\n" | |
| L"3. The password.\n" | |
| L"4. A NUL byte.\n" | |
| L"5. The full command line to execute.\n" | |
| L"6. A NUL byte.\n", | |
| progname | |
| ); | |
| return 1; | |
| } | |
| // set stdin to binary | |
| _setmode(_fileno(stdin), _O_BINARY); | |
| // username, then password, then command | |
| std::string username = readUntilNul(L"username"); | |
| std::string password = readUntilNul(L"password"); | |
| std::string command = readUntilNul(L"command"); | |
| std::string::size_type backslash = username.find("\\"); | |
| bool haveDomain = false; | |
| std::string domain; | |
| if (backslash != std::string::npos) | |
| { | |
| // split username into domain and password | |
| haveDomain = true; | |
| domain = username.substr(0, backslash); | |
| username = username.substr(backslash + 1); | |
| } | |
| // we'll need this as a modifiable buffer | |
| std::wstring wideCommand = widen(command); | |
| // go | |
| STARTUPINFOW si; | |
| memset(&si, 0, sizeof(si)); | |
| si.cb = sizeof(si); | |
| PROCESS_INFORMATION pi; | |
| int ret = CreateProcessWithLogonW( | |
| widen(username).c_str(), | |
| haveDomain ? widen(domain).c_str() : nullptr, | |
| widen(password).c_str(), | |
| LOGON_WITH_PROFILE, | |
| nullptr, // application name (part of command line) | |
| &wideCommand[0], | |
| CREATE_DEFAULT_ERROR_MODE | CREATE_UNICODE_ENVIRONMENT, | |
| nullptr, // environment (inherit) | |
| nullptr, // working dir (inherit) | |
| &si, | |
| &pi | |
| ); | |
| if (ret == 0) | |
| { | |
| fwprintf(stderr, L"%ls: Process launch failed: %lu\n", progname, ret); | |
| abort(); | |
| } | |
| CloseHandle(pi.hProcess); | |
| CloseHandle(pi.hThread); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment