github.com/google/fleetspeak@v0.1.15-0.20240426164851-4f31f62c1aea/fleetspeak/src/windows/regutil/regutil_windows.go (about) 1 // Copyright 2017 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build windows 16 17 // Package regutil contains utility functions for Windows registry handling. 18 package regutil 19 20 import ( 21 "errors" 22 "fmt" 23 "path/filepath" 24 "strings" 25 26 "golang.org/x/sys/windows/registry" 27 ) 28 29 const hkeyPrefix = `HKEY_LOCAL_MACHINE\` 30 31 // ErrKeyNotExist is returned if an attempt is made to access a key that does not exist. 32 var ErrKeyNotExist = errors.New("regutil: registry key does not exist") 33 34 // ErrValueNotExist is returned if an attempt is made to read a value that a key does not have. 35 var ErrValueNotExist = errors.New("regutil: registry value does not exist") 36 37 // VerifyPath performs basic verification on registry paths. 38 func VerifyPath(configurationPath string) error { 39 if !strings.HasPrefix(configurationPath, hkeyPrefix) { 40 return fmt.Errorf("invalid path [%s], only registry paths starting with %s are supported", configurationPath, hkeyPrefix) 41 } 42 43 return nil 44 } 45 46 func stripHKey(keypath string) (string, error) { 47 if err := VerifyPath(keypath); err != nil { 48 return "", err 49 } 50 51 return filepath.Clean(keypath[len(hkeyPrefix):]), nil 52 } 53 54 // Thin wrapper over registry.OpenKey() with better error-reporting. 55 func openKey(keypath string, access uint32) (registry.Key, error) { 56 k, err := registry.OpenKey(registry.LOCAL_MACHINE, keypath, access) 57 if err != nil { 58 if err == registry.ErrNotExist { 59 return k, ErrKeyNotExist 60 } 61 return k, fmt.Errorf("unable to open registry keypath [%s]: %v", keypath, err) 62 } 63 return k, nil 64 } 65 66 // CreateKeyIfNotExist checks if a registry key exists, and if it does not, creates it (along with all its ancestors). 67 func CreateKeyIfNotExist(keypath string) error { 68 p, err := stripHKey(keypath) 69 if err != nil { 70 return err 71 } 72 73 key, _, err := registry.CreateKey(registry.LOCAL_MACHINE, p, registry.QUERY_VALUE) 74 if err != nil { 75 return err 76 } 77 defer key.Close() 78 return nil 79 } 80 81 // WriteBinaryValue writes a REG_BINARY value to the given registry path. 82 func WriteBinaryValue(keypath, valuename string, content []byte) error { 83 p, err := stripHKey(keypath) 84 if err != nil { 85 return err 86 } 87 88 k, err := openKey(p, registry.SET_VALUE) 89 if err != nil { 90 return err 91 } 92 defer k.Close() 93 94 err = k.SetBinaryValue(valuename, content) 95 if err != nil { 96 return fmt.Errorf("unable to write binary (REG_BINARY) registry value [%s -> %s]: %v", keypath, valuename, err) 97 } 98 99 return nil 100 } 101 102 // ReadBinaryValue reads a REG_BINARY value from the given registry path. 103 func ReadBinaryValue(keypath, valuename string) ([]byte, error) { 104 p, err := stripHKey(keypath) 105 if err != nil { 106 return nil, err 107 } 108 109 k, err := openKey(p, registry.QUERY_VALUE) 110 if err != nil { 111 return nil, err 112 } 113 defer k.Close() 114 115 s, _, err := k.GetBinaryValue(valuename) 116 if err != nil { 117 if err == registry.ErrNotExist { 118 return nil, ErrValueNotExist 119 } 120 return nil, fmt.Errorf("unable to read binary (REG_BINARY) registry value [%s -> %s]: %v", p, valuename, err) 121 } 122 123 return s, nil 124 } 125 126 // WriteStringValue writes a REG_SZ value to the given registry path. 127 func WriteStringValue(keypath, valuename string, content string) error { 128 p, err := stripHKey(keypath) 129 if err != nil { 130 return err 131 } 132 133 k, err := openKey(p, registry.SET_VALUE) 134 if err != nil { 135 return err 136 } 137 defer k.Close() 138 139 err = k.SetStringValue(valuename, content) 140 if err != nil { 141 return fmt.Errorf("unable to write string (REG_SZ) registry value [%s -> %s]: %v", keypath, valuename, err) 142 } 143 144 return nil 145 } 146 147 // ReadStringValue reads a REG_SZ value from the given registry path. 148 func ReadStringValue(keypath, valuename string) (string, error) { 149 p, err := stripHKey(keypath) 150 if err != nil { 151 return "", err 152 } 153 154 k, err := openKey(p, registry.QUERY_VALUE) 155 if err != nil { 156 return "", err 157 } 158 defer k.Close() 159 160 s, _, err := k.GetStringValue(valuename) 161 if err != nil { 162 if err == registry.ErrNotExist { 163 return "", ErrValueNotExist 164 } 165 return "", fmt.Errorf("unable to read string (REG_SZ) registry value [%s -> %s]: %v", p, valuename, err) 166 } 167 168 return s, nil 169 } 170 171 // ReadMultiStringValue reads a REG_MULTI_SZ value from the given registry path. 172 func ReadMultiStringValue(keypath, valuename string) ([]string, error) { 173 p, err := stripHKey(keypath) 174 if err != nil { 175 return nil, err 176 } 177 178 k, err := openKey(p, registry.QUERY_VALUE) 179 if err != nil { 180 return nil, err 181 } 182 defer k.Close() 183 184 vs, _, err := k.GetStringsValue(valuename) 185 if err != nil { 186 if err == registry.ErrNotExist { 187 return nil, ErrValueNotExist 188 } 189 return nil, fmt.Errorf("unable to read multi-string (REG_MULTI_SZ) registry value [%s -> %s]: %v", p, valuename, err) 190 } 191 192 return vs, nil 193 } 194 195 // Ls returns all the value names of the given key. 196 func Ls(keypath string) ([]string, error) { 197 p, err := stripHKey(keypath) 198 if err != nil { 199 return nil, err 200 } 201 202 k, err := openKey(p, registry.QUERY_VALUE) 203 if err != nil { 204 return nil, err 205 } 206 defer k.Close() 207 208 vs, err := k.ReadValueNames(0) 209 if err != nil { 210 return nil, fmt.Errorf("unable to list values in key path [%s]: %v", p, err) 211 } 212 213 return vs, nil 214 }