mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-10-17 01:59:04 +02:00
headers: remove unused netapi32, secur32 and schedule_service (#2550)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
3485634c49
commit
1fc968a06d
@@ -1,132 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Copyright The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build windows
|
||||
|
||||
package netapi32
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// WKSTAInfo102 is a wrapper of WKSTA_Info_102
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/ns-lmwksta-wksta_info_102
|
||||
type wKSTAInfo102 struct {
|
||||
wki102_platform_id uint32
|
||||
wki102_computername *uint16
|
||||
wki102_langroup *uint16
|
||||
wki102_ver_major uint32
|
||||
wki102_ver_minor uint32
|
||||
wki102_lanroot *uint16
|
||||
wki102_logged_on_users uint32
|
||||
}
|
||||
|
||||
// WorkstationInfo is an idiomatic wrapper of WKSTAInfo102.
|
||||
type WorkstationInfo struct {
|
||||
PlatformId uint32
|
||||
ComputerName string
|
||||
LanGroup string
|
||||
VersionMajor uint32
|
||||
VersionMinor uint32
|
||||
LanRoot string
|
||||
LoggedOnUsers uint32
|
||||
}
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
var (
|
||||
netapi32 = windows.NewLazySystemDLL("netapi32")
|
||||
procNetWkstaGetInfo = netapi32.NewProc("NetWkstaGetInfo")
|
||||
procNetApiBufferFree = netapi32.NewProc("NetApiBufferFree")
|
||||
)
|
||||
|
||||
// NetApiStatus is a map of Network Management Error Codes.
|
||||
// https://docs.microsoft.com/en-gb/windows/win32/netmgmt/network-management-error-codes?redirectedfrom=MSDN
|
||||
//
|
||||
//nolint:gochecknoglobals
|
||||
var NetApiStatus = map[uint32]string{
|
||||
// Success
|
||||
0: "NERR_Success",
|
||||
// This computer name is invalid.
|
||||
2351: "NERR_InvalidComputer",
|
||||
// This operation is only allowed on the primary domain controller of the domain.
|
||||
2226: "NERR_NotPrimary",
|
||||
// This operation is not allowed on this special group.
|
||||
2234: "NERR_SpeGroupOp",
|
||||
// This operation is not allowed on the last administrative account.
|
||||
2452: "NERR_LastAdmin",
|
||||
// The password parameter is invalid.
|
||||
2203: "NERR_BadPassword",
|
||||
// The password does not meet the password policy requirements.
|
||||
// Check the minimum password length, password complexity and password history requirements.
|
||||
2245: "NERR_PasswordTooShort",
|
||||
// The user name could not be found.
|
||||
2221: "NERR_UserNotFound",
|
||||
// Errors
|
||||
5: "ERROR_ACCESS_DENIED",
|
||||
8: "ERROR_NOT_ENOUGH_MEMORY",
|
||||
87: "ERROR_INVALID_PARAMETER",
|
||||
123: "ERROR_INVALID_NAME",
|
||||
124: "ERROR_INVALID_LEVEL",
|
||||
234: "ERROR_MORE_DATA",
|
||||
1219: "ERROR_SESSION_CREDENTIAL_CONFLICT",
|
||||
}
|
||||
|
||||
// NetApiBufferFree frees the memory other network management functions use internally to return information.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/lmapibuf/nf-lmapibuf-netapibufferfree
|
||||
func netApiBufferFree(buffer *wKSTAInfo102) {
|
||||
procNetApiBufferFree.Call(uintptr(unsafe.Pointer(buffer))) //nolint:errcheck
|
||||
}
|
||||
|
||||
// NetWkstaGetInfo returns information about the configuration of a workstation.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/nf-lmwksta-netwkstagetinfo
|
||||
func netWkstaGetInfo() (wKSTAInfo102, uint32, error) {
|
||||
var lpwi *wKSTAInfo102
|
||||
|
||||
pLevel := uintptr(102)
|
||||
|
||||
r1, _, _ := procNetWkstaGetInfo.Call(0, pLevel, uintptr(unsafe.Pointer(&lpwi)))
|
||||
defer netApiBufferFree(lpwi)
|
||||
|
||||
if ret := *(*uint32)(unsafe.Pointer(&r1)); ret != 0 {
|
||||
return wKSTAInfo102{}, ret, errors.New(NetApiStatus[ret])
|
||||
}
|
||||
|
||||
deref := *lpwi
|
||||
|
||||
return deref, 0, nil
|
||||
}
|
||||
|
||||
// GetWorkstationInfo is an idiomatic wrapper for netWkstaGetInfo.
|
||||
func GetWorkstationInfo() (WorkstationInfo, error) {
|
||||
info, _, err := netWkstaGetInfo()
|
||||
if err != nil {
|
||||
return WorkstationInfo{}, err
|
||||
}
|
||||
|
||||
workstationInfo := WorkstationInfo{
|
||||
PlatformId: info.wki102_platform_id,
|
||||
ComputerName: windows.UTF16PtrToString(info.wki102_computername),
|
||||
LanGroup: windows.UTF16PtrToString(info.wki102_langroup),
|
||||
VersionMajor: info.wki102_ver_major,
|
||||
VersionMinor: info.wki102_ver_minor,
|
||||
LanRoot: windows.UTF16PtrToString(info.wki102_lanroot),
|
||||
LoggedOnUsers: info.wki102_logged_on_users,
|
||||
}
|
||||
|
||||
return workstationInfo, nil
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Copyright The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build windows
|
||||
|
||||
package schedule_service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/go-ole/go-ole"
|
||||
"github.com/go-ole/go-ole/oleutil"
|
||||
)
|
||||
|
||||
type ScheduleService struct {
|
||||
taskSchedulerObj *ole.IUnknown
|
||||
taskServiceObj *ole.IDispatch
|
||||
taskService *ole.VARIANT
|
||||
}
|
||||
|
||||
func New() *ScheduleService {
|
||||
return &ScheduleService{}
|
||||
}
|
||||
|
||||
func (s *ScheduleService) Connect() error {
|
||||
// The only way to run WMI queries in parallel while being thread-safe is to
|
||||
// ensure the CoInitialize[Ex]() call is bound to its current OS thread.
|
||||
// Otherwise, attempting to initialize and run parallel queries across
|
||||
// goroutines will result in protected memory errors.
|
||||
runtime.LockOSThread()
|
||||
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if err := ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED|ole.COINIT_DISABLE_OLE1DDE); err != nil {
|
||||
var oleCode *ole.OleError
|
||||
if errors.As(err, &oleCode) && oleCode.Code() != ole.S_OK && oleCode.Code() != 0x00000001 {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
scheduleClassID, err := ole.ClassIDFrom("Schedule.Service")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.taskSchedulerObj, err = ole.CreateInstance(scheduleClassID, nil)
|
||||
if err != nil || s.taskSchedulerObj == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.taskService, err = oleutil.CallMethod(s.taskServiceObj, "Connect")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to task service: %w", err)
|
||||
}
|
||||
|
||||
s.taskServiceObj = s.taskSchedulerObj.MustQueryInterface(ole.IID_IDispatch)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ScheduleService) GetOLETaskServiceObj() *ole.IDispatch {
|
||||
return s.taskServiceObj
|
||||
}
|
||||
|
||||
func (s *ScheduleService) Close() {
|
||||
if s.taskService != nil {
|
||||
_ = s.taskService.Clear()
|
||||
}
|
||||
|
||||
if s.taskServiceObj != nil {
|
||||
s.taskServiceObj.Release()
|
||||
}
|
||||
|
||||
if s.taskSchedulerObj != nil {
|
||||
s.taskSchedulerObj.Release()
|
||||
}
|
||||
|
||||
ole.CoUninitialize()
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Copyright The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build windows
|
||||
|
||||
package secur32
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// based on https://github.com/carlpett/winlsa/blob/master/winlsa.go
|
||||
//
|
||||
//nolint:gochecknoglobals
|
||||
var (
|
||||
secur32 = windows.NewLazySystemDLL("Secur32.dll")
|
||||
advapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||
|
||||
procLsaEnumerateLogonSessions = secur32.NewProc("LsaEnumerateLogonSessions")
|
||||
procLsaGetLogonSessionData = secur32.NewProc("LsaGetLogonSessionData")
|
||||
procLsaFreeReturnBuffer = secur32.NewProc("LsaFreeReturnBuffer")
|
||||
procLsaNtStatusToWinError = advapi32.NewProc("LsaNtStatusToWinError")
|
||||
)
|
||||
|
||||
func GetLogonSessions() ([]*LogonSessionData, error) {
|
||||
var (
|
||||
buffer uintptr
|
||||
sessionCount uint32
|
||||
)
|
||||
|
||||
err := LsaEnumerateLogonSessions(&sessionCount, &buffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if buffer != 0 {
|
||||
defer func(buffer uintptr) {
|
||||
_ = LsaFreeReturnBuffer(buffer)
|
||||
}(buffer)
|
||||
}
|
||||
|
||||
sizeLUID := unsafe.Sizeof(windows.LUID{})
|
||||
|
||||
sessionDataSlice := make([]*LogonSessionData, 0, sessionCount)
|
||||
|
||||
for i := range sessionCount {
|
||||
curPtr := unsafe.Pointer(buffer + (uintptr(i) * sizeLUID))
|
||||
luid := (*windows.LUID)(curPtr)
|
||||
|
||||
sessionData, err := GetLogonSessionData(luid)
|
||||
if err != nil {
|
||||
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
|
||||
// Skip logon sessions that we don't have access to
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sessionDataSlice = append(sessionDataSlice, sessionData)
|
||||
}
|
||||
|
||||
return sessionDataSlice, nil
|
||||
}
|
||||
|
||||
func GetLogonSessionData(luid *windows.LUID) (*LogonSessionData, error) {
|
||||
var dataBuffer *SECURITY_LOGON_SESSION_DATA
|
||||
if err := LsaGetLogonSessionData(luid, &dataBuffer); err != nil {
|
||||
return nil, fmt.Errorf("failed to get logon session data: %w", err)
|
||||
}
|
||||
|
||||
defer func(buffer uintptr) {
|
||||
_ = LsaFreeReturnBuffer(buffer)
|
||||
}(uintptr(unsafe.Pointer(dataBuffer)))
|
||||
|
||||
return newLogonSessionData(dataBuffer), nil
|
||||
}
|
||||
|
||||
func LsaEnumerateLogonSessions(sessionCount *uint32, sessions *uintptr) error {
|
||||
r0, _, _ := procLsaEnumerateLogonSessions.Call(uintptr(unsafe.Pointer(sessionCount)), uintptr(unsafe.Pointer(sessions)))
|
||||
|
||||
return LsaNtStatusToWinError(r0)
|
||||
}
|
||||
|
||||
func LsaGetLogonSessionData(luid *windows.LUID, ppLogonSessionData **SECURITY_LOGON_SESSION_DATA) error {
|
||||
r0, _, _ := procLsaGetLogonSessionData.Call(uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(ppLogonSessionData)))
|
||||
|
||||
return LsaNtStatusToWinError(r0)
|
||||
}
|
||||
|
||||
func LsaFreeReturnBuffer(buffer uintptr) error {
|
||||
r0, _, _ := procLsaFreeReturnBuffer.Call(buffer)
|
||||
|
||||
return LsaNtStatusToWinError(r0)
|
||||
}
|
||||
|
||||
func LsaNtStatusToWinError(ntstatus uintptr) error {
|
||||
r0, _, err := procLsaNtStatusToWinError.Call(ntstatus)
|
||||
|
||||
switch {
|
||||
case errors.Is(err, windows.ERROR_SUCCESS):
|
||||
if r0 == 0 {
|
||||
return nil
|
||||
}
|
||||
case errors.Is(err, windows.ERROR_MR_MID_NOT_FOUND):
|
||||
return fmt.Errorf("unknown LSA NTSTATUS code %x", ntstatus)
|
||||
}
|
||||
|
||||
return windows.Errno(r0)
|
||||
}
|
||||
|
||||
func newLogonSessionData(data *SECURITY_LOGON_SESSION_DATA) *LogonSessionData {
|
||||
return &LogonSessionData{
|
||||
LogonId: data.LogonId,
|
||||
UserName: data.UserName.String(),
|
||||
LogonDomain: data.LogonDomain.String(),
|
||||
LogonType: data.LogonType,
|
||||
LogonTime: time.Unix(0, data.LogonTime.Nanoseconds()),
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Copyright The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build windows
|
||||
|
||||
package secur32_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus-community/windows_exporter/internal/headers/secur32"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetLogonSessions(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
sessionData, err := secur32.GetLogonSessions()
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, sessionData)
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Copyright The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build windows
|
||||
|
||||
package secur32
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
type LogonType uint32
|
||||
|
||||
type LSA_LAST_INTER_LOGON_INFO struct {
|
||||
LastSuccessfulLogon windows.Filetime
|
||||
LastFailedLogon windows.Filetime
|
||||
FailedAttemptCountSinceLastSuccessfulLogon uint32
|
||||
}
|
||||
|
||||
type SECURITY_LOGON_SESSION_DATA struct {
|
||||
Size uint32
|
||||
LogonId LUID
|
||||
UserName windows.NTUnicodeString
|
||||
LogonDomain windows.NTUnicodeString
|
||||
AuthenticationPackage windows.NTUnicodeString
|
||||
LogonType LogonType
|
||||
Session uint32
|
||||
Sid *windows.SID
|
||||
LogonTime windows.Filetime
|
||||
LogonServer windows.NTUnicodeString
|
||||
DnsDomainName windows.NTUnicodeString
|
||||
Upn windows.NTUnicodeString
|
||||
UserFlags uint32
|
||||
LastLogonInfo LSA_LAST_INTER_LOGON_INFO
|
||||
LogonScript windows.NTUnicodeString
|
||||
ProfilePath windows.NTUnicodeString
|
||||
HomeDirectory windows.NTUnicodeString
|
||||
HomeDirectoryDrive windows.NTUnicodeString
|
||||
LogoffTime windows.Filetime
|
||||
KickOffTime windows.Filetime
|
||||
PasswordLastSet windows.Filetime
|
||||
PasswordCanChange windows.Filetime
|
||||
PasswordMustChange windows.Filetime
|
||||
}
|
||||
|
||||
const (
|
||||
// LogonTypeSystem Not explicitly defined in LSA, but according to
|
||||
// https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-logonsession,
|
||||
// LogonType=0 is "Used only by the System account."
|
||||
LogonTypeSystem LogonType = iota
|
||||
_ // LogonType=1 is not used
|
||||
LogonTypeInteractive
|
||||
LogonTypeNetwork
|
||||
LogonTypeBatch
|
||||
LogonTypeService
|
||||
LogonTypeProxy
|
||||
LogonTypeUnlock
|
||||
LogonTypeNetworkCleartext
|
||||
LogonTypeNewCredentials
|
||||
LogonTypeRemoteInteractive
|
||||
LogonTypeCachedInteractive
|
||||
LogonTypeCachedRemoteInteractive
|
||||
LogonTypeCachedUnlock
|
||||
)
|
||||
|
||||
func (lt LogonType) String() string {
|
||||
switch lt {
|
||||
case LogonTypeSystem:
|
||||
return "System"
|
||||
case LogonTypeInteractive:
|
||||
return "Interactive"
|
||||
case LogonTypeNetwork:
|
||||
return "Network"
|
||||
case LogonTypeBatch:
|
||||
return "Batch"
|
||||
case LogonTypeService:
|
||||
return "Service"
|
||||
case LogonTypeProxy:
|
||||
return "Proxy"
|
||||
case LogonTypeUnlock:
|
||||
return "Unlock"
|
||||
case LogonTypeNetworkCleartext:
|
||||
return "NetworkCleartext"
|
||||
case LogonTypeNewCredentials:
|
||||
return "NewCredentials"
|
||||
case LogonTypeRemoteInteractive:
|
||||
return "RemoteInteractive"
|
||||
case LogonTypeCachedInteractive:
|
||||
return "CachedInteractive"
|
||||
case LogonTypeCachedRemoteInteractive:
|
||||
return "CachedRemoteInteractive"
|
||||
case LogonTypeCachedUnlock:
|
||||
return "CachedUnlock"
|
||||
default:
|
||||
return fmt.Sprintf("Undefined LogonType(%d)", lt)
|
||||
}
|
||||
}
|
||||
|
||||
type LogonSessionData struct {
|
||||
LogonId LUID
|
||||
UserName string
|
||||
LogonDomain string
|
||||
AuthenticationPackage string
|
||||
LogonType LogonType
|
||||
Session uint32
|
||||
Sid *windows.SID
|
||||
LogonTime time.Time
|
||||
}
|
||||
|
||||
type LUID windows.LUID
|
||||
|
||||
func (l LUID) String() string {
|
||||
return fmt.Sprintf("0x%x:0x%x", l.HighPart, l.LowPart)
|
||||
}
|
||||
Reference in New Issue
Block a user