Blob Blame History Raw
/*********************************************************/
/*  toksvc: a framework-native token broker service      */
/*  Copyright (C) 2020  SysDeer Technologies, LLC        */
/*  Released under GPLv2 and GPLv3; see COPYING.TOKSVC.  */
/*********************************************************/

#include <psxtypes/psxtypes.h>

#include "toksvc_driver_impl.h"
#include "toksvc_dprintf_impl.h"
#include "toksvc_log_impl.h"

static const char * toks_log_entry_header[15] = {
	[TOKS_LOG_ENTRY_SERVER_STATUS] = "SERVER (STATUS):",
	[TOKS_LOG_ENTRY_SERVER_INFO]   = "SERVER (INFO):  ",
	[TOKS_LOG_ENTRY_SERVER_ERROR]  = "SERVER (ERROR): ",
	[TOKS_LOG_ENTRY_CLIENT_STATUS] = "CLIENT (STATUS):",
	[TOKS_LOG_ENTRY_CLIENT_INFO]   = "CLIENT (INFO):  ",
	[TOKS_LOG_ENTRY_CLIENT_ERROR]  = "CLIENT (ERROR): ",
	[TOKS_LOG_ENTRY_SUB_LEVEL_1]   = " ├─",
	[TOKS_LOG_ENTRY_SUB_LEVEL_2]   = " ├───",
	[TOKS_LOG_ENTRY_SUB_LEVEL_3]   = " ├─────",
	[TOKS_LOG_ENTRY_SUB_LEVEL_4]   = " ├───────",
	[TOKS_LOG_ENTRY_SUB_LEVEL_5]   = " ├─────────",
	[TOKS_LOG_ENTRY_SUB_LEVEL_6]   = " ├───────────",
};

static int32_t toks_log_strconv_utf16_to_utf8(
	const wchar16_t *	wch,
	size_t			len,
	char *			ch,
	size_t			bufsize)
{
	int32_t			status;
	nt_strconv_nativetomb	params;

	params.src		 = wch;
	params.src_size_in_bytes = len;
	params.dst		 = (unsigned char *)ch;
	params.dst_size_in_bytes = bufsize;
	params.code_points	 = 0;
	params.bytes_written	 = 0;

	status = ntapi->uc_convert_unicode_stream_utf16_to_utf8(&params);

	if (status == NT_STATUS_SUCCESS)
		ch[params.bytes_written] = 0;

	return params.leftover_count
		? NT_STATUS_ILLEGAL_CHARACTER
		: status;
}

static int32_t toks_log_write_impl(
	const struct toks_driver_ctx *  dctx,
	const void *                    buf,
	size_t                          size)
{
	int32_t			status;
	nt_runtime_data *	rtdata;
	ntapi_zw_write_file *	iofn;
	void *			hlog;
	void *			hio;
	void *			hevent;
	int			fdtype;
	nt_iosb			iosb;
	const char *		ch;

	/* size */
	if (size >= 0x80000000)
		return NT_STATUS_INVALID_PARAMETER;

	/* rtdata, hevent, hlog */
	hevent = toks_get_driver_hevent(dctx);
	rtdata = toks_get_driver_rtdata(dctx);
	hlog   = rtdata->hlog;
	ch     = buf;

	/* hio, io type */
	if (hlog) {
		hio    = hlog;
		fdtype = NT_FILE_TYPE_UNKNOWN;
	} else {
		hio    = rtdata->hstderr;
		fdtype = rtdata->stderr_type;
	}

	if (!hio)
		return NT_STATUS_INVALID_HANDLE;

	/* iofn */
	iofn = (fdtype ==  NT_FILE_TYPE_PTY)
		? (ntapi_zw_write_file *)toks_ntapi->pty_write
		: toks_ntapi->zw_write_file;

	/* iowrite */
	do {
		iosb.status = NT_STATUS_PENDING;

		status = iofn(
			hio,hevent,
			0,0,&iosb,
			(void *)ch,
			size,0,0);

		if (status == NT_STATUS_PENDING)
			toks_ntapi->zw_wait_for_single_object(
				hevent,0,0);

		size -= iosb.info;
		ch   += iosb.info;
	} while (size && (iosb.status == NT_STATUS_SUCCESS));


	/* ret */
	return iosb.status;
}

void toks_log_header(
	const struct toks_driver_ctx *  dctx,
	enum toks_log_entry_type        type,
	const char *                    fmt,
	...)
{
	nt_filetime	pcnt;
	va_list		ap;
	char *		ch;
	char		buf[2048];

	toks_query_performance_counters(dctx,&pcnt);

	va_start(ap, fmt);
	ch  = buf;
	ch += ntapi->sprintf(ch,"\n[%08x.%08x]: ",pcnt.ihigh,pcnt.ulow);
	ch += ntapi->sprintf(ch,"%s ",toks_log_entry_header[type]);
	ch += ntapi->vsnprintf(ch, &buf[sizeof(buf)] - ch, fmt, ap);
	va_end(ap);

	toks_log_write_impl(dctx,buf,ch-buf);
}

void toks_log_write(
	const struct toks_driver_ctx *  dctx,
	enum toks_log_entry_type        type,
	const char *                    fmt,
	...)
{
	va_list		ap;
	char *		ch;
	char		buf[2048];

	va_start(ap, fmt);
	ch  = buf;
	ch += ntapi->sprintf(buf,"%s ",toks_log_entry_header[type]);
	ch += ntapi->vsnprintf(ch, &buf[sizeof(buf)] - ch, fmt, ap);
	va_end(ap);

	toks_log_write_impl(dctx,buf,ch-buf);
}

void toks_log_get_process_name(void * hprocess, char * utf8, size_t bytes)
{
	wchar16_t		buf[0x1000];
	nt_unicode_string *	path;

	path = (nt_unicode_string *)buf;

	if (!(ntapi->zw_query_information_process(
			hprocess,
			NT_PROCESS_IMAGE_FILE_NAME,
			buf,sizeof(buf),
			&(uint32_t){0})))
		if (!(toks_log_strconv_utf16_to_utf8(
				path->buffer,
				path->strlen,
				utf8,bytes)))
			return;

	ntapi->tt_generic_memcpy(
		utf8,
		(char[]){'#','E','R','R','O','R',0},
		7);
}

void toks_log_get_arbitrary_process_name(nt_cid * cid, char * utf8, size_t bytes)
{
	void *	hprocess = NT_INVALID_HANDLE_VALUE;
	nt_oa	oa = {sizeof(oa),0,0,0,0,0};

	if (cid->process_id == 0) {
		*utf8++ = '(';
		*utf8++ = 'N';
		*utf8++ = '/';
		*utf8++ = 'A';
		*utf8++ = ')';
		*utf8++ = 0;
		return;
	}

	ntapi->zw_open_process(
		&hprocess,
		NT_PROCESS_SYNCHRONIZE | NT_PROCESS_QUERY_INFORMATION,
		&oa,cid);

	if (hprocess == NT_INVALID_HANDLE_VALUE) {
		ntapi->tt_generic_memcpy(
			utf8,
			(char[]){'#','E','R','R','O','R',0},
			7);

		return;
	}

	toks_log_get_process_name(
		hprocess,
		utf8,bytes);

	ntapi->zw_close(
		hprocess);
}

const char * toks_log_basename(const char * path)
{
	const char * ch;

	for (ch=path; *ch; ch++)
		(void)0;

	for (--ch; ch>=path; ch--)
		if (*ch == '\\')
			return ++ch;

	return path;
}