//go:build windows package authstorage import ( "encoding/base64" "os" "path/filepath" "runtime" "testing" "github.com/aritmolab/thothii/tools/tht/internal/safeio" "golang.org/x/sys/windows" ) func TestProtocolCreatesRecordsWithOwnerOnlyDACLAndRejectsReparseRoot(t *testing.T) { root := filepath.Join(t.TempDir(), "auth") filename := "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.json" runRequest(t, request{Version: 1, Operation: "create", Root: root, Directory: "sessions", Filename: filename, ContentBase64: base64.StdEncoding.EncodeToString([]byte("private"))}) if err := safeio.ValidatePrivateDirectory(root); err != nil { t.Fatalf("root DACL = %v", err) } if err := safeio.ValidatePrivateDirectory(filepath.Join(root, "sessions")); err != nil { t.Fatalf("sessions DACL = %v", err) } if err := safeio.ValidatePrivateRegular(filepath.Join(root, "sessions", filename)); err != nil { t.Fatalf("record DACL = %v", err) } } func TestProtocolRejectsPermissiveDACLAndReparseRoot(t *testing.T) { root := filepath.Join(t.TempDir(), "auth") filename := "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff.json" runRequest(t, request{Version: 1, Operation: "create", Root: root, Directory: "sessions", Filename: filename, ContentBase64: base64.StdEncoding.EncodeToString([]byte("private"))}) path := filepath.Join(root, "sessions", filename) if err := setPermissiveDACL(path); err != nil { t.Fatal(err) } runRejected(t, request{Version: 1, Operation: "read", Root: root, Directory: "sessions", Filename: filename}) linkedRoot := filepath.Join(t.TempDir(), "reparse-auth") if err := os.Symlink(root, linkedRoot); err != nil { t.Skipf("Windows host does not permit test symlink creation: %v", err) } runRejected(t, request{Version: 1, Operation: "create", Root: linkedRoot, Directory: "sessions", Filename: filename, ContentBase64: base64.StdEncoding.EncodeToString([]byte("private"))}) } func setPermissiveDACL(path string) error { world, err := windows.StringToSid("S-1-1-0") if err != nil { return err } var pinner runtime.Pinner pinner.Pin(world) defer pinner.Unpin() acl, err := windows.ACLFromEntries([]windows.EXPLICIT_ACCESS{{ AccessPermissions: windows.GENERIC_READ | windows.GENERIC_WRITE, AccessMode: windows.GRANT_ACCESS, Trustee: windows.TRUSTEE{ TrusteeForm: windows.TRUSTEE_IS_SID, TrusteeType: windows.TRUSTEE_IS_GROUP, TrusteeValue: windows.TrusteeValueFromSID(world), }, }}, nil) if err != nil { return err } return windows.SetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION, nil, nil, acl, nil) }