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 ***