1
/* $Id: bsdnss.c 114 2007-02-08 16:42:22Z lennart $ */
4
This file is part of nss-mdns.
6
nss-mdns is free software; you can redistribute it and/or modify
7
it under the terms of the GNU Lesser General Public License as published
8
by the Free Software Foundation; either version 2 of the License,
9
or (at your option) any later version.
11
nss-mdns is distributed in the hope that it will be useful, but1
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
General Public License for more details.
16
You should have received a copy of the GNU Lesser General Public License
17
along with nss-mdns; if not, write to the Free Software
18
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22
/* Original author: Bruce M. Simpson <bms@FreeBSD.org> */
28
#include <sys/param.h>
29
#include <sys/types.h>
32
#include <sys/socket.h>
33
#include <sys/ktrace.h>
45
#include <netinet/in.h>
52
* FreeBSD support prefers Avahi.
56
#if defined(NSS_IPV4_ONLY) || defined(NSS_IPV6_ONLY)
58
* FreeBSD's libc is always built with IPv4 support.
59
* There is no way of telling at compile time with a define if libc
60
* was built with -DINET6 or not; a configure test would be required.
61
* Therefore, distinguishing between the two makes no sense.
63
#define NO_BUILD_BSD_NSS
66
#ifndef NO_BUILD_BSD_NSS
68
* To turn on utrace() records, compile with -DDEBUG_UTRACE.
71
#define _NSS_UTRACE(msg) \
73
static const char __msg[] = msg ; \
74
(void)utrace(__msg, sizeof(__msg)); \
77
#define _NSS_UTRACE(msg)
80
ns_mtab *nss_module_register(const char *source, unsigned int *mtabsize,
81
nss_module_unregister_fn *unreg);
83
extern enum nss_status _nss_mdns_gethostbyname_r (const char *name, struct hostent * result,
84
char *buffer, size_t buflen, int *errnop,
87
extern enum nss_status _nss_mdns_gethostbyname2_r (const char *name, int af, struct hostent * result,
88
char *buffer, size_t buflen, int *errnop,
90
extern enum nss_status _nss_mdns_gethostbyaddr_r (struct in_addr * addr, int len, int type,
91
struct hostent * result, char *buffer,
92
size_t buflen, int *errnop, int *h_errnop);
93
extern enum nss_status _nss_mdns4_gethostbyname_r (const char *name, struct hostent * result,
94
char *buffer, size_t buflen, int *errnop,
97
extern enum nss_status _nss_mdns4_gethostbyname2_r (const char *name, int af, struct hostent * result,
98
char *buffer, size_t buflen, int *errnop,
100
extern enum nss_status _nss_mdns4_gethostbyaddr_r (struct in_addr * addr, int len, int type,
101
struct hostent * result, char *buffer,
102
size_t buflen, int *errnop, int *h_errnop);
103
extern enum nss_status _nss_mdns6_gethostbyname_r (const char *name, struct hostent * result,
104
char *buffer, size_t buflen, int *errnop,
107
extern enum nss_status _nss_mdns6_gethostbyname2_r (const char *name, int af, struct hostent * result,
108
char *buffer, size_t buflen, int *errnop,
110
extern enum nss_status _nss_mdns6_gethostbyaddr_r (struct in_addr * addr, int len, int type,
111
struct hostent * result, char *buffer,
112
size_t buflen, int *errnop, int *h_errnop);
114
typedef enum nss_status (*_bsd_nsstub_fn_t)(const char *, struct hostent *, char *, size_t, int *, int *);
116
/* XXX: FreeBSD 5.x is not supported. */
117
static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_getaddrinfo);
118
static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_gethostbyaddr_r);
119
static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_gethostbyname2_r);
120
static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_ghbyaddr);
121
static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_ghbyname);
123
static ns_mtab methods[] = {
124
/* database, name, method, mdata */
125
{ NSDB_HOSTS, "getaddrinfo", __nss_bsdcompat_getaddrinfo, NULL },
126
{ NSDB_HOSTS, "gethostbyaddr_r", __nss_bsdcompat_gethostbyaddr_r, NULL },
127
{ NSDB_HOSTS, "gethostbyname2_r", __nss_bsdcompat_gethostbyname2_r, NULL },
128
{ NSDB_HOSTS, "ghbyaddr", __nss_bsdcompat_ghbyaddr, NULL },
129
{ NSDB_HOSTS, "ghbyname", __nss_bsdcompat_ghbyname, NULL },
133
nss_module_register(const char *source, unsigned int *mtabsize,
134
nss_module_unregister_fn *unreg)
137
*mtabsize = sizeof(methods)/sizeof(methods[0]);
143
* Calling convention:
144
* ap: const char *name (optional), struct addrinfo *pai (hints, optional)
145
* retval: struct addrinfo **
147
* TODO: Map all returned hostents, not just the first match.
149
* name must always be specified by libc; pai is allocated
150
* by libc and must always be specified.
152
* We can malloc() addrinfo instances and hang them off ai->next;
153
* canonnames may also be malloc()'d.
154
* libc is responsible for mapping our ns error return to gai_strerror().
156
* libc calls us only to look up qualified hostnames. We don't need to
157
* worry about port numbers; libc will call getservbyname() and explore
158
* the appropriate maps configured in nsswitch.conf(5).
160
* _errno and _h_errno are unused by getaddrinfo(), as it is
161
* [mostly] OS independent interface implemented by Win32.
164
__nss_bsdcompat_getaddrinfo(void *retval, void *mdata __unused, va_list ap)
166
struct addrinfo sentinel;
169
void *cbufp; /* buffer handed to libc */
172
void *mbufp; /* buffer handed to mdns */
174
const struct addrinfo *pai;
175
struct sockaddr *psa; /* actually *sockaddr_storage */
176
struct addrinfo **resultp;
179
size_t mbuflen = 1024;
180
enum nss_status status;
182
_NSS_UTRACE("__nss_bsdcompat_getaddrinfo: called");
184
_h_errno = _errno = 0;
185
status = NSS_STATUS_UNAVAIL;
187
name = va_arg(ap, const char *);
188
pai = va_arg(ap, struct addrinfo *);
189
resultp = (struct addrinfo **)retval;
191
/* XXX: Will be used to hang off multiple matches later. */
192
memset(&sentinel, 0, sizeof(sentinel));
194
if (name == NULL || pai == NULL) {
195
*resultp = sentinel.ai_next;
199
mbufp = malloc((sizeof(struct hostent) + mbuflen));
201
*resultp = sentinel.ai_next;
204
hp = (struct hostent *)mbufp;
205
buffer = (char *)(hp + 1);
207
cbufp = malloc(sizeof(struct addrinfo) +
208
sizeof(struct sockaddr_storage));
211
*resultp = sentinel.ai_next;
214
ai = (struct addrinfo *)cbufp;
215
psa = (struct sockaddr *)(ai + 1);
218
* 1. Select which function to call based on the address family.
219
* 2. Map hostent to addrinfo.
220
* 3. Hand-off buffer to libc.
222
switch (pai->ai_family) {
224
status = _nss_mdns_gethostbyname_r(name, hp, buffer, mbuflen,
228
status = _nss_mdns4_gethostbyname_r(name, hp, buffer, mbuflen,
232
status = _nss_mdns6_gethostbyname_r(name, hp, buffer, mbuflen,
238
status = __nss_compat_result(status, _errno);
240
if (status == NS_SUCCESS) {
241
memset(ai, 0, sizeof(struct addrinfo));
242
ai->ai_flags = pai->ai_flags;
243
ai->ai_socktype = pai->ai_socktype;
244
ai->ai_protocol = pai->ai_protocol;
245
ai->ai_family = hp->h_addrtype;
246
memset(psa, 0, sizeof(struct sockaddr_storage));
247
psa->sa_len = ai->ai_addrlen;
248
psa->sa_family = ai->ai_family;
250
hap = hp->h_addr_list[0];
251
switch (ai->ai_family) {
253
ai->ai_addrlen = sizeof(struct sockaddr_in);
254
memcpy(&((struct sockaddr_in *)psa)->sin_addr, hap,
258
ai->ai_addrlen = sizeof(struct sockaddr_in6);
259
memcpy(&((struct sockaddr_in6 *)psa)->sin6_addr, hap,
263
ai->ai_addrlen = sizeof(struct sockaddr_storage);
264
memcpy(psa->sa_data, hap, ai->ai_addrlen);
266
sentinel.ai_next = ai;
270
if (sentinel.ai_next == NULL) {
275
*resultp = sentinel.ai_next;
280
* Calling convention:
281
* ap: const u_char *uaddr, socklen_t len, int af, struct hostent *hp,
282
* char *buf, size_t buflen, int ret_errno, int *h_errnop
283
* retval: should be set to NULL or hp passed in
286
__nss_bsdcompat_gethostbyaddr_r(void *retval, void *mdata __unused, va_list ap)
292
struct hostent **resultp;
297
enum nss_status status;
299
addr = va_arg(ap, void *);
300
len = va_arg(ap, socklen_t);
301
af = va_arg(ap, int);
302
hp = va_arg(ap, struct hostent *);
303
buf = va_arg(ap, char *);
304
buflen = va_arg(ap, size_t);
305
ret_errno = va_arg(ap, int);
306
h_errnop = va_arg(ap, int *);
307
resultp = (struct hostent **)retval;
310
status = _nss_mdns_gethostbyaddr_r(addr, len, af, hp, buf, buflen,
311
&ret_errno, h_errnop);
313
status = __nss_compat_result(status, *h_errnop);
314
if (status == NS_SUCCESS)
320
* Calling convention:
321
* ap: const char *name, int af, struct hostent *hp, char *buf,
322
* size_t buflen, int ret_errno, int *h_errnop
323
* retval is a struct hostent **result passed in by the libc client,
324
* which is responsible for allocating storage.
327
__nss_bsdcompat_gethostbyname2_r(void *retval, void *mdata __unused,
334
struct hostent **resultp;
338
enum nss_status status;
340
name = va_arg(ap, char *);
341
af = va_arg(ap, int);
342
hp = va_arg(ap, struct hostent *);
343
buf = va_arg(ap, char *);
344
buflen = va_arg(ap, size_t);
345
ret_errno = va_arg(ap, int);
346
h_errnop = va_arg(ap, int *);
347
resultp = (struct hostent **)retval;
353
status = _nss_mdns_gethostbyname2_r(name, af, hp, buf, buflen,
354
&ret_errno, h_errnop);
356
status = __nss_compat_result(status, *h_errnop);
357
if (status == NS_SUCCESS)
363
* Used by getipnodebyaddr(3).
365
* Calling convention:
366
* ap: struct in[6]_addr *src, size_t len, int af, int *errp
367
* retval: pointer to a pointer to an uninitialized struct hostent,
368
* in which should be returned a single pointer to on-heap storage.
370
* This function is responsible for allocating on-heap storage.
371
* The caller is responsible for calling freehostent() on the returned
375
__nss_bsdcompat_ghbyaddr(void *retval, void *mdata __unused, va_list ap)
381
struct hostent **resultp;
384
size_t buflen = 1024;
387
enum nss_status status;
389
src = va_arg(ap, void *);
390
len = va_arg(ap, size_t);
391
af = va_arg(ap, int);
392
errp = va_arg(ap, int *);
393
resultp = (struct hostent **)retval;
395
_NSS_UTRACE("__nss_bsdcompat_ghbyaddr: called");
397
bufp = malloc((sizeof(struct hostent) + buflen));
402
hp = (struct hostent *)bufp;
403
buffer = (char *)(hp + 1);
405
status = _nss_mdns_gethostbyaddr_r(src, len, af, hp, buffer,
406
buflen, errp, &h_errnop);
408
status = __nss_compat_result(status, *errp);
409
if (status != NS_SUCCESS) {
418
* Used by getipnodebyname(3).
420
* Calling convention:
421
* ap: const char *name, int af, int *errp
422
* retval: pointer to a pointer to an uninitialized struct hostent.
424
* This function is responsible for allocating on-heap storage.
425
* The caller is responsible for calling freehostent() on the returned
429
__nss_bsdcompat_ghbyname(void *retval, void *mdata __unused, va_list ap)
435
struct hostent **resultp;
438
size_t buflen = 1024;
440
enum nss_status status;
442
name = va_arg(ap, char *);
443
af = va_arg(ap, int);
444
errp = va_arg(ap, int *);
445
resultp = (struct hostent **)retval;
447
bufp = malloc((sizeof(struct hostent) + buflen));
452
hp = (struct hostent *)bufp;
453
buffer = (char *)(hp + 1);
455
status = _nss_mdns_gethostbyname_r(name, hp, buffer, buflen, errp,
458
status = __nss_compat_result(status, *errp);
459
if (status != NS_SUCCESS) {
467
#endif /* !NO_BUILD_BSD_NSS */