2N/A/*
2N/A * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * lib/kad5/kadm_host_srv_names.c
2N/A */
2N/A
2N/A#include <k5-int.h>
2N/A#include "admin.h"
2N/A#include <stdio.h>
2N/A#include <os-proto.h>
2N/A
2N/A
2N/A#define KADM5_MASTER "admin_server"
2N/A#define KADM5_KPASSWD "kpasswd_server"
2N/A
2N/A/*
2N/A * Find the admin server for the given realm. If the realm is null or
2N/A * the empty string, find the admin server for the default realm.
2N/A * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to
2N/A * free the storage allocated to the admin server, master.
2N/A */
2N/Akadm5_ret_t
2N/Akadm5_get_master(krb5_context context, const char *realm, char **master)
2N/A{
2N/A /* Solaris Kerberos */
2N/A char *def_realm = NULL;
2N/A
2N/A char *delim;
2N/A#ifdef KRB5_DNS_LOOKUP
2N/A struct sockaddr *addrs;
2N/A int naddrs;
2N/A unsigned short dns_portno;
2N/A char dns_host[MAX_DNS_NAMELEN];
2N/A krb5_data dns_realm;
2N/A krb5_error_code dns_ret = 1;
2N/A#endif /* KRB5_DNS_LOOKUP */
2N/A
2N/A if (realm == 0 || *realm == '\0')
2N/A krb5_get_default_realm(context, &def_realm);
2N/A
2N/A (void) profile_get_string(context->profile, "realms",
2N/A realm ? realm : def_realm,
2N/A KADM5_MASTER, 0, master);
2N/A
2N/A if ((*master != NULL) && ((delim = strchr(*master, ':')) != NULL))
2N/A *delim = '\0';
2N/A#ifdef KRB5_DNS_LOOKUP
2N/A if (*master == NULL) {
2N/A /*
2N/A * Initialize realm info for (possible) DNS lookups.
2N/A */
2N/A dns_realm.data = strdup(realm ? realm : def_realm);
2N/A dns_realm.length = strlen(realm ? realm : def_realm);
2N/A dns_realm.magic = 0;
2N/A
2N/A dns_ret = krb5_get_servername(context, &dns_realm,
2N/A "_kerberos-adm", "_udp",
2N/A dns_host, &dns_portno);
2N/A if (dns_ret == 0)
2N/A *master = strdup(dns_host);
2N/A
2N/A if (dns_realm.data)
2N/A free(dns_realm.data);
2N/A }
2N/A#endif /* KRB5_DNS_LOOKUP */
2N/A
2N/A /* Solaris Kerberos */
2N/A if (def_realm != NULL)
2N/A krb5_free_default_realm(context, def_realm);
2N/A
2N/A return (*master ? KADM5_OK : KADM5_NO_SRV);
2N/A}
2N/A
2N/A/*
2N/A * Find the kpasswd server for the given realm. If the realm is null or
2N/A * the empty string, find the admin server for the default realm.
2N/A * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to
2N/A * free the storage allocated to the admin server, master.
2N/A */
2N/Akadm5_ret_t
2N/Akadm5_get_kpasswd(krb5_context context, const char *realm, char **kpasswd)
2N/A{
2N/A char *def_realm = NULL;
2N/A char *delim;
2N/A#ifdef KRB5_DNS_LOOKUP
2N/A struct sockaddr *addrs;
2N/A int naddrs;
2N/A unsigned short dns_portno;
2N/A char dns_host[MAX_DNS_NAMELEN];
2N/A krb5_data dns_realm;
2N/A krb5_error_code dns_ret = 1, ret;
2N/A char **masterlist, **hostlist, *host, *port, *cp;
2N/A#endif /* KRB5_DNS_LOOKUP */
2N/A
2N/A if (realm == 0 || *realm == '\0') {
2N/A ret = krb5_get_default_realm(context, &def_realm);
2N/A if (ret != 0)
2N/A return (ret);
2N/A }
2N/A
2N/A (void) profile_get_string(context->profile, "realms",
2N/A realm ? realm : def_realm,
2N/A KADM5_KPASSWD, 0, kpasswd);
2N/A
2N/A if ((*kpasswd != NULL) && ((delim = strchr(*kpasswd, ':')) != NULL))
2N/A *delim = '\0';
2N/A#ifdef KRB5_DNS_LOOKUP
2N/A if (*kpasswd == NULL) {
2N/A /*
2N/A * Initialize realm info for (possible) DNS lookups.
2N/A */
2N/A dns_realm.data = strdup(realm ? realm : def_realm);
2N/A if (dns_realm.data == NULL) {
2N/A if (def_realm != NULL)
2N/A free(def_realm);
2N/A return (ENOMEM);
2N/A }
2N/A dns_realm.length = strlen(realm ? realm : def_realm);
2N/A dns_realm.magic = 0;
2N/A
2N/A dns_ret = krb5_get_servername(context, &dns_realm,
2N/A "_kpasswd", "_tcp",
2N/A dns_host, &dns_portno);
2N/A if (dns_ret == 0) {
2N/A *kpasswd = strdup(dns_host);
2N/A
2N/A if (*kpasswd == NULL) {
2N/A free(dns_realm.data);
2N/A if (def_realm != NULL)
2N/A free(def_realm);
2N/A return (ENOMEM);
2N/A }
2N/A }
2N/A
2N/A free(dns_realm.data);
2N/A }
2N/A#endif /* KRB5_DNS_LOOKUP */
2N/A
2N/A if (def_realm != NULL)
2N/A free(def_realm);
2N/A return (*kpasswd ? KADM5_OK : KADM5_NO_SRV);
2N/A}
2N/A
2N/Avoid
2N/Afree_srv_names(char **srv_names)
2N/A{
2N/A int i;
2N/A
2N/A if (srv_names == NULL)
2N/A return;
2N/A
2N/A for (i = 0; srv_names[i] != NULL; i++) {
2N/A free(srv_names[i]);
2N/A }
2N/A
2N/A free(srv_names);
2N/A}
2N/A
2N/A/*
2N/A * Get the host base service name for the admin principal. Returns
2N/A * KADM5_OK on success. Caller must call free_srv_names() on
2N/A * host_service_names.
2N/A */
2N/Akadm5_ret_t
2N/Akadm5_get_adm_host_srv_names(krb5_context context,
2N/A const char *realm, char ***host_service_names)
2N/A{
2N/A kadm5_ret_t ret;
2N/A char **tmp_srv_names;
2N/A struct addrlist al = ADDRLIST_INIT;
2N/A int i;
2N/A krb5_data realm_data;
2N/A
2N/A /* get list of admin servers */
2N/A if (realm == NULL)
2N/A return (EINVAL);
2N/A realm_data.magic = KV5M_DATA;
2N/A realm_data.data = (char *) realm;
2N/A realm_data.length = strlen(realm);
2N/A if (ret = locate_kadmin(context, (const krb5_data *) &realm_data, &al))
2N/A return (ret);
2N/A
2N/A /* + 1 for array terminator */
2N/A tmp_srv_names = calloc(al.naddrs + 1, sizeof (char *));
2N/A if (tmp_srv_names == NULL) {
2N/A krb5int_free_addrlist(&al);
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A for (i = 0; i < al.naddrs; i++) {
2N/A tmp_srv_names[i] = malloc(strlen(KADM5_ADMIN_HOST_SERVICE) +
2N/A strlen(al.addrs[i].hostname) + 2);
2N/A if (tmp_srv_names[i] == NULL) {
2N/A free_srv_names(tmp_srv_names);
2N/A krb5int_free_addrlist(&al);
2N/A return (ENOMEM);
2N/A }
2N/A sprintf(tmp_srv_names[i], "%s@%s", KADM5_ADMIN_HOST_SERVICE,
2N/A al.addrs[i].hostname);
2N/A }
2N/A
2N/A krb5int_free_addrlist(&al);
2N/A *host_service_names = tmp_srv_names;
2N/A return (KADM5_OK);
2N/A}
2N/A
2N/A/*
2N/A * Get the host base service name for the changepw principal. Returns
2N/A * KADM5_OK on success. Caller must call free_srv_names() on
2N/A * host_service_names.
2N/A */
2N/Akadm5_ret_t
2N/Akadm5_get_cpw_host_srv_names(krb5_context context,
2N/A const char *realm, char ***host_service_names)
2N/A{
2N/A kadm5_ret_t ret;
2N/A char **tmp_srv_names;
2N/A struct addrlist al = ADDRLIST_INIT;
2N/A int i;
2N/A krb5_data realm_data;
2N/A
2N/A /* get list of kpassd or admin servers */
2N/A if (realm == NULL)
2N/A return (EINVAL);
2N/A realm_data.magic = KV5M_DATA;
2N/A realm_data.data = (char *) realm;
2N/A realm_data.length = strlen(realm);
2N/A if (ret = locate_kpasswd(context, (const krb5_data *) &realm_data, &al, 0))
2N/A return (ret);
2N/A
2N/A /* + 1 for array terminator */
2N/A tmp_srv_names = calloc(al.naddrs + 1, sizeof (char *));
2N/A if (tmp_srv_names == NULL) {
2N/A krb5int_free_addrlist(&al);
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A for (i = 0; i < al.naddrs; i++) {
2N/A tmp_srv_names[i] = malloc(strlen(KADM5_CHANGEPW_HOST_SERVICE) +
2N/A strlen(al.addrs[i].hostname) + 2);
2N/A if (tmp_srv_names[i] == NULL) {
2N/A free_srv_names(tmp_srv_names);
2N/A krb5int_free_addrlist(&al);
2N/A return (ENOMEM);
2N/A }
2N/A sprintf(tmp_srv_names[i], "%s@%s", KADM5_CHANGEPW_HOST_SERVICE,
2N/A al.addrs[i].hostname);
2N/A }
2N/A
2N/A krb5int_free_addrlist(&al);
2N/A
2N/A *host_service_names = tmp_srv_names;
2N/A
2N/A return (KADM5_OK);
2N/A}
2N/A
2N/A/*
2N/A * Get the host base service name for the kiprop principal. Returns
2N/A * KADM5_OK on success. Caller must free the storage allocated
2N/A * for host_service_name.
2N/A */
2N/Akadm5_ret_t
2N/Akadm5_get_kiprop_host_srv_names(krb5_context context,
2N/A const char *realm,
2N/A char ***host_service_names)
2N/A{
2N/A kadm5_ret_t ret;
2N/A char **tmp_srv_names;
2N/A struct addrlist al = ADDRLIST_INIT;
2N/A int i;
2N/A krb5_data realm_data;
2N/A
2N/A /* get list of admin or kpasswd servers */
2N/A if (realm == NULL)
2N/A return (EINVAL);
2N/A realm_data.magic = KV5M_DATA;
2N/A realm_data.data = (char *) realm;
2N/A realm_data.length = strlen(realm);
2N/A if (ret = locate_kadmin(context, (const krb5_data *) &realm_data, &al))
2N/A return (ret);
2N/A
2N/A /* + 1 for array terminator */
2N/A tmp_srv_names = calloc(al.naddrs + 1, sizeof (char *));
2N/A if (tmp_srv_names == NULL) {
2N/A krb5int_free_addrlist(&al);
2N/A return (ENOMEM);
2N/A }
2N/A
2N/A for (i = 0; i < al.naddrs; i++) {
2N/A tmp_srv_names[i] = malloc(strlen(KADM5_KIPROP_HOST_SERVICE) +
2N/A strlen(al.addrs[i].hostname) + 2);
2N/A if (tmp_srv_names[i] == NULL) {
2N/A free_srv_names(tmp_srv_names);
2N/A krb5int_free_addrlist(&al);
2N/A return (ENOMEM);
2N/A }
2N/A sprintf(tmp_srv_names[i], "%s@%s", KADM5_KIPROP_HOST_SERVICE,
2N/A al.addrs[i].hostname);
2N/A }
2N/A
2N/A krb5int_free_addrlist(&al);
2N/A *host_service_names = tmp_srv_names;
2N/A return (KADM5_OK);
2N/A}
2N/A
2N/A/*
2N/A * Solaris Kerberos:
2N/A * Try to determine if this system is one of the master KDCs for a given realm
2N/A */
2N/Akadm5_ret_t kadm5_is_master(krb5_context context, const char *realm,
2N/A krb5_boolean *is_master, char **master_hostname) {
2N/A
2N/A kadm5_ret_t ret = KADM5_OK;
2N/A krb5_address **tmp_addr, **master_addr = NULL;
2N/A krb5_address **local_addr = NULL;
2N/A struct addrlist al = ADDRLIST_INIT;
2N/A int i;
2N/A krb5_data realm_data;
2N/A
2N/A if (is_master)
2N/A *is_master = FALSE;
2N/A else
2N/A return (KADM5_FAILURE);
2N/A
2N/A /* get list of admin servers (master KDCs) */
2N/A if (realm == NULL)
2N/A return (EINVAL);
2N/A realm_data.magic = KV5M_DATA;
2N/A realm_data.data = (char *) realm;
2N/A realm_data.length = strlen(realm);
2N/A if (ret = locate_kadmin(context, (const krb5_data *) &realm_data, &al))
2N/A return (ret);
2N/A
2N/A /* Get the local addresses */
2N/A if (ret = krb5_os_localaddr(context, &local_addr))
2N/A goto error;
2N/A
2N/A for (i = 0; i < al.naddrs; i++) {
2N/A if (ret = krb5_os_hostaddr(context, al.addrs[i].hostname, &master_addr))
2N/A goto error;
2N/A
2N/A /* Compare them */
2N/A for (tmp_addr = master_addr; *tmp_addr; tmp_addr++) {
2N/A if (krb5_address_search(context, *tmp_addr, local_addr)) {
2N/A *is_master = TRUE;
2N/A if (master_hostname != NULL) {
2N/A *master_hostname = strdup(al.addrs[i].hostname);
2N/A if (*master_hostname == NULL) {
2N/A ret = ENOMEM;
2N/A goto error;
2N/A }
2N/A }
2N/A break;
2N/A }
2N/A }
2N/A krb5_free_addresses(context, master_addr);
2N/A master_addr = NULL;
2N/A }
2N/A
2N/Aerror:
2N/A if (local_addr)
2N/A krb5_free_addresses(context, local_addr);
2N/A if (master_addr)
2N/A krb5_free_addresses(context, master_addr);
2N/A if (al.naddrs > 0)
2N/A krb5int_free_addrlist(&al);
2N/A
2N/A return (ret);
2N/A}