126 lines
4.4 KiB
Diff
126 lines
4.4 KiB
Diff
From 5613937623f0037a54490b22c60f7eb1aa52cf4e Mon Sep 17 00:00:00 2001
|
|
From: James Chapman <jachapma@redhat.com>
|
|
Date: Wed, 25 Jun 2025 14:11:05 +0000
|
|
Subject: [PATCH] =?UTF-8?q?Issue=206825=20-=20RootDN=20Access=20Control=20?=
|
|
=?UTF-8?q?Plugin=20with=20wildcards=20for=20IP=20addre=E2=80=A6=20(#6826)?=
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Bug description:
|
|
RootDN Access Control Plugin with wildcards for IP addresses fails withi
|
|
an error "Invalid IP address"
|
|
|
|
socket.inet_aton() validates IPv4 IP addresses and does not support wildcards.
|
|
|
|
Fix description:
|
|
Add a regex pattern to match wildcard IP addresses, check each octet is
|
|
between 0-255
|
|
|
|
Fixes: https://github.com/389ds/389-ds-base/issues/6825
|
|
|
|
Reviewed by: @droideck (Thank you)
|
|
---
|
|
.../lib389/cli_conf/plugins/rootdn_ac.py | 16 +++-----
|
|
src/lib389/lib389/utils.py | 40 +++++++++++++++++++
|
|
2 files changed, 45 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/src/lib389/lib389/cli_conf/plugins/rootdn_ac.py b/src/lib389/lib389/cli_conf/plugins/rootdn_ac.py
|
|
index 65486fff8..1456f5ebe 100644
|
|
--- a/src/lib389/lib389/cli_conf/plugins/rootdn_ac.py
|
|
+++ b/src/lib389/lib389/cli_conf/plugins/rootdn_ac.py
|
|
@@ -8,7 +8,7 @@
|
|
|
|
import socket
|
|
from lib389.plugins import RootDNAccessControlPlugin
|
|
-from lib389.utils import is_valid_hostname
|
|
+from lib389.utils import is_valid_hostname, is_valid_ip
|
|
from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit
|
|
from lib389.cli_base import CustomHelpFormatter
|
|
|
|
@@ -62,19 +62,13 @@ def validate_args(args):
|
|
|
|
if args.allow_ip is not None:
|
|
for ip in args.allow_ip:
|
|
- if ip != "delete":
|
|
- try:
|
|
- socket.inet_aton(ip)
|
|
- except socket.error:
|
|
- raise ValueError(f"Invalid IP address ({ip}) for '--allow-ip'")
|
|
+ if ip != "delete" and not is_valid_ip(ip):
|
|
+ raise ValueError(f"Invalid IP address ({ip}) for '--allow-ip'")
|
|
|
|
if args.deny_ip is not None and args.deny_ip != "delete":
|
|
for ip in args.deny_ip:
|
|
- if ip != "delete":
|
|
- try:
|
|
- socket.inet_aton(ip)
|
|
- except socket.error:
|
|
- raise ValueError(f"Invalid IP address ({ip}) for '--deny-ip'")
|
|
+ if ip != "delete" and not is_valid_ip(ip):
|
|
+ raise ValueError(f"Invalid IP address ({ip}) for '--deny-ip'")
|
|
|
|
if args.allow_host is not None:
|
|
for hostname in args.allow_host:
|
|
diff --git a/src/lib389/lib389/utils.py b/src/lib389/lib389/utils.py
|
|
index afc282e94..3937fc1a8 100644
|
|
--- a/src/lib389/lib389/utils.py
|
|
+++ b/src/lib389/lib389/utils.py
|
|
@@ -31,6 +31,7 @@ import logging
|
|
import shutil
|
|
import ldap
|
|
import socket
|
|
+import ipaddress
|
|
import time
|
|
import stat
|
|
from datetime import (datetime, timedelta)
|
|
@@ -1707,6 +1708,45 @@ def is_valid_hostname(hostname):
|
|
allowed = re.compile(r"(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
|
|
return all(allowed.match(x) for x in hostname.split("."))
|
|
|
|
+def is_valid_ip(ip):
|
|
+ """ Validate an IPv4 or IPv6 address, including asterisks for wildcards. """
|
|
+ if '*' in ip and '.' in ip:
|
|
+ ipv4_pattern = r'^(\d{1,3}|\*)\.(\d{1,3}|\*)\.(\d{1,3}|\*)\.(\d{1,3}|\*)$'
|
|
+ if re.match(ipv4_pattern, ip):
|
|
+ octets = ip.split('.')
|
|
+ for octet in octets:
|
|
+ if octet != '*':
|
|
+ try:
|
|
+ val = int(octet, 10)
|
|
+ if not (0 <= val <= 255):
|
|
+ return False
|
|
+ except ValueError:
|
|
+ return False
|
|
+ return True
|
|
+ else:
|
|
+ return False
|
|
+
|
|
+ if '*' in ip and ':' in ip:
|
|
+ ipv6_pattern = r'^([0-9a-fA-F]{1,4}|\*)(:([0-9a-fA-F]{1,4}|\*)){0,7}$'
|
|
+ if re.match(ipv6_pattern, ip):
|
|
+ octets = ip.split(':')
|
|
+ for octet in octets:
|
|
+ if octet != '*':
|
|
+ try:
|
|
+ val = int(octet, 16)
|
|
+ if not (0 <= val <= 0xFFFF):
|
|
+ return False
|
|
+ except ValueError:
|
|
+ return False
|
|
+ return True
|
|
+ else:
|
|
+ return False
|
|
+
|
|
+ try:
|
|
+ ipaddress.ip_address(ip)
|
|
+ return True
|
|
+ except ValueError:
|
|
+ return False
|
|
|
|
def parse_size(size):
|
|
"""
|
|
--
|
|
2.49.0
|
|
|