/* $Id: nthlpcore.c 3534 2021-12-20 23:31:55Z bird $ */ /** @file * MSC + NT core helpers functions and globals. */ /* * Copyright (c) 2005-2013 knut st. osmundsen * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * Alternatively, the content of this file may be used under the terms of the * GPL version 2 or later, or LGPL version 2.1 or later. */ /******************************************************************************* * Header Files * *******************************************************************************/ #include #include "nthlp.h" #ifndef NDEBUG # include #endif /******************************************************************************* * Global Variables * *******************************************************************************/ MY_NTSTATUS (WINAPI *g_pfnNtClose)(HANDLE); MY_NTSTATUS (WINAPI *g_pfnNtCreateFile)(PHANDLE, MY_ACCESS_MASK, MY_OBJECT_ATTRIBUTES *, MY_IO_STATUS_BLOCK *, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG); MY_NTSTATUS (WINAPI *g_pfnNtDeleteFile)(MY_OBJECT_ATTRIBUTES *); MY_NTSTATUS (WINAPI *g_pfnNtDuplicateObject)(HANDLE hSrcProc, HANDLE hSrc, HANDLE hDstProc, HANDLE *phRet, MY_ACCESS_MASK fDesiredAccess, ULONG fAttribs, ULONG fOptions); MY_NTSTATUS (WINAPI *g_pfnNtReadFile)(HANDLE hFile, HANDLE hEvent, MY_IO_APC_ROUTINE *pfnApc, PVOID pvApcCtx, MY_IO_STATUS_BLOCK *, PVOID pvBuf, ULONG cbToRead, PLARGE_INTEGER poffFile, PULONG puKey); MY_NTSTATUS (WINAPI *g_pfnNtQueryInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); MY_NTSTATUS (WINAPI *g_pfnNtQueryVolumeInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FS_INFORMATION_CLASS); MY_NTSTATUS (WINAPI *g_pfnNtQueryDirectoryFile)(HANDLE, HANDLE, MY_IO_APC_ROUTINE *, PVOID, MY_IO_STATUS_BLOCK *, PVOID, ULONG, MY_FILE_INFORMATION_CLASS, BOOLEAN, MY_UNICODE_STRING *, BOOLEAN); MY_NTSTATUS (WINAPI *g_pfnNtQueryAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_BASIC_INFORMATION *); MY_NTSTATUS (WINAPI *g_pfnNtQueryFullAttributesFile)(MY_OBJECT_ATTRIBUTES *, MY_FILE_NETWORK_OPEN_INFORMATION *); MY_NTSTATUS (WINAPI *g_pfnNtSetInformationFile)(HANDLE, MY_IO_STATUS_BLOCK *, PVOID, LONG, MY_FILE_INFORMATION_CLASS); BOOLEAN (WINAPI *g_pfnRtlDosPathNameToNtPathName_U)(PCWSTR, MY_UNICODE_STRING *, PCWSTR *, MY_RTL_RELATIVE_NAME_U *); MY_NTSTATUS (WINAPI *g_pfnRtlAnsiStringToUnicodeString)(MY_UNICODE_STRING *, MY_ANSI_STRING const *, BOOLEAN); MY_NTSTATUS (WINAPI *g_pfnRtlUnicodeStringToAnsiString)(MY_ANSI_STRING *, MY_UNICODE_STRING *, BOOLEAN); BOOLEAN (WINAPI *g_pfnRtlEqualUnicodeString)(MY_UNICODE_STRING const *, MY_UNICODE_STRING const *, BOOLEAN); BOOLEAN (WINAPI *g_pfnRtlEqualString)(MY_ANSI_STRING const *, MY_ANSI_STRING const *, BOOLEAN); UCHAR (WINAPI *g_pfnRtlUpperChar)(UCHAR uch); ULONG (WINAPI *g_pfnRtlNtStatusToDosError)(MY_NTSTATUS rcNt); VOID (WINAPI *g_pfnRtlAcquirePebLock)(VOID); VOID (WINAPI *g_pfnRtlReleasePebLock)(VOID); static struct { FARPROC *ppfn; const char *pszName; } const g_apfnDynamicNtdll[] = { { (FARPROC *)&g_pfnNtClose, "NtClose" }, { (FARPROC *)&g_pfnNtCreateFile, "NtCreateFile" }, { (FARPROC *)&g_pfnNtDeleteFile, "NtDeleteFile" }, { (FARPROC *)&g_pfnNtDuplicateObject, "NtDuplicateObject" }, { (FARPROC *)&g_pfnNtReadFile, "NtReadFile" }, { (FARPROC *)&g_pfnNtQueryInformationFile, "NtQueryInformationFile" }, { (FARPROC *)&g_pfnNtQueryVolumeInformationFile, "NtQueryVolumeInformationFile" }, { (FARPROC *)&g_pfnNtQueryDirectoryFile, "NtQueryDirectoryFile" }, { (FARPROC *)&g_pfnNtQueryAttributesFile, "NtQueryAttributesFile" }, { (FARPROC *)&g_pfnNtQueryFullAttributesFile, "NtQueryFullAttributesFile" }, { (FARPROC *)&g_pfnNtSetInformationFile, "NtSetInformationFile" }, { (FARPROC *)&g_pfnRtlDosPathNameToNtPathName_U, "RtlDosPathNameToNtPathName_U" }, { (FARPROC *)&g_pfnRtlAnsiStringToUnicodeString, "RtlAnsiStringToUnicodeString" }, { (FARPROC *)&g_pfnRtlUnicodeStringToAnsiString, "RtlUnicodeStringToAnsiString" }, { (FARPROC *)&g_pfnRtlEqualUnicodeString, "RtlEqualUnicodeString" }, { (FARPROC *)&g_pfnRtlEqualString, "RtlEqualString" }, { (FARPROC *)&g_pfnRtlUpperChar, "RtlUpperChar" }, { (FARPROC *)&g_pfnRtlNtStatusToDosError, "RtlNtStatusToDosError" }, { (FARPROC *)&g_pfnRtlAcquirePebLock, "RtlAcquirePebLock" }, { (FARPROC *)&g_pfnRtlReleasePebLock, "RtlReleasePebLock" }, }; /** Set to 1 if we've successfully resolved the imports, otherwise 0. */ int g_fResolvedNtImports = 0; void birdResolveImportsWorker(void) { HMODULE hMod = LoadLibraryW(L"ntdll.dll"); int i = sizeof(g_apfnDynamicNtdll) / sizeof(g_apfnDynamicNtdll[0]); while (i-- > 0) { const char *pszSym = g_apfnDynamicNtdll[i].pszName; FARPROC pfn; *g_apfnDynamicNtdll[i].ppfn = pfn = GetProcAddress(hMod, pszSym); if (!pfn) { /* Write short message and die. */ static const char s_szMsg[] = "\r\nFatal error resolving NTDLL.DLL symbols!\r\nSymbol: "; DWORD cbWritten; if ( !WriteFile(GetStdHandle(STD_ERROR_HANDLE), s_szMsg, sizeof(s_szMsg) - 1, &cbWritten, NULL) || !WriteFile(GetStdHandle(STD_ERROR_HANDLE), pszSym, (DWORD)strlen(pszSym), &cbWritten, NULL) || !WriteFile(GetStdHandle(STD_ERROR_HANDLE), "\r\n", sizeof("\r\n") - 1, &cbWritten, NULL) ) *(void **)(size_t)i = NULL; ExitProcess(127); } } g_fResolvedNtImports = 1; } void *birdTmpAlloc(size_t cb) { return malloc(cb); } void birdTmpFree(void *pv) { if (pv) free(pv); } void *birdMemAlloc(size_t cb) { return malloc(cb); } void *birdMemAllocZ(size_t cb) { return calloc(cb, 1); } void birdMemFree(void *pv) { if (pv) free(pv); } int birdErrnoFromNtStatus(MY_NTSTATUS rcNt) { switch (rcNt) { /* EPERM = 1 */ case STATUS_CANNOT_DELETE: return EPERM; /* ENOENT = 2 */ case STATUS_NOT_FOUND: case STATUS_OBJECT_NAME_NOT_FOUND: case STATUS_OBJECT_PATH_NOT_FOUND: case STATUS_OBJECT_NAME_INVALID: case STATUS_INVALID_COMPUTER_NAME: case STATUS_VARIABLE_NOT_FOUND: case STATUS_MESSAGE_NOT_FOUND: case STATUS_DLL_NOT_FOUND: case STATUS_ORDINAL_NOT_FOUND: case STATUS_ENTRYPOINT_NOT_FOUND: case STATUS_PATH_NOT_COVERED: case STATUS_BAD_NETWORK_PATH: case STATUS_DFS_EXIT_PATH_FOUND: case RPC_NT_OBJECT_NOT_FOUND: case STATUS_DELETE_PENDING: return ENOENT; /* ESRCH = 3 */ case STATUS_PROCESS_NOT_IN_JOB: return ESRCH; /* EINTR = 4 */ case STATUS_ALERTED: case STATUS_USER_APC: return EINTR; /* EIO = 5 */ /* ENXIO = 6 */ /* E2BIG = 7 */ /* ENOEXEC = 8 */ case STATUS_INVALID_IMAGE_FORMAT: case STATUS_INVALID_IMAGE_NE_FORMAT: case STATUS_INVALID_IMAGE_LE_FORMAT: case STATUS_INVALID_IMAGE_NOT_MZ: case STATUS_INVALID_IMAGE_PROTECT: case STATUS_INVALID_IMAGE_WIN_16: case STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT: case STATUS_IMAGE_CHECKSUM_MISMATCH: case STATUS_IMAGE_MP_UP_MISMATCH: case STATUS_IMAGE_MACHINE_TYPE_MISMATCH: case STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE: case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE: case STATUS_SECTION_NOT_IMAGE: case STATUS_INVALID_IMAGE_WIN_32: case STATUS_INVALID_IMAGE_WIN_64: case STATUS_INVALID_IMAGE_HASH: case STATUS_IMAGE_CERT_REVOKED: return ENOEXEC; /* EBADF = 9 */ case STATUS_INVALID_HANDLE: case STATUS_PORT_CLOSED: case STATUS_OPLOCK_HANDLE_CLOSED: case STATUS_HANDLES_CLOSED: case STATUS_FILE_FORCED_CLOSED: return EBADF; /* ECHILD = 10 */ /* EAGAIN = 11 */ case STATUS_WMI_TRY_AGAIN: case STATUS_GRAPHICS_TRY_AGAIN_LATER: case STATUS_GRAPHICS_TRY_AGAIN_NOW: return EAGAIN; /* ENOMEM = 12 */ case STATUS_NO_MEMORY: case STATUS_HV_INSUFFICIENT_MEMORY: case STATUS_INSUFFICIENT_RESOURCES: case STATUS_REMOTE_RESOURCES: case STATUS_INSUFF_SERVER_RESOURCES: return ENOMEM; /* EACCES = 13 */ case STATUS_ACCESS_DENIED: case STATUS_NETWORK_ACCESS_DENIED: case RPC_NT_PROXY_ACCESS_DENIED: case STATUS_CTX_SHADOW_DENIED: case STATUS_CTX_WINSTATION_ACCESS_DENIED: return EACCES; /* EFAULT = 14 */ case STATUS_ACCESS_VIOLATION: case STATUS_HARDWARE_MEMORY_ERROR: return EFAULT; /* EBUSY = 16 */ case STATUS_PIPE_BUSY: case STATUS_RESOURCE_IN_USE: return EBUSY; /* EEXIST = 17 */ case STATUS_OBJECT_NAME_EXISTS: case STATUS_OBJECT_NAME_COLLISION: case STATUS_DUPLICATE_NAME: return EEXIST; /* EXDEV = 18 */ case STATUS_NOT_SAME_DEVICE: return EXDEV; /* ENODEV = 19 */ /* ENOTDIR = 20 */ case STATUS_NOT_A_DIRECTORY: case STATUS_DIRECTORY_IS_A_REPARSE_POINT: case STATUS_OBJECT_PATH_SYNTAX_BAD: case STATUS_OBJECT_PATH_INVALID: case STATUS_OBJECT_TYPE_MISMATCH: return ENOTDIR; /* EISDIR = 21 */ case STATUS_FILE_IS_A_DIRECTORY: return EISDIR; /* EINVAL = 22 */ case STATUS_INVALID_PARAMETER: case STATUS_INVALID_PARAMETER_1: case STATUS_INVALID_PARAMETER_2: case STATUS_INVALID_PARAMETER_3: case STATUS_INVALID_PARAMETER_4: case STATUS_INVALID_PARAMETER_5: case STATUS_INVALID_PARAMETER_6: case STATUS_INVALID_PARAMETER_7: case STATUS_INVALID_PARAMETER_8: case STATUS_INVALID_PARAMETER_9: case STATUS_INVALID_PARAMETER_10: case STATUS_INVALID_PARAMETER_11: case STATUS_INVALID_PARAMETER_12: case STATUS_INVALID_PARAMETER_MIX: return EINVAL; /* ENFILE = 23 */ /* EMFILE = 24 */ case STATUS_TOO_MANY_OPENED_FILES: return EMFILE; /* ENOTTY = 25 */ /* EFBIG = 27 */ /* ENOSPC = 28 */ case STATUS_DISK_FULL: return ENOSPC; /* ESPIPE = 29 */ /* EROFS = 30 */ /* EMLINK = 31 */ /* EPIPE = 32 */ case STATUS_PIPE_BROKEN: case RPC_NT_PIPE_CLOSED: return EPIPE; /* EDOM = 33 */ /* ERANGE = 34 */ /* EDEADLK = 36 */ case STATUS_POSSIBLE_DEADLOCK: return EDEADLK; /* ENAMETOOLONG = 38 */ case STATUS_NAME_TOO_LONG: return ENAMETOOLONG; /* ENOLCK = 39 */ /* ENOSYS = 40 */ case STATUS_NOT_SUPPORTED: return ENOSYS; /* ENOTEMPTY = 41 */ case STATUS_DIRECTORY_NOT_EMPTY: return ENOTEMPTY; /* EILSEQ = 42 */ /* EADDRINUSE = 100 */ /* EADDRNOTAVAIL = 101 */ /* EAFNOSUPPORT = 102 */ /* EALREADY = 103 */ case STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED: case STATUS_DEVICE_ALREADY_ATTACHED: case STATUS_PORT_ALREADY_SET: case STATUS_IMAGE_ALREADY_LOADED: case STATUS_TOKEN_ALREADY_IN_USE: case STATUS_IMAGE_ALREADY_LOADED_AS_DLL: case STATUS_ADDRESS_ALREADY_EXISTS: case STATUS_ADDRESS_ALREADY_ASSOCIATED: return EALREADY; /* EBADMSG = 104 */ /* ECANCELED = 105 */ /* ECONNABORTED = 106 */ /* ECONNREFUSED = 107 */ /* ECONNRESET = 108 */ /* EDESTADDRREQ = 109 */ /* EHOSTUNREACH = 110 */ case STATUS_HOST_UNREACHABLE: return EHOSTUNREACH; /* EIDRM = 111 */ /* EINPROGRESS = 112 */ /* EISCONN = 113 */ /* ELOOP = 114 */ /* EMSGSIZE = 115 */ /* ENETDOWN = 116 */ /* ENETRESET = 117 */ /* ENETUNREACH = 118 */ case STATUS_NETWORK_UNREACHABLE: return ENETUNREACH; /* ENOBUFS = 119 */ /* ENODATA = 120 */ /* ENOLINK = 121 */ /* ENOMSG = 122 */ /* ENOPROTOOPT = 123 */ /* ENOSR = 124 */ /* ENOSTR = 125 */ /* ENOTCONN = 126 */ /* ENOTRECOVERABLE = 127 */ /* ENOTSOCK = 128 */ /* ENOTSUP = 129 */ /* EOPNOTSUPP = 130 */ /* EOTHER = 131 */ /* EOVERFLOW = 132 */ /* EOWNERDEAD = 133 */ /* EPROTO = 134 */ /* EPROTONOSUPPORT = 135 */ /* EPROTOTYPE = 136 */ /* ETIME = 137 */ /* ETIMEDOUT = 138 */ case STATUS_VIRTUAL_CIRCUIT_CLOSED: case STATUS_TIMEOUT: return ETIMEDOUT; /* ETXTBSY = 139 */ case STATUS_SHARING_VIOLATION: return ETXTBSY; /* EWOULDBLOCK = 140 */ } #ifndef NDEBUG __debugbreak(); fprintf(stderr, "rcNt=%#x (%d)\n", rcNt, rcNt); #endif return EINVAL; } int birdSetErrnoFromNt(MY_NTSTATUS rcNt) { errno = birdErrnoFromNtStatus(rcNt); #if 0 { ULONG rcWin32; _doserrno = rcWin32 = g_pfnRtlNtStatusToDosError(rcNt); SetLastError(rcWin32); } #endif return -1; } int birdSetErrnoFromWin32(DWORD dwErr) { switch (dwErr) { default: case ERROR_INVALID_FUNCTION: errno = EINVAL; break; case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; case ERROR_TOO_MANY_OPEN_FILES: errno = EMFILE; break; case ERROR_ACCESS_DENIED: errno = EACCES; break; case ERROR_INVALID_HANDLE: errno = EBADF; break; case ERROR_ARENA_TRASHED: errno = ENOMEM; break; case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break; case ERROR_INVALID_BLOCK: errno = ENOMEM; break; case ERROR_BAD_ENVIRONMENT: errno = E2BIG; break; case ERROR_BAD_FORMAT: errno = ENOEXEC; break; case ERROR_INVALID_ACCESS: errno = EINVAL; break; case ERROR_INVALID_DATA: errno = EINVAL; break; case ERROR_INVALID_DRIVE: errno = ENOENT; break; case ERROR_CURRENT_DIRECTORY: errno = EACCES; break; case ERROR_NOT_SAME_DEVICE: errno = EXDEV; break; case ERROR_NO_MORE_FILES: errno = ENOENT; break; case ERROR_LOCK_VIOLATION: errno = EACCES; break; case ERROR_BAD_NETPATH: errno = ENOENT; break; case ERROR_NETWORK_ACCESS_DENIED: errno = EACCES; break; case ERROR_BAD_NET_NAME: errno = ENOENT; break; case ERROR_FILE_EXISTS: errno = EEXIST; break; case ERROR_CANNOT_MAKE: errno = EACCES; break; case ERROR_FAIL_I24: errno = EACCES; break; case ERROR_INVALID_PARAMETER: errno = EINVAL; break; case ERROR_NO_PROC_SLOTS: errno = EAGAIN; break; case ERROR_DRIVE_LOCKED: errno = EACCES; break; case ERROR_BROKEN_PIPE: errno = EPIPE; break; case ERROR_DISK_FULL: errno = ENOSPC; break; case ERROR_INVALID_TARGET_HANDLE: errno = EBADF; break; case ERROR_WAIT_NO_CHILDREN: errno = ECHILD; break; case ERROR_CHILD_NOT_COMPLETE: errno = ECHILD; break; case ERROR_DIRECT_ACCESS_HANDLE: errno = EBADF; break; case ERROR_NEGATIVE_SEEK: errno = EINVAL; break; case ERROR_SEEK_ON_DEVICE: errno = EACCES; break; case ERROR_DIR_NOT_EMPTY: errno = ENOTEMPTY; break; case ERROR_NOT_LOCKED: errno = EACCES; break; case ERROR_BAD_PATHNAME: errno = ENOENT; break; case ERROR_MAX_THRDS_REACHED: errno = EAGAIN; break; case ERROR_LOCK_FAILED: errno = EACCES; break; case ERROR_ALREADY_EXISTS: errno = EEXIST; break; case ERROR_FILENAME_EXCED_RANGE: errno = ENOENT; break; case ERROR_NESTING_NOT_ALLOWED: errno = EAGAIN; break; #ifdef EMLINK case ERROR_TOO_MANY_LINKS: errno = EMLINK; break; #endif case ERROR_SHARING_VIOLATION: errno = ETXTBSY; break; } return -1; } int birdSetErrnoToNoMem(void) { errno = ENOMEM; return -1; } int birdSetErrnoToInvalidArg(void) { errno = EINVAL; return -1; } int birdSetErrnoToBadFileNo(void) { errno = EBADF; return -1; }