1// Copyright 2012 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build windows
6
7package svc
8
9import (
10	"unsafe"
11
12	"golang.org/x/sys/windows"
13)
14
15func allocSid(subAuth0 uint32) (*windows.SID, error) {
16	var sid *windows.SID
17	err := windows.AllocateAndInitializeSid(&windows.SECURITY_NT_AUTHORITY,
18		1, subAuth0, 0, 0, 0, 0, 0, 0, 0, &sid)
19	if err != nil {
20		return nil, err
21	}
22	return sid, nil
23}
24
25// IsAnInteractiveSession determines if calling process is running interactively.
26// It queries the process token for membership in the Interactive group.
27// http://stackoverflow.com/questions/2668851/how-do-i-detect-that-my-application-is-running-as-service-or-in-an-interactive-s
28func IsAnInteractiveSession() (bool, error) {
29	interSid, err := allocSid(windows.SECURITY_INTERACTIVE_RID)
30	if err != nil {
31		return false, err
32	}
33	defer windows.FreeSid(interSid)
34
35	serviceSid, err := allocSid(windows.SECURITY_SERVICE_RID)
36	if err != nil {
37		return false, err
38	}
39	defer windows.FreeSid(serviceSid)
40
41	t, err := windows.OpenCurrentProcessToken()
42	if err != nil {
43		return false, err
44	}
45	defer t.Close()
46
47	gs, err := t.GetTokenGroups()
48	if err != nil {
49		return false, err
50	}
51	p := unsafe.Pointer(&gs.Groups[0])
52	groups := (*[2 << 20]windows.SIDAndAttributes)(p)[:gs.GroupCount]
53	for _, g := range groups {
54		if windows.EqualSid(g.Sid, interSid) {
55			return true, nil
56		}
57		if windows.EqualSid(g.Sid, serviceSid) {
58			return false, nil
59		}
60	}
61	return false, nil
62}
63