1 /*
2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * lib/krb5/os/sn2princ.c
6 *
7 * Copyright 1991,2002 by the Massachusetts Institute of Technology.
8 * All Rights Reserved.
9 *
10 * Export of this software from the United States of America may
11 * require a specific license from the United States Government.
12 * It is the responsibility of any person or organization contemplating
13 * export to obtain such a license before exporting.
14 *
15 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
16 * distribute this software and its documentation for any purpose and
17 * without fee is hereby granted, provided that the above copyright
18 * notice appear in all copies and that both that copyright notice and
19 * this permission notice appear in supporting documentation, and that
20 * the name of M.I.T. not be used in advertising or publicity pertaining
21 * to distribution of the software without specific, written prior
22 * permission. Furthermore if you modify this software you must label
23 * your software as modified software and not distribute it in such a
24 * fashion that it might be confused with the original M.I.T. software.
25 * M.I.T. makes no representations about the suitability of
26 * this software for any purpose. It is provided "as is" without express
27 * or implied warranty.
28 *
29 *
30 * Convert a hostname and service name to a principal in the "standard"
31 * form.
32 */
33
34 #include "k5-int.h"
35 #include "os-proto.h"
36 #include "fake-addrinfo.h"
37 #include <ctype.h>
38 #ifdef HAVE_SYS_PARAM_H
39 #include <sys/param.h>
40 #endif
41 #include <locale.h>
42 #include <syslog.h>
43
44 #if !defined(DEFAULT_RDNS_LOOKUP)
45 /* Solaris Kerberos */
46 #define DEFAULT_RDNS_LOOKUP 0
47 #endif
48
49 /*
50 * Solaris Kerberos:
51 * The following prototypes are needed because these are
52 * private interfaces that do not have prototypes in any .h
53 */
54 extern struct hostent *res_getipnodebyname(const char *, int, int, int *);
55 extern struct hostent *res_getipnodebyaddr(const void *, size_t, int, int *);
56 extern void res_freehostent(struct hostent *);
57
58 static int
maybe_use_reverse_dns(krb5_context context,int defalt)59 maybe_use_reverse_dns (krb5_context context, int defalt)
60 {
61 krb5_error_code code;
62 char * value = NULL;
63 int use_rdns = 0;
64
65 code = profile_get_string(context->profile, "libdefaults",
66 "rdns", 0, 0, &value);
67 if (code)
68 return defalt;
69
70 if (value == 0)
71 return defalt;
72
73 use_rdns = _krb5_conf_boolean(value);
74 profile_release_string(value);
75 return use_rdns;
76 }
77
78
79 /*
80 * Solaris Kerberos:
81 * Note, krb5_sname_to_principal() allocates memory for ret_princ. Be sure to
82 * use krb5_free_principal() on ret_princ to free it when done referencing it.
83 */
84 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)85 krb5_sname_to_principal(krb5_context context, const char *hostname, const char *sname, krb5_int32 type, krb5_principal *ret_princ)
86 {
87 char **hrealms, *realm, *remote_host;
88 krb5_error_code retval;
89 register char *cp;
90 char localname[MAXHOSTNAMELEN];
91 /* Solaris Kerberos */
92 KRB5_LOG0(KRB5_INFO, "krb5_sname_to_principal() start");
93 #ifdef DEBUG_REFERRALS
94 printf("krb5_sname_to_principal(host=%s, sname=%s, type=%d)\n",hostname,sname,type);
95 printf(" name types: 0=unknown, 3=srv_host\n");
96 #endif
97 if ((type == KRB5_NT_UNKNOWN) ||
98 (type == KRB5_NT_SRV_HST)) {
99
100 /* if hostname is NULL, use local hostname */
101 if (! hostname) {
102 if (gethostname(localname, MAXHOSTNAMELEN)) {
103 /* Solaris Kerberos */
104 KRB5_LOG0(KRB5_ERR, "krb5_sname_to_principal()"
105 " gethostname failed");
106 return SOCKET_ERRNO;
107 }
108 hostname = localname;
109 }
110
111 /* if sname is NULL, use "host" */
112 if (! sname)
113 sname = "host";
114
115 /* copy the hostname into non-volatile storage */
116
117 if (type == KRB5_NT_SRV_HST) {
118 /* Solaris Kerberos */
119 struct hostent *hp = NULL;
120 struct hostent *hp2 = NULL;
121 int err;
122 int addr_family;
123
124 /* Note that the old code would accept numeric addresses,
125 and if the gethostbyaddr step could convert them to
126 real hostnames, you could actually get reasonable
127 results. If the mapping failed, you'd get dotted
128 triples as realm names. *sigh*
129
130 The latter has been fixed in hst_realm.c, but we should
131 keep supporting numeric addresses if they do have
132 hostnames associated. */
133
134 /*
135 * Solaris kerberos: using res_getipnodebyname() to force dns name
136 * resolution. Note, res_getaddrinfo() isn't exported by libreolv
137 * so we use res_getipnodebyname() (MIT uses getaddrinfo()).
138 */
139 KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal() hostname %s",
140 hostname);
141
142 addr_family = AF_INET;
143 try_getipnodebyname_again:
144 hp = res_getipnodebyname(hostname, addr_family, 0, &err);
145 if (!hp) {
146 #ifdef DEBUG_REFERRALS
147 printf("sname_to_princ: probably punting due to bad hostname of %s\n",hostname);
148 #endif
149 if (addr_family == AF_INET) {
150 KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal()"
151 " can't get AF_INET addr, err = %d", err);
152 /* Just in case it's an IPv6-only name. */
153 addr_family = AF_INET6;
154 goto try_getipnodebyname_again;
155 }
156 KRB5_LOG(KRB5_ERR, "krb5_sname_to_principal()"
157 " can't get AF_INET or AF_INET6 addr,"
158 " err = %d", err);
159
160 krb5_set_error_message(context, KRB5_ERR_BAD_HOSTNAME,
161 dgettext(TEXT_DOMAIN,
162 "Hostname cannot be canonicalized for '%s': %s"),
163 hostname, strerror(err));
164 return KRB5_ERR_BAD_HOSTNAME;
165 }
166 remote_host = strdup(hp ? hp->h_name : hostname);
167 if (!remote_host) {
168 if (hp != NULL)
169 res_freehostent(hp);
170 return ENOMEM;
171 }
172
173 if (maybe_use_reverse_dns(context, DEFAULT_RDNS_LOOKUP)) {
174 /*
175 * Do a reverse resolution to get the full name, just in
176 * case there's some funny business going on. If there
177 * isn't an in-addr record, give up.
178 */
179 /* XXX: This is *so* bogus. There are several cases where
180 this won't get us the canonical name of the host, but
181 this is what we've trained people to expect. We'll
182 probably fix it at some point, but let's try to
183 preserve the current behavior and only shake things up
184 once when it comes time to fix this lossage. */
185 hp2 = res_getipnodebyaddr(hp->h_addr, hp->h_length,
186 hp->h_addrtype, &err);
187
188 if (hp2 != NULL) {
189 free(remote_host);
190 remote_host = strdup(hp2->h_name);
191 if (!remote_host) {
192 res_freehostent(hp2);
193 if (hp != NULL)
194 res_freehostent(hp);
195 return ENOMEM;
196 }
197 KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal() remote_host %s",
198 remote_host);
199 }
200 }
201
202 if (hp != NULL) {
203 res_freehostent(hp);
204 }
205
206 if (hp2 != NULL) {
207 res_freehostent(hp2);
208 }
209
210 } else /* type == KRB5_NT_UNKNOWN */ {
211 remote_host = strdup(hostname);
212 }
213 if (!remote_host)
214 return ENOMEM;
215 #ifdef DEBUG_REFERRALS
216 printf("sname_to_princ: hostname <%s> after rdns processing\n",remote_host);
217 #endif
218
219 if (type == KRB5_NT_SRV_HST)
220 for (cp = remote_host; *cp; cp++)
221 if (isupper((unsigned char) (*cp)))
222 *cp = tolower((unsigned char) (*cp));
223
224 /*
225 * Windows NT5's broken resolver gratuitously tacks on a
226 * trailing period to the hostname (at least it does in
227 * Beta2). Find and remove it.
228 */
229 if (remote_host[0]) {
230 cp = remote_host + strlen(remote_host)-1;
231 if (*cp == '.')
232 *cp = 0;
233 }
234
235
236 if ((retval = krb5_get_host_realm(context, remote_host, &hrealms))) {
237 free(remote_host);
238 return retval;
239 }
240
241 #ifdef DEBUG_REFERRALS
242 printf("sname_to_princ: realm <%s> after krb5_get_host_realm\n",hrealms[0]);
243 #endif
244
245 if (!hrealms[0]) {
246 /* Solaris Kerberos */
247 krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN,
248 dgettext(TEXT_DOMAIN,
249 "Cannot determine realm for host: host is '%s'"),
250 remote_host ? remote_host : "unknown");
251
252 free(remote_host);
253 krb5_xfree(hrealms);
254 return KRB5_ERR_HOST_REALM_UNKNOWN;
255 }
256 realm = hrealms[0];
257
258 retval = krb5_build_principal(context, ret_princ, strlen(realm),
259 realm, sname, remote_host,
260 (char *)0);
261
262 if (retval == 0)
263 krb5_princ_type(context, *ret_princ) = type;
264
265 #ifdef DEBUG_REFERRALS
266 printf("krb5_sname_to_principal returning\n");
267 printf("realm: <%s>, sname: <%s>, remote_host: <%s>\n",
268 realm,sname,remote_host);
269 krb5int_dbgref_dump_principal("krb5_sname_to_principal",*ret_princ);
270 #endif
271
272 free(remote_host);
273
274 krb5_free_host_realm(context, hrealms);
275 return retval;
276 } else {
277 return KRB5_SNAME_UNSUPP_NAMETYPE;
278 }
279 }
280
281