aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/conf/filewriter_windows.go
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-11-25 22:29:13 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2020-11-27 12:50:53 +0100
commitea8a6b076ef2359426687467d7465e4c092f6447 (patch)
treea474c3dd789e62a97fee033c9d9899b6beef4069 /conf/filewriter_windows.go
parentdocs: fix /0 -> /1 in netquirk (diff)
downloadwireguard-windows-ea8a6b076ef2359426687467d7465e4c092f6447.tar.xz
wireguard-windows-ea8a6b076ef2359426687467d7465e4c092f6447.zip
conf: do exponential back off for sharing violation in hotfolder
Windows gives us notifications about writes to files in a directory, but it does not give us notifications on when file handles are closed and when we can expect to be able to grab a handle to it; this would be racey at best. So, there always exists a race between the writer's last call to WriteFile() and its eventual CloseHandle(). Work around this by implementing a basic exponential back off of retrying the open call. While we're at it, clean up the "file already exists" logic to remove a basic toctou situation, and switch to using random temp file names in order to handle better the case of saving a new file from two different administrators at once. Reported-by: Jim Salter <jim@jrs-s.net> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'conf/filewriter_windows.go')
-rw-r--r--conf/filewriter_windows.go23
1 files changed, 20 insertions, 3 deletions
diff --git a/conf/filewriter_windows.go b/conf/filewriter_windows.go
index 6f7c40ad..ca45bf42 100644
--- a/conf/filewriter_windows.go
+++ b/conf/filewriter_windows.go
@@ -6,6 +6,8 @@
package conf
import (
+ "crypto/rand"
+ "encoding/hex"
"sync/atomic"
"unsafe"
@@ -14,7 +16,16 @@ import (
var encryptedFileSd unsafe.Pointer
-func writeEncryptedFile(destination string, contents []byte) error {
+func randomFileName() string {
+ var randBytes [32]byte
+ _, err := rand.Read(randBytes[:])
+ if err != nil {
+ panic(err)
+ }
+ return hex.EncodeToString(randBytes[:]) + ".tmp"
+}
+
+func writeEncryptedFile(destination string, overwrite bool, contents []byte) error {
var err error
sa := &windows.SecurityAttributes{Length: uint32(unsafe.Sizeof(windows.SecurityAttributes{}))}
sa.SecurityDescriptor = (*windows.SECURITY_DESCRIPTOR)(atomic.LoadPointer(&encryptedFileSd))
@@ -29,7 +40,7 @@ func writeEncryptedFile(destination string, contents []byte) error {
if err != nil {
return err
}
- tmpDestination := destination + ".tmp"
+ tmpDestination := randomFileName()
tmpDestination16, err := windows.UTF16PtrFromString(tmpDestination)
if err != nil {
return err
@@ -57,7 +68,13 @@ func writeEncryptedFile(destination string, contents []byte) error {
rootDirectory windows.Handle
fileNameLength uint32
fileName [windows.MAX_PATH]uint16
- }{replaceIfExists: 1, fileNameLength: uint32(len(destination16) - 1)}
+ }{replaceIfExists: func() byte {
+ if overwrite {
+ return 1
+ } else {
+ return 0
+ }
+ }(), fileNameLength: uint32(len(destination16) - 1)}
if len(destination16) > len(fileRenameInfo.fileName) {
deleteIt()
return windows.ERROR_BUFFER_OVERFLOW