aboutsummaryrefslogtreecommitdiffhomepage
path: root/acl/c.go
diff options
context:
space:
mode:
Diffstat (limited to 'acl/c.go')
-rw-r--r--acl/c.go159
1 files changed, 128 insertions, 31 deletions
diff --git a/acl/c.go b/acl/c.go
index 89bc0469..4bbc5491 100644
--- a/acl/c.go
+++ b/acl/c.go
@@ -1,50 +1,95 @@
package acl
+import "C"
import (
"errors"
- "fmt"
+ "runtime"
"syscall"
"unsafe"
)
-//#include <stdlib.h>
-//#include <sys/acl.h>
-//#include <acl/libacl.h>
-//#cgo linux LDFLAGS: -lacl
-import "C"
+/*
+#cgo linux pkg-config: libacl
-type acl struct {
- val C.acl_t
- freed bool
+#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;
}
-func aclGetFile(path string, t C.acl_type_t) (*acl, error) {
- p := C.CString(path)
- a, err := C.acl_get_file(p, t)
- C.free(unsafe.Pointer(p))
+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 &acl{val: a, freed: false}, err
-}
-func (a *acl) setFile(path string, t C.acl_type_t) error {
- if C.acl_valid(a.val) != 0 {
- return fmt.Errorf("invalid acl")
- }
+ return newACL(a), err
+}
- p := C.CString(path)
- _, err := C.acl_set_file(p, t, a.val)
- C.free(unsafe.Pointer(p))
+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 (a *acl) removeEntry(tt C.acl_tag_t, tq int) error {
+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(a.val, C.ACL_FIRST_ENTRY, &e); err != nil {
+ 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
@@ -52,7 +97,7 @@ func (a *acl) removeEntry(tt C.acl_tag_t, tq int) error {
}
for {
- if r, err := C.acl_get_entry(a.val, C.ACL_NEXT_ENTRY, &e); err != nil {
+ 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
@@ -84,16 +129,68 @@ func (a *acl) removeEntry(tt C.acl_tag_t, tq int) error {
// delete on match
if t == tt && q == tq {
- _, err := C.acl_delete_entry(a.val, e)
+ _, err := C.acl_delete_entry(acl.acl, e)
return err
}
}
}
-func (a *acl) free() {
- if a.freed {
- panic("acl already freed")
+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
}
- C.acl_free(unsafe.Pointer(a.val))
- a.freed = true
+
+ // 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)
}