From 02a15049b923581a2de2271bcf162991d9f885c1 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 24 Jan 2021 14:39:46 +0100 Subject: updater,version: simplify code locations Signed-off-by: Jason A. Donenfeld --- conf/dpapi/dpapi_windows.go | 12 +-- updater/authenticode.go | 31 ++++++ updater/downloader.go | 2 +- updater/msirunner.go | 116 +++++++++++++++++++++++ updater/msirunner_linux.go | 23 ----- updater/msirunner_windows.go | 116 ----------------------- updater/updater_test.go | 2 +- updater/winhttp/httptest.exe | Bin 3318784 -> 0 bytes version/certificate_windows.go | 115 ----------------------- version/debugging_linux.go | 35 ------- version/official.go | 157 +++++++++++++++++++++++++++++++ version/official_windows.go | 77 --------------- version/os.go | 207 +++++++++++++++++++++++++++++++++++++++++ version/os_windows.go | 207 ----------------------------------------- 14 files changed, 519 insertions(+), 581 deletions(-) create mode 100644 updater/authenticode.go create mode 100644 updater/msirunner.go delete mode 100644 updater/msirunner_linux.go delete mode 100644 updater/msirunner_windows.go delete mode 100755 updater/winhttp/httptest.exe delete mode 100644 version/certificate_windows.go delete mode 100644 version/debugging_linux.go create mode 100644 version/official.go delete mode 100644 version/official_windows.go create mode 100644 version/os.go delete mode 100644 version/os_windows.go diff --git a/conf/dpapi/dpapi_windows.go b/conf/dpapi/dpapi_windows.go index 45ad950e..f3a238d5 100644 --- a/conf/dpapi/dpapi_windows.go +++ b/conf/dpapi/dpapi_windows.go @@ -7,19 +7,19 @@ package dpapi import ( "errors" + "fmt" "runtime" "unsafe" - "fmt" "golang.org/x/sys/windows" ) func bytesToBlob(bytes []byte) *windows.DataBlob { - blob := &windows.DataBlob{Size: uint32(len(bytes))} - if len(bytes) > 0 { - blob.Data = &bytes[0] - } - return blob + blob := &windows.DataBlob{Size: uint32(len(bytes))} + if len(bytes) > 0 { + blob.Data = &bytes[0] + } + return blob } func Encrypt(data []byte, name string) ([]byte, error) { diff --git a/updater/authenticode.go b/updater/authenticode.go new file mode 100644 index 00000000..13ce6917 --- /dev/null +++ b/updater/authenticode.go @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. + */ + +package updater + +import ( + "unsafe" + + "golang.org/x/sys/windows" +) + +func verifyAuthenticode(path string) bool { + path16, err := windows.UTF16PtrFromString(path) + if err != nil { + return false + } + data := &windows.WinTrustData{ + Size: uint32(unsafe.Sizeof(windows.WinTrustData{})), + UIChoice: windows.WTD_UI_NONE, + RevocationChecks: windows.WTD_REVOKE_WHOLECHAIN, // Full revocation checking, as this is called with network connectivity. + UnionChoice: windows.WTD_CHOICE_FILE, + StateAction: windows.WTD_STATEACTION_VERIFY, + FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{ + Size: uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})), + FilePath: path16, + }), + } + return windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) == nil +} diff --git a/updater/downloader.go b/updater/downloader.go index 98159553..a61acbd4 100644 --- a/updater/downloader.go +++ b/updater/downloader.go @@ -168,7 +168,7 @@ func DownloadVerifyAndExecute(userToken uintptr) (progress chan DownloadProgress } progress <- DownloadProgress{Activity: "Verifying authenticode signature"} - if !version.VerifyAuthenticode(file.ExclusivePath()) { + if !verifyAuthenticode(file.ExclusivePath()) { progress <- DownloadProgress{Error: errors.New("The downloaded update does not have an authentic authenticode signature")} return } diff --git a/updater/msirunner.go b/updater/msirunner.go new file mode 100644 index 00000000..d7631706 --- /dev/null +++ b/updater/msirunner.go @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. + */ + +package updater + +import ( + "crypto/rand" + "encoding/hex" + "errors" + "os" + "os/exec" + "path/filepath" + "runtime" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +type tempFile struct { + *os.File + originalHandle windows.Handle +} + +func (t *tempFile) ExclusivePath() string { + if t.originalHandle != 0 { + t.Close() // TODO: sort of a toctou, but msi requires unshared file + t.originalHandle = 0 + } + return t.Name() +} + +func (t *tempFile) Delete() error { + if t.originalHandle == 0 { + name16, err := windows.UTF16PtrFromString(t.Name()) + if err != nil { + return err + } + return windows.DeleteFile(name16) //TODO: how does this deal with reparse points? + } + disposition := byte(1) + err := windows.SetFileInformationByHandle(t.originalHandle, windows.FileDispositionInfo, &disposition, 1) + t.originalHandle = 0 + t.Close() + return err +} + +func runMsi(msi *tempFile, userToken uintptr) error { + system32, err := windows.GetSystemDirectory() + if err != nil { + return err + } + devNull, err := os.OpenFile(os.DevNull, os.O_RDWR, 0) + if err != nil { + return err + } + defer devNull.Close() + msiPath := msi.ExclusivePath() + attr := &os.ProcAttr{ + Sys: &syscall.SysProcAttr{ + Token: syscall.Token(userToken), + }, + Files: []*os.File{devNull, devNull, devNull}, + Dir: filepath.Dir(msiPath), + } + msiexec := filepath.Join(system32, "msiexec.exe") + proc, err := os.StartProcess(msiexec, []string{msiexec, "/qb!-", "/i", filepath.Base(msiPath)}, attr) + if err != nil { + return err + } + state, err := proc.Wait() + if err != nil { + return err + } + if !state.Success() { + return &exec.ExitError{ProcessState: state} + } + return nil +} + +func msiTempFile() (*tempFile, error) { + var randBytes [32]byte + n, err := rand.Read(randBytes[:]) + if err != nil { + return nil, err + } + if n != int(len(randBytes)) { + return nil, errors.New("Unable to generate random bytes") + } + sd, err := windows.SecurityDescriptorFromString("O:SYD:PAI(A;;FA;;;SY)(A;;FR;;;BA)") + if err != nil { + return nil, err + } + sa := &windows.SecurityAttributes{ + Length: uint32(unsafe.Sizeof(windows.SecurityAttributes{})), + SecurityDescriptor: sd, + } + windir, err := windows.GetWindowsDirectory() + if err != nil { + return nil, err + } + name := filepath.Join(windir, "Temp", hex.EncodeToString(randBytes[:])) + name16 := windows.StringToUTF16Ptr(name) + fileHandle, err := windows.CreateFile(name16, windows.GENERIC_WRITE|windows.DELETE, 0, sa, windows.CREATE_NEW, windows.FILE_ATTRIBUTE_TEMPORARY, 0) + runtime.KeepAlive(sd) + if err != nil { + return nil, err + } + windows.MoveFileEx(name16, nil, windows.MOVEFILE_DELAY_UNTIL_REBOOT) + return &tempFile{ + File: os.NewFile(uintptr(fileHandle), name), + originalHandle: fileHandle, + }, nil +} diff --git a/updater/msirunner_linux.go b/updater/msirunner_linux.go deleted file mode 100644 index f6cca441..00000000 --- a/updater/msirunner_linux.go +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. - */ - -package updater - -import ( - "fmt" - "io/ioutil" - "os" - "os/exec" -) - -// This isn't a Linux program, yes, but having the updater package work across platforms is quite helpful for testing. - -func runMsi(msiPath string, userToken uintptr, env []string) error { - return exec.Command("qarma", "--info", "--text", fmt.Sprintf("It seems to be working! Were we on Windows, ā€˜%sā€™ would be executed.", msiPath)).Run() -} - -func msiTempFile() (*os.File, error) { - return ioutil.TempFile(os.TempDir(), "") -} diff --git a/updater/msirunner_windows.go b/updater/msirunner_windows.go deleted file mode 100644 index d7631706..00000000 --- a/updater/msirunner_windows.go +++ /dev/null @@ -1,116 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. - */ - -package updater - -import ( - "crypto/rand" - "encoding/hex" - "errors" - "os" - "os/exec" - "path/filepath" - "runtime" - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -type tempFile struct { - *os.File - originalHandle windows.Handle -} - -func (t *tempFile) ExclusivePath() string { - if t.originalHandle != 0 { - t.Close() // TODO: sort of a toctou, but msi requires unshared file - t.originalHandle = 0 - } - return t.Name() -} - -func (t *tempFile) Delete() error { - if t.originalHandle == 0 { - name16, err := windows.UTF16PtrFromString(t.Name()) - if err != nil { - return err - } - return windows.DeleteFile(name16) //TODO: how does this deal with reparse points? - } - disposition := byte(1) - err := windows.SetFileInformationByHandle(t.originalHandle, windows.FileDispositionInfo, &disposition, 1) - t.originalHandle = 0 - t.Close() - return err -} - -func runMsi(msi *tempFile, userToken uintptr) error { - system32, err := windows.GetSystemDirectory() - if err != nil { - return err - } - devNull, err := os.OpenFile(os.DevNull, os.O_RDWR, 0) - if err != nil { - return err - } - defer devNull.Close() - msiPath := msi.ExclusivePath() - attr := &os.ProcAttr{ - Sys: &syscall.SysProcAttr{ - Token: syscall.Token(userToken), - }, - Files: []*os.File{devNull, devNull, devNull}, - Dir: filepath.Dir(msiPath), - } - msiexec := filepath.Join(system32, "msiexec.exe") - proc, err := os.StartProcess(msiexec, []string{msiexec, "/qb!-", "/i", filepath.Base(msiPath)}, attr) - if err != nil { - return err - } - state, err := proc.Wait() - if err != nil { - return err - } - if !state.Success() { - return &exec.ExitError{ProcessState: state} - } - return nil -} - -func msiTempFile() (*tempFile, error) { - var randBytes [32]byte - n, err := rand.Read(randBytes[:]) - if err != nil { - return nil, err - } - if n != int(len(randBytes)) { - return nil, errors.New("Unable to generate random bytes") - } - sd, err := windows.SecurityDescriptorFromString("O:SYD:PAI(A;;FA;;;SY)(A;;FR;;;BA)") - if err != nil { - return nil, err - } - sa := &windows.SecurityAttributes{ - Length: uint32(unsafe.Sizeof(windows.SecurityAttributes{})), - SecurityDescriptor: sd, - } - windir, err := windows.GetWindowsDirectory() - if err != nil { - return nil, err - } - name := filepath.Join(windir, "Temp", hex.EncodeToString(randBytes[:])) - name16 := windows.StringToUTF16Ptr(name) - fileHandle, err := windows.CreateFile(name16, windows.GENERIC_WRITE|windows.DELETE, 0, sa, windows.CREATE_NEW, windows.FILE_ATTRIBUTE_TEMPORARY, 0) - runtime.KeepAlive(sd) - if err != nil { - return nil, err - } - windows.MoveFileEx(name16, nil, windows.MOVEFILE_DELAY_UNTIL_REBOOT) - return &tempFile{ - File: os.NewFile(uintptr(fileHandle), name), - originalHandle: fileHandle, - }, nil -} diff --git a/updater/updater_test.go b/updater/updater_test.go index a29d71f6..02e980eb 100644 --- a/updater/updater_test.go +++ b/updater/updater_test.go @@ -20,7 +20,7 @@ func TestUpdate(t *testing.T) { return } t.Log("Found update") - progress := DownloadVerifyAndExecute(0, nil) + progress := DownloadVerifyAndExecute(0) for { dp := <-progress if dp.Error != nil { diff --git a/updater/winhttp/httptest.exe b/updater/winhttp/httptest.exe deleted file mode 100755 index 9f7ecda4..00000000 Binary files a/updater/winhttp/httptest.exe and /dev/null differ diff --git a/version/certificate_windows.go b/version/certificate_windows.go deleted file mode 100644 index b5ae3764..00000000 --- a/version/certificate_windows.go +++ /dev/null @@ -1,115 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. - */ - -package version - -import ( - "syscall" - "unsafe" - - "golang.org/x/sys/windows" -) - -func extractCertificateNames(path string) ([]string, error) { - path16, err := windows.UTF16PtrFromString(path) - if err != nil { - return nil, err - } - var certStore windows.Handle - err = windows.CryptQueryObject(windows.CERT_QUERY_OBJECT_FILE, unsafe.Pointer(path16), windows.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, windows.CERT_QUERY_FORMAT_FLAG_ALL, 0, nil, nil, nil, &certStore, nil, nil) - if err != nil { - return nil, err - } - defer windows.CertCloseStore(certStore, 0) - var cert *windows.CertContext - var names []string - for { - cert, err = windows.CertEnumCertificatesInStore(certStore, cert) - if err != nil { - if errno, ok := err.(syscall.Errno); ok { - if errno == syscall.Errno(windows.CRYPT_E_NOT_FOUND) { - break - } - } - return nil, err - } - if cert == nil { - break - } - nameLen := windows.CertGetNameString(cert, windows.CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil, nil, 0) - if nameLen == 0 { - continue - } - name16 := make([]uint16, nameLen) - if windows.CertGetNameString(cert, windows.CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil, &name16[0], nameLen) != nameLen { - continue - } - if name16[0] == 0 { - continue - } - names = append(names, windows.UTF16ToString(name16)) - } - if names == nil { - return nil, syscall.Errno(windows.CRYPT_E_NOT_FOUND) - } - return names, nil -} - -func extractCertificatePolicies(path string, oid string) ([]string, error) { - path16, err := windows.UTF16PtrFromString(path) - if err != nil { - return nil, err - } - oid8, err := windows.BytePtrFromString(oid) - if err != nil { - return nil, err - } - var certStore windows.Handle - err = windows.CryptQueryObject(windows.CERT_QUERY_OBJECT_FILE, unsafe.Pointer(path16), windows.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, windows.CERT_QUERY_FORMAT_FLAG_ALL, 0, nil, nil, nil, &certStore, nil, nil) - if err != nil { - return nil, err - } - defer windows.CertCloseStore(certStore, 0) - var cert *windows.CertContext - var policies []string - for { - cert, err = windows.CertEnumCertificatesInStore(certStore, cert) - if err != nil { - if errno, ok := err.(syscall.Errno); ok { - if errno == syscall.Errno(windows.CRYPT_E_NOT_FOUND) { - break - } - } - return nil, err - } - if cert == nil { - break - } - ci := (*windows.CertInfo)(unsafe.Pointer(cert.CertInfo)) - ext := windows.CertFindExtension(oid8, ci.CountExtensions, ci.Extensions) - if ext == nil { - continue - } - var decodedLen uint32 - err = windows.CryptDecodeObject(windows.X509_ASN_ENCODING|windows.PKCS_7_ASN_ENCODING, ext.ObjId, ext.Value.Data, ext.Value.Size, 0, nil, &decodedLen) - if err != nil { - return nil, err - } - bytes := make([]byte, decodedLen) - certPoliciesInfo := (*windows.CertPoliciesInfo)(unsafe.Pointer(&bytes[0])) - err = windows.CryptDecodeObject(windows.X509_ASN_ENCODING|windows.PKCS_7_ASN_ENCODING, ext.ObjId, ext.Value.Data, ext.Value.Size, 0, unsafe.Pointer(&bytes[0]), &decodedLen) - if err != nil { - return nil, err - } - for i := uintptr(0); i < uintptr(certPoliciesInfo.Count); i++ { - cp := (*windows.CertPolicy)(unsafe.Pointer(uintptr(unsafe.Pointer(certPoliciesInfo.PolicyInfos)) + i*unsafe.Sizeof(*certPoliciesInfo.PolicyInfos))) - policies = append(policies, windows.BytePtrToString(cp.Identifier)) - } - } - if policies == nil { - return nil, syscall.Errno(windows.CRYPT_E_NOT_FOUND) - } - return policies, nil -} diff --git a/version/debugging_linux.go b/version/debugging_linux.go deleted file mode 100644 index da90e271..00000000 --- a/version/debugging_linux.go +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. - */ - -package version - -import ( - "bytes" - "fmt" - - "golang.org/x/sys/unix" -) - -// For testing the updater package from linux. Debug stuff only. - -func utsToStr(u [65]byte) string { - i := bytes.IndexByte(u[:], 0) - if i < 0 { - return string(u[:]) - } - return string(u[:i]) -} - -func OsName() string { - var utsname unix.Utsname - if unix.Uname(&utsname) != nil { - return "Unix Unknown" - } - return fmt.Sprintf("%s %s %s", utsToStr(utsname.Sysname), utsToStr(utsname.Release), utsToStr(utsname.Version)) -} - -func VerifyAuthenticode(path string) bool { - return true -} diff --git a/version/official.go b/version/official.go new file mode 100644 index 00000000..2345a0b7 --- /dev/null +++ b/version/official.go @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. + */ + +package version + +import ( + "errors" + "os" + "unsafe" + + "golang.org/x/sys/windows" +) + +const ( + officialCommonName = "WireGuard LLC" + evPolicyOid = "2.23.140.1.3" + policyExtensionOid = "2.5.29.32" +) + +// These are easily by-passable checks, which do not serve serve security purposes. +// DO NOT PLACE SECURITY-SENSITIVE FUNCTIONS IN THIS FILE + +func IsRunningOfficialVersion() bool { + path, err := os.Executable() + if err != nil { + return false + } + + names, err := extractCertificateNames(path) + if err != nil { + return false + } + for _, name := range names { + if name == officialCommonName { + return true + } + } + return false +} + +func IsRunningEVSigned() bool { + path, err := os.Executable() + if err != nil { + return false + } + + policies, err := extractCertificatePolicies(path, policyExtensionOid) + if err != nil { + return false + } + for _, policy := range policies { + if policy == evPolicyOid { + return true + } + } + return false +} + +func extractCertificateNames(path string) ([]string, error) { + path16, err := windows.UTF16PtrFromString(path) + if err != nil { + return nil, err + } + var certStore windows.Handle + err = windows.CryptQueryObject(windows.CERT_QUERY_OBJECT_FILE, unsafe.Pointer(path16), windows.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, windows.CERT_QUERY_FORMAT_FLAG_ALL, 0, nil, nil, nil, &certStore, nil, nil) + if err != nil { + return nil, err + } + defer windows.CertCloseStore(certStore, 0) + var cert *windows.CertContext + var names []string + for { + cert, err = windows.CertEnumCertificatesInStore(certStore, cert) + if err != nil { + if errors.Is(err, windows.Errno(windows.CRYPT_E_NOT_FOUND)) { + break + } + return nil, err + } + if cert == nil { + break + } + nameLen := windows.CertGetNameString(cert, windows.CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil, nil, 0) + if nameLen == 0 { + continue + } + name16 := make([]uint16, nameLen) + if windows.CertGetNameString(cert, windows.CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nil, &name16[0], nameLen) != nameLen { + continue + } + if name16[0] == 0 { + continue + } + names = append(names, windows.UTF16ToString(name16)) + } + if names == nil { + return nil, windows.Errno(windows.CRYPT_E_NOT_FOUND) + } + return names, nil +} + +func extractCertificatePolicies(path string, oid string) ([]string, error) { + path16, err := windows.UTF16PtrFromString(path) + if err != nil { + return nil, err + } + oid8, err := windows.BytePtrFromString(oid) + if err != nil { + return nil, err + } + var certStore windows.Handle + err = windows.CryptQueryObject(windows.CERT_QUERY_OBJECT_FILE, unsafe.Pointer(path16), windows.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, windows.CERT_QUERY_FORMAT_FLAG_ALL, 0, nil, nil, nil, &certStore, nil, nil) + if err != nil { + return nil, err + } + defer windows.CertCloseStore(certStore, 0) + var cert *windows.CertContext + var policies []string + for { + cert, err = windows.CertEnumCertificatesInStore(certStore, cert) + if err != nil { + if errors.Is(err, windows.Errno(windows.CRYPT_E_NOT_FOUND)) { + break + } + return nil, err + } + if cert == nil { + break + } + ci := (*windows.CertInfo)(unsafe.Pointer(cert.CertInfo)) + ext := windows.CertFindExtension(oid8, ci.CountExtensions, ci.Extensions) + if ext == nil { + continue + } + var decodedLen uint32 + err = windows.CryptDecodeObject(windows.X509_ASN_ENCODING|windows.PKCS_7_ASN_ENCODING, ext.ObjId, ext.Value.Data, ext.Value.Size, 0, nil, &decodedLen) + if err != nil { + return nil, err + } + bytes := make([]byte, decodedLen) + certPoliciesInfo := (*windows.CertPoliciesInfo)(unsafe.Pointer(&bytes[0])) + err = windows.CryptDecodeObject(windows.X509_ASN_ENCODING|windows.PKCS_7_ASN_ENCODING, ext.ObjId, ext.Value.Data, ext.Value.Size, 0, unsafe.Pointer(&bytes[0]), &decodedLen) + if err != nil { + return nil, err + } + for i := uintptr(0); i < uintptr(certPoliciesInfo.Count); i++ { + cp := (*windows.CertPolicy)(unsafe.Pointer(uintptr(unsafe.Pointer(certPoliciesInfo.PolicyInfos)) + i*unsafe.Sizeof(*certPoliciesInfo.PolicyInfos))) + policies = append(policies, windows.BytePtrToString(cp.Identifier)) + } + } + if policies == nil { + return nil, windows.Errno(windows.CRYPT_E_NOT_FOUND) + } + return policies, nil +} diff --git a/version/official_windows.go b/version/official_windows.go deleted file mode 100644 index 1bfcf90b..00000000 --- a/version/official_windows.go +++ /dev/null @@ -1,77 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. - */ - -package version - -import ( - "os" - "unsafe" - - "golang.org/x/sys/windows" -) - -const ( - officialCommonName = "WireGuard LLC" - evPolicyOid = "2.23.140.1.3" - policyExtensionOid = "2.5.29.32" -) - -func VerifyAuthenticode(path string) bool { - path16, err := windows.UTF16PtrFromString(path) - if err != nil { - return false - } - data := &windows.WinTrustData{ - Size: uint32(unsafe.Sizeof(windows.WinTrustData{})), - UIChoice: windows.WTD_UI_NONE, - RevocationChecks: windows.WTD_REVOKE_WHOLECHAIN, // Full revocation checking, as this is called with network connectivity. - UnionChoice: windows.WTD_CHOICE_FILE, - StateAction: windows.WTD_STATEACTION_VERIFY, - FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{ - Size: uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})), - FilePath: path16, - }), - } - return windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) == nil -} - -// These are easily by-passable checks, which do not serve serve security purposes. Do not place security-sensitive -// functions below this line. - -func IsRunningOfficialVersion() bool { - path, err := os.Executable() - if err != nil { - return false - } - - names, err := extractCertificateNames(path) - if err != nil { - return false - } - for _, name := range names { - if name == officialCommonName { - return true - } - } - return false -} - -func IsRunningEVSigned() bool { - path, err := os.Executable() - if err != nil { - return false - } - - policies, err := extractCertificatePolicies(path, policyExtensionOid) - if err != nil { - return false - } - for _, policy := range policies { - if policy == evPolicyOid { - return true - } - } - return false -} diff --git a/version/os.go b/version/os.go new file mode 100644 index 00000000..315a4901 --- /dev/null +++ b/version/os.go @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. + */ + +package version + +import ( + "fmt" + + "golang.org/x/sys/windows" + "golang.org/x/sys/windows/registry" +) + +const ( + PRODUCT_UNDEFINED = 0x00000000 + PRODUCT_ULTIMATE = 0x00000001 + PRODUCT_HOME_BASIC = 0x00000002 + PRODUCT_HOME_PREMIUM = 0x00000003 + PRODUCT_ENTERPRISE = 0x00000004 + PRODUCT_HOME_BASIC_N = 0x00000005 + PRODUCT_BUSINESS = 0x00000006 + PRODUCT_STANDARD_SERVER = 0x00000007 + PRODUCT_DATACENTER_SERVER = 0x00000008 + PRODUCT_SMALLBUSINESS_SERVER = 0x00000009 + PRODUCT_ENTERPRISE_SERVER = 0x0000000A + PRODUCT_STARTER = 0x0000000B + PRODUCT_DATACENTER_SERVER_CORE = 0x0000000C + PRODUCT_STANDARD_SERVER_CORE = 0x0000000D + PRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E + PRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F + PRODUCT_BUSINESS_N = 0x00000010 + PRODUCT_WEB_SERVER = 0x00000011 + PRODUCT_CLUSTER_SERVER = 0x00000012 + PRODUCT_HOME_SERVER = 0x00000013 + PRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014 + PRODUCT_STORAGE_STANDARD_SERVER = 0x00000015 + PRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016 + PRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017 + PRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018 + PRODUCT_SMALLBUSINESS_SERVER_PREMIUM = 0x00000019 + PRODUCT_HOME_PREMIUM_N = 0x0000001A + PRODUCT_ENTERPRISE_N = 0x0000001B + PRODUCT_ULTIMATE_N = 0x0000001C + PRODUCT_WEB_SERVER_CORE = 0x0000001D + PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E + PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F + PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020 + PRODUCT_SERVER_FOUNDATION = 0x00000021 + PRODUCT_HOME_PREMIUM_SERVER = 0x00000022 + PRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023 + PRODUCT_STANDARD_SERVER_V = 0x00000024 + PRODUCT_DATACENTER_SERVER_V = 0x00000025 + PRODUCT_ENTERPRISE_SERVER_V = 0x00000026 + PRODUCT_DATACENTER_SERVER_CORE_V = 0x00000027 + PRODUCT_STANDARD_SERVER_CORE_V = 0x00000028 + PRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029 + PRODUCT_HYPERV = 0x0000002A + PRODUCT_STORAGE_EXPRESS_SERVER_CORE = 0x0000002B + PRODUCT_STORAGE_STANDARD_SERVER_CORE = 0x0000002C + PRODUCT_STORAGE_WORKGROUP_SERVER_CORE = 0x0000002D + PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE = 0x0000002E + PRODUCT_STARTER_N = 0x0000002F + PRODUCT_PROFESSIONAL = 0x00000030 + PRODUCT_PROFESSIONAL_N = 0x00000031 + PRODUCT_SB_SOLUTION_SERVER = 0x00000032 + PRODUCT_SERVER_FOR_SB_SOLUTIONS = 0x00000033 + PRODUCT_STANDARD_SERVER_SOLUTIONS = 0x00000034 + PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE = 0x00000035 + PRODUCT_SB_SOLUTION_SERVER_EM = 0x00000036 + PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM = 0x00000037 + PRODUCT_SOLUTION_EMBEDDEDSERVER = 0x00000038 + PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE = 0x00000039 + PRODUCT_PROFESSIONAL_EMBEDDED = 0x0000003A + PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT = 0x0000003B + PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL = 0x0000003C + PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC = 0x0000003D + PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC = 0x0000003E + PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE = 0x0000003F + PRODUCT_CLUSTER_SERVER_V = 0x00000040 + PRODUCT_EMBEDDED = 0x00000041 + PRODUCT_STARTER_E = 0x00000042 + PRODUCT_HOME_BASIC_E = 0x00000043 + PRODUCT_HOME_PREMIUM_E = 0x00000044 + PRODUCT_PROFESSIONAL_E = 0x00000045 + PRODUCT_ENTERPRISE_E = 0x00000046 + PRODUCT_ULTIMATE_E = 0x00000047 + PRODUCT_ENTERPRISE_EVALUATION = 0x00000048 + PRODUCT_MULTIPOINT_STANDARD_SERVER = 0x0000004C + PRODUCT_MULTIPOINT_PREMIUM_SERVER = 0x0000004D + PRODUCT_STANDARD_EVALUATION_SERVER = 0x0000004F + PRODUCT_DATACENTER_EVALUATION_SERVER = 0x00000050 + PRODUCT_ENTERPRISE_N_EVALUATION = 0x00000054 + PRODUCT_EMBEDDED_AUTOMOTIVE = 0x00000055 + PRODUCT_EMBEDDED_INDUSTRY_A = 0x00000056 + PRODUCT_THINPC = 0x00000057 + PRODUCT_EMBEDDED_A = 0x00000058 + PRODUCT_EMBEDDED_INDUSTRY = 0x00000059 + PRODUCT_EMBEDDED_E = 0x0000005A + PRODUCT_EMBEDDED_INDUSTRY_E = 0x0000005B + PRODUCT_EMBEDDED_INDUSTRY_A_E = 0x0000005C + PRODUCT_STORAGE_WORKGROUP_EVALUATION_SERVER = 0x0000005F + PRODUCT_STORAGE_STANDARD_EVALUATION_SERVER = 0x00000060 + PRODUCT_CORE_ARM = 0x00000061 + PRODUCT_CORE_N = 0x00000062 + PRODUCT_CORE_COUNTRYSPECIFIC = 0x00000063 + PRODUCT_CORE_SINGLELANGUAGE = 0x00000064 + PRODUCT_CORE = 0x00000065 + PRODUCT_PROFESSIONAL_WMC = 0x00000067 + PRODUCT_EMBEDDED_INDUSTRY_EVAL = 0x00000069 + PRODUCT_EMBEDDED_INDUSTRY_E_EVAL = 0x0000006A + PRODUCT_EMBEDDED_EVAL = 0x0000006B + PRODUCT_EMBEDDED_E_EVAL = 0x0000006C + PRODUCT_NANO_SERVER = 0x0000006D + PRODUCT_CLOUD_STORAGE_SERVER = 0x0000006E + PRODUCT_CORE_CONNECTED = 0x0000006F + PRODUCT_PROFESSIONAL_STUDENT = 0x00000070 + PRODUCT_CORE_CONNECTED_N = 0x00000071 + PRODUCT_PROFESSIONAL_STUDENT_N = 0x00000072 + PRODUCT_CORE_CONNECTED_SINGLELANGUAGE = 0x00000073 + PRODUCT_CORE_CONNECTED_COUNTRYSPECIFIC = 0x00000074 + PRODUCT_CONNECTED_CAR = 0x00000075 + PRODUCT_INDUSTRY_HANDHELD = 0x00000076 + PRODUCT_PPI_PRO = 0x00000077 + PRODUCT_ARM64_SERVER = 0x00000078 + PRODUCT_EDUCATION = 0x00000079 + PRODUCT_EDUCATION_N = 0x0000007A + PRODUCT_IOTUAP = 0x0000007B + PRODUCT_CLOUD_HOST_INFRASTRUCTURE_SERVER = 0x0000007C + PRODUCT_ENTERPRISE_S = 0x0000007D + PRODUCT_ENTERPRISE_S_N = 0x0000007E + PRODUCT_PROFESSIONAL_S = 0x0000007F + PRODUCT_PROFESSIONAL_S_N = 0x00000080 + PRODUCT_ENTERPRISE_S_EVALUATION = 0x00000081 + PRODUCT_ENTERPRISE_S_N_EVALUATION = 0x00000082 + PRODUCT_HOLOGRAPHIC = 0x00000087 + PRODUCT_PRO_SINGLE_LANGUAGE = 0x0000008A + PRODUCT_PRO_CHINA = 0x0000008B + PRODUCT_ENTERPRISE_SUBSCRIPTION = 0x0000008C + PRODUCT_ENTERPRISE_SUBSCRIPTION_N = 0x0000008D + PRODUCT_DATACENTER_NANO_SERVER = 0x0000008F + PRODUCT_STANDARD_NANO_SERVER = 0x00000090 + PRODUCT_DATACENTER_A_SERVER_CORE = 0x00000091 + PRODUCT_STANDARD_A_SERVER_CORE = 0x00000092 + PRODUCT_DATACENTER_WS_SERVER_CORE = 0x00000093 + PRODUCT_STANDARD_WS_SERVER_CORE = 0x00000094 + PRODUCT_UTILITY_VM = 0x00000095 + PRODUCT_DATACENTER_EVALUATION_SERVER_CORE = 0x0000009F + PRODUCT_STANDARD_EVALUATION_SERVER_CORE = 0x000000A0 + PRODUCT_PRO_WORKSTATION = 0x000000A1 + PRODUCT_PRO_WORKSTATION_N = 0x000000A2 + PRODUCT_PRO_FOR_EDUCATION = 0x000000A4 + PRODUCT_PRO_FOR_EDUCATION_N = 0x000000A5 + PRODUCT_AZURE_SERVER_CORE = 0x000000A8 + PRODUCT_AZURE_NANO_SERVER = 0x000000A9 + PRODUCT_ENTERPRISEG = 0x000000AB + PRODUCT_ENTERPRISEGN = 0x000000AC + PRODUCT_SERVERRDSH = 0x000000AF + PRODUCT_CLOUD = 0x000000B2 + PRODUCT_CLOUDN = 0x000000B3 + PRODUCT_HUBOS = 0x000000B4 + PRODUCT_ONECOREUPDATEOS = 0x000000B6 + PRODUCT_CLOUDE = 0x000000B7 + PRODUCT_ANDROMEDA = 0x000000B8 + PRODUCT_IOTOS = 0x000000B9 + PRODUCT_CLOUDEN = 0x000000BA + PRODUCT_UNLICENSED = 0xABCDABCD +) + +func OsIsCore() bool { + versionInfo := windows.RtlGetVersion() + if versionInfo.MajorVersion > 6 || (versionInfo.MajorVersion == 6 && versionInfo.MinorVersion >= 2) { + k, err := registry.OpenKey(registry.LOCAL_MACHINE, `Software\Microsoft\Windows NT\CurrentVersion\Server\ServerLevels`, registry.READ) + if err != nil { + return false + } + nanoServerInteger, _, err1 := k.GetIntegerValue("NanoServer") + serverCoreInteger, _, err2 := k.GetIntegerValue("ServerCore") + serverGuiInteger, _, err3 := k.GetIntegerValue("Server-Gui-Shell") + nanoServer := nanoServerInteger == 1 && err1 == nil + serverCore := serverCoreInteger == 1 && err2 == nil + serverGui := serverGuiInteger == 1 && err3 == nil + k.Close() + return (nanoServer || serverCore) && !serverGui + } + + switch versionInfo.ProductType { + case PRODUCT_DATACENTER_SERVER_CORE, PRODUCT_STANDARD_SERVER_CORE, PRODUCT_ENTERPRISE_SERVER_CORE, PRODUCT_WEB_SERVER_CORE, PRODUCT_DATACENTER_SERVER_CORE_V, PRODUCT_STANDARD_SERVER_CORE_V, PRODUCT_ENTERPRISE_SERVER_CORE_V, PRODUCT_STORAGE_EXPRESS_SERVER_CORE, PRODUCT_STORAGE_STANDARD_SERVER_CORE, PRODUCT_STORAGE_WORKGROUP_SERVER_CORE, PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE, PRODUCT_DATACENTER_A_SERVER_CORE, PRODUCT_STANDARD_A_SERVER_CORE, PRODUCT_DATACENTER_WS_SERVER_CORE, PRODUCT_STANDARD_WS_SERVER_CORE, PRODUCT_DATACENTER_EVALUATION_SERVER_CORE, PRODUCT_STANDARD_EVALUATION_SERVER_CORE, PRODUCT_AZURE_SERVER_CORE, PRODUCT_NANO_SERVER, PRODUCT_DATACENTER_NANO_SERVER, PRODUCT_STANDARD_NANO_SERVER, PRODUCT_AZURE_NANO_SERVER: + return true + } + return false +} + +func OsName() string { + versionInfo := windows.RtlGetVersion() + winType := "" + switch versionInfo.ProductType { + case 3: + winType = " Server" + case 2: + winType = " Controller" + } + if OsIsCore() { + winType += " Core" + } + return fmt.Sprintf("Windows%s %d.%d.%d", winType, versionInfo.MajorVersion, versionInfo.MinorVersion, versionInfo.BuildNumber) +} diff --git a/version/os_windows.go b/version/os_windows.go deleted file mode 100644 index 315a4901..00000000 --- a/version/os_windows.go +++ /dev/null @@ -1,207 +0,0 @@ -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. - */ - -package version - -import ( - "fmt" - - "golang.org/x/sys/windows" - "golang.org/x/sys/windows/registry" -) - -const ( - PRODUCT_UNDEFINED = 0x00000000 - PRODUCT_ULTIMATE = 0x00000001 - PRODUCT_HOME_BASIC = 0x00000002 - PRODUCT_HOME_PREMIUM = 0x00000003 - PRODUCT_ENTERPRISE = 0x00000004 - PRODUCT_HOME_BASIC_N = 0x00000005 - PRODUCT_BUSINESS = 0x00000006 - PRODUCT_STANDARD_SERVER = 0x00000007 - PRODUCT_DATACENTER_SERVER = 0x00000008 - PRODUCT_SMALLBUSINESS_SERVER = 0x00000009 - PRODUCT_ENTERPRISE_SERVER = 0x0000000A - PRODUCT_STARTER = 0x0000000B - PRODUCT_DATACENTER_SERVER_CORE = 0x0000000C - PRODUCT_STANDARD_SERVER_CORE = 0x0000000D - PRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E - PRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F - PRODUCT_BUSINESS_N = 0x00000010 - PRODUCT_WEB_SERVER = 0x00000011 - PRODUCT_CLUSTER_SERVER = 0x00000012 - PRODUCT_HOME_SERVER = 0x00000013 - PRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014 - PRODUCT_STORAGE_STANDARD_SERVER = 0x00000015 - PRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016 - PRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017 - PRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018 - PRODUCT_SMALLBUSINESS_SERVER_PREMIUM = 0x00000019 - PRODUCT_HOME_PREMIUM_N = 0x0000001A - PRODUCT_ENTERPRISE_N = 0x0000001B - PRODUCT_ULTIMATE_N = 0x0000001C - PRODUCT_WEB_SERVER_CORE = 0x0000001D - PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E - PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F - PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020 - PRODUCT_SERVER_FOUNDATION = 0x00000021 - PRODUCT_HOME_PREMIUM_SERVER = 0x00000022 - PRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023 - PRODUCT_STANDARD_SERVER_V = 0x00000024 - PRODUCT_DATACENTER_SERVER_V = 0x00000025 - PRODUCT_ENTERPRISE_SERVER_V = 0x00000026 - PRODUCT_DATACENTER_SERVER_CORE_V = 0x00000027 - PRODUCT_STANDARD_SERVER_CORE_V = 0x00000028 - PRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029 - PRODUCT_HYPERV = 0x0000002A - PRODUCT_STORAGE_EXPRESS_SERVER_CORE = 0x0000002B - PRODUCT_STORAGE_STANDARD_SERVER_CORE = 0x0000002C - PRODUCT_STORAGE_WORKGROUP_SERVER_CORE = 0x0000002D - PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE = 0x0000002E - PRODUCT_STARTER_N = 0x0000002F - PRODUCT_PROFESSIONAL = 0x00000030 - PRODUCT_PROFESSIONAL_N = 0x00000031 - PRODUCT_SB_SOLUTION_SERVER = 0x00000032 - PRODUCT_SERVER_FOR_SB_SOLUTIONS = 0x00000033 - PRODUCT_STANDARD_SERVER_SOLUTIONS = 0x00000034 - PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE = 0x00000035 - PRODUCT_SB_SOLUTION_SERVER_EM = 0x00000036 - PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM = 0x00000037 - PRODUCT_SOLUTION_EMBEDDEDSERVER = 0x00000038 - PRODUCT_SOLUTION_EMBEDDEDSERVER_CORE = 0x00000039 - PRODUCT_PROFESSIONAL_EMBEDDED = 0x0000003A - PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT = 0x0000003B - PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL = 0x0000003C - PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC = 0x0000003D - PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC = 0x0000003E - PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE = 0x0000003F - PRODUCT_CLUSTER_SERVER_V = 0x00000040 - PRODUCT_EMBEDDED = 0x00000041 - PRODUCT_STARTER_E = 0x00000042 - PRODUCT_HOME_BASIC_E = 0x00000043 - PRODUCT_HOME_PREMIUM_E = 0x00000044 - PRODUCT_PROFESSIONAL_E = 0x00000045 - PRODUCT_ENTERPRISE_E = 0x00000046 - PRODUCT_ULTIMATE_E = 0x00000047 - PRODUCT_ENTERPRISE_EVALUATION = 0x00000048 - PRODUCT_MULTIPOINT_STANDARD_SERVER = 0x0000004C - PRODUCT_MULTIPOINT_PREMIUM_SERVER = 0x0000004D - PRODUCT_STANDARD_EVALUATION_SERVER = 0x0000004F - PRODUCT_DATACENTER_EVALUATION_SERVER = 0x00000050 - PRODUCT_ENTERPRISE_N_EVALUATION = 0x00000054 - PRODUCT_EMBEDDED_AUTOMOTIVE = 0x00000055 - PRODUCT_EMBEDDED_INDUSTRY_A = 0x00000056 - PRODUCT_THINPC = 0x00000057 - PRODUCT_EMBEDDED_A = 0x00000058 - PRODUCT_EMBEDDED_INDUSTRY = 0x00000059 - PRODUCT_EMBEDDED_E = 0x0000005A - PRODUCT_EMBEDDED_INDUSTRY_E = 0x0000005B - PRODUCT_EMBEDDED_INDUSTRY_A_E = 0x0000005C - PRODUCT_STORAGE_WORKGROUP_EVALUATION_SERVER = 0x0000005F - PRODUCT_STORAGE_STANDARD_EVALUATION_SERVER = 0x00000060 - PRODUCT_CORE_ARM = 0x00000061 - PRODUCT_CORE_N = 0x00000062 - PRODUCT_CORE_COUNTRYSPECIFIC = 0x00000063 - PRODUCT_CORE_SINGLELANGUAGE = 0x00000064 - PRODUCT_CORE = 0x00000065 - PRODUCT_PROFESSIONAL_WMC = 0x00000067 - PRODUCT_EMBEDDED_INDUSTRY_EVAL = 0x00000069 - PRODUCT_EMBEDDED_INDUSTRY_E_EVAL = 0x0000006A - PRODUCT_EMBEDDED_EVAL = 0x0000006B - PRODUCT_EMBEDDED_E_EVAL = 0x0000006C - PRODUCT_NANO_SERVER = 0x0000006D - PRODUCT_CLOUD_STORAGE_SERVER = 0x0000006E - PRODUCT_CORE_CONNECTED = 0x0000006F - PRODUCT_PROFESSIONAL_STUDENT = 0x00000070 - PRODUCT_CORE_CONNECTED_N = 0x00000071 - PRODUCT_PROFESSIONAL_STUDENT_N = 0x00000072 - PRODUCT_CORE_CONNECTED_SINGLELANGUAGE = 0x00000073 - PRODUCT_CORE_CONNECTED_COUNTRYSPECIFIC = 0x00000074 - PRODUCT_CONNECTED_CAR = 0x00000075 - PRODUCT_INDUSTRY_HANDHELD = 0x00000076 - PRODUCT_PPI_PRO = 0x00000077 - PRODUCT_ARM64_SERVER = 0x00000078 - PRODUCT_EDUCATION = 0x00000079 - PRODUCT_EDUCATION_N = 0x0000007A - PRODUCT_IOTUAP = 0x0000007B - PRODUCT_CLOUD_HOST_INFRASTRUCTURE_SERVER = 0x0000007C - PRODUCT_ENTERPRISE_S = 0x0000007D - PRODUCT_ENTERPRISE_S_N = 0x0000007E - PRODUCT_PROFESSIONAL_S = 0x0000007F - PRODUCT_PROFESSIONAL_S_N = 0x00000080 - PRODUCT_ENTERPRISE_S_EVALUATION = 0x00000081 - PRODUCT_ENTERPRISE_S_N_EVALUATION = 0x00000082 - PRODUCT_HOLOGRAPHIC = 0x00000087 - PRODUCT_PRO_SINGLE_LANGUAGE = 0x0000008A - PRODUCT_PRO_CHINA = 0x0000008B - PRODUCT_ENTERPRISE_SUBSCRIPTION = 0x0000008C - PRODUCT_ENTERPRISE_SUBSCRIPTION_N = 0x0000008D - PRODUCT_DATACENTER_NANO_SERVER = 0x0000008F - PRODUCT_STANDARD_NANO_SERVER = 0x00000090 - PRODUCT_DATACENTER_A_SERVER_CORE = 0x00000091 - PRODUCT_STANDARD_A_SERVER_CORE = 0x00000092 - PRODUCT_DATACENTER_WS_SERVER_CORE = 0x00000093 - PRODUCT_STANDARD_WS_SERVER_CORE = 0x00000094 - PRODUCT_UTILITY_VM = 0x00000095 - PRODUCT_DATACENTER_EVALUATION_SERVER_CORE = 0x0000009F - PRODUCT_STANDARD_EVALUATION_SERVER_CORE = 0x000000A0 - PRODUCT_PRO_WORKSTATION = 0x000000A1 - PRODUCT_PRO_WORKSTATION_N = 0x000000A2 - PRODUCT_PRO_FOR_EDUCATION = 0x000000A4 - PRODUCT_PRO_FOR_EDUCATION_N = 0x000000A5 - PRODUCT_AZURE_SERVER_CORE = 0x000000A8 - PRODUCT_AZURE_NANO_SERVER = 0x000000A9 - PRODUCT_ENTERPRISEG = 0x000000AB - PRODUCT_ENTERPRISEGN = 0x000000AC - PRODUCT_SERVERRDSH = 0x000000AF - PRODUCT_CLOUD = 0x000000B2 - PRODUCT_CLOUDN = 0x000000B3 - PRODUCT_HUBOS = 0x000000B4 - PRODUCT_ONECOREUPDATEOS = 0x000000B6 - PRODUCT_CLOUDE = 0x000000B7 - PRODUCT_ANDROMEDA = 0x000000B8 - PRODUCT_IOTOS = 0x000000B9 - PRODUCT_CLOUDEN = 0x000000BA - PRODUCT_UNLICENSED = 0xABCDABCD -) - -func OsIsCore() bool { - versionInfo := windows.RtlGetVersion() - if versionInfo.MajorVersion > 6 || (versionInfo.MajorVersion == 6 && versionInfo.MinorVersion >= 2) { - k, err := registry.OpenKey(registry.LOCAL_MACHINE, `Software\Microsoft\Windows NT\CurrentVersion\Server\ServerLevels`, registry.READ) - if err != nil { - return false - } - nanoServerInteger, _, err1 := k.GetIntegerValue("NanoServer") - serverCoreInteger, _, err2 := k.GetIntegerValue("ServerCore") - serverGuiInteger, _, err3 := k.GetIntegerValue("Server-Gui-Shell") - nanoServer := nanoServerInteger == 1 && err1 == nil - serverCore := serverCoreInteger == 1 && err2 == nil - serverGui := serverGuiInteger == 1 && err3 == nil - k.Close() - return (nanoServer || serverCore) && !serverGui - } - - switch versionInfo.ProductType { - case PRODUCT_DATACENTER_SERVER_CORE, PRODUCT_STANDARD_SERVER_CORE, PRODUCT_ENTERPRISE_SERVER_CORE, PRODUCT_WEB_SERVER_CORE, PRODUCT_DATACENTER_SERVER_CORE_V, PRODUCT_STANDARD_SERVER_CORE_V, PRODUCT_ENTERPRISE_SERVER_CORE_V, PRODUCT_STORAGE_EXPRESS_SERVER_CORE, PRODUCT_STORAGE_STANDARD_SERVER_CORE, PRODUCT_STORAGE_WORKGROUP_SERVER_CORE, PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE, PRODUCT_DATACENTER_A_SERVER_CORE, PRODUCT_STANDARD_A_SERVER_CORE, PRODUCT_DATACENTER_WS_SERVER_CORE, PRODUCT_STANDARD_WS_SERVER_CORE, PRODUCT_DATACENTER_EVALUATION_SERVER_CORE, PRODUCT_STANDARD_EVALUATION_SERVER_CORE, PRODUCT_AZURE_SERVER_CORE, PRODUCT_NANO_SERVER, PRODUCT_DATACENTER_NANO_SERVER, PRODUCT_STANDARD_NANO_SERVER, PRODUCT_AZURE_NANO_SERVER: - return true - } - return false -} - -func OsName() string { - versionInfo := windows.RtlGetVersion() - winType := "" - switch versionInfo.ProductType { - case 3: - winType = " Server" - case 2: - winType = " Controller" - } - if OsIsCore() { - winType += " Core" - } - return fmt.Sprintf("Windows%s %d.%d.%d", winType, versionInfo.MajorVersion, versionInfo.MinorVersion, versionInfo.BuildNumber) -} -- cgit v1.2.3-59-g8ed1b