git: 35e48795412e - main - net/freeipa-server: Add New Port

Jochen Neumeister <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.ports
Message-ID <[email protected]>
The branch main has been updated by joneum:

URL: https://cgit.FreeBSD.org/ports/commit/?id=35e48795412e5aba7dcf12b074b5ffa152aed031

commit 35e48795412e5aba7dcf12b074b5ffa152aed031
Author:     Jochen Neumeister <[email protected]>
AuthorDate: 2026-08-18 20:39:54 +0000
Commit:     Jochen Neumeister <[email protected]>
CommitDate: 2026-08-18 20:41:19 +0000

    net/freeipa-server: Add New Port
    
    FreeIPA is an integrated identity and authentication solution: an LDAP
    directory (389 Directory Server), a Kerberos KDC (MIT krb5), a Dogtag
    PKI certificate authority and a web UI/CLI, combined into a single managed
    domain, the Free Software counterpart to Active Directory.
    
    This port provides the FreeIPA server on FreeBSD together with the
    FreeBSD-specific integration that upstream (Linux/systemd oriented) does
    not ship: an ipaplatform "freebsd" backend, rc.d service scripts, and
    the glue required to run the whole stack against the ports MIT Kerberos
    (security/krb5).
    
    WWW: https://www.freeipa.org/
    
    Sponsored by:   Netzkommune GmbH
---
 GIDs                                               |    4 +-
 UIDs                                               |    4 +-
 net/Makefile                                       |    1 +
 net/freeipa-server/Makefile                        |  147 +
 net/freeipa-server/distinfo                        |    3 +
 net/freeipa-server/files/README.md                 |  283 ++
 net/freeipa-server/files/freeipa-server.in         |  100 +
 .../files/freeipa-server.newsyslog.conf            |    4 +
 net/freeipa-server/files/ipa-custodia.in           |   27 +
 net/freeipa-server/files/ipa-otpd-wrapper.in       |   16 +
 net/freeipa-server/files/patch-Makefile.am         |   29 +
 net/freeipa-server/files/patch-Makefile.python.am  |   15 +
 .../files/patch-asn1_asn1c_asn__system.h           |   11 +
 .../files/patch-client_ipa-getkeytab.c             |   16 +
 net/freeipa-server/files/patch-client_ipa-join.c   |   20 +
 net/freeipa-server/files/patch-configure.ac        |   43 +
 .../files/patch-daemons_ipa-kdb_ipa__kdb.c         |   32 +
 .../files/patch-daemons_ipa-kdb_ipa__kdb__common.c |   13 +
 .../files/patch-daemons_ipa-otpd_oauth2.c          |   10 +
 .../files/patch-daemons_ipa-otpd_parse.c           |   11 +
 .../files/patch-daemons_ipa-otpd_passkey.c         |   10 +
 ...daemons_ipa-slapi-plugins_ipa-cldap_Makefile.am |   10 +
 ...h-daemons_ipa-slapi-plugins_ipa-dns_Makefile.am |   10 +
 ...ns_ipa-slapi-plugins_ipa-enrollment_Makefile.am |   10 +
 ..._ipa-slapi-plugins_ipa-extdom-extop_Makefile.am |   10 +
 ...a-slapi-plugins_ipa-extdom-extop_back__extdom.h |   16 +
 ...ins_ipa-extdom-extop_back__extdom__sss__idmap.c |   13 +
 ...-plugins_ipa-extdom-extop_ipa__extdom__common.c |   12 +
 ...s_ipa-slapi-plugins_ipa-graceperiod_Makefile.am |   10 +
 ...emons_ipa-slapi-plugins_ipa-lockout_Makefile.am |   10 +
 ...aemons_ipa-slapi-plugins_ipa-modrdn_Makefile.am |   10 +
 ...s_ipa-slapi-plugins_ipa-otp-counter_Makefile.am |   10 +
 ...ipa-slapi-plugins_ipa-otp-lasttoken_Makefile.am |   10 +
 ...ons_ipa-slapi-plugins_ipa-pwd-extop_Makefile.am |   10 +
 ...emons_ipa-slapi-plugins_ipa-pwd-extop_prepost.c |   15 +
 ...s_ipa-slapi-plugins_ipa-range-check_Makefile.am |   10 +
 ...aemons_ipa-slapi-plugins_ipa-sidgen_Makefile.am |   12 +
 ...-daemons_ipa-slapi-plugins_ipa-uuid_Makefile.am |   10 +
 ...emons_ipa-slapi-plugins_ipa-version_Makefile.am |   10 +
 ...emons_ipa-slapi-plugins_ipa-winsync_Makefile.am |   10 +
 net/freeipa-server/files/patch-install_Makefile.am |   38 +
 .../files/patch-install_html_Makefile.am           |   11 +
 .../patch-install_share_gssproxy.conf.template     |   18 +
 ...patch-install_share_ipa-kdc-proxy.conf.template |   43 +
 .../files/patch-install_share_ipa.conf.template    |  128 +
 .../files/patch-install_share_wsgi.py              |   18 +
 .../patch-install_tools_ipa-httpd-kdcproxy.in      |   18 +
 .../patch-install_updates_80-schema__compat.update |   11 +
 net/freeipa-server/files/patch-ipalib_config.py    |   14 +
 net/freeipa-server/files/patch-ipalib_frontend.py  |   14 +
 .../files/patch-ipaplatform_base_paths.py          |  129 +
 .../files/patch-ipaplatform_base_tasks.py          |   11 +
 .../patch-ipaplatform_freebsd_____init____.py      |   10 +
 .../files/patch-ipaplatform_freebsd_constants.py   |   22 +
 .../files/patch-ipaplatform_freebsd_paths.py       |  223 ++
 .../files/patch-ipaplatform_freebsd_services.py    |  525 ++++
 .../files/patch-ipaplatform_freebsd_tasks.py       |  254 ++
 .../files/patch-ipaplatform_setup.py               |   10 +
 .../files/patch-ipapython_ipaldap.py               |   26 +
 .../files/patch-ipapython_ipautil.py               |   11 +
 .../files/patch-ipapython_kernel__keyring.py       |   12 +
 .../files/patch-ipaserver_install_cainstance.py    |   60 +
 .../patch-ipaserver_install_dogtaginstance.py      |   20 +
 .../files/patch-ipaserver_install_dsinstance.py    |   35 +
 .../files/patch-ipaserver_install_httpinstance.py  |  135 +
 .../patch-ipaserver_install_ipa__acme__manage.py   |   20 +
 .../patch-ipaserver_install_ipa__cert__fix.py      |   50 +
 .../files/patch-ipaserver_install_kra.py           |   15 +
 .../files/patch-ipaserver_install_krbinstance.py   |   35 +
 .../patch-ipaserver_install_server_upgrade.py      |   43 +
 ...tests_test__integration_test__ipa__cert__fix.py |   15 +
 net/freeipa-server/files/patch-po_Makefile.hack.in |   20 +
 net/freeipa-server/files/patch-server.m4           |   25 +
 net/freeipa-server/files/patch-util_ipa__krb5.c    |   14 +
 net/freeipa-server/pkg-descr                       |    3 +
 net/freeipa-server/pkg-message                     |   60 +
 net/freeipa-server/pkg-plist                       | 3257 ++++++++++++++++++++
 77 files changed, 6356 insertions(+), 4 deletions(-)

diff --git a/GIDs b/GIDs
index b94830b8d7e3..2a6742151d49 100644
--- a/GIDs
+++ b/GIDs
@@ -540,7 +540,7 @@ avahi-autoipd:*:588:
 # free: 595
 # free: 596
 # free: 597
-# free: 598
+ipaapi:*:598:www
 pkiuser:*:599:
 _xsi:*:600:
 _tss:*:601:
@@ -548,7 +548,7 @@ _pkcs11:*:602:
 _acme:*:603:
 _lego:*:604:
 _hockeypuck:*:605:
-# free: 606
+kdcproxy:*:606:
 # free: 607
 # free: 608
 # free: 609
diff --git a/UIDs b/UIDs
index 8bc61d39e26a..bbef697ab42e 100644
--- a/UIDs
+++ b/UIDs
@@ -545,7 +545,7 @@ avahi-autoipd:*:588:588::0:0:Avahi Autoipd Daemon user:/nonexistent:/usr/sbin/no
 # free: 595
 # free: 596
 # free: 597
-# free: 598
+ipaapi:*:598:598::0:0:IPA Framework User:/nonexistent:/usr/sbin/nologin
 pkiuser:*:599:599::0:0:Dogtag PKI user:/nonexistent:/usr/sbin/nologin
 _xsi:*:600:600::0:0:XMLSysInfo User:/nonexistent:/usr/sbin/nologin
 _tss:*:601:601:daemon:0:0:TCG Software Stack user:/var/empty:/usr/sbin/nologin
@@ -553,7 +553,7 @@ _pkcs11:*:602:602:daemon:0:0:opencryptoki user:/var/empty:/usr/sbin/nologin
 _acme:*:603:603::0:0:ACME client user:/var/empty:/usr/sbin/nologin
 _lego:*:604:604::0:0:lego client user:/nonexistent:/usr/sbin/nologin
 _hockeypuck:*:605:605::0:0:hockeypuck pgp keyserver user:/var/empty:/usr/sbin/nologin
-# free: 606
+kdcproxy:*:606:606::0:0:IPA KDC Proxy User:/nonexistent:/usr/sbin/nologin
 # free: 607
 # free: 608
 # free: 609
diff --git a/net/Makefile b/net/Makefile
index 00339f174ab0..c10ebf24ab5d 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -171,6 +171,7 @@
     SUBDIR += freebsd-uucp
     SUBDIR += freediameter
     SUBDIR += freeipa-client
+    SUBDIR += freeipa-server
     SUBDIR += freeradius-client
     SUBDIR += freeradius3
     SUBDIR += freerdp
diff --git a/net/freeipa-server/Makefile b/net/freeipa-server/Makefile
new file mode 100644
index 000000000000..7ecc32aff44c
--- /dev/null
+++ b/net/freeipa-server/Makefile
@@ -0,0 +1,147 @@
+PORTNAME=	freeipa-server
+DISTVERSION=	4.13.1
+CATEGORIES=	net
+MASTER_SITES=	https://releases.pagure.org/freeipa/
+DISTNAME=	freeipa-${DISTVERSION}
+
+MAINTAINER=	[email protected]
+COMMENT=	FreeIPA server
+WWW=		https://www.freeipa.org/
+
+LICENSE=	GPLv3+
+LICENSE_FILE=	${WRKSRC}/COPYING
+
+BUILD_DEPENDS=	${LOCALBASE}/bin/getopt:misc/getopt \
+		${LOCALBASE}/libdata/pkgconfig/dirsrv.pc:net/389-ds-base \
+		${LOCALBASE}/libdata/pkgconfig/sss_idmap.pc:security/sssd2 \
+		${PY_SETUPTOOLS} \
+		${PYTHON_PKGNAMEPREFIX}lesscpy>0:www/py-lesscpy@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}pip>0:devel/py-pip@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}rjsmin>0:archivers/py-rjsmin@${PY_FLAVOR} \
+		bash:shells/bash \
+		samba416>=0:net/samba416
+
+LIB_DEPENDS=	libcurl.so:ftp/curl \
+		libini_config.so:devel/ding-libs \
+		libintl.so:devel/gettext-runtime \
+		libjansson.so:devel/jansson \
+		libkrad.so:security/krb5 \
+		libnspr4.so:devel/nspr \
+		libpopt.so:devel/popt \
+		libpwquality.so:security/libpwquality \
+		libsasl2.so:security/cyrus-sasl2 \
+		libsss_nss_idmap.so:security/sssd2 \
+		libtalloc.so:devel/talloc \
+		libtevent.so:devel/tevent \
+		libunistring.so:devel/libunistring \
+		libuuid.so:misc/libuuid \
+		libxmlrpc.so:net/xmlrpc-c
+
+RUN_DEPENDS=	${LOCALBASE}/libexec/apache24/mod_auth_gssapi.so:www/freeipa-auth-gssapi \
+		${LOCALBASE}/libexec/apache24/mod_deflate.so:www/apache24 \
+		${LOCALBASE}/libexec/apache24/mod_expires.so:www/apache24 \
+		${LOCALBASE}/libexec/apache24/mod_lookup_identity.so:www/mod_lookup_identity \
+		${LOCALBASE}/libexec/apache24/mod_proxy.so:www/apache24 \
+		${LOCALBASE}/libexec/apache24/mod_proxy_ajp.so:www/apache24 \
+		${LOCALBASE}/libexec/apache24/mod_proxy_http.so:www/apache24 \
+		${LOCALBASE}/libexec/apache24/mod_rewrite.so:www/apache24 \
+		${LOCALBASE}/libexec/apache24/mod_session.so:www/apache24 \
+		${LOCALBASE}/libexec/apache24/mod_session_cookie.so:www/apache24 \
+		${LOCALBASE}/libexec/apache24/mod_ssl.so:www/apache24 \
+		${LOCALBASE}/libexec/apache24/mod_wsgi.so:www/mod_wsgi@${PY_FLAVOR} \
+		${LOCALBASE}/sbin/certmonger:security/certmonger \
+		${LOCALBASE}/sbin/gssproxy:security/gssproxy \
+		${LOCALBASE}/sbin/httpd:www/apache24 \
+		${LOCALBASE}/sbin/oddjobd:sysutils/oddjob \
+		${PYTHON_PKGNAMEPREFIX}dbus>0:devel/py-dbus@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}gssapi>0:security/py-gssapi@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}ifaddr>0:net/py-ifaddr@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}jwcrypto>0:security/py-jwcrypto@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}kdcproxy>0:security/py-kdcproxy@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}lib389>=0:net/py-lib389@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}netaddr>0:net/py-netaddr@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}python-augeas>0:textproc/py-python-augeas@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}python-dateutil>0:devel/py-python-dateutil@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}qrcode>0:textproc/py-qrcode@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}sqlite3>0:databases/py-sqlite3@${PY_FLAVOR} \
+		${PYTHON_PKGNAMEPREFIX}urllib3>0:net/py-urllib3@${PY_FLAVOR} \
+		389-ds-base>=0:net/389-ds-base \
+		dogtag-pki>0:security/dogtag-pki \
+		samba416>=0:net/samba416 \
+		slapi-nis>=0.70.0:net/slapi-nis
+
+USES=		autoreconf gettext-runtime gettext-tools gmake gssapi:mit iconv \
+		ldap libtool localbase:ldflags nodejs:build pkgconfig python \
+		shebangfix ssl
+
+USE_RC_SUBR=	ipa-custodia freeipa-server
+
+SHEBANG_FILES=	install/ui/util/build.sh install/ui/util/change-profile.sh \
+		install/ui/util/clean.sh install/ui/util/compile.sh \
+		install/ui/util/make-builder.sh install/ui/util/make-dojo.sh \
+		install/ui/util/make-patternfly.sh install/ui/util/make-ui.sh \
+		install/ui/util/prepare-dojo.sh install/ui/util/sync.sh
+
+GNU_CONFIGURE=	yes
+
+CONFIGURE_ARGS=	--disable-client \
+		--with-ipaplatform=freebsd \
+		--with-vendor-suffix=+FreeBSD
+
+CONFIGURE_ENV=	LIBS="-lintl" \
+		LIBVERTO_CFLAGS="-I${LOCALBASE}/include" \
+		LIBVERTO_LIBS="-L${LOCALBASE}/lib -lverto"
+
+CFLAGS+=	-D__BSD_VISIBLE=1
+
+CONFLICTS_INSTALL=	freeipa-client
+
+BINARY_ALIAS=	getopt=${LOCALBASE}/bin/getopt
+SUB_FILES=	ipa-otpd-wrapper
+SUB_LIST+=	PYTHON_CMD=${PYTHON_CMD}
+
+USERS=		ipaapi kdcproxy
+GROUPS=		ipaapi kdcproxy
+
+OPTIONS_DEFINE=	DOCS
+
+post-build:
+	${MAKE_CMD} -C ${WRKSRC}/client \
+		LIBINTL_LIBS="-lintl" ipa-getkeytab ipa-rmkeytab ipa-join
+
+post-install:
+	${CHMOD} 0555 ${STAGEDIR}${PREFIX}/libexec/ipa/certmonger/*
+	${INSTALL_SCRIPT} ${WRKSRC}/client/ipa-client-install.in \
+		${STAGEDIR}${PREFIX}/sbin/ipa-client-install
+	@${REINPLACE_CMD} -e "1s|^#!/usr/bin/python3.*|#!${PYTHON_CMD} -I|" \
+		${STAGEDIR}${PREFIX}/sbin/ipa-client-install
+	@${RM} ${STAGEDIR}${PREFIX}/sbin/ipa-client-install.bak
+	${INSTALL_SCRIPT} ${WRKSRC}/client/ipa-client-automount.in \
+		${STAGEDIR}${PREFIX}/sbin/ipa-client-automount
+	@${REINPLACE_CMD} -e "1s|/usr/bin/python3|${PYTHON_CMD} -I|" \
+		${STAGEDIR}${PREFIX}/sbin/ipa-client-automount
+	@${RM} ${STAGEDIR}${PREFIX}/sbin/ipa-client-automount.bak
+	${INSTALL_PROGRAM} ${WRKSRC}/client/ipa-getkeytab \
+		${STAGEDIR}${PREFIX}/sbin/ipa-getkeytab
+	${INSTALL_PROGRAM} ${WRKSRC}/client/ipa-rmkeytab \
+		${STAGEDIR}${PREFIX}/sbin/ipa-rmkeytab
+	${INSTALL_PROGRAM} ${WRKSRC}/client/ipa-join \
+		${STAGEDIR}${PREFIX}/sbin/ipa-join
+	${INSTALL_SCRIPT} ${WRKDIR}/ipa-otpd-wrapper \
+		${STAGEDIR}${PREFIX}/libexec/ipa/ipa-otpd-wrapper
+	@${MKDIR} ${STAGEDIR}${PREFIX}/etc/newsyslog.conf.d
+	${INSTALL_DATA} ${FILESDIR}/freeipa-server.newsyslog.conf \
+		${STAGEDIR}${PREFIX}/etc/newsyslog.conf.d/freeipa-server.conf.sample
+	@${MKDIR} ${STAGEDIR}/var/db/ipa-client/pki
+	@${MKDIR} ${STAGEDIR}/var/db/ipa-client/sysrestore
+	@${MKDIR} ${STAGEDIR}${PREFIX}/share/ipa/client
+	${INSTALL_DATA} ${WRKSRC}/client/share/freeipa.template \
+		${STAGEDIR}${PREFIX}/share/ipa/client/freeipa.template
+	${INSTALL_DATA} ${WRKSRC}/client/share/freeipa-realm.template \
+		${STAGEDIR}${PREFIX}/share/ipa/client/freeipa-realm.template
+
+post-install-DOCS-on:
+	@${MKDIR} ${STAGEDIR}${DOCSDIR}
+	${INSTALL_DATA} ${FILESDIR}/README.md ${STAGEDIR}${DOCSDIR}/README.md
+
+.include <bsd.port.mk>
diff --git a/net/freeipa-server/distinfo b/net/freeipa-server/distinfo
new file mode 100644
index 000000000000..c09113243f24
--- /dev/null
+++ b/net/freeipa-server/distinfo
@@ -0,0 +1,3 @@
+TIMESTAMP = 1782325059
+SHA256 (freeipa-4.13.1.tar.gz) = 5353127d7c56ca72bc2d458376d457f8b0cc451cdbd31dc7939a88058e91527c
+SIZE (freeipa-4.13.1.tar.gz) = 41552419
diff --git a/net/freeipa-server/files/README.md b/net/freeipa-server/files/README.md
new file mode 100644
index 000000000000..9fe895d348de
--- /dev/null
+++ b/net/freeipa-server/files/README.md
@@ -0,0 +1,283 @@
+# FreeIPA server on FreeBSD (net/freeipa-server)
+
+FreeIPA integrated identity management (LDAP + Kerberos + PKI) on FreeBSD.
+This port ships FreeIPA 4.13.x together with the FreeBSD-specific glue that
+upstream (Linux/systemd oriented) does not provide.
+
+This document has two audiences:
+
+* **Operators** — how to install, configure and run an IPA server
+  (sections *Prerequisites* … *Uninstalling*).
+* **Port maintainers / reviewers** — why the FreeBSD patches exist
+  (section *FreeBSD integration notes*).
+
+---
+
+## Prerequisites (read this first)
+
+### Kerberos / SASL — **do this or the install fails at the very end**
+
+FreeIPA on FreeBSD uses the **MIT Kerberos from ports** (`security/krb5`).
+The SASL/GSSAPI plugin used by the final *client enrolment* step of
+`ipa-server-install` must use the **same** Kerberos. By default
+`security/cyrus-sasl2-gssapi` is built with `GSSAPI_BASE`, which links the
+**base-system** Kerberos (`/usr/lib/libgssapi_krb5`) and reads
+`/etc/krb5.conf` — the wrong Kerberos for FreeIPA. The install then runs
+all the way through and fails at the end with either:
+
+```
+Insufficient access: SASL(-1): ... (SPNEGO cannot find mechanisms to negotiate)
+```
+
+or `Cannot find KDC for realm "..."`.
+
+**Fix:** build `security/cyrus-sasl2-gssapi` with the **`GSSAPI_MIT`** option
+(instead of the default `GSSAPI_BASE`) so the plugin links the ports
+Kerberos (`/usr/local/lib/libgssapi_krb5`) and reads
+`/usr/local/etc/krb5.conf`:
+
+```sh
+# make.conf (ports / poudriere):
+security_cyrus-sasl2-gssapi_SET=GSSAPI_MIT
+security_cyrus-sasl2-gssapi_UNSET=GSSAPI_BASE
+
+# or interactively, then rebuild + reinstall the plugin:
+make -C /usr/ports/security/cyrus-sasl2-gssapi config   # select GSSAPI_MIT
+```
+
+Verify (must show the ports Kerberos, **not** `/usr/lib/...`):
+
+```sh
+ldd /usr/local/lib/sasl2/libgssapiv2.so | grep libgssapi_krb5
+# -> /usr/local/lib/libgssapi_krb5.so
+```
+
+This is a system-wide choice: all SASL/GSSAPI consumers (SSSD, OpenLDAP,
+Postfix, ...) then use the ports MIT Kerberos — the correct, consistent
+setup on a host dedicated to FreeIPA. The plugin is loaded at runtime via
+`dlopen`, so those consumers do **not** need rebuilding.
+
+### Python GSSAPI bindings — same Kerberos, same reason
+
+`security/py-gssapi` (the `pyXX-gssapi` package) has the **same** default
+pitfall and must be fixed the same way. It defaults to `GSSAPI_BASE`, building
+against the base-system Kerberos. FreeIPA's own tooling uses these Python
+bindings for the Kerberos step of the self-enrolment (`ipalib` calls `kinit`);
+with the base Kerberos it cannot find the KDC and the install fails at the very
+end with `Cannot find KDC for realm "..."`.
+
+**Fix:** build `security/py-gssapi` with **`GSSAPI_MIT`** too:
+
+```sh
+# make.conf (ports / poudriere):
+security_py-gssapi_SET=GSSAPI_MIT
+security_py-gssapi_UNSET=GSSAPI_BASE
+
+# or interactively:
+make -C /usr/ports/security/py-gssapi config   # select GSSAPI_MIT
+```
+
+Verify (must show the ports Kerberos, **not** `/usr/lib/...`):
+
+```sh
+ldd /usr/local/lib/python3*/site-packages/gssapi/raw/misc*.so | grep libgssapi_krb5
+# -> /usr/local/lib/libgssapi_krb5.so
+```
+
+---
+
+FreeIPA is very sensitive to host naming. **Before** running
+`ipa-server-install` make sure:
+
+1. The system hostname is a **fully-qualified domain name** (FQDN):
+
+   ```sh
+   sysrc hostname="ipa.example.com"
+   hostname ipa.example.com
+   ```
+
+2. The FQDN resolves to the host's **real** IP address (not `127.0.0.1`)
+   and is the **canonical** name in `/etc/hosts`:
+
+   ```
+   ::1         localhost
+   127.0.0.1   localhost
+   10.0.0.10   ipa.example.com ipa
+   ```
+
+   Do **not** map the hostname to a loopback address and do **not** let the
+   short name be canonical. A short hostname breaks Kerberos and Dogtag
+   (certificate hostname mismatch, wrong TLS-key passphrase lookup).
+
+3. Check the result — both must print the FQDN:
+
+   ```sh
+   hostname
+   python3 -c 'import socket; print(socket.gethostname(), socket.getfqdn())'
+   ```
+
+The `freeipa_server` rc script warns at start time if the hostname is not a
+FQDN, but it does not fix it for you.
+
+---
+
+## Installation
+
+```sh
+pkg install freeipa-server
+```
+
+Then configure the instance (interactive; `--no-host-dns` skips DNS
+pre-checks when you manage names via `/etc/hosts`, `--no-ntp` skips the
+chrony client which is not used on FreeBSD):
+
+```sh
+ipa-server-install \
+    --hostname=ipa.example.com \
+    --domain=example.com \
+    --realm=EXAMPLE.COM \
+    --no-host-dns \
+    --no-ntp
+```
+
+`ipa-server-install` creates and configures the 389-ds instance, the KDC,
+the Dogtag CA, Apache/httpd and the helper services.
+
+---
+
+## Running the server
+
+The whole stack is driven by a single rc service that wraps IPA's own
+orchestrator `ipactl` (it starts/stops the components in the correct order):
+
+```sh
+sysrc freeipa_server_enable=YES
+service freeipa_server start      # start | stop | status
+```
+
+You do **not** need to enable the individual back-end services in
+`rc.conf` — `ipactl` starts them with `service <name> onestart`, which does
+not require a per-service `_enable=YES`. The single switch
+`freeipa_server_enable=YES` is enough for boot.
+
+`ipa-custodia` ships its own rc script (`ipa_custodia`) and is managed by
+`ipactl` as part of the stack.
+
+### Boot persistence (surviving a reboot)
+
+Two host-level settings must be right or the server will **not** come back
+up after a reboot (`freeipa_server_enable=YES` alone is not enough):
+
+1. **Enable D-Bus.** `certmonger` and `oddjobd` (both pulled in by FreeIPA)
+   connect to the system D-Bus at start and their rc scripts `REQUIRE: dbus`.
+   If D-Bus is not enabled the boot **hangs** in `oddjobd`'s endless
+   `Error connecting to bus for "com.redhat.oddjob"` retry loop (and
+   `certmonger` fails to start), which also delays `sshd`:
+
+   ```sh
+   sysrc dbus_enable=YES
+   ```
+
+2. **Enable gssproxy.** `httpd`'s `mod_auth_gssapi` acquires the HTTP
+   service credentials through gssproxy (the ports MIT Kerberos GSS
+   proxy).  Without it every authenticated request to the IPA API / Web
+   UI fails -- `gss_acquire_cred() ... SPNEGO cannot find mechanisms to
+   negotiate` in the httpd error log, and `ipa` commands report
+   `No valid Negotiate header in server response`:
+
+   ```sh
+   sysrc gssproxy_enable=YES
+   ```
+
+3. **Stop cloud-init from managing `/etc/hosts`.** On cloud-init images
+   (`manage_etc_hosts: true`) `/etc/hosts` is regenerated from a template on
+   every boot; that drops the `FQDN -> real-IP` line and maps the host to
+   `127.0.0.1` only. FreeIPA can then no longer resolve its own FQDN and
+   `ipactl` aborts at boot with `socket.gaierror: [Errno 8] Name does not
+   resolve`. Disable it and keep the `/etc/hosts` entry from the
+   Prerequisites section above:
+
+   ```sh
+   printf 'manage_etc_hosts: false\n' \
+       > /usr/local/etc/cloud/cloud.cfg.d/99-ipa-no-manage-hosts.cfg
+   ```
+
+---
+
+## Components / service map
+
+| Component            | Program / rc            | Runs as   | Notes                                    |
+|----------------------|-------------------------|-----------|------------------------------------------|
+| Directory server     | `ns-slapd` (389-ds)     | `dirsrv`  | instance `slapd-<REALM>`, LDAP 389/636   |
+| Kerberos KDC         | `krb5kdc`               | `root`    | UDP/TCP 88; data in `/usr/local/var/krb5kdc` |
+| Kerberos admin       | `kadmind`               | `root`    | 464                                      |
+| Dogtag PKI (CA)      | `pki-tomcatd` (jsvc)    | `pkiuser` | Tomcat 8080/8443; `security/dogtag-pki`  |
+| Web UI / API         | `httpd` (apache24)      | `www`     | 80/443; mod_wsgi as `ipaapi`             |
+| KDC proxy (MS-KKDCP) | mod_wsgi `/KdcProxy`    | `kdcproxy`| HTTPS 443; `security/py-kdcproxy`        |
+| Secret sharing       | `ipa-custodia`          | `root`    | rc `ipa_custodia`                        |
+| OTP daemon           | `ipa-otpd`              | `root`    | socket in `/var/run/krb5kdc`             |
+
+Service users `ipaapi` and `kdcproxy` are created by the port.
+
+---
+
+## Uninstalling
+
+`ipa-server-install --uninstall` removes the IPA **instance** (its
+configuration and data). As on upstream FreeIPA it does **not** remove the
+installed packages, and it deliberately leaves shared helper services and
+their `rc.conf` toggles alone. Two cases:
+
+### Reinstall later (keep this host as an IPA server)
+
+```sh
+ipa-server-install --uninstall -U
+```
+
+That is all you need before another `ipa-server-install`. Leftover enabled
+helpers (e.g. `certmonger`) are harmless - the next install reconfigures them.
+If you plan to reinstall, also drop the Kerberos config left from the previous
+instance (`--uninstall` leaves it behind) so the reinstall regenerates it
+cleanly:
+
+```sh
+rm -rf /usr/local/etc/krb5.conf /usr/local/etc/krb5.conf.d
+```
+
+### Full decommission (this host should no longer run IPA)
+
+`--uninstall` intentionally does not stop/disable shared services or undo
+`rc.conf` toggles it did not exclusively own, so finish by hand:
+
+```sh
+ipa-server-install --uninstall -U
+
+# stop helper daemons that may still run from the removed instance
+service certmonger stop 2>/dev/null || pkill certmonger
+service gssproxy   stop 2>/dev/null || pkill gssproxy
+
+# drop rc.conf leftovers the instance left behind
+sysrc -x certmonger_enable kdc_program
+
+# optional: remove the package(s)
+pkg delete -y freeipa-server
+
+# a reboot then guarantees nothing lingers in memory or /var/run
+```
+
+`certmonger`, `gssproxy` and the system-wide `GSSAPI_MIT` choice for
+`security/cyrus-sasl2-gssapi` (see *Prerequisites*) are shared: only
+disable/revert them if nothing else on the host relies on them.
+
+---
+
+## Building / testing
+
+Development tree: `~/dev/ports` on the poudriere host. Test a single port:
+
+```sh
+poudriere testport -j <jail> -p ports net/freeipa-server
+```
+
+The runtime is exercised on a dedicated test VM (`ipa-server-install`),
+not on the build host.
diff --git a/net/freeipa-server/files/freeipa-server.in b/net/freeipa-server/files/freeipa-server.in
new file mode 100644
index 000000000000..b06145da69f1
--- /dev/null
+++ b/net/freeipa-server/files/freeipa-server.in
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+# PROVIDE: freeipa_server
+# REQUIRE: LOGIN NETWORKING
+# KEYWORD: shutdown
+#
+# Add the following line to /etc/rc.conf to enable the FreeIPA server:
+#
+# freeipa_server_enable="YES"
+#
+# The whole stack (dirsrv, krb5kdc, kadmind, pki-tomcatd, httpd, custodia,
+# ipa-otpd) is orchestrated by IPA's own controller, ipactl.  Enabling this
+# single service is enough; the back-end services are started via
+# "service <name> onestart" and need no individual rc.conf entry.
+
+. /etc/rc.subr
+
+name="freeipa_server"
+desc="FreeIPA server control service"
+rcvar="freeipa_server_enable"
+
+load_rc_config "${name}"
+
+: ${freeipa_server_enable:="NO"}
+
+command="%%PREFIX%%/sbin/ipactl"
+ipa_config="%%PREFIX%%/etc/ipa/default.conf"
+
+extra_commands="prepare"
+prepare_cmd="${name}_prepare"
+start_precmd="${name}_prestart"
+
+start_cmd="${name}_start"
+stop_cmd="${name}_stop"
+restart_cmd="${name}_restart"
+status_cmd="${name}_status"
+
+freeipa_server_prepare()
+{
+	/usr/bin/install -d -o root -g wheel -m 0711 /var/run/ipa
+	/usr/bin/install -d -o ipaapi -g ipaapi -m 6770 /var/run/ipa/ccaches
+	# mod_wsgi socket directory for httpd; must be traversable by the www
+	# worker user so it can reach the /ipa WSGI daemon sockets (else 503).
+	/usr/bin/install -d -o root -g wheel -m 0755 /var/run/httpd
+
+	if [ ! -f /var/run/ipa/services.list ]; then
+		/usr/bin/printf '[]\n' > /var/run/ipa/services.list
+		/bin/chmod 0644 /var/run/ipa/services.list
+	fi
+}
+
+freeipa_server_prestart()
+{
+	# FreeIPA is not usable until ipa-server-install has run.
+	if [ ! -f "${ipa_config}" ]; then
+		warn "FreeIPA is not configured yet - run 'ipa-server-install' first"
+		return 1
+	fi
+
+	# FreeIPA requires a fully-qualified hostname that resolves to a real
+	# address.  A short name breaks Kerberos and Dogtag (certificate
+	# hostname mismatch, wrong TLS-key passphrase lookup).
+	_fqdn=$(/bin/hostname)
+	case "${_fqdn}" in
+	*.*)	;;
+	*)	warn "hostname '${_fqdn}' is not a FQDN - FreeIPA expects e.g. ipa.example.com" ;;
+	esac
+
+	freeipa_server_prepare
+}
+
+freeipa_server_start()
+{
+	# Start the whole stack detached from the boot rc's session/process
+	# group.  FreeBSD job-control cleanup (killjobc) sends SIGHUP to the rc
+	# process group when a boot subshell exits, and 389-ds (ns-slapd) treats
+	# SIGHUP as a shutdown -- so the Directory Server would die ~10-20s into
+	# the boot.  daemon(8) puts ipactl, and thus every service it starts,
+	# into its own session so that SIGHUP never reaches them.
+	# --ignore-service-failures lets the stack come up even if the slow
+	# Dogtag/Java CA times out on a cold boot.
+	/usr/sbin/daemon -f "${command}" start --ignore-service-failures
+}
+
+freeipa_server_stop()
+{
+	"${command}" stop
+}
+
+freeipa_server_restart()
+{
+	"${command}" restart
+}
+
+freeipa_server_status()
+{
+	"${command}" status
+}
+
+run_rc_command "$1"
diff --git a/net/freeipa-server/files/freeipa-server.newsyslog.conf b/net/freeipa-server/files/freeipa-server.newsyslog.conf
new file mode 100644
index 000000000000..7be7af785888
--- /dev/null
+++ b/net/freeipa-server/files/freeipa-server.newsyslog.conf
@@ -0,0 +1,4 @@
+# newsyslog configuration for the FreeIPA OTP daemon
+#
+# logfilename             owner:group  mode count size when flags
+/var/log/ipa-otpd.log     root:wheel   600  7     1000 *    JNC
diff --git a/net/freeipa-server/files/ipa-custodia.in b/net/freeipa-server/files/ipa-custodia.in
new file mode 100644
index 000000000000..12f86c0368a9
--- /dev/null
+++ b/net/freeipa-server/files/ipa-custodia.in
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# PROVIDE: ipa_custodia
+# REQUIRE: LOGIN NETWORKING
+# KEYWORD: shutdown
+
+. /etc/rc.subr
+
+name=ipa_custodia
+desc="FreeIPA Custodia service"
+rcvar=ipa_custodia_enable
+
+load_rc_config ${name}
+
+: ${ipa_custodia_enable:="NO"}
+: ${ipa_custodia_config:="%%PREFIX%%/etc/ipa/custodia/custodia.conf"}
+
+pidfile="/var/run/${name}.pid"
+command="/usr/sbin/daemon"
+: ${ipa_custodia_logfile:="/var/log/ipa-custodia.log"}
+
+procname="%%PREFIX%%/libexec/ipa/ipa-custodia"
+command_interpreter="%%PYTHON_CMD%%"
+required_files="${ipa_custodia_config}"
+command_args="-p ${pidfile} ${procname} ${ipa_custodia_config} >> ${ipa_custodia_logfile} 2>&1"
+
+run_rc_command "$1"
diff --git a/net/freeipa-server/files/ipa-otpd-wrapper.in b/net/freeipa-server/files/ipa-otpd-wrapper.in
new file mode 100644
index 000000000000..7062df42190b
--- /dev/null
+++ b/net/freeipa-server/files/ipa-otpd-wrapper.in
@@ -0,0 +1,16 @@
+#!/bin/sh
+#
+# FreeBSD inetd wrapper for ipa-otpd.
+#
+umask 077
+exec 2>>/var/log/ipa-otpd.log
+
+if [ "$#" -ne 1 ]; then
+    echo "Usage: $0 <ldap_uri>" >&2
+    exit 64
+fi
+
+LC_ALL=C.UTF-8
+export LC_ALL
+
+exec %%PREFIX%%/libexec/ipa/ipa-otpd "$1"
diff --git a/net/freeipa-server/files/patch-Makefile.am b/net/freeipa-server/files/patch-Makefile.am
new file mode 100644
index 000000000000..0b70e13251e0
--- /dev/null
+++ b/net/freeipa-server/files/patch-Makefile.am
@@ -0,0 +1,29 @@
+--- Makefile.am.orig	2026-07-01 19:36:23 UTC
++++ Makefile.am
+@@ -11,11 +11,16 @@ endif
+     IPATESTS_SUBDIRS = ipatests
+ endif
+ 
++if ENABLE_CLIENT
++    CLIENT_SUBDIRS = client
++    CLIENT_PYTHON_SCRIPT_SUBDIRS = $(top_builddir)/client
++endif
++
+ IPACLIENT_SUBDIRS = ipaclient ipalib ipaplatform ipapython
+ PYTHON_SUBDIRS = $(IPACLIENT_SUBDIRS) $(IPATESTS_SUBDIRS) $(IPASERVER_SUBDIRS)
+ PYTHON_SCRIPT_SUBDIRS = \
+         $(top_builddir) \
+-        $(top_builddir)/client \
++        $(CLIENT_PYTHON_SCRIPT_SUBDIRS) \
+         $(top_builddir)/daemons/dnssec \
+         $(top_builddir)/install/certmonger \
+         $(top_builddir)/install/oddjob \
+@@ -31,7 +36,7 @@ SUBDIRS = \
+ SUBDIRS = \
+         asn1 \
+         util \
+-        client \
++        $(CLIENT_SUBDIRS) \
+         contrib \
+         po \
+         pypi \
diff --git a/net/freeipa-server/files/patch-Makefile.python.am b/net/freeipa-server/files/patch-Makefile.python.am
new file mode 100644
index 000000000000..371fba44e420
--- /dev/null
+++ b/net/freeipa-server/files/patch-Makefile.python.am
@@ -0,0 +1,15 @@
+--- Makefile.python.am.orig	2025-01-15 09:52:47 UTC
++++ Makefile.python.am
+@@ -25,9 +25,10 @@ install-exec-local: $(top_builddir)/ipasetup.py
+ 		    build \
+ 		        --build-base "$(abs_builddir)/build" \
+ 		    install \
+-		        --prefix "$(DESTDIR)$(prefix)" \
++		        --root "$(DESTDIR)" \
++		        --prefix "$(prefix)" \
+ 		        --single-version-externally-managed \
+-		        --record "$(DESTDIR)$(pkgpythondir)/install_files.txt" \
++		        --record "$(abs_builddir)/install_files.txt" \
+ 		        --optimize 1 \
+ 		        $(PYTHON_INSTALL_EXTRA_OPTIONS); \
+ 	fi
diff --git a/net/freeipa-server/files/patch-asn1_asn1c_asn__system.h b/net/freeipa-server/files/patch-asn1_asn1c_asn__system.h
new file mode 100644
index 000000000000..3a4d082c3c10
--- /dev/null
+++ b/net/freeipa-server/files/patch-asn1_asn1c_asn__system.h
@@ -0,0 +1,11 @@
+--- asn1/asn1c/asn_system.h.orig	2025-01-15 09:52:47 UTC
++++ asn1/asn1c/asn_system.h
+@@ -27,6 +27,8 @@
+ 
+ #ifdef	HAVE_ALLOCA_H
+ #include <alloca.h>	/* For alloca(3) */
++#elif defined(__FreeBSD__)
++#define alloca(size) __builtin_alloca(size)
+ #endif
+ 
+ #ifdef	_WIN32
diff --git a/net/freeipa-server/files/patch-client_ipa-getkeytab.c b/net/freeipa-server/files/patch-client_ipa-getkeytab.c
new file mode 100644
index 000000000000..197b15cde85a
--- /dev/null
+++ b/net/freeipa-server/files/patch-client_ipa-getkeytab.c
@@ -0,0 +1,16 @@
+--- client/ipa-getkeytab.c.orig	2025-09-30 12:18:32 UTC
++++ client/ipa-getkeytab.c
+@@ -34,6 +34,13 @@
+ #include <time.h>
+ #include <krb5.h>
+ #include <ldap.h>
++typedef unsigned char   u_char;
++typedef unsigned short  u_short;
++typedef unsigned int    u_int;
++typedef unsigned long   u_long;
++#include <sys/types.h>
++#include <netinet/in.h>
++#include <arpa/nameser.h>
+ #include <resolv.h>
+ #include <sasl/sasl.h>
+ #include <popt.h>
diff --git a/net/freeipa-server/files/patch-client_ipa-join.c b/net/freeipa-server/files/patch-client_ipa-join.c
new file mode 100644
index 000000000000..94f5f85cc117
--- /dev/null
+++ b/net/freeipa-server/files/patch-client_ipa-join.c
@@ -0,0 +1,20 @@
+--- client/ipa-join.c.orig	2025-01-15 09:52:51 UTC
++++ client/ipa-join.c
+@@ -1197,7 +1197,7 @@ join(const char *server, const char *hostname, const c
+ 
+     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 @@ unenroll_host(const char *server, const char *hostname
+     }
+     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-server/files/patch-configure.ac b/net/freeipa-server/files/patch-configure.ac
new file mode 100644
index 000000000000..9906346103a4
--- /dev/null
+++ b/net/freeipa-server/files/patch-configure.ac
@@ -0,0 +1,43 @@
+--- configure.ac.orig	2025-12-04 10:21:07 UTC
++++ configure.ac
+@@ -45,6 +45,16 @@ AM_CONDITIONAL([ENABLE_SERVER], [test x$enable_server 
+     [enable_server=yes])
+ AM_CONDITIONAL([ENABLE_SERVER], [test x$enable_server = xyes])
+ 
++AC_ARG_ENABLE([client],
++    [AC_HELP_STRING([--disable-client], [Disable client tools])],
++    [case "${enableval}" in
++         yes) enable_client=yes ;;
++          no) enable_client=no ;;
++           *) AC_MSG_ERROR([bad value ${enableval} for --disable-client]) ;;
++     esac],
++    [enable_client=yes])
++AM_CONDITIONAL([ENABLE_CLIENT], [test x$enable_client = xyes])
++
+ AC_ARG_WITH([ipatests],
+     [AC_HELP_STRING([--without-ipatests], [Build without ipatests])],
+     [with_ipatests=${withval}],
+@@ -252,7 +262,9 @@ dnl --------------------------------------------------
+ dnl - Check for systemd directories
+ dnl ---------------------------------------------------------------------------
+ 
++AS_IF([test "x$with_ipaplatform" != "xfreebsd"], [
+ PKG_CHECK_EXISTS([systemd], [], [AC_MSG_ERROR([systemd not found])])
++])
+ AC_ARG_WITH([systemdsystemunitdir],
+             AS_HELP_STRING([--with-systemdsystemunitdir=DIR],
+                [Directory for systemd service files]),
+@@ -405,6 +417,13 @@ if test "x${IPAPLATFORM}" == "xdebian"; then
+     ODS_GROUP="opendnssec"
+     # see https://www.debian.org/doc/packaging-manuals/python-policy/ap-packaging_tools.html
+     PYTHON_INSTALL_EXTRA_OPTIONS="--install-layout=deb"
++elif test "x${IPAPLATFORM}" == "xfreebsd"; then
++    HTTPD_GROUP="www"
++    KRB5KDC_SERVICE="krb5kdc"
++    NAMED_GROUP="bind"
++    ODS_USER="opendnssec"
++    ODS_GROUP="opendnssec"
++    PYTHON_INSTALL_EXTRA_OPTIONS=""
+ else
+     HTTPD_GROUP="apache"
+     KRB5KDC_SERVICE="krb5kdc.service"
diff --git a/net/freeipa-server/files/patch-daemons_ipa-kdb_ipa__kdb.c b/net/freeipa-server/files/patch-daemons_ipa-kdb_ipa__kdb.c
new file mode 100644
index 000000000000..134276e9b90c
--- /dev/null
+++ b/net/freeipa-server/files/patch-daemons_ipa-kdb_ipa__kdb.c
@@ -0,0 +1,32 @@
+--- daemons/ipa-kdb/ipa_kdb.c.orig	2025-06-17 07:48:40 UTC
++++ daemons/ipa-kdb/ipa_kdb.c
+@@ -87,6 +87,11 @@ static void ipadb_context_free(krb5_context kcontext,
+ }
+ 
+ #define LDAPI_URI_PREFIX "ldapi://"
++#ifdef __FreeBSD__
++#define IPA_KDB_LDAPI_DIR "/var/run"
++#else
++#define IPA_KDB_LDAPI_DIR LDAPIDIR
++#endif
+ #define LDAPI_PATH_PREFIX "%2fslapd-"
+ #define SOCKET_SUFFIX ".socket"
+ #define APPEND_PATH_PART(pos, part) \
+@@ -104,7 +109,7 @@ static char *ipadb_realm_to_ldapi_uri(char *realm)
+     int len;
+ 
+     /* uri length, assume worst case for LDAPIDIR */
+-    len = strlen(LDAPI_URI_PREFIX) + strlen(LDAPIDIR) * 3
++    len = strlen(LDAPI_URI_PREFIX) + strlen(IPA_KDB_LDAPI_DIR) * 3
+           + strlen(LDAPI_PATH_PREFIX) + strlen(realm)
+           + strlen(SOCKET_SUFFIX) + 1;
+ 
+@@ -118,7 +123,7 @@ static char *ipadb_realm_to_ldapi_uri(char *realm)
+     APPEND_PATH_PART(p, LDAPI_URI_PREFIX);
+ 
+     /* copy path and escape '/' to '%2f' */
*** 5970 LINES SKIPPED ***
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.