~ubuntu-branches/ubuntu/oneiric/nfs-utils/oneiric

« back to all changes in this revision

Viewing changes to utils/statd/hostname.c

  • Committer: Steve Langasek
  • Date: 2010-06-04 09:53:57 UTC
  • mfrom: (14.1.5 sid)
  • Revision ID: vorlon@debian.org-20100604095357-zbu3na972v3nmgvg
mergeĀ versionĀ 1:1.2.2-1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2009 Oracle.  All rights reserved.
 
3
 *
 
4
 * This file is part of nfs-utils.
 
5
 *
 
6
 * nfs-utils is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * nfs-utils is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
/*
 
21
 * NSM for Linux.
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include <config.h>
 
26
#endif
 
27
 
 
28
#include <sys/types.h>
 
29
#include <sys/socket.h>
 
30
 
 
31
#include <stdlib.h>
 
32
#include <stdbool.h>
 
33
#include <string.h>
 
34
#include <strings.h>
 
35
#include <netdb.h>
 
36
#include <arpa/inet.h>
 
37
 
 
38
#include "sockaddr.h"
 
39
#include "statd.h"
 
40
#include "xlog.h"
 
41
 
 
42
#ifndef HAVE_DECL_AI_ADDRCONFIG
 
43
#define AI_ADDRCONFIG   0
 
44
#endif
 
45
 
 
46
/**
 
47
 * statd_present_address - convert sockaddr to presentation address
 
48
 * @sap: pointer to socket address to convert
 
49
 * @buf: pointer to buffer to fill in
 
50
 * @buflen: length of buffer
 
51
 *
 
52
 * Convert the passed-in sockaddr-style address to presentation format.
 
53
 * The presentation format address is placed in @buf and is
 
54
 * '\0'-terminated.
 
55
 *
 
56
 * Returns true if successful; otherwise false.
 
57
 *
 
58
 * getnameinfo(3) is preferred, since it can parse IPv6 scope IDs.
 
59
 * An alternate version of statd_present_address() is available to
 
60
 * handle older glibcs that do not have getnameinfo(3).
 
61
 */
 
62
#ifdef HAVE_GETNAMEINFO
 
63
_Bool
 
64
statd_present_address(const struct sockaddr *sap, char *buf, const size_t buflen)
 
65
{
 
66
        socklen_t salen;
 
67
        int error;
 
68
 
 
69
        salen = nfs_sockaddr_length(sap);
 
70
        if (salen == 0) {
 
71
                xlog(D_GENERAL, "%s: unsupported address family",
 
72
                                __func__);
 
73
                return false;
 
74
        }
 
75
 
 
76
        error = getnameinfo(sap, salen, buf, (socklen_t)buflen,
 
77
                                                NULL, 0, NI_NUMERICHOST);
 
78
        if (error != 0) {
 
79
                xlog(D_GENERAL, "%s: getnameinfo(3): %s",
 
80
                                __func__, gai_strerror(error));
 
81
                return false;
 
82
        }
 
83
        return true;
 
84
}
 
85
#else   /* !HAVE_GETNAMEINFO */
 
86
_Bool
 
87
statd_present_address(const struct sockaddr *sap, char *buf, const size_t buflen)
 
88
{
 
89
        const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
 
90
 
 
91
        if (sin->sin_family != AF_INET) {
 
92
                xlog(D_GENERAL, "%s: unsupported address family", __func__);
 
93
                return false;
 
94
        }
 
95
 
 
96
        /* ensure '\0' termination */
 
97
        memset(buf, 0, buflen);
 
98
 
 
99
        if (inet_ntop(AF_INET, (char *)&sin->sin_addr,
 
100
                                        buf, (socklen_t)buflen) == NULL) {
 
101
                xlog(D_GENERAL, "%s: inet_ntop(3): %m", __func__);
 
102
                return false;
 
103
        }
 
104
        return true;
 
105
}
 
106
#endif  /* !HAVE_GETNAMEINFO */
 
107
 
 
108
/*
 
109
 * Look up the hostname; report exceptional errors.  Caller must
 
110
 * call freeaddrinfo(3) if a valid addrinfo is returned.
 
111
 */
 
112
__attribute_malloc__
 
113
static struct addrinfo *
 
114
get_addrinfo(const char *hostname, const struct addrinfo *hint)
 
115
{
 
116
        struct addrinfo *ai = NULL;
 
117
        int error;
 
118
 
 
119
        error = getaddrinfo(hostname, NULL, hint, &ai);
 
120
        switch (error) {
 
121
        case 0:
 
122
                return ai;
 
123
        case EAI_NONAME:
 
124
                break;
 
125
        default:
 
126
                xlog(D_GENERAL, "%s: failed to resolve host %s: %s",
 
127
                                __func__, hostname, gai_strerror(error));
 
128
        }
 
129
 
 
130
        return NULL;
 
131
}
 
132
 
 
133
#ifdef HAVE_GETNAMEINFO
 
134
static _Bool
 
135
get_nameinfo(const struct sockaddr *sap, const socklen_t salen,
 
136
                /*@out@*/ char *buf, const socklen_t buflen)
 
137
{
 
138
        int error;
 
139
 
 
140
        error = getnameinfo(sap, salen, buf, buflen, NULL, 0, NI_NAMEREQD);
 
141
        if (error != 0) {
 
142
                xlog(D_GENERAL, "%s: failed to resolve address: %s",
 
143
                                __func__, gai_strerror(error));
 
144
                return false;
 
145
        }
 
146
 
 
147
        return true;
 
148
}
 
149
#else   /* !HAVE_GETNAMEINFO */
 
150
static _Bool
 
151
get_nameinfo(const struct sockaddr *sap,
 
152
                __attribute__ ((unused)) const socklen_t salen,
 
153
                /*@out@*/ char *buf, socklen_t buflen)
 
154
{
 
155
        struct sockaddr_in *sin = (struct sockaddr_in *)(char *)sap;
 
156
        struct hostent *hp;
 
157
 
 
158
        if (sin->sin_family != AF_INET) {
 
159
                xlog(D_GENERAL, "%s: unknown address family: %d",
 
160
                                sin->sin_family);
 
161
                return false;
 
162
        }
 
163
 
 
164
        hp = gethostbyaddr((const char *)&(sin->sin_addr.s_addr),
 
165
                                sizeof(struct in_addr), AF_INET);
 
166
        if (hp == NULL) {
 
167
                xlog(D_GENERAL, "%s: failed to resolve address: %m", __func__);
 
168
                return false;
 
169
        }
 
170
 
 
171
        strncpy(buf, hp->h_name, (size_t)buflen);
 
172
        return true;
 
173
}
 
174
#endif  /* !HAVE_GETNAMEINFO */
 
175
 
 
176
/**
 
177
 * statd_canonical_name - choose file name for monitor record files
 
178
 * @hostname: C string containing hostname or presentation address
 
179
 *
 
180
 * Returns a '\0'-terminated ASCII string containing a fully qualified
 
181
 * canonical hostname, or NULL if @hostname does not have a reverse
 
182
 * mapping.  Caller must free the result with free(3).
 
183
 *
 
184
 * Incoming hostnames are looked up to determine the canonical hostname,
 
185
 * and incoming presentation addresses are converted to canonical
 
186
 * hostnames.
 
187
 *
 
188
 * We won't monitor peers that don't have a reverse map.  The canonical
 
189
 * name gives us a key for our monitor list.
 
190
 */
 
191
__attribute_malloc__
 
192
char *
 
193
statd_canonical_name(const char *hostname)
 
194
{
 
195
        struct addrinfo hint = {
 
196
#ifdef IPV6_SUPPORTED
 
197
                .ai_family      = AF_UNSPEC,
 
198
#else   /* !IPV6_SUPPORTED */
 
199
                .ai_family      = AF_INET,
 
200
#endif  /* !IPV6_SUPPORTED */
 
201
                .ai_flags       = AI_NUMERICHOST,
 
202
                .ai_protocol    = (int)IPPROTO_UDP,
 
203
        };
 
204
        char buf[NI_MAXHOST];
 
205
        struct addrinfo *ai;
 
206
 
 
207
        ai = get_addrinfo(hostname, &hint);
 
208
        if (ai != NULL) {
 
209
                /* @hostname was a presentation address */
 
210
                _Bool result;
 
211
                result = get_nameinfo(ai->ai_addr, ai->ai_addrlen,
 
212
                                        buf, (socklen_t)sizeof(buf));
 
213
                freeaddrinfo(ai);
 
214
                if (!result)
 
215
                        return NULL;
 
216
                return strdup(buf);
 
217
        }
 
218
 
 
219
        /* @hostname was a hostname */
 
220
        hint.ai_flags = AI_CANONNAME;
 
221
        ai = get_addrinfo(hostname, &hint);
 
222
        if (ai == NULL)
 
223
                return NULL;
 
224
        strcpy(buf, ai->ai_canonname);
 
225
        freeaddrinfo(ai);
 
226
 
 
227
        return strdup(buf);
 
228
}
 
229
 
 
230
/**
 
231
 * statd_matchhostname - check if two hostnames are equivalent
 
232
 * @hostname1: C string containing hostname
 
233
 * @hostname2: C string containing hostname
 
234
 *
 
235
 * Returns true if the hostnames are the same, the hostnames resolve
 
236
 * to the same canonical name, or the hostnames resolve to at least
 
237
 * one address that is the same.  False is returned if the hostnames
 
238
 * do not match in any of these ways, if either hostname contains
 
239
 * wildcard characters, if either hostname is a netgroup name, or
 
240
 * if an error occurs.
 
241
 */
 
242
_Bool
 
243
statd_matchhostname(const char *hostname1, const char *hostname2)
 
244
{
 
245
        struct addrinfo *ai1, *ai2, *results1 = NULL, *results2 = NULL;
 
246
        struct addrinfo hint = {
 
247
                .ai_family      = AF_UNSPEC,
 
248
                .ai_flags       = AI_CANONNAME,
 
249
                .ai_protocol    = (int)IPPROTO_UDP,
 
250
        };
 
251
        _Bool result = false;
 
252
 
 
253
        if (strcasecmp(hostname1, hostname2) == 0) {
 
254
                result = true;
 
255
                goto out;
 
256
        }
 
257
 
 
258
        results1 = get_addrinfo(hostname1, &hint);
 
259
        if (results1 == NULL)
 
260
                goto out;
 
261
        results2 = get_addrinfo(hostname2, &hint);
 
262
        if (results2 == NULL)
 
263
                goto out;
 
264
 
 
265
        if (strcasecmp(results1->ai_canonname, results2->ai_canonname) == 0) {
 
266
                result = true;
 
267
                goto out;
 
268
        }
 
269
 
 
270
        for (ai1 = results1; ai1 != NULL; ai1 = ai1->ai_next)
 
271
                for (ai2 = results2; ai2 != NULL; ai2 = ai2->ai_next)
 
272
                        if (nfs_compare_sockaddr(ai1->ai_addr, ai2->ai_addr)) {
 
273
                                result = true;
 
274
                                break;
 
275
                        }
 
276
 
 
277
out:
 
278
        freeaddrinfo(results2);
 
279
        freeaddrinfo(results1);
 
280
 
 
281
        xlog(D_CALL, "%s: hostnames %s", __func__,
 
282
                        (result ? "matched" : "did not match"));
 
283
        return result;
 
284
}