agent/util/process/process_windows.go (130 lines of code) (raw):
package process
import (
"errors"
"fmt"
"os"
"syscall"
"unsafe"
"github.com/aliyun/aliyun_assist_client/agent/cryptdata"
"github.com/aliyun/aliyun_assist_client/agent/log"
"github.com/aliyun/aliyun_assist_client/agent/util/paramstore"
"golang.org/x/sys/windows"
)
var (
advapi32 = syscall.NewLazyDLL("advapi32.dll")
logonProc = advapi32.NewProc("LogonUserW")
impersonateProc = advapi32.NewProc("ImpersonateLoggedOnUser")
revertSelfProc = advapi32.NewProc("RevertToSelf")
)
const (
//logon32LogonNetwork = uintptr(3)
logon32LOGONINTERACTIVE = uintptr(2)
logon32ProviderDefault = uintptr(0)
)
func (p *ProcessCmd) prepareProcess() error {
// if p.command.SysProcAttr == nil {
// p.command.SysProcAttr = &windows.SysProcAttr{}
// }
// 1. Duplicate current environment variable settings as base
var env []string
if p.command.Env == nil || len(p.command.Env) == 0 {
env = os.Environ()
} else {
// append specific envs to osEnv, the value of repetitive key will be covered
env = os.Environ()
for i := 0; i < len(p.command.Env); i++ {
env = append(env, p.command.Env[i])
}
}
p.command.Env = env
for _, opt := range p.commandOptions {
if err := opt(p.command); err != nil {
return err
}
}
return nil
}
func (p *ProcessCmd) addCredential() error {
log.GetLogger().Infoln("addCredential")
vm_password, err := getSecretParam(p.password)
if err != nil {
log.GetLogger().Errorln("get password failed", err)
return err
}
token, err := logonUser(p.user_name, vm_password)
if err != nil {
return err
}
p.command.SysProcAttr = &windows.SysProcAttr{
Token: syscall.Token(token),
}
return nil
}
func (p *ProcessCmd) removeCredential() error {
p.command.SysProcAttr.Token.Close()
return nil
}
func impersonate(user string, pass string) error {
token, err := logonUser(user, pass)
if err != nil {
return err
}
defer mustCloseHandle(token)
if rc, _, ec := syscall.Syscall(impersonateProc.Addr(), 1, uintptr(token), 0, 0); rc == 0 {
return error(ec)
}
return nil
}
func IsUserValid (userName string, password string) error {
vm_password, err := getSecretParam(password)
if err != nil {
return err
}
token, err := logonUser(userName, vm_password)
if err != nil {
log.GetLogger().WithError(err).Errorf("Authentication failed for user %s with password", userName)
return errors.New("UsernameOrPasswordInvalid")
}
defer mustCloseHandle(token)
return nil
}
func logonUser(user, pass string) (token syscall.Handle, err error) {
// ".\0" meaning "this computer:
domain := [2]uint16{uint16('.'), 0}
//domain,_ := syscall.UTF16FromString("")
var pu, pp []uint16
if pu, err = syscall.UTF16FromString(user); err != nil {
return
}
if pp, err = syscall.UTF16FromString(pass); err != nil {
return
}
if rc, _, ec := syscall.Syscall6(logonProc.Addr(), 6,
uintptr(unsafe.Pointer(&pu[0])),
uintptr(unsafe.Pointer(&domain[0])),
uintptr(unsafe.Pointer(&pp[0])),
logon32LOGONINTERACTIVE,
logon32ProviderDefault,
uintptr(unsafe.Pointer(&token))); rc == 0 {
err = error(ec)
}
return
}
func mustCloseHandle(handle syscall.Handle) {
if err := syscall.CloseHandle(handle); err != nil {
log.GetLogger().Errorln(err)
}
}
//revertToSelf reverts the impersonation process.
func revertToSelf() error {
if rc, _, ec := syscall.Syscall(revertSelfProc.Addr(), 0, 0, 0, 0); rc == 0 {
return error(ec)
}
return nil
}
func getSecretParam(secretName string) (string, error) {
var value string
var paramValueInfo *cryptdata.ParamValueInfo
var err_1, err_2 error
if paramValueInfo, err_1 = cryptdata.GetSecretParamValue(secretName); err_1 != nil {
if value, err_2 = paramstore.GetSecretParam(secretName); err_2 != nil {
log.GetLogger().Errorf("Secret param '%s' not found in agent [%v] and oos[%v]", secretName, err_1, err_2)
err := errors.New(fmt.Sprintf("Secret param '%s' not found in agent [%v] and oos[%v]", secretName, err_1, err_2))
return "", err
}
} else {
value = paramValueInfo.SecretValue
}
return value, nil
}