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 }