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:
Jan-Otto Kröpke
2026-10-08 14:48:43 +02:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 3485634c49
commit 1fc968a06d
5 changed files with 0 additions and 524 deletions
-132
View File
@@ -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()
}
-137
View File
@@ -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()),
}
}
-33
View File
@@ -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)
}
-129
View File
@@ -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)
}