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, i;
 276         int                     r_count = 0;
 277         int                     a2h_count = 0, p2s_count = 0;
 278 
 279         lxt_debug("_netdir_getbyaddr: request recieved\n");
 280 
 281         /* Make sure this is an ipv4 request. */
 282         if (!netconfig_is_ipv4(netconfigp)) {
 283                 _nderror = ND_BADARG;
 284                 goto fail;
 285         }
 286 
 287         /*
 288          * Make sure the netbuf contains one struct sockaddr_in of
 289          * type AF_INET.
 290          */
 291         if ((nbp->len != sizeof (struct sockaddr_in)) ||
 292             (nbp->len < nbp->maxlen)) {
 293                 _nderror = ND_BADARG;
 294                 goto fail;
 295         }
 296         /*LINTED*/
 297         sap = (struct sockaddr_in *)nbp->buf;
 298         if (sap->sin_family != AF_INET) {
 299                 _nderror = ND_BADARG;
 300                 goto fail;
 301         }
 302 
 303         /* Allocate memory for the queries. */
 304         if (((a2h_buf = malloc(NSS_BUFLEN_HOSTS)) == NULL) ||
 305             ((p2s_buf = malloc(NSS_BUFLEN_SERVICES)) == NULL))
 306                 goto malloc_fail;
 307 
 308         if (sap->sin_addr.s_addr != INADDR_ANY) {
 309                 lxt_debug("_netdir_getbyaddr: "
 310                     "resolving host address: 0x%x\n", sap->sin_addr.s_addr);
 311                 if (lxt_gethostbyaddr_r((char *)&sap->sin_addr.s_addr,
 312                     sizeof (sap->sin_addr.s_addr), AF_INET,
 313                     &a2h_result, a2h_buf, NSS_BUFLEN_HOSTS,
 314                     &h_errno) == NULL) {
 315                         if (errno == ERANGE) {
 316                                 _nderror = ND_SYSTEM;
 317                         } else if (h_errno == HOST_NOT_FOUND) {
 318                                 _nderror = ND_NOHOST;
 319                         } else if (h_errno == TRY_AGAIN) {
 320                                 _nderror = ND_TRY_AGAIN;
 321                         } else if (h_errno == NO_RECOVERY) {
 322                                 _nderror = ND_NO_RECOVERY;
 323                         } else if (h_errno == NO_DATA) {
 324                                 _nderror = ND_NO_DATA;
 325                         } else {
 326                                 _nderror = ND_SYSTEM;
 327                         }
 328                         goto fail;
 329                 }
 330                 while (a2h_result.h_aliases[a2h_count++] != NULL);
 331                 /*
 332                  * We need to count a2h_result.h_name as a valid name for
 333                  * for the address we just looked up.  Of course a2h_count
 334                  * is actually over estimated by one, so instead of
 335                  * decrementing it here we'll just leave it as it to
 336                  * account for a2h_result.h_name.
 337                  */
 338         }
 339 
 340         if (sap->sin_port != 0) {
 341                 lxt_debug("_netdir_getbyaddr: "
 342                     "resolving service port: 0x%x\n", sap->sin_port);
 343                 if (lxt_getservbyport_r(sap->sin_port,
 344                     netconfigp->nc_proto, &p2s_result,
 345                     p2s_buf, NSS_BUFLEN_SERVICES) == NULL) {
 346                         _nderror = ND_SYSTEM;
 347                         goto fail;
 348                 }
 349                 p2s_count = 1;
 350         }
 351 
 352         /* Make sure we got some results. */
 353         if ((a2h_count + p2s_count) == 0) {
 354                 lxt_debug("_netdir_getbyaddr: no results!\n");
 355                 goto exit;
 356         }
 357         r_count = (a2h_count != 0) ? a2h_count : 1;
 358 
 359         /*
 360          * Allocate the return buffers.  These buffers will be free'd
 361          * by libnsl`netdir_free(), so we need to allocate them in the
 362          * way that libnsl`netdir_free() expects.
 363          */
 364         if (((rp = calloc(1, sizeof (struct nd_hostservlist))) == NULL) ||
 365             ((hsp = calloc(1, sizeof (struct nd_hostserv) * r_count)) == NULL))
 366                 goto malloc_fail;
 367 
 368         lxt_debug("_netdir_getbyaddr: hahaha0 - %d\n", r_count);
 369         rp->h_cnt = r_count;
 370         rp->h_hostservs = hsp;
 371         for (i = 0; i < r_count; i++) {
 372                 /* If we looked up any host names copy them out. */
 373         lxt_debug("_netdir_getbyaddr: hahaha1 - %d\n", r_count);
 374                 if ((a2h_count > 0) && (i == 0) &&
 375                     ((hsp[i].h_host = strdup(a2h_result.h_name)) == NULL))
 376                         goto malloc_fail;
 377 
 378                 if ((a2h_count > 0) && (i > 0) &&
 379                     ((hsp[i].h_host =
 380                             strdup(a2h_result.h_aliases[i - 1])) == NULL))
 381                         goto malloc_fail;
 382 
 383         lxt_debug("_netdir_getbyaddr: hahaha2 - %d\n", r_count);
 384                 /* If we looked up any service names copy them out. */
 385                 if ((p2s_count > 0) &&
 386                     ((hsp[i].h_serv = strdup(p2s_result.s_name)) == NULL))
 387                         goto malloc_fail;
 388         lxt_debug("_netdir_getbyaddr: hahaha3 - %d\n", r_count);
 389         }
 390 
 391         /* We're finally done. */
 392         lxt_debug("_netdir_getbyaddr: success\n");
 393         return (rp);
 394 
 395 malloc_fail:
 396         _nderror = ND_NOMEM;
 397 
 398 fail:
 399         lxt_debug("_netdir_getbyaddr: failed!\n");
 400 
 401 exit:
 402         if (a2h_buf == NULL)
 403                 free(a2h_buf);
 404         if (p2s_buf == NULL)
 405                 free(p2s_buf);
 406         if (rp == NULL)
 407                 free(rp);
 408         if (hsp != NULL) {
 409                 for (i = 0; i < r_count; i++) {
 410                         if (hsp[i].h_host != NULL)
 411                                 free(hsp[i].h_host);
 412                         if (hsp[i].h_serv != NULL)
 413                                 free(hsp[i].h_serv);
 414                 }
 415                 free(hsp);
 416         }
 417         return (NULL);
 418 }
 419 
 420 char *
 421 /* ARGSUSED */
 422 _taddr2uaddr(struct netconfig *netconfigp, struct netbuf *nbp)
 423 {
 424         extern char             *inet_ntoa_r();
 425 
 426         struct sockaddr_in      *sa;
 427         char                    tmp[RPC_INET6_MAXUADDRSIZE];
 428         unsigned short          myport;
 429 
 430         if (netconfigp == NULL || nbp == NULL || nbp->buf == NULL) {
 431                 _nderror = ND_BADARG;
 432                 return (NULL);
 433         }
 434 
 435         if (strcmp(netconfigp->nc_protofmly, NC_INET) != 0) {
 436                 /* we only support inet address translation */
 437                 assert(0);
 438                 _nderror = ND_SYSTEM;
 439                 return (NULL);
 440         }
 441 
 442         /* LINTED pointer cast */
 443         sa = (struct sockaddr_in *)(nbp->buf);
 444         myport = ntohs(sa->sin_port);
 445         (void) inet_ntoa_r(sa->sin_addr, tmp);
 446 
 447         (void) sprintf(tmp + strlen(tmp), ".%d.%d",
 448             myport >> 8, myport & 255);
 449         return (strdup(tmp));   /* Doesn't return static data ! */
 450 }
 451 
 452 /*
 453  * _uaddr2taddr() translates a universal address back into a
 454  * netaddr structure.  Since the universal address is a string,
 455  * put that into the TLI buffer (making sure to change all \ddd
 456  * characters back and strip off the trailing \0 character).
 457  */
 458 struct netbuf *
 459 /* ARGSUSED */
 460 _uaddr2taddr(struct netconfig *netconfigp, char *uaddr)
 461 {
 462         assert(0);
 463         _nderror = ND_SYSTEM;
 464         return (NULL);
 465 }
 466 
 467 /*
 468  * _netdir_options() is a "catch-all" routine that does
 469  * transport specific things.  The only thing that these
 470  * routines have to worry about is ND_MERGEADDR.
 471  */
 472 int
 473 /* ARGSUSED */
 474 _netdir_options(struct netconfig *netconfigp, int option, int fd, void *par)
 475 {
 476         assert(0);
 477         _nderror = ND_SYSTEM;
 478         return (0);
 479 }