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