diff --git a/daemons/ipa-otpd/Makefile.am b/daemons/ipa-otpd/Makefile.am index 867269300..975a0c935 100644 --- a/daemons/ipa-otpd/Makefile.am +++ b/daemons/ipa-otpd/Makefile.am @@ -1,9 +1,11 @@ +AM_CPPFLAGS := -I$(top_srcdir)/util AM_CFLAGS := @LDAP_CFLAGS@ @LIBVERTO_CFLAGS@ @KRB5_CFLAGS@ @NSPR_CFLAGS@ AM_LDFLAGS := @LDAP_LIBS@ @LIBVERTO_LIBS@ @KRAD_LIBS@ @KRB5_LIBS@ noinst_HEADERS = internal.h appdir = $(libexecdir)/ipa/ app_PROGRAMS = ipa-otpd +ipa_otpd_LDADD = $(top_builddir)/util/libutil.la dist_noinst_DATA = ipa-otpd.socket.in ipa-otpd@.service.in test.py systemdsystemunit_DATA = ipa-otpd.socket ipa-otpd@.service diff --git a/daemons/ipa-otpd/main.c b/daemons/ipa-otpd/main.c index aebc039bc..1538cb861 100644 --- a/daemons/ipa-otpd/main.c +++ b/daemons/ipa-otpd/main.c @@ -32,6 +32,7 @@ #include #include +#include "ipa_hostname.h" /* Our global state. */ struct otpd_context ctx; @@ -212,7 +213,7 @@ static krb5_error_code setup_ldap(const char *uri, krb5_boolean bind, int main(int argc, char **argv) { - char hostname[HOST_NAME_MAX + 1]; + char hostname[IPA_HOST_NAME_LEN]; krb5_error_code retval; krb5_data hndata; verto_ev *sig; @@ -227,7 +228,7 @@ int main(int argc, char **argv) memset(&ctx, 0, sizeof(ctx)); ctx.exitstatus = 1; - if (gethostname(hostname, sizeof(hostname)) < 0) { + if (ipa_gethostfqdn(hostname) < 0) { otpd_log_err(errno, "Unable to get hostname"); goto error; } diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c index 6431417b0..c0d63b982 100644 --- a/daemons/ipa-sam/ipa_sam.c +++ b/daemons/ipa-sam/ipa_sam.c @@ -36,6 +36,7 @@ char *smb_xstrdup(const char *s); #include #include #include +#include "ipa_hostname.h" #include "ipa_asn1.h" #include "ipa_pwd.h" #include "ipa_mspac.h" @@ -4440,7 +4441,7 @@ static char *sec_key(TALLOC_CTX *mem_ctx, const char *d) static NTSTATUS save_sid_to_secret(struct ipasam_private *ipasam_state) { - char hostname[255]; + char hostname[IPA_HOST_NAME_LEN]; int ret; char *p; TALLOC_CTX *tmp_ctx; @@ -4466,13 +4467,12 @@ static NTSTATUS save_sid_to_secret(struct ipasam_private *ipasam_state) goto done; } - ret = gethostname(hostname, sizeof(hostname)); + ret = ipa_gethostfqdn(hostname); if (ret == -1) { DEBUG(1, ("gethostname failed.\n")); status = NT_STATUS_UNSUCCESSFUL; goto done; } - hostname[sizeof(hostname)-1] = '\0'; p = strchr(hostname, '.'); if (p != NULL) { *p = '\0'; @@ -4724,7 +4724,7 @@ static NTSTATUS ipasam_generate_principals(struct ipasam_private *ipasam_state) int ret; krb5_context context; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; - char hostname[255]; + char hostname[IPA_HOST_NAME_LEN]; char *default_realm = NULL; if (!ipasam_state) { @@ -4736,12 +4736,11 @@ static NTSTATUS ipasam_generate_principals(struct ipasam_private *ipasam_state) return status; } - ret = gethostname(hostname, sizeof(hostname)); + ret = ipa_gethostfqdn(hostname); if (ret == -1) { DEBUG(1, ("gethostname failed.\n")); goto done; } - hostname[sizeof(hostname)-1] = '\0'; rc = krb5_get_default_realm(context, &default_realm); if (rc) { diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am b/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am index 0eae746e9..da600d063 100644 --- a/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am +++ b/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am @@ -5,6 +5,7 @@ PLUGIN_COMMON_DIR = $(srcdir)/../common AM_CPPFLAGS = \ -I$(srcdir) \ -I$(PLUGIN_COMMON_DIR) \ + -I$(top_srcdir)/util \ -DPREFIX=\""$(prefix)"\" \ -DBINDIR=\""$(bindir)"\" \ -DLIBDIR=\""$(libdir)"\" \ @@ -31,6 +32,7 @@ libipa_cldap_la_SOURCES = \ libipa_cldap_la_LDFLAGS = -avoid-version libipa_cldap_la_LIBADD = \ + $(top_builddir)/util/libutil.la \ $(LDAP_LIBS) \ $(NDRNBT_LIBS) \ $(NULL) @@ -49,6 +51,7 @@ ipa_cldap_tests_LDFLAGS = \ -rpath $(shell pkg-config --libs-only-L dirsrv | sed -e 's/-L//') \ $(NULL) ipa_cldap_tests_LDADD = \ + $(top_builddir)/util/libutil.la \ $(CMOCKA_LIBS) \ $(NDRNBT_LIBS) \ $(DIRSRV_LIBS) \ diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c index 460f96cd5..eb0d18315 100644 --- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c +++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c @@ -38,6 +38,7 @@ * END COPYRIGHT BLOCK **/ #include "ipa_cldap.h" +#include "ipa_hostname.h" #include #include #include @@ -236,7 +237,7 @@ int ipa_cldap_netlogon(struct ipa_cldap_ctx *ctx, struct ipa_cldap_req *req, struct berval *reply) { - char hostname[MAXHOSTNAMELEN + 1]; /* NOTE: lenght hardcoded in kernel */ + char hostname[IPA_HOST_NAME_LEN]; char *domain = NULL; char *our_domain = NULL; char *guid = NULL; @@ -321,13 +322,11 @@ int ipa_cldap_netlogon(struct ipa_cldap_ctx *ctx, goto done; } - ret = gethostname(hostname, MAXHOSTNAMELEN); + ret = ipa_gethostfqdn(hostname); if (ret == -1) { ret = errno; goto done; } - /* Make double sure it is terminated */ - hostname[MAXHOSTNAMELEN] = '\0'; dot = strchr(hostname, '.'); if (!dot) { /* this name is not fully qualified, therefore invalid */ diff --git a/install/tools/ipa-csreplica-manage.in b/install/tools/ipa-csreplica-manage.in index d61205433..5faed5a84 100644 --- a/install/tools/ipa-csreplica-manage.in +++ b/install/tools/ipa-csreplica-manage.in @@ -30,6 +30,7 @@ from ipaplatform.paths import paths from ipaserver.install import (replication, installutils, bindinstance, cainstance) from ipalib import api, errors +from ipalib.constants import FQDN from ipalib.util import has_managed_topology from ipapython import ipautil, ipaldap, version from ipapython.admintool import ScriptError @@ -343,7 +344,7 @@ def re_initialize(realm, options): if not options.fromhost: sys.exit("re-initialize requires the option --from ") - thishost = installutils.get_fqdn() + thishost = FQDN try: repl = replication.get_cs_replication_manager(realm, options.fromhost, @@ -383,7 +384,7 @@ def force_sync(realm, thishost, fromhost, dirman_passwd): def set_renewal_master(realm, replica): if not replica: - replica = installutils.get_fqdn() + replica = FQDN ca = cainstance.CAInstance(realm) if ca.is_renewal_master(replica): @@ -434,7 +435,7 @@ def main(): if options.host: host = options.host else: - host = installutils.get_fqdn() + host = FQDN options.host = host diff --git a/install/tools/ipa-custodia-check.in b/install/tools/ipa-custodia-check.in index 66f8f1d72..e357b117d 100644 --- a/install/tools/ipa-custodia-check.in +++ b/install/tools/ipa-custodia-check.in @@ -9,7 +9,6 @@ import argparse import logging import os import platform -import socket import warnings from custodia.message.kem import KEY_USAGE_SIG, KEY_USAGE_ENC, KEY_USAGE_MAP @@ -136,7 +135,6 @@ class IPACustodiaTester: def check(self): self.status() - self.check_fqdn() self.check_files() self.check_client() self.check_jwk() @@ -156,13 +154,6 @@ class IPACustodiaTester: if self.host == self.args.server: self.warning("Performing self-test only.") - def check_fqdn(self): - fqdn = socket.getfqdn() - if self.host != fqdn: - self.warning( - "socket.getfqdn() reports hostname '{}'".format(fqdn) - ) - def check_files(self): for filename in self.files: if not os.path.isfile(filename): diff --git a/install/tools/ipa-replica-conncheck.in b/install/tools/ipa-replica-conncheck.in index b22db1139..fdc3224d6 100644 --- a/install/tools/ipa-replica-conncheck.in +++ b/install/tools/ipa-replica-conncheck.in @@ -28,6 +28,7 @@ from ipapython.dn import DN from ipapython import version from ipapython import ipautil, certdb from ipalib import api, errors, x509 +from ipalib.constants import FQDN from ipaserver.install import installutils # pylint: disable=deprecated-module from optparse import OptionGroup, OptionValueError @@ -205,7 +206,7 @@ def parse_options(): parser.error("No action: you should select either --replica or --master option.") if not options.hostname: - options.hostname = socket.getfqdn() + options.hostname = FQDN return safe_options, options diff --git a/install/tools/ipa-replica-manage.in b/install/tools/ipa-replica-manage.in index f4e949407..a29c550d2 100644 --- a/install/tools/ipa-replica-manage.in +++ b/install/tools/ipa-replica-manage.in @@ -38,6 +38,7 @@ from ipaserver.install import bindinstance, cainstance from ipaserver.install import opendnssecinstance, dnskeysyncinstance from ipapython import version, ipaldap from ipalib import api, errors +from ipalib.constants import FQDN from ipalib.util import has_managed_topology, verify_host_resolvable from ipapython.ipa_log_manager import standard_logging_setup from ipapython.dn import DN @@ -1525,7 +1526,7 @@ def main(options, args): if options.host: host = options.host else: - host = installutils.get_fqdn() + host = FQDN options.host = host diff --git a/ipaclient/discovery.py b/ipaclient/discovery.py index fb344a34a..035e33c5e 100644 --- a/ipaclient/discovery.py +++ b/ipaclient/discovery.py @@ -20,13 +20,13 @@ from __future__ import absolute_import import logging -import socket import six from dns import rdatatype from dns.exception import DNSException from ipalib import errors +from ipalib.constants import FQDN from ipalib.util import validate_domain_name from ipapython.dnsutil import query_srv, resolve @@ -222,7 +222,7 @@ class IPADiscovery: if not domain: # domain not provided do full DNS discovery # get the local host name if not hostname: - hostname = socket.getfqdn() + hostname = FQDN logger.debug('Hostname: %s', hostname) if not hostname: return BAD_HOST_CONFIG diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py index 960e25e06..175a56cb7 100644 --- a/ipaclient/install/client.py +++ b/ipaclient/install/client.py @@ -36,7 +36,7 @@ from urllib.parse import urlparse, urlunparse from ipalib import api, errors, x509 from ipalib import sysrestore -from ipalib.constants import IPAAPI_USER, MAXHOSTNAMELEN +from ipalib.constants import FQDN, IPAAPI_USER, MAXHOSTNAMELEN from ipalib.install import certmonger, certstore, service from ipalib.install import hostname as hostname_ from ipalib.facts import is_ipa_client_configured, is_ipa_configured @@ -2121,7 +2121,7 @@ def install_check(options): hostname = options.hostname hostname_source = 'Provided as option' else: - hostname = socket.getfqdn() + hostname = FQDN hostname_source = "Machine's FQDN" if hostname != hostname.lower(): raise ScriptError( @@ -3270,7 +3270,7 @@ def uninstall(options): pass if hostname is None: - hostname = socket.getfqdn() + hostname = FQDN ipa_db = certdb.NSSDatabase(paths.IPA_NSSDB_DIR) sys_db = certdb.NSSDatabase(paths.NSS_DB_DIR) diff --git a/ipalib/constants.py b/ipalib/constants.py index 132d658c6..ae5291c04 100644 --- a/ipalib/constants.py +++ b/ipalib/constants.py @@ -23,18 +23,14 @@ All constants centralised in one file. """ import os -import socket + from ipaplatform.constants import constants as _constants from ipapython.dn import DN +from ipapython.fqdn import gethostfqdn from ipapython.version import VERSION, API_VERSION -try: - FQDN = socket.getfqdn() -except Exception: - try: - FQDN = socket.gethostname() - except Exception: - FQDN = None + +FQDN = gethostfqdn() # TLS related constants # * SSL2 and SSL3 are broken. diff --git a/ipapython/config.py b/ipapython/config.py index 1f4bfe011..f8c9b322d 100644 --- a/ipapython/config.py +++ b/ipapython/config.py @@ -25,7 +25,6 @@ from optparse import ( from copy import copy from configparser import SafeConfigParser from urllib.parse import urlsplit -import socket import functools from dns.exception import DNSException @@ -211,8 +210,11 @@ def __discover_config(discover_server = True): servers = query_srv(name) except DNSException: # try cycling on domain components of FQDN + # pylint: disable=ipa-forbidden-import + from ipalib.constants import FQDN + # pylint: enable=ipa-forbidden-import try: - domain = dns.name.from_text(socket.getfqdn()) + domain = dns.name.from_text(FQDN) except DNSException: return False diff --git a/ipapython/fqdn.py b/ipapython/fqdn.py new file mode 100644 index 000000000..efa157d4f --- /dev/null +++ b/ipapython/fqdn.py @@ -0,0 +1,30 @@ +# +# Copyright (C) 2020 FreeIPA Contributors see COPYING for license +# +"""Get host's FQDN +""" +import socket + + +def gethostfqdn(): + hostname = socket.gethostname() + + # optional optimization, consider hostname with dot as FQDN + if "." in hostname: + return hostname + + # this call can never fail except for misconfigured nsswitch.conf + # without nss-myhostname provider. The myhostname provider translates + # gethostname() to local interfaces. + gai = socket.getaddrinfo( + hostname, + None, # service/port is irrelevant + family=socket.AF_UNSPEC, # IPv4 or IPv6 + type=socket.SOCK_DGRAM, # optimization, TCP/RAW gives same result + # include canonical name in first addrinfo struct + # only use address family when at least one non-local interface + # is configured with that address family + flags=socket.AI_CANONNAME | socket.AI_ADDRCONFIG + ) + # first addrinfo struct, fourth field is canonical name + return gai[0][3] diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py index 27d075425..ff5627060 100644 --- a/ipaserver/dcerpc.py +++ b/ipaserver/dcerpc.py @@ -30,11 +30,11 @@ import time from ipalib import api, _ from ipalib import errors +from ipalib.constants import FQDN from ipapython import ipautil from ipapython.dn import DN from ipapython.dnsutil import query_srv from ipapython.ipaldap import ldap_initialize -from ipaserver.install import installutils from ipaserver.dcerpc_common import (TRUST_BIDIRECTIONAL, TRUST_JOIN_EXTERNAL, trust_type_string) @@ -1645,7 +1645,7 @@ class TrustDomainJoins: ld.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS) ld.creds.guess(ld.parm) ld.creds.set_workstation(ld.hostname) - ld.retrieve(installutils.get_fqdn()) + ld.retrieve(FQDN) self.local_domain = ld def populate_remote_domain(self, realm, realm_server=None, diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py index 8ef71f64e..57f2c13cc 100644 --- a/ipaserver/install/installutils.py +++ b/ipaserver/install/installutils.py @@ -50,7 +50,7 @@ import ipaplatform from ipapython import ipautil, admintool, version, ipaldap from ipapython.admintool import ScriptError, SERVER_NOT_CONFIGURED # noqa: E402 from ipapython.certdb import EXTERNAL_CA_TRUST_FLAGS -from ipalib.constants import MAXHOSTNAMELEN +from ipalib.constants import FQDN, MAXHOSTNAMELEN from ipalib.util import validate_hostname from ipalib import api, errors, x509 from ipalib.install import dnsforwarders @@ -118,16 +118,16 @@ class ReplicaConfig: subject_base = ipautil.dn_attribute_property('_subject_base') + def get_fqdn(): - fqdn = "" - try: - fqdn = socket.getfqdn() - except Exception: - try: - fqdn = socket.gethostname() - except Exception: - fqdn = "" - return fqdn + """Get fully qualified domain name of current host + + :note: used by ansible_freeipa + :deprecated: use ipalib.constants.FQDN + :return: str + """ + return FQDN + def verify_fqdn(host_name, no_host_dns=False, local_hostname=True): """ diff --git a/ipaserver/install/schemaupdate.py b/ipaserver/install/schemaupdate.py index 0370ef319..ab0dd8ac4 100644 --- a/ipaserver/install/schemaupdate.py +++ b/ipaserver/install/schemaupdate.py @@ -24,9 +24,9 @@ import ldap.schema import ipapython.version from ipalib import api +from ipalib.constants import FQDN from ipapython.dn import DN from ipaserver.install.ldapupdate import connect -from ipaserver.install import installutils SCHEMA_ELEMENT_CLASSES = ( @@ -105,9 +105,7 @@ def update_schema(schema_files, ldapi=False): """ SCHEMA_ELEMENT_CLASSES_KEYS = [x[0] for x in SCHEMA_ELEMENT_CLASSES] - conn = connect(ldapi=ldapi, - realm=api.env.realm, - fqdn=installutils.get_fqdn()) + conn = connect(ldapi=ldapi, realm=api.env.realm, fqdn=FQDN) old_schema = conn.schema diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py index 2d632576f..c0d33f3e7 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py @@ -31,7 +31,7 @@ from ipaplatform import services from ipaplatform.paths import paths from ipaplatform.tasks import tasks from ipalib import api, errors, x509 -from ipalib.constants import DOMAIN_LEVEL_0 +from ipalib.constants import DOMAIN_LEVEL_0, FQDN from ipalib.facts import is_ipa_configured, is_ipa_client_configured from ipalib.util import ( validate_domain_name, @@ -44,7 +44,7 @@ from ipaserver.install import ( otpdinstance, custodiainstance, replication, service, sysupgrade, cainstance) from ipaserver.install.installutils import ( - BadHostError, get_fqdn, get_server_ip_address, + BadHostError, get_server_ip_address, load_pkcs12, read_password, verify_fqdn, update_hosts_file, validate_mask) @@ -493,7 +493,7 @@ def install_check(installer): if options.host_name: host_default = options.host_name else: - host_default = get_fqdn() + host_default = FQDN if installer.interactive and not options.host_name: host_name = read_host_name(host_default) diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py index 896fb19ca..b1ea6883c 100644 --- a/ipaserver/install/service.py +++ b/ipaserver/install/service.py @@ -22,7 +22,6 @@ from __future__ import absolute_import import logging import sys import os -import socket import time import traceback import tempfile @@ -35,6 +34,7 @@ from ipapython import ipautil from ipapython.dn import DN from ipapython import kerberos from ipalib import api, errors, x509 +from ipalib.constants import FQDN from ipaplatform import services from ipaplatform.constants import User from ipaplatform.paths import paths @@ -291,7 +291,7 @@ class Service: self.steps = [] self.output_fd = sys.stdout - self.fqdn = socket.gethostname() + self.fqdn = FQDN if sstore: self.sstore = sstore diff --git a/ipatests/test_install/test_updates.py b/ipatests/test_install/test_updates.py index 125be52fc..0d356e7dc 100644 --- a/ipatests/test_install/test_updates.py +++ b/ipatests/test_install/test_updates.py @@ -28,8 +28,8 @@ import pytest from ipalib import api from ipalib import errors +from ipalib.constants import FQDN from ipaserver.install.ldapupdate import LDAPUpdate, BadSyntax -from ipaserver.install import installutils from ipapython import ipaldap from ipaplatform.constants import constants as platformconstants from ipapython.dn import DN @@ -56,7 +56,6 @@ class TestUpdate: @pytest.fixture(autouse=True) def update_setup(self, request): - fqdn = installutils.get_fqdn() pwfile = api.env.dot_ipa + os.sep + ".dmpw" if os.path.isfile(pwfile): with open(pwfile, "r") as fp: @@ -64,7 +63,7 @@ class TestUpdate: else: pytest.skip("No directory manager password") self.updater = LDAPUpdate() - self.ld = ipaldap.LDAPClient.from_hostname_secure(fqdn) + self.ld = ipaldap.LDAPClient.from_hostname_secure(FQDN) self.ld.simple_bind(bind_dn=ipaldap.DIRMAN_DN, bind_password=self.dm_password) self.testdir = os.path.abspath(os.path.dirname(__file__)) diff --git a/util/Makefile.am b/util/Makefile.am index 319809ba3..5e21c098f 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -1,17 +1,23 @@ +NULL = + AUTOMAKE_OPTIONS = 1.7 subdir-objects AM_CPPFLAGS = $(CRYPTO_CFLAGS) $(KRB5_CFLAGS) $(LDAP_CFLAGS) $(PWQUALITY_CFLAGS) noinst_LTLIBRARIES = libutil.la -libutil_la_SOURCES = ipa_krb5.c \ +libutil_la_SOURCES = \ + ipa_hostname.c \ + ipa_hostname.h \ + ipa_krb5.c \ ipa_krb5.h \ ipa_mspac.h \ ipa_ldap.c \ ipa_ldap.h \ ipa_pwd.c \ ipa_pwd.h \ - ipa_pwd_ntlm.c + ipa_pwd_ntlm.c \ + $(NULL) libutil_la_LIBADD = $(CRYPTO_LIBS) $(KRB5_LIBS) $(LDAP_LIBS) $(PWQUALITY_LIBS) diff --git a/util/ipa_hostname.c b/util/ipa_hostname.c new file mode 100644 index 000000000..97fe54cc6 --- /dev/null +++ b/util/ipa_hostname.c @@ -0,0 +1,111 @@ + +/* + * Copyright (C) 2020 FreeIPA Contributors see COPYING for license + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#include "ipa_hostname.h" + +int +ipa_gethostname(char *name) +{ + int ret; + + ret = gethostname(name, IPA_HOST_NAME_LEN - 1); + + /* Make double sure it is terminated */ + name[IPA_HOST_NAME_LEN - 1] = '\0'; + + return ret; +} + +static int +_get_fqdn(char *fqdn) +{ + char hostname[IPA_HOST_NAME_LEN]; + char *canonname = NULL; + struct addrinfo hints; + struct addrinfo *ai = NULL; + int r; + + r = ipa_gethostname(hostname); + if (r != 0) { + goto error; + } + + memset(&hints, 0, sizeof(struct addrinfo)); + /* use IPv4 or IPv6 */ + hints.ai_family = AF_UNSPEC; + /* optimize, RAW and STREAM return same kind of information */ + hints.ai_socktype = SOCK_DGRAM; + /* any protocol */ + hints.ai_protocol = 0; + /* get canonical name + * only use IPv4/6 when at least one interface for proto is configured */ + hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; + + r = getaddrinfo(hostname, NULL, &hints, &ai); + if (r != 0) { + /* getaddrinfo() for gethostname() should never fail. The + * nss-myhostname provider should always add a positive match. */ + errno = ENOENT; + goto error; + } + + /* only the first addrinfo struct holds a canonical name value */ + canonname = ai->ai_canonname; + + /* check that canon name is filled and not too long */ + if (!canonname) { + errno = ENOENT; + goto error; + } + if (strlen(canonname) >= IPA_HOST_NAME_LEN) { + errno = ENAMETOOLONG; + goto error; + } +#if 0 + /* refuse non-qualified short names and localhost */ + if ((strchr(canonname, '.') == NULL) || + (strcasecmp(canonname, "localhost.localdomain") == 0)) { + errno = EINVAL; + goto error; + } +#endif + + strcpy(fqdn, canonname); + /* Make double sure it is terminated */ + fqdn[IPA_HOST_NAME_LEN - 1] = '\0'; + freeaddrinfo(ai); + return 0; + + error: + fqdn[0] = '\0'; + if (ai != NULL) { + freeaddrinfo(ai); + } + return -1; +} + +int ipa_gethostfqdn(char *name) +{ + static char cached_fqdn[IPA_HOST_NAME_LEN] = {0}; + + if (!cached_fqdn) { + int res = _get_fqdn(cached_fqdn); + if (res != 0) { + return -1; + } + } + strcpy(name, cached_fqdn); + return 0; +} diff --git a/util/ipa_hostname.h b/util/ipa_hostname.h new file mode 100644 index 000000000..75c10a5dc --- /dev/null +++ b/util/ipa_hostname.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 FreeIPA Contributors see COPYING for license + */ + +#include +#include + +/* + * host name length including NULL byte + * + * NOTE: length hardcoded in kernel + */ +#define IPA_HOST_NAME_LEN (HOST_NAME_MAX + 1) + +int +ipa_gethostname(char *name); + +int +ipa_gethostfqdn(char *name);