如何在 Go 中管理 Windows 个用户帐户?
How do I manage Windows User Accounts in Go?
我需要能够从 Go 应用程序管理 Windows 本地用户帐户,似乎不使用 CGo 就没有本机绑定。
我最初的搜索让我看到有人说最好使用 "exec.Command" 到 运行 "net user" 命令,但在解析响应时这似乎很混乱且不可靠代码。
我发现处理这类事情的函数在 netapi32.dll 库中,但是由于 Go 本身不支持 Windows 头文件,调用它似乎并不容易这些功能。
以 https://github.com/golang/sys/tree/master/windows 为例,Go 团队似乎一直在重新定义代码中的所有内容,然后调用 DLL 函数。
我很难将它包装在一起,但我有这个低级别的模板 API 我的目标是,然后在上面包装一个更高级别的 API它,很像核心 Go 运行time 所做的。
type LMSTR ????
type DWORD ????
type LPBYTE ????
type LPDWORD ????
type LPWSTR ????
type NET_API_STATUS DWORD;
type 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
}
type GROUP_USERS_INFO_0 struct {
grui0_name LPWSTR
}
type USER_INFO_1003 struct {
usri1003_password LPWSTR
}
const (
USER_PRIV_GUEST = ????
USER_PRIV_USER = ????
USER_PRIV_ADMIN = ????
UF_SCRIPT = ????
UF_ACCOUNTDISABLE = ????
UF_HOMEDIR_REQUIRED = ????
UF_PASSWD_NOTREQD = ????
UF_PASSWD_CANT_CHANGE = ????
UF_LOCKOUT = ????
UF_DONT_EXPIRE_PASSWD = ????
UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = ????
UF_NOT_DELEGATED = ????
UF_SMARTCARD_REQUIRED = ????
UF_USE_DES_KEY_ONLY = ????
UF_DONT_REQUIRE_PREAUTH = ????
UF_TRUSTED_FOR_DELEGATION = ????
UF_PASSWORD_EXPIRED = ????
UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = ????
UF_NORMAL_ACCOUNT = ????
UF_TEMP_DUPLICATE_ACCOUNT = ????
UF_WORKSTATION_TRUST_ACCOUNT = ????
UF_SERVER_TRUST_ACCOUNT = ????
UF_INTERDOMAIN_TRUST_ACCOUNT = ????
NERR_Success = ????
NERR_InvalidComputer = ????
NERR_NotPrimary = ????
NERR_GroupExists = ????
NERR_UserExists = ????
NERR_PasswordTooShort = ????
NERR_UserNotFound = ????
NERR_BufTooSmall = ????
NERR_InternalError = ????
NERR_GroupNotFound = ????
NERR_BadPassword = ????
NERR_SpeGroupOp = ????
NERR_LastAdmin = ????
ERROR_ACCESS_DENIED = ????
ERROR_INVALID_PASSWORD = ????
ERROR_INVALID_LEVEL = ????
ERROR_MORE_DATA = ????
ERROR_BAD_NETPATH = ????
ERROR_INVALID_NAME = ????
ERROR_NOT_ENOUGH_MEMORY = ????
ERROR_INVALID_PARAMETER = ????
FILTER_TEMP_DUPLICATE_ACCOUNT = ????
FILTER_NORMAL_ACCOUNT = ????
FILTER_INTERDOMAIN_TRUST_ACCOUNT = ????
FILTER_WORKSTATION_TRUST_ACCOUNT = ????
FILTER_SERVER_TRUST_ACCOUNT = ????
)
func NetApiBufferFree(Buffer LPVOID) (NET_API_STATUS);
func NetUserAdd(servername LMSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (NET_API_STATUS);
func NetUserChangePassword(domainname LPCWSTR, username LPCWSTR, oldpassword LPCWSTR, newpassword LPCWSTR) (NET_API_STATUS);
func NetUserDel(servername LPCWSTR, username LPCWSTR) (NET_API_STATUS);
func NetUserEnum(servername LPCWSTR, level DWORD, filter DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD, resume_handle LPDWORD) (NET_API_STATUS);
func NetUserGetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD) (NET_API_STATUS);
func NetUserSetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, num_entries DWORD) (NET_API_STATUS);
func NetUserSetInfo(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (NET_API_STATUS);
最好的包装方式是什么?
使用 Windows DLL 是(在我看来)直接使用 Win32 API.
的最佳方式
如果您查看 Go 安装的 src/syscall
目录,您可以找到一个名为 mksyscall_windows.go 的文件。这似乎是 Go 团队管理所有 DLL 包装器的方式。
使用 go generate
生成您的代码
看看 syscall_windows.go 如何使用它。具体来说,它有以下 go generate
命令:
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go
定义 Win32 API 类型
然后他们定义他们的类型。您需要自己手动执行此操作。
有时这是一个挑战,因为保持结构字段的大小和对齐方式至关重要。我使用 Visual Studio Community Edition 浏览 Microsoft 定义的大量基本类型,以确定它们的 Go 等价物。
Windows 对字符串使用 UTF16。因此,您会将这些表示为 *uint16
。使用 syscall.UTF16PtrFromString
从 Go 字符串生成一个。
注释 Win32 API 要导出的函数
mksyscall_windows.go
的重点是生成所有样板代码,因此您最终会得到一个为您调用 DLL 的 Go 函数。
这是通过添加注释(Go 注释)来完成的。
例如,在 syscall_windows.go
中,您有这些注释:
//sys GetLastError() (lasterr error)
//...
//sys CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardLinkW
mksyscall_windows.go
有文档注释来帮助您弄清楚这是如何工作的。您还可以在 zsyscall_windows.go.
中查看 go 生成的代码
运行 go generate
很简单,就运行:
go generate
示例:
对于您的示例,创建一个名为 win32_windows.go
:
的文件
package win32
//go generate go run mksyscall_windows.go -output zwin32_windows.go win32_windows.go
type (
LPVOID uintptr
LMSTR *uint16
DWORD uint32
LPBYTE *byte
LPDWORD *uint32
LPWSTR *uint16
NET_API_STATUS DWORD
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
}
GROUP_USERS_INFO_0 struct {
Grui0_name LPWSTR
}
USER_INFO_1003 struct {
Usri1003_password LPWSTR
}
)
const (
// from LMaccess.h
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_ACCOUNT_TYPE_MASK = UF_TEMP_DUPLICATE_ACCOUNT |
UF_NORMAL_ACCOUNT |
UF_INTERDOMAIN_TRUST_ACCOUNT |
UF_WORKSTATION_TRUST_ACCOUNT |
UF_SERVER_TRUST_ACCOUNT
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
UF_SETTABLE_BITS = UF_SCRIPT |
UF_ACCOUNTDISABLE |
UF_LOCKOUT |
UF_HOMEDIR_REQUIRED |
UF_PASSWD_NOTREQD |
UF_PASSWD_CANT_CHANGE |
UF_ACCOUNT_TYPE_MASK |
UF_DONT_EXPIRE_PASSWD |
UF_MNS_LOGON_ACCOUNT |
UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED |
UF_SMARTCARD_REQUIRED |
UF_TRUSTED_FOR_DELEGATION |
UF_NOT_DELEGATED |
UF_USE_DES_KEY_ONLY |
UF_DONT_REQUIRE_PREAUTH |
UF_PASSWORD_EXPIRED |
UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION |
UF_NO_AUTH_DATA_REQUIRED |
UF_USE_AES_KEYS |
UF_PARTIAL_SECRETS_ACCOUNT
FILTER_TEMP_DUPLICATE_ACCOUNT = (0x0001)
FILTER_NORMAL_ACCOUNT = (0x0002)
FILTER_INTERDOMAIN_TRUST_ACCOUNT = (0x0008)
FILTER_WORKSTATION_TRUST_ACCOUNT = (0x0010)
FILTER_SERVER_TRUST_ACCOUNT = (0x0020)
LG_INCLUDE_INDIRECT = (0x0001)
// etc...
)
//sys NetApiBufferFree(Buffer LPVOID) (status NET_API_STATUS) = netapi32.NetApiBufferFree
//sys NetUserAdd(servername LMSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (status NET_API_STATUS) = netapi32.NetUserAdd
//sys NetUserChangePassword(domainname LPCWSTR, username LPCWSTR, oldpassword LPCWSTR, newpassword LPCWSTR) (status NET_API_STATUS) = netapi32.NetUserChangePassword
//sys NetUserDel(servername LPCWSTR, username LPCWSTR) (status NET_API_STATUS) = netapi32.NetUserDel
//sys NetUserEnum(servername LPCWSTR, level DWORD, filter DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD, resume_handle LPDWORD) (status NET_API_STATUS) = netapi32.NetUserEnum
//sys NetUserGetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD) (status NET_API_STATUS) = netapi32.NetUserGetGroups
//sys NetUserSetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, num_entries DWORD) (status NET_API_STATUS) = netapi32.NetUserSetGroups
//sys NetUserSetInfo(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (status NET_API_STATUS) = netapi32.NetUserSetInfo
在 运行 宁 go generate
之后(只要你复制 mksyscall_windows.go
到同一个目录)你将有一个名为 "zwin32_windows.go" 的文件(类似这样):
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
package win32
import "unsafe"
import "syscall"
var _ unsafe.Pointer
var (
modnetapi32 = syscall.NewLazyDLL("netapi32.dll")
procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
procNetUserAdd = modnetapi32.NewProc("NetUserAdd")
procNetUserChangePassword = modnetapi32.NewProc("NetUserChangePassword")
procNetUserDel = modnetapi32.NewProc("NetUserDel")
procNetUserEnum = modnetapi32.NewProc("NetUserEnum")
procNetUserGetGroups = modnetapi32.NewProc("NetUserGetGroups")
procNetUserSetGroups = modnetapi32.NewProc("NetUserSetGroups")
procNetUserSetInfo = modnetapi32.NewProc("NetUserSetInfo")
)
func NetApiBufferFree(Buffer LPVOID) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall(procNetApiBufferFree.Addr(), 1, uintptr(Buffer), 0, 0)
status = NET_API_STATUS(r0)
return
}
func NetUserAdd(servername LMSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall6(procNetUserAdd.Addr(), 4, uintptr(servername), uintptr(level), uintptr(buf), uintptr(parm_err), 0, 0)
status = NET_API_STATUS(r0)
return
}
func NetUserChangePassword(domainname LPCWSTR, username LPCWSTR, oldpassword LPCWSTR, newpassword LPCWSTR) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall6(procNetUserChangePassword.Addr(), 4, uintptr(domainname), uintptr(username), uintptr(oldpassword), uintptr(newpassword), 0, 0)
status = NET_API_STATUS(r0)
return
}
func NetUserDel(servername LPCWSTR, username LPCWSTR) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall(procNetUserDel.Addr(), 2, uintptr(servername), uintptr(username), 0)
status = NET_API_STATUS(r0)
return
}
func NetUserEnum(servername LPCWSTR, level DWORD, filter DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD, resume_handle LPDWORD) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall9(procNetUserEnum.Addr(), 8, uintptr(servername), uintptr(level), uintptr(filter), uintptr(unsafe.Pointer(bufptr)), uintptr(prefmaxlen), uintptr(entriesread), uintptr(totalentries), uintptr(resume_handle), 0)
status = NET_API_STATUS(r0)
return
}
func NetUserGetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall9(procNetUserGetGroups.Addr(), 7, uintptr(servername), uintptr(username), uintptr(level), uintptr(unsafe.Pointer(bufptr)), uintptr(prefmaxlen), uintptr(entriesread), uintptr(totalentries), 0, 0)
status = NET_API_STATUS(r0)
return
}
func NetUserSetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, num_entries DWORD) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall6(procNetUserSetGroups.Addr(), 5, uintptr(servername), uintptr(username), uintptr(level), uintptr(buf), uintptr(num_entries), 0)
status = NET_API_STATUS(r0)
return
}
func NetUserSetInfo(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall6(procNetUserSetInfo.Addr(), 5, uintptr(servername), uintptr(username), uintptr(level), uintptr(buf), uintptr(parm_err), 0)
status = NET_API_STATUS(r0)
return
}
显然,大部分工作是将 Win32 类型转换为其 Go 等价物。
随意浏览 syscall
包 - 它们通常已经定义了您可能感兴趣的结构。
ZOMG 认真的??1! 2 辛苦了!
这比手写代码要好。而且不需要 CGo!
免责声明: 我还没有测试上面的代码来验证它是否真的做了你想要的。使用 Win32 API 本身就是一种乐趣。
我需要能够从 Go 应用程序管理 Windows 本地用户帐户,似乎不使用 CGo 就没有本机绑定。
我最初的搜索让我看到有人说最好使用 "exec.Command" 到 运行 "net user" 命令,但在解析响应时这似乎很混乱且不可靠代码。
我发现处理这类事情的函数在 netapi32.dll 库中,但是由于 Go 本身不支持 Windows 头文件,调用它似乎并不容易这些功能。
以 https://github.com/golang/sys/tree/master/windows 为例,Go 团队似乎一直在重新定义代码中的所有内容,然后调用 DLL 函数。
我很难将它包装在一起,但我有这个低级别的模板 API 我的目标是,然后在上面包装一个更高级别的 API它,很像核心 Go 运行time 所做的。
type LMSTR ????
type DWORD ????
type LPBYTE ????
type LPDWORD ????
type LPWSTR ????
type NET_API_STATUS DWORD;
type 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
}
type GROUP_USERS_INFO_0 struct {
grui0_name LPWSTR
}
type USER_INFO_1003 struct {
usri1003_password LPWSTR
}
const (
USER_PRIV_GUEST = ????
USER_PRIV_USER = ????
USER_PRIV_ADMIN = ????
UF_SCRIPT = ????
UF_ACCOUNTDISABLE = ????
UF_HOMEDIR_REQUIRED = ????
UF_PASSWD_NOTREQD = ????
UF_PASSWD_CANT_CHANGE = ????
UF_LOCKOUT = ????
UF_DONT_EXPIRE_PASSWD = ????
UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = ????
UF_NOT_DELEGATED = ????
UF_SMARTCARD_REQUIRED = ????
UF_USE_DES_KEY_ONLY = ????
UF_DONT_REQUIRE_PREAUTH = ????
UF_TRUSTED_FOR_DELEGATION = ????
UF_PASSWORD_EXPIRED = ????
UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = ????
UF_NORMAL_ACCOUNT = ????
UF_TEMP_DUPLICATE_ACCOUNT = ????
UF_WORKSTATION_TRUST_ACCOUNT = ????
UF_SERVER_TRUST_ACCOUNT = ????
UF_INTERDOMAIN_TRUST_ACCOUNT = ????
NERR_Success = ????
NERR_InvalidComputer = ????
NERR_NotPrimary = ????
NERR_GroupExists = ????
NERR_UserExists = ????
NERR_PasswordTooShort = ????
NERR_UserNotFound = ????
NERR_BufTooSmall = ????
NERR_InternalError = ????
NERR_GroupNotFound = ????
NERR_BadPassword = ????
NERR_SpeGroupOp = ????
NERR_LastAdmin = ????
ERROR_ACCESS_DENIED = ????
ERROR_INVALID_PASSWORD = ????
ERROR_INVALID_LEVEL = ????
ERROR_MORE_DATA = ????
ERROR_BAD_NETPATH = ????
ERROR_INVALID_NAME = ????
ERROR_NOT_ENOUGH_MEMORY = ????
ERROR_INVALID_PARAMETER = ????
FILTER_TEMP_DUPLICATE_ACCOUNT = ????
FILTER_NORMAL_ACCOUNT = ????
FILTER_INTERDOMAIN_TRUST_ACCOUNT = ????
FILTER_WORKSTATION_TRUST_ACCOUNT = ????
FILTER_SERVER_TRUST_ACCOUNT = ????
)
func NetApiBufferFree(Buffer LPVOID) (NET_API_STATUS);
func NetUserAdd(servername LMSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (NET_API_STATUS);
func NetUserChangePassword(domainname LPCWSTR, username LPCWSTR, oldpassword LPCWSTR, newpassword LPCWSTR) (NET_API_STATUS);
func NetUserDel(servername LPCWSTR, username LPCWSTR) (NET_API_STATUS);
func NetUserEnum(servername LPCWSTR, level DWORD, filter DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD, resume_handle LPDWORD) (NET_API_STATUS);
func NetUserGetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD) (NET_API_STATUS);
func NetUserSetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, num_entries DWORD) (NET_API_STATUS);
func NetUserSetInfo(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (NET_API_STATUS);
最好的包装方式是什么?
使用 Windows DLL 是(在我看来)直接使用 Win32 API.
的最佳方式如果您查看 Go 安装的 src/syscall
目录,您可以找到一个名为 mksyscall_windows.go 的文件。这似乎是 Go 团队管理所有 DLL 包装器的方式。
使用 go generate
生成您的代码
看看 syscall_windows.go 如何使用它。具体来说,它有以下 go generate
命令:
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go
定义 Win32 API 类型
然后他们定义他们的类型。您需要自己手动执行此操作。
有时这是一个挑战,因为保持结构字段的大小和对齐方式至关重要。我使用 Visual Studio Community Edition 浏览 Microsoft 定义的大量基本类型,以确定它们的 Go 等价物。
Windows 对字符串使用 UTF16。因此,您会将这些表示为 *uint16
。使用 syscall.UTF16PtrFromString
从 Go 字符串生成一个。
注释 Win32 API 要导出的函数
mksyscall_windows.go
的重点是生成所有样板代码,因此您最终会得到一个为您调用 DLL 的 Go 函数。
这是通过添加注释(Go 注释)来完成的。
例如,在 syscall_windows.go
中,您有这些注释:
//sys GetLastError() (lasterr error)
//...
//sys CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardLinkW
mksyscall_windows.go
有文档注释来帮助您弄清楚这是如何工作的。您还可以在 zsyscall_windows.go.
运行 go generate
很简单,就运行:
go generate
示例:
对于您的示例,创建一个名为 win32_windows.go
:
package win32
//go generate go run mksyscall_windows.go -output zwin32_windows.go win32_windows.go
type (
LPVOID uintptr
LMSTR *uint16
DWORD uint32
LPBYTE *byte
LPDWORD *uint32
LPWSTR *uint16
NET_API_STATUS DWORD
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
}
GROUP_USERS_INFO_0 struct {
Grui0_name LPWSTR
}
USER_INFO_1003 struct {
Usri1003_password LPWSTR
}
)
const (
// from LMaccess.h
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_ACCOUNT_TYPE_MASK = UF_TEMP_DUPLICATE_ACCOUNT |
UF_NORMAL_ACCOUNT |
UF_INTERDOMAIN_TRUST_ACCOUNT |
UF_WORKSTATION_TRUST_ACCOUNT |
UF_SERVER_TRUST_ACCOUNT
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
UF_SETTABLE_BITS = UF_SCRIPT |
UF_ACCOUNTDISABLE |
UF_LOCKOUT |
UF_HOMEDIR_REQUIRED |
UF_PASSWD_NOTREQD |
UF_PASSWD_CANT_CHANGE |
UF_ACCOUNT_TYPE_MASK |
UF_DONT_EXPIRE_PASSWD |
UF_MNS_LOGON_ACCOUNT |
UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED |
UF_SMARTCARD_REQUIRED |
UF_TRUSTED_FOR_DELEGATION |
UF_NOT_DELEGATED |
UF_USE_DES_KEY_ONLY |
UF_DONT_REQUIRE_PREAUTH |
UF_PASSWORD_EXPIRED |
UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION |
UF_NO_AUTH_DATA_REQUIRED |
UF_USE_AES_KEYS |
UF_PARTIAL_SECRETS_ACCOUNT
FILTER_TEMP_DUPLICATE_ACCOUNT = (0x0001)
FILTER_NORMAL_ACCOUNT = (0x0002)
FILTER_INTERDOMAIN_TRUST_ACCOUNT = (0x0008)
FILTER_WORKSTATION_TRUST_ACCOUNT = (0x0010)
FILTER_SERVER_TRUST_ACCOUNT = (0x0020)
LG_INCLUDE_INDIRECT = (0x0001)
// etc...
)
//sys NetApiBufferFree(Buffer LPVOID) (status NET_API_STATUS) = netapi32.NetApiBufferFree
//sys NetUserAdd(servername LMSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (status NET_API_STATUS) = netapi32.NetUserAdd
//sys NetUserChangePassword(domainname LPCWSTR, username LPCWSTR, oldpassword LPCWSTR, newpassword LPCWSTR) (status NET_API_STATUS) = netapi32.NetUserChangePassword
//sys NetUserDel(servername LPCWSTR, username LPCWSTR) (status NET_API_STATUS) = netapi32.NetUserDel
//sys NetUserEnum(servername LPCWSTR, level DWORD, filter DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD, resume_handle LPDWORD) (status NET_API_STATUS) = netapi32.NetUserEnum
//sys NetUserGetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD) (status NET_API_STATUS) = netapi32.NetUserGetGroups
//sys NetUserSetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, num_entries DWORD) (status NET_API_STATUS) = netapi32.NetUserSetGroups
//sys NetUserSetInfo(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (status NET_API_STATUS) = netapi32.NetUserSetInfo
在 运行 宁 go generate
之后(只要你复制 mksyscall_windows.go
到同一个目录)你将有一个名为 "zwin32_windows.go" 的文件(类似这样):
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
package win32
import "unsafe"
import "syscall"
var _ unsafe.Pointer
var (
modnetapi32 = syscall.NewLazyDLL("netapi32.dll")
procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
procNetUserAdd = modnetapi32.NewProc("NetUserAdd")
procNetUserChangePassword = modnetapi32.NewProc("NetUserChangePassword")
procNetUserDel = modnetapi32.NewProc("NetUserDel")
procNetUserEnum = modnetapi32.NewProc("NetUserEnum")
procNetUserGetGroups = modnetapi32.NewProc("NetUserGetGroups")
procNetUserSetGroups = modnetapi32.NewProc("NetUserSetGroups")
procNetUserSetInfo = modnetapi32.NewProc("NetUserSetInfo")
)
func NetApiBufferFree(Buffer LPVOID) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall(procNetApiBufferFree.Addr(), 1, uintptr(Buffer), 0, 0)
status = NET_API_STATUS(r0)
return
}
func NetUserAdd(servername LMSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall6(procNetUserAdd.Addr(), 4, uintptr(servername), uintptr(level), uintptr(buf), uintptr(parm_err), 0, 0)
status = NET_API_STATUS(r0)
return
}
func NetUserChangePassword(domainname LPCWSTR, username LPCWSTR, oldpassword LPCWSTR, newpassword LPCWSTR) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall6(procNetUserChangePassword.Addr(), 4, uintptr(domainname), uintptr(username), uintptr(oldpassword), uintptr(newpassword), 0, 0)
status = NET_API_STATUS(r0)
return
}
func NetUserDel(servername LPCWSTR, username LPCWSTR) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall(procNetUserDel.Addr(), 2, uintptr(servername), uintptr(username), 0)
status = NET_API_STATUS(r0)
return
}
func NetUserEnum(servername LPCWSTR, level DWORD, filter DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD, resume_handle LPDWORD) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall9(procNetUserEnum.Addr(), 8, uintptr(servername), uintptr(level), uintptr(filter), uintptr(unsafe.Pointer(bufptr)), uintptr(prefmaxlen), uintptr(entriesread), uintptr(totalentries), uintptr(resume_handle), 0)
status = NET_API_STATUS(r0)
return
}
func NetUserGetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall9(procNetUserGetGroups.Addr(), 7, uintptr(servername), uintptr(username), uintptr(level), uintptr(unsafe.Pointer(bufptr)), uintptr(prefmaxlen), uintptr(entriesread), uintptr(totalentries), 0, 0)
status = NET_API_STATUS(r0)
return
}
func NetUserSetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, num_entries DWORD) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall6(procNetUserSetGroups.Addr(), 5, uintptr(servername), uintptr(username), uintptr(level), uintptr(buf), uintptr(num_entries), 0)
status = NET_API_STATUS(r0)
return
}
func NetUserSetInfo(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (status NET_API_STATUS) {
r0, _, _ := syscall.Syscall6(procNetUserSetInfo.Addr(), 5, uintptr(servername), uintptr(username), uintptr(level), uintptr(buf), uintptr(parm_err), 0)
status = NET_API_STATUS(r0)
return
}
显然,大部分工作是将 Win32 类型转换为其 Go 等价物。
随意浏览 syscall
包 - 它们通常已经定义了您可能感兴趣的结构。
ZOMG 认真的??1! 2 辛苦了!
这比手写代码要好。而且不需要 CGo!
免责声明: 我还没有测试上面的代码来验证它是否真的做了你想要的。使用 Win32 API 本身就是一种乐趣。