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