1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* 29 * Ye olde non-reentrant interface (MT-unsafe, caveat utor) 30 */ 31 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 #include "mt.h" 35 #include <stdlib.h> 36 #include <ctype.h> 37 #include <string.h> 38 #include <strings.h> 39 #include <netdb.h> 40 #include <stdio.h> 41 #include <arpa/inet.h> 42 #include <nss_dbdefs.h> 43 #include <netinet/in.h> 44 #include <sys/socket.h> 45 46 /* 47 * Still just a global. If you want per-thread h_errno, 48 * use the reentrant interfaces (gethostbyname_r et al) 49 */ 50 int h_errno; 51 52 #ifdef NSS_INCLUDE_UNSAFE 53 54 /* 55 * Don't free this, even on an endhostent(), because bitter experience shows 56 * that there's production code that does getXXXbyYYY(), then endXXXent(), 57 * and then continues to use the pointer it got back. 58 */ 59 static nss_XbyY_buf_t *buffer; 60 #define GETBUF() \ 61 NSS_XbyY_ALLOC(&buffer, sizeof (struct hostent), NSS_BUFLEN_HOSTS) 62 /* === ?? set ENOMEM on failure? */ 63 64 struct hostent * 65 gethostbyname(const char *nam) 66 { 67 nss_XbyY_buf_t *b; 68 69 if ((b = GETBUF()) == 0) 70 return (NULL); 71 return (gethostbyname_r(nam, b->result, b->buffer, b->buflen, 72 &h_errno)); 73 } 74 75 struct hostent * 76 gethostbyaddr(const void *addr, socklen_t len, int type) 77 { 78 nss_XbyY_buf_t *b; 79 80 h_errno = 0; 81 if (type == AF_INET6) 82 return (getipnodebyaddr(addr, len, type, &h_errno)); 83 84 if ((b = GETBUF()) == 0) 85 return (NULL); 86 return (gethostbyaddr_r(addr, len, type, 87 b->result, b->buffer, b->buflen, &h_errno)); 88 } 89 90 struct hostent * 91 gethostent(void) 92 { 93 nss_XbyY_buf_t *b; 94 95 if ((b = GETBUF()) == 0) 96 return (NULL); 97 return (gethostent_r(b->result, b->buffer, b->buflen, &h_errno)); 98 } 99 100 /* 101 * Return values: 0 = success, 1 = parse error, 2 = erange ... 102 * The structure pointer passed in is a structure in the caller's space 103 * wherein the field pointers would be set to areas in the buffer if 104 * need be. instring and buffer should be separate areas. 105 */ 106 int 107 __str2hostent(int af, const char *instr, int lenstr, void *ent, char *buffer, 108 int buflen) 109 { 110 struct hostent *host = (struct hostent *)ent; 111 const char *p, *addrstart, *limit; 112 int naddr, i, aliases_erange = 0; 113 int addrlen, res; 114 char addrbuf[100]; /* Why 100? */ 115 struct in_addr *addrp; 116 struct in6_addr *addrp6; 117 char **addrvec; 118 119 if ((instr >= buffer && (buffer + buflen) > instr) || 120 (buffer >= instr && (instr + lenstr) > buffer)) 121 return (NSS_STR_PARSE_PARSE); 122 if (af != AF_INET && af != AF_INET6) { 123 /* 124 * XXX - Returning ERANGE here is completely bogus. 125 * Unfortunately, there's no error code identifying 126 * bogus calls from the backend (and nothing the user 127 * can do about our bugs anyway). 128 */ 129 return (NSS_STR_PARSE_ERANGE); 130 } 131 132 /* 133 * The DNS-via-YP code returns multiple lines for a key. 134 * Normal YP return values do not contain newlines (nor do 135 * lines from /etc/hosts or other sources) 136 * We count the number of newlines; this should give us 137 * the number of IP addresses specified. 138 * We'll also call the aliases code and instruct it to 139 * stop at the first newline as the remaining lines will 140 * all contain the same hostname/aliases (no aliases, unfortunately). 141 * 142 * When confronted with a string with embedded newlines, 143 * this code will take the hostname/aliases on the first line 144 * and each of the IP addresses at the start of all lines. 145 * Because the NIS protocol limits return values to 1024 bytes, 146 * we still do not get all addresses. If you want to fix 147 * that problem, do not look here. 148 */ 149 150 p = instr; 151 152 /* Strip trailing newlines */ 153 while (lenstr > 0 && p[lenstr - 1] == '\n') 154 lenstr--; 155 156 naddr = 1; 157 limit = p + lenstr; 158 159 for (; p < limit && (p = memchr(p, '\n', limit - p)); p++) 160 naddr++; 161 162 /* Allocate space for naddr addresses and h_addr_list */ 163 164 if (af == AF_INET6) { 165 addrp6 = (struct in6_addr *)ROUND_DOWN(buffer + buflen, 166 sizeof (*addrp6)); 167 addrp6 -= naddr; 168 addrvec = (char **)ROUND_DOWN(addrp6, sizeof (*addrvec)); 169 addrvec -= naddr + 1; 170 } else { 171 addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen, 172 sizeof (*addrp)); 173 addrp -= naddr; 174 addrvec = (char **)ROUND_DOWN(addrp, sizeof (*addrvec)); 175 addrvec -= naddr + 1; 176 } 177 178 if ((char *)addrvec < buffer) 179 return (NSS_STR_PARSE_ERANGE); 180 181 /* For each addr, parse and get it */ 182 183 p = instr; 184 185 for (i = 0; i < naddr; i ++) { 186 187 limit = memchr(p, '\n', lenstr - (p - instr)); 188 if (limit == NULL) 189 limit = instr + lenstr; 190 191 while (p < limit && isspace(*p)) 192 p++; 193 addrstart = p; 194 while (p < limit && !isspace(*p)) 195 p++; 196 if (p >= limit) 197 /* Syntax error - no hostname present or truncated line */ 198 return (NSS_STR_PARSE_PARSE); 199 addrlen = p - addrstart; 200 if (addrlen >= sizeof (addrbuf)) 201 /* Syntax error -- supposed IP address is too long */ 202 return (NSS_STR_PARSE_PARSE); 203 (void) memcpy(addrbuf, addrstart, addrlen); 204 addrbuf[addrlen] = '\0'; 205 206 if (addrlen > ((af == AF_INET6) ? INET6_ADDRSTRLEN 207 : INET_ADDRSTRLEN)) 208 /* Syntax error -- supposed IP address is too long */ 209 return (NSS_STR_PARSE_PARSE); 210 if (af == AF_INET) { 211 /* 212 * inet_pton() doesn't handle d.d.d, d.d, or d formats, 213 * so we must use inet_addr() for IPv4 addresses. 214 */ 215 addrvec[i] = (char *)&addrp[i]; 216 if ((addrp[i].s_addr = inet_addr(addrbuf)) == 217 0xffffffffU) 218 /* Syntax error -- bogus IPv4 address */ 219 return (NSS_STR_PARSE_PARSE); 220 } else { 221 /* 222 * In the case of AF_INET6, we can have both v4 and v6 223 * addresses, so we convert v4's to v4 mapped addresses 224 * and return them as such. 225 */ 226 addrvec[i] = (char *)&addrp6[i]; 227 if (strchr(addrbuf, ':') != 0) { 228 if (inet_pton(af, addrbuf, &addrp6[i]) != 1) 229 return (NSS_STR_PARSE_PARSE); 230 } else { 231 struct in_addr in4; 232 if ((in4.s_addr = inet_addr(addrbuf)) == 233 0xffffffffU) 234 return (NSS_STR_PARSE_PARSE); 235 IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]); 236 } 237 } 238 239 /* First address, this is where we get the hostname + aliases */ 240 if (i == 0) { 241 while (p < limit && isspace(*p)) { 242 p++; 243 } 244 host->h_aliases = _nss_netdb_aliases(p, limit - p, 245 buffer, ((char *)addrvec) - buffer); 246 if (host->h_aliases == NULL) 247 aliases_erange = 1; /* too big for buffer */ 248 } 249 if (limit >= instr + lenstr) 250 break; 251 else 252 p = limit + 1; /* skip NL */ 253 } 254 255 if (host->h_aliases == 0) { 256 if (aliases_erange) 257 res = NSS_STR_PARSE_ERANGE; 258 else 259 res = NSS_STR_PARSE_PARSE; 260 } else { 261 /* Success */ 262 host->h_name = host->h_aliases[0]; 263 host->h_aliases++; 264 res = NSS_STR_PARSE_SUCCESS; 265 } 266 /* 267 * If i < naddr, we quit the loop early and addrvec[i+1] needs NULL 268 * otherwise, we ran naddr iterations and addrvec[naddr] needs NULL 269 */ 270 addrvec[i >= naddr ? naddr : i + 1] = 0; 271 if (af == AF_INET6) { 272 host->h_length = sizeof (struct in6_addr); 273 } else { 274 host->h_length = sizeof (struct in_addr); 275 } 276 host->h_addrtype = af; 277 host->h_addr_list = addrvec; 278 279 return (res); 280 } 281 #endif /* NSS_INCLUDE_UNSAFE */ 282