github.com/google/osv-scalibr@v0.4.1/common/windows/registry/live.go (about)

     1  // Copyright 2025 Google LLC
     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  //      http://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 registry
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"strconv"
    23  
    24  	winregistry "golang.org/x/sys/windows/registry"
    25  )
    26  
    27  // LiveOpener is an opener for the live registry.
    28  type LiveOpener struct{}
    29  
    30  // NewLiveOpener creates a new LiveOpener, allowing to open the live registry.
    31  func NewLiveOpener() *LiveOpener {
    32  	return &LiveOpener{}
    33  }
    34  
    35  // Open the live registry.
    36  func (o *LiveOpener) Open() (Registry, error) {
    37  	return &LiveRegistry{}, nil
    38  }
    39  
    40  // LiveRegistry wraps the windows registry library to provide live parsing of the Windows registry.
    41  type LiveRegistry struct{}
    42  
    43  // OpenKey open the requested registry key.
    44  func (o *LiveRegistry) OpenKey(hive string, path string) (Key, error) {
    45  	var winHive winregistry.Key
    46  
    47  	switch hive {
    48  	case "HKLM":
    49  		winHive = winregistry.LOCAL_MACHINE
    50  	case "HKCU":
    51  		winHive = winregistry.CURRENT_USER
    52  	case "HKU":
    53  		winHive = winregistry.USERS
    54  	default:
    55  		return nil, fmt.Errorf("unsupported hive: %s", hive)
    56  	}
    57  
    58  	key, err := winregistry.OpenKey(winHive, path, winregistry.QUERY_VALUE|winregistry.ENUMERATE_SUB_KEYS)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	return &LiveKey{
    64  		key:  &key,
    65  		name: path,
    66  	}, nil
    67  }
    68  
    69  // Close closes the registry hive.
    70  // For live keys, this is a no-op.
    71  func (o *LiveRegistry) Close() error {
    72  	return nil
    73  }
    74  
    75  // LiveKey wraps a winregistry.Key to provide an implementation of the registry.Key interface.
    76  type LiveKey struct {
    77  	key  *winregistry.Key
    78  	name string
    79  }
    80  
    81  // Name returns the name of the key.
    82  func (o *LiveKey) Name() string {
    83  	return o.name
    84  }
    85  
    86  // Subkeys returns the opened subkeys of the key.
    87  // NOT SUPPORTED: This method would be too heavy. We can decide to revisit later if a strong use case
    88  // presents itself. Please use a combination of SubkeyNames() and OpenKey() tailored to your use
    89  // case instead.
    90  func (o *LiveKey) Subkeys() ([]Key, error) {
    91  	return nil, errors.New("not implemented on live registry: this method would be too heavy")
    92  }
    93  
    94  // SubkeyNames returns the names of the subkeys of the key.
    95  func (o *LiveKey) SubkeyNames() ([]string, error) {
    96  	return o.key.ReadSubKeyNames(0)
    97  }
    98  
    99  // Close closes the key.
   100  func (o *LiveKey) Close() error {
   101  	return o.key.Close()
   102  }
   103  
   104  // ClassName returns the class name of the key.
   105  // NOT SUPPORTED: This method is not supported on live registry as the library we use does not
   106  // provide this information and we do not have a use case for it.
   107  func (o *LiveKey) ClassName() ([]byte, error) {
   108  	return nil, errors.New("not supported: class name is not supported on live registry")
   109  }
   110  
   111  // Value returns the value with the given name.
   112  // The actual value is lazy loaded when Data() is called.
   113  func (o *LiveKey) Value(name string) (Value, error) {
   114  	return &LiveValue{
   115  		name: name,
   116  		key:  o.key,
   117  	}, nil
   118  }
   119  
   120  // ValueBytes directly returns the content (as bytes) of the named value.
   121  func (o *LiveKey) ValueBytes(name string) ([]byte, error) {
   122  	value, err := o.Value(name)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  
   127  	return value.Data()
   128  }
   129  
   130  // ValueString directly returns the content (as string) of the named value.
   131  func (o *LiveKey) ValueString(name string) (string, error) {
   132  	value, err := o.Value(name)
   133  	if err != nil {
   134  		return "", err
   135  	}
   136  
   137  	return value.DataString()
   138  }
   139  
   140  // Values returns the different values contained in the key.
   141  func (o *LiveKey) Values() ([]Value, error) {
   142  	valueNames, err := o.key.ReadValueNames(0)
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  
   147  	var values []Value
   148  	for _, valueName := range valueNames {
   149  		values = append(values, &LiveValue{
   150  			name: valueName,
   151  			key:  o.key,
   152  		})
   153  	}
   154  
   155  	return values, nil
   156  }
   157  
   158  // LiveValue wraps a winregistry.Value to provide an implementation of the registry.Value interface.
   159  type LiveValue struct {
   160  	name string
   161  	key  *winregistry.Key
   162  }
   163  
   164  // Name returns the name of the value.
   165  func (o *LiveValue) Name() string {
   166  	return o.name
   167  }
   168  
   169  // Data returns the data contained in the value as bytes.
   170  func (o *LiveValue) Data() ([]byte, error) {
   171  	size, _, err := o.key.GetValue(o.name, nil)
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	buffer := make([]byte, size)
   177  	if _, _, err = o.key.GetValue(o.name, buffer); err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	return buffer, nil
   182  }
   183  
   184  // DataString returns the data contained in the value as a string.
   185  func (o *LiveValue) DataString() (string, error) {
   186  	val, valtype, err := o.key.GetStringValue(o.name)
   187  	if (err == nil) || (valtype == winregistry.SZ || valtype == winregistry.EXPAND_SZ) {
   188  		return val, err
   189  	}
   190  
   191  	switch valtype {
   192  	case winregistry.DWORD, winregistry.DWORD_BIG_ENDIAN, winregistry.QWORD:
   193  		val, _, err := o.key.GetIntegerValue(o.name)
   194  		return strconv.FormatUint(val, 10), err
   195  	default:
   196  		return "", fmt.Errorf("unsupported value type: %v for value %q", valtype, o.name)
   197  	}
   198  }