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