/* SPDX-License-Identifier: MIT * * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. */packagemainimport("fmt""log""os""strconv""strings""time""golang.org/x/sys/windows""golang.zx2c4.com/wireguard/windows/elevate""golang.zx2c4.com/wireguard/windows/l18n""golang.zx2c4.com/wireguard/windows/manager""golang.zx2c4.com/wireguard/windows/ringlogger""golang.zx2c4.com/wireguard/windows/tunnel""golang.zx2c4.com/wireguard/windows/ui""golang.zx2c4.com/wireguard/windows/updater")funcfatal(v...interface{}){windows.MessageBox(0,windows.StringToUTF16Ptr(fmt.Sprint(v...)),windows.StringToUTF16Ptr(l18n.Sprintf("Error")),windows.MB_ICONERROR)os.Exit(1)}funcfatalf(formatstring,v...interface{}){fatal(l18n.Sprintf(format,v...))}funcinfo(titlestring,formatstring,v...interface{}){windows.MessageBox(0,windows.StringToUTF16Ptr(l18n.Sprintf(format,v...)),windows.StringToUTF16Ptr(title),windows.MB_ICONINFORMATION)}funcusage(){varflags=[...]string{l18n.Sprintf("(no argument): elevate and install manager service"),"/installmanagerservice","/installtunnelservice CONFIG_PATH","/uninstallmanagerservice","/uninstalltunnelservice TUNNEL_NAME","/managerservice","/tunnelservice CONFIG_PATH","/ui CMD_READ_HANDLE CMD_WRITE_HANDLE CMD_EVENT_HANDLE LOG_MAPPING_HANDLE","/dumplog OUTPUT_PATH","/update [LOG_FILE]",}builder:=strings.Builder{}for_,flag:=rangeflags{builder.WriteString(fmt.Sprintf(" %s\n",flag))}info(l18n.Sprintf("Command Line Options"),"Usage: %s [\n%s]",os.Args[0],builder.String())os.Exit(1)}funccheckForWow64(){varbboolerr:=windows.IsWow64Process(windows.CurrentProcess(),&b)iferr!=nil{fatalf("Unable to determine whether the process is running under WOW64: %v",err)}ifb{fatalf("You must use the 64-bit version of WireGuard on this computer.")}}funccheckForAdminGroup(){// This is not a security check, but rather a user-confusion one.varprocessTokenwindows.Tokenerr:=windows.OpenProcessToken(windows.CurrentProcess(),windows.TOKEN_QUERY|windows.TOKEN_DUPLICATE,&processToken)iferr!=nil{fatalf("Unable to open current process token: %v",err)}deferprocessToken.Close()if!elevate.TokenIsElevatedOrElevatable(processToken){fatalf("WireGuard may only be used by users who are a member of the Builtin %s group.",elevate.AdminGroupName())}}funccheckForAdminDesktop(){adminDesktop,err:=elevate.IsAdminDesktop()if!adminDesktop&&err==nil{fatalf("WireGuard is running, but the UI is only accessible from desktops of the Builtin %s group.",elevate.AdminGroupName())}}funcexecElevatedManagerServiceInstaller()error{path,err:=os.Executable()iferr!=nil{returnerr}err=elevate.ShellExecute(path,"/installmanagerservice","",windows.SW_SHOW)iferr!=nil{returnerr}os.Exit(0)returnwindows.ERROR_ACCESS_DENIED// Not reached}funcpipeFromHandleArgument(handleStrstring)(*os.File,error){handleInt,err:=strconv.ParseUint(handleStr,10,64)iferr!=nil{returnnil,err}returnos.NewFile(uintptr(handleInt),"pipe"),nil}funcmain(){checkForWow64()iflen(os.Args)<=1{checkForAdminGroup()ifui.RaiseUI(){return}err:=execElevatedManagerServiceInstaller()iferr!=nil{fatal(err)}return}switchos.Args[1]{case"/installmanagerservice":iflen(os.Args)!=2{usage()}goui.WaitForRaiseUIThenQuit()err:=manager.InstallManager()iferr!=nil{iferr==manager.ErrManagerAlreadyRunning{checkForAdminDesktop()}fatal(err)}checkForAdminDesktop()time.Sleep(30*time.Second)fatalf("WireGuard system tray icon did not appear after 30 seconds.")returncase"/uninstallmanagerservice":iflen(os.Args)!=2{usage()}err:=manager.UninstallManager()iferr!=nil{fatal(err)}returncase"/managerservice":iflen(os.Args)!=2{usage()}err:=manager.Run()iferr!=nil{fatal(err)}returncase"/installtunnelservice":iflen(os.Args)!=3{usage()}err:=manager.InstallTunnel(os.Args[2])iferr!=nil{fatal(err)}returncase"/uninstalltunnelservice":iflen(os.Args)!=3{usage()}err:=manager.UninstallTunnel(os.Args[2])iferr!=nil{fatal(err)}returncase"/tunnelservice":iflen(os.Args)!=3{usage()}err:=tunnel.Run(os.Args[2])iferr!=nil{fatal(err)}returncase"/ui":iflen(os.Args)!=6{usage()}err:=elevate.DropAllPrivileges(false)iferr!=nil{fatal(err)}readPipe,err:=pipeFromHandleArgument(os.Args[2])iferr!=nil{fatal(err)}writePipe,err:=pipeFromHandleArgument(os.Args[3])iferr!=nil{fatal(err)}eventPipe,err:=pipeFromHandleArgument(os.Args[4])iferr!=nil{fatal(err)}ringlogger.Global,err=ringlogger.NewRingloggerFromInheritedMappingHandle(os.Args[5],"GUI")iferr!=nil{fatal(err)}manager.InitializeIPCClient(readPipe,writePipe,eventPipe)ui.RunUI()returncase"/dumplog":iflen(os.Args)!=3{usage()}file,err:=os.Create(os.Args[2])iferr!=nil{fatal(err)}deferfile.Close()err=ringlogger.DumpTo(file,true)iferr!=nil{fatal(err)}returncase"/update":iflen(os.Args)!=2&&len(os.Args)!=3{usage()}varf*os.Filevarerrerroriflen(os.Args)==2{f=os.Stdout}else{f,err=os.Create(os.Args[2])iferr!=nil{fatal(err)}deferf.Close()}l:=log.New(f,"",log.LstdFlags)forprogress:=rangeupdater.DownloadVerifyAndExecute(0){iflen(progress.Activity)>0{ifprogress.BytesTotal>0||progress.BytesDownloaded>0{varpercentfloat64ifprogress.BytesTotal>0{percent=float64(progress.BytesDownloaded)/float64(progress.BytesTotal)*100.0}l.Printf("%s: %d/%d (%.2f%%)\n",progress.Activity,progress.BytesDownloaded,progress.BytesTotal,percent)}else{l.Println(progress.Activity)}}ifprogress.Error!=nil{l.Printf("Error: %v\n",progress.Error)}ifprogress.Complete||progress.Error!=nil{return}}return}usage()}