static krb5_error_code locate_srv_dns_1(const krb5_data *realm, const char *service, const char *protocol, struct serverlist *serverlist) { struct srv_dns_entry *head = NULL, *entry = NULL; krb5_error_code code = 0; int socktype; code = krb5int_make_srv_query_realm(realm, service, protocol, &head); if (code) return 0; if (head == NULL) return 0; /* Check for the "." case indicating no support. */ if (head->next == NULL && head->host[0] == '\0') { code = KRB5_ERR_NO_SERVICE; goto cleanup; } for (entry = head; entry != NULL; entry = entry->next) { socktype = (strcmp(protocol, "_tcp") == 0) ? SOCK_STREAM : SOCK_DGRAM; code = add_host_to_list(serverlist, entry->host, htons(entry->port), socktype, AF_UNSPEC); if (code) goto cleanup; } cleanup: krb5int_free_srv_dns_data(head); return code; }
static krb5_error_code locate_srv_dns_1(krb5_context context, const krb5_data *realm, const char *service, const char *protocol, struct serverlist *serverlist) { struct srv_dns_entry *head = NULL, *entry = NULL; krb5_error_code code = 0; k5_transport transport; code = krb5int_make_srv_query_realm(context, realm, service, protocol, &head); if (code) return 0; if (head == NULL) return 0; /* Check for the "." case indicating no support. */ if (head->next == NULL && head->host[0] == '\0') { code = KRB5_ERR_NO_SERVICE; goto cleanup; } for (entry = head; entry != NULL; entry = entry->next) { transport = (strcmp(protocol, "_tcp") == 0) ? TCP : UDP; code = add_host_to_list(serverlist, entry->host, entry->port, transport, AF_UNSPEC, NULL, -1); if (code) goto cleanup; } cleanup: krb5int_free_srv_dns_data(head); return code; }
/* * Collect a list of servers from DNS URI records, for the requested service * and transport type. Problematic entries are skipped. */ static krb5_error_code locate_uri(krb5_context context, const krb5_data *realm, const char *req_service, struct serverlist *serverlist, k5_transport req_transport, int default_port, krb5_boolean master_only) { krb5_error_code ret; k5_transport transport, host_trans; struct srv_dns_entry *answers, *entry; char *host; const char *host_field, *path; int port, def_port, master; ret = k5_make_uri_query(context, realm, req_service, &answers); if (ret || answers == NULL) return ret; for (entry = answers; entry != NULL; entry = entry->next) { def_port = default_port; path = NULL; parse_uri_fields(entry->host, &transport, &host_field, &master); if (host_field == NULL) continue; /* TCP_OR_UDP allows entries of any transport type; otherwise * we're asking for a match. */ if (req_transport != TCP_OR_UDP && req_transport != transport) continue; /* Process a MS-KKDCP target. */ if (transport == HTTPS) { host_trans = 0; def_port = 443; parse_uri_if_https(host_field, &host_trans, &host_field, &path); if (host_trans != HTTPS) continue; } ret = k5_parse_host_string(host_field, def_port, &host, &port); if (ret == ENOMEM) break; if (ret || host == NULL) { ret = 0; continue; } ret = add_host_to_list(serverlist, host, port, transport, AF_UNSPEC, path, master); free(host); if (ret) break; } krb5int_free_srv_dns_data(answers); return ret; }
/* * Solaris Kerberos: for backward compat. Avoid using this * function! */ krb5_error_code krb5_get_servername(krb5_context context, const krb5_data *realm, const char *name, const char *proto, char *srvhost, unsigned short *port) { krb5_error_code code = KRB5_REALM_UNKNOWN; #ifdef KRB5_DNS_LOOKUP { int use_dns = _krb5_use_dns_kdc(context); if (use_dns) { struct srv_dns_entry *head = NULL; code = krb5int_make_srv_query_realm(realm, name, proto, &head); if (code) return (code); if (head == NULL) return KRB5_REALM_CANT_RESOLVE; *port = head->port; (void) strlcpy(srvhost, head->host, MAX_DNS_NAMELEN); #ifdef DEBUG fprintf (stderr, "krb5_get_servername svrhost %s, port %d\n", srvhost, *port); #endif krb5int_free_srv_dns_data(head); } } #endif /* KRB5_DNS_LOOKUP */ return (code); }
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; }