github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/clients/pkg/promtail/targets/windows/win_eventlog/util.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  	"fmt"
    33  	"io"
    34  	"strings"
    35  	"unicode/utf16"
    36  	"unicode/utf8"
    37  	"unsafe"
    38  
    39  	"golang.org/x/sys/windows"
    40  )
    41  
    42  // DecodeUTF16 to UTF8 bytes
    43  func DecodeUTF16(b []byte) ([]byte, error) {
    44  
    45  	if len(b)%2 != 0 {
    46  		return nil, fmt.Errorf("must have even length byte slice")
    47  	}
    48  
    49  	u16s := make([]uint16, 1)
    50  
    51  	ret := &bytes.Buffer{}
    52  
    53  	b8buf := make([]byte, 4)
    54  
    55  	lb := len(b)
    56  	for i := 0; i < lb; i += 2 {
    57  		u16s[0] = uint16(b[i]) + (uint16(b[i+1]) << 8)
    58  		r := utf16.Decode(u16s)
    59  		n := utf8.EncodeRune(b8buf, r[0])
    60  		ret.Write(b8buf[:n])
    61  	}
    62  
    63  	return ret.Bytes(), nil
    64  }
    65  
    66  // GetFromSnapProcess finds information about process by the given pid
    67  // Returns process parent pid, threads info handle and process name
    68  func GetFromSnapProcess(pid uint32) (uint32, uint32, string, error) {
    69  	snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, uint32(pid))
    70  	if err != nil {
    71  		return 0, 0, "", err
    72  	}
    73  	defer windows.CloseHandle(snap)
    74  	var pe32 windows.ProcessEntry32
    75  	pe32.Size = uint32(unsafe.Sizeof(pe32))
    76  	if err = windows.Process32First(snap, &pe32); err != nil {
    77  		return 0, 0, "", err
    78  	}
    79  	for {
    80  		if pe32.ProcessID == uint32(pid) {
    81  			szexe := windows.UTF16ToString(pe32.ExeFile[:])
    82  			return uint32(pe32.ParentProcessID), uint32(pe32.Threads), szexe, nil
    83  		}
    84  		if err = windows.Process32Next(snap, &pe32); err != nil {
    85  			break
    86  		}
    87  	}
    88  	return 0, 0, "", fmt.Errorf("couldn't find pid: %d", pid)
    89  }
    90  
    91  type xmlnode struct {
    92  	XMLName xml.Name
    93  	Attrs   []xml.Attr `xml:"-"`
    94  	Content []byte     `xml:",innerxml"`
    95  	Text    string     `xml:",chardata"`
    96  	Nodes   []xmlnode  `xml:",any"`
    97  }
    98  
    99  // EventField for unique rendering
   100  type EventField struct {
   101  	Name  string
   102  	Value string
   103  }
   104  
   105  // UnmarshalXML redefined for xml elements walk
   106  func (n *xmlnode) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
   107  	n.Attrs = start.Attr
   108  	type node xmlnode
   109  
   110  	return d.DecodeElement((*node)(n), &start)
   111  }
   112  
   113  // UnrollXMLFields extracts fields from xml data
   114  func UnrollXMLFields(data []byte, fieldsUsage map[string]int, separator string) ([]EventField, map[string]int) {
   115  	buf := bytes.NewBuffer(data)
   116  	dec := xml.NewDecoder(buf)
   117  	var fields []EventField
   118  	for {
   119  		var node xmlnode
   120  		err := dec.Decode(&node)
   121  		if err == io.EOF {
   122  			break
   123  		}
   124  		if err != nil {
   125  			// log.Fatal(err)
   126  			break
   127  		}
   128  		var parents []string
   129  		walkXML([]xmlnode{node}, parents, separator, func(node xmlnode, parents []string, separator string) bool {
   130  			innerText := strings.TrimSpace(node.Text)
   131  			if len(innerText) > 0 {
   132  				valueName := strings.Join(parents, separator)
   133  				fieldsUsage[valueName]++
   134  				field := EventField{Name: valueName, Value: innerText}
   135  				fields = append(fields, field)
   136  			}
   137  			return true
   138  		})
   139  	}
   140  	return fields, fieldsUsage
   141  }
   142  
   143  func walkXML(nodes []xmlnode, parents []string, separator string, f func(xmlnode, []string, string) bool) {
   144  	for _, node := range nodes {
   145  		parentName := node.XMLName.Local
   146  		for _, attr := range node.Attrs {
   147  			attrName := strings.ToLower(attr.Name.Local)
   148  			if attrName == "name" {
   149  				// Add Name attribute to parent name
   150  				parentName = strings.Join([]string{parentName, attr.Value}, separator)
   151  			}
   152  		}
   153  		nodeParents := append(parents, parentName)
   154  		if f(node, nodeParents, separator) {
   155  			walkXML(node.Nodes, nodeParents, separator, f)
   156  		}
   157  	}
   158  }
   159  
   160  // UniqueFieldNames forms unique field names
   161  // by adding _<num> if there are several of them
   162  func UniqueFieldNames(fields []EventField, fieldsUsage map[string]int, separator string) []EventField {
   163  	var fieldsCounter = map[string]int{}
   164  	var fieldsUnique []EventField
   165  	for _, field := range fields {
   166  		fieldName := field.Name
   167  		if fieldsUsage[field.Name] > 1 {
   168  			fieldsCounter[field.Name]++
   169  			fieldName = fmt.Sprint(field.Name, separator, fieldsCounter[field.Name])
   170  		}
   171  		fieldsUnique = append(fieldsUnique, EventField{
   172  			Name:  fieldName,
   173  			Value: field.Value,
   174  		})
   175  	}
   176  	return fieldsUnique
   177  }