//go:build windows // +build windows package fs import ( "os/user" "testing" "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/test" "golang.org/x/sys/windows" ) var ( testFileSDs = []string{"AQAUvBQAAAAwAAAAAAAAAEwAAAABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvqAwAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIAfAAEAAAAAAAkAKkAEgABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvtAwAAABAUAP8BHwABAQAAAAAABRIAAAAAEBgA/wEfAAECAAAAAAAFIAAAACACAAAAECQA/wEfAAEFAAAAAAAFFQAAAIifWK5WoILqzL0mq+oDAAA=", "AQAUvBQAAAAwAAAAAAAAAEwAAAABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvqAwAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIAyAAHAAAAAAAUAKkAEgABAQAAAAAABQcAAAAAABQAiQASAAEBAAAAAAAFBwAAAAAAJACpABIAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSar7QMAAAAAJAC/ARMAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSar6gMAAAAAFAD/AR8AAQEAAAAAAAUSAAAAAAAYAP8BHwABAgAAAAAABSAAAAAgAgAAAAAkAP8BHwABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvqAwAA", "AQAUvBQAAAAwAAAA7AAAAEwAAAABBQAAAAAABRUAAAAvr7t03PyHGk2FokNHCAAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIAoAAFAAAAAAAkAP8BHwABBQAAAAAABRUAAAAvr7t03PyHGk2FokNHCAAAAAAkAKkAEgABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvtAwAAABAUAP8BHwABAQAAAAAABRIAAAAAEBgA/wEfAAECAAAAAAAFIAAAACACAAAAECQA/wEfAAEFAAAAAAAFFQAAAIifWK5WoILqzL0mq+oDAAACAHQAAwAAAAKAJAC/AQIAAQUAAAAAAAUVAAAAL6+7dNz8hxpNhaJDtgQAAALAJAC/AQMAAQUAAAAAAAUVAAAAL6+7dNz8hxpNhaJDPgkAAAJAJAD/AQ8AAQUAAAAAAAUVAAAAL6+7dNz8hxpNhaJDtQQAAA==", } testDirSDs = []string{"AQAUvBQAAAAwAAAAAAAAAEwAAAABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvqAwAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIAfAAEAAAAAAAkAKkAEgABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvtAwAAABMUAP8BHwABAQAAAAAABRIAAAAAExgA/wEfAAECAAAAAAAFIAAAACACAAAAEyQA/wEfAAEFAAAAAAAFFQAAAIifWK5WoILqzL0mq+oDAAA=", "AQAUvBQAAAAwAAAAAAAAAEwAAAABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvqAwAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIA3AAIAAAAAAIUAKkAEgABAQAAAAAABQcAAAAAAxQAiQASAAEBAAAAAAAFBwAAAAAAJACpABIAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSar7QMAAAAAJAC/ARMAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSar6gMAAAALFAC/ARMAAQEAAAAAAAMAAAAAABMUAP8BHwABAQAAAAAABRIAAAAAExgA/wEfAAECAAAAAAAFIAAAACACAAAAEyQA/wEfAAEFAAAAAAAFFQAAAIifWK5WoILqzL0mq+oDAAA=", "AQAUvBQAAAAwAAAA7AAAAEwAAAABBQAAAAAABRUAAAAvr7t03PyHGk2FokNHCAAAAQUAAAAAAAUVAAAAiJ9YrlaggurMvSarAQIAAAIAoAAFAAAAAAAkAP8BHwABBQAAAAAABRUAAAAvr7t03PyHGk2FokNHCAAAAAAkAKkAEgABBQAAAAAABRUAAACIn1iuVqCC6sy9JqvtAwAAABMUAP8BHwABAQAAAAAABRIAAAAAExgA/wEfAAECAAAAAAAFIAAAACACAAAAEyQA/wEfAAEFAAAAAAAFFQAAAIifWK5WoILqzL0mq+oDAAACAHQAAwAAAAKAJAC/AQIAAQUAAAAAAAUVAAAAL6+7dNz8hxpNhaJDtgQAAALAJAC/AQMAAQUAAAAAAAUVAAAAL6+7dNz8hxpNhaJDPgkAAAJAJAD/AQ8AAQUAAAAAAAUVAAAAL6+7dNz8hxpNhaJDtQQAAA==", } ) // isAdmin checks if current user is an administrator. func isAdmin() (isAdmin bool, err error) { var sid *windows.SID err = windows.AllocateAndInitializeSid(&windows.SECURITY_NT_AUTHORITY, 2, windows.SECURITY_BUILTIN_DOMAIN_RID, windows.DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &sid) if err != nil { return false, errors.Errorf("sid error: %s", err) } windows.GetCurrentProcessToken() token := windows.Token(0) member, err := token.IsMember(sid) if err != nil { return false, errors.Errorf("token membership error: %s", err) } return member, nil } // compareSecurityDescriptors runs tests for comparing 2 security descriptors in []byte format. func compareSecurityDescriptors(t *testing.T, testPath string, sdInputBytes, sdOutputBytes []byte) { sdInput, err := securityDescriptorBytesToStruct(sdInputBytes) test.OK(t, errors.Wrapf(err, "Error converting SD to struct for: %s", testPath)) sdOutput, err := securityDescriptorBytesToStruct(sdOutputBytes) test.OK(t, errors.Wrapf(err, "Error converting SD to struct for: %s", testPath)) isAdmin, err := isAdmin() test.OK(t, errors.Wrapf(err, "Error checking if user is admin: %s", testPath)) var ownerExpected *windows.SID var defaultedOwnerExpected bool var groupExpected *windows.SID var defaultedGroupExpected bool var daclExpected *windows.ACL var defaultedDaclExpected bool var saclExpected *windows.ACL var defaultedSaclExpected bool // The Dacl is set correctly whether or not application is running as admin. daclExpected, defaultedDaclExpected, err = sdInput.DACL() test.OK(t, errors.Wrapf(err, "Error getting input dacl for: %s", testPath)) if isAdmin { // If application is running as admin, all sd values including owner, group, dacl, sacl are set correctly during restore. // Hence we will use the input values for comparison with the output values. ownerExpected, defaultedOwnerExpected, err = sdInput.Owner() test.OK(t, errors.Wrapf(err, "Error getting input owner for: %s", testPath)) groupExpected, defaultedGroupExpected, err = sdInput.Group() test.OK(t, errors.Wrapf(err, "Error getting input group for: %s", testPath)) saclExpected, defaultedSaclExpected, err = sdInput.SACL() test.OK(t, errors.Wrapf(err, "Error getting input sacl for: %s", testPath)) } else { // If application is not running as admin, owner and group are set as current user's SID/GID during restore and sacl is empty. // Get the current user user, err := user.Current() test.OK(t, errors.Wrapf(err, "Could not get current user for: %s", testPath)) // Get current user's SID currentUserSID, err := windows.StringToSid(user.Uid) test.OK(t, errors.Wrapf(err, "Error getting output group for: %s", testPath)) // Get current user's Group SID currentGroupSID, err := windows.StringToSid(user.Gid) test.OK(t, errors.Wrapf(err, "Error getting output group for: %s", testPath)) // Set owner and group as current user's SID and GID during restore. ownerExpected = currentUserSID defaultedOwnerExpected = false groupExpected = currentGroupSID defaultedGroupExpected = false // If application is not running as admin, SACL is returned empty. saclExpected = nil defaultedSaclExpected = false } // Now do all the comparisons // Get owner SID from output file ownerOut, defaultedOwnerOut, err := sdOutput.Owner() test.OK(t, errors.Wrapf(err, "Error getting output owner for: %s", testPath)) // Compare owner SIDs. We must use the Equals method for comparison as a syscall is made for comparing SIDs. test.Assert(t, ownerExpected.Equals(ownerOut), "Owner from SDs read from test path don't match: %s, cur:%s, exp: %s", testPath, ownerExpected.String(), ownerOut.String()) test.Equals(t, defaultedOwnerExpected, defaultedOwnerOut, "Defaulted for owner from SDs read from test path don't match: %s", testPath) // Get group SID from output file groupOut, defaultedGroupOut, err := sdOutput.Group() test.OK(t, errors.Wrapf(err, "Error getting output group for: %s", testPath)) // Compare group SIDs. We must use the Equals method for comparison as a syscall is made for comparing SIDs. test.Assert(t, groupExpected.Equals(groupOut), "Group from SDs read from test path don't match: %s, cur:%s, exp: %s", testPath, groupExpected.String(), groupOut.String()) test.Equals(t, defaultedGroupExpected, defaultedGroupOut, "Defaulted for group from SDs read from test path don't match: %s", testPath) // Get dacl from output file daclOut, defaultedDaclOut, err := sdOutput.DACL() test.OK(t, errors.Wrapf(err, "Error getting output dacl for: %s", testPath)) // Compare dacls test.Equals(t, daclExpected, daclOut, "DACL from SDs read from test path don't match: %s", testPath) test.Equals(t, defaultedDaclExpected, defaultedDaclOut, "Defaulted for DACL from SDs read from test path don't match: %s", testPath) // Get sacl from output file saclOut, defaultedSaclOut, err := sdOutput.SACL() test.OK(t, errors.Wrapf(err, "Error getting output sacl for: %s", testPath)) // Compare sacls test.Equals(t, saclExpected, saclOut, "DACL from SDs read from test path don't match: %s", testPath) test.Equals(t, defaultedSaclExpected, defaultedSaclOut, "Defaulted for SACL from SDs read from test path don't match: %s", testPath) }