1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "httpd.h"
18 #include "http_log.h"
19 #include "mpm_winnt.h"
20 #include "apr_strings.h"
21 #include "apr_lib.h"
22 #include "apr_portable.h"
23 #include "ap_regkey.h"
24
25 static const char *display_name = NULL;
26 static HANDLE stderr_thread = NULL;
27 static HANDLE stderr_ready;
28
service_stderr_thread(LPVOID hPipe)29 static DWORD WINAPI service_stderr_thread(LPVOID hPipe)
30 {
31 HANDLE hPipeRead = (HANDLE) hPipe;
32 HANDLE hEventSource;
33 char errbuf[256];
34 char *errmsg = errbuf;
35 const char *errarg[9];
36 DWORD errres;
37 ap_regkey_t *regkey;
38 apr_status_t rv;
39 apr_pool_t *p;
40
41 apr_pool_create_ex(&p, NULL, NULL, NULL);
42
43 errarg[0] = "The Apache service named";
44 errarg[1] = display_name;
45 errarg[2] = "reported the following error:\r\n>>>";
46 errarg[3] = errbuf;
47 errarg[4] = NULL;
48 errarg[5] = NULL;
49 errarg[6] = NULL;
50 errarg[7] = NULL;
51 errarg[8] = NULL;
52
53 /* What are we going to do in here, bail on the user? not. */
54 if ((rv = ap_regkey_open(®key, AP_REGKEY_LOCAL_MACHINE,
55 "SYSTEM\\CurrentControlSet\\Services\\"
56 "EventLog\\Application\\Apache Service",
57 APR_READ | APR_WRITE | APR_CREATE, p))
58 == APR_SUCCESS)
59 {
60 DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
61 EVENTLOG_INFORMATION_TYPE;
62
63 /* The stock message file */
64 ap_regkey_value_set(regkey, "EventMessageFile",
65 "%SystemRoot%\\System32\\netmsg.dll",
66 AP_REGKEY_EXPAND, p);
67
68 ap_regkey_value_raw_set(regkey, "TypesSupported", &dwData,
69 sizeof(dwData), REG_DWORD, p);
70 ap_regkey_close(regkey);
71 }
72
73 hEventSource = RegisterEventSourceW(NULL, L"Apache Service");
74
75 SetEvent(stderr_ready);
76
77 while (ReadFile(hPipeRead, errmsg, 1, &errres, NULL) && (errres == 1))
78 {
79 if ((errmsg > errbuf) || !apr_isspace(*errmsg))
80 {
81 ++errmsg;
82 if ((*(errmsg - 1) == '\n')
83 || (errmsg >= errbuf + sizeof(errbuf) - 1))
84 {
85 while ((errmsg > errbuf) && apr_isspace(*(errmsg - 1))) {
86 --errmsg;
87 }
88 *errmsg = '\0';
89
90 /* Generic message: '%1 %2 %3 %4 %5 %6 %7 %8 %9'
91 * The event code in netmsg.dll is 3299
92 */
93 ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0,
94 3299, NULL, 9, 0, errarg, NULL);
95 errmsg = errbuf;
96 }
97 }
98 }
99
100 if ((errres = GetLastError()) != ERROR_BROKEN_PIPE) {
101 apr_snprintf(errbuf, sizeof(errbuf),
102 "Win32 error %lu reading stderr pipe stream\r\n",
103 GetLastError());
104
105 ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0,
106 3299, NULL, 9, 0, errarg, NULL);
107 }
108
109 CloseHandle(hPipeRead);
110 DeregisterEventSource(hEventSource);
111 CloseHandle(stderr_thread);
112 stderr_thread = NULL;
113 apr_pool_destroy(p);
114 return 0;
115 }
116
117
mpm_nt_eventlog_stderr_flush(void)118 void mpm_nt_eventlog_stderr_flush(void)
119 {
120 HANDLE cleanup_thread = stderr_thread;
121
122 if (cleanup_thread) {
123 HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE);
124 fclose(stderr);
125 CloseHandle(hErr);
126 WaitForSingleObject(cleanup_thread, 30000);
127 CloseHandle(cleanup_thread);
128 }
129 }
130
131
mpm_nt_eventlog_stderr_open(const char * argv0,apr_pool_t * p)132 void mpm_nt_eventlog_stderr_open(const char *argv0, apr_pool_t *p)
133 {
134 SECURITY_ATTRIBUTES sa;
135 HANDLE hPipeRead = NULL;
136 HANDLE hPipeWrite = NULL;
137 DWORD threadid;
138 apr_file_t *eventlog_file;
139 apr_file_t *stderr_file;
140
141 display_name = argv0;
142
143 /* Create a pipe to send stderr messages to the system error log.
144 *
145 * _dup2() duplicates the write handle inheritable for us.
146 */
147 sa.nLength = sizeof(sa);
148 sa.lpSecurityDescriptor = NULL;
149 sa.bInheritHandle = FALSE;
150 CreatePipe(&hPipeRead, &hPipeWrite, NULL, 0);
151 ap_assert(hPipeRead && hPipeWrite);
152
153 stderr_ready = CreateEvent(NULL, FALSE, FALSE, NULL);
154 stderr_thread = CreateThread(NULL, 65536, service_stderr_thread,
155 (LPVOID)hPipeRead, stack_res_flag, &threadid);
156 ap_assert(stderr_ready && stderr_thread);
157
158 WaitForSingleObject(stderr_ready, INFINITE);
159
160 if ((apr_file_open_stderr(&stderr_file, p)
161 == APR_SUCCESS)
162 && (apr_os_file_put(&eventlog_file, &hPipeWrite, APR_WRITE, p)
163 == APR_SUCCESS))
164 apr_file_dup2(stderr_file, eventlog_file, p);
165
166 /* The code above _will_ corrupt the StdHandle...
167 * and we must do so anyways. We set this up only
168 * after we initialized the posix stderr API.
169 */
170 ap_open_stderr_log(p);
171 }
172