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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * BrandZ lx name services translation library. 31 * 32 * This library is specified as the default name services translation 33 * library in a custom netconfig(4) file that is only used when running 34 * native solaris processes in a Linux branded zone. 35 * 36 * What this means it that when a native solaris process runs in a 37 * Linux branded zone and issues a name service request to libnsl.so 38 * (either directly or indirectly via any libraries the program may 39 * be linked against) libnsl.so will dlopen(3c) this library and call 40 * into it to service these requests. 41 * 42 * This library is in turn linked against lx_thunk.so and will attempt 43 * to call interfaces in lx_thunk.so to resolve these requests. The 44 * functions that are called in lx_thunk.so are designed to have the 45 * same signature and behavior as the existing solaris name service 46 * interfaces. The name services interfaces we call are: 47 * 48 * Native Interface -> lx_thunk.so Interface 49 * ---------------- -> --------------------- 50 * gethostbyname_r -> lxt_gethostbyname_r 51 * gethostbyaddr_r -> lxt_gethostbyaddr_r 52 * getservbyname_r -> lxt_getservbyname_r 53 * getservbyport_r -> lxt_getservbyport_r 54 * 55 * This library also uses one additional interface from lx_thunk.so: 56 * lxt_debug 57 * Information debugging messages are sent to lx_thunk.so via this 58 * interface and that library can decided if it wants to drop the 59 * messages or output them somewhere. 60 */ 61 62 #include <assert.h> 63 #include <dlfcn.h> 64 #include <errno.h> 65 #include <fcntl.h> 66 #include <netdb.h> 67 #include <netdir.h> 68 #include <nss_dbdefs.h> 69 #include <rpc/clnt.h> 70 #include <stdarg.h> 71 #include <stdio.h> 72 #include <stdlib.h> 73 #include <string.h> 74 #include <strings.h> 75 #include <sys/mman.h> 76 #include <sys/stat.h> 77 #include <sys/types.h> 78 #include <sys/varargs.h> 79 #include <sys/wait.h> 80 #include <thread.h> 81 #include <tiuser.h> 82 #include <unistd.h> 83 #include <sys/lx_thunk.h> 84 85 86 /* 87 * Private nametoaddr library interfaces. 88 */ 89 static int 90 netconfig_is_ipv4(struct netconfig *config) 91 { 92 int i; 93 /* 94 * If we look at the rpc services registered on a Linux system 95 * (this can be done via rpcinfo(1M)) for both on the loopback 96 * interface and on any remote interfaces we only see services 97 * registered for tcp and udp. So here we'll limit our support 98 * to these transports. 99 */ 100 char *ipv4_netids[] = { 101 "tcp", 102 "udp", 103 NULL 104 }; 105 106 for (i = 0; ipv4_netids[i] != NULL; i++) { 107 if (strcmp(ipv4_netids[i], config->nc_netid) == 0) 108 return (1); 109 } 110 return (0); 111 } 112 113 /* 114 * Public nametoaddr library interfaces. 115 * 116 * These are the functional entry points that libnsl will lookup (via 117 * the symbol names) when it loads this nametoaddr translation library. 118 */ 119 120 /* 121 * _netdir_getbyname() returns all of the addresses for 122 * a specified host and service. 123 */ 124 struct nd_addrlist * 125 _netdir_getbyname(struct netconfig *netconfigp, 126 struct nd_hostserv *nd_hostservp) 127 { 128 struct nd_addrlist *rp = NULL; 129 struct netbuf *nbp = NULL; 130 struct sockaddr_in *sap = NULL; 131 struct hostent n2h_result; 132 struct servent n2s_result; 133 char *n2h_buf = NULL, *n2s_buf = NULL; 134 int h_errno, i, host_self = 0, r_count; 135 int n2h_count = 0, n2s_count = 0; 136 137 lxt_debug("_netdir_getbyname: request recieved\n"); 138 139 /* Make sure this is an ipv4 request. */ 140 if (!netconfig_is_ipv4(netconfigp)) { 141 _nderror = ND_BADARG; 142 goto fail; 143 } 144 145 /* Allocate memory for the queries. */ 146 if (((n2h_buf = malloc(NSS_BUFLEN_HOSTS)) == NULL) || 147 ((n2s_buf = malloc(NSS_BUFLEN_SERVICES)) == NULL)) 148 goto malloc_fail; 149 150 /* Check if the host name specified is HOST_SELF. */ 151 if (strcmp(nd_hostservp->h_host, HOST_SELF) == 0) 152 host_self = 1; 153 154 /* 155 * If the hostname specified is HOST_SELF, the we're just 156 * just doing a service lookup so don't bother with trying 157 * to lookup the host name. 158 */ 159 if (!host_self) { 160 /* Resolve the hostname. */ 161 lxt_debug("_netdir_getbyname: " 162 "resolving host name: %s\n", nd_hostservp->h_host); 163 if (lxt_gethostbyname_r(nd_hostservp->h_host, &n2h_result, 164 n2h_buf, NSS_BUFLEN_HOSTS, &h_errno) == NULL) { 165 if (errno == ERANGE) { 166 _nderror = ND_SYSTEM; 167 } else if (h_errno == HOST_NOT_FOUND) { 168 _nderror = ND_NOHOST; 169 } else if (h_errno == TRY_AGAIN) { 170 _nderror = ND_TRY_AGAIN; 171 } else if (h_errno == NO_RECOVERY) { 172 _nderror = ND_NO_RECOVERY; 173 } else if (h_errno == NO_DATA) { 174 _nderror = ND_NO_DATA; 175 } else { 176 _nderror = ND_SYSTEM; 177 } 178 goto fail; 179 } 180 while (n2h_result.h_addr_list[n2h_count++] != NULL); 181 n2h_count--; 182 } 183 184 if (nd_hostservp->h_serv != NULL) { 185 /* Resolve the service name */ 186 lxt_debug("_netdir_getbyname: " 187 "resolving service name: %s\n", nd_hostservp->h_serv); 188 if (lxt_getservbyname_r(nd_hostservp->h_serv, 189 netconfigp->nc_proto, &n2s_result, 190 n2s_buf, NSS_BUFLEN_SERVICES) == NULL) { 191 _nderror = ND_SYSTEM; 192 goto fail; 193 } 194 n2s_count = 1; 195 } 196 197 /* Make sure we got some results. */ 198 if ((n2h_count + n2s_count) == 0) { 199 lxt_debug("_netdir_getbyname: no results!\n"); 200 goto exit; 201 } 202 r_count = (n2h_count != 0) ? n2h_count : 1; 203 204 /* 205 * Allocate the return buffers. These buffers will be free'd 206 * by libnsl`netdir_free(), so we need to allocate them in the 207 * way that libnsl`netdir_free() expects. 208 */ 209 if (((rp = calloc(1, sizeof (struct nd_addrlist))) == NULL) || 210 ((nbp = calloc(1, sizeof (struct netbuf) * r_count)) == NULL) || 211 ((sap = calloc(1, sizeof (struct sockaddr_in) * r_count)) == NULL)) 212 goto malloc_fail; 213 214 /* Initialize the structures we're going to return. */ 215 rp->n_cnt = r_count; 216 rp->n_addrs = nbp; 217 for (i = 0; i < r_count; i++) { 218 219 /* Initialize the netbuf. */ 220 nbp[i].maxlen = nbp[i].len = sizeof (struct sockaddr_in); 221 nbp[i].buf = (char *)&sap[i]; 222 223 /* Initialize the sockaddr_in. */ 224 sap[i].sin_family = AF_INET; 225 226 /* If we looked up any host address copy them out. */ 227 if (!host_self) 228 bcopy(n2h_result.h_addr_list[i], &sap[i].sin_addr, 229 sizeof (sap[i].sin_addr)); 230 231 /* If we looked up any service ports copy them out. */ 232 if (nd_hostservp->h_serv != NULL) 233 sap[i].sin_port = n2s_result.s_port; 234 } 235 236 /* We're finally done. */ 237 lxt_debug("_netdir_getbyname: success\n"); 238 return (rp); 239 240 malloc_fail: 241 _nderror = ND_NOMEM; 242 243 fail: 244 lxt_debug("_netdir_getbyname: failed!\n"); 245 246 exit: 247 if (n2h_buf == NULL) 248 free(n2h_buf); 249 if (n2s_buf == NULL) 250 free(n2s_buf); 251 if (rp == NULL) 252 free(rp); 253 if (nbp == NULL) 254 free(nbp); 255 if (sap == NULL) 256 free(sap); 257 return (NULL); 258 } 259 260 /* 261 * _netdir_getbyaddr() takes an address (hopefully obtained from 262 * someone doing a _netdir_getbyname()) and returns all hosts with 263 * that address. 264 */ 265 struct nd_hostservlist * 266 /*ARGSUSED*/ 267 _netdir_getbyaddr(struct netconfig *netconfigp, struct netbuf *nbp) 268 { 269 struct nd_hostservlist *rp = NULL; 270 struct nd_hostserv *hsp = NULL; 271 struct sockaddr_in *sap; 272 struct servent p2s_result; 273 struct hostent a2h_result; 274 char *a2h_buf = NULL, *p2s_buf = NULL; 275 int h_errno, r_count, i; 276 int a2h_count = 0, p2s_count = 0; 277 278 lxt_debug("_netdir_getbyaddr: request recieved\n"); 279 280 /* Make sure this is an ipv4 request. */ 281 if (!netconfig_is_ipv4(netconfigp)) { 282 _nderror = ND_BADARG; 283 goto fail; 284 } 285 286 /* 287 * Make sure the netbuf contains one struct sockaddr_in of 288 * type AF_INET. 289 */ 290 if ((nbp->len != sizeof (struct sockaddr_in)) || 291 (nbp->len < nbp->maxlen)) { 292 _nderror = ND_BADARG; 293 goto fail; 294 } 295 /*LINTED*/ 296 sap = (struct sockaddr_in *)nbp->buf; 297 if (sap->sin_family != AF_INET) { 298 _nderror = ND_BADARG; 299 goto fail; 300 } 301 302 /* Allocate memory for the queries. */ 303 if (((a2h_buf = malloc(NSS_BUFLEN_HOSTS)) == NULL) || 304 ((p2s_buf = malloc(NSS_BUFLEN_SERVICES)) == NULL)) 305 goto malloc_fail; 306 307 if (sap->sin_addr.s_addr != INADDR_ANY) { 308 lxt_debug("_netdir_getbyaddr: " 309 "resolving host address: 0x%x\n", sap->sin_addr.s_addr); 310 if (lxt_gethostbyaddr_r((char *)&sap->sin_addr.s_addr, 311 sizeof (sap->sin_addr.s_addr), AF_INET, 312 &a2h_result, a2h_buf, NSS_BUFLEN_HOSTS, 313 &h_errno) == NULL) { 314 if (errno == ERANGE) { 315 _nderror = ND_SYSTEM; 316 } else if (h_errno == HOST_NOT_FOUND) { 317 _nderror = ND_NOHOST; 318 } else if (h_errno == TRY_AGAIN) { 319 _nderror = ND_TRY_AGAIN; 320 } else if (h_errno == NO_RECOVERY) { 321 _nderror = ND_NO_RECOVERY; 322 } else if (h_errno == NO_DATA) { 323 _nderror = ND_NO_DATA; 324 } else { 325 _nderror = ND_SYSTEM; 326 } 327 goto fail; 328 } 329 while (a2h_result.h_aliases[a2h_count++] != NULL); 330 /* 331 * We need to count a2h_result.h_name as a valid name for 332 * for the address we just looked up. Of course a2h_count 333 * is actually over estimated by one, so instead of 334 * decrementing it here we'll just leave it as it to 335 * account for a2h_result.h_name. 336 */ 337 } 338 339 if (sap->sin_port != 0) { 340 lxt_debug("_netdir_getbyaddr: " 341 "resolving service port: 0x%x\n", sap->sin_port); 342 if (lxt_getservbyport_r(sap->sin_port, 343 netconfigp->nc_proto, &p2s_result, 344 p2s_buf, NSS_BUFLEN_SERVICES) == NULL) { 345 _nderror = ND_SYSTEM; 346 goto fail; 347 } 348 p2s_count = 1; 349 } 350 351 /* Make sure we got some results. */ 352 if ((a2h_count + p2s_count) == 0) { 353 lxt_debug("_netdir_getbyaddr: no results!\n"); 354 goto exit; 355 } 356 r_count = (a2h_count != 0) ? a2h_count : 1; 357 358 /* 359 * Allocate the return buffers. These buffers will be free'd 360 * by libnsl`netdir_free(), so we need to allocate them in the 361 * way that libnsl`netdir_free() expects. 362 */ 363 if (((rp = calloc(1, sizeof (struct nd_hostservlist))) == NULL) || 364 ((hsp = calloc(1, sizeof (struct nd_hostserv) * r_count)) == NULL)) 365 goto malloc_fail; 366 367 lxt_debug("_netdir_getbyaddr: hahaha0 - %d\n", r_count); 368 rp->h_cnt = r_count; 369 rp->h_hostservs = hsp; 370 for (i = 0; i < r_count; i++) { 371 /* If we looked up any host names copy them out. */ 372 lxt_debug("_netdir_getbyaddr: hahaha1 - %d\n", r_count); 373 if ((a2h_count > 0) && (i == 0) && 374 ((hsp[i].h_host = strdup(a2h_result.h_name)) == NULL)) 375 goto malloc_fail; 376 377 if ((a2h_count > 0) && (i > 0) && 378 ((hsp[i].h_host = 379 strdup(a2h_result.h_aliases[i - 1])) == NULL)) 380 goto malloc_fail; 381 382 lxt_debug("_netdir_getbyaddr: hahaha2 - %d\n", r_count); 383 /* If we looked up any service names copy them out. */ 384 if ((p2s_count > 0) && 385 ((hsp[i].h_serv = strdup(p2s_result.s_name)) == NULL)) 386 goto malloc_fail; 387 lxt_debug("_netdir_getbyaddr: hahaha3 - %d\n", r_count); 388 } 389 390 /* We're finally done. */ 391 lxt_debug("_netdir_getbyaddr: success\n"); 392 return (rp); 393 394 malloc_fail: 395 _nderror = ND_NOMEM; 396 397 fail: 398 lxt_debug("_netdir_getbyaddr: failed!\n"); 399 400 exit: 401 if (a2h_buf == NULL) 402 free(a2h_buf); 403 if (p2s_buf == NULL) 404 free(p2s_buf); 405 if (rp == NULL) 406 free(rp); 407 if (hsp != NULL) { 408 for (i = 0; i < r_count; i++) { 409 if (hsp[i].h_host != NULL) 410 free(hsp[i].h_host); 411 if (hsp[i].h_serv != NULL) 412 free(hsp[i].h_serv); 413 } 414 free(hsp); 415 } 416 return (NULL); 417 } 418 419 char * 420 /* ARGSUSED */ 421 _taddr2uaddr(struct netconfig *netconfigp, struct netbuf *nbp) 422 { 423 extern char *inet_ntoa_r(); 424 425 struct sockaddr_in *sa; 426 char tmp[RPC_INET6_MAXUADDRSIZE]; 427 unsigned short myport; 428 429 if (netconfigp == NULL || nbp == NULL || nbp->buf == NULL) { 430 _nderror = ND_BADARG; 431 return (NULL); 432 } 433 434 if (strcmp(netconfigp->nc_protofmly, NC_INET) != 0) { 435 /* we only support inet address translation */ 436 assert(0); 437 _nderror = ND_SYSTEM; 438 return (NULL); 439 } 440 441 /* LINTED pointer cast */ 442 sa = (struct sockaddr_in *)(nbp->buf); 443 myport = ntohs(sa->sin_port); 444 (void) inet_ntoa_r(sa->sin_addr, tmp); 445 446 (void) sprintf(tmp + strlen(tmp), ".%d.%d", 447 myport >> 8, myport & 255); 448 return (strdup(tmp)); /* Doesn't return static data ! */ 449 } 450 451 /* 452 * _uaddr2taddr() translates a universal address back into a 453 * netaddr structure. Since the universal address is a string, 454 * put that into the TLI buffer (making sure to change all \ddd 455 * characters back and strip off the trailing \0 character). 456 */ 457 struct netbuf * 458 /* ARGSUSED */ 459 _uaddr2taddr(struct netconfig *netconfigp, char *uaddr) 460 { 461 assert(0); 462 _nderror = ND_SYSTEM; 463 return (NULL); 464 } 465 466 /* 467 * _netdir_options() is a "catch-all" routine that does 468 * transport specific things. The only thing that these 469 * routines have to worry about is ND_MERGEADDR. 470 */ 471 int 472 /* ARGSUSED */ 473 _netdir_options(struct netconfig *netconfigp, int option, int fd, void *par) 474 { 475 assert(0); 476 _nderror = ND_SYSTEM; 477 return (0); 478 }