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