/* * Try all of the server location methods in sequence. transport must be * TCP_OR_UDP, TCP, or UDP. It is applied to hostname entries in the profile * and affects whether we query modules or DNS for UDP or TCP or both, but does * not restrict a method from returning entries of other transports. */ static krb5_error_code locate_server(krb5_context context, const krb5_data *realm, struct serverlist *serverlist, enum locate_service_type svc, k5_transport transport) { krb5_error_code ret; struct serverlist list = SERVERLIST_INIT; *serverlist = list; /* Try modules. If a module returns 0 but leaves the list empty, return an * empty list. */ ret = module_locate_server(context, realm, &list, svc, transport); if (ret != KRB5_PLUGIN_NO_HANDLE) goto done; /* Try the profile. Fall back to DNS if it returns an empty list. */ ret = prof_locate_server(context, realm, &list, svc, transport); if (ret) goto done; #ifdef KRB5_DNS_LOOKUP if (list.nservers == 0) ret = dns_locate_server(context, realm, &list, svc, transport); #endif done: if (ret) { k5_free_serverlist(&list); return ret; } *serverlist = list; return 0; }
krb5_error_code k5_locate_server(krb5_context context, const krb5_data *realm, struct serverlist *serverlist, enum locate_service_type svc, int socktype) { krb5_error_code code; struct serverlist al = SERVERLIST_INIT; *serverlist = al; if (realm == NULL || realm->data == NULL || realm->data[0] == 0) { krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, "Cannot find KDC for invalid realm name \"\""); return KRB5_REALM_CANT_RESOLVE; } code = module_locate_server(context, realm, &al, svc, socktype); Tprintf("module_locate_server returns %d\n", code); if (code == KRB5_PLUGIN_NO_HANDLE) { /* * We always try the local file before DNS. Note that there * is no way to indicate "service not available" via the * config file. */ code = prof_locate_server(context, realm, &al, svc, socktype); #ifdef KRB5_DNS_LOOKUP if (code) { /* Try DNS for all profile errors? */ krb5_error_code code2; code2 = dns_locate_server(context, realm, &al, svc, socktype); if (code2 != KRB5_PLUGIN_NO_HANDLE) code = code2; } #endif /* KRB5_DNS_LOOKUP */ /* We could put more heuristics here, like looking up a hostname of "kerberos."+REALM, etc. */ } if (code == 0) Tprintf ("krb5int_locate_server found %d addresses\n", al.nservers); else Tprintf ("krb5int_locate_server returning error code %d/%s\n", code, error_message(code)); if (code != 0) { k5_free_serverlist(&al); return code; } if (al.nservers == 0) { /* No good servers */ k5_free_serverlist(&al); krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, _("Cannot resolve servers for KDC in realm " "\"%.*s\""), realm->length, realm->data); return KRB5_REALM_CANT_RESOLVE; } *serverlist = al; return 0; }
krb5_error_code krb5int_locate_server (krb5_context context, const krb5_data *realm, struct addrlist *addrlist, enum locate_service_type svc, int socktype, int family) { krb5_error_code code; struct addrlist al = ADDRLIST_INIT; char **hostlist = NULL; struct srv_dns_entry *dns_list_head = NULL; *addrlist = al; /* * Solaris Kerberos (illumos) * Allow main programs to override _locate_server() */ code = override_locate_server(context, realm, &al, svc, socktype, family); if (code != KRB5_PLUGIN_NO_HANDLE) { if (code == 0) *addrlist = al; else if (al.space) free_list (&al); return (code); } /* Solaris Kerberos (illumos) */ code = module_locate_server(context, realm, &al, svc, socktype, family); Tprintf("module_locate_server returns %d\n", code); if (code == KRB5_PLUGIN_NO_HANDLE) { /* * We always try the local file before DNS. Note that there * is no way to indicate "service not available" via the * config file. */ code = prof_locate_server(context, realm, &hostlist, svc); /* * Solaris Kerberos: * If kpasswd_server has not been configured and dns_lookup_kdc - * dns_fallback are not configured then admin_server should * be inferred, per krb5.conf(4). */ if (code && svc == locate_service_kpasswd && !maybe_use_dns(context, "dns_lookup_kdc", 0)) { code = prof_locate_server(context, realm, &hostlist, locate_service_kadmin); } #ifdef KRB5_DNS_LOOKUP /* * Solaris Kerberos: * There is no point in trying to locate the KDC in DNS if "realm" * is empty. */ /* Try DNS for all profile errors? */ if (code && !krb5_is_referral_realm(realm)) { krb5_error_code code2; code2 = dns_locate_server(context, realm, &dns_list_head, svc, socktype, family); if (code2 != KRB5_PLUGIN_NO_HANDLE) code = code2; } #endif /* KRB5_DNS_LOOKUP */ /* We could put more heuristics here, like looking up a hostname of "kerberos."+REALM, etc. */ } if (code != 0) { if (al.space) free_list (&al); if (hostlist) profile_free_list(hostlist); if (dns_list_head) krb5int_free_srv_dns_data(dns_list_head); return code; } /* * At this point we have no errors, let's check to see if we have * any KDC entries from krb5.conf or DNS. */ if (!hostlist && !dns_list_head) { switch(svc) { case locate_service_master_kdc: krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, dgettext(TEXT_DOMAIN, "Cannot find a master KDC entry in krb5.conf(4) or DNS Service Location records for realm '%.*s'"), realm->length, realm->data); break; case locate_service_kadmin: krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, dgettext(TEXT_DOMAIN, "Cannot find a kadmin KDC entry in krb5.conf(4) or DNS Service Location records for realm '%.*s'"), realm->length, realm->data); break; case locate_service_kpasswd: krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, dgettext(TEXT_DOMAIN, "Cannot find a kpasswd KDC entry in krb5.conf(4) or DNS Service Location records for realm '%.*s'"), realm->length, realm->data); break; default: /* locate_service_kdc: */ krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, dgettext(TEXT_DOMAIN, "Cannot find any KDC entries in krb5.conf(4) or DNS Service Location records for realm '%.*s'"), realm->length, realm->data); } return KRB5_REALM_CANT_RESOLVE; } /* We have KDC entries, let see if we can get their net addrs. */ if (hostlist) code = prof_hostnames2netaddrs(hostlist, svc, socktype, family, &al); else if (dns_list_head) code = dns_hostnames2netaddrs(dns_list_head, svc, socktype, family, &al); if (code) { if (hostlist) profile_free_list(hostlist); if (dns_list_head) krb5int_free_srv_dns_data(dns_list_head); return code; } /* * Solaris Kerberos: * If an entry for _kerberos-master. does not exist (checked for * above) but _kpasswd. does then treat that as an entry for the * master KDC (but use port 88 not the kpasswd port). MS AD creates * kpasswd entries by default in DNS. */ if (!dns_list_head && svc == locate_service_master_kdc && al.naddrs == 0) { /* Look for _kpasswd._tcp|udp */ code = dns_locate_server(context, realm, &dns_list_head, locate_service_kpasswd, socktype, family); if (code == 0 && dns_list_head) { int i; struct addrinfo *a; code = dns_hostnames2netaddrs(dns_list_head, svc, socktype, family, &al); /* Set the port to 88 instead of the kpasswd port */ if (code == 0 && al.naddrs > 0) { for (i = 0; i < al.naddrs; i++) { if (al.addrs[i].ai->ai_family == AF_INET) for (a = al.addrs[i].ai; a != NULL; a = a->ai_next) ((struct sockaddr_in *)a->ai_addr)->sin_port = htons(KRB5_DEFAULT_PORT); if (al.addrs[i].ai->ai_family == AF_INET6) for (a = al.addrs[i].ai; a != NULL; a = a->ai_next) ((struct sockaddr_in6 *)a->ai_addr)->sin6_port = htons(KRB5_DEFAULT_PORT); } } } } /* No errors so far, lets see if we have KDC net addrs */ if (al.naddrs == 0) { char *hostlist_str = NULL, *dnslist_str = NULL; if (al.space) free_list (&al); if (hostlist) { hostlist_str = hostlist2str(hostlist); krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, dgettext(TEXT_DOMAIN, "Cannot resolve network address for KDCs '%s' specified in krb5.conf(4) for realm %.*s"), hostlist_str ? hostlist_str : "unknown", realm->length, realm->data); if (hostlist_str) free(hostlist_str); } else if (dns_list_head) { dnslist_str = dnslist2str(dns_list_head); krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, dgettext(TEXT_DOMAIN, "Cannot resolve network address for KDCs '%s' discovered via DNS Service Location records for realm '%.*s'"), dnslist_str ? dnslist_str : "unknown", realm->length, realm->data); if (dnslist_str) free(dnslist_str); } if (hostlist) profile_free_list(hostlist); if (dns_list_head) krb5int_free_srv_dns_data(dns_list_head); return KRB5_REALM_CANT_RESOLVE; } if (hostlist) profile_free_list(hostlist); if (dns_list_head) krb5int_free_srv_dns_data(dns_list_head); *addrlist = al; return 0; }