xref: /onnv-gate/usr/src/lib/krb5/kadm5/kadm_host_srv_names.c (revision 12361:b3d87c6a3997)
10Sstevel@tonic-gate /*
2*12361SMark.Phalan@Sun.COM  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
30Sstevel@tonic-gate  */
40Sstevel@tonic-gate 
50Sstevel@tonic-gate /*
60Sstevel@tonic-gate  * lib/kad5/kadm_host_srv_names.c
70Sstevel@tonic-gate  */
80Sstevel@tonic-gate 
97934SMark.Phalan@Sun.COM #include <k5-int.h>
100Sstevel@tonic-gate #include "admin.h"
110Sstevel@tonic-gate #include <stdio.h>
120Sstevel@tonic-gate #include <os-proto.h>
130Sstevel@tonic-gate 
147934SMark.Phalan@Sun.COM 
150Sstevel@tonic-gate #define	KADM5_MASTER "admin_server"
166656Ssemery #define	KADM5_KPASSWD "kpasswd_server"
170Sstevel@tonic-gate 
180Sstevel@tonic-gate /*
190Sstevel@tonic-gate  * Find the admin server for the given realm. If the realm is null or
200Sstevel@tonic-gate  * the empty string, find the admin server for the default realm.
210Sstevel@tonic-gate  * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to
220Sstevel@tonic-gate  * free the storage allocated to the admin server, master.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate kadm5_ret_t
kadm5_get_master(krb5_context context,const char * realm,char ** master)250Sstevel@tonic-gate kadm5_get_master(krb5_context context, const char *realm, char **master)
260Sstevel@tonic-gate {
2711490SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
2811490SMark.Phalan@Sun.COM 	char *def_realm = NULL;
2911490SMark.Phalan@Sun.COM 
300Sstevel@tonic-gate 	char *delim;
310Sstevel@tonic-gate #ifdef KRB5_DNS_LOOKUP
320Sstevel@tonic-gate 	struct sockaddr *addrs;
330Sstevel@tonic-gate 	int naddrs;
340Sstevel@tonic-gate 	unsigned short dns_portno;
350Sstevel@tonic-gate 	char dns_host[MAX_DNS_NAMELEN];
360Sstevel@tonic-gate 	krb5_data dns_realm;
370Sstevel@tonic-gate 	krb5_error_code dns_ret = 1;
380Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
390Sstevel@tonic-gate 
400Sstevel@tonic-gate 	if (realm == 0 || *realm == '\0')
410Sstevel@tonic-gate 		krb5_get_default_realm(context, &def_realm);
420Sstevel@tonic-gate 
430Sstevel@tonic-gate 	(void) profile_get_string(context->profile, "realms",
446426Smp153739 	    realm ? realm : def_realm,
456426Smp153739 	    KADM5_MASTER, 0, master);
460Sstevel@tonic-gate 
470Sstevel@tonic-gate 	if ((*master != NULL) && ((delim = strchr(*master, ':')) != NULL))
480Sstevel@tonic-gate 		*delim = '\0';
490Sstevel@tonic-gate #ifdef KRB5_DNS_LOOKUP
500Sstevel@tonic-gate 	if (*master == NULL) {
510Sstevel@tonic-gate 		/*
520Sstevel@tonic-gate 		 * Initialize realm info for (possible) DNS lookups.
530Sstevel@tonic-gate 		 */
540Sstevel@tonic-gate 		dns_realm.data = strdup(realm ? realm : def_realm);
550Sstevel@tonic-gate 		dns_realm.length = strlen(realm ? realm : def_realm);
560Sstevel@tonic-gate 		dns_realm.magic = 0;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate 		dns_ret = krb5_get_servername(context, &dns_realm,
596426Smp153739 		    "_kerberos-adm", "_udp",
606426Smp153739 		    dns_host, &dns_portno);
610Sstevel@tonic-gate 		if (dns_ret == 0)
620Sstevel@tonic-gate 			*master = strdup(dns_host);
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 		if (dns_realm.data)
650Sstevel@tonic-gate 			free(dns_realm.data);
660Sstevel@tonic-gate 	}
670Sstevel@tonic-gate #endif /* KRB5_DNS_LOOKUP */
6811490SMark.Phalan@Sun.COM 
6911490SMark.Phalan@Sun.COM 	/* Solaris Kerberos */
7011490SMark.Phalan@Sun.COM 	if (def_realm != NULL)
7111490SMark.Phalan@Sun.COM 		krb5_free_default_realm(context, def_realm);
7211490SMark.Phalan@Sun.COM 
730Sstevel@tonic-gate 	return (*master ? KADM5_OK : KADM5_NO_SRV);
740Sstevel@tonic-gate }
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /*
776656Ssemery  * Find the kpasswd server for the given realm. If the realm is null or
786656Ssemery  * the empty string, find the admin server for the default realm.
796656Ssemery  * Returns 0 on succsess (KADM5_OK). It is the callers responsibility to
806656Ssemery  * free the storage allocated to the admin server, master.
816656Ssemery  */
826656Ssemery kadm5_ret_t
kadm5_get_kpasswd(krb5_context context,const char * realm,char ** kpasswd)836656Ssemery kadm5_get_kpasswd(krb5_context context, const char *realm, char **kpasswd)
846656Ssemery {
856656Ssemery 	char *def_realm = NULL;
866656Ssemery 	char *delim;
876656Ssemery #ifdef KRB5_DNS_LOOKUP
886656Ssemery 	struct sockaddr *addrs;
896656Ssemery 	int naddrs;
906656Ssemery 	unsigned short dns_portno;
916656Ssemery 	char dns_host[MAX_DNS_NAMELEN];
926656Ssemery 	krb5_data dns_realm;
936656Ssemery 	krb5_error_code dns_ret = 1, ret;
946656Ssemery #endif /* KRB5_DNS_LOOKUP */
956656Ssemery 
966656Ssemery 	if (realm == 0 || *realm == '\0') {
976656Ssemery 		ret = krb5_get_default_realm(context, &def_realm);
986656Ssemery 		if (ret != 0)
996656Ssemery 			return (ret);
1006656Ssemery 	}
1016656Ssemery 
1026656Ssemery 	(void) profile_get_string(context->profile, "realms",
1036656Ssemery 	    realm ? realm : def_realm,
1046656Ssemery 	    KADM5_KPASSWD, 0, kpasswd);
1056656Ssemery 
1066656Ssemery 	if ((*kpasswd != NULL) && ((delim = strchr(*kpasswd, ':')) != NULL))
1076656Ssemery 		*delim = '\0';
1086656Ssemery #ifdef KRB5_DNS_LOOKUP
1096656Ssemery 	if (*kpasswd == NULL) {
1106656Ssemery 		/*
1116656Ssemery 		 * Initialize realm info for (possible) DNS lookups.
1126656Ssemery 		 */
1136656Ssemery 		dns_realm.data = strdup(realm ? realm : def_realm);
1146656Ssemery 		if (dns_realm.data == NULL) {
1156656Ssemery 			if (def_realm != NULL)
1166656Ssemery 				free(def_realm);
1176656Ssemery 			return (ENOMEM);
1186656Ssemery 		}
1196656Ssemery 		dns_realm.length = strlen(realm ? realm : def_realm);
1206656Ssemery 		dns_realm.magic = 0;
1216656Ssemery 
1226656Ssemery 		dns_ret = krb5_get_servername(context, &dns_realm,
1236656Ssemery 		    "_kpasswd", "_tcp",
1246656Ssemery 		    dns_host, &dns_portno);
1256656Ssemery 		if (dns_ret == 0) {
1266656Ssemery 			*kpasswd = strdup(dns_host);
1276656Ssemery 
1286656Ssemery 			if (*kpasswd == NULL) {
1296656Ssemery 				free(dns_realm.data);
1306656Ssemery 				if (def_realm != NULL)
1316656Ssemery 					free(def_realm);
1326656Ssemery 				return (ENOMEM);
1336656Ssemery 			}
1346656Ssemery 		}
1356656Ssemery 
1366656Ssemery 		free(dns_realm.data);
1376656Ssemery 	}
1386656Ssemery #endif /* KRB5_DNS_LOOKUP */
1396656Ssemery 
1406656Ssemery 	if (def_realm != NULL)
1416656Ssemery 		free(def_realm);
1426656Ssemery 	return (*kpasswd ? KADM5_OK : KADM5_NO_SRV);
1436656Ssemery }
1446656Ssemery 
1456656Ssemery /*
1460Sstevel@tonic-gate  * Get the host base service name for the admin principal. Returns
1470Sstevel@tonic-gate  * KADM5_OK on success. Caller must free the storage allocated for
1480Sstevel@tonic-gate  * host_service_name.
1490Sstevel@tonic-gate  */
1500Sstevel@tonic-gate kadm5_ret_t
kadm5_get_adm_host_srv_name(krb5_context context,const char * realm,char ** host_service_name)1510Sstevel@tonic-gate kadm5_get_adm_host_srv_name(krb5_context context,
1520Sstevel@tonic-gate 			    const char *realm, char **host_service_name)
1530Sstevel@tonic-gate {
1540Sstevel@tonic-gate 	kadm5_ret_t ret;
1550Sstevel@tonic-gate 	char *name;
1560Sstevel@tonic-gate 	char *host;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 	if (ret = kadm5_get_master(context, realm, &host))
1600Sstevel@tonic-gate 		return (ret);
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	name = malloc(strlen(KADM5_ADMIN_HOST_SERVICE)+ strlen(host) + 2);
1630Sstevel@tonic-gate 	if (name == NULL) {
1640Sstevel@tonic-gate 		free(host);
1650Sstevel@tonic-gate 		return (ENOMEM);
1660Sstevel@tonic-gate 	}
1670Sstevel@tonic-gate 	sprintf(name, "%s@%s", KADM5_ADMIN_HOST_SERVICE, host);
1680Sstevel@tonic-gate 	free(host);
1690Sstevel@tonic-gate 	*host_service_name = name;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	return (KADM5_OK);
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate /*
1750Sstevel@tonic-gate  * Get the host base service name for the changepw principal. Returns
1760Sstevel@tonic-gate  * KADM5_OK on success. Caller must free the storage allocated for
1770Sstevel@tonic-gate  * host_service_name.
1780Sstevel@tonic-gate  */
1790Sstevel@tonic-gate kadm5_ret_t
kadm5_get_cpw_host_srv_name(krb5_context context,const char * realm,char ** host_service_name)1800Sstevel@tonic-gate kadm5_get_cpw_host_srv_name(krb5_context context,
1810Sstevel@tonic-gate 			    const char *realm, char **host_service_name)
1820Sstevel@tonic-gate {
1830Sstevel@tonic-gate 	kadm5_ret_t ret;
1840Sstevel@tonic-gate 	char *name;
1850Sstevel@tonic-gate 	char *host;
1860Sstevel@tonic-gate 
1876656Ssemery 	/*
1886656Ssemery 	 * First try to find the kpasswd server, after all we are about to
1896656Ssemery 	 * try to change our password.  If this fails then try admin_server.
1906656Ssemery 	 */
1916656Ssemery 	if (ret = kadm5_get_kpasswd(context, realm, &host)) {
1926656Ssemery 		if (ret = kadm5_get_master(context, realm, &host))
1936656Ssemery 			return (ret);
1946656Ssemery 	}
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	name = malloc(strlen(KADM5_CHANGEPW_HOST_SERVICE) + strlen(host) + 2);
1970Sstevel@tonic-gate 	if (name == NULL) {
1980Sstevel@tonic-gate 		free(host);
1990Sstevel@tonic-gate 		return (ENOMEM);
2000Sstevel@tonic-gate 	}
2010Sstevel@tonic-gate 	sprintf(name, "%s@%s", KADM5_CHANGEPW_HOST_SERVICE, host);
2020Sstevel@tonic-gate 	free(host);
2030Sstevel@tonic-gate 	*host_service_name = name;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	return (KADM5_OK);
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate /*
2090Sstevel@tonic-gate  * Get the host base service name for the kiprop principal. Returns
2100Sstevel@tonic-gate  * KADM5_OK on success. Caller must free the storage allocated
2110Sstevel@tonic-gate  * for host_service_name.
2120Sstevel@tonic-gate  */
kadm5_get_kiprop_host_srv_name(krb5_context context,const char * realm,char ** host_service_name)2130Sstevel@tonic-gate kadm5_ret_t kadm5_get_kiprop_host_srv_name(krb5_context context,
2140Sstevel@tonic-gate 				    const char *realm,
2150Sstevel@tonic-gate 				    char **host_service_name) {
2160Sstevel@tonic-gate 	kadm5_ret_t ret;
2170Sstevel@tonic-gate 	char *name;
2180Sstevel@tonic-gate 	char *host;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	if (ret = kadm5_get_master(context, realm, &host))
2220Sstevel@tonic-gate 		return (ret);
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	name = malloc(strlen(KADM5_KIPROP_HOST_SERVICE) + strlen(host) + 2);
2250Sstevel@tonic-gate 	if (name == NULL) {
2260Sstevel@tonic-gate 		free(host);
2270Sstevel@tonic-gate 		return (ENOMEM);
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 	sprintf(name, "%s@%s", KADM5_KIPROP_HOST_SERVICE, host);
2300Sstevel@tonic-gate 	free(host);
2310Sstevel@tonic-gate 	*host_service_name = name;
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	return (KADM5_OK);
2340Sstevel@tonic-gate }
2356426Smp153739 
2366426Smp153739 /*
2376426Smp153739  * Solaris Kerberos:
2386426Smp153739  * Try to determine if this is the master KDC for a given realm
2396426Smp153739  */
kadm5_is_master(krb5_context context,const char * realm,krb5_boolean * is_master)2406426Smp153739 kadm5_ret_t kadm5_is_master(krb5_context context, const char *realm,
2416426Smp153739     krb5_boolean *is_master) {
2426426Smp153739 
2436426Smp153739 	kadm5_ret_t ret;
2446426Smp153739 	char *admin_host = NULL;
245*12361SMark.Phalan@Sun.COM 	krb5_address **tmp_addr, **master_addr = NULL;
2466426Smp153739 	krb5_address **local_addr = NULL;
2476426Smp153739 
2486426Smp153739 	if (is_master)
2496426Smp153739 		*is_master = FALSE;
2506426Smp153739 	else
2516426Smp153739 		return (KADM5_FAILURE);
2526426Smp153739 
2536426Smp153739 	/* Locate the master KDC */
2546426Smp153739 	if (ret = kadm5_get_master(context, realm, &admin_host))
2556426Smp153739 		return (ret);
2566426Smp153739 
2576426Smp153739 	if (ret = krb5_os_hostaddr(context, admin_host, &master_addr)) {
2586426Smp153739 		free(admin_host);
2596426Smp153739 		return (ret);
2606426Smp153739 	}
2616426Smp153739 
2626426Smp153739 	/* Get the local addresses */
2636426Smp153739 	if (ret = krb5_os_localaddr(context, &local_addr)) {
2646426Smp153739 		krb5_free_addresses(context, master_addr);
2656426Smp153739 		free(admin_host);
2666426Smp153739 		return (ret);
2676426Smp153739 	}
2686426Smp153739 
2696426Smp153739 	/* Compare them */
270*12361SMark.Phalan@Sun.COM 	for (tmp_addr = master_addr; *tmp_addr; tmp_addr++) {
271*12361SMark.Phalan@Sun.COM 		if (krb5_address_search(context, *tmp_addr, local_addr)) {
2726426Smp153739 			*is_master = TRUE;
2736426Smp153739 			break;
2746426Smp153739 		}
2756426Smp153739 	}
2766426Smp153739 
2776426Smp153739 	krb5_free_addresses(context, local_addr);
2786426Smp153739 	krb5_free_addresses(context, master_addr);
2796426Smp153739 	free(admin_host);
2806426Smp153739 
2816426Smp153739 	return (KADM5_OK);
2826426Smp153739 }
283