hakurei/system/acl.go
Ophestra cf38a00ecc
All checks were successful
Test / Flake checks (push) Successful in 1m40s
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m24s
Test / Hakurei (push) Successful in 3m18s
Test / Hpkg (push) Successful in 4m11s
Test / Sandbox (race detector) (push) Successful in 4m23s
Test / Hakurei (race detector) (push) Successful in 5m4s
app: set up acl on X11 socket
The socket is typically owned by the priv-user, and inaccessible by the target user, so just allowing access to the directory is not enough. This change fixes this oversight and add checks that will also be useful for merging #1.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2025-08-18 02:27:52 +09:00

94 lines
2.1 KiB
Go

package system
import (
"errors"
"fmt"
"os"
"slices"
"hakurei.app/system/acl"
)
// UpdatePerm appends an ephemeral acl update Op.
func (sys *I) UpdatePerm(path string, perms ...acl.Perm) *I {
sys.UpdatePermType(Process, path, perms...)
return sys
}
// UpdatePermType appends an acl update Op.
func (sys *I) UpdatePermType(et Enablement, path string, perms ...acl.Perm) *I {
sys.lock.Lock()
defer sys.lock.Unlock()
sys.ops = append(sys.ops, &ACL{et, path, perms, false})
return sys
}
// UpdatePermTypeOptional appends an acl update Op that silently continues if the target does not exist.
func (sys *I) UpdatePermTypeOptional(et Enablement, path string, perms ...acl.Perm) *I {
sys.lock.Lock()
defer sys.lock.Unlock()
sys.ops = append(sys.ops, &ACL{et, path, perms, true})
return sys
}
type ACL struct {
et Enablement
path string
perms acl.Perms
// since revert operations are cross-process, the success of apply must not affect the outcome of revert
skipNotExist bool
}
func (a *ACL) Type() Enablement { return a.et }
func (a *ACL) apply(sys *I) error {
msg.Verbose("applying ACL", a)
if err := acl.Update(a.path, sys.uid, a.perms...); err != nil {
if !a.skipNotExist || !os.IsNotExist(err) {
return wrapErrSuffix(err,
fmt.Sprintf("cannot apply ACL entry to %q:", a.path))
}
msg.Verbosef("path %q does not exist", a.path)
return nil
}
return nil
}
func (a *ACL) revert(sys *I, ec *Criteria) error {
if ec.hasType(a) {
msg.Verbose("stripping ACL", a)
err := acl.Update(a.path, sys.uid)
if errors.Is(err, os.ErrNotExist) {
// the ACL is effectively stripped if the file no longer exists
msg.Verbosef("target of ACL %s no longer exists", a)
err = nil
}
return wrapErrSuffix(err,
fmt.Sprintf("cannot strip ACL entry from %q:", a.path))
} else {
msg.Verbose("skipping ACL", a)
return nil
}
}
func (a *ACL) Is(o Op) bool {
a0, ok := o.(*ACL)
return ok && a0 != nil &&
a.et == a0.et &&
a.path == a0.path &&
slices.Equal(a.perms, a0.perms)
}
func (a *ACL) Path() string { return a.path }
func (a *ACL) String() string {
return fmt.Sprintf("%s type: %s path: %q",
a.perms, TypeString(a.et), a.path)
}