1 /* 2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * lib/krb5/os/sn2princ.c 6 * 7 * Copyright 1991,2002 by the Massachusetts Institute of Technology. 8 * All Rights Reserved. 9 * 10 * Export of this software from the United States of America may 11 * require a specific license from the United States Government. 12 * It is the responsibility of any person or organization contemplating 13 * export to obtain such a license before exporting. 14 * 15 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 16 * distribute this software and its documentation for any purpose and 17 * without fee is hereby granted, provided that the above copyright 18 * notice appear in all copies and that both that copyright notice and 19 * this permission notice appear in supporting documentation, and that 20 * the name of M.I.T. not be used in advertising or publicity pertaining 21 * to distribution of the software without specific, written prior 22 * permission. Furthermore if you modify this software you must label 23 * your software as modified software and not distribute it in such a 24 * fashion that it might be confused with the original M.I.T. software. 25 * M.I.T. makes no representations about the suitability of 26 * this software for any purpose. It is provided "as is" without express 27 * or implied warranty. 28 * 29 * 30 * Convert a hostname and service name to a principal in the "standard" 31 * form. 32 */ 33 34 #include "k5-int.h" 35 #include "os-proto.h" 36 #include "fake-addrinfo.h" 37 #include <ctype.h> 38 #ifdef HAVE_SYS_PARAM_H 39 #include <sys/param.h> 40 #endif 41 #include <locale.h> 42 #include <syslog.h> 43 44 #if !defined(DEFAULT_RDNS_LOOKUP) 45 /* Solaris Kerberos */ 46 #define DEFAULT_RDNS_LOOKUP 0 47 #endif 48 49 /* 50 * Solaris Kerberos: 51 * The following prototypes are needed because these are 52 * private interfaces that do not have prototypes in any .h 53 */ 54 extern struct hostent *res_getipnodebyname(const char *, int, int, int *); 55 extern struct hostent *res_getipnodebyaddr(const void *, size_t, int, int *); 56 extern void res_freehostent(struct hostent *); 57 58 static int 59 maybe_use_reverse_dns (krb5_context context, int defalt) 60 { 61 krb5_error_code code; 62 char * value = NULL; 63 int use_rdns = 0; 64 65 code = profile_get_string(context->profile, "libdefaults", 66 "rdns", 0, 0, &value); 67 if (code) 68 return defalt; 69 70 if (value == 0) 71 return defalt; 72 73 use_rdns = _krb5_conf_boolean(value); 74 profile_release_string(value); 75 return use_rdns; 76 } 77 78 79 /* 80 * Solaris Kerberos: 81 * Note, krb5_sname_to_principal() allocates memory for ret_princ. Be sure to 82 * use krb5_free_principal() on ret_princ to free it when done referencing it. 83 */ 84 krb5_error_code KRB5_CALLCONV 85 krb5_sname_to_principal(krb5_context context, const char *hostname, const char *sname, krb5_int32 type, krb5_principal *ret_princ) 86 { 87 char **hrealms, *realm, *remote_host; 88 krb5_error_code retval; 89 register char *cp; 90 char localname[MAXHOSTNAMELEN]; 91 /* Solaris Kerberos */ 92 KRB5_LOG0(KRB5_INFO, "krb5_sname_to_principal() start"); 93 #ifdef DEBUG_REFERRALS 94 printf("krb5_sname_to_principal(host=%s, sname=%s, type=%d)\n",hostname,sname,type); 95 printf(" name types: 0=unknown, 3=srv_host\n"); 96 #endif 97 if ((type == KRB5_NT_UNKNOWN) || 98 (type == KRB5_NT_SRV_HST)) { 99 100 /* if hostname is NULL, use local hostname */ 101 if (! hostname) { 102 if (gethostname(localname, MAXHOSTNAMELEN)) { 103 /* Solaris Kerberos */ 104 KRB5_LOG0(KRB5_ERR, "krb5_sname_to_principal()" 105 " gethostname failed"); 106 return SOCKET_ERRNO; 107 } 108 hostname = localname; 109 } 110 111 /* if sname is NULL, use "host" */ 112 if (! sname) 113 sname = "host"; 114 115 /* copy the hostname into non-volatile storage */ 116 117 if (type == KRB5_NT_SRV_HST) { 118 /* Solaris Kerberos */ 119 struct hostent *hp = NULL; 120 struct hostent *hp2 = NULL; 121 int err; 122 int addr_family; 123 124 /* Note that the old code would accept numeric addresses, 125 and if the gethostbyaddr step could convert them to 126 real hostnames, you could actually get reasonable 127 results. If the mapping failed, you'd get dotted 128 triples as realm names. *sigh* 129 130 The latter has been fixed in hst_realm.c, but we should 131 keep supporting numeric addresses if they do have 132 hostnames associated. */ 133 134 /* 135 * Solaris kerberos: using res_getipnodebyname() to force dns name 136 * resolution. Note, res_getaddrinfo() isn't exported by libreolv 137 * so we use res_getipnodebyname() (MIT uses getaddrinfo()). 138 */ 139 KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal() hostname %s", 140 hostname); 141 142 addr_family = AF_INET; 143 try_getipnodebyname_again: 144 hp = res_getipnodebyname(hostname, addr_family, 0, &err); 145 if (!hp) { 146 #ifdef DEBUG_REFERRALS 147 printf("sname_to_princ: probably punting due to bad hostname of %s\n",hostname); 148 #endif 149 if (addr_family == AF_INET) { 150 KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal()" 151 " can't get AF_INET addr, err = %d", err); 152 /* Just in case it's an IPv6-only name. */ 153 addr_family = AF_INET6; 154 goto try_getipnodebyname_again; 155 } 156 KRB5_LOG(KRB5_ERR, "krb5_sname_to_principal()" 157 " can't get AF_INET or AF_INET6 addr," 158 " err = %d", err); 159 160 krb5_set_error_message(context, KRB5_ERR_BAD_HOSTNAME, 161 dgettext(TEXT_DOMAIN, 162 "Hostname cannot be canonicalized for '%s': %s"), 163 hostname, strerror(err)); 164 return KRB5_ERR_BAD_HOSTNAME; 165 } 166 remote_host = strdup(hp ? hp->h_name : hostname); 167 if (!remote_host) { 168 if (hp != NULL) 169 res_freehostent(hp); 170 return ENOMEM; 171 } 172 173 if (maybe_use_reverse_dns(context, DEFAULT_RDNS_LOOKUP)) { 174 /* 175 * Do a reverse resolution to get the full name, just in 176 * case there's some funny business going on. If there 177 * isn't an in-addr record, give up. 178 */ 179 /* XXX: This is *so* bogus. There are several cases where 180 this won't get us the canonical name of the host, but 181 this is what we've trained people to expect. We'll 182 probably fix it at some point, but let's try to 183 preserve the current behavior and only shake things up 184 once when it comes time to fix this lossage. */ 185 hp2 = res_getipnodebyaddr(hp->h_addr, hp->h_length, 186 hp->h_addrtype, &err); 187 188 if (hp2 != NULL) { 189 free(remote_host); 190 remote_host = strdup(hp2->h_name); 191 if (!remote_host) { 192 res_freehostent(hp2); 193 if (hp != NULL) 194 res_freehostent(hp); 195 return ENOMEM; 196 } 197 KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal() remote_host %s", 198 remote_host); 199 } 200 } 201 202 if (hp != NULL) { 203 res_freehostent(hp); 204 } 205 206 if (hp2 != NULL) { 207 res_freehostent(hp2); 208 } 209 210 } else /* type == KRB5_NT_UNKNOWN */ { 211 remote_host = strdup(hostname); 212 } 213 if (!remote_host) 214 return ENOMEM; 215 #ifdef DEBUG_REFERRALS 216 printf("sname_to_princ: hostname <%s> after rdns processing\n",remote_host); 217 #endif 218 219 if (type == KRB5_NT_SRV_HST) 220 for (cp = remote_host; *cp; cp++) 221 if (isupper((unsigned char) (*cp))) 222 *cp = tolower((unsigned char) (*cp)); 223 224 /* 225 * Windows NT5's broken resolver gratuitously tacks on a 226 * trailing period to the hostname (at least it does in 227 * Beta2). Find and remove it. 228 */ 229 if (remote_host[0]) { 230 cp = remote_host + strlen(remote_host)-1; 231 if (*cp == '.') 232 *cp = 0; 233 } 234 235 236 if ((retval = krb5_get_host_realm(context, remote_host, &hrealms))) { 237 free(remote_host); 238 return retval; 239 } 240 241 #ifdef DEBUG_REFERRALS 242 printf("sname_to_princ: realm <%s> after krb5_get_host_realm\n",hrealms[0]); 243 #endif 244 245 if (!hrealms[0]) { 246 /* Solaris Kerberos */ 247 krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN, 248 dgettext(TEXT_DOMAIN, 249 "Cannot determine realm for host: host is '%s'"), 250 remote_host ? remote_host : "unknown"); 251 252 free(remote_host); 253 krb5_xfree(hrealms); 254 return KRB5_ERR_HOST_REALM_UNKNOWN; 255 } 256 realm = hrealms[0]; 257 258 retval = krb5_build_principal(context, ret_princ, strlen(realm), 259 realm, sname, remote_host, 260 (char *)0); 261 262 if (retval == 0) 263 krb5_princ_type(context, *ret_princ) = type; 264 265 #ifdef DEBUG_REFERRALS 266 printf("krb5_sname_to_principal returning\n"); 267 printf("realm: <%s>, sname: <%s>, remote_host: <%s>\n", 268 realm,sname,remote_host); 269 krb5int_dbgref_dump_principal("krb5_sname_to_principal",*ret_princ); 270 #endif 271 272 free(remote_host); 273 274 krb5_free_host_realm(context, hrealms); 275 return retval; 276 } else { 277 return KRB5_SNAME_UNSUPP_NAMETYPE; 278 } 279 } 280 281