aboutsummaryrefslogtreecommitdiffhomepage
path: root/acl
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-02-17 20:37:10 +0900
committerOphestra <cat@gensokyo.uk>2025-02-17 21:39:14 +0900
commite85be67fd98dd5adb17fefdc52a28c8a7a7c3b28 (patch)
treed026ee5cddd84c99349edc19112caa396f5be0bc /acl
parent7e69893264f4b3ee3fc9168a61908552f7fbddac (diff)
acl: implement Update in C
The original implementation was effectively just writing C in Go. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'acl')
-rw-r--r--acl/acl-update.c69
-rw-r--r--acl/acl-update.h3
-rw-r--r--acl/acl.go193
3 files changed, 88 insertions, 177 deletions
diff --git a/acl/acl-update.c b/acl/acl-update.c
new file mode 100644
index 00000000..1d83c15d
--- /dev/null
+++ b/acl/acl-update.c
@@ -0,0 +1,69 @@
+#include "acl-update.h"
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/acl.h>
+#include <acl/libacl.h>
+
+int f_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms, size_t plen) {
+ int ret = -1;
+ bool v;
+ int i;
+ acl_t acl;
+ acl_entry_t entry;
+ acl_tag_t tag_type;
+ void *qualifier_p;
+ acl_permset_t permset;
+
+ acl = acl_get_file(path_p, ACL_TYPE_ACCESS);
+ if (acl == NULL)
+ goto out;
+
+ // prune entries by uid
+ for (i = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); i == 1; i = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) {
+ if (acl_get_tag_type(entry, &tag_type) != 0)
+ return -1;
+ if (tag_type != ACL_USER)
+ continue;
+
+ qualifier_p = acl_get_qualifier(entry);
+ if (qualifier_p == NULL)
+ return -1;
+ v = *(uid_t *)qualifier_p == uid;
+ acl_free(qualifier_p);
+
+ if (!v)
+ continue;
+
+ acl_delete_entry(acl, entry);
+ }
+
+ if (plen == 0)
+ goto set;
+
+ if (acl_create_entry(&acl, &entry) != 0)
+ goto out;
+ if (acl_get_permset(entry, &permset) != 0)
+ goto out;
+ for (i = 0; i < plen; i++) {
+ if (acl_add_perm(permset, perms[i]) != 0)
+ goto out;
+ }
+ if (acl_set_tag_type(entry, ACL_USER) != 0)
+ goto out;
+ if (acl_set_qualifier(entry, (void *)&uid) != 0)
+ goto out;
+
+set:
+ if (acl_calc_mask(&acl) != 0)
+ goto out;
+ if (acl_valid(acl) != 0)
+ goto out;
+ if (acl_set_file(path_p, ACL_TYPE_ACCESS, acl) == 0)
+ ret = 0;
+
+out:
+ free((void *)path_p);
+ if (acl != NULL)
+ acl_free((void *)acl);
+ return ret;
+}
diff --git a/acl/acl-update.h b/acl/acl-update.h
new file mode 100644
index 00000000..e758788e
--- /dev/null
+++ b/acl/acl-update.h
@@ -0,0 +1,3 @@
+#include <sys/acl.h>
+
+int f_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms, size_t plen);
diff --git a/acl/acl.go b/acl/acl.go
index fe355612..bd2d9c43 100644
--- a/acl/acl.go
+++ b/acl/acl.go
@@ -1,197 +1,36 @@
// Package acl implements simple ACL manipulation via libacl.
package acl
-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;
-}
+#include "acl-update.h"
*/
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)
-}
+type Perm C.acl_perm_t
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
+ Read Perm = C.ACL_READ
+ Write Perm = C.ACL_WRITE
+ Execute Perm = C.ACL_EXECUTE
)
-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
+ var p *Perm
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
- }
+ p = &perms[0]
}
- // calculate mask after update
- if _, err = C.acl_calc_mask(&a.acl); err != nil {
- return err
+ r, err := C.f_acl_update_file_by_uid(
+ C.CString(name),
+ C.uid_t(uid),
+ (*C.acl_perm_t)(p),
+ C.size_t(len(perms)),
+ )
+ if r == 0 {
+ return nil
}
-
- // write acl to file
- return a.setFile(name, TypeAccess)
+ return err
}