google_guest_agent/accounts_windows.go (152 lines of code) (raw):

// Copyright 2017 Google LLC // 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 // https://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. package main import ( "context" "fmt" "syscall" "unsafe" "golang.org/x/sys/windows" ) var ( netAPI32 = windows.NewLazySystemDLL("netapi32.dll") procNetUserAdd = netAPI32.NewProc("NetUserAdd") procNetUserGetInfo = netAPI32.NewProc("NetUserGetInfo") procNetUserSetInfo = netAPI32.NewProc("NetUserSetInfo") procNetLocalGroupAddMembers = netAPI32.NewProc("NetLocalGroupAddMembers") ) type ( USER_INFO_0 struct { Usri0_name LPWSTR } USER_INFO_1 struct { Usri1_name LPWSTR Usri1_password LPWSTR Usri1_password_age DWORD Usri1_priv DWORD Usri1_home_dir LPWSTR Usri1_comment LPWSTR Usri1_flags DWORD Usri1_script_path LPWSTR } LOCALGROUP_MEMBERS_INFO_0 struct { Lgrmi0_sid *syscall.SID } USER_INFO_1003 struct { Usri1003_password LPWSTR } ) const ( USER_PRIV_GUEST = 0 USER_PRIV_USER = 1 USER_PRIV_ADMIN = 2 UF_SCRIPT = 0x0001 UF_ACCOUNTDISABLE = 0x0002 UF_HOMEDIR_REQUIRED = 0x0008 UF_LOCKOUT = 0x0010 UF_PASSWD_NOTREQD = 0x0020 UF_PASSWD_CANT_CHANGE = 0x0040 UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0x0080 UF_TEMP_DUPLICATE_ACCOUNT = 0x0100 UF_NORMAL_ACCOUNT = 0x0200 UF_INTERDOMAIN_TRUST_ACCOUNT = 0x0800 UF_WORKSTATION_TRUST_ACCOUNT = 0x1000 UF_SERVER_TRUST_ACCOUNT = 0x2000 UF_DONT_EXPIRE_PASSWD = 0x10000 UF_MNS_LOGON_ACCOUNT = 0x20000 UF_SMARTCARD_REQUIRED = 0x40000 UF_TRUSTED_FOR_DELEGATION = 0x80000 UF_NOT_DELEGATED = 0x100000 UF_USE_DES_KEY_ONLY = 0x200000 UF_DONT_REQUIRE_PREAUTH = 0x400000 UF_PASSWORD_EXPIRED = 0x800000 UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x1000000 UF_NO_AUTH_DATA_REQUIRED = 0x2000000 UF_PARTIAL_SECRETS_ACCOUNT = 0x4000000 UF_USE_AES_KEYS = 0x8000000 ) func resetPwd(username, pwd string) error { uPtr, err := syscall.UTF16PtrFromString(username) if err != nil { return fmt.Errorf("error encoding username to UTF16: %v", err) } pPtr, err := syscall.UTF16PtrFromString(pwd) if err != nil { return fmt.Errorf("error encoding password to UTF16: %v", err) } ret, _, _ := procNetUserSetInfo.Call( uintptr(0), uintptr(unsafe.Pointer(uPtr)), uintptr(1003), uintptr(unsafe.Pointer(&USER_INFO_1003{pPtr})), uintptr(0)) if ret != 0 { return fmt.Errorf("nonzero return code from NetUserSetInfo: %s", syscall.Errno(ret)) } return nil } func addUserToGroup(_ context.Context, username, group string) error { gPtr, err := syscall.UTF16PtrFromString(group) if err != nil { return fmt.Errorf("error encoding group to UTF16: %v", err) } sid, _, _, err := syscall.LookupSID("", username) if err != nil { return err } sArray := []LOCALGROUP_MEMBERS_INFO_0{{sid}} ret, _, _ := procNetLocalGroupAddMembers.Call( uintptr(0), uintptr(unsafe.Pointer(gPtr)), uintptr(0), uintptr(unsafe.Pointer(&sArray[0])), uintptr(1), ) // Ignore ERROR_MEMBER_IN_ALIAS (1378). if ret != 0 && ret != 1378 { return fmt.Errorf("nonzero return code from NetLocalGroupAddMembers: %s", syscall.Errno(ret)) } return nil } func createUser(_ context.Context, username, pwd, _ string) error { uPtr, err := syscall.UTF16PtrFromString(username) if err != nil { return fmt.Errorf("error encoding username to UTF16: %v", err) } pPtr, err := syscall.UTF16PtrFromString(pwd) if err != nil { return fmt.Errorf("error encoding password to UTF16: %v", err) } uInfo1 := USER_INFO_1{ Usri1_name: uPtr, Usri1_password: pPtr, Usri1_priv: USER_PRIV_USER, Usri1_flags: UF_SCRIPT | UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD, } ret, _, _ := procNetUserAdd.Call( uintptr(0), uintptr(1), uintptr(unsafe.Pointer(&uInfo1)), uintptr(0), ) // If Error 2236 = The user already belongs to this group. // No action is required, see: // https://learn.microsoft.com/en-us/troubleshoot/windows-server/remote/terminal-server-error-messages-2200-to-2299#error-2236 if ret != 0 && ret != 2236 { return fmt.Errorf("nonzero return code from NetUserAdd: %s", syscall.Errno(ret)) } return nil } func userExists(name string) (bool, error) { uPtr, err := syscall.UTF16PtrFromString(name) if err != nil { return false, fmt.Errorf("error encoding username to UTF16: %v", err) } ret, _, _ := procNetUserGetInfo.Call( uintptr(0), uintptr(unsafe.Pointer(uPtr)), uintptr(1), uintptr(unsafe.Pointer(&USER_INFO_0{})), ) if ret != 0 { return false, fmt.Errorf("nonzero return code from NetUserGetInfo: %s", syscall.Errno(ret)) } return true, nil } func getUIDAndGID(_ string) (string, string) { return "", "" }