golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/conf/path_windows.go (about) 1 /* SPDX-License-Identifier: MIT 2 * 3 * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. 4 */ 5 6 package conf 7 8 import ( 9 "errors" 10 "os" 11 "path/filepath" 12 "strings" 13 "unsafe" 14 15 "golang.org/x/sys/windows" 16 ) 17 18 var ( 19 cachedConfigFileDir string 20 cachedRootDir string 21 ) 22 23 func tunnelConfigurationsDirectory() (string, error) { 24 if cachedConfigFileDir != "" { 25 return cachedConfigFileDir, nil 26 } 27 root, err := RootDirectory(true) 28 if err != nil { 29 return "", err 30 } 31 c := filepath.Join(root, "Configurations") 32 err = os.Mkdir(c, os.ModeDir|0o700) 33 if err != nil && !os.IsExist(err) { 34 return "", err 35 } 36 cachedConfigFileDir = c 37 return cachedConfigFileDir, nil 38 } 39 40 // PresetRootDirectory causes RootDirectory() to not try any automatic deduction, and instead 41 // uses what's passed to it. This isn't used by wireguard-windows, but is useful for external 42 // consumers of our libraries who might want to do strange things. 43 func PresetRootDirectory(root string) { 44 cachedRootDir = root 45 } 46 47 func RootDirectory(create bool) (string, error) { 48 if cachedRootDir != "" { 49 return cachedRootDir, nil 50 } 51 root, err := windows.KnownFolderPath(windows.FOLDERID_ProgramFiles, windows.KF_FLAG_DEFAULT) 52 if err != nil { 53 return "", err 54 } 55 root = filepath.Join(root, "WireGuard") 56 if !create { 57 return filepath.Join(root, "Data"), nil 58 } 59 root16, err := windows.UTF16PtrFromString(root) 60 if err != nil { 61 return "", err 62 } 63 64 // The root directory inherits its ACL from Program Files; we don't want to mess with that 65 err = windows.CreateDirectory(root16, nil) 66 if err != nil && err != windows.ERROR_ALREADY_EXISTS { 67 return "", err 68 } 69 70 dataDirectorySd, err := windows.SecurityDescriptorFromString("O:SYG:SYD:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)") 71 if err != nil { 72 return "", err 73 } 74 dataDirectorySa := &windows.SecurityAttributes{ 75 Length: uint32(unsafe.Sizeof(windows.SecurityAttributes{})), 76 SecurityDescriptor: dataDirectorySd, 77 } 78 79 data := filepath.Join(root, "Data") 80 data16, err := windows.UTF16PtrFromString(data) 81 if err != nil { 82 return "", err 83 } 84 var dataHandle windows.Handle 85 for { 86 err = windows.CreateDirectory(data16, dataDirectorySa) 87 if err != nil && err != windows.ERROR_ALREADY_EXISTS { 88 return "", err 89 } 90 dataHandle, err = windows.CreateFile(data16, windows.READ_CONTROL|windows.WRITE_OWNER|windows.WRITE_DAC, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, nil, windows.OPEN_EXISTING, windows.FILE_FLAG_BACKUP_SEMANTICS|windows.FILE_FLAG_OPEN_REPARSE_POINT|windows.FILE_ATTRIBUTE_DIRECTORY, 0) 91 if err != nil && err != windows.ERROR_FILE_NOT_FOUND { 92 return "", err 93 } 94 if err == nil { 95 break 96 } 97 } 98 defer windows.CloseHandle(dataHandle) 99 var fileInfo windows.ByHandleFileInformation 100 err = windows.GetFileInformationByHandle(dataHandle, &fileInfo) 101 if err != nil { 102 return "", err 103 } 104 if fileInfo.FileAttributes&windows.FILE_ATTRIBUTE_DIRECTORY == 0 { 105 return "", errors.New("Data directory is actually a file") 106 } 107 if fileInfo.FileAttributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0 { 108 return "", errors.New("Data directory is reparse point") 109 } 110 buf := make([]uint16, windows.MAX_PATH+4) 111 for { 112 bufLen, err := windows.GetFinalPathNameByHandle(dataHandle, &buf[0], uint32(len(buf)), 0) 113 if err != nil { 114 return "", err 115 } 116 if bufLen < uint32(len(buf)) { 117 break 118 } 119 buf = make([]uint16, bufLen) 120 } 121 if !strings.EqualFold(`\\?\`+data, windows.UTF16ToString(buf[:])) { 122 return "", errors.New("Data directory jumped to unexpected location") 123 } 124 err = windows.SetKernelObjectSecurity(dataHandle, windows.DACL_SECURITY_INFORMATION|windows.GROUP_SECURITY_INFORMATION|windows.OWNER_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION, dataDirectorySd) 125 if err != nil { 126 return "", err 127 } 128 cachedRootDir = data 129 return cachedRootDir, nil 130 } 131 132 func LogFile(createRoot bool) (string, error) { 133 root, err := RootDirectory(createRoot) 134 if err != nil { 135 return "", err 136 } 137 return filepath.Join(root, "log.bin"), nil 138 }