17c478bd9Sstevel@tonic-gate /*
25e01956fSGlenn Barry  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
37c478bd9Sstevel@tonic-gate  */
47c478bd9Sstevel@tonic-gate /*
57c478bd9Sstevel@tonic-gate  * lib/krb5/os/sn2princ.c
67c478bd9Sstevel@tonic-gate  *
7505d05c7Sgtb  * Copyright 1991,2002 by the Massachusetts Institute of Technology.
87c478bd9Sstevel@tonic-gate  * All Rights Reserved.
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
117c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
127c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
137c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
1455fea89dSDan Cross  *
157c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
167c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
177c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
187c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
197c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
207c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
217c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
227c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
237c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
247c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
257c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
267c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
277c478bd9Sstevel@tonic-gate  * or implied warranty.
2855fea89dSDan Cross  *
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * Convert a hostname and service name to a principal in the "standard"
317c478bd9Sstevel@tonic-gate  * form.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
34159d09a2SMark Phalan #include "k5-int.h"
35159d09a2SMark Phalan #include "os-proto.h"
36505d05c7Sgtb #include "fake-addrinfo.h"
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #ifdef HAVE_SYS_PARAM_H
397c478bd9Sstevel@tonic-gate #include <sys/param.h>
407c478bd9Sstevel@tonic-gate #endif
415e01956fSGlenn Barry #include <locale.h>
425e01956fSGlenn Barry #include <syslog.h>
437c478bd9Sstevel@tonic-gate 
44159d09a2SMark Phalan #if !defined(DEFAULT_RDNS_LOOKUP)
45159d09a2SMark Phalan /* Solaris Kerberos */
46159d09a2SMark Phalan #define DEFAULT_RDNS_LOOKUP 0
47159d09a2SMark Phalan #endif
48159d09a2SMark Phalan 
49fe598cdcSmp /*
50fe598cdcSmp  * Solaris Kerberos:
51fe598cdcSmp  * The following prototypes are needed because these are
527c478bd9Sstevel@tonic-gate  * private interfaces that do not have prototypes in any .h
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate extern struct hostent	*res_getipnodebyname(const char *, int, int, int *);
557c478bd9Sstevel@tonic-gate extern struct hostent	*res_getipnodebyaddr(const void *, size_t, int, int *);
567c478bd9Sstevel@tonic-gate extern void		res_freehostent(struct hostent *);
577c478bd9Sstevel@tonic-gate 
58159d09a2SMark Phalan static int
maybe_use_reverse_dns(krb5_context context,int def_val)59*9b622488SToomas Soome maybe_use_reverse_dns (krb5_context context, int def_val)
60159d09a2SMark Phalan {
61159d09a2SMark Phalan     krb5_error_code code;
62159d09a2SMark Phalan     char * value = NULL;
63159d09a2SMark Phalan     int use_rdns = 0;
64159d09a2SMark Phalan 
65159d09a2SMark Phalan     code = profile_get_string(context->profile, "libdefaults",
66159d09a2SMark Phalan                               "rdns", 0, 0, &value);
67159d09a2SMark Phalan     if (code)
68*9b622488SToomas Soome         return def_val;
69159d09a2SMark Phalan 
70159d09a2SMark Phalan     if (value == 0)
71*9b622488SToomas Soome 	return def_val;
72159d09a2SMark Phalan 
73159d09a2SMark Phalan     use_rdns = _krb5_conf_boolean(value);
74159d09a2SMark Phalan     profile_release_string(value);
75159d09a2SMark Phalan     return use_rdns;
76159d09a2SMark Phalan }
77159d09a2SMark Phalan 
78159d09a2SMark Phalan 
797c478bd9Sstevel@tonic-gate /*
80159d09a2SMark Phalan  * Solaris Kerberos:
817c478bd9Sstevel@tonic-gate  * Note, krb5_sname_to_principal() allocates memory for ret_princ.  Be sure to
827c478bd9Sstevel@tonic-gate  * use krb5_free_principal() on ret_princ to free it when done referencing it.
837c478bd9Sstevel@tonic-gate  */
84159d09a2SMark Phalan 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)85505d05c7Sgtb krb5_sname_to_principal(krb5_context context, const char *hostname, const char *sname, krb5_int32 type, krb5_principal *ret_princ)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate     char **hrealms, *realm, *remote_host;
887c478bd9Sstevel@tonic-gate     krb5_error_code retval;
897c478bd9Sstevel@tonic-gate     register char *cp;
907c478bd9Sstevel@tonic-gate     char localname[MAXHOSTNAMELEN];
91159d09a2SMark Phalan     /* Solaris Kerberos */
92159d09a2SMark Phalan     KRB5_LOG0(KRB5_INFO, "krb5_sname_to_principal() start");
93fe598cdcSmp #ifdef DEBUG_REFERRALS
94fe598cdcSmp     printf("krb5_sname_to_principal(host=%s, sname=%s, type=%d)\n",hostname,sname,type);
95fe598cdcSmp     printf("      name types: 0=unknown, 3=srv_host\n");
96fe598cdcSmp #endif
977c478bd9Sstevel@tonic-gate     if ((type == KRB5_NT_UNKNOWN) ||
987c478bd9Sstevel@tonic-gate 	(type == KRB5_NT_SRV_HST)) {
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	/* if hostname is NULL, use local hostname */
1017c478bd9Sstevel@tonic-gate 	if (! hostname) {
1027c478bd9Sstevel@tonic-gate 	    if (gethostname(localname, MAXHOSTNAMELEN)) {
103159d09a2SMark Phalan 		/* Solaris Kerberos */
1047c478bd9Sstevel@tonic-gate 		KRB5_LOG0(KRB5_ERR, "krb5_sname_to_principal()"
1057c478bd9Sstevel@tonic-gate 		       " gethostname failed");
1067c478bd9Sstevel@tonic-gate 		return SOCKET_ERRNO;
1077c478bd9Sstevel@tonic-gate 	    }
1087c478bd9Sstevel@tonic-gate 	    hostname = localname;
1097c478bd9Sstevel@tonic-gate 	}
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	/* if sname is NULL, use "host" */
1127c478bd9Sstevel@tonic-gate 	if (! sname)
1137c478bd9Sstevel@tonic-gate 	    sname = "host";
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	/* copy the hostname into non-volatile storage */
116159d09a2SMark Phalan 
1177c478bd9Sstevel@tonic-gate 	if (type == KRB5_NT_SRV_HST) {
118159d09a2SMark Phalan 	    /* Solaris Kerberos */
119159d09a2SMark Phalan 	    struct hostent *hp = NULL;
120159d09a2SMark Phalan 	    struct hostent *hp2 = NULL;
121159d09a2SMark Phalan 	    int err;
122159d09a2SMark Phalan 	    int addr_family;
123159d09a2SMark Phalan 
124159d09a2SMark Phalan 	    /* Note that the old code would accept numeric addresses,
125159d09a2SMark Phalan 	       and if the gethostbyaddr step could convert them to
126159d09a2SMark Phalan 	       real hostnames, you could actually get reasonable
127159d09a2SMark Phalan 	       results.  If the mapping failed, you'd get dotted
128159d09a2SMark Phalan 	       triples as realm names.  *sigh*
129159d09a2SMark Phalan 
130159d09a2SMark Phalan 	       The latter has been fixed in hst_realm.c, but we should
131159d09a2SMark Phalan 	       keep supporting numeric addresses if they do have
132159d09a2SMark Phalan 	       hostnames associated.  */
133159d09a2SMark Phalan 
134159d09a2SMark Phalan     /*
135159d09a2SMark Phalan      * Solaris kerberos: using res_getipnodebyname() to force dns name
136159d09a2SMark Phalan      * resolution.  Note, res_getaddrinfo() isn't exported by libreolv
137159d09a2SMark Phalan      * so we use res_getipnodebyname() (MIT uses getaddrinfo()).
138159d09a2SMark Phalan      */
139159d09a2SMark Phalan 	    KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal() hostname %s",
140159d09a2SMark Phalan 	       hostname);
141159d09a2SMark Phalan 
142159d09a2SMark Phalan 	    addr_family = AF_INET;
143159d09a2SMark Phalan 	try_getipnodebyname_again:
144159d09a2SMark Phalan 	    hp = res_getipnodebyname(hostname, addr_family, 0, &err);
145159d09a2SMark Phalan 	    if (!hp) {
146159d09a2SMark Phalan #ifdef DEBUG_REFERRALS
147159d09a2SMark Phalan 	        printf("sname_to_princ: probably punting due to bad hostname of %s\n",hostname);
1487c478bd9Sstevel@tonic-gate #endif
149159d09a2SMark Phalan 		if (addr_family == AF_INET) {
150159d09a2SMark Phalan 	    		KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal()"
151159d09a2SMark Phalan 			   " can't get AF_INET addr, err = %d", err);
152159d09a2SMark Phalan 		    /* Just in case it's an IPv6-only name.  */
153159d09a2SMark Phalan 		    addr_family = AF_INET6;
154159d09a2SMark Phalan 		    goto try_getipnodebyname_again;
155159d09a2SMark Phalan 		}
156159d09a2SMark Phalan 		KRB5_LOG(KRB5_ERR, "krb5_sname_to_principal()"
157159d09a2SMark Phalan 		       " can't get AF_INET or AF_INET6 addr,"
158159d09a2SMark Phalan 		       " err = %d", err);
1595e01956fSGlenn Barry 
1605e01956fSGlenn Barry 		krb5_set_error_message(context, KRB5_ERR_BAD_HOSTNAME,
1615e01956fSGlenn Barry 				    dgettext(TEXT_DOMAIN,
1625e01956fSGlenn Barry 					    "Hostname cannot be canonicalized for '%s': %s"),
1635e01956fSGlenn Barry 				    hostname, strerror(err));
164159d09a2SMark Phalan 		return KRB5_ERR_BAD_HOSTNAME;
165159d09a2SMark Phalan 	    }
166159d09a2SMark Phalan 	    remote_host = strdup(hp ? hp->h_name : hostname);
167159d09a2SMark Phalan 	    if (!remote_host) {
168159d09a2SMark Phalan 		if (hp != NULL)
169159d09a2SMark Phalan 		    res_freehostent(hp);
170159d09a2SMark Phalan 		return ENOMEM;
171159d09a2SMark Phalan 	    }
172159d09a2SMark Phalan 
173159d09a2SMark Phalan             if (maybe_use_reverse_dns(context, DEFAULT_RDNS_LOOKUP)) {
174159d09a2SMark Phalan                 /*
175159d09a2SMark Phalan                  * Do a reverse resolution to get the full name, just in
176159d09a2SMark Phalan                  * case there's some funny business going on.  If there
177159d09a2SMark Phalan                  * isn't an in-addr record, give up.
178159d09a2SMark Phalan                  */
179159d09a2SMark Phalan                 /* XXX: This is *so* bogus.  There are several cases where
180159d09a2SMark Phalan                    this won't get us the canonical name of the host, but
181159d09a2SMark Phalan                    this is what we've trained people to expect.  We'll
182159d09a2SMark Phalan                    probably fix it at some point, but let's try to
183159d09a2SMark Phalan                    preserve the current behavior and only shake things up
184159d09a2SMark Phalan                    once when it comes time to fix this lossage.  */
185159d09a2SMark Phalan                 hp2 = res_getipnodebyaddr(hp->h_addr, hp->h_length,
186159d09a2SMark Phalan                 			hp->h_addrtype, &err);
187159d09a2SMark Phalan 
188159d09a2SMark Phalan                 if (hp2 != NULL) {
189159d09a2SMark Phalan                     free(remote_host);
190159d09a2SMark Phalan                     remote_host = strdup(hp2->h_name);
191159d09a2SMark Phalan                     if (!remote_host) {
192159d09a2SMark Phalan                         res_freehostent(hp2);
193159d09a2SMark Phalan                         if (hp != NULL)
194159d09a2SMark Phalan                             res_freehostent(hp);
195159d09a2SMark Phalan                         return ENOMEM;
196159d09a2SMark Phalan                     }
197159d09a2SMark Phalan                     KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal() remote_host %s",
198159d09a2SMark Phalan                         remote_host);
199159d09a2SMark Phalan                 }
200159d09a2SMark Phalan             }
201159d09a2SMark Phalan 
202159d09a2SMark Phalan             if (hp != NULL) {
203159d09a2SMark Phalan                 res_freehostent(hp);
204159d09a2SMark Phalan             }
205159d09a2SMark Phalan 
206159d09a2SMark Phalan             if (hp2 != NULL) {
207159d09a2SMark Phalan 	        res_freehostent(hp2);
208159d09a2SMark Phalan             }
209159d09a2SMark Phalan 
2107c478bd9Sstevel@tonic-gate 	} else /* type == KRB5_NT_UNKNOWN */ {
211159d09a2SMark Phalan 	    remote_host = strdup(hostname);
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate 	if (!remote_host)
2147c478bd9Sstevel@tonic-gate 	    return ENOMEM;
215fe598cdcSmp #ifdef DEBUG_REFERRALS
216fe598cdcSmp  	printf("sname_to_princ: hostname <%s> after rdns processing\n",remote_host);
217fe598cdcSmp #endif
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (type == KRB5_NT_SRV_HST)
2207c478bd9Sstevel@tonic-gate 	    for (cp = remote_host; *cp; cp++)
221159d09a2SMark Phalan 		if (isupper((unsigned char) (*cp)))
222159d09a2SMark Phalan 		    *cp = tolower((unsigned char) (*cp));
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	/*
2257c478bd9Sstevel@tonic-gate 	 * Windows NT5's broken resolver gratuitously tacks on a
2267c478bd9Sstevel@tonic-gate 	 * trailing period to the hostname (at least it does in
2277c478bd9Sstevel@tonic-gate 	 * Beta2).  Find and remove it.
2287c478bd9Sstevel@tonic-gate 	 */
2297c478bd9Sstevel@tonic-gate 	if (remote_host[0]) {
230159d09a2SMark Phalan 		cp = remote_host + strlen(remote_host)-1;
231159d09a2SMark Phalan 		if (*cp == '.')
232159d09a2SMark Phalan 			*cp = 0;
2337c478bd9Sstevel@tonic-gate 	}
23455fea89dSDan Cross 
235159d09a2SMark Phalan 
236159d09a2SMark Phalan 	if ((retval = krb5_get_host_realm(context, remote_host, &hrealms))) {
2377c478bd9Sstevel@tonic-gate 	    free(remote_host);
2387c478bd9Sstevel@tonic-gate 	    return retval;
2397c478bd9Sstevel@tonic-gate 	}
240fe598cdcSmp 
241fe598cdcSmp #ifdef DEBUG_REFERRALS
242fe598cdcSmp 	printf("sname_to_princ:  realm <%s> after krb5_get_host_realm\n",hrealms[0]);
243fe598cdcSmp #endif
244fe598cdcSmp 
2457c478bd9Sstevel@tonic-gate 	if (!hrealms[0]) {
2465e01956fSGlenn Barry 	    /* Solaris Kerberos */
2475e01956fSGlenn Barry 	    krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN,
2485e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
2495e01956fSGlenn Barry 					"Cannot determine realm for host: host is '%s'"),
2505e01956fSGlenn Barry 				remote_host ? remote_host : "unknown");
2515e01956fSGlenn Barry 
2527c478bd9Sstevel@tonic-gate 	    free(remote_host);
2537c478bd9Sstevel@tonic-gate 	    krb5_xfree(hrealms);
2547c478bd9Sstevel@tonic-gate 	    return KRB5_ERR_HOST_REALM_UNKNOWN;
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 	realm = hrealms[0];
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	retval = krb5_build_principal(context, ret_princ, strlen(realm),
2597c478bd9Sstevel@tonic-gate 				      realm, sname, remote_host,
2607c478bd9Sstevel@tonic-gate 				      (char *)0);
2617c478bd9Sstevel@tonic-gate 
262bb294766SMark Phalan 	if (retval == 0)
263bb294766SMark Phalan 		krb5_princ_type(context, *ret_princ) = type;
2647c478bd9Sstevel@tonic-gate 
265fe598cdcSmp #ifdef DEBUG_REFERRALS
266fe598cdcSmp 	printf("krb5_sname_to_principal returning\n");
267fe598cdcSmp 	printf("realm: <%s>, sname: <%s>, remote_host: <%s>\n",
268fe598cdcSmp 	       realm,sname,remote_host);
269fe598cdcSmp 	krb5int_dbgref_dump_principal("krb5_sname_to_principal",*ret_princ);
270fe598cdcSmp #endif
271fe598cdcSmp 
2727c478bd9Sstevel@tonic-gate 	free(remote_host);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	krb5_free_host_realm(context, hrealms);
2757c478bd9Sstevel@tonic-gate 	return retval;
2767c478bd9Sstevel@tonic-gate     } else {
2777c478bd9Sstevel@tonic-gate 	return KRB5_SNAME_UNSUPP_NAMETYPE;
2787c478bd9Sstevel@tonic-gate     }
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate 
281