xref: /onnv-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/os/sn2princ.c (revision 13132:9615cdbf7b70)
10Sstevel@tonic-gate /*
2*13132SGlenn.Barry@oracle.com  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
30Sstevel@tonic-gate  */
40Sstevel@tonic-gate /*
50Sstevel@tonic-gate  * lib/krb5/os/sn2princ.c
60Sstevel@tonic-gate  *
7781Sgtb  * Copyright 1991,2002 by the Massachusetts Institute of Technology.
80Sstevel@tonic-gate  * All Rights Reserved.
90Sstevel@tonic-gate  *
100Sstevel@tonic-gate  * Export of this software from the United States of America may
110Sstevel@tonic-gate  *   require a specific license from the United States Government.
120Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
130Sstevel@tonic-gate  *   export to obtain such a license before exporting.
140Sstevel@tonic-gate  *
150Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
160Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
170Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
180Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
190Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
200Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
210Sstevel@tonic-gate  * to distribution of the software without specific, written prior
220Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
230Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
240Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
250Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
260Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
270Sstevel@tonic-gate  * or implied warranty.
280Sstevel@tonic-gate  *
290Sstevel@tonic-gate  *
300Sstevel@tonic-gate  * Convert a hostname and service name to a principal in the "standard"
310Sstevel@tonic-gate  * form.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
347934SMark.Phalan@Sun.COM #include "k5-int.h"
357934SMark.Phalan@Sun.COM #include "os-proto.h"
36781Sgtb #include "fake-addrinfo.h"
370Sstevel@tonic-gate #include <ctype.h>
380Sstevel@tonic-gate #ifdef HAVE_SYS_PARAM_H
390Sstevel@tonic-gate #include <sys/param.h>
400Sstevel@tonic-gate #endif
41*13132SGlenn.Barry@oracle.com #include <locale.h>
42*13132SGlenn.Barry@oracle.com #include <syslog.h>
430Sstevel@tonic-gate 
447934SMark.Phalan@Sun.COM #if !defined(DEFAULT_RDNS_LOOKUP)
457934SMark.Phalan@Sun.COM /* Solaris Kerberos */
467934SMark.Phalan@Sun.COM #define DEFAULT_RDNS_LOOKUP 0
477934SMark.Phalan@Sun.COM #endif
487934SMark.Phalan@Sun.COM 
494807Smp153739 /*
504807Smp153739  * Solaris Kerberos:
514807Smp153739  * The following prototypes are needed because these are
520Sstevel@tonic-gate  * private interfaces that do not have prototypes in any .h
530Sstevel@tonic-gate  */
540Sstevel@tonic-gate extern struct hostent	*res_getipnodebyname(const char *, int, int, int *);
550Sstevel@tonic-gate extern struct hostent	*res_getipnodebyaddr(const void *, size_t, int, int *);
560Sstevel@tonic-gate extern void		res_freehostent(struct hostent *);
570Sstevel@tonic-gate 
587934SMark.Phalan@Sun.COM static int
maybe_use_reverse_dns(krb5_context context,int defalt)597934SMark.Phalan@Sun.COM maybe_use_reverse_dns (krb5_context context, int defalt)
607934SMark.Phalan@Sun.COM {
617934SMark.Phalan@Sun.COM     krb5_error_code code;
627934SMark.Phalan@Sun.COM     char * value = NULL;
637934SMark.Phalan@Sun.COM     int use_rdns = 0;
647934SMark.Phalan@Sun.COM 
657934SMark.Phalan@Sun.COM     code = profile_get_string(context->profile, "libdefaults",
667934SMark.Phalan@Sun.COM                               "rdns", 0, 0, &value);
677934SMark.Phalan@Sun.COM     if (code)
687934SMark.Phalan@Sun.COM         return defalt;
697934SMark.Phalan@Sun.COM 
707934SMark.Phalan@Sun.COM     if (value == 0)
717934SMark.Phalan@Sun.COM 	return defalt;
727934SMark.Phalan@Sun.COM 
737934SMark.Phalan@Sun.COM     use_rdns = _krb5_conf_boolean(value);
747934SMark.Phalan@Sun.COM     profile_release_string(value);
757934SMark.Phalan@Sun.COM     return use_rdns;
767934SMark.Phalan@Sun.COM }
777934SMark.Phalan@Sun.COM 
787934SMark.Phalan@Sun.COM 
790Sstevel@tonic-gate /*
807934SMark.Phalan@Sun.COM  * Solaris Kerberos:
810Sstevel@tonic-gate  * Note, krb5_sname_to_principal() allocates memory for ret_princ.  Be sure to
820Sstevel@tonic-gate  * use krb5_free_principal() on ret_princ to free it when done referencing it.
830Sstevel@tonic-gate  */
847934SMark.Phalan@Sun.COM krb5_error_code KRB5_CALLCONV
krb5_sname_to_principal(krb5_context context,const char * hostname,const char * sname,krb5_int32 type,krb5_principal * ret_princ)85781Sgtb krb5_sname_to_principal(krb5_context context, const char *hostname, const char *sname, krb5_int32 type, krb5_principal *ret_princ)
860Sstevel@tonic-gate {
870Sstevel@tonic-gate     char **hrealms, *realm, *remote_host;
880Sstevel@tonic-gate     krb5_error_code retval;
890Sstevel@tonic-gate     register char *cp;
900Sstevel@tonic-gate     char localname[MAXHOSTNAMELEN];
917934SMark.Phalan@Sun.COM     /* Solaris Kerberos */
927934SMark.Phalan@Sun.COM     KRB5_LOG0(KRB5_INFO, "krb5_sname_to_principal() start");
934807Smp153739 #ifdef DEBUG_REFERRALS
944807Smp153739     printf("krb5_sname_to_principal(host=%s, sname=%s, type=%d)\n",hostname,sname,type);
954807Smp153739     printf("      name types: 0=unknown, 3=srv_host\n");
964807Smp153739 #endif
970Sstevel@tonic-gate     if ((type == KRB5_NT_UNKNOWN) ||
980Sstevel@tonic-gate 	(type == KRB5_NT_SRV_HST)) {
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	/* if hostname is NULL, use local hostname */
1010Sstevel@tonic-gate 	if (! hostname) {
1020Sstevel@tonic-gate 	    if (gethostname(localname, MAXHOSTNAMELEN)) {
1037934SMark.Phalan@Sun.COM 		/* Solaris Kerberos */
1040Sstevel@tonic-gate 		KRB5_LOG0(KRB5_ERR, "krb5_sname_to_principal()"
1050Sstevel@tonic-gate 		       " gethostname failed");
1060Sstevel@tonic-gate 		return SOCKET_ERRNO;
1070Sstevel@tonic-gate 	    }
1080Sstevel@tonic-gate 	    hostname = localname;
1090Sstevel@tonic-gate 	}
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	/* if sname is NULL, use "host" */
1120Sstevel@tonic-gate 	if (! sname)
1130Sstevel@tonic-gate 	    sname = "host";
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	/* copy the hostname into non-volatile storage */
1167934SMark.Phalan@Sun.COM 
1170Sstevel@tonic-gate 	if (type == KRB5_NT_SRV_HST) {
1187934SMark.Phalan@Sun.COM 	    /* Solaris Kerberos */
1197934SMark.Phalan@Sun.COM 	    struct hostent *hp = NULL;
1207934SMark.Phalan@Sun.COM 	    struct hostent *hp2 = NULL;
1217934SMark.Phalan@Sun.COM 	    int err;
1227934SMark.Phalan@Sun.COM 	    int addr_family;
1237934SMark.Phalan@Sun.COM 
1247934SMark.Phalan@Sun.COM 	    /* Note that the old code would accept numeric addresses,
1257934SMark.Phalan@Sun.COM 	       and if the gethostbyaddr step could convert them to
1267934SMark.Phalan@Sun.COM 	       real hostnames, you could actually get reasonable
1277934SMark.Phalan@Sun.COM 	       results.  If the mapping failed, you'd get dotted
1287934SMark.Phalan@Sun.COM 	       triples as realm names.  *sigh*
1297934SMark.Phalan@Sun.COM 
1307934SMark.Phalan@Sun.COM 	       The latter has been fixed in hst_realm.c, but we should
1317934SMark.Phalan@Sun.COM 	       keep supporting numeric addresses if they do have
1327934SMark.Phalan@Sun.COM 	       hostnames associated.  */
1337934SMark.Phalan@Sun.COM 
1347934SMark.Phalan@Sun.COM     /*
1357934SMark.Phalan@Sun.COM      * Solaris kerberos: using res_getipnodebyname() to force dns name
1367934SMark.Phalan@Sun.COM      * resolution.  Note, res_getaddrinfo() isn't exported by libreolv
1377934SMark.Phalan@Sun.COM      * so we use res_getipnodebyname() (MIT uses getaddrinfo()).
1387934SMark.Phalan@Sun.COM      */
1397934SMark.Phalan@Sun.COM 	    KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal() hostname %s",
1407934SMark.Phalan@Sun.COM 	       hostname);
1417934SMark.Phalan@Sun.COM 
1427934SMark.Phalan@Sun.COM 	    addr_family = AF_INET;
1437934SMark.Phalan@Sun.COM 	try_getipnodebyname_again:
1447934SMark.Phalan@Sun.COM 	    hp = res_getipnodebyname(hostname, addr_family, 0, &err);
1457934SMark.Phalan@Sun.COM 	    if (!hp) {
1467934SMark.Phalan@Sun.COM #ifdef DEBUG_REFERRALS
1477934SMark.Phalan@Sun.COM 	        printf("sname_to_princ: probably punting due to bad hostname of %s\n",hostname);
1480Sstevel@tonic-gate #endif
1497934SMark.Phalan@Sun.COM 		if (addr_family == AF_INET) {
1507934SMark.Phalan@Sun.COM 	    		KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal()"
1517934SMark.Phalan@Sun.COM 			   " can't get AF_INET addr, err = %d", err);
1527934SMark.Phalan@Sun.COM 		    /* Just in case it's an IPv6-only name.  */
1537934SMark.Phalan@Sun.COM 		    addr_family = AF_INET6;
1547934SMark.Phalan@Sun.COM 		    goto try_getipnodebyname_again;
1557934SMark.Phalan@Sun.COM 		}
1567934SMark.Phalan@Sun.COM 		KRB5_LOG(KRB5_ERR, "krb5_sname_to_principal()"
1577934SMark.Phalan@Sun.COM 		       " can't get AF_INET or AF_INET6 addr,"
1587934SMark.Phalan@Sun.COM 		       " err = %d", err);
159*13132SGlenn.Barry@oracle.com 
160*13132SGlenn.Barry@oracle.com 		krb5_set_error_message(context, KRB5_ERR_BAD_HOSTNAME,
161*13132SGlenn.Barry@oracle.com 				    dgettext(TEXT_DOMAIN,
162*13132SGlenn.Barry@oracle.com 					    "Hostname cannot be canonicalized for '%s': %s"),
163*13132SGlenn.Barry@oracle.com 				    hostname, strerror(err));
1647934SMark.Phalan@Sun.COM 		return KRB5_ERR_BAD_HOSTNAME;
1657934SMark.Phalan@Sun.COM 	    }
1667934SMark.Phalan@Sun.COM 	    remote_host = strdup(hp ? hp->h_name : hostname);
1677934SMark.Phalan@Sun.COM 	    if (!remote_host) {
1687934SMark.Phalan@Sun.COM 		if (hp != NULL)
1697934SMark.Phalan@Sun.COM 		    res_freehostent(hp);
1707934SMark.Phalan@Sun.COM 		return ENOMEM;
1717934SMark.Phalan@Sun.COM 	    }
1727934SMark.Phalan@Sun.COM 
1737934SMark.Phalan@Sun.COM             if (maybe_use_reverse_dns(context, DEFAULT_RDNS_LOOKUP)) {
1747934SMark.Phalan@Sun.COM                 /*
1757934SMark.Phalan@Sun.COM                  * Do a reverse resolution to get the full name, just in
1767934SMark.Phalan@Sun.COM                  * case there's some funny business going on.  If there
1777934SMark.Phalan@Sun.COM                  * isn't an in-addr record, give up.
1787934SMark.Phalan@Sun.COM                  */
1797934SMark.Phalan@Sun.COM                 /* XXX: This is *so* bogus.  There are several cases where
1807934SMark.Phalan@Sun.COM                    this won't get us the canonical name of the host, but
1817934SMark.Phalan@Sun.COM                    this is what we've trained people to expect.  We'll
1827934SMark.Phalan@Sun.COM                    probably fix it at some point, but let's try to
1837934SMark.Phalan@Sun.COM                    preserve the current behavior and only shake things up
1847934SMark.Phalan@Sun.COM                    once when it comes time to fix this lossage.  */
1857934SMark.Phalan@Sun.COM                 hp2 = res_getipnodebyaddr(hp->h_addr, hp->h_length,
1867934SMark.Phalan@Sun.COM                 			hp->h_addrtype, &err);
1877934SMark.Phalan@Sun.COM 
1887934SMark.Phalan@Sun.COM                 if (hp2 != NULL) {
1897934SMark.Phalan@Sun.COM                     free(remote_host);
1907934SMark.Phalan@Sun.COM                     remote_host = strdup(hp2->h_name);
1917934SMark.Phalan@Sun.COM                     if (!remote_host) {
1927934SMark.Phalan@Sun.COM                         res_freehostent(hp2);
1937934SMark.Phalan@Sun.COM                         if (hp != NULL)
1947934SMark.Phalan@Sun.COM                             res_freehostent(hp);
1957934SMark.Phalan@Sun.COM                         return ENOMEM;
1967934SMark.Phalan@Sun.COM                     }
1977934SMark.Phalan@Sun.COM                     KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal() remote_host %s",
1987934SMark.Phalan@Sun.COM                         remote_host);
1997934SMark.Phalan@Sun.COM                 }
2007934SMark.Phalan@Sun.COM             }
2017934SMark.Phalan@Sun.COM 
2027934SMark.Phalan@Sun.COM             if (hp != NULL) {
2037934SMark.Phalan@Sun.COM                 res_freehostent(hp);
2047934SMark.Phalan@Sun.COM             }
2057934SMark.Phalan@Sun.COM 
2067934SMark.Phalan@Sun.COM             if (hp2 != NULL) {
2077934SMark.Phalan@Sun.COM 	        res_freehostent(hp2);
2087934SMark.Phalan@Sun.COM             }
2097934SMark.Phalan@Sun.COM 
2100Sstevel@tonic-gate 	} else /* type == KRB5_NT_UNKNOWN */ {
2117934SMark.Phalan@Sun.COM 	    remote_host = strdup(hostname);
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 	if (!remote_host)
2140Sstevel@tonic-gate 	    return ENOMEM;
2154807Smp153739 #ifdef DEBUG_REFERRALS
2164807Smp153739  	printf("sname_to_princ: hostname <%s> after rdns processing\n",remote_host);
2174807Smp153739 #endif
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	if (type == KRB5_NT_SRV_HST)
2200Sstevel@tonic-gate 	    for (cp = remote_host; *cp; cp++)
2217934SMark.Phalan@Sun.COM 		if (isupper((unsigned char) (*cp)))
2227934SMark.Phalan@Sun.COM 		    *cp = tolower((unsigned char) (*cp));
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	/*
2250Sstevel@tonic-gate 	 * Windows NT5's broken resolver gratuitously tacks on a
2260Sstevel@tonic-gate 	 * trailing period to the hostname (at least it does in
2270Sstevel@tonic-gate 	 * Beta2).  Find and remove it.
2280Sstevel@tonic-gate 	 */
2290Sstevel@tonic-gate 	if (remote_host[0]) {
2307934SMark.Phalan@Sun.COM 		cp = remote_host + strlen(remote_host)-1;
2317934SMark.Phalan@Sun.COM 		if (*cp == '.')
2327934SMark.Phalan@Sun.COM 			*cp = 0;
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 
2357934SMark.Phalan@Sun.COM 
2367934SMark.Phalan@Sun.COM 	if ((retval = krb5_get_host_realm(context, remote_host, &hrealms))) {
2370Sstevel@tonic-gate 	    free(remote_host);
2380Sstevel@tonic-gate 	    return retval;
2390Sstevel@tonic-gate 	}
2404807Smp153739 
2414807Smp153739 #ifdef DEBUG_REFERRALS
2424807Smp153739 	printf("sname_to_princ:  realm <%s> after krb5_get_host_realm\n",hrealms[0]);
2434807Smp153739 #endif
2444807Smp153739 
2450Sstevel@tonic-gate 	if (!hrealms[0]) {
246*13132SGlenn.Barry@oracle.com 	    /* Solaris Kerberos */
247*13132SGlenn.Barry@oracle.com 	    krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN,
248*13132SGlenn.Barry@oracle.com 				dgettext(TEXT_DOMAIN,
249*13132SGlenn.Barry@oracle.com 					"Cannot determine realm for host: host is '%s'"),
250*13132SGlenn.Barry@oracle.com 				remote_host ? remote_host : "unknown");
251*13132SGlenn.Barry@oracle.com 
2520Sstevel@tonic-gate 	    free(remote_host);
2530Sstevel@tonic-gate 	    krb5_xfree(hrealms);
2540Sstevel@tonic-gate 	    return KRB5_ERR_HOST_REALM_UNKNOWN;
2550Sstevel@tonic-gate 	}
2560Sstevel@tonic-gate 	realm = hrealms[0];
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	retval = krb5_build_principal(context, ret_princ, strlen(realm),
2590Sstevel@tonic-gate 				      realm, sname, remote_host,
2600Sstevel@tonic-gate 				      (char *)0);
2610Sstevel@tonic-gate 
26211160SMark.Phalan@Sun.COM 	if (retval == 0)
26311160SMark.Phalan@Sun.COM 		krb5_princ_type(context, *ret_princ) = type;
2640Sstevel@tonic-gate 
2654807Smp153739 #ifdef DEBUG_REFERRALS
2664807Smp153739 	printf("krb5_sname_to_principal returning\n");
2674807Smp153739 	printf("realm: <%s>, sname: <%s>, remote_host: <%s>\n",
2684807Smp153739 	       realm,sname,remote_host);
2694807Smp153739 	krb5int_dbgref_dump_principal("krb5_sname_to_principal",*ret_princ);
2704807Smp153739 #endif
2714807Smp153739 
2720Sstevel@tonic-gate 	free(remote_host);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	krb5_free_host_realm(context, hrealms);
2750Sstevel@tonic-gate 	return retval;
2760Sstevel@tonic-gate     } else {
2770Sstevel@tonic-gate 	return KRB5_SNAME_UNSUPP_NAMETYPE;
2780Sstevel@tonic-gate     }
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate 
281