Re: git: 497924deb1b0 - main - net/freeipa-client: make host enrollment work on FreeBSD
Date: Thu, 03 Sep 2026 10:11:14 UTC
Hello!
Not so good idea to hardcode paths (such as /usr/local) to the patches instead of %%LOCALBASE%% macro and appropriate reinplace in post-patch.
At least LOCALBASE may be redefined at some point.
--
Dima. (desktop, kde, x11, office, ports-secteam)@FreeBSD team
(fluffy@FreeBSD.org, https://t.me/FluffyBSD)
> On четверг, сент. 03, 2026 at 12:58 PM, Xavier Beaudouin <kiwi@FreeBSD.org (mailto:kiwi@FreeBSD.org)> wrote:
> The branch main has been updated by kiwi:
>
> URL: https://cgit.FreeBSD.org/ports/commit/?id=497924deb1b06877f232f7088ab05d540b8e27d2
>
> commit 497924deb1b06877f232f7088ab05d540b8e27d2
> Author: Jochen Neumeister <joneum@FreeBSD.org>
> AuthorDate: 2026-09-03 09:55:28 +0000
> Commit: Xavier Beaudouin <kiwi@FreeBSD.org>
> CommitDate: 2026-09-03 09:57:46 +0000
>
> net/freeipa-client: make host enrollment work on FreeBSD
>
> This update make client enrollment against a net/freeipa-server
> working.
>
> PR: 297487
> Approved by: kiwi (maintainer)
> ---
> net/freeipa-client/Makefile | 22 +
> net/freeipa-client/files/patch-client_ipa-join.c | 20 +
> net/freeipa-client/files/patch-ipalib_config.py | 14 +
> net/freeipa-client/files/patch-ipalib_frontend.py | 14 +
> .../files/patch-ipaplatform_base_paths.py | 129 +++++
> .../files/patch-ipaplatform_base_tasks.py | 11 +
> .../files/patch-ipaplatform_freebsd_constants.py | 22 +
> .../files/patch-ipaplatform_freebsd_paths.py | 235 +++++++++
> .../files/patch-ipaplatform_freebsd_services.py | 525 +++++++++++++++++++++
> .../files/patch-ipaplatform_freebsd_tasks.py | 247 ++++++++++
> .../files/patch-ipapython_ipautil.py | 11 +
> .../files/patch-ipapython_kernel__keyring.py | 12 +
> net/freeipa-client/files/patch-util_ipa__ldap.h | 11 +
> net/freeipa-client/pkg-plist | 8 +
> 14 files changed, 1281 insertions(+)
>
> diff --git a/net/freeipa-client/Makefile b/net/freeipa-client/Makefile
> index fc270f8a1aef..5bc437a60eb3 100644
> --- a/net/freeipa-client/Makefile
> +++ b/net/freeipa-client/Makefile
> @@ -1,5 +1,6 @@
> PORTNAME= freeipa-client
> DISTVERSION= 4.13.1
> +PORTREVISION= 1
> CATEGORIES= net
> MASTER_SITES= https://releases.pagure.org/freeipa/
> DISTNAME= freeipa-${DISTVERSION}
> @@ -25,6 +26,24 @@ LIB_DEPENDS= libcmocka.so:sysutils/cmocka \
> libsasl2.so:security/cyrus-sasl2 \
> libxmlrpc.so:net/xmlrpc-c
>
> +RUN_DEPENDS= ${LOCALBASE}/bin/chronyc:net/chrony \
> + ${LOCALBASE}/sbin/certmonger:security/certmonger \
> + ${PYTHON_PKGNAMEPREFIX}cffi>0:devel/py-cffi@${PY_FLAVOR} \
> + ${PYTHON_PKGNAMEPREFIX}cryptography>0:security/py-cryptography@${PY_FLAVOR} \
> + ${PYTHON_PKGNAMEPREFIX}dbus>0:devel/py-dbus@${PY_FLAVOR} \
> + ${PYTHON_PKGNAMEPREFIX}dnspython>0:dns/py-dnspython@${PY_FLAVOR} \
> + ${PYTHON_PKGNAMEPREFIX}gssapi>0:security/py-gssapi@${PY_FLAVOR} \
> + ${PYTHON_PKGNAMEPREFIX}ifaddr>0:net/py-ifaddr@${PY_FLAVOR} \
> + ${PYTHON_PKGNAMEPREFIX}netaddr>0:net/py-netaddr@${PY_FLAVOR} \
> + ${PYTHON_PKGNAMEPREFIX}pyasn1>0:devel/py-pyasn1@${PY_FLAVOR} \
> + ${PYTHON_PKGNAMEPREFIX}pyasn1-modules>0:devel/py-pyasn1-modules@${PY_FLAVOR} \
> + ${PYTHON_PKGNAMEPREFIX}python-augeas>0:textproc/py-python-augeas@${PY_FLAVOR} \
> + ${PYTHON_PKGNAMEPREFIX}python-ldap>0:net/py-python-ldap@${PY_FLAVOR} \
> + ${PYTHON_PKGNAMEPREFIX}qrcode>0:textproc/py-qrcode@${PY_FLAVOR} \
> + ${PYTHON_PKGNAMEPREFIX}six>0:devel/py-six@${PY_FLAVOR} \
> + sssd2>0:security/sssd2 \
> + ${PYTHON_PKGNAMEPREFIX}urllib3>0:net/py-urllib3@${PY_FLAVOR}
> +
> USES= autoreconf gettext gmake gssapi:mit ldap libtool \
> localbase:ldflags ssl pkgconfig python
>
> @@ -50,6 +69,9 @@ PLIST_SUB= DISTVERSION=${DISTVERSION}
> # Make sample configuration file
> post-install:
> @${MV} ${STAGEDIR}${PREFIX}/etc/ipa/epn.conf ${STAGEDIR}${PREFIX}/etc/ipa/epn.conf.sample
> + @${MKDIR} ${STAGEDIR}/var/db/ipa-client/pki
> + @${MKDIR} ${STAGEDIR}/var/db/ipa-client/sysrestore
> + @${MKDIR} ${STAGEDIR}${PREFIX}/etc/krb5.conf.d
>
> post-stage:
> ${REINPLACE_CMD} -e 's|${STAGEDIR}||' \
> diff --git a/net/freeipa-client/files/patch-client_ipa-join.c b/net/freeipa-client/files/patch-client_ipa-join.c
> new file mode 100644
> index 000000000000..db8322849f28
> --- /dev/null
> +++ b/net/freeipa-client/files/patch-client_ipa-join.c
> @@ -0,0 +1,20 @@
> +--- client/ipa-join.c.orig 2025-01-15 10:52:51.570724638 +0100
> ++++ client/ipa-join.c 2026-08-12 23:05:48.986059000 +0200
> +@@ -1197,7 +1197,7 @@
> +
> + if (childpid == 0) {
> + char *argv[12];
> +- char *path = "/usr/sbin/ipa-getkeytab";
> ++ char *path = "/usr/local/sbin/ipa-getkeytab";
> + int arg = 0;
> + int err;
> +
> +@@ -1372,7 +1372,7 @@
> + }
> + krb5_cc_close(krbctx, ccache);
> + ccache = NULL;
> +- putenv("KRB5CCNAME=MEMORY:ipa-join");
> ++ setenv("KRB5CCNAME", "MEMORY:ipa-join", 1);
> +
> + #ifdef WITH_IPA_JOIN_XML
> + rval = xmlrpc_unenroll_host(ipaserver, hostname, quiet);
> diff --git a/net/freeipa-client/files/patch-ipalib_config.py b/net/freeipa-client/files/patch-ipalib_config.py
> new file mode 100644
> index 000000000000..c3b8cb2f2199
> --- /dev/null
> +++ b/net/freeipa-client/files/patch-ipalib_config.py
> @@ -0,0 +1,14 @@
> +--- ipalib/config.py.orig 2026-08-11 07:29:25 UTC
> ++++ ipalib/config.py
> +@@ -495,7 +495,10 @@ class Env:
> + elif self.in_tree:
> + self.confdir = self.dot_ipa
> + else:
> +- self.confdir = path.join('/', 'etc', 'ipa')
> ++ # FreeBSD: honour the platform confdir (paths.ETC_IPA)
> ++ # instead of the hard-coded Linux /etc/ipa.
> ++ from ipaplatform.paths import paths as _ipaplatform_paths
> ++ self.confdir = _ipaplatform_paths.ETC_IPA
> +
> + # Set conf (config file for this context):
> + if 'conf' not in self:
> diff --git a/net/freeipa-client/files/patch-ipalib_frontend.py b/net/freeipa-client/files/patch-ipalib_frontend.py
> new file mode 100644
> index 000000000000..014cd2299c1b
> --- /dev/null
> +++ b/net/freeipa-client/files/patch-ipalib_frontend.py
> @@ -0,0 +1,14 @@
> +--- ipalib/frontend.py.orig 2026-07-08 19:34:13 UTC
> ++++ ipalib/frontend.py
> +@@ -481,7 +481,10 @@ class Command(HasParam):
> + return
> + setattr(context, 'audit_action', None)
> +
> +- from systemd import journal
> ++ try:
> ++ from systemd import journal
> ++ except ImportError:
> ++ return
> + from ipalib.ipajson import json_encode_binary
> + args_opts = dict([*self._safe_args_and_params(**params)])
> + json_encoded = json_encode_binary(args_opts, API_VERSION,
> diff --git a/net/freeipa-client/files/patch-ipaplatform_base_paths.py b/net/freeipa-client/files/patch-ipaplatform_base_paths.py
> new file mode 100644
> index 000000000000..1159b57f7cb7
> --- /dev/null
> +++ b/net/freeipa-client/files/patch-ipaplatform_base_paths.py
> @@ -0,0 +1,129 @@
> +--- ipaplatform/base/paths.py.orig 2026-01-16 09:23:31 UTC
> ++++ ipaplatform/base/paths.py
> +@@ -88,13 +88,13 @@ class BasePathNamespace:
> + NAMED_CUSTOM_CONF = "/etc/named/ipa-ext.conf"
> + NAMED_LOGGING_OPTIONS_CONF = "/etc/named/ipa-logging-ext.conf"
> + NAMED_CUSTOM_OPTIONS_CONF = "/etc/named/ipa-options-ext.conf"
> +- NAMED_CONF_SRC = '/usr/share/ipa/bind.named.conf.template'
> +- NAMED_CUSTOM_CONF_SRC = '/usr/share/ipa/bind.ipa-ext.conf.template'
> ++ NAMED_CONF_SRC = '/usr/local/share/ipa/bind.named.conf.template'
> ++ NAMED_CUSTOM_CONF_SRC = '/usr/local/share/ipa/bind.ipa-ext.conf.template'
> + NAMED_CUSTOM_OPTIONS_CONF_SRC = (
> +- '/usr/share/ipa/bind.ipa-options-ext.conf.template'
> ++ '/usr/local/share/ipa/bind.ipa-options-ext.conf.template'
> + )
> + NAMED_LOGGING_OPTIONS_CONF_SRC = (
> +- "/usr/share/ipa/bind.ipa-logging-ext.conf.template"
> ++ "/usr/local/share/ipa/bind.ipa-logging-ext.conf.template"
> + )
> + NAMED_VAR_DIR = "/var/named"
> + NAMED_KEYTAB = "/etc/named.keytab"
> +@@ -102,7 +102,7 @@ class BasePathNamespace:
> + NAMED_ROOT_KEY = "/etc/named.root.key"
> + NAMED_MANAGED_KEYS_DIR = "/var/named/dynamic"
> + NAMED_CRYPTO_POLICY_FILE = None
> +- UNBOUND_CONF_SRC = '/usr/share/ipa/client/unbound.conf.template'
> ++ UNBOUND_CONF_SRC = '/usr/local/share/ipa/client/unbound.conf.template'
> + UNBOUND_CONFIG_DIR = "/etc/unbound/conf.d/"
> + UNBOUND_CONF = "/etc/unbound/conf.d/zzz-ipa.conf"
> + NSLCD_CONF = "/etc/nslcd.conf"
> +@@ -143,11 +143,11 @@ class BasePathNamespace:
> + LIMITS_CONF = "/etc/security/limits.conf"
> + SSH_CONFIG_DIR = "/etc/ssh"
> + SSH_CONFIG = "/etc/ssh/ssh_config"
> +- SSH_IPA_CONFIG_TEMPLATE = "/usr/share/ipa/client/ssh_ipa.conf.template"
> ++ SSH_IPA_CONFIG_TEMPLATE = "/usr/local/share/ipa/client/ssh_ipa.conf.template"
> + SSH_IPA_CONFIG = "/etc/ssh/ssh_config.d/04-ipa.conf"
> + SSHD_CONFIG = "/etc/ssh/sshd_config"
> + SSHD_IPA_CONFIG = "/etc/ssh/sshd_config.d/04-ipa.conf"
> +- SSHD_IPA_CONFIG_TEMPLATE = "/usr/share/ipa/client/sshd_ipa.conf.template"
> ++ SSHD_IPA_CONFIG_TEMPLATE = "/usr/local/share/ipa/client/sshd_ipa.conf.template"
> + SSSD_CONF = "/etc/sssd/sssd.conf"
> + SSSD_CONF_BKP = "/etc/sssd/sssd.conf.bkp"
> + SSSD_CONF_DELETED = "/etc/sssd/sssd.conf.deleted"
> +@@ -214,8 +214,8 @@ class BasePathNamespace:
> + KLIST = "/usr/bin/klist"
> + KTUTIL = "/usr/bin/ktutil"
> + BIN_KVNO = "/usr/bin/kvno"
> +- LDAPMODIFY = "/usr/bin/ldapmodify"
> +- LDAPPASSWD = "/usr/bin/ldappasswd"
> ++ LDAPMODIFY = "/usr/local/bin/ldapmodify"
> ++ LDAPPASSWD = "/usr/local/bin/ldappasswd"
> + MODUTIL = "/usr/bin/modutil"
> + NET = "/usr/bin/net"
> + BIN_NISDOMAINNAME = "/usr/bin/nisdomainname"
> +@@ -283,6 +283,7 @@ class BasePathNamespace:
> + PKIDESTROY = "/usr/sbin/pkidestroy"
> + PKISPAWN = "/usr/sbin/pkispawn"
> + PKI = "/usr/bin/pki"
> ++ PKI_SERVER = "/usr/sbin/pki-server"
> + RESTORECON = "/usr/sbin/restorecon"
> + SELINUXENABLED = "/usr/sbin/selinuxenabled"
> + SETSEBOOL = "/usr/sbin/setsebool"
> +@@ -292,16 +293,16 @@ class BasePathNamespace:
> + FONTS_DIR = "/usr/share/fonts"
> + FONTS_OPENSANS_DIR = "/usr/share/fonts/open-sans"
> + FONTS_FONTAWESOME_DIR = "/usr/share/fonts/fontawesome"
> +- USR_SHARE_IPA_DIR = "/usr/share/ipa/"
> +- USR_SHARE_IPA_CLIENT_DIR = "/usr/share/ipa/client"
> +- CA_TOPOLOGY_ULDIF = "/usr/share/ipa/ca-topology.uldif"
> +- IPA_HTML_DIR = "/usr/share/ipa/html"
> +- CA_CRT = "/usr/share/ipa/html/ca.crt"
> +- SCHEMA_COMPAT_ULDIF = "/usr/share/ipa/updates/91-schema_compat.update"
> +- SCHEMA_COMPAT_POST_ULDIF = "/usr/share/ipa/schema_compat_post.uldif"
> +- SUBID_GENERATORS_ULDIF = "/usr/share/ipa/subid-generators.uldif"
> +- IPA_JS_PLUGINS_DIR = "/usr/share/ipa/ui/js/plugins"
> +- UPDATES_DIR = "/usr/share/ipa/updates/"
> ++ USR_SHARE_IPA_DIR = "/usr/local/share/ipa/"
> ++ USR_SHARE_IPA_CLIENT_DIR = "/usr/local/share/ipa/client"
> ++ CA_TOPOLOGY_ULDIF = "/usr/local/share/ipa/ca-topology.uldif"
> ++ IPA_HTML_DIR = "/usr/local/share/ipa/html"
> ++ CA_CRT = "/usr/local/share/ipa/html/ca.crt"
> ++ SCHEMA_COMPAT_ULDIF = "/usr/local/share/ipa/updates/91-schema_compat.update"
> ++ SCHEMA_COMPAT_POST_ULDIF = "/usr/local/share/ipa/schema_compat_post.uldif"
> ++ SUBID_GENERATORS_ULDIF = "/usr/local/share/ipa/subid-generators.uldif"
> ++ IPA_JS_PLUGINS_DIR = "/usr/local/share/ipa/ui/js/plugins"
> ++ UPDATES_DIR = "/usr/local/share/ipa/updates/"
> + DICT_WORDS = "/usr/share/dict/words"
> + VAR_KERBEROS_KRB5KDC_DIR = "/var/kerberos/krb5kdc/"
> + VAR_KRB5KDC_K5_REALM = "/var/kerberos/krb5kdc/.k5."
> +@@ -408,7 +409,7 @@ class BasePathNamespace:
> + IPA_RENEWAL_LOCK = "/run/ipa/renewal.lock"
> + SVC_LIST_FILE = "/run/ipa/services.list"
> + KRB5CC_SAMBA = "/run/samba/krb5cc_samba"
> +- SLAPD_INSTANCE_SOCKET_TEMPLATE = "/run/slapd-%s.socket"
> ++ SLAPD_INSTANCE_SOCKET_TEMPLATE = "/var/run/slapd-%s.socket"
> + ADMIN_CERT_PATH = '/root/.dogtag/pki-tomcat/ca_admin.cert'
> + ENTROPY_AVAIL = '/proc/sys/kernel/random/entropy_avail'
> + KDCPROXY_CONFIG = '/etc/ipa/kdcproxy/kdcproxy.conf'
> +@@ -428,7 +429,7 @@ class BasePathNamespace:
> + IPA_CUSTODIA_CHECK = "/usr/libexec/ipa/ipa-custodia-check"
> + IPA_GETKEYTAB = '/usr/sbin/ipa-getkeytab'
> + IPA_MIGRATE_LOG = '/var/log/ipa-migrate.log'
> +- EXTERNAL_SCHEMA_DIR = '/usr/share/ipa/schema.d'
> ++ EXTERNAL_SCHEMA_DIR = '/usr/local/share/ipa/schema.d'
> + GSSPROXY_CONF = '/etc/gssproxy/10-ipa.conf'
> + KRB5CC_HTTPD = '/tmp/krb5cc-httpd'
> + IF_INET6 = '/proc/net/if_inet6'
> +@@ -442,9 +443,9 @@ class BasePathNamespace:
> + DSCTL = '/usr/sbin/dsctl'
> + DSCONF = '/usr/sbin/dsconf'
> + # DS related constants
> +- ETC_DIRSRV = "/etc/dirsrv"
> +- DS_KEYTAB = "/etc/dirsrv/ds.keytab"
> +- ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE = "/etc/dirsrv/slapd-%s"
> ++ ETC_DIRSRV = "/usr/local/etc/dirsrv"
> ++ DS_KEYTAB = "/usr/local/etc/dirsrv/ds.keytab"
> ++ ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE = "/usr/local/etc/dirsrv/slapd-%s"
> + USR_LIB_DIRSRV = "/usr/lib/dirsrv"
> + USR_LIB_DIRSRV_64 = "/usr/lib64/dirsrv"
> + VAR_LIB_DIRSRV_INSTANCE_SCRIPTS_TEMPLATE = "/var/lib/dirsrv/scripts-%s"
> +@@ -453,7 +454,7 @@ class BasePathNamespace:
> + SLAPD_INSTANCE_DB_DIR_TEMPLATE = "/var/lib/dirsrv/slapd-%s/db/%s"
> + SLAPD_INSTANCE_LDIF_DIR_TEMPLATE = "/var/lib/dirsrv/slapd-%s/ldif"
> + DIRSRV_LOCK_DIR = "/run/lock/dirsrv"
> +- ALL_SLAPD_INSTANCE_SOCKETS = "/run/slapd-*.socket"
> ++ ALL_SLAPD_INSTANCE_SOCKETS = "/var/run/slapd-*.socket"
> + VAR_LOG_DIRSRV_INSTANCE_TEMPLATE = "/var/log/dirsrv/slapd-%s"
> + VAR_LOG_DIRSRV = "/var/log/dirsrv/"
> + SLAPD_INSTANCE_ACCESS_LOG_TEMPLATE = "/var/log/dirsrv/slapd-%s/access"
> diff --git a/net/freeipa-client/files/patch-ipaplatform_base_tasks.py b/net/freeipa-client/files/patch-ipaplatform_base_tasks.py
> new file mode 100644
> index 000000000000..7326c0ba5b9a
> --- /dev/null
> +++ b/net/freeipa-client/files/patch-ipaplatform_base_tasks.py
> @@ -0,0 +1,11 @@
> +--- ipaplatform/base/tasks.py.orig 2026-01-16 09:23:31 UTC
> ++++ ipaplatform/base/tasks.py
> +@@ -303,7 +303,7 @@ class BaseTaskNamespace:
> + :param version: textual version
> + :return: object implementing proper __cmp__ method for version compare
> + """
> +- return IPAAbstractVersion(parse_version(version))
> ++ return parse_version(version)
> +
> + def set_hostname(self, hostname):
> + """
> diff --git a/net/freeipa-client/files/patch-ipaplatform_freebsd_constants.py b/net/freeipa-client/files/patch-ipaplatform_freebsd_constants.py
> new file mode 100644
> index 000000000000..f6f948806734
> --- /dev/null
> +++ b/net/freeipa-client/files/patch-ipaplatform_freebsd_constants.py
> @@ -0,0 +1,22 @@
> +--- ipaplatform/freebsd/constants.py.orig 2026-06-30 21:34:05 UTC
> ++++ ipaplatform/freebsd/constants.py
> +@@ -0,0 +1,19 @@
> ++#
> ++# Copyright (C) 2026 FreeIPA Contributors see COPYING for license
> ++#
> ++
> ++from ipaplatform.base.constants import BaseConstantsNamespace, Group, User
> ++
> ++__all__ = ("constants", "User", "Group")
> ++
> ++
> ++class FreeBSDConstantsNamespace(BaseConstantsNamespace):
> ++ HTTPD_USER = User("www")
> ++ HTTPD_GROUP = Group("www")
> ++ NAMED_USER = User("bind")
> ++ NAMED_GROUP = Group("bind")
> ++ ODS_USER = User("opendnssec")
> ++ ODS_GROUP = Group("opendnssec")
> ++
> ++
> ++constants = FreeBSDConstantsNamespace()
> diff --git a/net/freeipa-client/files/patch-ipaplatform_freebsd_paths.py b/net/freeipa-client/files/patch-ipaplatform_freebsd_paths.py
> new file mode 100644
> index 000000000000..6724f0e7fecf
> --- /dev/null
> +++ b/net/freeipa-client/files/patch-ipaplatform_freebsd_paths.py
> @@ -0,0 +1,235 @@
> +--- ipaplatform/freebsd/paths.py.orig 2026-08-11 16:06:37 UTC
> ++++ ipaplatform/freebsd/paths.py
> +@@ -0,0 +1,232 @@
> ++#
> ++# Copyright (C) 2026 FreeIPA Contributors see COPYING for license
> ++#
> ++
> ++from ipaplatform.base.paths import BasePathNamespace
> ++
> ++
> ++class FreeBSDPathNamespace(BasePathNamespace):
> ++ USR_SHARE_IPA_DIR = "/usr/local/share/ipa/"
> ++ USR_SHARE_IPA_CLIENT_DIR = "/usr/local/share/ipa/client"
> ++ SSH_IPA_CONFIG_TEMPLATE = "/usr/local/share/ipa/client/ssh_ipa.conf.template"
> ++ SSHD_IPA_CONFIG_TEMPLATE = "/usr/local/share/ipa/client/sshd_ipa.conf.template"
> ++ UNBOUND_CONF_SRC = "/usr/local/share/ipa/client/unbound.conf.template"
> ++ PKIDESTROY = "/usr/local/sbin/pkidestroy"
> ++ PKISPAWN = "/usr/local/sbin/pkispawn"
> ++ PKI = "/usr/local/bin/pki"
> ++ PKI_SERVER = "/usr/local/sbin/pki-server"
> ++ BIN_TOMCAT = "/usr/local/apache-tomcat-9.0/bin/catalina.sh"
> ++ BIN_PS = "/bin/ps"
> ++
> ++ PKI_CONFIGURATION = "/usr/local/etc/pki"
> ++ PKI_TOMCAT = "/var/db/pki/pki-tomcat/conf"
> ++ PKI_TOMCAT_ALIAS_DIR = "/var/db/pki/pki-tomcat/alias"
> ++ PKI_TOMCAT_ALIAS_PWDFILE_TXT = "/var/db/pki/pki-tomcat/alias/pwdfile.txt"
> ++ PKI_TOMCAT_PASSWORD_CONF = "/var/db/pki/pki-tomcat/conf/password.conf"
> ++ PKI_TOMCAT_SERVER_XML = "/var/db/pki/pki-tomcat/conf/server.xml"
> ++ PKI_ACME_CONFIGSOURCES_CONF = "/var/db/pki/pki-tomcat/conf/acme/configsources.conf"
> ++ PKI_ACME_DATABASE_CONF = "/var/db/pki/pki-tomcat/conf/acme/database.conf"
> ++ PKI_ACME_ENGINE_CONF = "/var/db/pki/pki-tomcat/conf/acme/engine.conf"
> ++ PKI_ACME_ISSUER_CONF = "/var/db/pki/pki-tomcat/conf/acme/issuer.conf"
> ++ PKI_ACME_REALM_CONF = "/var/db/pki/pki-tomcat/conf/acme/realm.conf"
> ++
> ++ VAR_LIB_PKI_DIR = "/var/db/pki"
> ++ VAR_LIB_PKI_CA_ALIAS_DIR = "/var/db/pki-ca/alias"
> ++ VAR_LIB_PKI_TOMCAT_DIR = "/var/db/pki/pki-tomcat"
> ++ CA_BACKUP_KEYS_P12 = "/var/db/pki/pki-tomcat/alias/ca_backup_keys.p12"
> ++ KRA_BACKUP_KEYS_P12 = "/var/db/pki/pki-tomcat/alias/kra_backup_keys.p12"
> ++ CA_CS_CFG_PATH = "/var/db/pki/pki-tomcat/conf/ca/CS.cfg"
> ++ CASIGNEDLOGCERT_CFG = "/var/db/pki/pki-tomcat/ca/profiles/ca/caSignedLogCert.cfg"
> ++ KRA_CS_CFG_PATH = "/var/db/pki/pki-tomcat/conf/kra/CS.cfg"
> ++ SVC_LIST_FILE = "/var/run/ipa/services.list"
> ++ IPA_OTPD_INETD_CONF = "/var/run/ipa/ipa-otpd.inetd.conf"
> ++ IPA_OTPD_INETD_PID = "/var/run/ipa/ipa-otpd-inetd.pid"
> ++ IPA_OTPD_SOCKET_DIR = "/var/run/krb5kdc"
> ++ IPA_OTPD_SOCKET = "/var/run/krb5kdc/DEFAULT.socket"
> ++ IPA_CCACHES = "/var/run/ipa/ccaches"
> ++ IPA_RENEWAL_LOCK = "/var/run/ipa/renewal.lock"
> ++ KLIST = "/usr/local/bin/klist"
> ++ KADMIN_LOCAL = "/usr/local/sbin/kadmin.local"
> ++ KDB5_UTIL = "/usr/local/sbin/kdb5_util"
> ++
> ++ ETC_IPA = "/usr/local/etc/ipa"
> ++ IPA_DEFAULT_CONF = "/usr/local/etc/ipa/default.conf"
> ++
> ++ IPA_CUSTODIA_CONF_DIR = "/usr/local/etc/ipa/custodia"
> ++ IPA_CUSTODIA_CONF = "/usr/local/etc/ipa/custodia/custodia.conf"
> ++ IPA_CUSTODIA_KEYS = "/usr/local/etc/ipa/custodia/server.keys"
> ++ IPA_CUSTODIA_SOCKET = "/var/run/httpd/ipa-custodia.sock"
> ++
> ++ KDCPROXY_CONFIG = "/usr/local/etc/ipa/kdcproxy/kdcproxy.conf"
> ++
> ++ VAR_LIB_IPA = "/var/db/ipa"
> ++ CA_BUNDLE_PEM = "/var/db/ipa-client/pki/ca-bundle.pem"
> ++ KDC_CA_BUNDLE_PEM = "/var/db/ipa-client/pki/kdc-ca-bundle.pem"
> ++ HTTPD_CERT_FILE = "/var/db/ipa/certs/httpd.crt"
> ++ HTTPD_KEY_FILE = "/var/db/ipa/private/httpd.key"
> ++ HTTPD_PASSWD_FILE_FMT = "/var/db/ipa/passwds/{host}-443-RSA"
> ++ HTTP_KEYTAB = "/var/db/ipa/gssproxy/http.keytab"
> ++ GSSPROXY_CONF = "/usr/local/etc/gssproxy/10-ipa.conf"
> ++ IPA_CCACHE_SWEEPER_GSSPROXY_SOCK = (
> ++ "/var/db/gssproxy/ipa_ccache_sweeper.sock"
> ++ )
> ++ RA_AGENT_PEM = "/var/db/ipa/ra-agent.pem"
> ++ RA_AGENT_KEY = "/var/db/ipa/ra-agent.key"
> ++ IPA_BACKUP_DIR = "/var/db/ipa/backup"
> ++ IPA_DNSSEC_DIR = "/var/db/ipa/dnssec"
> ++ IPA_KASP_DB_BACKUP = "/var/db/ipa/ipa-kasp.db.backup"
> ++ DNSSEC_TOKENS_DIR = "/var/db/ipa/dnssec/tokens"
> ++ DNSSEC_SOFTHSM_PIN = "/var/db/ipa/dnssec/softhsm_pin"
> ++ IPA_CA_CSR = "/var/db/ipa/ca.csr"
> ++ REPLICA_INFO_TEMPLATE = "/var/db/ipa/replica-info-%s"
> ++ REPLICA_INFO_GPG_TEMPLATE = "/var/db/ipa/replica-info-%s.gpg"
> ++ PKI_CA_PUBLISH_DIR = "/var/db/ipa/pki-ca/publish"
> ++ CERTUTIL = "/usr/local/bin/certutil"
> ++ PK12UTIL = "/usr/local/bin/pk12util"
> ++ MODUTIL = "/usr/local/bin/modutil"
> ++ SYSCONFIG_PKI_TOMCAT = "/var/db/pki/pki-tomcat/conf/tomcat.conf"
> ++ SYSCONFIG_PKI_TOMCAT_PKI_TOMCAT_DIR = "/usr/local/etc/pki/tomcat/pki-tomcat"
> ++ IPA_CLIENT_SYSRESTORE = "/var/db/ipa-client/sysrestore"
> ++ SYSRESTORE_INDEX = "/var/db/ipa-client/sysrestore/sysrestore.index"
> ++ SYSRESTORE = "/var/db/ipa/sysrestore"
> ++ STATEFILE_DIR = "/var/db/ipa/sysupgrade"
> ++
> ++ VAR_KERBEROS_KRB5KDC_DIR = "/usr/local/var/krb5kdc/"
> ++ KRB5_CONF = "/usr/local/etc/krb5.conf"
> ++ COMMON_KRB5_CONF_DIR = "/usr/local/etc/krb5.conf.d/"
> ++ KRB5_FREEIPA_DEFAULTS = "/usr/local/etc/krb5.conf.d/freeipa"
> ++ KRB5_FREEIPA = "/usr/local/etc/krb5.conf.d/freeipa-realm"
> ++ KRB5_FREEIPA_SERVER = "/usr/local/etc/krb5.conf.d/freeipa-server"
> ++ VAR_KRB5KDC_K5_REALM = "/usr/local/var/krb5kdc/.k5."
> ++ CACERT_PEM = "/usr/local/var/krb5kdc/cacert.pem"
> ++ KRB5KDC_KADM5_ACL = "/usr/local/var/krb5kdc/kadm5.acl"
> ++ KRB5KDC_KADM5_KEYTAB = "/usr/local/var/krb5kdc/kadm5.keytab"
> ++ KRB5KDC_KDC_CONF = "/usr/local/var/krb5kdc/kdc.conf"
> ++ KDC_CERT = "/usr/local/var/krb5kdc/kdc.crt"
> ++ KDC_KEY = "/usr/local/var/krb5kdc/kdc.key"
> ++
> ++ IPACTL = "/usr/local/sbin/ipactl"
> ++ IPA_CLIENT_AUTOMOUNT = "/usr/local/sbin/ipa-client-automount"
> ++ IPA_CLIENT_INSTALL = "/usr/local/sbin/ipa-client-install"
> ++ IPA_GETKEYTAB = "/usr/local/sbin/ipa-getkeytab"
> ++ IPA_RMKEYTAB = "/usr/local/sbin/ipa-rmkeytab"
> ++ SBIN_IPA_JOIN = "/usr/local/sbin/ipa-join"
> ++ CONNCHECK_CCACHE = "/usr/local/etc/ipa/.conncheck_ccache"
> ++ IPA_DNS_CCACHE = "/usr/local/etc/ipa/.dns_ccache"
> ++ OPENLDAP_LDAP_CONF = "/usr/local/etc/openldap/ldap.conf"
> ++ IPA_DNS_UPDATE_TXT = "/usr/local/etc/ipa/.dns_update.txt"
> ++ IPA_CA_CRT = "/usr/local/etc/ipa/ca.crt"
> ++ IPA_DNSKEYSYNCD_KEYTAB = "/usr/local/etc/ipa/dnssec/ipa-dnskeysyncd.keytab"
> ++ IPA_ODS_EXPORTER_KEYTAB = "/usr/local/etc/ipa/dnssec/ipa-ods-exporter.keytab"
> ++ IPA_SERVER_CONF = "/usr/local/etc/ipa/server.conf"
> ++ DNSSEC_OPENSSL_CONF = "/usr/local/etc/ipa/dnssec/openssl.cnf"
> ++ DNSSEC_SOFTHSM2_CONF = "/usr/local/etc/ipa/dnssec/softhsm2.conf"
> ++ DNSSEC_SOFTHSM_PIN_SO = "/usr/local/etc/ipa/dnssec/softhsm_pin_so"
> ++ IPA_NSSDB_DIR = "/usr/local/etc/ipa/nssdb"
> ++ IPA_NSSDB_PWDFILE_TXT = "/usr/local/etc/ipa/nssdb/pwdfile.txt"
> ++ NSS_DB_DIR = "/usr/local/etc/pki/nssdb"
> ++
> ++ LIBEXEC_IPA_DIR = "/usr/local/libexec/ipa"
> ++ IPA_OTPD = "/usr/local/libexec/ipa/ipa-otpd"
> ++ IPA_OTPD_WRAPPER = "/usr/local/libexec/ipa/ipa-otpd-wrapper"
> ++ IPA_OTPD_LOG = "/var/log/ipa-otpd.log"
> ++ LIBEXEC_CERTMONGER_DIR = "/usr/local/libexec/certmonger"
> ++ CERTMONGER_COMMAND_TEMPLATE = "/usr/local/libexec/ipa/certmonger/%s"
> ++ CERTMONGER_DOGTAG_SUBMIT = "/usr/local/libexec/certmonger/dogtag-submit"
> ++ DOGTAG_IPA_CA_RENEW_AGENT_SUBMIT = "/usr/local/libexec/certmonger/dogtag-ipa-ca-renew-agent-submit"
> ++ DOGTAG_IPA_RENEW_AGENT_SUBMIT = "/usr/local/libexec/certmonger/dogtag-ipa-renew-agent-submit"
> ++ IPA_SERVER_GUARD = "/usr/local/libexec/certmonger/ipa-server-guard"
> ++ IPA_DNSKEYSYNCD_REPLICA = "/usr/local/libexec/ipa/ipa-dnskeysync-replica"
> ++ IPA_DNSKEYSYNCD = "/usr/local/libexec/ipa/ipa-dnskeysyncd"
> ++ IPA_ODS_EXPORTER = "/usr/local/libexec/ipa/ipa-ods-exporter"
> ++ IPA_PKI_RETRIEVE_KEY = "/usr/local/libexec/ipa/ipa-pki-retrieve-key"
> ++ IPA_PKI_WAIT_RUNNING = "/usr/local/libexec/ipa/ipa-pki-wait-running"
> ++ IPA_CUSTODIA_HANDLER = "/usr/local/libexec/ipa/custodia"
> ++ IPA_CUSTODIA_CHECK = "/usr/local/libexec/ipa/ipa-custodia-check"
> ++
> ++ SSSD_CONF = "/usr/local/etc/sssd/sssd.conf"
> ++ SSSD_CONF_BKP = "/usr/local/etc/sssd/sssd.conf.bkp"
> ++ SSSD_CONF_DELETED = "/usr/local/etc/sssd/sssd.conf.deleted"
> ++ SSSD_DB = "/var/db/sss/db"
> ++ SSSD_LDB = "/var/db/sss/db/sssd.ldb"
> ++ SSSD_CONFIG_LDB = "/var/db/sss/db/config.ldb"
> ++ SSSD_MC_GROUP = "/var/db/sss/mc/group"
> ++ SSSD_MC_PASSWD = "/var/db/sss/mc/passwd"
> ++ SSSD_MC_INITGROUPS = "/var/db/sss/mc/initgroups"
> ++ SSSD_MC_SID = "/var/db/sss/mc/sid"
> ++ SSSD_PIPES = "/var/db/sss/pipes"
> ++ SSSD_PUBCONF_DIR = "/var/db/sss/pubconf"
> ++ SSSD_PUBCONF_KNOWN_HOSTS = "/var/db/sss/pubconf/known_hosts"
> ++ SSSD_PUBCONF_KRB5_INCLUDE_D_DIR = "/var/db/sss/pubconf/krb5.include.d/"
> ++ SSSD_KEYTABS_DIR = "/var/db/sss/keytabs"
> ++ SSSD_SECRETS = "/var/db/sss/secrets/secrets.ldb"
> ++
> ++ DSCTL = "/usr/local/bin/dsctl"
> ++
> ++ VAR_LIB_DIRSRV = "/var/db/dirsrv"
> ++ VAR_LIB_DIRSRV_INSTANCE_SCRIPTS_TEMPLATE = "/var/db/dirsrv/scripts-%s"
> ++ VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE = "/var/db/dirsrv/slapd-%s"
> ++ SLAPD_INSTANCE_BACKUP_DIR_TEMPLATE = "/var/db/dirsrv/slapd-%s/bak/%s"
> ++ SLAPD_INSTANCE_DB_DIR_TEMPLATE = "/var/db/dirsrv/slapd-%s/db/%s"
> ++ SLAPD_INSTANCE_LDIF_DIR_TEMPLATE = "/var/db/dirsrv/slapd-%s/ldif"
> ++ VAR_RUN_DIRSRV_DIR = "/var/run/dirsrv"
> ++ DIRSRV_LOCK_DIR = "/var/run/dirsrv"
> ++
> ++ HTTPD = "/usr/local/sbin/httpd"
> ++ ETC_HTTPD_DIR = "/usr/local/etc/apache24"
> ++ HTTPD_ALIAS_DIR = "/usr/local/etc/apache24/alias"
> ++ GSSAPI_SESSION_KEY = "/usr/local/etc/apache24/alias/ipasession.key"
> ++ HTTPD_CONF_D_DIR = "/usr/local/etc/apache24/Includes/"
> ++ HTTPD_IPA_WSGI_MODULES_CONF = "/usr/local/etc/apache24/modules.d/290_freeipa.conf"
> ++ HTTPD_IPA_ENVVARS_CONF = "/usr/local/etc/apache24/envvars.d/ipa.env"
> ++ HTTPD_IPA_RC_CONF = "/usr/local/etc/rc.conf.d/apache24/ipa"
> ++ HTTPD_IPA_CONF = "/usr/local/etc/apache24/Includes/ipa.conf"
> ++ HTTPD_IPA_KDCPROXY_CONF = "/usr/local/etc/ipa/kdcproxy/ipa-kdc-proxy.conf"
> ++ HTTPD_IPA_KDCPROXY_CONF_SYMLINK = "/usr/local/etc/apache24/Includes/ipa-kdc-proxy.conf"
> ++ HTTPD_IPA_PKI_PROXY_CONF = "/usr/local/etc/apache24/Includes/ipa-pki-proxy.conf"
> ++ HTTPD_IPA_REWRITE_CONF = "/usr/local/etc/apache24/Includes/ipa-rewrite.conf"
> ++ HTTPD_NSS_CONF = "/usr/local/etc/apache24/Includes/nss.conf"
> ++ HTTPD_PASSWORD_CONF = "/usr/local/etc/apache24/password.conf"
> ++ HTTPD_SSL_CONF = "/usr/local/etc/apache24/extra/httpd-ssl.conf"
> ++ HTTPD_SSL_SITE_CONF = "/usr/local/etc/apache24/extra/httpd-ssl.conf"
> ++ HTTPD_IPA_SSL_CONF_SYMLINK = "/usr/local/etc/apache24/Includes/ipa-ssl.conf"
> ++ OLD_IPA_KEYTAB = "/usr/local/etc/apache24/ipa.keytab"
> ++ OLD_KRA_AGENT_PEM = "/usr/local/etc/apache24/alias/kra-agent.pem"
> ++ WSGI_PREFIX_DIR = "/var/run/httpd/wsgi"
> ++ IPA_HTTPD_KDCPROXY = "/usr/local/libexec/ipa/ipa-httpd-kdcproxy"
> ++ IPA_HTTPD_PASSWD_READER = "/usr/local/libexec/ipa/ipa-httpd-pwdreader"
> ++
> ++ BIN_CURL = "/usr/local/bin/curl"
> ++ CERTMONGER = "/usr/local/sbin/certmonger"
> ++ GPG2 = "/usr/local/bin/gpg"
> ++ GPG_AGENT = "/usr/local/bin/gpg-agent"
> ++ IPA_DNS_INSTALL = "/usr/local/sbin/ipa-dns-install"
> ++ IPA_REPLICA_CONNCHECK = "/usr/local/sbin/ipa-replica-conncheck"
> ++ IPA_SERVER_UPGRADE = "/usr/local/sbin/ipa-server-upgrade"
> ++ KDESTROY = "/usr/local/bin/kdestroy"
> ++ KINIT = "/usr/local/bin/kinit"
> ++ KTUTIL = "/usr/local/bin/ktutil"
> ++ NET = "/usr/local/bin/net"
> ++ NSUPDATE = "/usr/local/bin/nsupdate"
> ++ SMBD = "/usr/local/sbin/smbd"
> ++ SSSCTL = "/usr/local/sbin/sssctl"
> ++ SSS_SSH_AUTHORIZEDKEYS = "/usr/local/bin/sss_ssh_authorizedkeys"
> ++ SSS_SSH_KNOWNHOSTS = "/usr/local/bin/sss_ssh_knownhosts"
> ++ SSS_SSH_KNOWNHOSTSPROXY = "/usr/local/bin/sss_ssh_knownhostsproxy"
> ++ TDBTOOL = "/usr/local/bin/tdbtool"
> ++
> ++ IPA_CACERT_MANAGE = "/usr/local/sbin/ipa-cacert-manage"
> ++ IPA_GETCERT = "/usr/local/bin/ipa-getcert"
> ++
> ++ CHRONYC = "/usr/local/bin/chronyc"
> ++ CHRONYD = "/usr/local/sbin/chronyd"
> ++ CHRONY_CONF = "/usr/local/etc/chrony.conf"
> ++
> ++ SYSTEMCTL = None
> ++ SYSTEMD_TMPFILES = None
> ++ SBIN_INETD = "/usr/sbin/inetd"
> ++ SBIN_SERVICE = "/usr/sbin/service"
> ++ SBIN_SYSRC = "/usr/sbin/sysrc"
> ++
> ++
> ++paths = FreeBSDPathNamespace()
> diff --git a/net/freeipa-client/files/patch-ipaplatform_freebsd_services.py b/net/freeipa-client/files/patch-ipaplatform_freebsd_services.py
> new file mode 100644
> index 000000000000..a0ee42fb72bf
> --- /dev/null
> +++ b/net/freeipa-client/files/patch-ipaplatform_freebsd_services.py
> @@ -0,0 +1,525 @@
> +--- ipaplatform/freebsd/services.py.orig 2026-08-11 14:55:32 UTC
> ++++ ipaplatform/freebsd/services.py
> +@@ -0,0 +1,522 @@
> ++#
> ++# Copyright (C) 2026 FreeIPA Contributors see COPYING for license
> ++#
> ++
> ++import errno
> ++import json
> ++import logging
> ++import os
> ++import signal
> ++import stat
> ++import time
> ++from configparser import RawConfigParser
> ++
> ++from ipaplatform.base import services as base_services
> ++from ipaplatform.paths import paths
> ++from ipapython import ipautil
> ++
> ++logger = logging.getLogger(__name__)
> ++
> ++freebsd_rc_services = dict((name, name) for name in base_services.wellknownservices)
> ++freebsd_rc_services.update({
> ++ "httpd": "apache24",
> ++ "kadmin": "kadmind",
> ++ "krb5kdc": "kdc",
> ++ "pki_tomcatd": "pki_tomcatd_pki_tomcat",
> ++ "pki-tomcatd": "pki_tomcatd_pki_tomcat",
> ++ "domainname": "nisdomain",
> ++})
> ++
> ++freebsd_rc_enable_names = {
> ++ "ipa-custodia": "ipa_custodia",
> ++}
> ++
> ++freebsd_kerberos_rcvars = {
> ++ "kdc": {
> ++ "kdc_program": "/usr/local/sbin/krb5kdc",
> ++ "kdc_enable": "YES",
> ++ },
> ++ "kadmind": {
> ++ "kdc_program": "/usr/local/sbin/krb5kdc",
> ++ "kdc_enable": "YES",
> ++ "kadmind_program": "/usr/local/sbin/kadmind",
> ++ "kadmind_enable": "YES",
> ++ },
> ++}
> ++
> ++
> ++class FreeBSDService(base_services.PlatformService):
> ++ def __init__(self, service_name, api=None):
> ++ super(FreeBSDService, self).__init__(service_name, api=api)
> ++ self.rc_name = freebsd_rc_services.get(service_name, service_name)
> ++ self.rc_enable_name = freebsd_rc_enable_names.get(
> ++ self.rc_name, self.rc_name.replace("-", "_")
> ++ )
> ++
> ++ def _set_rcvars(self, rcvars):
> ++ for key, value in rcvars.items():
> ++ try:
> ++ ipautil.run([paths.SBIN_SYSRC, "%s=%s" % (key, value)])
> ++ except ipautil.CalledProcessError:
> ++ pass
> ++
> ++ def _prepare_rc_service(self, action):
> ++ if action not in ("onestart", "onerestart", "start", "restart"):
> ++ return
> ++ self._set_rcvars(freebsd_kerberos_rcvars.get(self.rc_name, {}))
> ++
> ++ def _run_service(self, action, capture_output=True):
> ++ self._prepare_rc_service(action)
> ++ daemonizing = action in ("onestart", "onerestart", "start", "restart")
> ++ # rc.d daemons may inherit stdout and stderr. Redirect daemonizing
> ++ # actions to /dev/null to avoid waiting on inherited output pipes.
> ++ return ipautil.run(
> ++ [paths.SBIN_SERVICE, self.rc_name, action],
> ++ skip_output=daemonizing or not capture_output
> ++ )
> ++
> ++ def start(self, instance_name="", capture_output=True, wait=True):
> ++ os.makedirs(os.path.dirname(paths.SVC_LIST_FILE), mode=0o711, exist_ok=True)
> ++ if not self.is_running(instance_name, wait=wait):
> ++ try:
> ++ self._run_service("onestart", capture_output=capture_output)
> ++ except ipautil.CalledProcessError:
> ++ # FreeBSD base rc scripts for the Kerberos daemons (kdc,
> ++ # kadmind) can fail to (re)start while the environment is
> ++ # being torn down -- e.g. SimpleServiceInstance.uninstall()
> ++ # restores a previously-running kadmind after krb5kdc/DS
> ++ # were already unconfigured. Aborting the whole uninstall
> ++ # over a best-effort restore is worse than continuing; a
> ++ # genuine install-time failure still surfaces at the first
> ++ # real use of the service.
> ++ if self.rc_name not in ("kdc", "kadmind"):
> ++ raise
> ++ logger.warning(
> ++ "Ignoring failed '%s onestart' (service could not be "
> ++ "started; likely mid-teardown restore)", self.rc_name)
> ++ super(FreeBSDService, self).start(
> ++ instance_name, capture_output=capture_output, wait=wait
> ++ )
> ++
> ++ def stop(self, instance_name="", capture_output=True):
> ++ if self.is_running(instance_name):
> ++ self._run_service("onestop", capture_output=capture_output)
> ++ super(FreeBSDService, self).stop(
> ++ instance_name, capture_output=capture_output
> ++ )
> ++
> ++ def restart(self, instance_name="", capture_output=True, wait=True):
> ++ self._run_service("onerestart", capture_output=capture_output)
> ++
> ++ def try_restart(self, instance_name="", capture_output=True, wait=True):
> ++ if self.is_running(instance_name, wait=wait):
> ++ self.restart(instance_name, capture_output=capture_output, wait=wait)
> ++
> ++ def reload_or_restart(self, instance_name="", capture_output=True, wait=True):
> ++ self.restart(instance_name, capture_output=capture_output, wait=wait)
> ++
> ++ def is_running(self, instance_name="", wait=True):
> ++ try:
> ++ self._run_service("onestatus", capture_output=True)
> ++ except ipautil.CalledProcessError:
> ++ return False
> ++ return True
> ++
> ++ def is_installed(self):
> ++ return (
> ++ os.path.exists("/etc/rc.d/%s" % self.rc_name) or
> ++ os.path.exists("/usr/local/etc/rc.d/%s" % self.rc_name)
> ++ )
> ++
> ++ def enable(self, instance_name=""):
> ++ try:
> ++ self._set_rcvars(freebsd_kerberos_rcvars.get(self.rc_name, {}))
> ++ ipautil.run([paths.SBIN_SYSRC, "%s_enable=YES" % self.rc_enable_name])
> ++ except ipautil.CalledProcessError:
> ++ pass
> ++
> ++ def disable(self, instance_name=""):
> ++ try:
> ++ ipautil.run([paths.SBIN_SYSRC, "%s_enable=NO" % self.rc_enable_name])
> ++ # Undo the extra rc.conf variables that enable() set for the
> ++ # Kerberos services (kdc_program/kadmind_program and their
> ++ # *_enable flags) so an uninstall leaves no stale rc.conf
> ++ # entries behind.
> ++ for key in freebsd_kerberos_rcvars.get(self.rc_name, {}):
> ++ if key.endswith("_enable"):
> ++ ipautil.run([paths.SBIN_SYSRC, "%s=NO" % key])
> ++ else:
> ++ ipautil.run([paths.SBIN_SYSRC, "-x", key])
> ++ except ipautil.CalledProcessError:
> ++ pass
> ++
> ++ def is_enabled(self, instance_name=""):
> ++ try:
> ++ result = ipautil.run(
> ++ [paths.SBIN_SYSRC, "-n", "%s_enable" % self.rc_enable_name],
> ++ capture_output=True
> ++ )
> ++ except ipautil.CalledProcessError:
> ++ return False
> ++ return result.output.strip().upper() == "YES"
> ++
> ++ def install(self, instance_name=""):
> ++ self.enable(instance_name)
> ++
> ++ def remove(self, instance_name=""):
> ++ self.disable(instance_name)
> ++
> ++
> ++class FreeBSDOtpdService(base_services.PlatformService):
> ++ _START_TIMEOUT = 10.0
> ++ _STOP_TIMEOUT = 10.0
> ++
> ++ @staticmethod
> ++ def _ensure_directory(directory):
> ++ try:
> ++ os.makedirs(directory, 0o755)
> ++ except OSError as error:
> ++ if error.errno not in (errno.EEXIST,):
> ++ raise
> ++ if not os.path.isdir(directory):
> ++ raise RuntimeError("%s is not a directory" % directory)
> ++
> ++ @staticmethod
> ++ def _unlink(path):
> ++ try:
> ++ os.unlink(path)
> ++ except OSError as error:
> ++ if error.errno not in (errno.ENOENT,):
> ++ raise
> ++
> ++ def _read_ldap_uri(self):
> ++ parser = RawConfigParser()
> ++ if not parser.read(paths.IPA_DEFAULT_CONF):
> ++ raise RuntimeError("Unable to read %s" % paths.IPA_DEFAULT_CONF)
> ++ if not parser.has_section("global"):
> ++ raise RuntimeError(
> ++ "Missing global section in %s" % paths.IPA_DEFAULT_CONF
> ++ )
> ++ if not parser.has_option("global", "ldap_uri"):
> ++ raise RuntimeError(
> ++ "Missing ldap_uri in %s" % paths.IPA_DEFAULT_CONF
> ++ )
> ++ ldap_uri = parser.get("global", "ldap_uri").strip()
> ++ if not ldap_uri or any(char.isspace() for char in ldap_uri):
> ++ raise RuntimeError(
> ++ "Invalid ldap_uri in %s" % paths.IPA_DEFAULT_CONF
> ++ )
> ++ return ldap_uri
> ++
> ++ def _write_inetd_config(self):
> ++ self._ensure_directory(os.path.dirname(paths.IPA_OTPD_INETD_CONF))
> ++ self._ensure_directory(paths.IPA_OTPD_SOCKET_DIR)
> ++ ldap_uri = self._read_ldap_uri()
> ++ socket_spec = ":root:wheel:600:%s" % paths.IPA_OTPD_SOCKET
> ++ config_line = (
> ++ "%s\tstream\tunix\tnowait\troot\t%s\tipa-otpd-wrapper %s\n"
> ++ % (socket_spec, paths.IPA_OTPD_WRAPPER, ldap_uri)
> ++ )
> ++ temporary = paths.IPA_OTPD_INETD_CONF + ".tmp"
> ++ with open(temporary, "w") as config:
> ++ config.write(config_line)
> ++ config.flush()
> ++ os.fsync(config.fileno())
> ++ os.chmod(temporary, 0o600)
> ++ os.rename(temporary, paths.IPA_OTPD_INETD_CONF)
> ++
> ++ @staticmethod
> ++ def _read_pid_file():
> ++ try:
> ++ with open(paths.IPA_OTPD_INETD_PID, "r") as pid_file:
> ++ pid = int(pid_file.read().strip())
> ++ except (OSError, ValueError):
> ++ return None
> ++ if pid <= 1:
> ++ return None
> ++ return pid
> ++
> ++ @staticmethod
> ++ def _command_matches(command):
> ++ required = (
> ++ paths.SBIN_INETD,
> ++ paths.IPA_OTPD_INETD_PID,
> ++ paths.IPA_OTPD_INETD_CONF,
> ++ )
> ++ return all(value in command for value in required)
> ++
> ++ def _pid_command(self, pid):
> ++ result = ipautil.run(
> ++ [paths.BIN_PS, "-ww", "-p", str(pid), "-o", "command="],
> ++ capture_output=True,
> ++ raiseonerr=False
> ++ )
> ++ if result.returncode:
> ++ return ""
> ++ return result.output.strip()
> ++
> ++ def _find_pid(self):
> ++ pid = self._read_pid_file()
> ++ if pid is not None and self._command_matches(self._pid_command(pid)):
> ++ return pid
> ++
> ++ result = ipautil.run(
> ++ [paths.BIN_PS, "-axww", "-o", "pid=", "-o", "command="],
> ++ capture_output=True,
> ++ raiseonerr=False
> ++ )
> ++ if result.returncode:
> ++ return None
> ++
> ++ for line in result.output.splitlines():
> ++ fields = line.strip().split(None, 1)
> ++ if len(fields) < 2:
> ++ continue
> ++ try:
> ++ candidate = int(fields[0])
> ++ except ValueError:
> ++ continue
> ++ if self._command_matches(fields[1]):
> ++ return candidate
> ++ return None
> ++
> ++ @staticmethod
> ++ def _wait_until(predicate, timeout):
> ++ deadline = time.monotonic() + timeout
> ++ while time.monotonic() < deadline:
> ++ if predicate():
> ++ return True
> ++ time.sleep(0.1)
> ++ return predicate()
> ++
> ++ def _cleanup_runtime(self):
> ++ self._unlink(paths.IPA_OTPD_SOCKET)
> ++ self._unlink(paths.IPA_OTPD_INETD_PID)
> ++ self._unlink(paths.IPA_OTPD_INETD_CONF)
> ++
> ++ def _stop_private(self):
> ++ pid = self._find_pid()
> ++ if pid is not None:
> ++ try:
> ++ os.kill(pid, signal.SIGTERM)
> ++ except OSError as error:
> ++ if error.errno not in (errno.ESRCH,):
> ++ raise
> ++ stopped = self._wait_until(
> ++ lambda: self._find_pid() is None,
> ++ self._STOP_TIMEOUT
> ++ )
> ++ if not stopped:
> ++ raise RuntimeError("Unable to stop private ipa-otpd inetd")
> ++ self._cleanup_runtime()
> ++
> ++ def _start_private(self, capture_output=True):
> ++ if self.is_running(wait=False):
> ++ return
> ++ if self._find_pid() is not None:
> ++ self._stop_private()
> ++ else:
> ++ self._cleanup_runtime()
> ++ self._write_inetd_config()
> ++ ipautil.run(
> ++ [
> ++ paths.SBIN_INETD,
> ++ "-p",
> ++ paths.IPA_OTPD_INETD_PID,
> ++ paths.IPA_OTPD_INETD_CONF,
> ++ ],
> ++ skip_output=not capture_output
> ++ )
> ++ started = self._wait_until(
> ++ lambda: self.is_running(wait=False),
> ++ self._START_TIMEOUT
> ++ )
> ++ if not started:
> ++ self._stop_private()
> ++ raise RuntimeError("Unable to start private ipa-otpd inetd")
> ++
> ++ def start(self, instance_name="", capture_output=True, wait=True):
> ++ self._start_private(capture_output=capture_output)
> ++ base_services.PlatformService.start(
> ++ self, instance_name, capture_output=capture_output, wait=wait
> ++ )
> ++
> ++ def stop(self, instance_name="", capture_output=True):
> ++ self._stop_private()
> ++ base_services.PlatformService.stop(
> ++ self, instance_name, capture_output=capture_output
> ++ )
> ++
> ++ def restart(self, instance_name="", capture_output=True, wait=True):
> ++ self._stop_private()
> ++ self._start_private(capture_output=capture_output)
> ++
> ++ def try_restart(self, instance_name="", capture_output=True, wait=True):
> ++ if self._find_pid() is not None:
> ++ self.restart(
> ++ instance_name, capture_output=capture_output, wait=wait
> ++ )
> ++
> ++ def reload_or_restart(self, instance_name="", capture_output=True,
> ++ wait=True):
> ++ self.restart(
> ++ instance_name, capture_output=capture_output, wait=wait
> ++ )
> ++
> ++ def is_running(self, instance_name="", wait=True):
> ++ if self._find_pid() is None:
> ++ return False
> ++ try:
> ++ socket_status = os.stat(paths.IPA_OTPD_SOCKET)
> ++ except OSError:
> ++ return False
> ++ return stat.S_ISSOCK(socket_status.st_mode)
> ++
> ++ def is_installed(self):
> ++ return all(os.path.isfile(path) for path in (
> ++ paths.SBIN_INETD,
> ++ paths.IPA_OTPD,
> ++ paths.IPA_OTPD_WRAPPER,
> ++ ))
> ++
> ++ def enable(self, instance_name=""):
> ++ pass
> ++
> ++ def disable(self, instance_name=""):
> ++ pass
> ++
> ++ def is_enabled(self, instance_name=""):
> ++ return False
> ++
> ++ def install(self, instance_name=""):
> ++ pass
> ++
> ++ def remove(self, instance_name=""):
> ++ pass
> ++
> ++
> ++class FreeBSDDirectoryService(FreeBSDService):
> ++ def _instance_name(self, instance_name):
> ++ if instance_name:
> ++ return instance_name
> ++ realm = getattr(self.api.env, "realm", "")
> ++ if realm:
> ++ return realm.replace(".", "-")
> ++ return ""
> ++
> ++ def _run_dsctl(self, instance_name, action, capture_output=True):
> ++ instance_name = self._instance_name(instance_name)
> ++ if not instance_name:
> ++ raise ValueError("Directory Server instance name is required")
> *** 444 LINES SKIPPED ***
>