github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/clients/pkg/promtail/targets/windows/win_eventlog/win_eventlog.go (about) 1 // The MIT License (MIT) 2 3 // Copyright (c) 2015-2020 InfluxData Inc. 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in all 13 // copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 // SOFTWARE. 22 //go:build windows 23 // +build windows 24 25 //revive:disable-next-line:var-naming 26 // Package win_eventlog Input plugin to collect Windows Event Log messages 27 package win_eventlog 28 29 import ( 30 "bytes" 31 "encoding/xml" 32 "path/filepath" 33 "strings" 34 "syscall" 35 36 "github.com/go-kit/log/level" 37 "github.com/influxdata/telegraf" 38 "github.com/influxdata/telegraf/plugins/inputs" 39 "golang.org/x/sys/windows" 40 41 util_log "github.com/grafana/loki/pkg/util/log" 42 ) 43 44 var sampleConfig = ` 45 ## Telegraf should have Administrator permissions to subscribe for some Windows Events channels 46 ## (System log, for example) 47 48 ## LCID (Locale ID) for event rendering 49 ## 1033 to force English language 50 ## 0 to use default Windows locale 51 # locale = 0 52 53 ## Name of eventlog, used only if xpath_query is empty 54 ## Example: "Application" 55 # eventlog_name = "" 56 57 ## xpath_query can be in defined short form like "Event/System[EventID=999]" 58 ## or you can form a XML Query. Refer to the Consuming Events article: 59 ## https://docs.microsoft.com/en-us/windows/win32/wes/consuming-events 60 ## XML query is the recommended form, because it is most flexible 61 ## You can create or debug XML Query by creating Custom View in Windows Event Viewer 62 ## and then copying resulting XML here 63 xpath_query = ''' 64 <QueryList> 65 <Query Id="0" Path="Security"> 66 <Select Path="Security">*</Select> 67 <Suppress Path="Security">*[System[( (EventID >= 5152 and EventID <= 5158) or EventID=5379 or EventID=4672)]]</Suppress> 68 </Query> 69 <Query Id="1" Path="Application"> 70 <Select Path="Application">*[System[(Level < 4)]]</Select> 71 </Query> 72 <Query Id="2" Path="Windows PowerShell"> 73 <Select Path="Windows PowerShell">*[System[(Level < 4)]]</Select> 74 </Query> 75 <Query Id="3" Path="System"> 76 <Select Path="System">*</Select> 77 </Query> 78 <Query Id="4" Path="Setup"> 79 <Select Path="Setup">*</Select> 80 </Query> 81 </QueryList> 82 ''' 83 84 ## System field names: 85 ## "Source", "EventID", "Version", "Level", "Task", "Opcode", "Keywords", "TimeCreated", 86 ## "EventRecordID", "ActivityID", "RelatedActivityID", "ProcessID", "ThreadID", "ProcessName", 87 ## "Channel", "Computer", "UserID", "UserName", "Message", "LevelText", "TaskText", "OpcodeText" 88 89 ## In addition to System, Data fields can be unrolled from additional XML nodes in event. 90 ## Human-readable representation of those nodes is formatted into event Message field, 91 ## but XML is more machine-parsable 92 93 # Process UserData XML to fields, if this node exists in Event XML 94 process_userdata = true 95 96 # Process EventData XML to fields, if this node exists in Event XML 97 process_eventdata = true 98 99 ## Separator character to use for unrolled XML Data field names 100 separator = "_" 101 102 ## Get only first line of Message field. For most events first line is usually more than enough 103 only_first_line_of_message = true 104 105 ## Parse timestamp from TimeCreated.SystemTime event field. 106 ## Will default to current time of telegraf processing on parsing error or if set to false 107 timestamp_from_event = true 108 109 ## Fields to include as tags. Globbing supported ("Level*" for both "Level" and "LevelText") 110 event_tags = ["Source", "EventID", "Level", "LevelText", "Task", "TaskText", "Opcode", "OpcodeText", "Keywords", "Channel", "Computer"] 111 112 ## Default list of fields to send. All fields are sent by default. Globbing supported 113 event_fields = ["*"] 114 115 ## Fields to exclude. Also applied to data fields. Globbing supported 116 exclude_fields = ["TimeCreated", "Binary", "Data_Address*"] 117 118 ## Skip those tags or fields if their value is empty or equals to zero. Globbing supported 119 exclude_empty = ["*ActivityID", "UserID"] 120 ` 121 122 // WinEventLog config 123 type WinEventLog struct { 124 Locale uint32 `yaml:"locale"` 125 EventlogName string `yaml:"eventlog_name"` 126 Query string `yaml:"xpath_query"` 127 ProcessUserData bool `yaml:"process_userdata"` 128 ProcessEventData bool `yaml:"process_eventdata"` 129 Separator string `yaml:"separator"` 130 OnlyFirstLineOfMessage bool `yaml:"only_first_line_of_message"` 131 TimeStampFromEvent bool `yaml:"timestamp_from_event"` 132 EventTags []string `yaml:"event_tags"` 133 EventFields []string `yaml:"event_fields"` 134 ExcludeFields []string `yaml:"exclude_fields"` 135 ExcludeEmpty []string `yaml:"exclude_empty"` 136 137 subscription EvtHandle 138 buf []byte 139 } 140 141 var bufferSize = 1 << 14 142 143 var description = "Input plugin to collect Windows Event Log messages" 144 145 // Description for win_eventlog 146 func (w *WinEventLog) Description() string { 147 return description 148 } 149 150 // SampleConfig for win_eventlog 151 func (w *WinEventLog) SampleConfig() string { 152 return sampleConfig 153 } 154 155 // Gather Windows Event Log entries 156 func (w *WinEventLog) Gather(acc telegraf.Accumulator) error { 157 158 // var err error 159 // if w.subscription == 0 { 160 // w.subscription, err = w.evtSubscribe(w.EventlogName, w.Query) 161 // if err != nil { 162 // return fmt.Errorf("Windows Event Log subscription error: %v", err.Error()) 163 // } 164 // } 165 166 // loop: 167 // for { 168 // events, err := w.FetchEvents(w.subscription) 169 // if err != nil { 170 // switch { 171 // case err == ERROR_NO_MORE_ITEMS: 172 // break loop 173 // case err != nil: 174 // // w.Log.Error("Error getting events:", err.Error()) 175 // return err 176 // } 177 // } 178 179 // for _, event := range events { 180 // // Prepare fields names usage counter 181 // var fieldsUsage = map[string]int{} 182 183 // tags := map[string]string{} 184 // fields := map[string]interface{}{} 185 // evt := reflect.ValueOf(&event).Elem() 186 // timeStamp := time.Now() 187 // // Walk through all fields of Event struct to process System tags or fields 188 // for i := 0; i < evt.NumField(); i++ { 189 // fieldName := evt.Type().Field(i).Name 190 // fieldType := evt.Field(i).Type().String() 191 // fieldValue := evt.Field(i).Interface() 192 // computedValues := map[string]interface{}{} 193 // switch fieldName { 194 // case "Source": 195 // fieldValue = event.Source.Name 196 // fieldType = reflect.TypeOf(fieldValue).String() 197 // case "Execution": 198 // fieldValue := event.Execution.ProcessID 199 // fieldType = reflect.TypeOf(fieldValue).String() 200 // fieldName = "ProcessID" 201 // // Look up Process Name from pid 202 // if should, _ := w.shouldProcessField("ProcessName"); should { 203 // _, _, processName, err := GetFromSnapProcess(fieldValue) 204 // if err == nil { 205 // computedValues["ProcessName"] = processName 206 // } 207 // } 208 // case "TimeCreated": 209 // fieldValue = event.TimeCreated.SystemTime 210 // fieldType = reflect.TypeOf(fieldValue).String() 211 // if w.TimeStampFromEvent { 212 // timeStamp, err = time.Parse(time.RFC3339Nano, fmt.Sprintf("%v", fieldValue)) 213 // if err != nil { 214 // // w.Log.Warnf("Error parsing timestamp %q: %v", fieldValue, err) 215 // } 216 // } 217 // case "Correlation": 218 // if should, _ := w.shouldProcessField("ActivityID"); should { 219 // activityID := event.Correlation.ActivityID 220 // if len(activityID) > 0 { 221 // computedValues["ActivityID"] = activityID 222 // } 223 // } 224 // if should, _ := w.shouldProcessField("RelatedActivityID"); should { 225 // relatedActivityID := event.Correlation.RelatedActivityID 226 // if len(relatedActivityID) > 0 { 227 // computedValues["RelatedActivityID"] = relatedActivityID 228 // } 229 // } 230 // case "Security": 231 // computedValues["UserID"] = event.Security.UserID 232 // // Look up UserName and Domain from SID 233 // if should, _ := w.shouldProcessField("UserName"); should { 234 // sid := event.Security.UserID 235 // usid, err := syscall.StringToSid(sid) 236 // if err == nil { 237 // username, domain, _, err := usid.LookupAccount("") 238 // if err == nil { 239 // computedValues["UserName"] = fmt.Sprint(domain, "\\", username) 240 // } 241 // } 242 // } 243 // default: 244 // } 245 // if should, where := w.shouldProcessField(fieldName); should { 246 // if where == "tags" { 247 // strValue := fmt.Sprintf("%v", fieldValue) 248 // if !w.shouldExcludeEmptyField(fieldName, "string", strValue) { 249 // tags[fieldName] = strValue 250 // fieldsUsage[fieldName]++ 251 // } 252 // } else if where == "fields" { 253 // if !w.shouldExcludeEmptyField(fieldName, fieldType, fieldValue) { 254 // fields[fieldName] = fieldValue 255 // fieldsUsage[fieldName]++ 256 // } 257 // } 258 // } 259 260 // // Insert computed fields 261 // for computedKey, computedValue := range computedValues { 262 // if should, where := w.shouldProcessField(computedKey); should { 263 // if where == "tags" { 264 // tags[computedKey] = fmt.Sprintf("%v", computedValue) 265 // fieldsUsage[computedKey]++ 266 // } else if where == "fields" { 267 // fields[computedKey] = computedValue 268 // fieldsUsage[computedKey]++ 269 // } 270 // } 271 // } 272 // } 273 274 // // Unroll additional XML 275 // var xmlFields []EventField 276 // if w.ProcessUserData { 277 // fieldsUserData, xmlFieldsUsage := UnrollXMLFields(event.UserData.InnerXML, fieldsUsage, w.Separator) 278 // xmlFields = append(xmlFields, fieldsUserData...) 279 // fieldsUsage = xmlFieldsUsage 280 // } 281 // if w.ProcessEventData { 282 // fieldsEventData, xmlFieldsUsage := UnrollXMLFields(event.EventData.InnerXML, fieldsUsage, w.Separator) 283 // xmlFields = append(xmlFields, fieldsEventData...) 284 // fieldsUsage = xmlFieldsUsage 285 // } 286 // uniqueXMLFields := UniqueFieldNames(xmlFields, fieldsUsage, w.Separator) 287 // for _, xmlField := range uniqueXMLFields { 288 // if !w.shouldExclude(xmlField.Name) { 289 // fields[xmlField.Name] = xmlField.Value 290 // } 291 // } 292 293 // // Pass collected metrics 294 // acc.AddFields("win_eventlog", fields, tags, timeStamp) 295 // } 296 // } 297 298 return nil 299 } 300 301 func (w *WinEventLog) shouldExclude(field string) (should bool) { 302 for _, excludePattern := range w.ExcludeFields { 303 // Check if field name matches excluded list 304 if matched, _ := filepath.Match(excludePattern, field); matched { 305 return true 306 } 307 } 308 return false 309 } 310 311 func (w *WinEventLog) shouldProcessField(field string) (should bool, list string) { 312 for _, pattern := range w.EventTags { 313 if matched, _ := filepath.Match(pattern, field); matched { 314 // Tags are not excluded 315 return true, "tags" 316 } 317 } 318 319 for _, pattern := range w.EventFields { 320 if matched, _ := filepath.Match(pattern, field); matched { 321 if w.shouldExclude(field) { 322 return false, "excluded" 323 } 324 return true, "fields" 325 } 326 } 327 return false, "excluded" 328 } 329 330 func (w *WinEventLog) shouldExcludeEmptyField(field string, fieldType string, fieldValue interface{}) (should bool) { 331 for _, pattern := range w.ExcludeEmpty { 332 if matched, _ := filepath.Match(pattern, field); matched { 333 switch fieldType { 334 case "string": 335 return len(fieldValue.(string)) < 1 336 case "int": 337 return fieldValue.(int) == 0 338 case "uint32": 339 return fieldValue.(uint32) == 0 340 } 341 } 342 } 343 return false 344 } 345 346 func EvtSubscribe(logName, xquery string) (EvtHandle, error) { 347 var logNamePtr, xqueryPtr *uint16 348 349 sigEvent, err := windows.CreateEvent(nil, 0, 0, nil) 350 if err != nil { 351 return 0, err 352 } 353 defer windows.CloseHandle(sigEvent) 354 355 logNamePtr, err = syscall.UTF16PtrFromString(logName) 356 if err != nil { 357 return 0, err 358 } 359 360 xqueryPtr, err = syscall.UTF16PtrFromString(xquery) 361 if err != nil { 362 return 0, err 363 } 364 365 subsHandle, err := _EvtSubscribe(0, uintptr(sigEvent), logNamePtr, xqueryPtr, 366 0, 0, 0, EvtSubscribeToFutureEvents) 367 if err != nil { 368 return 0, err 369 } 370 level.Debug(util_log.Logger).Log("msg", "Subcribed with handle id", "id", subsHandle) 371 372 return subsHandle, nil 373 } 374 375 func EvtSubscribeWithBookmark(logName, xquery string, bookMark EvtHandle) (EvtHandle, error) { 376 var logNamePtr, xqueryPtr *uint16 377 378 sigEvent, err := windows.CreateEvent(nil, 0, 0, nil) 379 if err != nil { 380 return 0, err 381 } 382 defer windows.CloseHandle(sigEvent) 383 384 logNamePtr, err = syscall.UTF16PtrFromString(logName) 385 if err != nil { 386 return 0, err 387 } 388 389 xqueryPtr, err = syscall.UTF16PtrFromString(xquery) 390 if err != nil { 391 return 0, err 392 } 393 394 subsHandle, err := _EvtSubscribe(0, uintptr(sigEvent), logNamePtr, xqueryPtr, 395 bookMark, 0, 0, EvtSubscribeStartAfterBookmark) 396 if err != nil { 397 return 0, err 398 } 399 level.Debug(util_log.Logger).Log("msg", "Subcribed with handle id", "id", subsHandle) 400 401 return subsHandle, nil 402 } 403 404 func fetchEventHandles(subsHandle EvtHandle) ([]EvtHandle, error) { 405 var eventsNumber uint32 406 var evtReturned uint32 407 408 eventsNumber = 5 409 410 eventHandles := make([]EvtHandle, eventsNumber) 411 412 err := _EvtNext(subsHandle, eventsNumber, &eventHandles[0], 0, 0, &evtReturned) 413 if err != nil { 414 if err == ERROR_INVALID_OPERATION && evtReturned == 0 { 415 return nil, ERROR_NO_MORE_ITEMS 416 } 417 return nil, err 418 } 419 420 return eventHandles[:evtReturned], nil 421 } 422 423 type EventFetcher struct { 424 buf []byte 425 } 426 427 func NewEventFetcher() *EventFetcher { 428 return &EventFetcher{} 429 } 430 431 func (w *EventFetcher) FetchEvents(subsHandle EvtHandle, lang uint32) ([]Event, []EvtHandle, error) { 432 if w.buf == nil { 433 w.buf = make([]byte, bufferSize) 434 } 435 var events []Event 436 437 eventHandles, err := fetchEventHandles(subsHandle) 438 if err != nil { 439 return nil, nil, err 440 } 441 442 for _, eventHandle := range eventHandles { 443 if eventHandle != 0 { 444 event, err := w.renderEvent(eventHandle, lang) 445 if err == nil { 446 events = append(events, event) 447 } 448 } 449 } 450 451 return events, eventHandles, nil 452 } 453 454 func Close(handles []EvtHandle) error { 455 for i := 0; i < len(handles); i++ { 456 err := _EvtClose(handles[i]) 457 if err != nil { 458 return err 459 } 460 } 461 return nil 462 } 463 464 func (w *EventFetcher) renderEvent(eventHandle EvtHandle, lang uint32) (Event, error) { 465 var bufferUsed, propertyCount uint32 466 467 event := Event{} 468 err := _EvtRender(0, eventHandle, EvtRenderEventXml, uint32(len(w.buf)), &w.buf[0], &bufferUsed, &propertyCount) 469 if err != nil { 470 return event, err 471 } 472 473 eventXML, err := DecodeUTF16(w.buf[:bufferUsed]) 474 if err != nil { 475 return event, err 476 } 477 err = xml.Unmarshal([]byte(eventXML), &event) 478 if err != nil { 479 // We can return event without most text values, 480 // that way we will not loose information 481 // This can happen when processing Forwarded Events 482 return event, nil 483 } 484 485 publisherHandle, err := openPublisherMetadata(0, event.Source.Name, lang) 486 if err != nil { 487 return event, nil 488 } 489 defer _EvtClose(publisherHandle) 490 491 // Populating text values 492 keywords, err := formatEventString(EvtFormatMessageKeyword, eventHandle, publisherHandle) 493 if err == nil { 494 event.Keywords = keywords 495 } 496 message, err := formatEventString(EvtFormatMessageEvent, eventHandle, publisherHandle) 497 if err == nil { 498 event.Message = message 499 } 500 level, err := formatEventString(EvtFormatMessageLevel, eventHandle, publisherHandle) 501 if err == nil { 502 event.LevelText = level 503 } 504 task, err := formatEventString(EvtFormatMessageTask, eventHandle, publisherHandle) 505 if err == nil { 506 event.TaskText = task 507 } 508 opcode, err := formatEventString(EvtFormatMessageOpcode, eventHandle, publisherHandle) 509 if err == nil { 510 event.OpcodeText = opcode 511 } 512 return event, nil 513 } 514 515 func formatEventString( 516 messageFlag EvtFormatMessageFlag, 517 eventHandle EvtHandle, 518 publisherHandle EvtHandle, 519 ) (string, error) { 520 var bufferUsed uint32 521 err := _EvtFormatMessage(publisherHandle, eventHandle, 0, 0, 0, messageFlag, 522 0, nil, &bufferUsed) 523 if err != nil && err != ERROR_INSUFFICIENT_BUFFER { 524 return "", err 525 } 526 527 bufferUsed *= 2 528 buffer := make([]byte, bufferUsed) 529 bufferUsed = 0 530 531 err = _EvtFormatMessage(publisherHandle, eventHandle, 0, 0, 0, messageFlag, 532 uint32(len(buffer)/2), &buffer[0], &bufferUsed) 533 bufferUsed *= 2 534 if err != nil { 535 return "", err 536 } 537 538 result, err := DecodeUTF16(buffer[:bufferUsed]) 539 if err != nil { 540 return "", err 541 } 542 543 var out string 544 if messageFlag == EvtFormatMessageKeyword { 545 // Keywords are returned as array of a zero-terminated strings 546 splitZero := func(c rune) bool { return c == '\x00' } 547 eventKeywords := strings.FieldsFunc(string(result), splitZero) 548 // So convert them to comma-separated string 549 out = strings.Join(eventKeywords, ",") 550 } else { 551 result := bytes.Trim(result, "\x00") 552 out = string(result) 553 } 554 return out, nil 555 } 556 557 // openPublisherMetadata opens a handle to the publisher's metadata. Close must 558 // be called on returned EvtHandle when finished with the handle. 559 func openPublisherMetadata( 560 session EvtHandle, 561 publisherName string, 562 lang uint32, 563 ) (EvtHandle, error) { 564 p, err := syscall.UTF16PtrFromString(publisherName) 565 if err != nil { 566 return 0, err 567 } 568 569 h, err := _EvtOpenPublisherMetadata(session, p, nil, lang, 0) 570 if err != nil { 571 return 0, err 572 } 573 574 return h, nil 575 } 576 577 func init() { 578 inputs.Add("win_eventlog", func() telegraf.Input { 579 return &WinEventLog{ 580 buf: make([]byte, bufferSize), 581 ProcessUserData: true, 582 ProcessEventData: true, 583 Separator: "_", 584 OnlyFirstLineOfMessage: true, 585 TimeStampFromEvent: true, 586 EventTags: []string{"Source", "EventID", "Level", "LevelText", "Keywords", "Channel", "Computer"}, 587 EventFields: []string{"*"}, 588 ExcludeEmpty: []string{"Task", "Opcode", "*ActivityID", "UserID"}, 589 } 590 }) 591 }