mirror of https://github.com/restic/restic.git
vss: fix potential crash (not reachable in restic) (#3045)
HasSufficientPrivilegesForVSS() now returns an error
This commit is contained in:
parent
a06f5c28c0
commit
916b2d303b
|
@ -556,8 +556,8 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina
|
||||||
|
|
||||||
var targetFS fs.FS = fs.Local{}
|
var targetFS fs.FS = fs.Local{}
|
||||||
if runtime.GOOS == "windows" && opts.UseFsSnapshot {
|
if runtime.GOOS == "windows" && opts.UseFsSnapshot {
|
||||||
if !fs.HasSufficientPrivilegesForVSS() {
|
if err = fs.HasSufficientPrivilegesForVSS(); err != nil {
|
||||||
return errors.Fatal("user doesn't have sufficient privileges to use VSS snapshots\n")
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
errorHandler := func(item string, err error) error {
|
errorHandler := func(item string, err error) error {
|
||||||
|
|
|
@ -286,7 +286,7 @@ func TestBackup(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBackupWithFilesystemSnapshots(t *testing.T) {
|
func TestBackupWithFilesystemSnapshots(t *testing.T) {
|
||||||
if runtime.GOOS == "windows" && fs.HasSufficientPrivilegesForVSS() {
|
if runtime.GOOS == "windows" && fs.HasSufficientPrivilegesForVSS() == nil {
|
||||||
testBackup(t, true)
|
testBackup(t, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ type VssSnapshot struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasSufficientPrivilegesForVSS returns true if the user is allowed to use VSS.
|
// HasSufficientPrivilegesForVSS returns true if the user is allowed to use VSS.
|
||||||
func HasSufficientPrivilegesForVSS() bool {
|
func HasSufficientPrivilegesForVSS() error {
|
||||||
return false
|
return errors.New("VSS snapshots are only supported on windows")
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't
|
// NewVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't
|
||||||
|
|
|
@ -686,10 +686,10 @@ func (p *VssSnapshot) GetSnapshotDeviceObject() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeCOMInterface initialize an instance of the VSS COM api
|
// initializeCOMInterface initialize an instance of the VSS COM api
|
||||||
func initializeVssCOMInterface() (*ole.IUnknown, uintptr, error) {
|
func initializeVssCOMInterface() (*ole.IUnknown, error) {
|
||||||
vssInstance, err := loadIVssBackupComponentsConstructor()
|
vssInstance, err := loadIVssBackupComponentsConstructor()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure COM is initialized before use
|
// ensure COM is initialized before use
|
||||||
|
@ -697,22 +697,33 @@ func initializeVssCOMInterface() (*ole.IUnknown, uintptr, error) {
|
||||||
|
|
||||||
var oleIUnknown *ole.IUnknown
|
var oleIUnknown *ole.IUnknown
|
||||||
result, _, _ := vssInstance.Call(uintptr(unsafe.Pointer(&oleIUnknown)))
|
result, _, _ := vssInstance.Call(uintptr(unsafe.Pointer(&oleIUnknown)))
|
||||||
|
hresult := HRESULT(result)
|
||||||
|
|
||||||
return oleIUnknown, result, nil
|
switch hresult {
|
||||||
|
case S_OK:
|
||||||
|
case E_ACCESSDENIED:
|
||||||
|
return oleIUnknown, newVssError(
|
||||||
|
"The caller does not have sufficient backup privileges or is not an administrator",
|
||||||
|
hresult)
|
||||||
|
default:
|
||||||
|
return oleIUnknown, newVssError("Failed to create VSS instance", hresult)
|
||||||
|
}
|
||||||
|
|
||||||
|
if oleIUnknown == nil {
|
||||||
|
return nil, newVssError("Failed to initialize COM interface", hresult)
|
||||||
|
}
|
||||||
|
|
||||||
|
return oleIUnknown, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasSufficientPrivilegesForVSS returns true if the user is allowed to use VSS.
|
// HasSufficientPrivilegesForVSS returns nil if the user is allowed to use VSS.
|
||||||
func HasSufficientPrivilegesForVSS() bool {
|
func HasSufficientPrivilegesForVSS() error {
|
||||||
oleIUnknown, result, err := initializeVssCOMInterface()
|
oleIUnknown, err := initializeVssCOMInterface()
|
||||||
if oleIUnknown != nil {
|
if oleIUnknown != nil {
|
||||||
oleIUnknown.Release()
|
oleIUnknown.Release()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
return err
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return !(HRESULT(result) == E_ACCESSDENIED)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't
|
// NewVssSnapshot creates a new vss snapshot. If creating the snapshots doesn't
|
||||||
|
@ -734,24 +745,12 @@ func NewVssSnapshot(
|
||||||
|
|
||||||
timeoutInMillis := uint32(timeoutInSeconds * 1000)
|
timeoutInMillis := uint32(timeoutInSeconds * 1000)
|
||||||
|
|
||||||
oleIUnknown, result, err := initializeVssCOMInterface()
|
oleIUnknown, err := initializeVssCOMInterface()
|
||||||
if err != nil {
|
if oleIUnknown != nil {
|
||||||
if oleIUnknown != nil {
|
defer oleIUnknown.Release()
|
||||||
oleIUnknown.Release()
|
|
||||||
}
|
|
||||||
return VssSnapshot{}, err
|
|
||||||
}
|
}
|
||||||
defer oleIUnknown.Release()
|
if err != nil {
|
||||||
|
return VssSnapshot{}, err
|
||||||
switch HRESULT(result) {
|
|
||||||
case S_OK:
|
|
||||||
case E_ACCESSDENIED:
|
|
||||||
return VssSnapshot{}, newVssTextError(fmt.Sprintf("%s (%#x) The caller does not have "+
|
|
||||||
"sufficient backup privileges or is not an administrator.", HRESULT(result).Str(),
|
|
||||||
result))
|
|
||||||
default:
|
|
||||||
return VssSnapshot{}, newVssTextError(fmt.Sprintf("Failed to create VSS instance: %s (%#x)",
|
|
||||||
HRESULT(result).Str(), result))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
comInterface, err := queryInterface(oleIUnknown, UUID_IVSS)
|
comInterface, err := queryInterface(oleIUnknown, UUID_IVSS)
|
||||||
|
|
Loading…
Reference in New Issue