acl: rename UpdatePerms to Update
Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
38a3e6af03
commit
7e69893264
202
acl/acl.go
202
acl/acl.go
@ -1,19 +1,197 @@
|
|||||||
// Package acl implements simple ACL manipulation via libacl.
|
// Package acl implements simple ACL manipulation via libacl.
|
||||||
package acl
|
package acl
|
||||||
|
|
||||||
type Perms []Perm
|
import (
|
||||||
|
"errors"
|
||||||
|
"runtime"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
func (ps Perms) String() string {
|
/*
|
||||||
var s = []byte("---")
|
#cgo linux pkg-config: --static libacl
|
||||||
for _, p := range ps {
|
|
||||||
switch p {
|
#include <stdlib.h>
|
||||||
case Read:
|
#include <sys/acl.h>
|
||||||
s[0] = 'r'
|
#include <acl/libacl.h>
|
||||||
case Write:
|
|
||||||
s[1] = 'w'
|
static acl_t _go_acl_get_file(const char *path_p, acl_type_t type) {
|
||||||
case Execute:
|
acl_t acl = acl_get_file(path_p, type);
|
||||||
s[2] = 'x'
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return string(s)
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ func TestUpdatePerm(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("default clear mask", func(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)
|
t.Fatalf("UpdatePerm: error = %v", err)
|
||||||
}
|
}
|
||||||
if cur = getfacl(t, testFilePath); len(cur) != 4 {
|
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) {
|
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)
|
t.Fatalf("UpdatePerm: error = %v", err)
|
||||||
}
|
}
|
||||||
if val := getfacl(t, testFilePath); !reflect.DeepEqual(val, cur) {
|
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) {
|
func testUpdate(t *testing.T, testFilePath, name string, cur []*getFAclResp, val fAclPerm, perms ...acl.Perm) {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
t.Cleanup(func() {
|
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)
|
t.Fatalf("UpdatePerm: error = %v", err)
|
||||||
}
|
}
|
||||||
if v := getfacl(t, testFilePath); !reflect.DeepEqual(v, cur) {
|
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)
|
t.Fatalf("UpdatePerm: error = %v", err)
|
||||||
}
|
}
|
||||||
r := respByCred(getfacl(t, testFilePath), fAclTypeUser, cred)
|
r := respByCred(getfacl(t, testFilePath), fAclTypeUser, cred)
|
||||||
|
196
acl/c.go
196
acl/c.go
@ -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)
|
|
||||||
}
|
|
18
acl/perms.go
Normal file
18
acl/perms.go
Normal file
@ -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)
|
||||||
|
}
|
@ -34,14 +34,14 @@ func (a *ACL) Type() Enablement { return a.et }
|
|||||||
|
|
||||||
func (a *ACL) apply(sys *I) error {
|
func (a *ACL) apply(sys *I) error {
|
||||||
sys.println("applying ACL", a)
|
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))
|
fmt.Sprintf("cannot apply ACL entry to %q:", a.path))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ACL) revert(sys *I, ec *Criteria) error {
|
func (a *ACL) revert(sys *I, ec *Criteria) error {
|
||||||
if ec.hasType(a) {
|
if ec.hasType(a) {
|
||||||
sys.println("stripping ACL", 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))
|
fmt.Sprintf("cannot strip ACL entry from %q:", a.path))
|
||||||
} else {
|
} else {
|
||||||
sys.println("skipping ACL", a)
|
sys.println("skipping ACL", a)
|
||||||
|
@ -58,7 +58,7 @@ func (w *Wayland) apply(sys *I) error {
|
|||||||
} else {
|
} else {
|
||||||
*w.sync = sp
|
*w.sync = sp
|
||||||
sys.printf("wayland listening on %q", w.dst)
|
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))
|
fmt.Sprintf("cannot chmod socket on %q:", w.dst))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user