1 // SoftEther VPN Source Code - Developer Edition Master Branch
2 // Mayaqua Kernel
3 
4 
5 // Mayaqua.c
6 // Mayaqua Kernel program
7 
8 #include "Mayaqua.h"
9 
10 #include "Encrypt.h"
11 #include "FileIO.h"
12 #include "GlobalConst.h"
13 #include "Internat.h"
14 #include "Memory.h"
15 #include "Microsoft.h"
16 #include "Network.h"
17 #include "Object.h"
18 #include "OS.h"
19 #include "Secure.h"
20 #include "Str.h"
21 #include "Table.h"
22 #include "Tick64.h"
23 #include "Tracking.h"
24 
25 #include <locale.h>
26 #include <stdlib.h>
27 
28 // Global variable
29 bool g_memcheck;								// Enable memory check
30 bool g_debug;									// Debug mode
31 UINT64 kernel_status[NUM_KERNEL_STATUS];		// Kernel state
32 UINT64 kernel_status_max[NUM_KERNEL_STATUS];	// Kernel state (maximum value)
33 LOCK *kernel_status_lock[NUM_KERNEL_STATUS];	// Kernel state lock
34 bool kernel_status_inited = false;				// Kernel state initialization flag
35 bool g_little_endian = true;
36 char *cmdline = NULL;							// Command line
37 wchar_t *uni_cmdline = NULL;					// Unicode command line
38 bool g_foreground = false;					// Execute service in foreground mode
39 
40 // Static variable
41 static char *exename = NULL;						// EXE file name (ANSI)
42 static wchar_t *exename_w = NULL;					// EXE file name (Unicode)
43 static TOKEN_LIST *cmdline_token = NULL;			// Command line token
44 static UNI_TOKEN_LIST *cmdline_uni_token = NULL;	// Command line token (Unicode)
45 static OS_INFO *os_info = NULL;						// OS information
46 static bool dot_net_mode = false;
47 static bool minimal_mode = false;
48 static UINT last_time_check = 0;
49 static UINT first_time_check = 0;
50 static bool is_nt = false;
51 static bool is_ham_mode = false;
52 static UINT init_mayaqua_counter = 0;
53 static bool use_probe = false;
54 static BUF *probe_buf = NULL;
55 static LOCK *probe_lock = NULL;
56 static UINT64 probe_start = 0;
57 static UINT64 probe_last = 0;
58 static bool probe_enabled = false;
59 
60 // The function which should be called once as soon as possible after the process is started
61 static bool init_proc_once_flag = false;
InitProcessCallOnce()62 void InitProcessCallOnce()
63 {
64 	if (init_proc_once_flag == false)
65 	{
66 		init_proc_once_flag = true;
67 
68 #ifdef	OS_WIN32
69 		MsInitProcessCallOnce();
70 #endif	// OS_WIN32
71 	}
72 }
73 
74 // Calculate the checksum
CalcChecksum16(void * buf,UINT size)75 USHORT CalcChecksum16(void *buf, UINT size)
76 {
77 	int sum = 0;
78 	USHORT *addr = (USHORT *)buf;
79 	int len = (int)size;
80 	USHORT *w = addr;
81 	int nleft = len;
82 	USHORT answer = 0;
83 
84 	while (nleft > 1)
85 	{
86 		USHORT ww = 0;
87 		Copy(&ww, w++, sizeof(USHORT));
88 		sum += ww;
89 		nleft -= 2;
90 	}
91 
92 	if (nleft == 1)
93 	{
94 		*(UCHAR *)(&answer) = *(UCHAR *)w;
95 		sum += answer;
96 	}
97 
98 	sum = (sum >> 16) + (sum & 0xffff);
99 	sum += (sum >> 16);
100 
101 	answer = ~sum;
102 
103 	return answer;
104 }
105 
106 // Writing a probe with the data
WriteProbeData(char * filename,UINT line,char * str,void * data,UINT size)107 void WriteProbeData(char *filename, UINT line, char *str, void *data, UINT size)
108 {
109 	char tmp[MAX_SIZE];
110 	USHORT cs;
111 
112 	if (IsProbeEnabled() == false)
113 	{
114 		return;
115 	}
116 
117 	// Take a checksum of the data
118 	if (size != 0)
119 	{
120 		cs = CalcChecksum16(data, size);
121 	}
122 	else
123 	{
124 		cs = 0;
125 	}
126 
127 	// Generating a String
128 	snprintf(tmp, sizeof(tmp), "\"%s\" (Size=%5u, Crc=0x%04X)", str, size, cs);
129 
130 	WriteProbe(filename, line, tmp);
131 }
132 
133 // Writing Probe
WriteProbe(char * filename,UINT line,char * str)134 void WriteProbe(char *filename, UINT line, char *str)
135 {
136 #ifdef	OS_WIN32
137 	char *s;
138 	char tmp[MAX_SIZE];
139 	char tmp2[MAX_SIZE];
140 	UINT64 now = 0;
141 	UINT64 time;
142 
143 	if (IsProbeEnabled() == false)
144 	{
145 		return;
146 	}
147 
148 	now = MsGetHiResCounter();
149 
150 	Lock(probe_lock);
151 	{
152 		UINT64 diff;
153 
154 		time = MsGetHiResTimeSpanUSec(now - probe_start);
155 
156 		diff = time - probe_last;
157 
158 		if (time < probe_last)
159 		{
160 			diff = 0;
161 		}
162 
163 		probe_last = time;
164 
165 		ToStr64(tmp, time);
166 		MakeCharArray2(tmp2, ' ', (UINT)(MIN(12, (int)12 - (int)StrLen(tmp))));
167 		WriteBuf(probe_buf, tmp2, StrLen(tmp2));
168 		WriteBuf(probe_buf, tmp, StrLen(tmp));
169 
170 		s = " [+";
171 		WriteBuf(probe_buf, s, StrLen(s));
172 
173 		ToStr64(tmp, diff);
174 		MakeCharArray2(tmp2, ' ', (UINT)(MIN(12, (int)12 - (int)StrLen(tmp))));
175 		WriteBuf(probe_buf, tmp2, StrLen(tmp2));
176 		WriteBuf(probe_buf, tmp, StrLen(tmp));
177 
178 		s = "] - ";
179 		WriteBuf(probe_buf, s, StrLen(s));
180 
181 		WriteBuf(probe_buf, filename, StrLen(filename));
182 
183 		s = "(";
184 		WriteBuf(probe_buf, s, StrLen(s));
185 
186 		ToStr64(tmp, (UINT64)line);
187 		WriteBuf(probe_buf, tmp, StrLen(tmp));
188 
189 		s = "): ";
190 		WriteBuf(probe_buf, s, StrLen(s));
191 
192 		WriteBuf(probe_buf, str, StrLen(str));
193 
194 		s = "\r\n";
195 		WriteBuf(probe_buf, s, StrLen(s));
196 	}
197 	Unlock(probe_lock);
198 #endif	// OS_WIN32
199 }
200 
201 // Initialization of Probe
InitProbe()202 void InitProbe()
203 {
204 	probe_buf = NewBuf();
205 	probe_lock = NewLock();
206 	probe_enabled = false;
207 
208 	probe_start = 0;
209 
210 #ifdef	OS_WIN32
211 	probe_start = MsGetHiResCounter();
212 #endif	// OS_WIN32
213 }
214 
215 // Release of Probe
FreeProbe()216 void FreeProbe()
217 {
218 	if (probe_buf->Size >= 1)
219 	{
220 		SYSTEMTIME st;
221 		char filename[MAX_SIZE];
222 
223 		// Write all to the file
224 		MakeDirEx("@probe_log");
225 
226 		LocalTime(&st);
227 
228 		snprintf(filename, sizeof(filename), "@probe_log/%04u%02u%02u_%02u%02u%02u.log",
229 			st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
230 
231 		DumpBuf(probe_buf, filename);
232 	}
233 
234 	FreeBuf(probe_buf);
235 	DeleteLock(probe_lock);
236 }
237 
238 // Set enable / disable the Probe
EnableProbe(bool enable)239 void EnableProbe(bool enable)
240 {
241 	probe_enabled = enable;
242 }
243 
244 // Get whether the Probe is enabled?
IsProbeEnabled()245 bool IsProbeEnabled()
246 {
247 #ifndef	USE_PROBE
248 	return false;
249 #else	// USE_PROBE
250 	return probe_enabled;
251 #endif	// USE_PROBE
252 }
253 
254 // Set the Ham mode
SetHamMode()255 void SetHamMode()
256 {
257 	is_ham_mode = true;
258 }
259 
260 // Get whether in Ham mode
IsHamMode()261 bool IsHamMode()
262 {
263 	return is_ham_mode;
264 }
265 
266 // Display the time from the previous call to now
TimeCheck()267 void TimeCheck()
268 {
269 #ifdef OS_WIN32
270 	UINT now, ret, total;
271 	now = Win32GetTick();
272 	if (last_time_check == 0)
273 	{
274 		ret = 0;
275 	}
276 	else
277 	{
278 		ret = now - last_time_check;
279 	}
280 	last_time_check = now;
281 
282 	if (first_time_check == 0)
283 	{
284 		first_time_check = now;
285 	}
286 
287 	total = now - first_time_check;
288 
289 	printf(" -- %3.3f / %3.3f\n", (double)ret / 1000.0f, (double)total / 1000.0f);
290 #endif	// OS_WIN32
291 }
292 
293 // Whether this system is IA64
IsIA64()294 bool IsIA64()
295 {
296 	if (Is64() == false)
297 	{
298 		return false;
299 	}
300 
301 #ifndef	MAYAQUA_IA_64
302 	return false;
303 #else	// MAYAQUA_IA_64
304 	return true;
305 #endif	// MAYAQUA_IA_64
306 }
307 
308 // Whether in x64
IsX64()309 bool IsX64()
310 {
311 	if (Is64() == false)
312 	{
313 		return false;
314 	}
315 
316 #ifndef	MAYAQUA_IA_64
317 	return true;
318 #else	// MAYAQUA_IA_64
319 	return false;
320 #endif	// MAYAQUA_IA_64
321 }
322 
323 // Whether 64bit
Is64()324 bool Is64()
325 {
326 #ifdef	CPU_64
327 	return true;
328 #else	// CPU_64
329 	return false;
330 #endif	// CPU_64
331 }
332 
333 // Whether 32bit
Is32()334 bool Is32()
335 {
336 	return Is64() ? false : true;
337 }
338 
339 // Acquisition whether in .NET mode
MayaquaIsDotNetMode()340 bool MayaquaIsDotNetMode()
341 {
342 	return dot_net_mode;
343 }
344 
345 // Check the endian
CheckEndian()346 void CheckEndian()
347 {
348 	unsigned short test;
349 	UCHAR *buf;
350 
351 	test = 0x1234;
352 	buf = (UCHAR *)&test;
353 	if (buf[0] == 0x12)
354 	{
355 		g_little_endian = false;
356 	}
357 	else
358 	{
359 		g_little_endian = true;
360 	}
361 }
362 
363 // Minimize mode
MayaquaMinimalMode()364 void MayaquaMinimalMode()
365 {
366 	minimal_mode = true;
367 }
MayaquaIsMinimalMode()368 bool MayaquaIsMinimalMode()
369 {
370 	return minimal_mode;
371 }
372 
373 // Whether in NT
IsNt()374 bool IsNt()
375 {
376 	return is_nt;
377 }
378 
379 // Initialization of Mayaqua library
InitMayaqua(bool memcheck,bool debug,int argc,char ** argv)380 void InitMayaqua(bool memcheck, bool debug, int argc, char **argv)
381 {
382 	wchar_t tmp[MAX_PATH];
383 	UCHAR hash[SHA1_SIZE];
384 
385 	if ((init_mayaqua_counter++) > 0)
386 	{
387 		return;
388 	}
389 
390 	InitProcessCallOnce();
391 
392 	g_memcheck = memcheck;
393 	g_debug = debug;
394 	cmdline = NULL;
395 	if (dot_net_mode == false)
396 	{
397 		// Fail this for some reason when this is called this in .NET mode
398 		setbuf(stdout, NULL);
399 	}
400 
401 #ifdef OS_UNIX
402 	g_foreground = (argc >= 3 && StrCmpi(argv[2], UNIX_SVC_ARG_FOREGROUND) == 0);
403 #else
404 	g_foreground = false;
405 #endif // OS_UNIX
406 
407 	// Acquisition whether NT
408 #ifdef	OS_WIN32
409 	is_nt = Win32IsNt();
410 #endif	// OS_WIN32
411 
412 	// Check endian
413 	CheckEndian();
414 
415 #ifdef	OS_WIN32
416 	_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
417 #endif	// OS_WIN32
418 
419 	// Set the locale information of the CRT to the Japanese
420 	setlocale(LC_ALL, "");
421 
422 	// Initialization of OS
423 	OSInit();
424 
425 	// Initialize the random number
426 	srand((UINT)SystemTime64());
427 
428 	tick_manual_lock = NewLock();
429 
430 	// Initialization of CRC32
431 	InitCrc32();
432 
433 	// Initialization of the FIFO system
434 	InitFifo();
435 
436 	// Initialize the Kernel status
437 	InitKernelStatus();
438 
439 	if (IsTrackingEnabled())
440 	{
441 		// Initialize the tracking
442 		InitTracking();
443 	}
444 
445 	// Initialization of thread pool
446 	InitThreading();
447 
448 	// Initialize the string library
449 	InitStringLibrary();
450 
451 	// Initialization of the locale information
452 	SetLocale(NULL);
453 
454 	// Initialization of the crypt library
455 	InitCryptLibrary();
456 
457 	// Initialization of the real-time clock
458 	InitTick64();
459 
460 	// Initialize the network communication module
461 	InitNetwork();
462 
463 	// Initialization of the acquisition of the EXE file name
464 	InitGetExeName(argc >= 1 ? argv[0] : NULL);
465 
466 	// Initialization of the command line string
467 	InitCommandLineStr(argc, argv);
468 
469 	// Initialization of OS information
470 	InitOsInfo();
471 
472 	// Initialization of the operating system-specific module
473 #ifdef	OS_WIN32
474 	MsInit();	// Microsoft Win32
475 #endif	// OS_WIN32
476 
477 	// Initialization of the security token module
478 	InitSecure();
479 
480 	if (OSIsSupportedOs() == false)
481 	{
482 		// Abort
483 		exit(0);
484 	}
485 
486 	// RSA Check
487 	if (RsaCheckEx() == false)
488 	{
489 		// Abort
490 		Alert("OpenSSL Library Init Failed. (too old?)\nPlease install the latest version of OpenSSL.\n\n", "RsaCheck()");
491 		exit(0);
492 	}
493 
494 	// Initialization of HamCore file system
495 	InitHamcore();
496 
497 	// Initialization of string table routine
498 	InitTable();
499 
500 	if (exename == NULL)
501 	{
502 		// Executable file name
503 		exename = CopyStr("unknown");
504 	}
505 
506 	// Check whether the executable file name of themselves is found
507 	// (If not found, quit because this is started in strange path)
508 	GetExeNameW(tmp, sizeof(tmp));
509 	if (IsFileExistsW(tmp) == false)
510 	{
511 		wchar_t tmp2[MAX_SIZE];
512 
513 		UniFormat(tmp2, sizeof(tmp2),
514 			L"Error: Executable binary file \"%s\" not found.\r\n\r\n"
515 			L"Please execute program with full path.\r\n",
516 			tmp);
517 
518 		AlertW(tmp2, NULL);
519 		_exit(0);
520 	}
521 
522 	CheckUnixTempDir();
523 
524 	// Initialization of Probe
525 	InitProbe();
526 
527 	// Initialization of Machine Hash
528 	GetCurrentMachineIpProcessHash(hash);
529 
530 	// Reading Private IP file
531 	LoadPrivateIPFile();
532 }
533 
534 // Release of Mayaqua library
FreeMayaqua()535 void FreeMayaqua()
536 {
537 	if ((--init_mayaqua_counter) > 0)
538 	{
539 		return;
540 	}
541 
542 	// Release of Private IP File
543 	FreePrivateIPFile();
544 
545 	// Release of Probe
546 	FreeProbe();
547 
548 	// Delete the table
549 	FreeTable();
550 
551 	// Release of security token module
552 	FreeSecure();
553 
554 	// Release of the operating system specific module
555 #ifdef	OS_WIN32
556 	MsFree();
557 #endif	// OS_WIN32
558 
559 	// Release of OS information
560 	FreeOsInfo();
561 
562 	// Release of HamCore file system
563 	FreeHamcore();
564 
565 	// Release of the command line string
566 	FreeCommandLineStr();
567 
568 	// Release of the command line token
569 	FreeCommandLineTokens();
570 
571 	// Release of network communication module
572 	FreeNetwork();
573 
574 	// Release of real-time clock
575 	FreeTick64();
576 
577 	// Release of the string library
578 	FreeStringLibrary();
579 
580 	// Release of thread pool
581 	FreeThreading();
582 
583 	// Release of crypt library
584 	FreeCryptLibrary();
585 
586 	if (IsTrackingEnabled())
587 	{
588 		// Show the kernel status
589 		if (g_debug)
590 		{
591 			PrintKernelStatus();
592 		}
593 
594 		// Display the debug information
595 		if (g_memcheck)
596 		{
597 			PrintDebugInformation();
598 		}
599 
600 		// Release the tracking
601 		FreeTracking();
602 	}
603 
604 	// Release of the kernel status
605 	FreeKernelStatus();
606 
607 	DeleteLock(tick_manual_lock);
608 	tick_manual_lock = NULL;
609 
610 	// Release of OS
611 	OSFree();
612 }
613 
614 // Check whether /tmp is available in the UNIX
CheckUnixTempDir()615 void CheckUnixTempDir()
616 {
617 	if (OS_IS_UNIX(GetOsInfo()->OsType))
618 	{
619 		char tmp[128], tmp2[64];
620 		UINT64 now = SystemTime64();
621 		IO *o;
622 
623 		MakeDir("/tmp");
624 
625 		Format(tmp2, sizeof(tmp2), "%I64u", now);
626 
627 		Format(tmp, sizeof(tmp), "/tmp/.%s", tmp2);
628 
629 		o = FileCreate(tmp);
630 		if (o == NULL)
631 		{
632 			o = FileOpen(tmp, false);
633 			if (o == NULL)
634 			{
635 				Print("Unable to use /tmp.\n\n");
636 				exit(0);
637 			}
638 		}
639 
640 		FileClose(o);
641 
642 		FileDelete(tmp);
643 	}
644 }
645 
646 // Show an alert
Alert(char * msg,char * caption)647 void Alert(char *msg, char *caption)
648 {
649 	OSAlert(msg, caption);
650 }
AlertW(wchar_t * msg,wchar_t * caption)651 void AlertW(wchar_t *msg, wchar_t *caption)
652 {
653 	OSAlertW(msg, caption);
654 }
655 
656 // Get the OS type
GetOsType()657 UINT GetOsType()
658 {
659 	OS_INFO *i = GetOsInfo();
660 
661 	if (i == NULL)
662 	{
663 		return 0;
664 	}
665 
666 	return i->OsType;
667 }
668 
669 // Getting OS information
GetOsInfo()670 OS_INFO *GetOsInfo()
671 {
672 	return os_info;
673 }
674 
675 // Initialization of OS information
InitOsInfo()676 void InitOsInfo()
677 {
678 	if (os_info != NULL)
679 	{
680 		return;
681 	}
682 
683 	os_info = ZeroMalloc(sizeof(OS_INFO));
684 
685 	OSGetOsInfo(os_info);
686 }
687 
688 // Release of OS information
FreeOsInfo()689 void FreeOsInfo()
690 {
691 	if (os_info == NULL)
692 	{
693 		return;
694 	}
695 
696 	Free(os_info->OsSystemName);
697 	Free(os_info->OsProductName);
698 	Free(os_info->OsVendorName);
699 	Free(os_info->OsVersion);
700 	Free(os_info->KernelName);
701 	Free(os_info->KernelVersion);
702 	Free(os_info);
703 
704 	os_info = NULL;
705 }
706 
707 // Get the Unicode command line tokens
GetCommandLineUniToken()708 UNI_TOKEN_LIST *GetCommandLineUniToken()
709 {
710 	if (cmdline_uni_token == NULL)
711 	{
712 		return UniNullToken();
713 	}
714 	else
715 	{
716 		return UniCopyToken(cmdline_uni_token);
717 	}
718 }
719 
720 // Getting the command line tokens
GetCommandLineToken()721 TOKEN_LIST *GetCommandLineToken()
722 {
723 	if (cmdline_token == NULL)
724 	{
725 		return NullToken();
726 	}
727 	else
728 	{
729 		return CopyToken(cmdline_token);
730 	}
731 }
732 
733 // Convert the command line string into tokens
ParseCommandLineTokens()734 void ParseCommandLineTokens()
735 {
736 	if (cmdline_token != NULL)
737 	{
738 		FreeToken(cmdline_token);
739 	}
740 	cmdline_token = ParseCmdLine(cmdline);
741 
742 	if (cmdline_uni_token != NULL)
743 	{
744 		UniFreeToken(cmdline_uni_token);
745 	}
746 	cmdline_uni_token = UniParseCmdLine(uni_cmdline);
747 }
748 
749 // Release command line tokens
FreeCommandLineTokens()750 void FreeCommandLineTokens()
751 {
752 	if (cmdline_token != NULL)
753 	{
754 		FreeToken(cmdline_token);
755 	}
756 	cmdline_token = NULL;
757 
758 	if (cmdline_uni_token != NULL)
759 	{
760 		UniFreeToken(cmdline_uni_token);
761 	}
762 	cmdline_uni_token = NULL;
763 }
764 
765 // Initialization of the command line string
InitCommandLineStr(int argc,char ** argv)766 void InitCommandLineStr(int argc, char **argv)
767 {
768 	if (argc >= 1)
769 	{
770 #ifdef	OS_UNIX
771 		exename_w = CopyUtfToUni(argv[0]);
772 		exename = CopyUniToStr(exename_w);
773 #else	// OS_UNIX
774 		exename = CopyStr(argv[0]);
775 		exename_w = CopyStrToUni(exename);
776 #endif	// OS_UNIX
777 	}
778 	if (argc < 2 || argv == NULL)
779 	{
780 		// No command-line string
781 		SetCommandLineStr(NULL);
782 	}
783 	else
784 	{
785 		// There are command-line string
786 		int i, total_len = 1;
787 		char *tmp;
788 
789 		for (i = 1;i < argc;i++)
790 		{
791 			total_len += StrLen(argv[i]) * 2 + 32;
792 		}
793 		tmp = ZeroMalloc(total_len);
794 
795 		for (i = 1;i < argc;i++)
796 		{
797 			UINT s_size = StrLen(argv[i]) * 2;
798 			char *s = ZeroMalloc(s_size);
799 			bool dq = (SearchStrEx(argv[i], " ", 0, true) != INFINITE);
800 			ReplaceStrEx(s, s_size, argv[i], "\"", "\"\"", true);
801 			if (dq)
802 			{
803 				StrCat(tmp, total_len, "\"");
804 			}
805 			StrCat(tmp, total_len, s);
806 			if (dq)
807 			{
808 				StrCat(tmp, total_len, "\"");
809 			}
810 			StrCat(tmp, total_len, " ");
811 			Free(s);
812 		}
813 
814 		Trim(tmp);
815 		SetCommandLineStr(tmp);
816 		Free(tmp);
817 	}
818 }
819 
820 // Release of the command line string
FreeCommandLineStr()821 void FreeCommandLineStr()
822 {
823 	SetCommandLineStr(NULL);
824 
825 	if (exename != NULL)
826 	{
827 		Free(exename);
828 		exename = NULL;
829 	}
830 
831 	if (exename_w != NULL)
832 	{
833 		Free(exename_w);
834 		exename_w = NULL;
835 	}
836 }
837 
838 // Get the Unicode command line string
GetCommandLineUniStr()839 wchar_t *GetCommandLineUniStr()
840 {
841 	if (uni_cmdline == NULL)
842 	{
843 		return UniCopyStr(L"");
844 	}
845 	else
846 	{
847 		return UniCopyStr(uni_cmdline);
848 	}
849 }
850 
851 // Get the command line string
GetCommandLineStr()852 char *GetCommandLineStr()
853 {
854 	if (cmdline == NULL)
855 	{
856 		return CopyStr("");
857 	}
858 	else
859 	{
860 		return CopyStr(cmdline);
861 	}
862 }
863 
864 // Set the Unicode command line string
SetCommandLineUniStr(wchar_t * str)865 void SetCommandLineUniStr(wchar_t *str)
866 {
867 	if (uni_cmdline != NULL)
868 	{
869 		Free(uni_cmdline);
870 	}
871 	if (str == NULL)
872 	{
873 		uni_cmdline = NULL;
874 	}
875 	else
876 	{
877 		uni_cmdline = CopyUniStr(str);
878 	}
879 
880 	ParseCommandLineTokens();
881 }
882 
883 // Set the command-line string
SetCommandLineStr(char * str)884 void SetCommandLineStr(char *str)
885 {
886 	// Validate arguments
887 	if (str == NULL)
888 	{
889 		if (cmdline != NULL)
890 		{
891 			Free(cmdline);
892 		}
893 		cmdline = NULL;
894 	}
895 	else
896 	{
897 		if (cmdline != NULL)
898 		{
899 			Free(cmdline);
900 		}
901 		cmdline = CopyStr(str);
902 	}
903 
904 	if (cmdline == NULL)
905 	{
906 		if (uni_cmdline != NULL)
907 		{
908 			Free(uni_cmdline);
909 			uni_cmdline = NULL;
910 		}
911 	}
912 	else
913 	{
914 		if (uni_cmdline != NULL)
915 		{
916 			Free(uni_cmdline);
917 		}
918 		uni_cmdline = CopyStrToUni(cmdline);
919 	}
920 
921 	ParseCommandLineTokens();
922 }
923 
924 // Display the kernel status
PrintKernelStatus()925 void PrintKernelStatus()
926 {
927 	bool leaked = false;
928 
929 	Print("\n");
930 	Print(
931 		"     --------- Mayaqua Kernel Status ---------\n"
932 		"        Malloc Count ............... %u\n"
933 		"        ReAlloc Count .............. %u\n"
934 		"        Free Count ................. %u\n"
935 		"        Total Memory Size .......... %I64u bytes\n"
936 		"      * Current Memory Blocks ...... %u Blocks (Peek: %u)\n"
937 		"        Total Memory Blocks ........ %u Blocks\n"
938 		"      * Current MemPool Blocks ..... %u Blocks (Peek: %u)\n"
939 		"        Total MemPool Mallocs ...... %u Mallocs\n"
940 		"        Total MemPool ReAllocs ..... %u ReAllocs\n"
941 		"        NewLock Count .............. %u\n"
942 		"        DeleteLock Count ........... %u\n"
943 		"      * Current Lock Objects ....... %u Objects\n"
944 		"      * Current Locked Objects ..... %u Objects\n"
945 		"        NewRef Count ............... %u\n"
946 		"        FreeRef Count .............. %u\n"
947 		"      * Current Ref Objects ........ %u Objects\n"
948 		"      * Current Ref Count .......... %u Refs\n"
949 		"        GetTime Count .............. %u\n"
950 		"        GetTick Count .............. %u\n"
951 		"        NewThread Count ............ %u\n"
952 		"        FreeThread Count ........... %u\n"
953 		"      * Current Threads ............ %u Threads\n"
954 		"        Wait For Event Count ....... %u\n\n",
955 		KS_GET(KS_MALLOC_COUNT),
956 		KS_GET(KS_REALLOC_COUNT),
957 		KS_GET(KS_FREE_COUNT),
958 		KS_GET64(KS_TOTAL_MEM_SIZE),
959 		KS_GET(KS_CURRENT_MEM_COUNT),
960 		KS_GETMAX(KS_CURRENT_MEM_COUNT),
961 		KS_GET(KS_TOTAL_MEM_COUNT),
962 		KS_GET(KS_MEMPOOL_CURRENT_NUM),
963 		KS_GETMAX(KS_MEMPOOL_CURRENT_NUM),
964 		KS_GET(KS_MEMPOOL_MALLOC_COUNT),
965 		KS_GET(KS_MEMPOOL_REALLOC_COUNT),
966 		KS_GET(KS_NEWLOCK_COUNT),
967 		KS_GET(KS_DELETELOCK_COUNT),
968 		KS_GET(KS_CURRENT_LOCK_COUNT),
969 		KS_GET(KS_CURRENT_LOCKED_COUNT),
970 		KS_GET(KS_NEWREF_COUNT),
971 		KS_GET(KS_FREEREF_COUNT),
972 		KS_GET(KS_CURRENT_REF_COUNT),
973 		KS_GET(KS_CURRENT_REFED_COUNT),
974 		KS_GET(KS_GETTIME_COUNT),
975 		KS_GET(KS_GETTICK_COUNT),
976 		KS_GET(KS_NEWTHREAD_COUNT),
977 		KS_GET(KS_FREETHREAD_COUNT),
978 		KS_GET(KS_NEWTHREAD_COUNT) - KS_GET(KS_FREETHREAD_COUNT),
979 		KS_GET(KS_WAIT_COUNT)
980 		);
981 
982 	if (KS_GET(KS_CURRENT_MEM_COUNT) != 0 || KS_GET(KS_CURRENT_LOCK_COUNT) != 0 ||
983 		KS_GET(KS_MEMPOOL_CURRENT_NUM) != 0 ||
984 		KS_GET(KS_CURRENT_LOCKED_COUNT) != 0 || KS_GET(KS_CURRENT_REF_COUNT) != 0)
985 	{
986 		leaked = true;
987 	}
988 
989 	if (leaked)
990 	{
991 		Print("      !!! MEMORY LEAKS DETECTED !!!\n\n");
992 		if (g_memcheck == false)
993 		{
994 			if (IsHamMode())
995 			{
996 				Print("    Enable /memcheck startup option to see the leaking memory heap.\n");
997 				Print("    Press Enter key to exit the process.\n");
998 			}
999 			GetLine(NULL, 0);
1000 		}
1001 	}
1002 	else
1003 	{
1004 		Print("        @@@ NO MEMORY LEAKS @@@\n\n");
1005 	}
1006 }
1007 
1008 // Initialize Kernel status
InitKernelStatus()1009 void InitKernelStatus()
1010 {
1011 	UINT i;
1012 
1013 	// Memory initialization
1014 	Zero(kernel_status, sizeof(kernel_status));
1015 	Zero(kernel_status_max, sizeof(kernel_status_max));
1016 
1017 	// Lock initialization
1018 	for (i = 0;i < NUM_KERNEL_STATUS;i++)
1019 	{
1020 		kernel_status_lock[i] = OSNewLock();
1021 	}
1022 
1023 	kernel_status_inited = true;
1024 }
1025 
1026 // Release of the kernel status
FreeKernelStatus()1027 void FreeKernelStatus()
1028 {
1029 	UINT i;
1030 
1031 	kernel_status_inited = false;
1032 
1033 	// Lock release
1034 	for (i = 0;i < NUM_KERNEL_STATUS;i++)
1035 	{
1036 		OSDeleteLock(kernel_status_lock[i]);
1037 	}
1038 }
1039 
1040 // Lock the kernel status
LockKernelStatus(UINT id)1041 void LockKernelStatus(UINT id)
1042 {
1043 	// Validate arguments
1044 	if (id >= NUM_KERNEL_STATUS)
1045 	{
1046 		return;
1047 	}
1048 
1049 	OSLock(kernel_status_lock[id]);
1050 }
1051 
1052 // Unlock the kernel status
UnlockKernelStatus(UINT id)1053 void UnlockKernelStatus(UINT id)
1054 {
1055 	// Validate arguments
1056 	if (id >= NUM_KERNEL_STATUS)
1057 	{
1058 		return;
1059 	}
1060 
1061 	OSUnlock(kernel_status_lock[id]);
1062 }
1063 
1064 // Display the debug information
PrintDebugInformation()1065 void PrintDebugInformation()
1066 {
1067 	MEMORY_STATUS memory_status;
1068 	GetMemoryStatus(&memory_status);
1069 
1070 	// Header
1071 	Print("====== " CEDAR_PRODUCT_STR " VPN System Debug Information ======\n");
1072 
1073 	// Memory information
1074 	Print(" <Memory Status>\n"
1075 		"       Number of Allocated Memory Blocks: %u\n"
1076 		"   Total Size of Allocated Memory Blocks: %u bytes\n",
1077 		memory_status.MemoryBlocksNum, memory_status.MemorySize);
1078 
1079 	// Footer
1080 	Print("====================================================\n");
1081 
1082 	if (KS_GET(KS_CURRENT_MEM_COUNT) != 0 || KS_GET(KS_CURRENT_LOCK_COUNT) != 0 ||
1083 		KS_GET(KS_CURRENT_LOCKED_COUNT) != 0 || KS_GET(KS_CURRENT_REF_COUNT) != 0)
1084 	{
1085 		// Show a debug menu because memory leaks suspected
1086 		MemoryDebugMenu();
1087 	}
1088 }
1089 
1090 
1091 
1092 
1093