<commit_before>/*
 * Copyright 2000-2017 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <Windows.h>
#include <elevTools.h>
#include <stdio.h>
#include <string.h>

#define ERR_INVALID_HANDLE -1
#define ERR_CANT_INHERIT -2
#define ERR_CANT_SET_CONSOLE -3
#define ERR_BAD_COMMAND_LINE -4
#define ERR_SET_DIR -5
#define ERR_PARENT_ID -6
#define ERR_GET_DESC -7
#define ERR_BAD_DESC -8
#define ERR_FAILED_TO_FIND -9 
#define ERR_FAILED_ATTACH - 10
#define ERR_OPEN_PARENT - 11
#define ERR_LAUNCHING - 12
#define ERR_WAITING - 13
#define ERR_PARENT_DIED -14
#define ERR_FAILED_PIPE_READ -15


// UAC-enabled (in manifset) tool to launch ptocesses.
// Connects to pipes and console, and then launches new process using CreateProcess

// Author: <NAME>


// Connects and waits for pipe if required by descriptor flags
// nDescriptor ELEV_DESC_*
// nDescriptorFlags flags passed from launcher to check if descriptor should be connected
// Returns 0 if ok, error otherwise. Could be windows error, EBADF or EMFILE for dup2
static DWORD _ConnectIfNeededPipe(DWORD nParentPid, DWORD nDescriptor, FILE* stream, int nDescriptorFlags, _Out_ PHANDLE pRemoteProcessHandle, _In_ HANDLE eventSource)
{
	if (!(nDescriptorFlags & nDescriptor))
	{
		*pRemoteProcessHandle = GetStdHandle(ELEV_DESCR_GET_HANDLE(nDescriptor));
		return 0; // Not needed to connect pipe, use real descriptor
	}
	ELEV_PIPE_NAME sPipeName;
	ELEV_GEN_PIPE_NAME(sPipeName, nParentPid, nDescriptor);
	WaitNamedPipe(sPipeName, INFINITE);
	BOOL bStdIn = nDescriptor == ELEV_DESCR_STDIN;
	unsigned long access = (bStdIn ? GENERIC_READ : GENERIC_WRITE);
	HANDLE hPipe = CreateFile(sPipeName, access, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hPipe == INVALID_HANDLE_VALUE || hPipe == NULL)
	{
		ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_INVALID_HANDLE, NULL, 0, 0, NULL, NULL);
		return GetLastError();
	}

	// Make inheritable by remote process
	if (!SetHandleInformation(hPipe, HANDLE_FLAG_INHERIT, TRUE))
	{
		ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_CANT_INHERIT, NULL, 0, 0, NULL, NULL);
		return GetLastError();
	}		

	// Fix Win32API
	DWORD hStdHandleToChange = ELEV_DESCR_GET_HANDLE(nDescriptor);
	if (!SetStdHandle(hStdHandleToChange, hPipe))
	{
		ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_CANT_SET_CONSOLE, NULL, 0, 0, NULL, NULL);
		return GetLastError();
	}

	*pRemoteProcessHandle = hPipe;
	return 0;
}

// Get the environment vars from the launcher through the named pipe.
static void _ReadAndSetEnvVars(DWORD nParentPid, _In_ HANDLE eventSource)
{
	ELEV_PIPE_NAME sEnvVarsPipeName;
	ELEV_GEN_PIPE_NAME(sEnvVarsPipeName, nParentPid, ELEV_DESCR_ENVVAR);

	HANDLE hEnvVarsPipe = CreateFile(sEnvVarsPipeName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
	if (hEnvVarsPipe == INVALID_HANDLE_VALUE) {
		ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_INVALID_HANDLE, NULL, 0, 0, NULL, NULL);
		fwprintf(stderr, L"Error opening env vars pipe. Exit code %ld", GetLastError());
		exit(ERR_INVALID_HANDLE);
	}

	WCHAR* buf = malloc(_MAX_ENV);
	while (TRUE) {
		DWORD ulBytesRead = 0;
		BOOL bReadOk = ReadFile(hEnvVarsPipe, buf, _MAX_ENV, &ulBytesRead, NULL);
		DWORD nError = GetLastError();
		if (nError == ERROR_BROKEN_PIPE || ulBytesRead == 0)
		{
			break;
		}
		if (!bReadOk)
		{
			ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_FAILED_PIPE_READ, NULL, 0, 0, NULL, NULL);
			fwprintf(stderr, L"Failed to read from env pipe: %ld", nError);
			exit(ERR_FAILED_PIPE_READ);
		}<commit_msg>CPP-20035 debug as root: Report GetLastError in _ReadAndSetEnvVars<commit_after>/*
 * Copyright 2000-2017 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <Windows.h>
#include <elevTools.h>
#include <stdio.h>
#include <string.h>

#define ERR_INVALID_HANDLE -1
#define ERR_CANT_INHERIT -2
#define ERR_CANT_SET_CONSOLE -3
#define ERR_BAD_COMMAND_LINE -4
#define ERR_SET_DIR -5
#define ERR_PARENT_ID -6
#define ERR_GET_DESC -7
#define ERR_BAD_DESC -8
#define ERR_FAILED_TO_FIND -9 
#define ERR_FAILED_ATTACH - 10
#define ERR_OPEN_PARENT - 11
#define ERR_LAUNCHING - 12
#define ERR_WAITING - 13
#define ERR_PARENT_DIED -14
#define ERR_FAILED_PIPE_READ -15


// UAC-enabled (in manifset) tool to launch ptocesses.
// Connects to pipes and console, and then launches new process using CreateProcess

// Author: <NAME>


// Connects and waits for pipe if required by descriptor flags
// nDescriptor ELEV_DESC_*
// nDescriptorFlags flags passed from launcher to check if descriptor should be connected
// Returns 0 if ok, error otherwise. Could be windows error, EBADF or EMFILE for dup2
static DWORD _ConnectIfNeededPipe(DWORD nParentPid, DWORD nDescriptor, FILE* stream, int nDescriptorFlags, _Out_ PHANDLE pRemoteProcessHandle, _In_ HANDLE eventSource)
{
	if (!(nDescriptorFlags & nDescriptor))
	{
		*pRemoteProcessHandle = GetStdHandle(ELEV_DESCR_GET_HANDLE(nDescriptor));
		return 0; // Not needed to connect pipe, use real descriptor
	}
	ELEV_PIPE_NAME sPipeName;
	ELEV_GEN_PIPE_NAME(sPipeName, nParentPid, nDescriptor);
	WaitNamedPipe(sPipeName, INFINITE);
	BOOL bStdIn = nDescriptor == ELEV_DESCR_STDIN;
	unsigned long access = (bStdIn ? GENERIC_READ : GENERIC_WRITE);
	HANDLE hPipe = CreateFile(sPipeName, access, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hPipe == INVALID_HANDLE_VALUE || hPipe == NULL)
	{
		ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_INVALID_HANDLE, NULL, 0, 0, NULL, NULL);
		return GetLastError();
	}

	// Make inheritable by remote process
	if (!SetHandleInformation(hPipe, HANDLE_FLAG_INHERIT, TRUE))
	{
		ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_CANT_INHERIT, NULL, 0, 0, NULL, NULL);
		return GetLastError();
	}		

	// Fix Win32API
	DWORD hStdHandleToChange = ELEV_DESCR_GET_HANDLE(nDescriptor);
	if (!SetStdHandle(hStdHandleToChange, hPipe))
	{
		ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_CANT_SET_CONSOLE, NULL, 0, 0, NULL, NULL);
		return GetLastError();
	}

	*pRemoteProcessHandle = hPipe;
	return 0;
}

// Get the environment vars from the launcher through the named pipe.
static void _ReadAndSetEnvVars(DWORD nParentPid, _In_ HANDLE eventSource)
{
	ELEV_PIPE_NAME sEnvVarsPipeName;
	ELEV_GEN_PIPE_NAME(sEnvVarsPipeName, nParentPid, ELEV_DESCR_ENVVAR);

	HANDLE hEnvVarsPipe = CreateFile(sEnvVarsPipeName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
	if (hEnvVarsPipe == INVALID_HANDLE_VALUE) {
		DWORD nError = GetLastError();
		ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_INVALID_HANDLE, NULL, 0, 0, NULL, NULL);
		fwprintf(stderr, L"Error opening env vars pipe. Exit code %ld", nError);
		exit(nError);
	}

	WCHAR* buf = malloc(_MAX_ENV);
	while (TRUE) {
		DWORD ulBytesRead = 0;
		BOOL bReadOk = ReadFile(hEnvVarsPipe, buf, _MAX_ENV, &ulBytesRead, NULL);
		DWORD nError = GetLastError();
		if (nError == ERROR_BROKEN_PIPE || ulBytesRead == 0)
		{
			break;
		}
		if (!bReadOk)
		{
			ReportEvent(eventSource, EVENTLOG_ERROR_TYPE, 0, ERR_FAILED_PIPE_READ, NULL, 0, 0, NULL, NULL);
			fwprintf(stderr, L"Failed to read from env pipe: %ld", nError);
			exit(ERR_FAILED_PIPE_READ);
		}
{'fraction_non_alphanumeric': 0.09262435677530018, 'fraction_numerical': 0.015069835824552806, 'mean_word_length': 5.151469480030143, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5986434', 'n_tokens_mistral': 3016, 'n_tokens_neox': 2825, 'n_words': 834}