diff --git a/backuptar/tar.go b/backuptar/tar.go index cb461ca3..b9857432 100644 --- a/backuptar/tar.go +++ b/backuptar/tar.go @@ -14,6 +14,7 @@ import ( "strings" "syscall" "time" + "unsafe" "github.com/Microsoft/go-winio" "golang.org/x/sys/windows" @@ -330,32 +331,34 @@ func FileInfoFromHeader(hdr *tar.Header) (name string, size int64, fileInfo *win // tar file that was not processed, or io.EOF is there are no more. func WriteBackupStreamFromTarFile(w io.Writer, t *tar.Reader, hdr *tar.Header) (*tar.Header, error) { bw := winio.NewBackupStreamWriter(w) - var sd []byte + sd := &windows.SECURITY_DESCRIPTOR{} var err error // Maintaining old SDDL-based behavior for backward compatibility. All new tar headers written // by this library will have raw binary for the security descriptor. if sddl, ok := hdr.PAXRecords[hdrSecurityDescriptor]; ok { - sd, err = winio.SddlToSecurityDescriptor(sddl) + sd, err = windows.SecurityDescriptorFromString(sddl) if err != nil { return nil, err } } if sdraw, ok := hdr.PAXRecords[hdrRawSecurityDescriptor]; ok { - sd, err = base64.StdEncoding.DecodeString(sdraw) + sdAsByteSlice, err := base64.StdEncoding.DecodeString(sdraw) if err != nil { return nil, err } + sd = (*windows.SECURITY_DESCRIPTOR)(unsafe.Pointer(&sdAsByteSlice[0])) } - if len(sd) != 0 { + sdLen := sd.Length() + if sdLen != 0 { bhdr := winio.BackupHeader{ Id: winio.BackupSecurity, - Size: int64(len(sd)), + Size: int64(sdLen), } err := bw.WriteHeader(&bhdr) if err != nil { return nil, err } - _, err = bw.Write(sd) + _, err = bw.Write((*[(1 << 31) - 1]byte)(unsafe.Pointer(sd))[:sdLen]) if err != nil { return nil, err } diff --git a/backuptar/tar_test.go b/backuptar/tar_test.go index 8be0bf34..ceea7b7f 100644 --- a/backuptar/tar_test.go +++ b/backuptar/tar_test.go @@ -5,6 +5,7 @@ package backuptar import ( "archive/tar" "bytes" + "io" "io/ioutil" "os" "path/filepath" @@ -22,7 +23,7 @@ func ensurePresent(t *testing.T, m map[string]string, keys ...string) { } } -func TestRoundTrip(t *testing.T) { +func TestTarFileFromBackupStream(t *testing.T) { f, err := ioutil.TempFile("", "tst") if err != nil { t.Fatal(err) @@ -84,3 +85,79 @@ func TestRoundTrip(t *testing.T) { ensurePresent(t, hdr.PAXRecords, "MSWINDOWS.fileattr", "MSWINDOWS.rawsd") } + +func TestBackupStreamFromTar(t *testing.T) { + f, err := ioutil.TempFile("", "tst") + if err != nil { + t.Fatal(err) + } + defer f.Close() + defer os.Remove(f.Name()) + + expectedContent := "testing 1 2 3\n" + if _, err = f.Write([]byte(expectedContent)); err != nil { + t.Fatal(err) + } + + if _, err = f.Seek(0, 0); err != nil { + t.Fatal(err) + } + + fi, err := f.Stat() + if err != nil { + t.Fatal(err) + } + + bi, err := winio.GetFileBasicInfo(f) + if err != nil { + t.Fatal(err) + } + + br := winio.NewBackupFileReader(f, true) + defer br.Close() + + var buf bytes.Buffer + tw := tar.NewWriter(&buf) + err = WriteTarFileFromBackupStream(tw, br, f.Name(), fi.Size(), bi) + if err != nil { + t.Fatal(err) + } + + tarContentReader := tar.NewReader(&buf) + hdr2, err := tarContentReader.Next() + if err != nil { + t.Fatal(err) + } + var backupStreamBuf bytes.Buffer + _, err = WriteBackupStreamFromTarFile(&backupStreamBuf, tarContentReader, hdr2) + if err != nil && err != io.EOF { + t.Fatal(err) + } + + bsr := winio.NewBackupStreamReader(&backupStreamBuf) + + // read the first header that has security descriptor + _, err = bsr.Next() + if err != nil && err != io.EOF { + t.Fatal(err) + } + + // read header for contents + bhdr, err := bsr.Next() + if err != nil && err != io.EOF { + t.Fatal(err) + } + + resultBuf := make([]byte, int(bhdr.Size)) + written, err := bsr.Read(resultBuf) + if err != nil && err != io.EOF { + t.Fatal(err) + } + if int64(written) != bhdr.Size { + t.Fatal("unexpected size of read bytes for backup stream") + } + + if expectedContent != string(resultBuf) { + t.Fatalf("expected to read \"%v\" instead got \"%v\"", expectedContent, string(resultBuf)) + } +} diff --git a/go.mod b/go.mod index 98a8dea0..b4eddc6e 100644 --- a/go.mod +++ b/go.mod @@ -5,5 +5,5 @@ go 1.12 require ( github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.7.0 - golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c + golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 ) diff --git a/go.sum b/go.sum index aa6ad3b5..a45bc3ee 100644 --- a/go.sum +++ b/go.sum @@ -10,5 +10,5 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/pipe.go b/pipe.go index 96700a73..3fedbe7e 100644 --- a/pipe.go +++ b/pipe.go @@ -13,6 +13,8 @@ import ( "syscall" "time" "unsafe" + + "golang.org/x/sys/windows" ) //sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe @@ -35,7 +37,7 @@ type objectAttributes struct { RootDirectory uintptr ObjectName *unicodeString Attributes uintptr - SecurityDescriptor *securityDescriptor + SecurityDescriptor *windows.SECURITY_DESCRIPTOR SecurityQoS uintptr } @@ -45,16 +47,6 @@ type unicodeString struct { Buffer uintptr } -type securityDescriptor struct { - Revision byte - Sbz1 byte - Control uint16 - Owner uintptr - Group uintptr - Sacl uintptr - Dacl uintptr -} - type ntstatus int32 func (status ntstatus) Err() error { @@ -82,8 +74,6 @@ const ( cFILE_PIPE_MESSAGE_TYPE = 1 cFILE_PIPE_REJECT_REMOTE_CLIENTS = 2 - - cSE_DACL_PRESENT = 4 ) var ( @@ -273,7 +263,7 @@ type win32PipeListener struct { doneCh chan int } -func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (syscall.Handle, error) { +func makeServerPipeHandle(path string, sd *windows.SECURITY_DESCRIPTOR, c *PipeConfig, first bool) (syscall.Handle, error) { path16, err := syscall.UTF16FromString(path) if err != nil { return 0, &os.PathError{Op: "open", Path: path, Err: err} @@ -286,29 +276,25 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy if err := rtlDosPathNameToNtPathName(&path16[0], &ntPath, 0, 0).Err(); err != nil { return 0, &os.PathError{Op: "open", Path: path, Err: err} } - defer localFree(ntPath.Buffer) + defer windows.LocalFree(windows.Handle(ntPath.Buffer)) oa.ObjectName = &ntPath // The security descriptor is only needed for the first pipe. if first { if sd != nil { - len := uint32(len(sd)) - sdb := localAlloc(0, len) - defer localFree(sdb) - copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd) - oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb)) + oa.SecurityDescriptor = sd } else { // Construct the default named pipe security descriptor. - var dacl uintptr - if err := rtlDefaultNpAcl(&dacl).Err(); err != nil { + dacl := &windows.ACL{} + if err := windows.RtlDefaultNpAcl(&dacl); err != nil { return 0, fmt.Errorf("getting default named pipe ACL: %s", err) } - defer localFree(dacl) - - sdb := &securityDescriptor{ - Revision: 1, - Control: cSE_DACL_PRESENT, - Dacl: dacl, + sdb, err := windows.NewSecurityDescriptor() + if err != nil { + return 0, err + } + if err := sdb.SetDACL(dacl, true, true); err != nil { + return 0, err } oa.SecurityDescriptor = sdb } @@ -440,14 +426,14 @@ type PipeConfig struct { // The pipe must not already exist. func ListenPipe(path string, c *PipeConfig) (net.Listener, error) { var ( - sd []byte + sd *windows.SECURITY_DESCRIPTOR err error ) if c == nil { c = &PipeConfig{} } if c.SecurityDescriptor != "" { - sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor) + sd, err = windows.SecurityDescriptorFromString(c.SecurityDescriptor) if err != nil { return nil, err } diff --git a/vhd/vhd.go b/vhd/vhd.go index b03b789e..5f5472c5 100644 --- a/vhd/vhd.go +++ b/vhd/vhd.go @@ -13,9 +13,9 @@ import ( //go:generate go run mksyscall_windows.go -output zvhd_windows.go vhd.go -//sys createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.CreateVirtualDisk +//sys createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *windows.SECURITY_DESCRIPTOR, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.CreateVirtualDisk //sys openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.OpenVirtualDisk -//sys attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) [failretval != 0] = virtdisk.AttachVirtualDisk +//sys attachVirtualDisk(handle syscall.Handle, securityDescriptor *windows.SECURITY_DESCRIPTOR, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) [failretval != 0] = virtdisk.AttachVirtualDisk //sys detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (err error) [failretval != 0] = virtdisk.DetachVirtualDisk //sys getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (err error) [failretval != 0] = virtdisk.GetVirtualDiskPhysicalPath diff --git a/vhd/zvhd_windows.go b/vhd/zvhd_windows.go index 572f7b42..4c97678a 100644 --- a/vhd/zvhd_windows.go +++ b/vhd/zvhd_windows.go @@ -47,7 +47,7 @@ var ( procOpenVirtualDisk = modvirtdisk.NewProc("OpenVirtualDisk") ) -func attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) { +func attachVirtualDisk(handle syscall.Handle, securityDescriptor *windows.SECURITY_DESCRIPTOR, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) { r1, _, e1 := syscall.Syscall6(procAttachVirtualDisk.Addr(), 6, uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped))) if r1 != 0 { err = errnoErr(e1) @@ -55,7 +55,7 @@ func attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attac return } -func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) { +func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *windows.SECURITY_DESCRIPTOR, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) { var _p0 *uint16 _p0, err = syscall.UTF16PtrFromString(path) if err != nil { @@ -64,7 +64,7 @@ func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virt return _createVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, securityDescriptor, createVirtualDiskFlags, providerSpecificFlags, parameters, overlapped, handle) } -func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) { +func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *windows.SECURITY_DESCRIPTOR, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) { r1, _, e1 := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(createVirtualDiskFlags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(handle))) if r1 != 0 { err = errnoErr(e1)