xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/os/def_realm.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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  */
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
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
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
275 krb5_free_default_realm(krb5_context context, char *lrealm)
276 {
277 	free (lrealm);
278 }
279