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(&regkey, 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