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