155682Smarkm/*
2233294Sstas * Copyright (c) 1999 - 2001 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "krb5_locl.h"
3555682Smarkm
3655682Smarkmstatic krb5_error_code
3755682Smarkmcopy_hostname(krb5_context context,
3855682Smarkm	      const char *orig_hostname,
3955682Smarkm	      char **new_hostname)
4055682Smarkm{
4155682Smarkm    *new_hostname = strdup (orig_hostname);
4278527Sassar    if (*new_hostname == NULL) {
43233294Sstas	krb5_set_error_message(context, ENOMEM,
44233294Sstas			       N_("malloc: out of memory", ""));
4555682Smarkm	return ENOMEM;
4678527Sassar    }
4757416Smarkm    strlwr (*new_hostname);
4855682Smarkm    return 0;
4955682Smarkm}
5055682Smarkm
51233294Sstas/**
52233294Sstas * krb5_expand_hostname() tries to make orig_hostname into a more
53233294Sstas * canonical one in the newly allocated space returned in
54233294Sstas * new_hostname.
55233294Sstas
56233294Sstas * @param context a Keberos context
57233294Sstas * @param orig_hostname hostname to canonicalise.
58233294Sstas * @param new_hostname output hostname, caller must free hostname with
59233294Sstas *        krb5_xfree().
60233294Sstas *
61233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
62233294Sstas *
63233294Sstas * @ingroup krb5_support
6455682Smarkm */
6555682Smarkm
66233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
6755682Smarkmkrb5_expand_hostname (krb5_context context,
6855682Smarkm		      const char *orig_hostname,
6955682Smarkm		      char **new_hostname)
7055682Smarkm{
7155682Smarkm    struct addrinfo *ai, *a, hints;
7255682Smarkm    int error;
7355682Smarkm
74178825Sdfr    if ((context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) == 0)
75178825Sdfr	return copy_hostname (context, orig_hostname, new_hostname);
76178825Sdfr
7755682Smarkm    memset (&hints, 0, sizeof(hints));
7855682Smarkm    hints.ai_flags = AI_CANONNAME;
7955682Smarkm
8055682Smarkm    error = getaddrinfo (orig_hostname, NULL, &hints, &ai);
8155682Smarkm    if (error)
8255682Smarkm	return copy_hostname (context, orig_hostname, new_hostname);
8355682Smarkm    for (a = ai; a != NULL; a = a->ai_next) {
8455682Smarkm	if (a->ai_canonname != NULL) {
8555682Smarkm	    *new_hostname = strdup (a->ai_canonname);
8655682Smarkm	    freeaddrinfo (ai);
8778527Sassar	    if (*new_hostname == NULL) {
88233294Sstas		krb5_set_error_message(context, ENOMEM,
89233294Sstas				       N_("malloc: out of memory", ""));
9055682Smarkm		return ENOMEM;
9178527Sassar	    } else {
9255682Smarkm		return 0;
9378527Sassar	    }
9455682Smarkm	}
9555682Smarkm    }
9655682Smarkm    freeaddrinfo (ai);
9755682Smarkm    return copy_hostname (context, orig_hostname, new_hostname);
9855682Smarkm}
9957416Smarkm
10057416Smarkm/*
10157422Smarkm * handle the case of the hostname being unresolvable and thus identical
10257422Smarkm */
10357422Smarkm
10457422Smarkmstatic krb5_error_code
10557422Smarkmvanilla_hostname (krb5_context context,
10657422Smarkm		  const char *orig_hostname,
10757422Smarkm		  char **new_hostname,
10857422Smarkm		  char ***realms)
10957422Smarkm{
11057422Smarkm    krb5_error_code ret;
11157422Smarkm
11257422Smarkm    ret = copy_hostname (context, orig_hostname, new_hostname);
11357422Smarkm    if (ret)
11457422Smarkm	return ret;
11557422Smarkm    strlwr (*new_hostname);
11657422Smarkm
11757422Smarkm    ret = krb5_get_host_realm (context, *new_hostname, realms);
11857422Smarkm    if (ret) {
11957422Smarkm	free (*new_hostname);
12057422Smarkm	return ret;
12157422Smarkm    }
12257422Smarkm    return 0;
12357422Smarkm}
12457422Smarkm
125233294Sstas/**
126233294Sstas * krb5_expand_hostname_realms() expands orig_hostname to a name we
127233294Sstas * believe to be a hostname in newly allocated space in new_hostname
128233294Sstas * and return the realms new_hostname is believed to belong to in
129233294Sstas * realms.
130233294Sstas *
131233294Sstas * @param context a Keberos context
132233294Sstas * @param orig_hostname hostname to canonicalise.
133233294Sstas * @param new_hostname output hostname, caller must free hostname with
134233294Sstas *        krb5_xfree().
135233294Sstas * @param realms output possible realms, is an array that is terminated
136233294Sstas *        with NULL. Caller must free with krb5_free_host_realm().
137233294Sstas *
138233294Sstas * @return Return an error code or 0, see krb5_get_error_message().
139233294Sstas *
140233294Sstas * @ingroup krb5_support
14157416Smarkm */
14257416Smarkm
143233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
14457416Smarkmkrb5_expand_hostname_realms (krb5_context context,
14557416Smarkm			     const char *orig_hostname,
14657416Smarkm			     char **new_hostname,
14757416Smarkm			     char ***realms)
14857416Smarkm{
14957416Smarkm    struct addrinfo *ai, *a, hints;
15057416Smarkm    int error;
15157416Smarkm    krb5_error_code ret = 0;
15257416Smarkm
153178825Sdfr    if ((context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) == 0)
154178825Sdfr	return vanilla_hostname (context, orig_hostname, new_hostname,
155178825Sdfr				 realms);
156178825Sdfr
15757416Smarkm    memset (&hints, 0, sizeof(hints));
15857416Smarkm    hints.ai_flags = AI_CANONNAME;
15957416Smarkm
16057416Smarkm    error = getaddrinfo (orig_hostname, NULL, &hints, &ai);
16157416Smarkm    if (error)
16257422Smarkm	return vanilla_hostname (context, orig_hostname, new_hostname,
16357422Smarkm				 realms);
16457422Smarkm
16557416Smarkm    for (a = ai; a != NULL; a = a->ai_next) {
16657416Smarkm	if (a->ai_canonname != NULL) {
16772445Sassar	    ret = copy_hostname (context, a->ai_canonname, new_hostname);
16857422Smarkm	    if (ret) {
16957422Smarkm		freeaddrinfo (ai);
17057422Smarkm		return ret;
17157422Smarkm	    }
17257416Smarkm	    strlwr (*new_hostname);
17357416Smarkm	    ret = krb5_get_host_realm (context, *new_hostname, realms);
17457422Smarkm	    if (ret == 0) {
17557422Smarkm		freeaddrinfo (ai);
17657422Smarkm		return 0;
17757422Smarkm	    }
17857416Smarkm	    free (*new_hostname);
17957416Smarkm	}
18057416Smarkm    }
18190926Snectar    freeaddrinfo(ai);
18257422Smarkm    return vanilla_hostname (context, orig_hostname, new_hostname, realms);
18357416Smarkm}
184