From 2bdcbc5f2be24c494ebaab63f47c71bad79b126c Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 27 Nov 2020 11:57:19 +0100 Subject: conf: separate out migration and print errors Signed-off-by: Jason A. Donenfeld --- conf/migration.go | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ conf/store.go | 76 ---------------------------------------------- manager/service.go | 2 +- 3 files changed, 90 insertions(+), 77 deletions(-) create mode 100644 conf/migration.go diff --git a/conf/migration.go b/conf/migration.go new file mode 100644 index 00000000..4b68763f --- /dev/null +++ b/conf/migration.go @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019-2020 WireGuard LLC. All Rights Reserved. + */ + +package conf + +import ( + "errors" + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" + "sync" + "time" + + "golang.org/x/sys/windows" +) + +var migrating sync.Mutex +var lastMigrationTimer *time.Timer + +func MigrateUnencryptedConfigs() { migrateUnencryptedConfigs(3) } + +func migrateUnencryptedConfigs(sharingBase int) { + migrating.Lock() + defer migrating.Unlock() + configFileDir, err := tunnelConfigurationsDirectory() + if err != nil { + return + } + files, err := ioutil.ReadDir(configFileDir) + if err != nil { + return + } + ignoreSharingViolations := false + for _, file := range files { + path := filepath.Join(configFileDir, file.Name()) + name := filepath.Base(file.Name()) + if len(name) <= len(configFileUnencryptedSuffix) || !strings.HasSuffix(name, configFileUnencryptedSuffix) { + continue + } + if !file.Mode().IsRegular() || file.Mode().Perm()&0444 == 0 { + continue + } + + var bytes []byte + var config *Config + // We don't use ioutil's ReadFile, because we actually want RDWR, so that we can take advantage + // of Windows file locking for ensuring the file is finished being written. + f, err := os.OpenFile(path, os.O_RDWR, 0) + if err != nil { + if errors.Is(err, windows.ERROR_SHARING_VIOLATION) { + if ignoreSharingViolations { + continue + } else if sharingBase > 0 { + if lastMigrationTimer != nil { + lastMigrationTimer.Stop() + } + lastMigrationTimer = time.AfterFunc(time.Second/time.Duration(sharingBase*sharingBase), func() { migrateUnencryptedConfigs(sharingBase - 1) }) + ignoreSharingViolations = true + continue + } + } + goto error + } + bytes, err = ioutil.ReadAll(f) + f.Close() + if err != nil { + goto error + } + config, err = FromWgQuickWithUnknownEncoding(string(bytes), strings.TrimSuffix(name, configFileUnencryptedSuffix)) + if err != nil { + goto error + } + err = config.Save(false) + if err != nil { + goto error + } + err = os.Remove(path) + if err != nil { + log.Printf("Unable to remove old path %#q: %v", path, err) + } + continue + error: + log.Printf("Unable to ingest and encrypt %#q: %v", path, err) + } +} diff --git a/conf/store.go b/conf/store.go index 5cc2ce46..18f99f66 100644 --- a/conf/store.go +++ b/conf/store.go @@ -11,10 +11,6 @@ import ( "os" "path/filepath" "strings" - "sync" - "time" - - "golang.org/x/sys/windows" "golang.zx2c4.com/wireguard/windows/conf/dpapi" ) @@ -51,78 +47,6 @@ func ListConfigNames() ([]string, error) { return configs[:i], nil } -var migrating sync.Mutex -var lastMigrationTimer *time.Timer - -func MigrateUnencryptedConfigs(sharingBase int) (int, []error) { - migrating.Lock() - defer migrating.Unlock() - configFileDir, err := tunnelConfigurationsDirectory() - if err != nil { - return 0, []error{err} - } - files, err := ioutil.ReadDir(configFileDir) - if err != nil { - return 0, []error{err} - } - errs := make([]error, len(files)) - i := 0 - e := 0 - for _, file := range files { - path := filepath.Join(configFileDir, file.Name()) - name := filepath.Base(file.Name()) - if len(name) <= len(configFileUnencryptedSuffix) || !strings.HasSuffix(name, configFileUnencryptedSuffix) { - continue - } - if !file.Mode().IsRegular() || file.Mode().Perm()&0444 == 0 { - continue - } - - // We don't use ioutil's ReadFile, because we actually want RDWR, so that we can take advantage - // of Windows file locking for ensuring the file is finished being written. - f, err := os.OpenFile(path, os.O_RDWR, 0) - if err != nil { - if sharingBase > 0 && errors.Is(err, windows.ERROR_SHARING_VIOLATION) { - if lastMigrationTimer != nil { - lastMigrationTimer.Stop() - } - lastMigrationTimer = time.AfterFunc(time.Second/time.Duration(sharingBase*sharingBase), func() { MigrateUnencryptedConfigs(sharingBase - 1) }) - sharingBase = 0 - } - errs[e] = err - e++ - continue - } - bytes, err := ioutil.ReadAll(f) - f.Close() - if err != nil { - errs[e] = err - e++ - continue - } - config, err := FromWgQuickWithUnknownEncoding(string(bytes), strings.TrimSuffix(name, configFileUnencryptedSuffix)) - if err != nil { - errs[e] = err - e++ - continue - } - err = config.Save(false) - if err != nil { - errs[e] = err - e++ - continue - } - err = os.Remove(path) - if err != nil { - errs[e] = err - e++ - continue - } - i++ - } - return i, errs[:e] -} - func LoadFromName(name string) (*Config, error) { configFileDir, err := tunnelConfigurationsDirectory() if err != nil { diff --git a/manager/service.go b/manager/service.go index 9044d9fb..2afd796f 100644 --- a/manager/service.go +++ b/manager/service.go @@ -85,7 +85,7 @@ func (service *managerService) Execute(args []string, r <-chan svc.ChangeRequest return } - conf.RegisterStoreChangeCallback(func() { conf.MigrateUnencryptedConfigs(3) }) + conf.RegisterStoreChangeCallback(conf.MigrateUnencryptedConfigs) conf.RegisterStoreChangeCallback(IPCServerNotifyTunnelsChange) procs := make(map[uint32]*os.Process) -- cgit v1.2.3-59-g8ed1b