From 9b2fff1a6d3162d7312b595bbfd867d58bda42eb Mon Sep 17 00:00:00 2001 From: Gabriel Adrian Samfira Date: Fri, 18 Nov 2022 12:56:16 -0800 Subject: [PATCH] Fix copyFileInfo on Windows The c.chowner function was being ignored. This change makes use of the supplied chowner and calls Chown() on the file. If no chowner is specified, we copy over the DACL and owner information from the source. --- copy/copy_windows.go | 69 +++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/copy/copy_windows.go b/copy/copy_windows.go index 5e37e8e2..58f822d0 100644 --- a/copy/copy_windows.go +++ b/copy/copy_windows.go @@ -17,46 +17,61 @@ func getUIDGID(fi os.FileInfo) (uid, gid int) { return 0, 0 } -func (c *copier) copyFileInfo(fi os.FileInfo, src, name string) error { - if err := os.Chmod(name, fi.Mode()); err != nil { - return errors.Wrapf(err, "failed to chmod %s", name) - } - - // Copy file ownership and ACL - // We need SeRestorePrivilege and SeTakeOwnershipPrivilege in order - // to restore security info on a file, especially if we're trying to - // apply security info which includes SIDs not necessarily present on - // the host. - privileges := []string{winio.SeRestorePrivilege, seTakeOwnershipPrivilege} - if err := winio.EnableProcessPrivileges(privileges); err != nil { - return err - } - defer winio.DisableProcessPrivileges(privileges) - +func getFileSecurityInfo(name string) (*windows.SID, *windows.ACL, error) { secInfo, err := windows.GetNamedSecurityInfo( - src, windows.SE_FILE_OBJECT, + name, windows.SE_FILE_OBJECT, windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION) if err != nil { - return err + return nil, nil, errors.Wrap(err, "fetching security info") + } + sid, _, err := secInfo.Owner() + if err != nil { + return nil, nil, errors.Wrap(err, "fetching owner SID") } - dacl, _, err := secInfo.DACL() if err != nil { - return err + return nil, nil, errors.Wrap(err, "fetching dacl") } + return sid, dacl, nil +} - sid, _, err := secInfo.Owner() +func (c *copier) copyFileInfo(fi os.FileInfo, src, name string) error { + if err := os.Chmod(name, fi.Mode()); err != nil { + return errors.Wrapf(err, "failed to chmod %s", name) + } + + sid, dacl, err := getFileSecurityInfo(src) if err != nil { - return err + return errors.Wrap(err, "getting file info") } - if err := windows.SetNamedSecurityInfo( - name, windows.SE_FILE_OBJECT, - windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION, - sid, nil, dacl, nil); err != nil { + if c.chown != nil { + // Use the defined chowner. + usr := &User{SID: sid.String()} + if err := Chown(name, usr, c.chown); err != nil { + return errors.Wrapf(err, "failed to chown %s", name) + } + return nil + } else { + // Copy file ownership and ACL from the source file. + // We need SeRestorePrivilege and SeTakeOwnershipPrivilege in order + // to restore security info on a file, especially if we're trying to + // apply security info which includes SIDs not necessarily present on + // the host. + privileges := []string{winio.SeRestorePrivilege, seTakeOwnershipPrivilege} + if err := winio.EnableProcessPrivileges(privileges); err != nil { + return err + } + defer winio.DisableProcessPrivileges(privileges) - return err + if err := windows.SetNamedSecurityInfo( + name, windows.SE_FILE_OBJECT, + windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION, + sid, nil, dacl, nil); err != nil { + + return err + } } if err := c.copyFileTimestamp(fi, name); err != nil {