summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/acl.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/acl.py')
-rwxr-xr-xbitbake/lib/bb/acl.py215
1 files changed, 215 insertions, 0 deletions
diff --git a/bitbake/lib/bb/acl.py b/bitbake/lib/bb/acl.py
new file mode 100755
index 0000000000..0f41b275cf
--- /dev/null
+++ b/bitbake/lib/bb/acl.py
@@ -0,0 +1,215 @@
+#! /usr/bin/env python3
+#
+# Copyright 2023 by Garmin Ltd. or its subsidiaries
+#
+# SPDX-License-Identifier: MIT
+
+
+import sys
+import ctypes
+import os
+import errno
+import pwd
+import grp
+
+libacl = ctypes.CDLL("libacl.so.1", use_errno=True)
+
+
+ACL_TYPE_ACCESS = 0x8000
+ACL_TYPE_DEFAULT = 0x4000
+
+ACL_FIRST_ENTRY = 0
+ACL_NEXT_ENTRY = 1
+
+ACL_UNDEFINED_TAG = 0x00
+ACL_USER_OBJ = 0x01
+ACL_USER = 0x02
+ACL_GROUP_OBJ = 0x04
+ACL_GROUP = 0x08
+ACL_MASK = 0x10
+ACL_OTHER = 0x20
+
+ACL_READ = 0x04
+ACL_WRITE = 0x02
+ACL_EXECUTE = 0x01
+
+acl_t = ctypes.c_void_p
+acl_entry_t = ctypes.c_void_p
+acl_permset_t = ctypes.c_void_p
+acl_perm_t = ctypes.c_uint
+
+acl_tag_t = ctypes.c_int
+
+libacl.acl_free.argtypes = [acl_t]
+
+
+def acl_free(acl):
+ libacl.acl_free(acl)
+
+
+libacl.acl_get_file.restype = acl_t
+libacl.acl_get_file.argtypes = [ctypes.c_char_p, ctypes.c_uint]
+
+
+def acl_get_file(path, typ):
+ acl = libacl.acl_get_file(os.fsencode(path), typ)
+ if acl is None:
+ err = ctypes.get_errno()
+ raise OSError(err, os.strerror(err), str(path))
+
+ return acl
+
+
+libacl.acl_get_entry.argtypes = [acl_t, ctypes.c_int, ctypes.c_void_p]
+
+
+def acl_get_entry(acl, entry_id):
+ entry = acl_entry_t()
+ ret = libacl.acl_get_entry(acl, entry_id, ctypes.byref(entry))
+ if ret < 0:
+ err = ctypes.get_errno()
+ raise OSError(err, os.strerror(err))
+
+ if ret == 0:
+ return None
+
+ return entry
+
+
+libacl.acl_get_tag_type.argtypes = [acl_entry_t, ctypes.c_void_p]
+
+
+def acl_get_tag_type(entry_d):
+ tag = acl_tag_t()
+ ret = libacl.acl_get_tag_type(entry_d, ctypes.byref(tag))
+ if ret < 0:
+ err = ctypes.get_errno()
+ raise OSError(err, os.strerror(err))
+ return tag.value
+
+
+libacl.acl_get_qualifier.restype = ctypes.c_void_p
+libacl.acl_get_qualifier.argtypes = [acl_entry_t]
+
+
+def acl_get_qualifier(entry_d):
+ ret = libacl.acl_get_qualifier(entry_d)
+ if ret is None:
+ err = ctypes.get_errno()
+ raise OSError(err, os.strerror(err))
+ return ctypes.c_void_p(ret)
+
+
+libacl.acl_get_permset.argtypes = [acl_entry_t, ctypes.c_void_p]
+
+
+def acl_get_permset(entry_d):
+ permset = acl_permset_t()
+ ret = libacl.acl_get_permset(entry_d, ctypes.byref(permset))
+ if ret < 0:
+ err = ctypes.get_errno()
+ raise OSError(err, os.strerror(err))
+
+ return permset
+
+
+libacl.acl_get_perm.argtypes = [acl_permset_t, acl_perm_t]
+
+
+def acl_get_perm(permset_d, perm):
+ ret = libacl.acl_get_perm(permset_d, perm)
+ if ret < 0:
+ err = ctypes.get_errno()
+ raise OSError(err, os.strerror(err))
+ return bool(ret)
+
+
+class Entry(object):
+ def __init__(self, tag, qualifier, mode):
+ self.tag = tag
+ self.qualifier = qualifier
+ self.mode = mode
+
+ def __str__(self):
+ typ = ""
+ qual = ""
+ if self.tag == ACL_USER:
+ typ = "user"
+ qual = pwd.getpwuid(self.qualifier).pw_name
+ elif self.tag == ACL_GROUP:
+ typ = "group"
+ qual = grp.getgrgid(self.qualifier).gr_name
+ elif self.tag == ACL_USER_OBJ:
+ typ = "user"
+ elif self.tag == ACL_GROUP_OBJ:
+ typ = "group"
+ elif self.tag == ACL_MASK:
+ typ = "mask"
+ elif self.tag == ACL_OTHER:
+ typ = "other"
+
+ r = "r" if self.mode & ACL_READ else "-"
+ w = "w" if self.mode & ACL_WRITE else "-"
+ x = "x" if self.mode & ACL_EXECUTE else "-"
+
+ return f"{typ}:{qual}:{r}{w}{x}"
+
+
+class ACL(object):
+ def __init__(self, acl):
+ self.acl = acl
+
+ def __del__(self):
+ acl_free(self.acl)
+
+ def entries(self):
+ entry_id = ACL_FIRST_ENTRY
+ while True:
+ entry = acl_get_entry(self.acl, entry_id)
+ if entry is None:
+ break
+
+ permset = acl_get_permset(entry)
+
+ mode = 0
+ for m in (ACL_READ, ACL_WRITE, ACL_EXECUTE):
+ if acl_get_perm(permset, m):
+ mode |= m
+
+ qualifier = None
+ tag = acl_get_tag_type(entry)
+
+ if tag == ACL_USER or tag == ACL_GROUP:
+ qual = acl_get_qualifier(entry)
+ qualifier = ctypes.cast(qual, ctypes.POINTER(ctypes.c_int))[0]
+
+ yield Entry(tag, qualifier, mode)
+
+ entry_id = ACL_NEXT_ENTRY
+
+ @classmethod
+ def from_path(cls, path, typ):
+ acl = acl_get_file(path, typ)
+ return cls(acl)
+
+
+def main():
+ import argparse
+ import pwd
+ import grp
+ from pathlib import Path
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument("path", help="File Path", type=Path)
+
+ args = parser.parse_args()
+
+ acl = ACL.from_path(args.path, ACL_TYPE_ACCESS)
+ for entry in acl.entries():
+ print(str(entry))
+
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())