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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Ye olde non-reentrant interface (MT-unsafe, caveat utor) 29 */ 30 31 #include "mt.h" 32 #include <stdlib.h> 33 #include <ctype.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <netdb.h> 37 #include <stdio.h> 38 #include <arpa/inet.h> 39 #include <nss_dbdefs.h> 40 #include <netinet/in.h> 41 #include <sys/socket.h> 42 43 /* 44 * Still just a global. If you want per-thread h_errno, 45 * use the reentrant interfaces (gethostbyname_r et al) 46 */ 47 int h_errno; 48 49 #ifdef NSS_INCLUDE_UNSAFE 50 51 /* 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. 55 */ 56 static nss_XbyY_buf_t *buffer; 57 #define GETBUF() \ 58 NSS_XbyY_ALLOC(&buffer, sizeof (struct hostent), NSS_BUFLEN_HOSTS) 59 /* === ?? set ENOMEM on failure? */ 60 61 struct hostent * 62 gethostbyname(const char *nam) 63 { 64 nss_XbyY_buf_t *b; 65 66 if ((b = GETBUF()) == 0) 67 return (NULL); 68 return (gethostbyname_r(nam, b->result, b->buffer, b->buflen, 69 &h_errno)); 70 } 71 72 struct hostent * 73 gethostbyaddr(const void *addr, socklen_t len, int type) 74 { 75 nss_XbyY_buf_t *b; 76 77 h_errno = 0; 78 if (type == AF_INET6) 79 return (getipnodebyaddr(addr, len, type, &h_errno)); 80 81 if ((b = GETBUF()) == 0) 82 return (NULL); 83 return (gethostbyaddr_r(addr, len, type, 84 b->result, b->buffer, b->buflen, &h_errno)); 85 } 86 87 struct hostent * 88 gethostent(void) 89 { 90 nss_XbyY_buf_t *b; 91 92 if ((b = GETBUF()) == 0) 93 return (NULL); 94 return (gethostent_r(b->result, b->buffer, b->buflen, &h_errno)); 95 } 96 97 /* 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. 102 */ 103 int 104 __str2hostent(int af, const char *instr, int lenstr, void *ent, char *buffer, 105 int buflen) 106 { 107 struct hostent *host = (struct hostent *)ent; 108 const char *p, *addrstart, *limit; 109 int naddr, i, aliases_erange = 0; 110 int addrlen, res; 111 char addrbuf[100]; /* Why 100? */ 112 struct in_addr *addrp; 113 struct in6_addr *addrp6; 114 char **addrvec; 115 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) { 120 /* 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). 125 */ 126 return (NSS_STR_PARSE_ERANGE); 127 } 128 129 /* 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). 138 * 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. 145 */ 146 147 p = instr; 148 149 /* Strip trailing newlines */ 150 while (lenstr > 0 && p[lenstr - 1] == '\n') 151 lenstr--; 152 153 naddr = 1; 154 limit = p + lenstr; 155 156 for (; p < limit && (p = memchr(p, '\n', limit - p)); p++) 157 naddr++; 158 159 /* Allocate space for naddr addresses and h_addr_list */ 160 161 if (af == AF_INET6) { 162 addrp6 = (struct in6_addr *)ROUND_DOWN(buffer + buflen, 163 sizeof (*addrp6)); 164 addrp6 -= naddr; 165 addrvec = (char **)ROUND_DOWN(addrp6, sizeof (*addrvec)); 166 addrvec -= naddr + 1; 167 } else { 168 addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen, 169 sizeof (*addrp)); 170 addrp -= naddr; 171 addrvec = (char **)ROUND_DOWN(addrp, sizeof (*addrvec)); 172 addrvec -= naddr + 1; 173 } 174 175 if ((char *)addrvec < buffer) 176 return (NSS_STR_PARSE_ERANGE); 177 178 /* For each addr, parse and get it */ 179 180 p = instr; 181 182 for (i = 0; i < naddr; i ++) { 183 184 limit = memchr(p, '\n', lenstr - (p - instr)); 185 if (limit == NULL) 186 limit = instr + lenstr; 187 188 while (p < limit && isspace(*p)) 189 p++; 190 addrstart = p; 191 while (p < limit && !isspace(*p)) 192 p++; 193 if (p >= limit) 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'; 202 203 if (addrlen > ((af == AF_INET6) ? INET6_ADDRSTRLEN 204 : INET_ADDRSTRLEN)) 205 /* Syntax error -- supposed IP address is too long */ 206 return (NSS_STR_PARSE_PARSE); 207 if (af == AF_INET) { 208 /* 209 * inet_pton() doesn't handle d.d.d, d.d, or d formats, 210 * so we must use inet_addr() for IPv4 addresses. 211 */ 212 addrvec[i] = (char *)&addrp[i]; 213 if ((addrp[i].s_addr = inet_addr(addrbuf)) == 214 0xffffffffU) 215 /* Syntax error -- bogus IPv4 address */ 216 return (NSS_STR_PARSE_PARSE); 217 } else { 218 /* 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. 222 */ 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); 227 } else { 228 struct in_addr in4; 229 if ((in4.s_addr = inet_addr(addrbuf)) == 230 0xffffffffU) 231 return (NSS_STR_PARSE_PARSE); 232 IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]); 233 } 234 } 235 236 /* First address, this is where we get the hostname + aliases */ 237 if (i == 0) { 238 while (p < limit && isspace(*p)) { 239 p++; 240 } 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 */ 245 } 246 if (limit >= instr + lenstr) 247 break; 248 else 249 p = limit + 1; /* skip NL */ 250 } 251 252 if (host->h_aliases == 0) { 253 if (aliases_erange) 254 res = NSS_STR_PARSE_ERANGE; 255 else 256 res = NSS_STR_PARSE_PARSE; 257 } else { 258 /* Success */ 259 host->h_name = host->h_aliases[0]; 260 host->h_aliases++; 261 res = NSS_STR_PARSE_SUCCESS; 262 } 263 /* 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 266 */ 267 addrvec[i >= naddr ? naddr : i + 1] = 0; 268 if (af == AF_INET6) { 269 host->h_length = sizeof (struct in6_addr); 270 } else { 271 host->h_length = sizeof (struct in_addr); 272 } 273 host->h_addrtype = af; 274 host->h_addr_list = addrvec; 275 276 return (res); 277 } 278 #endif /* NSS_INCLUDE_UNSAFE */ 279