mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-29 08:44:52 +02:00
Changes to remove Impersonation Privilege requirement in sshd (#142)
https://github.com/PowerShell/Win32-OpenSSH/issues/726
This commit is contained in:
parent
afc6ca91f7
commit
894f6dd79c
@ -96,9 +96,9 @@ cmd.exe /c 'sc.exe sdset ssh-agent D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPW
|
|||||||
|
|
||||||
New-Service -Name sshd -BinaryPathName $sshdpath -Description "SSH Daemon" -StartupType Manual -DependsOn ssh-agent | Out-Null
|
New-Service -Name sshd -BinaryPathName $sshdpath -Description "SSH Daemon" -StartupType Manual -DependsOn ssh-agent | Out-Null
|
||||||
sc.exe config sshd obj= $sshdAccount
|
sc.exe config sshd obj= $sshdAccount
|
||||||
|
sc.exe privs sshd SeAssignPrimaryTokenPrivilege
|
||||||
|
|
||||||
Add-Privilege -Account $sshdAccount -Privilege SeAssignPrimaryTokenPrivilege
|
Add-Privilege -Account $sshdAccount -Privilege SeAssignPrimaryTokenPrivilege
|
||||||
Add-Privilege -Account $sshdAccount -Privilege SeServiceLogonRight
|
|
||||||
|
|
||||||
if(-not (test-path $logsdir -PathType Container))
|
if(-not (test-path $logsdir -PathType Container))
|
||||||
{
|
{
|
||||||
|
@ -122,7 +122,7 @@
|
|||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PrecompiledHeader>
|
<PrecompiledHeader>
|
||||||
</PrecompiledHeader>
|
</PrecompiledHeader>
|
||||||
<WarningLevel>Level1</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<PreprocessorDefinitions>_WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_WIN32_WINNT=0x600;WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<SDLCheck>false</SDLCheck>
|
<SDLCheck>false</SDLCheck>
|
||||||
@ -164,7 +164,7 @@
|
|||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>Level1</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<PrecompiledHeader>
|
<PrecompiledHeader>
|
||||||
</PrecompiledHeader>
|
</PrecompiledHeader>
|
||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
@ -223,7 +223,7 @@ SendKeyStroke(HANDLE hInput, int keyStroke, char character)
|
|||||||
void
|
void
|
||||||
ProcessIncomingKeys(char * ansikey)
|
ProcessIncomingKeys(char * ansikey)
|
||||||
{
|
{
|
||||||
int keylen = strlen(ansikey);
|
int keylen = (int)strlen(ansikey);
|
||||||
|
|
||||||
if (!keylen)
|
if (!keylen)
|
||||||
return;
|
return;
|
||||||
@ -407,7 +407,7 @@ SendCharacter(HANDLE hInput, WORD attributes, wchar_t character)
|
|||||||
StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, "m", Color);
|
StringCbPrintfExA(Next, SizeLeft, &Next, &SizeLeft, 0, "m", Color);
|
||||||
|
|
||||||
if (bUseAnsiEmulation && attributes != pattributes)
|
if (bUseAnsiEmulation && attributes != pattributes)
|
||||||
WriteFile(hInput, formatted_output, (Next - formatted_output), &wr, NULL);
|
WriteFile(hInput, formatted_output, (DWORD)(Next - formatted_output), &wr, NULL);
|
||||||
|
|
||||||
/* East asian languages have 2 bytes for each character, only use the first */
|
/* East asian languages have 2 bytes for each character, only use the first */
|
||||||
if (!(attributes & COMMON_LVB_TRAILING_BYTE)) {
|
if (!(attributes & COMMON_LVB_TRAILING_BYTE)) {
|
||||||
@ -481,8 +481,8 @@ SizeWindow(HANDLE hInput)
|
|||||||
inputSi.dwYCountChars = 25;
|
inputSi.dwYCountChars = 25;
|
||||||
}
|
}
|
||||||
|
|
||||||
srWindowRect.Right = (SHORT)(min(inputSi.dwXCountChars, coordScreen.X) - 1);
|
srWindowRect.Right = (SHORT)(min(inputSi.dwXCountChars, (DWORD)coordScreen.X) - 1);
|
||||||
srWindowRect.Bottom = (SHORT)(min(inputSi.dwYCountChars, coordScreen.Y) - 1);
|
srWindowRect.Bottom = (SHORT)(min(inputSi.dwYCountChars, (DWORD)coordScreen.Y) - 1);
|
||||||
srWindowRect.Left = srWindowRect.Top = (SHORT)0;
|
srWindowRect.Left = srWindowRect.Top = (SHORT)0;
|
||||||
|
|
||||||
/* Define the new console buffer size to be the maximum possible */
|
/* Define the new console buffer size to be the maximum possible */
|
||||||
@ -511,14 +511,12 @@ MonitorChild(_In_ LPVOID lpParameter)
|
|||||||
DWORD
|
DWORD
|
||||||
ProcessEvent(void *p)
|
ProcessEvent(void *p)
|
||||||
{
|
{
|
||||||
char f[255];
|
|
||||||
wchar_t chUpdate;
|
wchar_t chUpdate;
|
||||||
WORD wAttributes;
|
WORD wAttributes;
|
||||||
WORD wX;
|
WORD wX;
|
||||||
WORD wY;
|
WORD wY;
|
||||||
DWORD dwProcessId;
|
DWORD dwProcessId;
|
||||||
DWORD wr = 0;
|
DWORD wr = 0;
|
||||||
DWORD dwMode;
|
|
||||||
DWORD event;
|
DWORD event;
|
||||||
HWND hwnd;
|
HWND hwnd;
|
||||||
LONG idObject;
|
LONG idObject;
|
||||||
@ -640,8 +638,8 @@ ProcessEvent(void *p)
|
|||||||
return dwError;
|
return dwError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readRect.Top > currentLine)
|
if ((DWORD)readRect.Top > currentLine)
|
||||||
for (SHORT n = currentLine; n < readRect.Top; n++)
|
for (DWORD n = currentLine; n < (DWORD)readRect.Top; n++)
|
||||||
SendLF(pipe_out);
|
SendLF(pipe_out);
|
||||||
|
|
||||||
/* Set cursor location based on the reported location from the message */
|
/* Set cursor location based on the reported location from the message */
|
||||||
@ -779,8 +777,6 @@ ProcessEventQueue(LPVOID p)
|
|||||||
|
|
||||||
if (child_in != INVALID_HANDLE_VALUE && child_in != NULL &&
|
if (child_in != INVALID_HANDLE_VALUE && child_in != NULL &&
|
||||||
child_out != INVALID_HANDLE_VALUE && child_out != NULL) {
|
child_out != INVALID_HANDLE_VALUE && child_out != NULL) {
|
||||||
DWORD dwInputMode;
|
|
||||||
DWORD dwOutputMode;
|
|
||||||
|
|
||||||
ZeroMemory(&consoleInfo, sizeof(consoleInfo));
|
ZeroMemory(&consoleInfo, sizeof(consoleInfo));
|
||||||
consoleInfo.cbSize = sizeof(consoleInfo);
|
consoleInfo.cbSize = sizeof(consoleInfo);
|
||||||
@ -908,8 +904,6 @@ ConsoleEventProc(HWINEVENTHOOK hWinEventHook,
|
|||||||
DWORD
|
DWORD
|
||||||
ProcessMessages(void* p)
|
ProcessMessages(void* p)
|
||||||
{
|
{
|
||||||
BOOL ret;
|
|
||||||
DWORD dwMode;
|
|
||||||
DWORD dwStatus;
|
DWORD dwStatus;
|
||||||
SECURITY_ATTRIBUTES sa;
|
SECURITY_ATTRIBUTES sa;
|
||||||
MSG msg;
|
MSG msg;
|
||||||
@ -966,8 +960,6 @@ start_with_pty(wchar_t *command)
|
|||||||
wchar_t cmd[MAX_CMD_LEN];
|
wchar_t cmd[MAX_CMD_LEN];
|
||||||
SECURITY_ATTRIBUTES sa;
|
SECURITY_ATTRIBUTES sa;
|
||||||
BOOL ret;
|
BOOL ret;
|
||||||
DWORD dwThreadId;
|
|
||||||
DWORD dwMode;
|
|
||||||
DWORD dwStatus;
|
DWORD dwStatus;
|
||||||
HANDLE hEventHook = NULL;
|
HANDLE hEventHook = NULL;
|
||||||
HMODULE hm_kernel32 = NULL, hm_user32 = NULL;
|
HMODULE hm_kernel32 = NULL, hm_user32 = NULL;
|
||||||
@ -1226,6 +1218,102 @@ cleanup:
|
|||||||
return child_exit_code;
|
return child_exit_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <Shlobj.h>
|
||||||
|
#include <Sddl.h>
|
||||||
|
|
||||||
|
static void* xmalloc(size_t size) {
|
||||||
|
void* ptr;
|
||||||
|
if ((ptr = malloc(size)) == NULL) {
|
||||||
|
printf("out of memory");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SET_USER_ENV(folder_id, evn_variable) do { \
|
||||||
|
if (SHGetKnownFolderPath(&folder_id,0,NULL,&path) == S_OK) \
|
||||||
|
{ \
|
||||||
|
SetEnvironmentVariableW(evn_variable, path); \
|
||||||
|
CoTaskMemFree(path); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* set user environment variables from user profile */
|
||||||
|
static void setup_session_user_vars()
|
||||||
|
{
|
||||||
|
/* retrieve and set env variables. */
|
||||||
|
HKEY reg_key = 0;
|
||||||
|
wchar_t *path;
|
||||||
|
wchar_t name[256];
|
||||||
|
wchar_t *data = NULL, *data_expanded = NULL, *path_value = NULL, *to_apply;
|
||||||
|
DWORD type, name_chars = 256, data_chars = 0, data_expanded_chars = 0, required, i = 0;
|
||||||
|
LONG ret;
|
||||||
|
|
||||||
|
SET_USER_ENV(FOLDERID_LocalAppData, L"LOCALAPPDATA");
|
||||||
|
SET_USER_ENV(FOLDERID_Profile, L"USERPROFILE");
|
||||||
|
SET_USER_ENV(FOLDERID_RoamingAppData, L"APPDATA");
|
||||||
|
|
||||||
|
ret = RegOpenKeyExW(HKEY_CURRENT_USER, L"Environment", 0, KEY_QUERY_VALUE, ®_key);
|
||||||
|
if (ret != ERROR_SUCCESS)
|
||||||
|
//error("Error retrieving user environment variables. RegOpenKeyExW returned %d", ret);
|
||||||
|
return;
|
||||||
|
else while (1) {
|
||||||
|
to_apply = NULL;
|
||||||
|
required = data_chars * 2;
|
||||||
|
name_chars = 256;
|
||||||
|
ret = RegEnumValueW(reg_key, i++, name, &name_chars, 0, &type, (LPBYTE)data, &required);
|
||||||
|
if (ret == ERROR_NO_MORE_ITEMS)
|
||||||
|
break;
|
||||||
|
else if (ret == ERROR_MORE_DATA || required > data_chars * 2) {
|
||||||
|
if (data != NULL)
|
||||||
|
free(data);
|
||||||
|
data = xmalloc(required);
|
||||||
|
data_chars = required / 2;
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (ret != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (type == REG_SZ)
|
||||||
|
to_apply = data;
|
||||||
|
else if (type == REG_EXPAND_SZ) {
|
||||||
|
required = ExpandEnvironmentStringsW(data, data_expanded, data_expanded_chars);
|
||||||
|
if (required > data_expanded_chars) {
|
||||||
|
if (data_expanded)
|
||||||
|
free(data_expanded);
|
||||||
|
data_expanded = xmalloc(required * 2);
|
||||||
|
data_expanded_chars = required;
|
||||||
|
ExpandEnvironmentStringsW(data, data_expanded, data_expanded_chars);
|
||||||
|
}
|
||||||
|
to_apply = data_expanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wcsicmp(name, L"PATH") == 0) {
|
||||||
|
if ((required = GetEnvironmentVariableW(L"PATH", NULL, 0)) != 0) {
|
||||||
|
/* "required" includes null term */
|
||||||
|
path_value = xmalloc((wcslen(to_apply) + 1 + required) * 2);
|
||||||
|
GetEnvironmentVariableW(L"PATH", path_value, required);
|
||||||
|
path_value[required - 1] = L';';
|
||||||
|
memcpy(path_value + required, to_apply, (wcslen(to_apply) + 1) * 2);
|
||||||
|
to_apply = path_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (to_apply)
|
||||||
|
SetEnvironmentVariableW(name, to_apply);
|
||||||
|
}
|
||||||
|
if (reg_key)
|
||||||
|
RegCloseKey(reg_key);
|
||||||
|
if (data)
|
||||||
|
free(data);
|
||||||
|
if (data_expanded)
|
||||||
|
free(data_expanded);
|
||||||
|
if (path_value)
|
||||||
|
free(path_value);
|
||||||
|
RevertToSelf();
|
||||||
|
}
|
||||||
|
|
||||||
int b64_pton(char const *src, u_char *target, size_t targsize);
|
int b64_pton(char const *src, u_char *target, size_t targsize);
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -1254,6 +1342,8 @@ wmain(int ac, wchar_t **av)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_session_user_vars();
|
||||||
|
|
||||||
/* decode cmd_b64*/
|
/* decode cmd_b64*/
|
||||||
if (cmd_b64) {
|
if (cmd_b64) {
|
||||||
char *cmd_b64_utf8, *cmd_utf8;
|
char *cmd_b64_utf8, *cmd_utf8;
|
||||||
|
@ -39,10 +39,7 @@ pty_make_controlling_tty(int *ttyfd, const char *tty) {
|
|||||||
void
|
void
|
||||||
pty_change_window_size(int ptyfd, u_int row, u_int col,
|
pty_change_window_size(int ptyfd, u_int row, u_int col,
|
||||||
u_int xpixel, u_int ypixel) {
|
u_int xpixel, u_int ypixel) {
|
||||||
COORD coord;
|
/* TODO - Need to implement*/
|
||||||
coord.X = col;
|
|
||||||
coord.Y = 9999;
|
|
||||||
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coord);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
112
session.c
112
session.c
@ -299,16 +299,7 @@ xauth_valid_string(const char *s)
|
|||||||
* - Interactive shell/commands are executed using ssh-shellhost.exe
|
* - Interactive shell/commands are executed using ssh-shellhost.exe
|
||||||
* - ssh-shellhost.exe implements server-side PTY for Windows
|
* - ssh-shellhost.exe implements server-side PTY for Windows
|
||||||
*/
|
*/
|
||||||
#include <Shlobj.h>
|
|
||||||
#include <Sddl.h>
|
|
||||||
|
|
||||||
#define SET_USER_ENV(folder_id, evn_variable) do { \
|
|
||||||
if (SHGetKnownFolderPath(&folder_id,0,token,&path) == S_OK) \
|
|
||||||
{ \
|
|
||||||
SetEnvironmentVariableW(evn_variable, path); \
|
|
||||||
CoTaskMemFree(path); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define UTF8_TO_UTF16_FATAL(o, i) do { \
|
#define UTF8_TO_UTF16_FATAL(o, i) do { \
|
||||||
if (o != NULL) free(o); \
|
if (o != NULL) free(o); \
|
||||||
@ -316,85 +307,6 @@ xauth_valid_string(const char *s)
|
|||||||
fatal("%s, out of memory", __func__); \
|
fatal("%s, out of memory", __func__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static void setup_session_user_vars(Session* s) /* set user environment variables from user profile */
|
|
||||||
{
|
|
||||||
/* retrieve and set env variables. */
|
|
||||||
HKEY reg_key = 0;
|
|
||||||
HANDLE token = s->authctxt->methoddata;
|
|
||||||
wchar_t *path;
|
|
||||||
wchar_t name[256];
|
|
||||||
wchar_t *data = NULL, *data_expanded = NULL, *path_value = NULL, *to_apply;
|
|
||||||
DWORD type, name_chars = 256, data_chars = 0, data_expanded_chars = 0, required, i = 0;
|
|
||||||
LONG ret;
|
|
||||||
|
|
||||||
if (ImpersonateLoggedOnUser(token) == FALSE)
|
|
||||||
debug("Failed to impersonate user token, %d", GetLastError());
|
|
||||||
SET_USER_ENV(FOLDERID_LocalAppData, L"LOCALAPPDATA");
|
|
||||||
SET_USER_ENV(FOLDERID_Profile, L"USERPROFILE");
|
|
||||||
SET_USER_ENV(FOLDERID_RoamingAppData, L"APPDATA");
|
|
||||||
|
|
||||||
ret = RegOpenKeyExW(HKEY_CURRENT_USER, L"Environment", 0, KEY_QUERY_VALUE, ®_key);
|
|
||||||
if (ret != ERROR_SUCCESS)
|
|
||||||
error("Error retrieving user environment variables. RegOpenKeyExW returned %d", ret);
|
|
||||||
else while (1) {
|
|
||||||
to_apply = NULL;
|
|
||||||
required = data_chars * 2;
|
|
||||||
name_chars = 256;
|
|
||||||
ret = RegEnumValueW(reg_key, i++, name, &name_chars, 0, &type, (LPBYTE)data, &required);
|
|
||||||
if (ret == ERROR_NO_MORE_ITEMS)
|
|
||||||
break;
|
|
||||||
else if (ret == ERROR_MORE_DATA || required > data_chars * 2) {
|
|
||||||
if (data != NULL)
|
|
||||||
free(data);
|
|
||||||
data = xmalloc(required);
|
|
||||||
data_chars = required/2;
|
|
||||||
i--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (ret != ERROR_SUCCESS) {
|
|
||||||
error("Error retrieving user environment variables. RegEnumValueW returned %d", ret);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == REG_SZ)
|
|
||||||
to_apply = data;
|
|
||||||
else if (type == REG_EXPAND_SZ) {
|
|
||||||
required = ExpandEnvironmentStringsW(data, data_expanded, data_expanded_chars);
|
|
||||||
if (required > data_expanded_chars) {
|
|
||||||
if (data_expanded)
|
|
||||||
free(data_expanded);
|
|
||||||
data_expanded = xmalloc(required * 2);
|
|
||||||
data_expanded_chars = required;
|
|
||||||
ExpandEnvironmentStringsW(data, data_expanded, data_expanded_chars);
|
|
||||||
}
|
|
||||||
to_apply = data_expanded;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wcsicmp(name, L"PATH") == 0) {
|
|
||||||
if ((required = GetEnvironmentVariableW(L"PATH", NULL, 0)) != 0) {
|
|
||||||
/* "required" includes null term */
|
|
||||||
path_value = xmalloc((wcslen(to_apply) + 1 + required)*2);
|
|
||||||
GetEnvironmentVariableW(L"PATH", path_value, required);
|
|
||||||
path_value[required - 1] = L';';
|
|
||||||
memcpy(path_value + required, to_apply, (wcslen(to_apply) + 1) * 2);
|
|
||||||
to_apply = path_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (to_apply)
|
|
||||||
SetEnvironmentVariableW(name, to_apply);
|
|
||||||
}
|
|
||||||
if (reg_key)
|
|
||||||
RegCloseKey(reg_key);
|
|
||||||
if (data)
|
|
||||||
free(data);
|
|
||||||
if (data_expanded)
|
|
||||||
free(data_expanded);
|
|
||||||
if (path_value)
|
|
||||||
free(path_value);
|
|
||||||
RevertToSelf();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_session_vars(Session* s) {
|
static void setup_session_vars(Session* s) {
|
||||||
wchar_t *pw_dir_w = NULL, *tmp = NULL;
|
wchar_t *pw_dir_w = NULL, *tmp = NULL;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
@ -444,7 +356,6 @@ static void setup_session_vars(Session* s) {
|
|||||||
SetEnvironmentVariableW(L"PROMPT", wbuf);
|
SetEnvironmentVariableW(L"PROMPT", wbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_session_user_vars(s);
|
|
||||||
free(pw_dir_w);
|
free(pw_dir_w);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
}
|
}
|
||||||
@ -579,29 +490,6 @@ int do_exec_windows(Session *s, const char *command, int pty) {
|
|||||||
|
|
||||||
if (!b)
|
if (!b)
|
||||||
fatal("ERROR. Cannot create process (%u).\n", GetLastError());
|
fatal("ERROR. Cannot create process (%u).\n", GetLastError());
|
||||||
else if (pty) { /*attach to shell console */
|
|
||||||
FreeConsole();
|
|
||||||
if (!debug_flag)
|
|
||||||
ImpersonateLoggedOnUser(hToken);
|
|
||||||
Sleep(20);
|
|
||||||
while (AttachConsole(pi.dwProcessId) == FALSE) {
|
|
||||||
DWORD exit_code;
|
|
||||||
if (GetExitCodeProcess(pi.hProcess, &exit_code) && exit_code != STILL_ACTIVE)
|
|
||||||
break;
|
|
||||||
Sleep(100);
|
|
||||||
}
|
|
||||||
if (!debug_flag)
|
|
||||||
RevertToSelf();
|
|
||||||
{
|
|
||||||
/* TODO - check this - Create Process above is not respecting x# and y# chars, so we are doing this explicity on the
|
|
||||||
* attached console agein */
|
|
||||||
|
|
||||||
COORD coord;
|
|
||||||
coord.X = s->col;
|
|
||||||
coord.Y = 9999;;
|
|
||||||
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseHandle(pi.hThread);
|
CloseHandle(pi.hThread);
|
||||||
s->pid = pi.dwProcessId;
|
s->pid = pi.dwProcessId;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user