4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Ye olde non-reentrant interface (MT-unsafe, caveat utor)
31 #pragma ident "%Z%%M% %I% %E% SMI"
40 #include <arpa/inet.h>
41 #include <nss_dbdefs.h>
42 #include <netinet/in.h>
43 #include <sys/socket.h>
46 * Still just a global. If you want per-thread h_errno,
47 * use the reentrant interfaces (gethostbyname_r et al)
52 * Don't free this, even on an endhostent(), because bitter experience shows
53 * that there's production code that does getXXXbyYYY(), then endXXXent(),
54 * and then continues to use the pointer it got back.
56 static nss_XbyY_buf_t
*buffer
;
58 NSS_XbyY_ALLOC(&buffer, sizeof (struct hostent), NSS_BUFLEN_HOSTS)
59 /* === ?? set ENOMEM on failure? */
62 gethostbyname(const char *nam
)
66 if ((b
= GETBUF()) == 0)
68 return (gethostbyname_r(nam
, b
->result
, b
->buffer
, b
->buflen
,
73 gethostbyaddr(const void *addr
, socklen_t len
, int type
)
79 return (getipnodebyaddr(addr
, len
, type
, &h_errno
));
81 if ((b
= GETBUF()) == 0)
83 return (gethostbyaddr_r(addr
, len
, type
,
84 b
->result
, b
->buffer
, b
->buflen
, &h_errno
));
92 if ((b
= GETBUF()) == 0)
94 return (gethostent_r(b
->result
, b
->buffer
, b
->buflen
, &h_errno
));
98 * Return values: 0 = success, 1 = parse error, 2 = erange ...
99 * The structure pointer passed in is a structure in the caller's space
100 * wherein the field pointers would be set to areas in the buffer if
101 * need be. instring and buffer should be separate areas.
104 __str2hostent(int af
, const char *instr
, int lenstr
, void *ent
, char *buffer
,
107 struct hostent
*host
= (struct hostent
*)ent
;
108 const char *p
, *addrstart
, *limit
;
109 int naddr
, i
, aliases_erange
= 0;
111 char addrbuf
[100]; /* Why 100? */
112 struct in_addr
*addrp
;
113 struct in6_addr
*addrp6
;
116 if ((instr
>= buffer
&& (buffer
+ buflen
) > instr
) ||
117 (buffer
>= instr
&& (instr
+ lenstr
) > buffer
))
118 return (NSS_STR_PARSE_PARSE
);
119 if (af
!= AF_INET
&& af
!= AF_INET6
) {
121 * XXX - Returning ERANGE here is completely bogus.
122 * Unfortunately, there's no error code identifying
123 * bogus calls from the backend (and nothing the user
124 * can do about our bugs anyway).
126 return (NSS_STR_PARSE_ERANGE
);
130 * The DNS-via-YP code returns multiple lines for a key.
131 * Normal YP return values do not contain newlines (nor do
132 * lines from /etc/hosts or other sources)
133 * We count the number of newlines; this should give us
134 * the number of IP addresses specified.
135 * We'll also call the aliases code and instruct it to
136 * stop at the first newline as the remaining lines will
137 * all contain the same hostname/aliases (no aliases, unfortunately).
139 * When confronted with a string with embedded newlines,
140 * this code will take the hostname/aliases on the first line
141 * and each of the IP addresses at the start of all lines.
142 * Because the NIS protocol limits return values to 1024 bytes,
143 * we still do not get all addresses. If you want to fix
144 * that problem, do not look here.
149 /* Strip trailing newlines */
150 while (lenstr
> 0 && p
[lenstr
- 1] == '\n')
156 for (; p
< limit
&& (p
= memchr(p
, '\n', limit
- p
)); p
++)
159 /* Allocate space for naddr addresses and h_addr_list */
161 if (af
== AF_INET6
) {
162 addrp6
= (struct in6_addr
*)ROUND_DOWN(buffer
+ buflen
,
165 addrvec
= (char **)ROUND_DOWN(addrp6
, sizeof (*addrvec
));
166 addrvec
-= naddr
+ 1;
168 addrp
= (struct in_addr
*)ROUND_DOWN(buffer
+ buflen
,
171 addrvec
= (char **)ROUND_DOWN(addrp
, sizeof (*addrvec
));
172 addrvec
-= naddr
+ 1;
175 if ((char *)addrvec
< buffer
)
176 return (NSS_STR_PARSE_ERANGE
);
178 /* For each addr, parse and get it */
182 for (i
= 0; i
< naddr
; i
++) {
184 limit
= memchr(p
, '\n', lenstr
- (p
- instr
));
186 limit
= instr
+ lenstr
;
188 while (p
< limit
&& isspace(*p
))
191 while (p
< limit
&& !isspace(*p
))
194 /* Syntax error - no hostname present or truncated line */
195 return (NSS_STR_PARSE_PARSE
);
196 addrlen
= p
- addrstart
;
197 if (addrlen
>= sizeof (addrbuf
))
198 /* Syntax error -- supposed IP address is too long */
199 return (NSS_STR_PARSE_PARSE
);
200 (void) memcpy(addrbuf
, addrstart
, addrlen
);
201 addrbuf
[addrlen
] = '\0';
203 if (addrlen
> ((af
== AF_INET6
) ? INET6_ADDRSTRLEN
205 /* Syntax error -- supposed IP address is too long */
206 return (NSS_STR_PARSE_PARSE
);
209 * inet_pton() doesn't handle d.d.d, d.d, or d formats,
210 * so we must use inet_addr() for IPv4 addresses.
212 addrvec
[i
] = (char *)&addrp
[i
];
213 if ((addrp
[i
].s_addr
= inet_addr(addrbuf
)) ==
215 /* Syntax error -- bogus IPv4 address */
216 return (NSS_STR_PARSE_PARSE
);
219 * In the case of AF_INET6, we can have both v4 and v6
220 * addresses, so we convert v4's to v4 mapped addresses
221 * and return them as such.
223 addrvec
[i
] = (char *)&addrp6
[i
];
224 if (strchr(addrbuf
, ':') != 0) {
225 if (inet_pton(af
, addrbuf
, &addrp6
[i
]) != 1)
226 return (NSS_STR_PARSE_PARSE
);
229 if ((in4
.s_addr
= inet_addr(addrbuf
)) ==
231 return (NSS_STR_PARSE_PARSE
);
232 IN6_INADDR_TO_V4MAPPED(&in4
, &addrp6
[i
]);
236 /* First address, this is where we get the hostname + aliases */
238 while (p
< limit
&& isspace(*p
)) {
241 host
->h_aliases
= _nss_netdb_aliases(p
, limit
- p
,
242 buffer
, ((char *)addrvec
) - buffer
);
243 if (host
->h_aliases
== NULL
)
244 aliases_erange
= 1; /* too big for buffer */
246 if (limit
>= instr
+ lenstr
)
249 p
= limit
+ 1; /* skip NL */
252 if (host
->h_aliases
== 0) {
254 res
= NSS_STR_PARSE_ERANGE
;
256 res
= NSS_STR_PARSE_PARSE
;
259 host
->h_name
= host
->h_aliases
[0];
261 res
= NSS_STR_PARSE_SUCCESS
;
264 * If i < naddr, we quit the loop early and addrvec[i+1] needs NULL
265 * otherwise, we ran naddr iterations and addrvec[naddr] needs NULL
267 addrvec
[i
>= naddr
? naddr
: i
+ 1] = 0;
268 if (af
== AF_INET6
) {
269 host
->h_length
= sizeof (struct in6_addr
);
271 host
->h_length
= sizeof (struct in_addr
);
273 host
->h_addrtype
= af
;
274 host
->h_addr_list
= addrvec
;