189 lines
6.3 KiB
Go
189 lines
6.3 KiB
Go
//go:build windows
|
||
|
||
package remote
|
||
|
||
import (
|
||
"fmt"
|
||
"os"
|
||
|
||
"github.com/KarpelesLab/vncpasswd"
|
||
"github.com/kardianos/service"
|
||
"golang.org/x/sys/windows/registry"
|
||
)
|
||
|
||
var VncService service.Service
|
||
|
||
// ReadVncServerConfig 从注册表读取 TightVNC 服务端配置(键值缺失按零值返回)
|
||
func ReadVncServerConfig() (VncServerConfig, error) {
|
||
var config VncServerConfig
|
||
|
||
key, err := registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\TightVNC\\Server", registry.ALL_ACCESS)
|
||
if err != nil {
|
||
return config, err
|
||
}
|
||
defer key.Close()
|
||
|
||
config.ExtraPorts, _, _ = key.GetStringValue("ExtraPorts")
|
||
config.QueryTimeout, _, _ = GetDwordValue(key, "QueryTimeout")
|
||
config.QueryAcceptOnTimeout, _, _ = GetDwordValue(key, "QueryAcceptOnTimeout")
|
||
config.LocalInputPriorityTimeout, _, _ = GetDwordValue(key, "LocalInputPriorityTimeout")
|
||
config.LocalInputPriority, _, _ = GetDwordValue(key, "LocalInputPriority")
|
||
config.BlockRemoteInput, _, _ = GetDwordValue(key, "BlockRemoteInput")
|
||
config.BlockLocalInput, _, _ = GetDwordValue(key, "BlockLocalInput")
|
||
config.IpAccessControl, _, _ = key.GetStringValue("IpAccessControl")
|
||
config.RfbPort, _, _ = GetDwordValue(key, "RfbPort")
|
||
config.HttpPort, _, _ = GetDwordValue(key, "HttpPort")
|
||
config.DisconnectAction, _, _ = GetDwordValue(key, "DisconnectAction")
|
||
config.AcceptRfbConnections, _, _ = GetDwordValue(key, "AcceptRfbConnections")
|
||
config.UseVncAuthentication, _, _ = GetDwordValue(key, "UseVncAuthentication")
|
||
config.UseControlAuthentication, _, _ = GetDwordValue(key, "UseControlAuthentication")
|
||
config.RepeatControlAuthentication, _, _ = GetDwordValue(key, "RepeatControlAuthentication")
|
||
config.LoopbackOnly, _, _ = GetDwordValue(key, "LoopbackOnly")
|
||
config.AcceptHttpConnections, _, _ = GetDwordValue(key, "AcceptHttpConnections")
|
||
config.LogLevel, _, _ = GetDwordValue(key, "LogLevel")
|
||
config.EnableFileTransfers, _, _ = GetDwordValue(key, "EnableFileTransfers")
|
||
config.RemoveWallpaper, _, _ = GetDwordValue(key, "RemoveWallpaper")
|
||
config.UseD3D, _, _ = GetDwordValue(key, "UseD3D")
|
||
config.UseMirrorDriver, _, _ = GetDwordValue(key, "UseMirrorDriver")
|
||
config.EnableUrlParams, _, _ = GetDwordValue(key, "EnableUrlParams")
|
||
config.Password, _, _ = key.GetBinaryValue("Password")
|
||
config.AlwaysShared, _, _ = GetDwordValue(key, "AlwaysShared")
|
||
config.NeverShared, _, _ = GetDwordValue(key, "NeverShared")
|
||
config.DisconnectClients, _, _ = GetDwordValue(key, "DisconnectClients")
|
||
config.PollingInterval, _, _ = GetDwordValue(key, "PollingInterval")
|
||
config.AllowLoopback, _, _ = GetDwordValue(key, "AllowLoopback")
|
||
config.VideoRecognitionInterval, _, _ = GetDwordValue(key, "VideoRecognitionInterval")
|
||
config.GrabTransparentWindows, _, _ = GetDwordValue(key, "GrabTransparentWindows")
|
||
config.SaveLogToAllUsersPath, _, _ = GetDwordValue(key, "SaveLogToAllUsersPath")
|
||
config.RunControlInterface, _, _ = GetDwordValue(key, "RunControlInterface")
|
||
config.IdleTimeout, _, _ = GetDwordValue(key, "IdleTimeout")
|
||
config.VideoClasses, _, _ = key.GetStringValue("VideoClasses")
|
||
config.VideoRects, _, _ = key.GetStringValue("VideoRects")
|
||
config.ConnectToRdp, _, _ = GetDwordValue(key, "ConnectToRdp")
|
||
|
||
return config, nil
|
||
}
|
||
|
||
// GetDwordValue 读取 REG_DWORD 类型注册表值
|
||
func GetDwordValue(k registry.Key, name string) (val uint32, valtype uint32, err error) {
|
||
val64 := uint64(0)
|
||
val64, valtype, err = k.GetIntegerValue(name)
|
||
val = uint32(val64)
|
||
return
|
||
}
|
||
|
||
var vncSvcConfig = &service.Config{
|
||
Name: "tvnserver",
|
||
DisplayName: "TightVNC Server",
|
||
Description: "TightVNC Server (managed by remote-core)",
|
||
Arguments: []string{"-service"},
|
||
}
|
||
|
||
// InstallVncServer 绿色安装 TightVNC 服务端(需管理员权限)。
|
||
// 最新版注册表全集配置(VncClientDefaultConfig 37 项, 随机 8 位密码)→ 注册系统服务。
|
||
// 装而不启:服务注册后保持 Stopped, 等远程指令再 VncStart(避免常驻监听开端口);
|
||
// 若服务已在运行则重启以加载新配置。返回生成的明文密码(调用方自行上报/展示)。
|
||
func InstallVncServer(exePath string) (string, error) {
|
||
if finfo, err := os.Stat(exePath); err != nil || finfo.IsDir() {
|
||
return "", fmt.Errorf("tvnserver.exe 不存在: %s", exePath)
|
||
}
|
||
|
||
// 最新版 TightVNC 注册表配置全集(含随机密码)
|
||
config := VncClientDefaultConfig(true)
|
||
if err := WriteVncServerConfig(config); err != nil {
|
||
return "", err
|
||
}
|
||
|
||
// 注册系统服务:未安装→安装; 运行中→重启加载新配置; 已停止→保持
|
||
vncSvcConfig.Executable = exePath
|
||
if err := VncInit(); err != nil {
|
||
return "", err
|
||
}
|
||
status, err := VncService.Status()
|
||
switch {
|
||
case err != nil: // 未安装(kardianos 对未安装服务 Status 返回错误)
|
||
if err := VncInstall(); err != nil {
|
||
return "", err
|
||
}
|
||
case status == service.StatusRunning:
|
||
if err := VncRestart(); err != nil {
|
||
return "", err
|
||
}
|
||
}
|
||
return VncPasswordDecrypt(config.Password), nil
|
||
}
|
||
|
||
// VncInit 初始化 VNC 服务对象,VncInstall/VncStart 等操作前必须调用
|
||
func VncInit() error {
|
||
var err error
|
||
VncService, err = service.New(nil, vncSvcConfig)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// VncInstall 安装 TightVNC 服务
|
||
func VncInstall() error {
|
||
err := VncService.Install()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// VncUninstall 停止并卸载 TightVNC 服务
|
||
func VncUninstall() error {
|
||
_ = VncService.Stop()
|
||
err := VncService.Uninstall()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// VncStart 启动 TightVNC 服务
|
||
func VncStart() error {
|
||
err := VncService.Start()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// VncStop 停止 TightVNC 服务
|
||
func VncStop() error {
|
||
err := VncService.Stop()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// VncRestart 重启 TightVNC 服务
|
||
func VncRestart() error {
|
||
err := VncService.Stop()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
err = VncService.Start()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// VncPasswordCrypt 加密 VNC 密码(TightVNC 注册表存储格式)
|
||
func VncPasswordCrypt(password string) []byte {
|
||
return vncpasswd.Crypt(password)
|
||
}
|
||
|
||
// VncPasswordDecrypt 解密 VNC 密码。密文恒为 8 字节(标准 VNC DES),
|
||
// 不足 8 字节(缺失/截断)直接返回空串——底层 DES 解密会按前 8 字节切片,短输入必 panic。
|
||
func VncPasswordDecrypt(data []byte) string {
|
||
if len(data) < 8 {
|
||
return ""
|
||
}
|
||
return vncpasswd.Decrypt(data)
|
||
}
|