2024-02-19 19:51:10 +00:00
|
|
|
From 78e4c9f2c2e97d23a67254647339d3c75bb7986d Mon Sep 17 00:00:00 2001
|
2024-02-13 15:25:04 +00:00
|
|
|
From: Vit Mojzis <vmojzis@redhat.com>
|
2024-02-19 19:51:10 +00:00
|
|
|
Date: Wed, 14 Feb 2024 13:08:40 +0100
|
2024-02-13 15:25:04 +00:00
|
|
|
Subject: [PATCH] python/semanage: Allow modifying records on "add"
|
|
|
|
Content-type: text/plain
|
|
|
|
|
|
|
|
When trying to add a record with a key that already exists, modify
|
|
|
|
the existing record instead.
|
|
|
|
|
|
|
|
Also, fix "semanage -m -e" (add_equal was called instead of
|
|
|
|
modify_equal), which meant that existing local equivalency couldn't be
|
|
|
|
modified (though a user could remove it and add a modified
|
|
|
|
equivalency).
|
|
|
|
|
|
|
|
Fixes:
|
|
|
|
https://github.com/SELinuxProject/selinux/issues/412
|
|
|
|
When a port or login definition present in the policy is modified
|
|
|
|
using "semanage port -m", "semanage export" exports the command as
|
|
|
|
"port -a" instead of "port -m". This results in "semanage import"
|
|
|
|
failing (port already defined). The same is true for port, user,
|
|
|
|
login, ibpkey, ibendport, node, interface and fcontext.
|
|
|
|
|
|
|
|
Signed-off-by: Vit Mojzis <vmojzis@redhat.com>
|
|
|
|
---
|
|
|
|
python/semanage/semanage | 2 +-
|
2024-02-19 19:51:10 +00:00
|
|
|
python/semanage/seobject.py | 208 +++++++++++++++++++++++++-----------
|
|
|
|
2 files changed, 147 insertions(+), 63 deletions(-)
|
2024-02-13 15:25:04 +00:00
|
|
|
|
|
|
|
diff --git a/python/semanage/semanage b/python/semanage/semanage
|
|
|
|
index 4fdb490f7df4..b269b9fca65b 100644
|
|
|
|
--- a/python/semanage/semanage
|
|
|
|
+++ b/python/semanage/semanage
|
|
|
|
@@ -322,7 +322,7 @@ def handleFcontext(args):
|
|
|
|
OBJECT.add(args.file_spec, args.type, args.ftype, args.range, args.seuser)
|
|
|
|
if args.action == "modify":
|
|
|
|
if args.equal:
|
|
|
|
- OBJECT.add_equal(args.file_spec, args.equal)
|
|
|
|
+ OBJECT.modify_equal(args.file_spec, args.equal)
|
|
|
|
else:
|
|
|
|
OBJECT.modify(args.file_spec, args.type, args.ftype, args.range, args.seuser)
|
|
|
|
if args.action == "delete":
|
|
|
|
diff --git a/python/semanage/seobject.py b/python/semanage/seobject.py
|
2024-02-19 19:51:10 +00:00
|
|
|
index cc944ae202c9..12133b53fe91 100644
|
2024-02-13 15:25:04 +00:00
|
|
|
--- a/python/semanage/seobject.py
|
|
|
|
+++ b/python/semanage/seobject.py
|
|
|
|
@@ -557,11 +557,6 @@ class loginRecords(semanageRecords):
|
|
|
|
if rc < 0:
|
|
|
|
raise ValueError(_("Could not create a key for %s") % name)
|
|
|
|
|
|
|
|
- (rc, exists) = semanage_seuser_exists(self.sh, k)
|
|
|
|
- if rc < 0:
|
|
|
|
- raise ValueError(_("Could not check if login mapping for %s is defined") % name)
|
|
|
|
- if exists:
|
|
|
|
- raise ValueError(_("Login mapping for %s is already defined") % name)
|
|
|
|
if name[0] == '%':
|
|
|
|
try:
|
|
|
|
grp.getgrnam(name[1:])
|
|
|
|
@@ -600,11 +595,29 @@ class loginRecords(semanageRecords):
|
|
|
|
def add(self, name, sename, serange):
|
|
|
|
try:
|
|
|
|
self.begin()
|
|
|
|
- self.__add(name, sename, serange)
|
|
|
|
+ # Add a new mapping, or modify an existing one
|
|
|
|
+ if self.__exists(name):
|
|
|
|
+ print(_("Login mapping for %s is already defined, modifying instead") % name)
|
|
|
|
+ self.__modify(name, sename, serange)
|
|
|
|
+ else:
|
|
|
|
+ self.__add(name, sename, serange)
|
|
|
|
self.commit()
|
|
|
|
except ValueError as error:
|
|
|
|
raise error
|
|
|
|
|
|
|
|
+ # check if login mapping for given user exists
|
|
|
|
+ def __exists(self, name):
|
|
|
|
+ (rc, k) = semanage_seuser_key_create(self.sh, name)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not create a key for %s") % name)
|
|
|
|
+
|
|
|
|
+ (rc, exists) = semanage_seuser_exists(self.sh, k)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not check if login mapping for %s is defined") % name)
|
|
|
|
+ semanage_seuser_key_free(k)
|
|
|
|
+
|
|
|
|
+ return exists
|
|
|
|
+
|
|
|
|
def __modify(self, name, sename="", serange=""):
|
|
|
|
rec, self.oldsename, self.oldserange = selinux.getseuserbyname(name)
|
|
|
|
if sename == "" and serange == "":
|
|
|
|
@@ -821,12 +834,6 @@ class seluserRecords(semanageRecords):
|
|
|
|
if rc < 0:
|
|
|
|
raise ValueError(_("Could not create a key for %s") % name)
|
|
|
|
|
|
|
|
- (rc, exists) = semanage_user_exists(self.sh, k)
|
|
|
|
- if rc < 0:
|
|
|
|
- raise ValueError(_("Could not check if SELinux user %s is defined") % name)
|
|
|
|
- if exists:
|
|
|
|
- raise ValueError(_("SELinux user %s is already defined") % name)
|
|
|
|
-
|
|
|
|
(rc, u) = semanage_user_create(self.sh)
|
|
|
|
if rc < 0:
|
|
|
|
raise ValueError(_("Could not create SELinux user for %s") % name)
|
|
|
|
@@ -866,12 +873,28 @@ class seluserRecords(semanageRecords):
|
|
|
|
def add(self, name, roles, selevel, serange, prefix):
|
|
|
|
try:
|
|
|
|
self.begin()
|
|
|
|
- self.__add(name, roles, selevel, serange, prefix)
|
|
|
|
+ if self.__exists(name):
|
|
|
|
+ print(_("SELinux user %s is already defined, modifying instead") % name)
|
|
|
|
+ self.__modify(name, roles, selevel, serange, prefix)
|
|
|
|
+ else:
|
|
|
|
+ self.__add(name, roles, selevel, serange, prefix)
|
|
|
|
self.commit()
|
|
|
|
except ValueError as error:
|
|
|
|
self.mylog.commit(0)
|
|
|
|
raise error
|
|
|
|
|
|
|
|
+ def __exists(self, name):
|
|
|
|
+ (rc, k) = semanage_user_key_create(self.sh, name)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not create a key for %s") % name)
|
|
|
|
+
|
|
|
|
+ (rc, exists) = semanage_user_exists(self.sh, k)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not check if SELinux user %s is defined") % name)
|
|
|
|
+ semanage_user_key_free(k)
|
|
|
|
+
|
|
|
|
+ return exists
|
|
|
|
+
|
|
|
|
def __modify(self, name, roles=[], selevel="", serange="", prefix=""):
|
|
|
|
oldserole = ""
|
|
|
|
oldserange = ""
|
|
|
|
@@ -1103,12 +1126,6 @@ class portRecords(semanageRecords):
|
|
|
|
|
|
|
|
(k, proto_d, low, high) = self.__genkey(port, proto)
|
|
|
|
|
|
|
|
- (rc, exists) = semanage_port_exists(self.sh, k)
|
|
|
|
- if rc < 0:
|
|
|
|
- raise ValueError(_("Could not check if port {proto}/{port} is defined").format(proto=proto, port=port))
|
|
|
|
- if exists:
|
|
|
|
- raise ValueError(_("Port {proto}/{port} already defined").format(proto=proto, port=port))
|
|
|
|
-
|
|
|
|
(rc, p) = semanage_port_create(self.sh)
|
|
|
|
if rc < 0:
|
|
|
|
raise ValueError(_("Could not create port for {proto}/{port}").format(proto=proto, port=port))
|
|
|
|
@@ -1152,9 +1169,23 @@ class portRecords(semanageRecords):
|
|
|
|
|
|
|
|
def add(self, port, proto, serange, type):
|
|
|
|
self.begin()
|
|
|
|
- self.__add(port, proto, serange, type)
|
|
|
|
+ if self.__exists(port, proto):
|
|
|
|
+ print(_("Port {proto}/{port} already defined, modifying instead").format(proto=proto, port=port))
|
|
|
|
+ self.__modify(port, proto, serange, type)
|
|
|
|
+ else:
|
|
|
|
+ self.__add(port, proto, serange, type)
|
|
|
|
self.commit()
|
|
|
|
|
|
|
|
+ def __exists(self, port, proto):
|
|
|
|
+ (k, proto_d, low, high) = self.__genkey(port, proto)
|
|
|
|
+
|
|
|
|
+ (rc, exists) = semanage_port_exists(self.sh, k)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not check if port {proto}/{port} is defined").format(proto=proto, port=port))
|
|
|
|
+ semanage_port_key_free(k)
|
|
|
|
+
|
|
|
|
+ return exists
|
|
|
|
+
|
|
|
|
def __modify(self, port, proto, serange, setype):
|
|
|
|
if serange == "" and setype == "":
|
|
|
|
if is_mls_enabled == 1:
|
|
|
|
@@ -1377,12 +1408,6 @@ class ibpkeyRecords(semanageRecords):
|
|
|
|
|
|
|
|
(k, subnet_prefix, low, high) = self.__genkey(pkey, subnet_prefix)
|
|
|
|
|
|
|
|
- (rc, exists) = semanage_ibpkey_exists(self.sh, k)
|
|
|
|
- if rc < 0:
|
|
|
|
- raise ValueError(_("Could not check if ibpkey {subnet_prefix}/{pkey} is defined").formnat(subnet_prefix=subnet_prefix, pkey=pkey))
|
|
|
|
- if exists:
|
|
|
|
- raise ValueError(_("ibpkey {subnet_prefix}/{pkey} already defined").format(subnet_prefix=subnet_prefix, pkey=pkey))
|
|
|
|
-
|
|
|
|
(rc, p) = semanage_ibpkey_create(self.sh)
|
|
|
|
if rc < 0:
|
|
|
|
raise ValueError(_("Could not create ibpkey for {subnet_prefix}/{pkey}").format(subnet_prefix=subnet_prefix, pkey=pkey))
|
|
|
|
@@ -1424,9 +1449,23 @@ class ibpkeyRecords(semanageRecords):
|
|
|
|
|
|
|
|
def add(self, pkey, subnet_prefix, serange, type):
|
|
|
|
self.begin()
|
|
|
|
- self.__add(pkey, subnet_prefix, serange, type)
|
|
|
|
+ if self.__exists(pkey, subnet_prefix):
|
|
|
|
+ print(_("ibpkey {subnet_prefix}/{pkey} already defined, modifying instead").format(subnet_prefix=subnet_prefix, pkey=pkey))
|
|
|
|
+ self.__modify(pkey, subnet_prefix, serange, type)
|
|
|
|
+ else:
|
|
|
|
+ self.__add(pkey, subnet_prefix, serange, type)
|
|
|
|
self.commit()
|
|
|
|
|
|
|
|
+ def __exists(self, pkey, subnet_prefix):
|
|
|
|
+ (k, subnet_prefix, low, high) = self.__genkey(pkey, subnet_prefix)
|
|
|
|
+
|
|
|
|
+ (rc, exists) = semanage_ibpkey_exists(self.sh, k)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not check if ibpkey {subnet_prefix}/{pkey} is defined").formnat(subnet_prefix=subnet_prefix, pkey=pkey))
|
|
|
|
+ semanage_ibpkey_key_free(k)
|
|
|
|
+
|
|
|
|
+ return exists
|
|
|
|
+
|
|
|
|
def __modify(self, pkey, subnet_prefix, serange, setype):
|
|
|
|
if serange == "" and setype == "":
|
|
|
|
if is_mls_enabled == 1:
|
|
|
|
@@ -1631,12 +1670,6 @@ class ibendportRecords(semanageRecords):
|
|
|
|
raise ValueError(_("Type %s is invalid, must be an ibendport type") % type)
|
|
|
|
(k, ibendport, port) = self.__genkey(ibendport, ibdev_name)
|
|
|
|
|
|
|
|
- (rc, exists) = semanage_ibendport_exists(self.sh, k)
|
|
|
|
- if rc < 0:
|
|
|
|
- raise ValueError(_("Could not check if ibendport {ibdev_name}/{port} is defined").format(ibdev_name=ibdev_name, port=port))
|
|
|
|
- if exists:
|
|
|
|
- raise ValueError(_("ibendport {ibdev_name}/{port} already defined").format(ibdev_name=ibdev_name, port=port))
|
|
|
|
-
|
|
|
|
(rc, p) = semanage_ibendport_create(self.sh)
|
|
|
|
if rc < 0:
|
|
|
|
raise ValueError(_("Could not create ibendport for {ibdev_name}/{port}").format(ibdev_name=ibdev_name, port=port))
|
|
|
|
@@ -1678,9 +1711,23 @@ class ibendportRecords(semanageRecords):
|
|
|
|
|
|
|
|
def add(self, ibendport, ibdev_name, serange, type):
|
|
|
|
self.begin()
|
|
|
|
- self.__add(ibendport, ibdev_name, serange, type)
|
|
|
|
+ if self.__exists(ibendport, ibdev_name):
|
|
|
|
+ print(_("ibendport {ibdev_name}/{port} already defined, modifying instead").format(ibdev_name=ibdev_name, port=port))
|
|
|
|
+ self.__modify(ibendport, ibdev_name, serange, type)
|
|
|
|
+ else:
|
|
|
|
+ self.__add(ibendport, ibdev_name, serange, type)
|
|
|
|
self.commit()
|
|
|
|
|
|
|
|
+ def __exists(self, ibendport, ibdev_name):
|
|
|
|
+ (k, ibendport, port) = self.__genkey(ibendport, ibdev_name)
|
|
|
|
+
|
|
|
|
+ (rc, exists) = semanage_ibendport_exists(self.sh, k)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not check if ibendport {ibdev_name}/{port} is defined").format(ibdev_name=ibdev_name, port=port))
|
|
|
|
+ semanage_ibendport_key_free(k)
|
|
|
|
+
|
|
|
|
+ return exists
|
|
|
|
+
|
|
|
|
def __modify(self, ibendport, ibdev_name, serange, setype):
|
|
|
|
if serange == "" and setype == "":
|
|
|
|
if is_mls_enabled == 1:
|
|
|
|
@@ -1902,12 +1949,6 @@ class nodeRecords(semanageRecords):
|
|
|
|
if rc < 0:
|
|
|
|
raise ValueError(_("Could not create key for %s") % addr)
|
|
|
|
|
|
|
|
- (rc, exists) = semanage_node_exists(self.sh, k)
|
|
|
|
- if rc < 0:
|
|
|
|
- raise ValueError(_("Could not check if addr %s is defined") % addr)
|
|
|
|
- if exists:
|
|
|
|
- raise ValueError(_("Addr %s already defined") % addr)
|
|
|
|
-
|
|
|
|
(rc, node) = semanage_node_create(self.sh)
|
|
|
|
if rc < 0:
|
|
|
|
raise ValueError(_("Could not create addr for %s") % addr)
|
2024-02-19 19:51:10 +00:00
|
|
|
@@ -1955,9 +1996,27 @@ class nodeRecords(semanageRecords):
|
2024-02-13 15:25:04 +00:00
|
|
|
|
|
|
|
def add(self, addr, mask, proto, serange, ctype):
|
|
|
|
self.begin()
|
|
|
|
- self.__add(addr, mask, proto, serange, ctype)
|
|
|
|
+ if self.__exists(addr, mask, proto):
|
|
|
|
+ print(_("Addr %s already defined, modifying instead") % addr)
|
|
|
|
+ self.__modify(addr, mask, proto, serange, ctype)
|
|
|
|
+ else:
|
|
|
|
+ self.__add(addr, mask, proto, serange, ctype)
|
|
|
|
self.commit()
|
|
|
|
|
|
|
|
+ def __exists(self, addr, mask, proto):
|
2024-02-19 19:51:10 +00:00
|
|
|
+ addr, mask, proto, audit_proto = self.validate(addr, mask, proto)
|
|
|
|
+
|
2024-02-13 15:25:04 +00:00
|
|
|
+ (rc, k) = semanage_node_key_create(self.sh, addr, mask, proto)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not create key for %s") % addr)
|
|
|
|
+
|
|
|
|
+ (rc, exists) = semanage_node_exists(self.sh, k)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not check if addr %s is defined") % addr)
|
|
|
|
+ semanage_node_key_free(k)
|
|
|
|
+
|
|
|
|
+ return exists
|
|
|
|
+
|
|
|
|
def __modify(self, addr, mask, proto, serange, setype):
|
|
|
|
addr, mask, proto, audit_proto = self.validate(addr, mask, proto)
|
|
|
|
|
2024-02-19 19:51:10 +00:00
|
|
|
@@ -2111,12 +2170,6 @@ class interfaceRecords(semanageRecords):
|
2024-02-13 15:25:04 +00:00
|
|
|
if rc < 0:
|
|
|
|
raise ValueError(_("Could not create key for %s") % interface)
|
|
|
|
|
|
|
|
- (rc, exists) = semanage_iface_exists(self.sh, k)
|
|
|
|
- if rc < 0:
|
|
|
|
- raise ValueError(_("Could not check if interface %s is defined") % interface)
|
|
|
|
- if exists:
|
|
|
|
- raise ValueError(_("Interface %s already defined") % interface)
|
|
|
|
-
|
|
|
|
(rc, iface) = semanage_iface_create(self.sh)
|
|
|
|
if rc < 0:
|
|
|
|
raise ValueError(_("Could not create interface for %s") % interface)
|
2024-02-19 19:51:10 +00:00
|
|
|
@@ -2163,9 +2216,25 @@ class interfaceRecords(semanageRecords):
|
2024-02-13 15:25:04 +00:00
|
|
|
|
|
|
|
def add(self, interface, serange, ctype):
|
|
|
|
self.begin()
|
|
|
|
- self.__add(interface, serange, ctype)
|
|
|
|
+ if self.__exists(interface):
|
|
|
|
+ print(_("Interface %s already defined, modifying instead") % interface)
|
|
|
|
+ self.__modify(interface, serange, ctype)
|
|
|
|
+ else:
|
|
|
|
+ self.__add(interface, serange, ctype)
|
|
|
|
self.commit()
|
|
|
|
|
|
|
|
+ def __exists(self, interface):
|
|
|
|
+ (rc, k) = semanage_iface_key_create(self.sh, interface)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not create key for %s") % interface)
|
|
|
|
+
|
|
|
|
+ (rc, exists) = semanage_iface_exists(self.sh, k)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not check if interface %s is defined") % interface)
|
|
|
|
+ semanage_iface_key_free(k)
|
|
|
|
+
|
|
|
|
+ return exists
|
|
|
|
+
|
|
|
|
def __modify(self, interface, serange, setype):
|
|
|
|
if serange == "" and setype == "":
|
|
|
|
raise ValueError(_("Requires setype or serange"))
|
2024-02-19 19:51:10 +00:00
|
|
|
@@ -2353,7 +2422,13 @@ class fcontextRecords(semanageRecords):
|
2024-02-13 15:25:04 +00:00
|
|
|
raise ValueError(_("Substitute %s is not valid. Substitute is not allowed to end with '/'") % substitute)
|
|
|
|
|
|
|
|
if target in self.equiv.keys():
|
|
|
|
- raise ValueError(_("Equivalence class for %s already exists") % target)
|
|
|
|
+ print(_("Equivalence class for %s already exists, modifying instead") % target)
|
|
|
|
+ self.equiv[target] = substitute
|
|
|
|
+ self.equal_ind = True
|
|
|
|
+ self.mylog.log_change("resrc=fcontext op=modify-equal %s %s" % (audit.audit_encode_nv_string("sglob", target, 0), audit.audit_encode_nv_string("tglob", substitute, 0)))
|
|
|
|
+ self.commit()
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
self.validate(target)
|
|
|
|
|
|
|
|
for fdict in (self.equiv, self.equiv_dist):
|
2024-02-19 19:51:10 +00:00
|
|
|
@@ -2429,18 +2504,6 @@ class fcontextRecords(semanageRecords):
|
2024-02-13 15:25:04 +00:00
|
|
|
if rc < 0:
|
|
|
|
raise ValueError(_("Could not create key for %s") % target)
|
|
|
|
|
|
|
|
- (rc, exists) = semanage_fcontext_exists(self.sh, k)
|
|
|
|
- if rc < 0:
|
|
|
|
- raise ValueError(_("Could not check if file context for %s is defined") % target)
|
|
|
|
-
|
|
|
|
- if not exists:
|
|
|
|
- (rc, exists) = semanage_fcontext_exists_local(self.sh, k)
|
|
|
|
- if rc < 0:
|
|
|
|
- raise ValueError(_("Could not check if file context for %s is defined") % target)
|
|
|
|
-
|
|
|
|
- if exists:
|
|
|
|
- raise ValueError(_("File context for %s already defined") % target)
|
|
|
|
-
|
|
|
|
(rc, fcontext) = semanage_fcontext_create(self.sh)
|
|
|
|
if rc < 0:
|
|
|
|
raise ValueError(_("Could not create file context for %s") % target)
|
2024-02-19 19:51:10 +00:00
|
|
|
@@ -2479,9 +2542,30 @@ class fcontextRecords(semanageRecords):
|
2024-02-13 15:25:04 +00:00
|
|
|
|
|
|
|
def add(self, target, type, ftype="", serange="", seuser="system_u"):
|
|
|
|
self.begin()
|
|
|
|
- self.__add(target, type, ftype, serange, seuser)
|
|
|
|
+ if self.__exists(target, ftype):
|
|
|
|
+ print(_("File context for %s already defined, modifying instead") % target)
|
|
|
|
+ self.__modify(target, type, ftype, serange, seuser)
|
|
|
|
+ else:
|
|
|
|
+ self.__add(target, type, ftype, serange, seuser)
|
|
|
|
self.commit()
|
|
|
|
|
|
|
|
+ def __exists(self, target, ftype):
|
|
|
|
+ (rc, k) = semanage_fcontext_key_create(self.sh, target, file_types[ftype])
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not create key for %s") % target)
|
|
|
|
+
|
|
|
|
+ (rc, exists) = semanage_fcontext_exists(self.sh, k)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not check if file context for %s is defined") % target)
|
|
|
|
+
|
|
|
|
+ if not exists:
|
|
|
|
+ (rc, exists) = semanage_fcontext_exists_local(self.sh, k)
|
|
|
|
+ if rc < 0:
|
|
|
|
+ raise ValueError(_("Could not check if file context for %s is defined") % target)
|
|
|
|
+ semanage_fcontext_key_free(k)
|
|
|
|
+
|
|
|
|
+ return exists
|
|
|
|
+
|
|
|
|
def __modify(self, target, setype, ftype, serange, seuser):
|
|
|
|
if serange == "" and setype == "" and seuser == "":
|
|
|
|
raise ValueError(_("Requires setype, serange or seuser"))
|
|
|
|
--
|
2024-02-19 19:51:10 +00:00
|
|
|
2.43.2
|
2024-02-13 15:25:04 +00:00
|
|
|
|