github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/osext/winsvc/svc/security.go (about)

     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  package svc
     6  
     7  import (
     8  	"chai2010.gopkg/osext/winsvc/winapi"
     9  	"syscall"
    10  	"unsafe"
    11  )
    12  
    13  // TODO(brainman): move some of that code to syscall/security.go
    14  
    15  // getInfo retrieves a specified type of information about an access token.
    16  func getInfo(t syscall.Token, class uint32, initSize int) (unsafe.Pointer, error) {
    17  	b := make([]byte, initSize)
    18  	var n uint32
    19  	e := syscall.GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
    20  	if e != nil {
    21  		if e != syscall.ERROR_INSUFFICIENT_BUFFER {
    22  			return nil, e
    23  		}
    24  		// make receive buffers of requested size and try again
    25  		b = make([]byte, n)
    26  		e = syscall.GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
    27  		if e != nil {
    28  			return nil, e
    29  		}
    30  	}
    31  	return unsafe.Pointer(&b[0]), nil
    32  }
    33  
    34  // getTokenUser retrieves access token t user account information.
    35  func getTokenGroups(t syscall.Token) (*winapi.Tokengroups, error) {
    36  	i, e := getInfo(t, syscall.TokenGroups, 50)
    37  	if e != nil {
    38  		return nil, e
    39  	}
    40  	return (*winapi.Tokengroups)(i), nil
    41  }
    42  
    43  func allocSid(subAuth0 uint32) (*syscall.SID, error) {
    44  	var sid *syscall.SID
    45  	err := winapi.AllocateAndInitializeSid(&winapi.SECURITY_NT_AUTHORITY,
    46  		1, subAuth0, 0, 0, 0, 0, 0, 0, 0, &sid)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	return sid, nil
    51  }
    52  
    53  // IsAnInteractiveSession determines if calling process is running interactively.
    54  // It queries the process token for membership in the Interactive group.
    55  // http://stackoverflow.com/questions/2668851/how-do-i-detect-that-my-application-is-running-as-service-or-in-an-interactive-s
    56  func IsAnInteractiveSession() (bool, error) {
    57  	interSid, err := allocSid(winapi.SECURITY_INTERACTIVE_RID)
    58  	if err != nil {
    59  		return false, err
    60  	}
    61  	defer winapi.FreeSid(interSid)
    62  
    63  	serviceSid, err := allocSid(winapi.SECURITY_SERVICE_RID)
    64  	if err != nil {
    65  		return false, err
    66  	}
    67  	defer winapi.FreeSid(serviceSid)
    68  
    69  	t, err := syscall.OpenCurrentProcessToken()
    70  	if err != nil {
    71  		return false, err
    72  	}
    73  	defer t.Close()
    74  
    75  	gs, err := getTokenGroups(t)
    76  	if err != nil {
    77  		return false, err
    78  	}
    79  	p := unsafe.Pointer(&gs.Groups[0])
    80  	groups := (*[256]syscall.SIDAndAttributes)(p)[:gs.GroupCount]
    81  	for _, g := range groups {
    82  		if winapi.EqualSid(g.Sid, interSid) {
    83  			return true, nil
    84  		}
    85  		if winapi.EqualSid(g.Sid, serviceSid) {
    86  			return false, nil
    87  		}
    88  	}
    89  	return false, nil
    90  }
    91  
    92  // IsAnIinteractiveSession is a misspelled version of IsAnInteractiveSession.
    93  // Do not use. It is kept here so we do not break existing code.
    94  func IsAnIinteractiveSession() (bool, error) {
    95  	return IsAnInteractiveSession()
    96  }