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 2008 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  * The BrandZ Linux thunking library.
  31  *
  32  * The interfaces defined in this file form the client side of a bridge
  33  * to allow native Solaris process to access Linux services.  Currently
  34  * the Linux services that is made accessible by these interfaces here
  35  * are:
  36  *      - Linux host <-> address naming services
  37  *      - Linux service <-> port naming services
  38  *      - Linux syslog
  39  *
  40  * Currently, to use this library it must be LD_PRELOADed into the
  41  * application that needs to access Linux services.  Once loaded
  42  * Linux services are accessed by the client application in two
  43  * different ways:
  44  *
  45  * - Direct library calls:
  46  *      lxt_gethostbyname_r
  47  *      lxt_gethostbyaddr_r
  48  *      lxt_getservbyname_r
  49  *      lxt_getservbyport_r
  50  *      lxt_debug
  51  *
  52  *   These library functions are used by the BrandZ lx name services
  53  *   translation library (lx_nametoaddr.so) to handle libnsl.so name
  54  *   service requests.
  55  *
  56  * - Intercepted library calls:
  57  *      openlog(3c)
  58  *      syslog(3c)
  59  *      vsyslog(3c)
  60  *      closelog(3c)
  61  *
  62  *   Via the LD_PRELOAD mechanism this library interposes itself on
  63  *   these interfaces and when the application calls these interfaces
  64  *   (either directly or indirectly via any libraries the program may
  65  *   be linked against) this library intercepts the request and passes
  66  *   it onto a Linux process to handle the request.
  67  *
  68  * Once this library receives a request that needs to be serviced by a
  69  * Linux process, it packs up that request and attempts to send it
  70  * to a doors server.  The door server interfaces are defined in
  71  * lx_thunk_server.h.  If the doors server is not running or not
  72  * responding, this library will attempt to spawn a new doors server
  73  * by forking and executing the following shell script (which runs as
  74  * a native /bin/sh Linux process):
  75  *      /native/usr/lib/brand/lx/lx_thunk
  76  *
  77  * Notes:
  78  * - This library also intercepts the following system calls:
  79  *      close(2) - We intercept close(2) to prevent the caller from
  80  *              accidentally closing any of the file descriptors we
  81  *              need to do our work.
  82  *
  83  *      setppriv(2) - We intercept setppriv(2) to prevent a process
  84  *              from dropping any of the privileges we'll need to create
  85  *              a new lx_thunk server process and to deal with service
  86  *              requests.
  87  *
  88  * - To facilitate the running of native Solaris programs and libraries
  89  *   when this library is preloaded into an application it will chroot()
  90  *   into /native.  This way the Solaris application and libraries can
  91  *   access files via their expected paths and we can avoid having to
  92  *   either do path mapping or modifying all libraries to make them
  93  *   aware of "/native" so that they can pre-pend it to all their
  94  *   filesystem operations.
  95  *
  96  * - This library can only be used with processes that are initially
  97  *   run by root in a zone.  The reason is that we use the chroot()
  98  *   system call and this requires the PRIV_PROC_CHROOT privilege,
  99  *   which non-root users don't have.
 100  */
 101 
 102 #include <alloca.h>
 103 #include <assert.h>
 104 #include <dlfcn.h>
 105 #include <door.h>
 106 #include <errno.h>
 107 #include <fcntl.h>
 108 #include <netdb.h>
 109 #include <netdir.h>
 110 #include <priv.h>
 111 #include <stdarg.h>
 112 #include <stdio.h>
 113 #include <stdlib.h>
 114 #include <string.h>
 115 #include <strings.h>
 116 #include <synch.h>
 117 #include <sys/brand.h>
 118 #include <sys/fcntl.h>
 119 #include <sys/lx_thunk_server.h>
 120 #include <sys/lx_thunk.h>
 121 #include <sys/mman.h>
 122 #include <sys/priv_impl.h>
 123 #include <sys/stat.h>
 124 #include <sys/syscall.h>
 125 #include <sys/types.h>
 126 #include <sys/wait.h>
 127 #include <thread.h>
 128 #include <unistd.h>
 129 #include <sys/varargs.h>
 130 
 131 #define LXT_DOOR_DIR            "/tmp"
 132 #define LXT_DOOR_PREFIX         "lxt"
 133 #define LXT_MSG_MAXLEN          (128 + MAXPATHLEN)
 134 
 135 #pragma init(init)
 136 
 137 typedef uintptr_t (*fp1_t)(uintptr_t);
 138 typedef uintptr_t (*fp3_t)(uintptr_t, uintptr_t, uintptr_t);
 139 
 140 static char     *lxt_debug_path = NULL;         /* debug output file path */
 141 static char     lxt_debug_path_buf[MAXPATHLEN];
 142 static int      root_fd;
 143 static int      debug_fd = -1;
 144 
 145 void lxt_debug(const char *msg, ...);
 146 
 147 void
 148 init(void)
 149 {
 150         if (getenv("LX_DEBUG") != NULL) {
 151 
 152                 /* check if there's a debug log file specified */
 153                 lxt_debug_path = getenv("LX_DEBUG_FILE");
 154                 if (lxt_debug_path == NULL) {
 155                         /* send all debugging output to /dev/tty */
 156                         lxt_debug_path = "/dev/tty";
 157                 }
 158 
 159                 (void) strlcpy(lxt_debug_path_buf, lxt_debug_path,
 160                     sizeof (lxt_debug_path_buf));
 161                 lxt_debug_path = lxt_debug_path_buf;
 162 
 163                 /*
 164                  * Open the debugging output file.  We need to open it
 165                  * and hold it open because we're going to call chroot()
 166                  * in just a second, so we won't be able to open it later.
 167                  */
 168                 if ((debug_fd = open(lxt_debug_path,
 169                     O_WRONLY|O_APPEND|O_CREAT|O_NDELAY|O_NOCTTY,
 170                     0666)) != -1) {
 171                         (void) fchmod(debug_fd, 0666);
 172                 }
 173         }
 174         lxt_debug("lxt_init: executing native process");
 175 
 176         /* Get a fd that points to the root directory */
 177         if ((root_fd = open("/", O_RDONLY)) < 0) {
 178                 lxt_debug("lxt_init(): "
 179                     "failed to open root directory: %s", strerror(errno));
 180                 exit(-1);
 181         }
 182 
 183         /*
 184          * Now, so that we can avoid having to do path mapping,
 185          * just chdir() and chroot() into /native.
 186          */
 187         if (chdir("/native") != 0) {
 188                 lxt_debug("lxt_init(): "
 189                     "failed to chdir to /native: %s", strerror(errno));
 190                 exit(-1);
 191         }
 192         if (chroot("/native") != 0) {
 193                 lxt_debug("lxt_init(): "
 194                     "failed to chroot to /native: %s", strerror(errno));
 195                 exit(-1);
 196         }
 197 }
 198 
 199 /*
 200  * Linux Thunking Interfaces - Client Side
 201  */
 202 static mutex_t  lxt_door_lock = DEFAULTMUTEX;
 203 static int      lxt_door_fd = -1;
 204 
 205 static void
 206 lxt_server_exec(int fifo_wr, int fifo_rd)
 207 {
 208         extern const char       **environ;
 209         char                    *nullist[] = { NULL };
 210 
 211         lxt_debug("lxt_server_exec: server starting");
 212 
 213         /*
 214          * First we need to dup our fifos to the file descriptors
 215          * the brand library is expecting them to be at.
 216          */
 217 
 218         /* Check if the write fifo needs to be moved aside */
 219         if ((fifo_wr == LXT_SERVER_FIFO_RD_FD) &&
 220             ((fifo_wr = dup(fifo_wr)) < 0))
 221                 return;
 222 
 223         /* Check if the read fifo needs to be moved aside */
 224         if ((fifo_rd == LXT_SERVER_FIFO_WR_FD) &&
 225             ((fifo_rd = dup(fifo_rd)) < 0))
 226                 return;
 227 
 228         if ((fifo_wr != LXT_SERVER_FIFO_WR_FD) &&
 229             (dup2(fifo_wr, LXT_SERVER_FIFO_WR_FD) < 0))
 230                 return;
 231         if ((fifo_rd != LXT_SERVER_FIFO_RD_FD) &&
 232             (dup2(fifo_rd, LXT_SERVER_FIFO_RD_FD) < 0))
 233                 return;
 234 
 235         /*
 236          * We're about to execute a native Linux process.
 237          * Since we've been loaded into a Solaris process with
 238          * LD_PRELOAD and LD_LIBRARY_PATH we should clear these
 239          * variables from the environment before calling exec.
 240          */
 241         (void) unsetenv("LD_PRELOAD");
 242         (void) unsetenv("LD_LIBRARY_PATH");
 243 
 244         /*
 245          * Now we need to exec the thunk server process.  This is a
 246          * branded Linux process that will act as a doors server and
 247          * service our requests to perform native Linux operations.
 248          * Since we're currently running as a native Solaris process
 249          * to start up the server we'll use the brand system call to
 250          * the kernel that the target of the exec will be a branded
 251          * process.
 252          */
 253         lxt_debug("lxt_server_exec: execing as Linux process");
 254         (void) syscall(SYS_brand, B_EXEC_BRAND,
 255             LXT_SERVER_BINARY, nullist, environ);
 256 }
 257 
 258 
 259 static void *
 260 lxt_door_waitpid(void *arg)
 261 {
 262         pid_t   child_pid = (pid_t)(uintptr_t)arg;
 263         int     stat;
 264 
 265         (void) waitpid(child_pid, &stat, 0);
 266         return (NULL);
 267 }
 268 
 269 static char *
 270 lxt_door_mkfifo()
 271 {
 272         char    *path;
 273 
 274         for (;;) {
 275                 path = tempnam(LXT_DOOR_DIR, LXT_DOOR_PREFIX);
 276                 if (path == NULL)
 277                         return (NULL);
 278                 if (mkfifo(path, S_IWUSR | S_IRUSR) != 0) {
 279                         if (errno != EEXIST) {
 280                                 free(path);
 281                                 return (NULL);
 282                         }
 283                         /* This file path exists, pick a new name. */
 284                         free(path);
 285                         continue;
 286                 }
 287                 /* We successfully created the fifo */
 288                 break;
 289         }
 290         return (path);
 291 }
 292 
 293 static void
 294 lxt_door_init()
 295 {
 296         char            *fifo1_path = NULL, *fifo2_path = NULL;
 297         char            fifo1_path_native[MAXPATHLEN];
 298         int             fifo1_rd = -1, fifo1_wr = -1;
 299         int             fifo2_rd = -1, fifo2_wr = -1;
 300         int             junk;
 301         pid_t           child_pid;
 302         thread_t        tid;
 303 
 304         lxt_debug("lxt_door_init: preparint to start server");
 305 
 306         /* Create two new fifos. */
 307         if (((fifo1_path = lxt_door_mkfifo()) == NULL) ||
 308             ((fifo2_path = lxt_door_mkfifo()) == NULL))
 309                 goto fail;
 310 
 311         (void) snprintf(fifo1_path_native, sizeof (fifo1_path_native),
 312             "/native%s", fifo1_path);
 313 
 314         /*
 315          * Open both fifos for reading and writing.  We have to open
 316          * the read side of the fifo first (because the write side will
 317          * fail to open if there is no reader) and we have to use the
 318          * O_NONBLOCK flag (because the read open with hang without it).
 319          */
 320         if (((fifo1_rd = open(fifo1_path, O_RDONLY | O_NONBLOCK)) < 0) ||
 321             ((fifo1_wr = open(fifo1_path, O_WRONLY)) < 0) ||
 322             ((fifo2_rd = open(fifo2_path, O_RDONLY | O_NONBLOCK)) < 0) ||
 323             ((fifo2_wr = open(fifo2_path, O_WRONLY)) < 0))
 324                 goto fail;
 325 
 326         /*
 327          * Now we have to close the read side of fifo1 and fifo2 and re-open
 328          * them without the O_NONBLOCK flag.  This is because we're using
 329          * the fifos for synchronization and when we actually try to read
 330          * from them we want to block.
 331          */
 332         (void) close(fifo1_rd);
 333         if ((fifo1_rd = open(fifo1_path, O_RDONLY)) < 0)
 334                 goto fail;
 335         (void) close(fifo2_rd);
 336         if ((fifo2_rd = open(fifo2_path, O_RDONLY)) < 0)
 337                 goto fail;
 338 
 339         /*
 340          * Once fifo2 is opened no one will ever need to open it again
 341          * so delete it now.
 342          */
 343         (void) unlink(fifo2_path);
 344         free(fifo2_path);
 345         fifo2_path = NULL;
 346 
 347         /* Attempt to fork and start the door server */
 348         lxt_debug("lxt_door_init: starting server");
 349         switch (child_pid = fork1()) {
 350         case -1:
 351                 /* fork1() failed. */
 352                 goto fail;
 353         case 0:
 354                 /* Child process - new door server. */
 355                 (void) close(fifo1_rd);
 356                 (void) close(fifo2_wr);
 357 
 358                 /* Need to chroot back to the real root directory */
 359                 if (fchroot(root_fd) != 0) {
 360                         lxt_debug("lxt_server_exec: "
 361                             "failed fchroot(\"/\"): %s", strerror(errno));
 362                         exit(-1);
 363                 }
 364                 (void) close(root_fd);
 365 
 366                 /* Start the server */
 367                 lxt_server_exec(fifo1_wr, fifo2_rd);
 368                 lxt_debug("lxt_server_exec: server init failed");
 369                 exit(-1);
 370                 /*NOTREACHED*/
 371         }
 372         /* Parent process - door client. */
 373 
 374         /*
 375          * fifo2 is used to send the door path to the child.
 376          * (We can't simply pass it via the address space since the
 377          * child will need to exec.)  We'll write the name of the door
 378          * file to fifo2 before we close the read end of the fifo2 so
 379          * that if the child has exited for some reason we won't get
 380          * a SIGPIPE.  Note that we're reusing the name of fifo1 as
 381          * the door path.  Also note that we've pre-pended /native
 382          * to the fifo/door path.  The reason is that we're chroot'ed
 383          * to /native, but when the thunking server executes it will
 384          * be chroot'ed back to the real root directory.
 385          */
 386         (void) write(fifo2_wr,
 387             fifo1_path_native, strlen(fifo1_path_native) + 1);
 388         (void) close(fifo2_wr);
 389         (void) close(fifo2_rd);
 390 
 391         /*
 392          * Start up a thread that will perfom a waitpid() on the child
 393          * door server process.  We do this because if the calling
 394          * application that is using our interfaces is forking it's own
 395          * children and using wait(), then it won't expect to see our
 396          * children.  We take advantage of the fact that if there are
 397          * wait() and a waitpid() calls in progress at the same time
 398          * when a child exists,  preference will be given to any
 399          * waitpid() calls that are explicity waiting for that child.
 400          * There is of course a window of time where the child could
 401          * exit after we've forked it but before we've called waitpid()
 402          * where another wait() in this process could collect the result.
 403          * There's nothing we can really do to prevent this short of
 404          * stopping all the other threads in this process.
 405          */
 406         (void) thr_create(NULL, 0,
 407             lxt_door_waitpid, (void *)(uintptr_t)child_pid, THR_DAEMON, &tid);
 408 
 409         /*
 410          * fifo1 is used for the child process to signal us that the
 411          * door server is ready to take requests.
 412          */
 413         (void) close(fifo1_wr);
 414         (void) read(fifo1_rd, &junk, 1);
 415         (void) close(fifo1_rd);
 416 
 417         /* If there was a door that was open, close it now. */
 418 
 419         if (lxt_door_fd >= 0)
 420                 (void) close(lxt_door_fd);
 421         /*
 422          * The server should be started up by now and fattach()ed the door
 423          * server to the fifo/door path.  so if we re-open that path now we
 424          * should get a fd to the door server.
 425          */
 426         lxt_door_fd = open(fifo1_path, O_RDWR);
 427 
 428         lxt_debug("lxt_door_init: new server door = %d", lxt_door_fd);
 429 
 430         /* We don't need the fifo/door anymore so delete it. */
 431         (void) unlink(fifo1_path);
 432         free(fifo1_path);
 433         return;
 434 
 435 fail:
 436         if (fifo1_path != NULL)
 437                 (void) unlink(fifo1_path);
 438         if (fifo2_path != NULL)
 439                 (void) unlink(fifo2_path);
 440         if (fifo1_rd != -1)
 441                 (void) close(fifo1_rd);
 442         if (fifo1_wr != -1)
 443                 (void) close(fifo1_wr);
 444         if (fifo2_rd != -1)
 445                 (void) close(fifo2_rd);
 446         if (fifo2_wr != -1)
 447                 (void) close(fifo2_wr);
 448 }
 449 
 450 static int
 451 lxt_door_call(door_arg_t *door_arg, int lock_held)
 452 {
 453         int fd;
 454 
 455         if (!lock_held)
 456                 (void) mutex_lock(&lxt_door_lock);
 457 
 458         /* Get a copy of lxt_door_fd */
 459         fd = lxt_door_fd;
 460 
 461         if (!lock_held)
 462                 (void) mutex_unlock(&lxt_door_lock);
 463 
 464         if (fd == -1) {
 465                 lxt_debug("lxt_door_call: no door available");
 466                 return (-1);
 467         }
 468 
 469         if (door_call(fd, door_arg) != 0) {
 470                 lxt_debug("lxt_door_call: call failed");
 471                 return (-1);
 472         }
 473         if (door_arg->rbuf == NULL) {
 474                 lxt_debug("lxt_door_call: call returned NULL");
 475                 return (-1);
 476         }
 477         return (0);
 478 }
 479 
 480 static int
 481 lxt_door_request(door_arg_t *door_arg)
 482 {
 483         door_arg_t              door_ping;
 484         lxt_server_arg_t        ping_request, *ping_result;
 485         int                     rv, ping_success = 0;
 486 
 487         /* First just try the door call. */
 488         lxt_debug("lxt_door_request: calling server");
 489         if (lxt_door_call(door_arg, 0) == 0)
 490                 return (0);
 491 
 492         /* Prepare a door server ping request. */
 493         bzero(&door_ping, sizeof (door_ping));
 494         bzero(&ping_request, sizeof (ping_request));
 495         door_ping.data_ptr      = (char *)&ping_request;
 496         door_ping.data_size     = sizeof (ping_request);
 497         ping_request.lxt_sa_op = LXT_SERVER_OP_PING;
 498 
 499         (void) mutex_lock(&lxt_door_lock);
 500 
 501         /* Ping the doors server. */
 502         lxt_debug("lxt_door_request: pinging server");
 503         if (lxt_door_call(&door_ping, 1) == 0) {
 504                 /*LINTED*/
 505                 ping_result = (lxt_server_arg_t *)door_ping.rbuf;
 506                 ping_success = ping_result->lxt_sa_success;
 507                 (void) munmap(door_ping.rbuf, door_ping.rsize);
 508         }
 509 
 510         if (!ping_success) {
 511                 /* The server is not responding so start up a new one. */
 512                 lxt_door_init();
 513         }
 514         (void) mutex_unlock(&lxt_door_lock);
 515 
 516         /* Retry the original request */
 517         lxt_debug("lxt_door_request: calling server, retry");
 518         if ((rv = lxt_door_call(door_arg, 0)) == 0)
 519                 return (0);
 520         return (rv);
 521 }
 522 
 523 static struct hostent *
 524 lxt_gethost(int op, const char *token, int token_len, int type,
 525     struct hostent *result, char *buf, int buf_len, int *h_errnop)
 526 {
 527         door_arg_t              door_arg;
 528         lxt_gethost_arg_t       *data;
 529         lxt_server_arg_t        *request;
 530         int                     request_size, errno_tmp, i;
 531 
 532         lxt_debug("lxt_gethost: request caught");
 533 
 534         request_size = sizeof (*request) + sizeof (*data) +
 535             token_len + buf_len - 1;
 536         if ((request = calloc(1, request_size)) == NULL) {
 537                 lxt_debug("lxt_gethost: calloc() failed");
 538                 *h_errnop = TRY_AGAIN;
 539                 return (NULL);
 540         }
 541         /*LINTED*/
 542         data = (lxt_gethost_arg_t *)&request->lxt_sa_data[0];
 543 
 544         /* Initialize the server request. */
 545         request->lxt_sa_op = op;
 546         data->lxt_gh_type = type;
 547         data->lxt_gh_token_len = token_len;
 548         data->lxt_gh_buf_len = buf_len;
 549         data->lxt_gh_storage_len = token_len + token_len;
 550         bcopy(token, &data->lxt_gh_storage[0], token_len);
 551 
 552         /* Initialize door_call() arguments. */
 553         bzero(&door_arg, sizeof (door_arg));
 554         door_arg.data_ptr       = (char *)request;
 555         door_arg.data_size      = request_size;
 556 
 557         if (lxt_door_request(&door_arg) != 0) {
 558                 lxt_debug("lxt_gethost: door_call() failed");
 559                 /* Don't know what caused the error so clear errno. */
 560                 errno = 0;
 561                 *h_errnop = ND_SYSTEM;
 562                 free(request);
 563                 return (NULL);
 564         }
 565 
 566         free(request);
 567 
 568         if (door_arg.rbuf == NULL) {
 569                 lxt_debug("lxt_gethost: door_call() returned NULL");
 570                 /* Don't know what caused the error so clear errno. */
 571                 errno = 0;
 572                 *h_errnop = ND_SYSTEM;
 573                 return (NULL);
 574         }
 575 
 576         /*LINTED*/
 577         request = (lxt_server_arg_t *)door_arg.rbuf;
 578         /*LINTED*/
 579         data = (lxt_gethost_arg_t *)&request->lxt_sa_data[0];
 580 
 581         /* Check if the remote procedure call failed */
 582         if (!request->lxt_sa_success) {
 583                 lxt_debug("lxt_gethost: remote function call failed");
 584                 errno_tmp = request->lxt_sa_errno;
 585                 *h_errnop = data->lxt_gh_h_errno;
 586                 (void) munmap(door_arg.rbuf, door_arg.rsize);
 587                 errno = errno_tmp;
 588                 return (NULL);
 589         }
 590 
 591         /* Copy out the results and output buffer. */
 592         bcopy(&data->lxt_gh_result, result, sizeof (*result));
 593         bcopy(&data->lxt_gh_storage[token_len], buf, buf_len);
 594         (void) munmap(door_arg.rbuf, door_arg.rsize);
 595 
 596         /* Now go through the results and convert all offsets to pointers */
 597         result->h_name = LXT_OFFSET_TO_PTR(result->h_name, buf);
 598         result->h_aliases = LXT_OFFSET_TO_PTR(result->h_aliases, buf);
 599         result->h_addr_list = LXT_OFFSET_TO_PTR(result->h_addr_list, buf);
 600         for (i = 0; result->h_aliases[i] != NULL; i++) {
 601                 result->h_aliases[i] =
 602                     LXT_OFFSET_TO_PTR(result->h_aliases[i], buf);
 603         }
 604         for (i = 0; result->h_addr_list[i] != NULL; i++) {
 605                 result->h_addr_list[i] =
 606                     LXT_OFFSET_TO_PTR(result->h_addr_list[i], buf);
 607         }
 608 
 609         return (result);
 610 }
 611 
 612 static struct servent *
 613 lxt_getserv(int op, const char *token, const int token_len, const char *proto,
 614     struct servent *result, char *buf, int buf_len)
 615 {
 616         door_arg_t              door_arg;
 617         lxt_getserv_arg_t       *data;
 618         lxt_server_arg_t        *request;
 619         int                     request_size, errno_tmp, i;
 620 
 621         lxt_debug("lxt_getserv: request caught");
 622 
 623         request_size = sizeof (*request) + sizeof (*data) +
 624             token_len + buf_len - 1;
 625         if ((request = calloc(1, request_size)) == NULL) {
 626                 lxt_debug("lxt_getserv: calloc() failed");
 627                 return (NULL);
 628         }
 629         /*LINTED*/
 630         data = (lxt_getserv_arg_t *)&request->lxt_sa_data[0];
 631 
 632         /* Initialize the server request. */
 633         request->lxt_sa_op = op;
 634         data->lxt_gs_token_len = token_len;
 635         data->lxt_gs_buf_len = buf_len;
 636         data->lxt_gs_storage_len = token_len + token_len;
 637         bcopy(token, &data->lxt_gs_storage[0], token_len);
 638 
 639         bzero(data->lxt_gs_proto, sizeof (data->lxt_gs_proto));
 640         if (proto != NULL)
 641                 (void) strncpy(data->lxt_gs_proto, proto,
 642                     sizeof (data->lxt_gs_proto));
 643 
 644         /* Initialize door_call() arguments. */
 645         bzero(&door_arg, sizeof (door_arg));
 646         door_arg.data_ptr       = (char *)request;
 647         door_arg.data_size      = request_size;
 648 
 649         /* Call the doors server */
 650         if (lxt_door_request(&door_arg) != 0) {
 651                 lxt_debug("lxt_getserv: door_call() failed");
 652                 /* Don't know what caused the error so clear errno */
 653                 errno = 0;
 654                 free(request);
 655                 return (NULL);
 656         }
 657         free(request);
 658 
 659         if (door_arg.rbuf == NULL) {
 660                 lxt_debug("lxt_getserv: door_call() returned NULL");
 661                 /* Don't know what caused the error so clear errno */
 662                 errno = 0;
 663                 return (NULL);
 664         }
 665         /*LINTED*/
 666         request = (lxt_server_arg_t *)door_arg.rbuf;
 667         /*LINTED*/
 668         data = (lxt_getserv_arg_t *)&request->lxt_sa_data[0];
 669 
 670         /* Check if the remote procedure call failed */
 671         if (!request->lxt_sa_success) {
 672                 lxt_debug("lxt_getserv: remote function call failed");
 673                 errno_tmp = request->lxt_sa_errno;
 674                 (void) munmap(door_arg.rbuf, door_arg.rsize);
 675                 errno = errno_tmp;
 676                 return (NULL);
 677         }
 678 
 679         /* Copy out the results and output buffer. */
 680         bcopy(&data->lxt_gs_result, result, sizeof (*result));
 681         bcopy(&data->lxt_gs_storage[token_len], buf, buf_len);
 682         (void) munmap(door_arg.rbuf, door_arg.rsize);
 683 
 684         /*
 685          * Now go through the results and convert all offsets to pointers.
 686          * See the comments in lxt_server_getserv() for why we need
 687          * to subtract 1 from each offset.
 688          */
 689         result->s_name = LXT_OFFSET_TO_PTR(result->s_name, buf);
 690         result->s_proto = LXT_OFFSET_TO_PTR(result->s_proto, buf);
 691         result->s_aliases = LXT_OFFSET_TO_PTR(result->s_aliases, buf);
 692         for (i = 0; result->s_aliases[i] != NULL; i++) {
 693                 result->s_aliases[i] =
 694                     LXT_OFFSET_TO_PTR(result->s_aliases[i], buf);
 695         }
 696 
 697         return (result);
 698 }
 699 
 700 static void
 701 lxt_openlog(const char *ident, int logopt, int facility)
 702 {
 703         door_arg_t              door_arg;
 704         lxt_openlog_arg_t       *data;
 705         lxt_server_arg_t        *request;
 706         int                     request_size;
 707 
 708         request_size = sizeof (*request) + sizeof (*data);
 709         if ((request = calloc(1, request_size)) == NULL) {
 710                 lxt_debug("lxt_openlog: calloc() failed");
 711                 return;
 712         }
 713         /*LINTED*/
 714         data = (lxt_openlog_arg_t *)&request->lxt_sa_data[0];
 715 
 716         /* Initialize the server request. */
 717         request->lxt_sa_op = LXT_SERVER_OP_OPENLOG;
 718         data->lxt_ol_facility = facility;
 719         data->lxt_ol_logopt = logopt;
 720         (void) strlcpy(data->lxt_ol_ident, ident, sizeof (data->lxt_ol_ident));
 721 
 722         /* Initialize door_call() arguments. */
 723         bzero(&door_arg, sizeof (door_arg));
 724         door_arg.data_ptr       = (char *)request;
 725         door_arg.data_size      = request_size;
 726 
 727         /* Call the doors server */
 728         if (lxt_door_request(&door_arg) != 0) {
 729                 lxt_debug("lxt_openlog: door_call() failed");
 730                 free(request);
 731                 return;
 732         }
 733         free(request);
 734 
 735         if (door_arg.rbuf == NULL) {
 736                 lxt_debug("lxt_openlog: door_call() returned NULL");
 737                 return;
 738         }
 739 
 740         /*LINTED*/
 741         request = (lxt_server_arg_t *)door_arg.rbuf;
 742 
 743         /* Check if the remote procedure call failed */
 744         if (!request->lxt_sa_success) {
 745                 lxt_debug("lxt_openlog: remote function call failed");
 746         }
 747         (void) munmap(door_arg.rbuf, door_arg.rsize);
 748 }
 749 
 750 static void
 751 lxt_vsyslog(int priority, const char *message, va_list va)
 752 {
 753         door_arg_t              door_arg;
 754         lxt_syslog_arg_t        *data;
 755         lxt_server_arg_t        *request;
 756         psinfo_t                p;
 757         char                    procfile[PRFNSZ], *buf = NULL, *estr;
 758         int                     buf_len, buf_i, estr_len, request_size, procfd;
 759         int                     i, key, err_count = 0, tok_count = 0;
 760         int                     errno_backup = errno;
 761 
 762         /*
 763          * Here we're going to use vsnprintf() to expand the message
 764          * string passed in before we hand it off to a Linux process.
 765          * Before we can call vsnprintf() we'll need to do modify the
 766          * string to deal with certain special tokens.
 767          *
 768          * syslog() supports a special '%m' format token that expands to
 769          * the error message string associated with the current value
 770          * of errno.  Unfortunatly if we pass this token to vsnprintf()
 771          * it will choke so we need to expand that token manually here.
 772          *
 773          * We also need to expand any "%%" characters into "%%%%".
 774          * The reason is that we'll be calling vsnprintf() which will
 775          * translate "%%%%" back to "%%", which is safe to pass to the
 776          * Linux version if syslog.  If we didn't do this then vsnprintf()
 777          * would translate "%%" to "%" and then the Linux syslog would
 778          * attempt to intrepret "%" and whatever character follows it
 779          * as a printf format style token.
 780          */
 781         for (key = i = 0; message[i] != '\0'; i++) {
 782                 if (!key && message[i] == '%') {
 783                         key = 1;
 784                         continue;
 785                 }
 786                 if (key && message[i] == '%')
 787                         tok_count++;
 788                 if (key && message[i] == 'm')
 789                         err_count++;
 790                 key = 0;
 791         }
 792 
 793         /* We found some tokens that we need to expand. */
 794         if (err_count || tok_count) {
 795                 estr = strerror(errno_backup);
 796                 estr_len = strlen(estr);
 797                 assert(estr_len >= 2);
 798 
 799                 /* Allocate a buffer to hold the expanded string. */
 800                 buf_len = i + 1 +
 801                     (tok_count * 2) + (err_count * (estr_len - 2));
 802                 if ((buf = calloc(1, buf_len)) == NULL) {
 803                         lxt_debug("lxt_vsyslog: calloc() failed");
 804                         return;
 805                 }
 806 
 807                 /* Finally, expand %% and %m. */
 808                 for (key = buf_i = i = 0; message[i] != '\0'; i++) {
 809                         assert(buf_i < buf_len);
 810                         if (!key && message[i] == '%') {
 811                                 buf[buf_i++] = '%';
 812                                 key = 1;
 813                                 continue;
 814                         }
 815                         if (key && message[i] == 'm') {
 816                                 (void) bcopy(estr, &buf[buf_i - 1], estr_len);
 817                                 buf_i += estr_len - 1;
 818                         } else if (key && message[i] == '%') {
 819                                 (void) bcopy("%%%%", &buf[buf_i - 1], 4);
 820                                 buf_i += 4 - 1;
 821                         } else {
 822                                 buf[buf_i++] = message[i];
 823                         }
 824                         key = 0;
 825                 }
 826                 assert(buf[buf_i] == '\0');
 827                 assert(buf_i == (buf_len - 1));
 828 
 829                 /* Use the expanded buffer as our format string. */
 830                 message = buf;
 831         }
 832 
 833         /* Allocate the request we're going to send to the server */
 834         request_size = sizeof (*request) + sizeof (*data);
 835         if ((request = calloc(1, request_size)) == NULL) {
 836                 lxt_debug("lxt_vsyslog: calloc() failed");
 837                 return;
 838         }
 839 
 840         /*LINTED*/
 841         data = (lxt_syslog_arg_t *)&request->lxt_sa_data[0];
 842 
 843         /* Initialize the server request. */
 844         request->lxt_sa_op = LXT_SERVER_OP_SYSLOG;
 845         data->lxt_sl_priority = priority;
 846         data->lxt_sl_pid = getpid();
 847         (void) vsnprintf(data->lxt_sl_message, sizeof (data->lxt_sl_message),
 848             message, va);
 849 
 850         /* If we did token expansion then free the intermediate buffer. */
 851         if (err_count || tok_count)
 852                 free(buf);
 853 
 854         /* Add the current program name into the request */
 855         (void) sprintf(procfile, "/proc/%u/psinfo", (int)getpid());
 856         /* (void) sprintf(procfile, "/native/proc/%u/psinfo", (int)getpid()); */
 857         if ((procfd = open(procfile, O_RDONLY)) >= 0) {
 858                 if (read(procfd, &p, sizeof (psinfo_t)) >= 0) {
 859                         (void) strncpy(data->lxt_sl_progname, p.pr_fname,
 860                             sizeof (data->lxt_sl_progname));
 861                 }
 862                 (void) close(procfd);
 863         }
 864 
 865         /* Initialize door_call() arguments. */
 866         bzero(&door_arg, sizeof (door_arg));
 867         door_arg.data_ptr       = (char *)request;
 868         door_arg.data_size      = request_size;
 869 
 870         /* Call the doors server */
 871         if (lxt_door_request(&door_arg) != 0) {
 872                 lxt_debug("lxt_vsyslog: door_call() failed");
 873                 free(request);
 874                 return;
 875         }
 876         free(request);
 877 
 878         if (door_arg.rbuf == NULL) {
 879                 lxt_debug("lxt_vsyslog: door_call() returned NULL");
 880                 return;
 881         }
 882 
 883         /*LINTED*/
 884         request = (lxt_server_arg_t *)door_arg.rbuf;
 885 
 886         /* Check if the remote procedure call failed */
 887         if (!request->lxt_sa_success) {
 888                 lxt_debug("lxt_vsyslog: remote function call failed");
 889         }
 890         (void) munmap(door_arg.rbuf, door_arg.rsize);
 891 }
 892 
 893 static void
 894 lxt_closelog(void)
 895 {
 896         door_arg_t              door_arg;
 897         lxt_server_arg_t        *request;
 898         int                     request_size;
 899 
 900         request_size = sizeof (*request);
 901         if ((request = calloc(1, request_size)) == NULL) {
 902                 lxt_debug("lxt_closelog: calloc() failed");
 903                 return;
 904         }
 905 
 906         /* Initialize the server request. */
 907         request->lxt_sa_op = LXT_SERVER_OP_CLOSELOG;
 908 
 909         /* Initialize door_call() arguments. */
 910         bzero(&door_arg, sizeof (door_arg));
 911         door_arg.data_ptr       = (char *)request;
 912         door_arg.data_size      = request_size;
 913 
 914         /* Call the doors server */
 915         if (lxt_door_request(&door_arg) != 0) {
 916                 lxt_debug("lxt_closelog: door_call() failed");
 917                 free(request);
 918                 return;
 919         }
 920         free(request);
 921 
 922         if (door_arg.rbuf == NULL) {
 923                 lxt_debug("lxt_closelog: door_call() returned NULL");
 924                 return;
 925         }
 926 
 927         /*LINTED*/
 928         request = (lxt_server_arg_t *)door_arg.rbuf;
 929 
 930         /* Check if the remote procedure call failed */
 931         if (!request->lxt_sa_success) {
 932                 lxt_debug("lxt_closelog: remote function call failed");
 933         }
 934         (void) munmap(door_arg.rbuf, door_arg.rsize);
 935 }
 936 
 937 static void
 938 lxt_pset_keep(priv_op_t op, priv_ptype_t type, priv_set_t *pset,
 939     const char *priv)
 940 {
 941         if (priv_ismember(pset, priv) == B_TRUE) {
 942                 if (op == PRIV_OFF) {
 943                         (void) priv_delset(pset, priv);
 944                         lxt_debug("lxt_pset_keep: "
 945                             "preventing drop of \"%s\" from \"%s\" set",
 946                             priv, type);
 947                 }
 948         } else {
 949                 if (op == PRIV_SET) {
 950                         (void) priv_addset(pset, priv);
 951                         lxt_debug("lxt_pset_keep: "
 952                             "preventing drop of \"%s\" from \"%s\" set",
 953                             priv, type);
 954                 }
 955         }
 956 }
 957 
 958 /*
 959  * Public interfaces - used by lx_nametoaddr
 960  */
 961 void
 962 lxt_vdebug(const char *msg, va_list va)
 963 {
 964         char            buf[LXT_MSG_MAXLEN + 1];
 965         int             rv, n;
 966 
 967         if (debug_fd == -1)
 968                 return;
 969 
 970         /* Prefix the message with pid/tid. */
 971         if ((n = snprintf(buf, sizeof (buf), "%u/%u: ",
 972             getpid(), thr_self())) == -1)
 973                 return;
 974 
 975         /* Format the message. */
 976         if (vsnprintf(&buf[n], sizeof (buf) - n, msg, va) == -1)
 977                 return;
 978 
 979         /* Add a carrige return if there isn't one already. */
 980         if ((buf[strlen(buf) - 1] != '\n') &&
 981             (strlcat(buf, "\n", sizeof (buf)) >= sizeof (buf)))
 982                 return;
 983 
 984         /* We retry in case of EINTR */
 985         do {
 986                 rv = write(debug_fd, buf, strlen(buf));
 987         } while ((rv == -1) && (errno == EINTR));
 988 }
 989 
 990 void
 991 lxt_debug(const char *msg, ...)
 992 {
 993         va_list         va;
 994         int             errno_backup;
 995 
 996         if (debug_fd == -1)
 997                 return;
 998 
 999         errno_backup = errno;
1000         va_start(va, msg);
1001         lxt_vdebug(msg, va);
1002         va_end(va);
1003         errno = errno_backup;
1004 }
1005 
1006 struct hostent *
1007 lxt_gethostbyaddr_r(const char *addr, int addr_len, int type,
1008     struct hostent *result, char *buf, int buf_len, int *h_errnop)
1009 {
1010         lxt_debug("lxt_gethostbyaddr_r: request recieved");
1011         return (lxt_gethost(LXT_SERVER_OP_ADDR2HOST,
1012             addr, addr_len, type, result, buf, buf_len, h_errnop));
1013 }
1014 
1015 struct hostent *
1016 lxt_gethostbyname_r(const char *name,
1017     struct hostent *result, char *buf, int buf_len, int *h_errnop)
1018 {
1019         lxt_debug("lxt_gethostbyname_r: request recieved");
1020         return (lxt_gethost(LXT_SERVER_OP_NAME2HOST,
1021             name, strlen(name) + 1, 0, result, buf, buf_len, h_errnop));
1022 }
1023 
1024 struct servent *
1025 lxt_getservbyport_r(int port, const char *proto,
1026     struct servent *result, char *buf, int buf_len)
1027 {
1028         lxt_debug("lxt_getservbyport_r: request recieved");
1029         return (lxt_getserv(LXT_SERVER_OP_PORT2SERV,
1030             (const char *)&port, sizeof (int), proto, result, buf, buf_len));
1031 }
1032 
1033 struct servent *
1034 lxt_getservbyname_r(const char *name, const char *proto,
1035     struct servent *result, char *buf, int buf_len)
1036 {
1037         lxt_debug("lxt_getservbyname_r: request recieved");
1038         return (lxt_getserv(LXT_SERVER_OP_NAME2SERV,
1039             name, strlen(name) + 1, proto, result, buf, buf_len));
1040 }
1041 
1042 /*
1043  * "Public" interfaces - used to override public existing interfaces
1044  */
1045 #pragma weak _close = close
1046 int
1047 close(int fd)
1048 {
1049         static fp1_t    fp = NULL;
1050 
1051         /*
1052          * Don't let the process close our file descriptor that points
1053          * back to the root directory.
1054          */
1055         if (fd == root_fd)
1056                 return (0);
1057         if (fd == debug_fd)
1058                 return (0);
1059 
1060         if (fp == NULL)
1061                 fp = (fp1_t)dlsym(RTLD_NEXT, "close");
1062         return (fp((uintptr_t)fd));
1063 }
1064 
1065 int
1066 _setppriv(priv_op_t op, priv_ptype_t type, const priv_set_t *pset)
1067 {
1068         static fp3_t    fp = NULL;
1069         priv_set_t      *pset_new;
1070         int             rv;
1071 
1072         lxt_debug("_setppriv: request caught");
1073 
1074         if (fp == NULL)
1075                 fp = (fp3_t)dlsym(RTLD_NEXT, "_setppriv");
1076 
1077         while ((pset_new = priv_allocset()) == NULL)
1078                 (void) sleep(1);
1079 
1080         priv_copyset(pset, pset_new);
1081         lxt_pset_keep(op, type, pset_new, PRIV_PROC_EXEC);
1082         lxt_pset_keep(op, type, pset_new, PRIV_PROC_FORK);
1083         lxt_pset_keep(op, type, pset_new, PRIV_PROC_CHROOT);
1084         lxt_pset_keep(op, type, pset_new, PRIV_FILE_DAC_READ);
1085         lxt_pset_keep(op, type, pset_new, PRIV_FILE_DAC_WRITE);
1086         lxt_pset_keep(op, type, pset_new, PRIV_FILE_DAC_SEARCH);
1087 
1088         rv = fp(op, (uintptr_t)type, (uintptr_t)pset_new);
1089         priv_freeset(pset_new);
1090         return (rv);
1091 }
1092 
1093 void
1094 openlog(const char *ident, int logopt, int facility)
1095 {
1096         lxt_debug("openlog: request caught");
1097         lxt_openlog(ident, logopt, facility);
1098 }
1099 
1100 void
1101 syslog(int priority, const char *message, ...)
1102 {
1103         va_list va;
1104 
1105         lxt_debug("syslog: request caught");
1106         va_start(va, message);
1107         lxt_vsyslog(priority, message, va);
1108         va_end(va);
1109 }
1110 
1111 void
1112 vsyslog(int priority, const char *message, va_list va)
1113 {
1114         lxt_debug("vsyslog: request caught");
1115         lxt_vsyslog(priority, message, va);
1116 }
1117 
1118 void
1119 closelog(void)
1120 {
1121         lxt_debug("closelog: request caught");
1122         lxt_closelog();
1123 }