OLD | NEW |
| (Empty) |
1 // Copyright 2007-2009 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 | |
16 | |
17 #include "omaha/common/event_logger.h" | |
18 | |
19 #include <sddl.h> | |
20 #include "omaha/base/debug.h" | |
21 #include "omaha/base/error.h" | |
22 #include "omaha/base/logging.h" | |
23 #include "omaha/base/omaha_version.h" | |
24 #include "omaha/base/reg_key.h" | |
25 #include "omaha/base/safe_format.h" | |
26 #include "omaha/base/user_info.h" | |
27 #include "omaha/common/config_manager.h" | |
28 | |
29 namespace omaha { | |
30 | |
31 void LogEventHelper(WORD type, DWORD id, size_t count, const TCHAR** strings, | |
32 const TCHAR* ctx) { | |
33 ASSERT1(count <= kint16max); | |
34 if (!ConfigManager::Instance()->CanLogEvents(type)) { | |
35 return; | |
36 } | |
37 | |
38 // Include the circular logging buffer in the event log if the type is a | |
39 // warning or an error. | |
40 CStringA data(ctx); | |
41 CString context = GetLogging()->GetHistory(); | |
42 if (!context.IsEmpty()) { | |
43 SafeCStringAAppendFormat(&data, "\n[More context: %S]", context); | |
44 } | |
45 | |
46 HRESULT hr = EventLogger::ReportEvent(EventLogger::kSourceName, | |
47 type, | |
48 EventLogger::kDefaultCategory, | |
49 id, | |
50 static_cast<WORD>(count), | |
51 strings, | |
52 data.GetLength(), | |
53 data.GetBuffer()); | |
54 if (FAILED(hr)) { | |
55 CORE_LOG(LW, (_T("[Failed to log event][0x%08x]"), hr)); | |
56 } | |
57 } | |
58 | |
59 CString BuildEventSourceRegistryKeyName(const TCHAR* src_name) { | |
60 ASSERT1(src_name); | |
61 CString key_name; | |
62 SafeCStringFormat(&key_name, | |
63 _T("HKLM\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\") | |
64 _T("Application\\%s"), | |
65 src_name); | |
66 return key_name; | |
67 } | |
68 | |
69 HRESULT EventLogger::AddEventSource(const TCHAR* src_name, | |
70 const TCHAR* msg_dll_path) { | |
71 ASSERT1(src_name); | |
72 if (!src_name) return E_INVALIDARG; | |
73 ASSERT1(msg_dll_path); | |
74 if (!msg_dll_path) return E_INVALIDARG; | |
75 | |
76 // Create the event source as a subkey of the "Application" log. | |
77 RegKey reg_key; | |
78 HRESULT hr = reg_key.Create(BuildEventSourceRegistryKeyName(src_name)); | |
79 if (FAILED(hr)) return hr; | |
80 | |
81 // Set the name of the message file. RegKey class can't set REG_EXPAND_SZ | |
82 // values so we must use the low level OS call. | |
83 int result = ::RegSetValueEx(reg_key.Key(), | |
84 _T("EventMessageFile"), | |
85 0, | |
86 REG_EXPAND_SZ, | |
87 reinterpret_cast<const byte*>(msg_dll_path), | |
88 (_tcslen(msg_dll_path) + 1) * sizeof(TCHAR)); | |
89 if (result != ERROR_SUCCESS) return HRESULT_FROM_WIN32(result); | |
90 | |
91 // Set the supported event types. | |
92 DWORD types = EVENTLOG_ERROR_TYPE | | |
93 EVENTLOG_WARNING_TYPE | | |
94 EVENTLOG_INFORMATION_TYPE; | |
95 hr = reg_key.SetValue(_T("TypesSupported"), types); | |
96 if (FAILED(hr)) return hr; | |
97 | |
98 return S_OK; | |
99 } | |
100 | |
101 HRESULT EventLogger::RemoveEventSource(const TCHAR* src_name) { | |
102 ASSERT1(src_name); | |
103 if (!src_name) return E_INVALIDARG; | |
104 | |
105 // RegKey::DeleteKey returns S_FALSE when attempting to delete | |
106 // a key that is not there. | |
107 HRESULT hr = RegKey::DeleteKey(BuildEventSourceRegistryKeyName(src_name), | |
108 false); | |
109 return SUCCEEDED(hr) ? S_OK : hr; | |
110 } | |
111 | |
112 | |
113 HRESULT EventLogger::ReportEvent(const TCHAR* src_name, | |
114 WORD type, | |
115 WORD category, | |
116 DWORD id, | |
117 WORD count, | |
118 const TCHAR** strings, | |
119 size_t buf_size, | |
120 void* buffer) { | |
121 ASSERT1(src_name); | |
122 ASSERT1(type == EVENTLOG_SUCCESS || | |
123 type == EVENTLOG_ERROR_TYPE || | |
124 type == EVENTLOG_WARNING_TYPE || | |
125 type == EVENTLOG_INFORMATION_TYPE); | |
126 | |
127 // Opens the log on the local computer. | |
128 HANDLE hlog = ::RegisterEventSource(NULL, src_name); | |
129 if (!hlog) { | |
130 return HRESULTFromLastError(); | |
131 } | |
132 | |
133 // Best effort to get the sid for the current effective user. The event | |
134 // logging provides for logging the sid at no cost so that the user shows up | |
135 // in the event log. | |
136 CString sid_string; | |
137 VERIFY1(SUCCEEDED(user_info::GetEffectiveUserSid(&sid_string))); | |
138 PSID psid = NULL; | |
139 if (!sid_string.IsEmpty()) { | |
140 VERIFY1(::ConvertStringSidToSid(sid_string, &psid)); | |
141 ASSERT1(psid); | |
142 } | |
143 | |
144 HRESULT hr = E_FAIL; | |
145 if (::ReportEvent(hlog, // Event log handle. | |
146 type, // Event type. | |
147 category, // Event category. | |
148 id, // Event identifier. | |
149 psid, // User security identifier. | |
150 count, // Number of substitution strings. | |
151 buf_size, // Size of binary data. | |
152 strings, // Pointer to strings. | |
153 buffer)) { // Binary data. | |
154 hr = S_OK; | |
155 } else { | |
156 hr = HRESULTFromLastError(); | |
157 } | |
158 | |
159 ::LocalFree(psid); | |
160 VERIFY1(::DeregisterEventSource(hlog)); | |
161 return hr; | |
162 } | |
163 | |
164 HRESULT EventLogger::ReadLastEvent(const TCHAR* src_name, EVENTLOGRECORD* rec) { | |
165 if (!(rec && src_name)) { | |
166 return E_INVALIDARG; | |
167 } | |
168 HANDLE hlog = ::OpenEventLog(NULL, src_name); | |
169 if (!hlog) { | |
170 return HRESULTFromLastError(); | |
171 } | |
172 HRESULT hr = E_FAIL; | |
173 DWORD bytes_read(0), bytes_needed(0); | |
174 const DWORD read_flags = EVENTLOG_BACKWARDS_READ | EVENTLOG_SEQUENTIAL_READ; | |
175 if (::ReadEventLog(hlog, // Event log handle. | |
176 read_flags, // Reverse chronological order. | |
177 0, // Not used. | |
178 rec, // Read buffer. | |
179 rec->Length, // Size of read buffer. | |
180 &bytes_read, // Number of bytes read. | |
181 &bytes_needed)) { // Number of bytes required. | |
182 hr = S_OK; | |
183 } else { | |
184 hr = HRESULTFromLastError(); | |
185 } | |
186 ::CloseEventLog(hlog); | |
187 return hr; | |
188 } | |
189 | |
190 // TODO(omaha): Decide whether to use IDS_PRODUCT_DISPLAY_NAME instead. | |
191 // On one hand this string makes it to the event viewer, on | |
192 // the other hand the same string is used to register an event log for an | |
193 // application in registry. We do not expect the mapping to change when the user | |
194 // changes languages or there are multiple users for a per-machine install that | |
195 // are using different languages., however we may decide to do so. | |
196 const TCHAR* const EventLogger::kSourceName = kAppName; | |
197 | |
198 void GoogleUpdateLogEvent::WriteEvent() { | |
199 ASSERT1(!event_desc_.IsEmpty()); | |
200 ASSERT1(type_ != 0); | |
201 ASSERT1(id_ != 0); | |
202 | |
203 const DWORD pid(::GetCurrentProcessId()); | |
204 const TCHAR* ver = GetVersionString(); | |
205 | |
206 const ConfigManager& cm = *ConfigManager::Instance(); | |
207 CString msg; | |
208 SafeCStringFormat(&msg, _T("\n%s.\npid=%d, ver=%s, machine=%d, extern=%d"), | |
209 event_desc_, pid, ver, is_machine_, !cm.IsInternalUser()); | |
210 #if DEBUG | |
211 msg.Append(_T(", debug")); | |
212 #endif | |
213 #if !OFFICIAL_BUILD | |
214 msg.Append(_T(", private")); | |
215 #endif | |
216 | |
217 if (!event_text_.IsEmpty()) { | |
218 SafeCStringAppendFormat(&msg, _T("\n%s"), event_text_); | |
219 } | |
220 | |
221 LogEvent(static_cast<WORD>(type_), id_, msg); | |
222 } | |
223 | |
224 } // namespace omaha | |
225 | |
OLD | NEW |