blob: f2f84045091519517f0bd2a4559c79c1a63f91e8 [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
/*
*
* @author Mladen Turk
* @version $Revision$, $Date$
*/
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#include <winsock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#include "apr.h"
#include "apr_pools.h"
#include "apr_poll.h"
#include "apr_network_io.h"
#include "apr_arch_misc.h" /* for apr_os_level */
#include "apr_arch_atime.h" /* for FileTimeToAprTime */
#include "tcn.h"
#ifdef HAVE_OPENSSL
#include "ssl_private.h"
#endif
#pragma warning(push)
#pragma warning(disable : 4201)
#if (_WIN32_WINNT < 0x0501)
#include <winternl.h>
#endif
#include <psapi.h>
#pragma warning(pop)
static CRITICAL_SECTION dll_critical_section; /* dll's critical section */
static HINSTANCE dll_instance = NULL;
static SYSTEM_INFO dll_system_info;
static HANDLE h_kernel = NULL;
static HANDLE h_ntdll = NULL;
static char dll_file_name[MAX_PATH];
typedef BOOL (WINAPI *pfnGetSystemTimes)(LPFILETIME, LPFILETIME, LPFILETIME);
static pfnGetSystemTimes fnGetSystemTimes = NULL;
#if (_WIN32_WINNT < 0x0501)
typedef NTSTATUS (WINAPI *pfnNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
static pfnNtQuerySystemInformation fnNtQuerySystemInformation = NULL;
#endif
BOOL
WINAPI
DllMain(
HINSTANCE instance,
DWORD reason,
LPVOID reserved)
{
switch (reason) {
/** The DLL is loading due to process
* initialization or a call to LoadLibrary.
*/
case DLL_PROCESS_ATTACH:
InitializeCriticalSection(&dll_critical_section);
dll_instance = instance;
GetSystemInfo(&dll_system_info);
if ((h_kernel = LoadLibrary("kernel32.dll")) != NULL)
fnGetSystemTimes = (pfnGetSystemTimes)GetProcAddress(h_kernel,
"GetSystemTimes");
if (fnGetSystemTimes == NULL) {
FreeLibrary(h_kernel);
h_kernel = NULL;
#if (_WIN32_WINNT < 0x0501)
if ((h_ntdll = LoadLibrary("ntdll.dll")) != NULL)
fnNtQuerySystemInformation =
(pfnNtQuerySystemInformation)GetProcAddress(h_ntdll,
"NtQuerySystemInformation");
if (fnNtQuerySystemInformation == NULL) {
FreeLibrary(h_ntdll);
h_ntdll = NULL;
}
#endif
}
GetModuleFileName(instance, dll_file_name, sizeof(dll_file_name));
break;
/** The attached process creates a new thread.
*/
case DLL_THREAD_ATTACH:
break;
/** The thread of the attached process terminates.
*/
case DLL_THREAD_DETACH:
break;
/** DLL unload due to process termination
* or FreeLibrary.
*/
case DLL_PROCESS_DETACH:
if (h_kernel)
FreeLibrary(h_kernel);
if (h_ntdll)
FreeLibrary(h_ntdll);
DeleteCriticalSection(&dll_critical_section);
break;
default:
break;
}
return TRUE;
UNREFERENCED_PARAMETER(reserved);
}
TCN_IMPLEMENT_CALL(jstring, OS, syserror)(TCN_STDARGS, jint err)
{
jstring str;
void *buf;
UNREFERENCED(o);
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&buf,
0,
NULL)) {
str = AJP_TO_JSTRING("Unknown Error");
}
else {
str = AJP_TO_JSTRING((const char *)buf);
LocalFree(buf);
}
return str;
}
TCN_IMPLEMENT_CALL(jstring, OS, expand)(TCN_STDARGS, jstring val)
{
jstring str;
jchar buf[TCN_BUFFER_SZ] = L"";
DWORD len;
TCN_ALLOC_WSTRING(val);
UNREFERENCED(o);
TCN_INIT_WSTRING(val);
len = ExpandEnvironmentStringsW(J2W(val), buf, TCN_BUFFER_SZ - 1);
if (len > (TCN_BUFFER_SZ - 1)) {
jchar *dbuf = malloc((len + 1) * 2);
ExpandEnvironmentStringsW(J2W(val), dbuf, len);
str = (*e)->NewString(e, dbuf, wcslen(dbuf));
free(dbuf);
}
else
str = (*e)->NewString(e, buf, wcslen(buf));
TCN_FREE_WSTRING(val);
return str;
}
#define LOG_MSG_EMERG 0xC0000001L
#define LOG_MSG_ERROR 0xC0000002L
#define LOG_MSG_NOTICE 0x80000003L
#define LOG_MSG_WARN 0x80000004L
#define LOG_MSG_INFO 0x40000005L
#define LOG_MSG_DEBUG 0x00000006L
#define LOG_MSG_DOMAIN "Native"
static char log_domain[MAX_PATH] = "Native";
static void init_log_source(const char *domain)
{
HKEY key;
DWORD ts;
char event_key[MAX_PATH];
strcpy(event_key, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\");
strcat(event_key, domain);
if (!RegCreateKey(HKEY_LOCAL_MACHINE, event_key, &key)) {
RegSetValueEx(key, "EventMessageFile", 0, REG_SZ, (LPBYTE)&dll_file_name[0],
strlen(dll_file_name) + 1);
ts = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
RegSetValueEx(key, "TypesSupported", 0, REG_DWORD, (LPBYTE) &ts, sizeof(DWORD));
RegCloseKey(key);
}
strcpy(log_domain, domain);
}
TCN_IMPLEMENT_CALL(void, OS, sysloginit)(TCN_STDARGS, jstring domain)
{
const char *d;
TCN_ALLOC_CSTRING(domain);
UNREFERENCED(o);
if ((d = J2S(domain)) == NULL)
d = LOG_MSG_DOMAIN;
init_log_source(d);
TCN_FREE_CSTRING(domain);
}
TCN_IMPLEMENT_CALL(void, OS, syslog)(TCN_STDARGS, jint level,
jstring msg)
{
TCN_ALLOC_CSTRING(msg);
DWORD id = LOG_MSG_DEBUG;
WORD il = EVENTLOG_SUCCESS;
HANDLE source;
const char *messages[1];
UNREFERENCED(o);
switch (level) {
case TCN_LOG_EMERG:
id = LOG_MSG_EMERG;
il = EVENTLOG_ERROR_TYPE;
break;
case TCN_LOG_ERROR:
id = LOG_MSG_ERROR;
il = EVENTLOG_ERROR_TYPE;
break;
case TCN_LOG_NOTICE:
id = LOG_MSG_NOTICE;
il = EVENTLOG_WARNING_TYPE;
break;
case TCN_LOG_WARN:
id = LOG_MSG_WARN;
il = EVENTLOG_WARNING_TYPE;
break;
case TCN_LOG_INFO:
id = LOG_MSG_INFO;
il = EVENTLOG_INFORMATION_TYPE;
break;
}
messages[0] = J2S(msg);
source = RegisterEventSource(NULL, log_domain);
if (source != NULL) {
ReportEvent(source, il,
0,
id,
NULL,
1, 0,
messages, NULL);
DeregisterEventSource(source);
}
TCN_FREE_CSTRING(msg);
}
TCN_IMPLEMENT_CALL(jboolean, OS, is)(TCN_STDARGS, jint type)
{
UNREFERENCED_STDARGS;
#ifdef _WIN64
if (type == 4)
return JNI_TRUE;
else
#endif
if (type == 3)
return JNI_TRUE;
else
return JNI_FALSE;
}
TCN_IMPLEMENT_CALL(jint, OS, info)(TCN_STDARGS,
jlongArray inf)
{
MEMORYSTATUSEX ms;
ULONGLONG st[4];
FILETIME ft[4];
PROCESS_MEMORY_COUNTERS pmc;
jint rv;
int i;
jsize ilen = (*e)->GetArrayLength(e, inf);
jlong *pvals = (*e)->GetLongArrayElements(e, inf, NULL);
if (ilen < 16) {
return APR_EINVAL;
}
for (i = 0; i < 16; i++)
pvals[i] = 0;
ms.dwLength = sizeof(MEMORYSTATUSEX);
UNREFERENCED(o);
if (GlobalMemoryStatusEx(&ms)) {
pvals[0] = (jlong)ms.ullTotalPhys;
pvals[1] = (jlong)ms.ullAvailPhys;
pvals[2] = (jlong)ms.ullTotalPageFile;
pvals[3] = (jlong)ms.ullAvailPageFile;
/* Slots 4 and 5 are for shared memory */
pvals[6] = (jlong)ms.dwMemoryLoad;
}
else
goto cleanup;
memset(st, 0, sizeof(st));
if (fnGetSystemTimes) {
if ((*fnGetSystemTimes)(&ft[0], &ft[1], &ft[2])) {
st[0] = (((ULONGLONG)ft[0].dwHighDateTime << 32) | ft[0].dwLowDateTime) / 10;
st[1] = (((ULONGLONG)ft[1].dwHighDateTime << 32) | ft[1].dwLowDateTime) / 10;
st[2] = (((ULONGLONG)ft[2].dwHighDateTime << 32) | ft[2].dwLowDateTime) / 10;
}
else
goto cleanup;
}
#if (_WIN32_WINNT < 0x0501)
else if (fnNtQuerySystemInformation) {
BYTE buf[2048]; /* This should ne enough for 32 processors */
NTSTATUS rs = (*fnNtQuerySystemInformation)(SystemProcessorPerformanceInformation,
(LPVOID)buf, 2048, NULL);
if (rs == 0) {
PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION pspi = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)&buf[0];
DWORD i;
/* Calculate all processors */
for (i = 0; i < dll_system_info.dwNumberOfProcessors; i++) {
st[0] += pspi[i].IdleTime.QuadPart / 10;
st[1] += pspi[i].KernelTime.QuadPart / 10;
st[2] += pspi[i].UserTime.QuadPart / 10;
}
}
else
goto cleanup;
}
#endif
pvals[7] = st[0];
pvals[8] = st[1];
pvals[9] = st[2];
memset(st, 0, sizeof(st));
if (GetProcessTimes(GetCurrentProcess(), &ft[0], &ft[1], &ft[2], &ft[3])) {
FileTimeToAprTime((apr_time_t *)&st[0], &ft[0]);
st[1] = (((ULONGLONG)ft[2].dwHighDateTime << 32) | ft[2].dwLowDateTime) / 10;
st[2] = (((ULONGLONG)ft[3].dwHighDateTime << 32) | ft[3].dwLowDateTime) / 10;
}
pvals[10] = st[0];
pvals[11] = st[1];
pvals[12] = st[2];
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
pvals[13] = pmc.WorkingSetSize;
pvals[14] = pmc.PeakWorkingSetSize;
pvals[15] = pmc.PageFaultCount;
}
(*e)->ReleaseLongArrayElements(e, inf, pvals, 0);
return APR_SUCCESS;
cleanup:
rv = apr_get_os_error();
(*e)->ReleaseLongArrayElements(e, inf, pvals, 0);
return rv;
}
#ifdef HAVE_OPENSSL
static DWORD WINAPI password_thread(void *data)
{
tcn_pass_cb_t *cb = (tcn_pass_cb_t *)data;
MSG msg;
HWINSTA hwss;
HWINSTA hwsu;
HDESK hwds;
HDESK hwdu;
HWND hwnd;
/* Ensure connection to service window station and desktop, and
* save their handles.
*/
GetDesktopWindow();
hwss = GetProcessWindowStation();
hwds = GetThreadDesktop(GetCurrentThreadId());
/* Impersonate the client and connect to the User's
* window station and desktop.
*/
hwsu = OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED);
if (hwsu == NULL) {
ExitThread(1);
return 1;
}
SetProcessWindowStation(hwsu);
hwdu = OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED);
if (hwdu == NULL) {
SetProcessWindowStation(hwss);
CloseWindowStation(hwsu);
ExitThread(1);
return 1;
}
SetThreadDesktop(hwdu);
hwnd = CreateDialog(dll_instance, MAKEINTRESOURCE(1001), NULL, NULL);
if (hwnd != NULL)
ShowWindow(hwnd, SW_SHOW);
else {
ExitThread(1);
return 1;
}
while (1) {
if (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) {
if (msg.message == WM_KEYUP) {
int nVirtKey = (int)msg.wParam;
if (nVirtKey == VK_ESCAPE) {
DestroyWindow(hwnd);
break;
}
else if (nVirtKey == VK_RETURN) {
HWND he = GetDlgItem(hwnd, 1002);
if (he) {
int n = GetWindowText(he, cb->password, SSL_MAX_PASSWORD_LEN - 1);
cb->password[n] = '\0';
}
DestroyWindow(hwnd);
break;
}
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
Sleep(100);
}
/* Restore window station and desktop.
*/
SetThreadDesktop(hwds);
SetProcessWindowStation(hwss);
CloseDesktop(hwdu);
CloseWindowStation(hwsu);
ExitThread(0);
return 0;
}
int WIN32_SSL_password_prompt(tcn_pass_cb_t *data)
{
DWORD id;
HANDLE thread;
/* TODO: See how to display this from service mode */
thread = CreateThread(NULL, 0,
password_thread, data,
0, &id);
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
return (int)strlen(data->password);
}
#endif