xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/os/def_realm.c (revision c3d26abc9ee97b4f60233556aadeb57e0bd30bb9)
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  */
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
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
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
291 krb5_free_default_realm(krb5_context context, char *lrealm)
292 {
293 	free (lrealm);
294 }
295