1
0
Fork 0
telegraf/plugins/inputs/win_eventlog/util.go
Daniel Baumann 4978089aab
Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-24 07:26:29 +02:00

148 lines
3.7 KiB
Go

//go:build windows
package win_eventlog
import (
"bytes"
"encoding/xml"
"errors"
"fmt"
"strings"
"unicode/utf16"
"unicode/utf8"
"unsafe"
"golang.org/x/sys/windows"
)
// decodeUTF16 to UTF8 bytes
func decodeUTF16(b []byte) ([]byte, error) {
if len(b)%2 != 0 {
return nil, errors.New("must have even length byte slice")
}
u16s := make([]uint16, 1)
ret := &bytes.Buffer{}
b8buf := make([]byte, 4)
lb := len(b)
for i := 0; i < lb; i += 2 {
u16s[0] = uint16(b[i]) + (uint16(b[i+1]) << 8)
r := utf16.Decode(u16s)
n := utf8.EncodeRune(b8buf, r[0])
ret.Write(b8buf[:n])
}
return ret.Bytes(), nil
}
// getFromSnapProcess finds information about process by the given pid
// Returns process name
func getFromSnapProcess(pid uint32) (string, error) {
snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, pid)
if err != nil {
return "", err
}
defer windows.CloseHandle(snap)
var pe32 windows.ProcessEntry32
pe32.Size = uint32(unsafe.Sizeof(pe32))
if err := windows.Process32First(snap, &pe32); err != nil {
return "", err
}
for {
if pe32.ProcessID == pid {
szexe := windows.UTF16ToString(pe32.ExeFile[:])
return szexe, nil
}
if err = windows.Process32Next(snap, &pe32); err != nil {
break
}
}
return "", fmt.Errorf("couldn't find pid: %d", pid)
}
type xmlnode struct {
XMLName xml.Name
Attrs []xml.Attr `xml:"-"`
Content []byte `xml:",innerxml"`
Text string `xml:",chardata"`
Nodes []xmlnode `xml:",any"`
}
// eventField for unique rendering
type eventField struct {
Name string
Value string
}
// UnmarshalXML redefined for xml elements walk
func (n *xmlnode) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
n.Attrs = start.Attr
type node xmlnode
return d.DecodeElement((*node)(n), &start)
}
// unrollXMLFields extracts fields from xml data
func unrollXMLFields(data []byte, fieldsUsage map[string]int, separator string) ([]eventField, map[string]int) {
buf := bytes.NewBuffer(data)
dec := xml.NewDecoder(buf)
var fields []eventField
for {
var node xmlnode
err := dec.Decode(&node)
if err != nil {
break
}
var parents []string
walkXML([]xmlnode{node}, parents, separator, func(node xmlnode, parents []string, separator string) bool {
innerText := strings.TrimSpace(node.Text)
if len(innerText) > 0 {
valueName := strings.Join(parents, separator)
fieldsUsage[valueName]++
field := eventField{Name: valueName, Value: innerText}
fields = append(fields, field)
}
return true
})
}
return fields, fieldsUsage
}
func walkXML(nodes []xmlnode, parents []string, separator string, f func(xmlnode, []string, string) bool) {
for _, node := range nodes {
parentName := node.XMLName.Local
for _, attr := range node.Attrs {
attrName := strings.ToLower(attr.Name.Local)
if attrName == "name" {
// Add Name attribute to parent name
parentName = strings.Join([]string{parentName, attr.Value}, separator)
}
}
nodeParents := append(parents, parentName)
if f(node, nodeParents, separator) {
walkXML(node.Nodes, nodeParents, separator, f)
}
}
}
// uniqueFieldNames forms unique field names by adding _<num> if there are several of them
func uniqueFieldNames(fields []eventField, fieldsUsage map[string]int, separator string) []eventField {
var fieldsCounter = make(map[string]int, len(fields))
fieldsUnique := make([]eventField, 0, len(fields))
for _, field := range fields {
fieldName := field.Name
if fieldsUsage[field.Name] > 1 {
fieldsCounter[field.Name]++
fieldName = fmt.Sprint(field.Name, separator, fieldsCounter[field.Name])
}
fieldsUnique = append(fieldsUnique, eventField{
Name: fieldName,
Value: field.Value,
})
}
return fieldsUnique
}