aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--acl/acl.go202
-rw-r--r--acl/acl_test.go8
-rw-r--r--acl/c.go196
-rw-r--r--acl/perms.go18
-rw-r--r--system/acl.go4
-rw-r--r--system/wayland.go2
6 files changed, 215 insertions, 215 deletions
diff --git a/acl/acl.go b/acl/acl.go
index 8b775688..fe355612 100644
--- a/acl/acl.go
+++ b/acl/acl.go
@@ -1,19 +1,197 @@
// Package acl implements simple ACL manipulation via libacl.
package acl
-type Perms []Perm
+import (
+ "errors"
+ "runtime"
+ "syscall"
+ "unsafe"
+)
-func (ps Perms) String() string {
- var s = []byte("---")
- for _, p := range ps {
- switch p {
- case Read:
- s[0] = 'r'
- case Write:
- s[1] = 'w'
- case Execute:
- s[2] = 'x'
+/*
+#cgo linux pkg-config: --static libacl
+
+#include <stdlib.h>
+#include <sys/acl.h>
+#include <acl/libacl.h>
+
+static acl_t _go_acl_get_file(const char *path_p, acl_type_t type) {
+ acl_t acl = acl_get_file(path_p, type);
+ free((void *)path_p);
+ return acl;
+}
+
+static int _go_acl_set_file(const char *path_p, acl_type_t type, acl_t acl) {
+ if (acl_valid(acl) != 0) {
+ return -1;
+ }
+
+ int ret = acl_set_file(path_p, type, acl);
+ free((void *)path_p);
+ return ret;
+}
+*/
+import "C"
+
+func getFile(name string, t C.acl_type_t) (*ACL, error) {
+ a, err := C._go_acl_get_file(C.CString(name), t)
+ if errors.Is(err, syscall.ENODATA) {
+ err = nil
+ }
+
+ return newACL(a), err
+}
+
+func (acl *ACL) setFile(name string, t C.acl_type_t) error {
+ _, err := C._go_acl_set_file(C.CString(name), t, acl.acl)
+ return err
+}
+
+func newACL(a C.acl_t) *ACL {
+ acl := &ACL{a}
+ runtime.SetFinalizer(acl, (*ACL).free)
+ return acl
+}
+
+type ACL struct {
+ acl C.acl_t
+}
+
+func (acl *ACL) free() {
+ C.acl_free(unsafe.Pointer(acl.acl))
+
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(acl, nil)
+}
+
+const (
+ Read = C.ACL_READ
+ Write = C.ACL_WRITE
+ Execute = C.ACL_EXECUTE
+
+ TypeDefault = C.ACL_TYPE_DEFAULT
+ TypeAccess = C.ACL_TYPE_ACCESS
+
+ UndefinedTag = C.ACL_UNDEFINED_TAG
+ UserObj = C.ACL_USER_OBJ
+ User = C.ACL_USER
+ GroupObj = C.ACL_GROUP_OBJ
+ Group = C.ACL_GROUP
+ Mask = C.ACL_MASK
+ Other = C.ACL_OTHER
+)
+
+type (
+ Perm C.acl_perm_t
+)
+
+func (acl *ACL) removeEntry(tt C.acl_tag_t, tq int) error {
+ var e C.acl_entry_t
+
+ // get first entry
+ if r, err := C.acl_get_entry(acl.acl, C.ACL_FIRST_ENTRY, &e); err != nil {
+ return err
+ } else if r == 0 {
+ // return on acl with no entries
+ return nil
+ }
+
+ for {
+ if r, err := C.acl_get_entry(acl.acl, C.ACL_NEXT_ENTRY, &e); err != nil {
+ return err
+ } else if r == 0 {
+ // return on drained acl
+ return nil
+ }
+
+ var (
+ q int
+ t C.acl_tag_t
+ )
+
+ // get current entry tag type
+ if _, err := C.acl_get_tag_type(e, &t); err != nil {
+ return err
+ }
+
+ // get current entry qualifier
+ if rq, err := C.acl_get_qualifier(e); err != nil {
+ // neither ACL_USER nor ACL_GROUP
+ if errors.Is(err, syscall.EINVAL) {
+ continue
+ }
+
+ return err
+ } else {
+ q = *(*int)(rq)
+ C.acl_free(rq)
+ }
+
+ // delete on match
+ if t == tt && q == tq {
+ _, err := C.acl_delete_entry(acl.acl, e)
+ return err
+ }
+ }
+}
+
+// Update replaces ACL_USER entry with qualifier uid.
+func Update(name string, uid int, perms ...Perm) error {
+ // read acl from file
+ a, err := getFile(name, TypeAccess)
+ if err != nil {
+ return err
+ }
+ // free acl on return if get is successful
+ defer a.free()
+
+ // remove existing entry
+ if err = a.removeEntry(User, uid); err != nil {
+ return err
+ }
+
+ // create new entry if perms are passed
+ if len(perms) > 0 {
+ // create new acl entry
+ var e C.acl_entry_t
+ if _, err = C.acl_create_entry(&a.acl, &e); err != nil {
+ return err
+ }
+
+ // get perm set of new entry
+ var p C.acl_permset_t
+ if _, err = C.acl_get_permset(e, &p); err != nil {
+ return err
+ }
+
+ // add target perms
+ for _, perm := range perms {
+ if _, err = C.acl_add_perm(p, C.acl_perm_t(perm)); err != nil {
+ return err
+ }
+ }
+
+ // set perm set to new entry
+ if _, err = C.acl_set_permset(e, p); err != nil {
+ return err
+ }
+
+ // set user tag to new entry
+ if _, err = C.acl_set_tag_type(e, User); err != nil {
+ return err
+ }
+
+ // set qualifier (uid) to new entry
+ if _, err = C.acl_set_qualifier(e, unsafe.Pointer(&uid)); err != nil {
+ return err
}
}
- return string(s)
+
+ // calculate mask after update
+ if _, err = C.acl_calc_mask(&a.acl); err != nil {
+ return err
+ }
+
+ // write acl to file
+ return a.setFile(name, TypeAccess)
}
diff --git a/acl/acl_test.go b/acl/acl_test.go
index 07acfdb9..9944b8ab 100644
--- a/acl/acl_test.go
+++ b/acl/acl_test.go
@@ -47,7 +47,7 @@ func TestUpdatePerm(t *testing.T) {
})
t.Run("default clear mask", func(t *testing.T) {
- if err := acl.UpdatePerm(testFilePath, uid); err != nil {
+ if err := acl.Update(testFilePath, uid); err != nil {
t.Fatalf("UpdatePerm: error = %v", err)
}
if cur = getfacl(t, testFilePath); len(cur) != 4 {
@@ -56,7 +56,7 @@ func TestUpdatePerm(t *testing.T) {
})
t.Run("default clear consistency", func(t *testing.T) {
- if err := acl.UpdatePerm(testFilePath, uid); err != nil {
+ if err := acl.Update(testFilePath, uid); err != nil {
t.Fatalf("UpdatePerm: error = %v", err)
}
if val := getfacl(t, testFilePath); !reflect.DeepEqual(val, cur) {
@@ -76,7 +76,7 @@ func TestUpdatePerm(t *testing.T) {
func testUpdate(t *testing.T, testFilePath, name string, cur []*getFAclResp, val fAclPerm, perms ...acl.Perm) {
t.Run(name, func(t *testing.T) {
t.Cleanup(func() {
- if err := acl.UpdatePerm(testFilePath, uid); err != nil {
+ if err := acl.Update(testFilePath, uid); err != nil {
t.Fatalf("UpdatePerm: error = %v", err)
}
if v := getfacl(t, testFilePath); !reflect.DeepEqual(v, cur) {
@@ -84,7 +84,7 @@ func testUpdate(t *testing.T, testFilePath, name string, cur []*getFAclResp, val
}
})
- if err := acl.UpdatePerm(testFilePath, uid, perms...); err != nil {
+ if err := acl.Update(testFilePath, uid, perms...); err != nil {
t.Fatalf("UpdatePerm: error = %v", err)
}
r := respByCred(getfacl(t, testFilePath), fAclTypeUser, cred)
diff --git a/acl/c.go b/acl/c.go
deleted file mode 100644
index 7609e142..00000000
--- a/acl/c.go
+++ /dev/null
@@ -1,196 +0,0 @@
-package acl
-
-import "C"
-import (
- "errors"
- "runtime"
- "syscall"
- "unsafe"
-)
-
-/*
-#cgo linux pkg-config: --static libacl
-
-#include <stdlib.h>
-#include <sys/acl.h>
-#include <acl/libacl.h>
-
-static acl_t _go_acl_get_file(const char *path_p, acl_type_t type) {
- acl_t acl = acl_get_file(path_p, type);
- free((void *)path_p);
- return acl;
-}
-
-static int _go_acl_set_file(const char *path_p, acl_type_t type, acl_t acl) {
- if (acl_valid(acl) != 0) {
- return -1;
- }
-
- int ret = acl_set_file(path_p, type, acl);
- free((void *)path_p);
- return ret;
-}
-*/
-import "C"
-
-func getFile(name string, t C.acl_type_t) (*ACL, error) {
- a, err := C._go_acl_get_file(C.CString(name), t)
- if errors.Is(err, syscall.ENODATA) {
- err = nil
- }
-
- return newACL(a), err
-}
-
-func (acl *ACL) setFile(name string, t C.acl_type_t) error {
- _, err := C._go_acl_set_file(C.CString(name), t, acl.acl)
- return err
-}
-
-func newACL(a C.acl_t) *ACL {
- acl := &ACL{a}
- runtime.SetFinalizer(acl, (*ACL).free)
- return acl
-}
-
-type ACL struct {
- acl C.acl_t
-}
-
-func (acl *ACL) free() {
- C.acl_free(unsafe.Pointer(acl.acl))
-
- // no need for a finalizer anymore
- runtime.SetFinalizer(acl, nil)
-}
-
-const (
- Read = C.ACL_READ
- Write = C.ACL_WRITE
- Execute = C.ACL_EXECUTE
-
- TypeDefault = C.ACL_TYPE_DEFAULT
- TypeAccess = C.ACL_TYPE_ACCESS
-
- UndefinedTag = C.ACL_UNDEFINED_TAG
- UserObj = C.ACL_USER_OBJ
- User = C.ACL_USER
- GroupObj = C.ACL_GROUP_OBJ
- Group = C.ACL_GROUP
- Mask = C.ACL_MASK
- Other = C.ACL_OTHER
-)
-
-type (
- Perm C.acl_perm_t
-)
-
-func (acl *ACL) removeEntry(tt C.acl_tag_t, tq int) error {
- var e C.acl_entry_t
-
- // get first entry
- if r, err := C.acl_get_entry(acl.acl, C.ACL_FIRST_ENTRY, &e); err != nil {
- return err
- } else if r == 0 {
- // return on acl with no entries
- return nil
- }
-
- for {
- if r, err := C.acl_get_entry(acl.acl, C.ACL_NEXT_ENTRY, &e); err != nil {
- return err
- } else if r == 0 {
- // return on drained acl
- return nil
- }
-
- var (
- q int
- t C.acl_tag_t
- )
-
- // get current entry tag type
- if _, err := C.acl_get_tag_type(e, &t); err != nil {
- return err
- }
-
- // get current entry qualifier
- if rq, err := C.acl_get_qualifier(e); err != nil {
- // neither ACL_USER nor ACL_GROUP
- if errors.Is(err, syscall.EINVAL) {
- continue
- }
-
- return err
- } else {
- q = *(*int)(rq)
- C.acl_free(rq)
- }
-
- // delete on match
- if t == tt && q == tq {
- _, err := C.acl_delete_entry(acl.acl, e)
- return err
- }
- }
-}
-
-func UpdatePerm(name string, uid int, perms ...Perm) error {
- // read acl from file
- a, err := getFile(name, TypeAccess)
- if err != nil {
- return err
- }
- // free acl on return if get is successful
- defer a.free()
-
- // remove existing entry
- if err = a.removeEntry(User, uid); err != nil {
- return err
- }
-
- // create new entry if perms are passed
- if len(perms) > 0 {
- // create new acl entry
- var e C.acl_entry_t
- if _, err = C.acl_create_entry(&a.acl, &e); err != nil {
- return err
- }
-
- // get perm set of new entry
- var p C.acl_permset_t
- if _, err = C.acl_get_permset(e, &p); err != nil {
- return err
- }
-
- // add target perms
- for _, perm := range perms {
- if _, err = C.acl_add_perm(p, C.acl_perm_t(perm)); err != nil {
- return err
- }
- }
-
- // set perm set to new entry
- if _, err = C.acl_set_permset(e, p); err != nil {
- return err
- }
-
- // set user tag to new entry
- if _, err = C.acl_set_tag_type(e, User); err != nil {
- return err
- }
-
- // set qualifier (uid) to new entry
- if _, err = C.acl_set_qualifier(e, unsafe.Pointer(&uid)); err != nil {
- return err
- }
- }
-
- // calculate mask after update
- if _, err = C.acl_calc_mask(&a.acl); err != nil {
- return err
- }
-
- // write acl to file
- return a.setFile(name, TypeAccess)
-}
diff --git a/acl/perms.go b/acl/perms.go
new file mode 100644
index 00000000..fbc99e82
--- /dev/null
+++ b/acl/perms.go
@@ -0,0 +1,18 @@
+package acl
+
+type Perms []Perm
+
+func (ps Perms) String() string {
+ var s = []byte("---")
+ for _, p := range ps {
+ switch p {
+ case Read:
+ s[0] = 'r'
+ case Write:
+ s[1] = 'w'
+ case Execute:
+ s[2] = 'x'
+ }
+ }
+ return string(s)
+}
diff --git a/system/acl.go b/system/acl.go
index 840c3971..8cd49cbd 100644
--- a/system/acl.go
+++ b/system/acl.go
@@ -34,14 +34,14 @@ func (a *ACL) Type() Enablement { return a.et }
func (a *ACL) apply(sys *I) error {
sys.println("applying ACL", a)
- return sys.wrapErrSuffix(acl.UpdatePerm(a.path, sys.uid, a.perms...),
+ return sys.wrapErrSuffix(acl.Update(a.path, sys.uid, a.perms...),
fmt.Sprintf("cannot apply ACL entry to %q:", a.path))
}
func (a *ACL) revert(sys *I, ec *Criteria) error {
if ec.hasType(a) {
sys.println("stripping ACL", a)
- return sys.wrapErrSuffix(acl.UpdatePerm(a.path, sys.uid),
+ return sys.wrapErrSuffix(acl.Update(a.path, sys.uid),
fmt.Sprintf("cannot strip ACL entry from %q:", a.path))
} else {
sys.println("skipping ACL", a)
diff --git a/system/wayland.go b/system/wayland.go
index 11f54d80..70b7dbd2 100644
--- a/system/wayland.go
+++ b/system/wayland.go
@@ -58,7 +58,7 @@ func (w *Wayland) apply(sys *I) error {
} else {
*w.sync = sp
sys.printf("wayland listening on %q", w.dst)
- return sys.wrapErrSuffix(errors.Join(os.Chmod(w.dst, 0), acl.UpdatePerm(w.dst, sys.uid, acl.Read, acl.Write, acl.Execute)),
+ return sys.wrapErrSuffix(errors.Join(os.Chmod(w.dst, 0), acl.Update(w.dst, sys.uid, acl.Read, acl.Write, acl.Execute)),
fmt.Sprintf("cannot chmod socket on %q:", w.dst))
}
}