1 /*
2 * lib/krb5/os/def_realm.c
3 *
4 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 *
26 *
27 * krb5_get_default_realm(), krb5_set_default_realm(),
28 * krb5_free_default_realm() functions.
29 */
30
31 /*
32 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
33 * Use is subject to license terms.
34 *
35 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
36 */
37
38 #include "k5-int.h"
39 #include "os-proto.h"
40 #include <stdio.h>
41
42 /*
43 * Solaris Kerberos:
44 * For krb5int_foreach_localaddr()
45 */
46 #include "foreachaddr.h"
47
48 #ifdef KRB5_DNS_LOOKUP
49 #ifdef WSHELPER
50 #include <wshelper.h>
51 #else /* WSHELPER */
52 #ifdef HAVE_NETINET_IN_H
53 #include <netinet/in.h>
54 #endif
55 #include <arpa/inet.h>
56 #include <arpa/nameser.h>
57 #include <resolv.h>
58 #include <netdb.h>
59 #endif /* WSHELPER */
60
61 /* for old Unixes and friends ... */
62 #ifndef MAXHOSTNAMELEN
63 #define MAXHOSTNAMELEN 64
64 #endif
65
66 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
67
68 #endif /* KRB5_DNS_LOOKUP */
69
70 /*
71 * Solaris Kerberos:
72 * The following prototype is needed because it is a
73 * private interface that does not have a prototype in any .h
74 */
75 extern struct hostent *res_gethostbyaddr(const char *addr, int len, int type);
76
77 /*
78 * Solaris Kerberos:
79 * krb5int_address_get_realm() given an address (either IPv4 or IPv6) tries to
80 * find a realm based on the DNS name of that address. Assumes that its being
81 * used as a callback for krb5int_foreach_localaddr().
82 */
krb5int_address_get_realm(void * data,struct sockaddr * addr)83 static int krb5int_address_get_realm(void *data, struct sockaddr *addr) {
84
85 krb5_context context = data;
86 struct hostent *he = NULL;
87
88 switch (addr->sa_family) {
89 case AF_INET:
90 he = res_gethostbyaddr((char*)(&sa2sin(addr)->sin_addr),
91 sizeof(sa2sin(addr)->sin_addr), AF_INET);
92 break;
93 case AF_INET6:
94 he = res_gethostbyaddr(
95 (char*)(&sa2sin6(addr)->sin6_addr),
96 sizeof(sa2sin6(addr)->sin6_addr), AF_INET6);
97 break;
98 }
99
100 if (he) {
101 /* Try to find realm using returned DNS name */
102 krb5int_fqdn_get_realm(context, he->h_name,
103 &context->default_realm);
104
105 /* If a realm was found return 1 to immediately halt
106 * krb5int_foreach_localaddr()
107 */
108 if (context->default_realm != 0) {
109 return (1);
110 }
111 }
112 return (0);
113 }
114
115
116 /*
117 * Retrieves the default realm to be used if no user-specified realm is
118 * available. [e.g. to interpret a user-typed principal name with the
119 * realm omitted for convenience]
120 *
121 * returns system errors, NOT_ENOUGH_SPACE, KV5M_CONTEXT
122 */
123
124 /*
125 * Implementation: the default realm is stored in a configuration file,
126 * named by krb5_config_file; the first token in this file is taken as
127 * the default local realm name.
128 */
129
130 krb5_error_code KRB5_CALLCONV
krb5_get_default_realm(krb5_context context,char ** lrealm)131 krb5_get_default_realm(krb5_context context, char **lrealm)
132 {
133 char *realm = 0;
134 char *cp;
135 char localhost[MAX_DNS_NAMELEN+1];
136 krb5_error_code retval;
137
138 (void) memset(localhost, 0, sizeof(localhost));
139
140 if (!context || (context->magic != KV5M_CONTEXT))
141 return KV5M_CONTEXT;
142
143 /*
144 * Solaris Kerberos: (illumos)
145 * Another way to provide the default realm.
146 */
147 if (!context->default_realm) {
148 if ((realm = getenv("KRB5_DEFAULT_REALM")) != NULL) {
149 context->default_realm = strdup(realm);
150 if (context->default_realm == NULL)
151 return ENOMEM;
152 }
153 }
154
155 if (!context->default_realm) {
156 context->default_realm = 0;
157 if (context->profile != 0) {
158 retval = profile_get_string(context->profile, "libdefaults",
159 "default_realm", 0, 0,
160 &realm);
161
162 if (!retval && realm) {
163 context->default_realm = malloc(strlen(realm) + 1);
164 if (!context->default_realm) {
165 profile_release_string(realm);
166 return ENOMEM;
167 }
168 strcpy(context->default_realm, realm);
169 profile_release_string(realm);
170 }
171 }
172 if (context->default_realm == 0) {
173 #ifdef KRB5_DNS_LOOKUP
174 if (_krb5_use_dns_realm(context)) {
175 /*
176 * Since this didn't appear in our config file, try looking
177 * it up via DNS. Look for a TXT records of the form:
178 *
179 * _kerberos.<localhost>
180 * _kerberos.<domainname>
181 * _kerberos.<searchlist>
182 *
183 */
184 char * p;
185 krb5int_get_fq_local_hostname (localhost, sizeof(localhost));
186
187 if ( localhost[0] ) {
188 p = localhost;
189 do {
190 retval = krb5_try_realm_txt_rr("_kerberos", p,
191 &context->default_realm);
192 p = strchr(p,'.');
193 if (p)
194 p++;
195 } while (retval && p && p[0]);
196
197 if (retval)
198 retval = krb5_try_realm_txt_rr("_kerberos", "",
199 &context->default_realm);
200 } else {
201 retval = krb5_try_realm_txt_rr("_kerberos", "",
202 &context->default_realm);
203 }
204 if (retval) {
205 return(KRB5_CONFIG_NODEFREALM);
206 }
207 } else
208 #endif /* KRB5_DNS_LOOKUP */
209 if (getenv("MS_INTEROP") == NULL) {
210
211 /*
212 * Solaris Kerberos:
213 * Try to find a realm based on one of the local IP addresses.
214 * Don't do this for AD, which often does _not_ support any
215 * DNS reverse lookup, making these queries take forever.
216 */
217 (void) krb5int_foreach_localaddr(context,
218 krb5int_address_get_realm, 0, 0);
219
220 /*
221 * Solaris Kerberos:
222 * As a final fallback try to find a realm based on the resolver search
223 * list
224 */
225 if (context->default_realm == 0) {
226 struct __res_state res;
227 int i;
228
229 (void) memset(&res, 0, sizeof (res));
230
231 if (res_ninit(&res) == 0) {
232 for (i = 0; res.dnsrch[i]; i++) {
233 krb5int_domain_get_realm(context,
234 res.dnsrch[i], &context->default_realm);
235
236 if (context->default_realm != 0)
237 break;
238 }
239 res_ndestroy(&res);
240 }
241 }
242
243 }
244 }
245 }
246
247 if (context->default_realm == 0)
248 return(KRB5_CONFIG_NODEFREALM);
249 if (context->default_realm[0] == 0) {
250 free (context->default_realm);
251 context->default_realm = 0;
252 return KRB5_CONFIG_NODEFREALM;
253 }
254
255 realm = context->default_realm;
256
257 /*LINTED*/
258 if (!(*lrealm = cp = malloc((unsigned int) strlen(realm) + 1)))
259 return ENOMEM;
260 strcpy(cp, realm);
261 return(0);
262 }
263
264 krb5_error_code KRB5_CALLCONV
krb5_set_default_realm(krb5_context context,const char * lrealm)265 krb5_set_default_realm(krb5_context context, const char *lrealm)
266 {
267 if (!context || (context->magic != KV5M_CONTEXT))
268 return KV5M_CONTEXT;
269
270 if (context->default_realm) {
271 free(context->default_realm);
272 context->default_realm = 0;
273 }
274
275 /* Allow the user to clear the default realm setting by passing in
276 NULL */
277 if (!lrealm) return 0;
278
279 context->default_realm = malloc(strlen (lrealm) + 1);
280
281 if (!context->default_realm)
282 return ENOMEM;
283
284 strcpy(context->default_realm, lrealm);
285 return(0);
286
287 }
288
289 /*ARGSUSED*/
290 void KRB5_CALLCONV
krb5_free_default_realm(krb5_context context,char * lrealm)291 krb5_free_default_realm(krb5_context context, char *lrealm)
292 {
293 free (lrealm);
294 }
295