If this flag is true, initial tickets will be proxiable by
default, if allowed by the KDC. The default value is false.
+**qualify_shortname**
+ If this string is set, it determines the domain suffix for
+ single-component hostnames when DNS canonicalization is not used
+ (either because **dns_canonicalize_hostname** is false or because
+ forward canonicalization failed). The default value is the first
+ search domain of the system's DNS configuration. To disable
+ qualification of shortnames, set this relation to the empty string
+ with ``qualify_shortname = ""``. (New in release 1.18.)
+
**rdns**
If this flag is true, reverse name lookup will be used in addition
to forward name lookup to canonicalizing hostnames for use in
#define KRB5_CONF_PLUGIN_BASE_DIR "plugin_base_dir"
#define KRB5_CONF_PREFERRED_PREAUTH_TYPES "preferred_preauth_types"
#define KRB5_CONF_PROXIABLE "proxiable"
+#define KRB5_CONF_QUALIFY_SHORTNAME "qualify_shortname"
#define KRB5_CONF_RDNS "rdns"
#define KRB5_CONF_REALMS "realms"
#define KRB5_CONF_REALM_TRY_DOMAINS "realm_try_domains"
* Define macros to use the best available DNS search functions. INIT_HANDLE()
* returns true if handle initialization is successful, false if it is not.
* SEARCH() returns the length of the response or -1 on error.
+ * PRIMARY_DOMAIN() returns the first search domain in allocated memory.
* DECLARE_HANDLE() must be used last in the declaration list since it may
* evaluate to nothing.
*/
#define DECLARE_HANDLE(h) dns_handle_t h
#define INIT_HANDLE(h) ((h = dns_open(NULL)) != NULL)
#define SEARCH(h, n, c, t, a, l) dns_search(h, n, c, t, a, l, NULL, NULL)
+#define PRIMARY_DOMAIN(h) dns_search_list_domain(h, 0)
#define DESTROY_HANDLE(h) dns_free(h)
#elif HAVE_RES_NINIT && HAVE_RES_NSEARCH
#define DECLARE_HANDLE(h) struct __res_state h
#define INIT_HANDLE(h) (memset(&h, 0, sizeof(h)), res_ninit(&h) == 0)
#define SEARCH(h, n, c, t, a, l) res_nsearch(&h, n, c, t, a, l)
+#define PRIMARY_DOMAIN(h) strdup(h.dnsrch[0])
#if HAVE_RES_NDESTROY
#define DESTROY_HANDLE(h) res_ndestroy(&h)
#else
#define DECLARE_HANDLE(h)
#define INIT_HANDLE(h) (res_init() == 0)
#define SEARCH(h, n, c, t, a, l) res_search(n, c, t, a, l)
+#define PRIMARY_DOMAIN(h) strdup(_res.defdname)
#define DESTROY_HANDLE(h)
#endif
return ret;
}
+char *
+k5_primary_domain()
+{
+ return NULL;
+}
+
#else /* _WIN32 */
krb5_error_code
return retval;
}
+char *
+k5_primary_domain()
+{
+ char *domain;
+ DECLARE_HANDLE(h);
+
+ if (!INIT_HANDLE(h))
+ return NULL;
+ domain = PRIMARY_DOMAIN(h);
+ DESTROY_HANDLE(h);
+ return domain;
+}
+
#endif /* not _WIN32 */
#endif /* KRB5_DNS_LOOKUP */
krb5_error_code k5_try_realm_txt_rr(krb5_context context, const char *prefix,
const char *name, char **realm);
+char *k5_primary_domain(void);
+
int _krb5_use_dns_realm (krb5_context);
int _krb5_use_dns_kdc (krb5_context);
int _krb5_conf_boolean (const char *);
&value);
if (ret)
return DEFAULT_RDNS_LOOKUP;
+
return value;
}
+/* Append a domain suffix to host and return the result in allocated memory.
+ * Return NULL if no suffix is configured or on failure. */
+static char *
+qualify_shortname(krb5_context context, const char *host)
+{
+ krb5_error_code ret;
+ char *fqdn = NULL, *prof_domain = NULL, *os_domain = NULL;
+ const char *domain;
+
+ ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
+ KRB5_CONF_QUALIFY_SHORTNAME, NULL, NULL,
+ &prof_domain);
+ if (ret)
+ return NULL;
+
+#ifdef KRB5_DNS_LOOKUP
+ if (prof_domain == NULL)
+ os_domain = k5_primary_domain();
+#endif
+
+ domain = (prof_domain != NULL) ? prof_domain : os_domain;
+ if (domain != NULL && *domain != '\0') {
+ if (asprintf(&fqdn, "%s.%s", host, domain) < 0)
+ fqdn = NULL;
+ }
+
+ profile_release_string(prof_domain);
+ free(os_domain);
+ return fqdn;
+}
+
krb5_error_code
k5_expand_hostname(krb5_context context, const char *host,
krb5_boolean is_fallback, char **canonhost_out)
{
struct addrinfo *ai = NULL, hint;
- char namebuf[NI_MAXHOST], *copy, *p;
+ char namebuf[NI_MAXHOST], *qualified = NULL, *copy, *p;
int err;
const char *canonhost;
krb5_boolean use_dns;
}
}
+ /* If we didn't use DNS and the name is just one component, try to add a
+ * domain suffix. */
+ if (canonhost == host && strchr(host, '.') == NULL) {
+ qualified = qualify_shortname(context, host);
+ if (qualified != NULL)
+ canonhost = qualified;
+ }
+
copy = strdup(canonhost);
if (copy == NULL)
goto cleanup;
/* We only return success or ENOMEM. */
if (ai != NULL)
freeaddrinfo(ai);
+ free(qualified);
return (*canonhost_out == NULL) ? ENOMEM : 0;
}
# Create two independent realms (no cross-realm TGTs). For the
# fallback realm tests we need to control the precise server hostname,
-# so turn off DNS canonicalization.
-conf = {'libdefaults': {'dns_canonicalize_hostname': 'false'}}
+# so turn off DNS canonicalization and shortname qualification.
+conf = {'libdefaults': {'dns_canonicalize_hostname': 'false',
+ 'qualify_shortname': ''}}
r1 = K5Realm(create_user=False, krb5_conf=conf)
r2 = K5Realm(create_user=False, krb5_conf=conf, realm='KRBTEST2.COM',
portbase=62000, testdir=os.path.join(r1.testdir, 'r2'))
'example.com': 'R2',
'mit.edu': 'R3'}}
no_rdns_conf = {'libdefaults': {'rdns': 'false'}}
-no_canon_conf = {'libdefaults': {'dns_canonicalize_hostname': 'false'}}
+no_canon_conf = {'libdefaults': {'dns_canonicalize_hostname': 'false',
+ 'qualify_shortname': 'example.com'}}
fallback_canon_conf = {'libdefaults':
{'rdns': 'false',
'dns_canonicalize_hostname': 'fallback'}}
testu('example.com.::123', 'example.com.::123', '')
# With dns_canonicalize_hostname=false, we downcase and remove
-# trailing dots but do not canonicalize the hostname. Trailers do not
-# get downcased.
+# trailing dots but do not canonicalize the hostname.
+# Single-component names are qualified with the configured suffix
+# (defaulting to the first OS search domain, but Python cannot easily
+# retrieve that value so we don't test it). Trailers do not get
+# downcased.
mark('dns_canonicalize_host=false')
testnc('ptr-mismatch.kerberos.org', 'ptr-mismatch.kerberos.org', 'R1')
testnc('Example.COM', 'example.com', 'R2')
-testnc('abcde', 'abcde', '')
+testnc('abcde', 'abcde.example.com', 'R2')
testnc('example.com.:123', 'example.com:123', 'R2')
testnc('Example.COM:xyZ', 'example.com:xyZ', 'R2')
testnc('example.com.::123', 'example.com.::123', '')
def _subst_cfg_value(self, value):
global buildtop, srctop, hostname
template = string.Template(value)
- return template.substitute(realm=self.realm,
- testdir=self.testdir,
- buildtop=buildtop,
- srctop=srctop,
- plugins=plugins,
- hostname=hostname,
- port0=self.portbase,
- port1=self.portbase + 1,
- port2=self.portbase + 2,
- port3=self.portbase + 3,
- port4=self.portbase + 4,
- port5=self.portbase + 5,
- port6=self.portbase + 6,
- port7=self.portbase + 7,
- port8=self.portbase + 8,
- port9=self.portbase + 9)
+ subst = template.substitute(realm=self.realm,
+ testdir=self.testdir,
+ buildtop=buildtop,
+ srctop=srctop,
+ plugins=plugins,
+ hostname=hostname,
+ port0=self.portbase,
+ port1=self.portbase + 1,
+ port2=self.portbase + 2,
+ port3=self.portbase + 3,
+ port4=self.portbase + 4,
+ port5=self.portbase + 5,
+ port6=self.portbase + 6,
+ port7=self.portbase + 7,
+ port8=self.portbase + 8,
+ port9=self.portbase + 9)
+ # Empty values must be quoted to avoid a syntax error.
+ return subst if subst else '""'
def _create_acl(self):
global hostname