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