| 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 |