#include "k5-int.h"
#include "os-proto.h"
#include "fake-addrinfo.h"
#include <ctype.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include <locale.h>
#include <syslog.h>
#if !defined(DEFAULT_RDNS_LOOKUP)
#define DEFAULT_RDNS_LOOKUP 0
#endif
extern struct hostent *res_getipnodebyname(const char *, int, int, int *);
extern struct hostent *res_getipnodebyaddr(const void *, size_t, int, int *);
extern void res_freehostent(struct hostent *);
static int
maybe_use_reverse_dns (krb5_context context, int def_val)
{
krb5_error_code code;
char * value = NULL;
int use_rdns = 0;
code = profile_get_string(context->profile, "libdefaults",
"rdns", 0, 0, &value);
if (code)
return def_val;
if (value == 0)
return def_val;
use_rdns = _krb5_conf_boolean(value);
profile_release_string(value);
return use_rdns;
}
krb5_error_code KRB5_CALLCONV
krb5_sname_to_principal(krb5_context context, const char *hostname, const char *sname, krb5_int32 type, krb5_principal *ret_princ)
{
char **hrealms, *realm, *remote_host;
krb5_error_code retval;
register char *cp;
char localname[MAXHOSTNAMELEN];
KRB5_LOG0(KRB5_INFO, "krb5_sname_to_principal() start");
#ifdef DEBUG_REFERRALS
printf("krb5_sname_to_principal(host=%s, sname=%s, type=%d)\n",hostname,sname,type);
printf(" name types: 0=unknown, 3=srv_host\n");
#endif
if ((type == KRB5_NT_UNKNOWN) ||
(type == KRB5_NT_SRV_HST)) {
if (! hostname) {
if (gethostname(localname, MAXHOSTNAMELEN)) {
KRB5_LOG0(KRB5_ERR, "krb5_sname_to_principal()"
" gethostname failed");
return SOCKET_ERRNO;
}
hostname = localname;
}
if (! sname)
sname = "host";
if (type == KRB5_NT_SRV_HST) {
struct hostent *hp = NULL;
struct hostent *hp2 = NULL;
int err;
int addr_family;
KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal() hostname %s",
hostname);
addr_family = AF_INET;
try_getipnodebyname_again:
hp = res_getipnodebyname(hostname, addr_family, 0, &err);
if (!hp) {
#ifdef DEBUG_REFERRALS
printf("sname_to_princ: probably punting due to bad hostname of %s\n",hostname);
#endif
if (addr_family == AF_INET) {
KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal()"
" can't get AF_INET addr, err = %d", err);
addr_family = AF_INET6;
goto try_getipnodebyname_again;
}
KRB5_LOG(KRB5_ERR, "krb5_sname_to_principal()"
" can't get AF_INET or AF_INET6 addr,"
" err = %d", err);
krb5_set_error_message(context, KRB5_ERR_BAD_HOSTNAME,
dgettext(TEXT_DOMAIN,
"Hostname cannot be canonicalized for '%s': %s"),
hostname, strerror(err));
return KRB5_ERR_BAD_HOSTNAME;
}
remote_host = strdup(hp ? hp->h_name : hostname);
if (!remote_host) {
if (hp != NULL)
res_freehostent(hp);
return ENOMEM;
}
if (maybe_use_reverse_dns(context, DEFAULT_RDNS_LOOKUP)) {
hp2 = res_getipnodebyaddr(hp->h_addr, hp->h_length,
hp->h_addrtype, &err);
if (hp2 != NULL) {
free(remote_host);
remote_host = strdup(hp2->h_name);
if (!remote_host) {
res_freehostent(hp2);
if (hp != NULL)
res_freehostent(hp);
return ENOMEM;
}
KRB5_LOG(KRB5_INFO, "krb5_sname_to_principal() remote_host %s",
remote_host);
}
}
if (hp != NULL) {
res_freehostent(hp);
}
if (hp2 != NULL) {
res_freehostent(hp2);
}
} else {
remote_host = strdup(hostname);
}
if (!remote_host)
return ENOMEM;
#ifdef DEBUG_REFERRALS
printf("sname_to_princ: hostname <%s> after rdns processing\n",remote_host);
#endif
if (type == KRB5_NT_SRV_HST)
for (cp = remote_host; *cp; cp++)
if (isupper((unsigned char) (*cp)))
*cp = tolower((unsigned char) (*cp));
if (remote_host[0]) {
cp = remote_host + strlen(remote_host)-1;
if (*cp == '.')
*cp = 0;
}
if ((retval = krb5_get_host_realm(context, remote_host, &hrealms))) {
free(remote_host);
return retval;
}
#ifdef DEBUG_REFERRALS
printf("sname_to_princ: realm <%s> after krb5_get_host_realm\n",hrealms[0]);
#endif
if (!hrealms[0]) {
krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN,
dgettext(TEXT_DOMAIN,
"Cannot determine realm for host: host is '%s'"),
remote_host ? remote_host : "unknown");
free(remote_host);
krb5_xfree(hrealms);
return KRB5_ERR_HOST_REALM_UNKNOWN;
}
realm = hrealms[0];
retval = krb5_build_principal(context, ret_princ, strlen(realm),
realm, sname, remote_host,
(char *)0);
if (retval == 0)
krb5_princ_type(context, *ret_princ) = type;
#ifdef DEBUG_REFERRALS
printf("krb5_sname_to_principal returning\n");
printf("realm: <%s>, sname: <%s>, remote_host: <%s>\n",
realm,sname,remote_host);
krb5int_dbgref_dump_principal("krb5_sname_to_principal",*ret_princ);
#endif
free(remote_host);
krb5_free_host_realm(context, hrealms);
return retval;
} else {
return KRB5_SNAME_UNSUPP_NAMETYPE;
}
}