xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/os/def_realm.c (revision 7800901e60d340b6af88e94a2149805dcfcaaf56)
1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2 
3 /*
4  * lib/krb5/os/def_realm.c
5  *
6  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
7  * All Rights Reserved.
8  *
9  * Export of this software from the United States of America may
10  *   require a specific license from the United States Government.
11  *   It is the responsibility of any person or organization contemplating
12  *   export to obtain such a license before exporting.
13  *
14  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
15  * distribute this software and its documentation for any purpose and
16  * without fee is hereby granted, provided that the above copyright
17  * notice appear in all copies and that both that copyright notice and
18  * this permission notice appear in supporting documentation, and that
19  * the name of M.I.T. not be used in advertising or publicity pertaining
20  * to distribution of the software without specific, written prior
21  * permission.  Furthermore if you modify this software you must label
22  * your software as modified software and not distribute it in such a
23  * fashion that it might be confused with the original M.I.T. software.
24  * M.I.T. makes no representations about the suitability of
25  * this software for any purpose.  It is provided "as is" without express
26  * or implied warranty.
27  *
28  *
29  * krb5_get_default_realm(), krb5_set_default_realm(),
30  * krb5_free_default_realm() functions.
31  */
32 
33 /*
34  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
35  * Use is subject to license terms.
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     if (!context->default_realm) {
144         context->default_realm = 0;
145         if (context->profile != 0) {
146             retval = profile_get_string(context->profile, "libdefaults",
147                                         "default_realm", 0, 0,
148                                         &realm);
149 
150             if (!retval && realm) {
151                 context->default_realm = malloc(strlen(realm) + 1);
152                 if (!context->default_realm) {
153                     profile_release_string(realm);
154                     return ENOMEM;
155                 }
156                 strcpy(context->default_realm, realm);
157                 profile_release_string(realm);
158             }
159         }
160         if (context->default_realm == 0) {
161 #ifdef KRB5_DNS_LOOKUP
162             if (_krb5_use_dns_realm(context)) {
163 		/*
164 		 * Since this didn't appear in our config file, try looking
165 		 * it up via DNS.  Look for a TXT records of the form:
166 		 *
167 		 * _kerberos.<localhost>
168 		 * _kerberos.<domainname>
169 		 * _kerberos.<searchlist>
170 		 *
171 		 */
172 		char * p;
173 		krb5int_get_fq_local_hostname (localhost, sizeof(localhost));
174 
175 		if ( localhost[0] ) {
176 		    p = localhost;
177 		    do {
178 			retval = krb5_try_realm_txt_rr("_kerberos", p,
179 						       &context->default_realm);
180 			p = strchr(p,'.');
181 			if (p)
182 			    p++;
183 		    } while (retval && p && p[0]);
184 
185 		    if (retval)
186 			retval = krb5_try_realm_txt_rr("_kerberos", "",
187 						       &context->default_realm);
188 		} else {
189 		    retval = krb5_try_realm_txt_rr("_kerberos", "",
190 						   &context->default_realm);
191 		}
192 		if (retval) {
193 		    return(KRB5_CONFIG_NODEFREALM);
194 		}
195             } else
196 #endif /* KRB5_DNS_LOOKUP */
197              {
198 
199 	/*
200 	 * Solaris Kerberos:
201 	 * Try to find a realm based on one of the local IP addresses
202 	 */
203 	(void) krb5int_foreach_localaddr(context,
204 	    krb5int_address_get_realm, 0, 0);
205 
206 	/*
207 	 * Solaris Kerberos:
208 	 * As a final fallback try to find a realm based on the resolver search
209 	 * list
210 	 */
211 	if (context->default_realm == 0) {
212 		struct __res_state res;
213 		int i;
214 
215 		(void) memset(&res, 0, sizeof (res));
216 
217 		if (res_ninit(&res) == 0) {
218 			for (i = 0; res.dnsrch[i]; i++) {
219 				krb5int_domain_get_realm(context,
220 				    res.dnsrch[i], &context->default_realm);
221 
222 				if (context->default_realm != 0)
223 					break;
224 			}
225 		res_ndestroy(&res);
226 		}
227 	}
228 
229 	}
230 	}
231 	}
232 
233     if (context->default_realm == 0)
234 	return(KRB5_CONFIG_NODEFREALM);
235     if (context->default_realm[0] == 0) {
236         free (context->default_realm);
237         context->default_realm = 0;
238         return KRB5_CONFIG_NODEFREALM;
239     }
240 
241     realm = context->default_realm;
242 
243     /*LINTED*/
244     if (!(*lrealm = cp = malloc((unsigned int) strlen(realm) + 1)))
245         return ENOMEM;
246     strcpy(cp, realm);
247     return(0);
248 }
249 
250 krb5_error_code KRB5_CALLCONV
251 krb5_set_default_realm(krb5_context context, const char *lrealm)
252 {
253     if (!context || (context->magic != KV5M_CONTEXT))
254 	    return KV5M_CONTEXT;
255 
256     if (context->default_realm) {
257 	    free(context->default_realm);
258 	    context->default_realm = 0;
259     }
260 
261     /* Allow the user to clear the default realm setting by passing in
262        NULL */
263     if (!lrealm) return 0;
264 
265     context->default_realm = malloc(strlen (lrealm) + 1);
266 
267     if (!context->default_realm)
268 	    return ENOMEM;
269 
270     strcpy(context->default_realm, lrealm);
271     return(0);
272 
273 }
274 
275 /*ARGSUSED*/
276 void KRB5_CALLCONV
277 krb5_free_default_realm(krb5_context context, char *lrealm)
278 {
279 	free (lrealm);
280 }
281