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  * The BrandZ Linux thunking server.
  31  *
  32  * The interfaces defined in this file form the server 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  * Access to all these services is provided through a doors server.
  41  * Currently the only client of these interfaces and the process that
  42  * initially starts up the doors server is lx_thunk.so.
  43  *
  44  * lx_thunk.so is a native solaris library that is loaded into native
  45  * solaris process that need to run inside a Linux zone and have access
  46  * to Linux services.  When lx_thunk.so receives a request that requires
  47  * accessing Linux services it creates a "thunk server" process by
  48  * forking and executing the following shell script (which runs as
  49  * a native /bin/sh Linux process):
  50  *      /native/usr/lib/brand/lx/lx_thunk
  51  *
  52  * The first and only thing this shell script attempts to do is re-exec
  53  * itself.  The brand library will detect when this script attempts to
  54  * re-exec itself and take control of the process.  The exec() system
  55  * call made by the Linux shell will never return.
  56  *
  57  * At this point the process becomes a "thunk server" process.
  58  * The first thing it does is a bunch of initialization:
  59  *
  60  * - Sanity check that a file descriptor based communication mechanism
  61  *   needed talk to the parent process is correctly initialized.
  62  *
  63  * - Verify that two predetermined file descriptors are FIFOs.
  64  *   These FIFOs will be used to establish communications with
  65  *   the client program that spawned us and which will be sending
  66  *   us requests.
  67  *
  68  * - Use existing debugging libraries (libproc.so, librtld_db.so,
  69  *   and the BrandZ lx plug-in to librtld_db.so) and /native/proc to
  70  *   walk the Linux link maps in our own address space to determine
  71  *   the address of the Linux dlsym() function.
  72  *
  73  * - Use the native Linux dlsym() function to look up other symbols
  74  *   (for both functions and variables) that we will need access
  75  *   to service thunking requests.
  76  *
  77  * - Create a doors server and notify the parent process that we
  78  *   are ready to service requests.
  79  *
  80  * - Enter a service loop and wait for requests.
  81  *
  82  * At this point the lx_thunk process is ready to service door
  83  * based requests.  When door service request is received the
  84  * following happens inside the lx_thunk process:
  85  *
  86  * - The doors server function is is invoked on a new solaris thread
  87  *   that the kernel injects into the lx_thunk process.  We sanity
  88  *   check the incoming request, place it on a service queue, and
  89  *   wait for notification that the request has been completed.
  90  *
  91  * - A Linux thread takes this request off the service queue
  92  *   and dispatches it to a service function that will:
  93  *      - Decode the request.
  94  *      - Handle the request by invoking native Linux interfaces.
  95  *      - Encode the results for the request.
  96  *
  97  * - The Linux thread then notifies the requesting doors server
  98  *   thread that the  request has been completed and goes to sleep
  99  *   until it receives another request.
 100  *
 101  * - the solaris door server thread returns the results of the
 102  *   operation to the caller.
 103  *
 104  * Notes:
 105  *
 106  * - The service request hand off operation from the solaris doors thread to
 107  *   the "Linux thread" is required because only "Linux threads" can call
 108  *   into Linux code.  In this context a "Linux thread" is a thread that
 109  *   is either the initial thread of a Linux process or a thread that was
 110  *   created by calling the Linux version of thread_create().  The reason
 111  *   for this restriction is that any thread that invokes Linux code needs
 112  *   to have been initialized in the Linux threading libraries and have
 113  *   things like Linux thread local storage properly setup.
 114  *
 115  *   But under solaris all door server threads are created and destroyed
 116  *   dynamically.  This means that when a doors server function is invoked,
 117  *   it is invoked via a thread that hasn't been initialized in the Linux
 118  *   environment and there for can't call directly into Linux code.
 119  *
 120  * - Currently when a thunk server process is starting up, it communicated
 121  *   with it's parent via two FIFOs.  These FIFOs are setup by the
 122  *   lx_thunk.so library.  After creating the FIFOs and starting the lx_thunk
 123  *   server, lx_thunk.so writes the name of the file that the door should
 124  *   be attached to to the first pipe.  The lx_thunk server reads in this
 125  *   value, initialized the server, fattach()s it to the file request by
 126  *   lx_thunk.so and does a write to the second FIFO to let lx_thunk.so
 127  *   know that the server is ready to take requests.
 128  *
 129  *   This negotiation could be simplified to use only use one FIFO.
 130  *   lx_thunk.so would attempt to read from the FIFO and the lx_thunk
 131  *   server process could send the new door server file descriptor
 132  *   to this process via an I_SENDFD ioctl (see streamio.7I).
 133  *
 134  * - The lx_thunk server process will exit when the client process
 135  *   that it's handling requests for exists.  (ie, when there are no
 136  *   more open file handles to the doors server.)
 137  */
 138 
 139 #include <assert.h>
 140 #include <door.h>
 141 #include <errno.h>
 142 #include <libproc.h>
 143 #include <stdio.h>
 144 #include <stdlib.h>
 145 #include <strings.h>
 146 #include <sys/lx_debug.h>
 147 #include <sys/lx_misc.h>
 148 #include <sys/lx_thread.h>
 149 #include <sys/lx_thunk_server.h>
 150 #include <sys/varargs.h>
 151 #include <thread.h>
 152 #include <unistd.h>
 153 
 154 /*
 155  * Generic interfaces used for looking up and calling Linux functions.
 156  */
 157 typedef struct __lx_handle_dlsym        *lx_handle_dlsym_t;
 158 typedef struct __lx_handle_sym          *lx_handle_sym_t;
 159 
 160 uintptr_t lx_call0(lx_handle_sym_t);
 161 uintptr_t lx_call1(lx_handle_sym_t, uintptr_t);
 162 uintptr_t lx_call2(lx_handle_sym_t, uintptr_t, uintptr_t);
 163 uintptr_t lx_call3(lx_handle_sym_t, uintptr_t, uintptr_t, uintptr_t);
 164 uintptr_t lx_call4(lx_handle_sym_t, uintptr_t, uintptr_t, uintptr_t,
 165     uintptr_t);
 166 uintptr_t lx_call5(lx_handle_sym_t, uintptr_t, uintptr_t, uintptr_t,
 167     uintptr_t, uintptr_t);
 168 uintptr_t lx_call6(lx_handle_sym_t, uintptr_t, uintptr_t, uintptr_t,
 169     uintptr_t, uintptr_t, uintptr_t);
 170 uintptr_t lx_call7(lx_handle_sym_t, uintptr_t, uintptr_t, uintptr_t,
 171     uintptr_t, uintptr_t, uintptr_t, uintptr_t);
 172 uintptr_t lx_call8(lx_handle_sym_t, uintptr_t, uintptr_t, uintptr_t,
 173     uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
 174 
 175 /*
 176  * Flag indicating if this process is destined to become a thunking
 177  * server process.
 178  */
 179 static int lxt_server_processes = 0;
 180 
 181 /*
 182  * Linux function call defines and handles.
 183  */
 184 static lx_handle_dlsym_t        lxh_init = NULL;
 185 
 186 #define LXTH_GETHOSTBYNAME_R    0
 187 #define LXTH_GETHOSTBYADDR_R    1
 188 #define LXTH_GETSERVBYNAME_R    2
 189 #define LXTH_GETSERVBYPORT_R    3
 190 #define LXTH_OPENLOG            4
 191 #define LXTH_SYSLOG             5
 192 #define LXTH_CLOSELOG           6
 193 #define LXTH_PROGNAME           7
 194 
 195 static struct lxt_handles {
 196         int             lxth_index;
 197         char            *lxth_name;
 198         lx_handle_sym_t lxth_handle;
 199 } lxt_handles[] = {
 200         { LXTH_GETHOSTBYNAME_R, "gethostbyname_r",      NULL },
 201         { LXTH_GETHOSTBYADDR_R, "gethostbyaddr_r",      NULL },
 202         { LXTH_GETSERVBYNAME_R, "getservbyname_r",      NULL },
 203         { LXTH_GETSERVBYPORT_R, "getservbyport_r",      NULL },
 204         { LXTH_OPENLOG,         "openlog",              NULL },
 205         { LXTH_SYSLOG,          "syslog",               NULL },
 206         { LXTH_CLOSELOG,        "closelog",             NULL },
 207         { LXTH_PROGNAME,        "__progname",           NULL },
 208         { -1,                   NULL,                   NULL },
 209 };
 210 
 211 /*
 212  * Door server operations dispatch functions and table.
 213  *
 214  * When the doors server get's a request for a particlar operation
 215  * this dispatch table controls what function will be invoked to
 216  * service the request.  The function is invoked via Linux thread
 217  * so that it can call into native Linux code if necessary.
 218  */
 219 static void lxt_server_gethost(lxt_server_arg_t *request, size_t request_size,
 220     char **door_result, size_t *door_result_size);
 221 static void lxt_server_getserv(lxt_server_arg_t *request, size_t request_size,
 222     char **door_result, size_t *door_result_size);
 223 static void lxt_server_openlog(lxt_server_arg_t *request, size_t request_size,
 224     char **door_result, size_t *door_result_size);
 225 static void lxt_server_syslog(lxt_server_arg_t *request, size_t request_size,
 226     char **door_result, size_t *door_result_size);
 227 static void lxt_server_closelog(lxt_server_arg_t *request, size_t request_size,
 228     char **door_result, size_t *door_result_size);
 229 
 230 typedef void (*lxt_op_func_t)(lxt_server_arg_t *request, size_t request_size,
 231     char **door_result, size_t *door_result_size);
 232 
 233 static struct lxt_operations {
 234         int             lxto_index;
 235         lxt_op_func_t   lxto_fp;
 236 } lxt_operations[] = {
 237         { LXT_SERVER_OP_PING,           NULL },
 238         { LXT_SERVER_OP_NAME2HOST,      lxt_server_gethost },
 239         { LXT_SERVER_OP_ADDR2HOST,      lxt_server_gethost },
 240         { LXT_SERVER_OP_NAME2SERV,      lxt_server_getserv },
 241         { LXT_SERVER_OP_PORT2SERV,      lxt_server_getserv },
 242         { LXT_SERVER_OP_OPENLOG,        lxt_server_openlog },
 243         { LXT_SERVER_OP_SYSLOG,         lxt_server_syslog },
 244         { LXT_SERVER_OP_CLOSELOG,       lxt_server_closelog },
 245 };
 246 
 247 /*
 248  * Structures for passing off requests from doors threads (which are
 249  * solaris threads) to a Linux thread that that can handle them.
 250  */
 251 typedef struct lxt_req {
 252         lxt_server_arg_t        *lxtr_request;
 253         size_t                  lxtr_request_size;
 254         char                    *lxtr_result;
 255         size_t                  lxtr_result_size;
 256         int                     lxtr_complete;
 257         cond_t                  lxtr_complete_cv;
 258 } lxt_req_t;
 259 
 260 static mutex_t          lxt_req_lock = DEFAULTMUTEX;
 261 static cond_t           lxt_req_cv = DEFAULTCV;
 262 static lxt_req_t        *lxt_req_ptr = NULL;
 263 
 264 static mutex_t          lxt_pid_lock = DEFAULTMUTEX;
 265 static pid_t            lxt_pid = NULL;
 266 
 267 /*
 268  * Interfaces used to call from lx_brand.so into Linux code.
 269  */
 270 typedef struct lookup_cb_arg {
 271         struct ps_prochandle    *lca_ph;
 272         caddr_t                 lca_ptr;
 273 } lookup_cb_arg_t;
 274 
 275 static int
 276 /*ARGSUSED*/
 277 lookup_cb(void *data, const prmap_t *pmp, const char *object)
 278 {
 279         lookup_cb_arg_t         *lcap = (lookup_cb_arg_t *)data;
 280         prsyminfo_t             si;
 281         GElf_Sym                sym;
 282 
 283         if (Pxlookup_by_name(lcap->lca_ph,
 284             LM_ID_BASE, object, "dlsym", &sym, &si) != 0)
 285                 return (0);
 286 
 287         if (sym.st_shndx == SHN_UNDEF)
 288                 return (0);
 289 
 290         /*
 291          * XXX: we should be more paranoid and verify that the symbol
 292          * we just looked up is libdl.so.2`dlsym
 293          */
 294         lcap->lca_ptr = (caddr_t)(uintptr_t)sym.st_value;
 295         return (1);
 296 }
 297 
 298 lx_handle_dlsym_t
 299 lx_call_init(void)
 300 {
 301         struct ps_prochandle    *ph;
 302         lookup_cb_arg_t         lca;
 303         extern int              __libc_threaded;
 304         int                     err;
 305 
 306         lx_debug("lx_call_init(): looking up Linux dlsym");
 307 
 308         /*
 309          * The handle is really the address of the Linux "dlsym" function.
 310          * Once we have this address we can call into the Linux "dlsym"
 311          * function to lookup other functions.  It's the initial lookup
 312          * of "dlsym" that's difficult.  To do this we'll leverage the
 313          * brand support that we added to librtld_db.  We're going
 314          * to fire up a seperate native solaris process that will
 315          * attach to us via libproc/librtld_db and lookup the symbol
 316          * for us.
 317          */
 318 
 319         /* Make sure we're single threaded. */
 320         if (__libc_threaded) {
 321                 lx_debug("lx_call_init() fail: "
 322                     "process must be single threaded");
 323                 return (NULL);
 324         }
 325 
 326         /* Tell libproc.so where the real procfs is mounted. */
 327         Pset_procfs_path("/native/proc");
 328 
 329         /* Tell librtld_db.so where the real /native is */
 330         (void) rd_ctl(RD_CTL_SET_HELPPATH, "/native");
 331 
 332         /* Grab ourselves but don't stop ourselves. */
 333         if ((ph = Pgrab(getpid(),
 334             PGRAB_FORCE | PGRAB_RDONLY | PGRAB_NOSTOP, &err)) == NULL) {
 335                 lx_debug("lx_call_init() fail: Pgrab failed: %s",
 336                     Pgrab_error(err));
 337                 return (NULL);
 338         }
 339 
 340         lca.lca_ph = ph;
 341         if (Pobject_iter(ph, lookup_cb, &lca) == -1) {
 342                 lx_debug("lx_call_init() fail: couldn't find Linux dlsym");
 343                 return (NULL);
 344         }
 345 
 346         lx_debug("lx_call_init(): Linux dlsym = 0x%p", lca.lca_ptr);
 347         return ((lx_handle_dlsym_t)lca.lca_ptr);
 348 }
 349 
 350 #define LX_RTLD_DEFAULT         ((void *)0)
 351 #define LX_RTLD_NEXT            ((void *) -1l)
 352 
 353 lx_handle_sym_t
 354 lx_call_dlsym(lx_handle_dlsym_t lxh_dlsym, const char *str)
 355 {
 356         lx_handle_sym_t result;
 357         lx_debug("lx_call_dlsym: calling Linux dlsym for: %s", str);
 358         result = (lx_handle_sym_t)lx_call2((lx_handle_sym_t)lxh_dlsym,
 359             (uintptr_t)LX_RTLD_DEFAULT, (uintptr_t)str);
 360         lx_debug("lx_call_dlsym: Linux sym: \"%s\" = 0x%p", str, result);
 361         return (result);
 362 }
 363 
 364 static uintptr_t
 365 /*ARGSUSED*/
 366 lx_call(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2,
 367     uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6, uintptr_t p7,
 368     uintptr_t p8)
 369 {
 370         typedef uintptr_t       (*fp8_t)(uintptr_t, uintptr_t, uintptr_t,
 371             uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
 372         lx_regs_t               *rp;
 373         uintptr_t               ret;
 374         fp8_t                   lx_funcp = (fp8_t)lx_ch;
 375         long                    cur_gs;
 376 
 377         rp = lx_syscall_regs();
 378 
 379         lx_debug("lx_call: calling to Linux code at 0x%p", lx_ch);
 380         lx_debug("lx_call: loading Linux gs, rp = 0x%p, gs = 0x%p",
 381             rp, rp->lxr_gs);
 382 
 383         lx_swap_gs(rp->lxr_gs, &cur_gs);
 384         ret = lx_funcp(p1, p2, p3, p4, p5, p6, p7, p8);
 385         lx_swap_gs(cur_gs, &rp->lxr_gs);
 386 
 387         lx_debug("lx_call: returned from Linux code at 0x%p (%p)", lx_ch, ret);
 388         lx_debug("lx_call: restored solaris gs 0x%p", cur_gs);
 389         return (ret);
 390 }
 391 
 392 uintptr_t
 393 lx_call0(lx_handle_sym_t lx_ch)
 394 {
 395         return (lx_call(lx_ch, 0, 0, 0, 0, 0, 0, 0, 0));
 396 }
 397 
 398 uintptr_t
 399 lx_call1(lx_handle_sym_t lx_ch, uintptr_t p1)
 400 {
 401         return (lx_call(lx_ch, p1, 0, 0, 0, 0, 0, 0, 0));
 402 }
 403 
 404 uintptr_t
 405 lx_call2(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2)
 406 {
 407         return (lx_call(lx_ch, p1, p2, 0, 0, 0, 0, 0, 0));
 408 }
 409 
 410 uintptr_t
 411 lx_call3(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2, uintptr_t p3)
 412 {
 413         return (lx_call(lx_ch, p1, p2, p3, 0, 0, 0, 0, 0));
 414 }
 415 
 416 uintptr_t
 417 lx_call4(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2, uintptr_t p3,
 418     uintptr_t p4)
 419 {
 420         return (lx_call(lx_ch, p1, p2, p3, p4, 0, 0, 0, 0));
 421 }
 422 
 423 uintptr_t
 424 lx_call5(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2, uintptr_t p3,
 425     uintptr_t p4, uintptr_t p5)
 426 {
 427         return (lx_call(lx_ch, p1, p2, p3, p4, p5, 0, 0, 0));
 428 }
 429 
 430 uintptr_t
 431 lx_call6(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2, uintptr_t p3,
 432     uintptr_t p4, uintptr_t p5, uintptr_t p6)
 433 {
 434         return (lx_call(lx_ch, p1, p2, p3, p4, p5, p6, 0, 0));
 435 }
 436 
 437 uintptr_t
 438 lx_call7(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2, uintptr_t p3,
 439     uintptr_t p4, uintptr_t p5, uintptr_t p6, uintptr_t p7)
 440 {
 441         return (lx_call(lx_ch, p1, p2, p3, p4, p5, p6, p7, 0));
 442 }
 443 
 444 uintptr_t
 445 lx_call8(lx_handle_sym_t lx_ch, uintptr_t p1, uintptr_t p2, uintptr_t p3,
 446     uintptr_t p4, uintptr_t p5, uintptr_t p6, uintptr_t p7, uintptr_t p8)
 447 {
 448         return (lx_call(lx_ch, p1, p2, p3, p4, p5, p6, p7, p8));
 449 }
 450 
 451 /*
 452  * Linux Thunking Interfaces - Server Side
 453  */
 454 static int
 455 lxt_gethost_arg_check(lxt_gethost_arg_t *x, int x_size)
 456 {
 457         if (x_size != sizeof (*x) + x->lxt_gh_buf_len - 1)
 458                 return (-1);
 459 
 460         if ((x->lxt_gh_token_len < 0) || (x->lxt_gh_buf_len < 0))
 461                 return (-1);
 462 
 463         /* Token and buf should use up all the storage. */
 464         if ((x->lxt_gh_token_len + x->lxt_gh_buf_len) != x->lxt_gh_storage_len)
 465                 return (-1);
 466 
 467         return (0);
 468 }
 469 
 470 static void
 471 lxt_server_gethost(lxt_server_arg_t *request, size_t request_size,
 472     char **door_result, size_t *door_result_size)
 473 {
 474         lxt_gethost_arg_t       *data;
 475         struct hostent          *result, *rv;
 476         int                     token_len, buf_len, type, data_size, i;
 477         char                    *token, *buf;
 478         int                     h_errnop;
 479 
 480         assert((request->lxt_sa_op == LXT_SERVER_OP_NAME2HOST) ||
 481             (request->lxt_sa_op == LXT_SERVER_OP_ADDR2HOST));
 482 
 483         /*LINTED*/
 484         data = (lxt_gethost_arg_t *)&request->lxt_sa_data[0];
 485         data_size = request_size - sizeof (*request) - 1;
 486 
 487         if (!lxt_gethost_arg_check(data, data_size)) {
 488                 lx_debug("lxt_server_gethost: invalid request");
 489                 *door_result = NULL;
 490                 *door_result_size = 0;
 491                 return;
 492         }
 493 
 494         /* Unpack the arguments. */
 495         type = data->lxt_gh_type;
 496         token = &data->lxt_gh_storage[0];
 497         token_len = data->lxt_gh_token_len;
 498         result = &data->lxt_gh_result;
 499         buf = &data->lxt_gh_storage[data->lxt_gh_token_len];
 500         buf_len = data->lxt_gh_buf_len - data->lxt_gh_token_len;
 501 
 502         if (request->lxt_sa_op == LXT_SERVER_OP_NAME2HOST) {
 503                 (void) lx_call6(lxt_handles[LXTH_GETHOSTBYNAME_R].lxth_handle,
 504                     (uintptr_t)token, (uintptr_t)result,
 505                     (uintptr_t)buf, buf_len, (uintptr_t)&rv,
 506                     (uintptr_t)&h_errnop);
 507         } else {
 508                 (void) lx_call8(lxt_handles[LXTH_GETHOSTBYADDR_R].lxth_handle,
 509                     (uintptr_t)token, token_len, type, (uintptr_t)result,
 510                     (uintptr_t)buf, buf_len, (uintptr_t)&rv,
 511                     (uintptr_t)&h_errnop);
 512         }
 513 
 514         if (rv == NULL) {
 515                 /* the lookup failed */
 516                 request->lxt_sa_success = 0;
 517                 request->lxt_sa_errno = errno;
 518                 data->lxt_gh_h_errno = h_errnop;
 519                 *door_result = (char *)request;
 520                 *door_result_size = request_size;
 521                 return;
 522         }
 523         request->lxt_sa_success = 1;
 524         request->lxt_sa_errno = 0;
 525         data->lxt_gh_h_errno = 0;
 526 
 527         /*
 528          * The result structure that we would normally return contains a
 529          * bunch of pointers, but those pointers are useless to our caller
 530          * since they are in a different address space.  So before returning
 531          * we'll convert all the result pointers into offsets.  The caller
 532          * can then map the offsets back into pointers.
 533          */
 534         for (i = 0; result->h_aliases[i] != NULL; i++) {
 535                 result->h_aliases[i] =
 536                     LXT_PTR_TO_OFFSET(result->h_aliases[i], buf);
 537         }
 538         for (i = 0; result->h_addr_list[i] != NULL; i++) {
 539                 result->h_addr_list[i] =
 540                     LXT_PTR_TO_OFFSET(result->h_addr_list[i], buf);
 541         }
 542         result->h_name = LXT_PTR_TO_OFFSET(result->h_name, buf);
 543         result->h_aliases = LXT_PTR_TO_OFFSET(result->h_aliases, buf);
 544         result->h_addr_list = LXT_PTR_TO_OFFSET(result->h_addr_list, buf);
 545 
 546         *door_result = (char *)request;
 547         *door_result_size = request_size;
 548 }
 549 
 550 static int
 551 lxt_getserv_arg_check(lxt_getserv_arg_t *x, int x_size)
 552 {
 553         if (x_size != sizeof (*x) + x->lxt_gs_buf_len - 1)
 554                 return (-1);
 555 
 556         if ((x->lxt_gs_token_len < 0) || (x->lxt_gs_buf_len < 0))
 557                 return (-1);
 558 
 559         /* Token and buf should use up all the storage. */
 560         if ((x->lxt_gs_token_len + x->lxt_gs_buf_len) != x->lxt_gs_storage_len)
 561                 return (-1);
 562 
 563         return (0);
 564 }
 565 
 566 static void
 567 lxt_server_getserv(lxt_server_arg_t *request, size_t request_size,
 568     char **door_result, size_t *door_result_size)
 569 {
 570         lxt_getserv_arg_t       *data;
 571         struct servent          *result, *rv;
 572         int                     token_len, buf_len, data_size, i, port;
 573         char                    *token, *buf, *proto = NULL;
 574 
 575         assert((request->lxt_sa_op == LXT_SERVER_OP_NAME2SERV) ||
 576             (request->lxt_sa_op == LXT_SERVER_OP_PORT2SERV));
 577 
 578         /*LINTED*/
 579         data = (lxt_getserv_arg_t *)&request->lxt_sa_data[0];
 580         data_size = request_size - sizeof (*request) - 1;
 581 
 582         if (!lxt_getserv_arg_check(data, data_size)) {
 583                 lx_debug("lxt_server_getserv: invalid request");
 584                 *door_result = NULL;
 585                 *door_result_size = 0;
 586                 return;
 587         }
 588 
 589         /* Unpack the arguments. */
 590         token = &data->lxt_gs_storage[0];
 591         token_len = data->lxt_gs_token_len;
 592         result = &data->lxt_gs_result;
 593         buf = &data->lxt_gs_storage[data->lxt_gs_token_len];
 594         buf_len = data->lxt_gs_buf_len - data->lxt_gs_token_len;
 595         if (strlen(data->lxt_gs_proto) > 0)
 596                 proto = data->lxt_gs_proto;
 597 
 598         /* Do more sanity checks */
 599         if ((request->lxt_sa_op == LXT_SERVER_OP_PORT2SERV) &&
 600             (token_len != sizeof (int))) {
 601                 lx_debug("lxt_server_getserv: invalid request");
 602                 *door_result = NULL;
 603                 *door_result_size = 0;
 604                 return;
 605         }
 606 
 607         if (request->lxt_sa_op == LXT_SERVER_OP_NAME2SERV) {
 608                 (void) lx_call6(lxt_handles[LXTH_GETSERVBYNAME_R].lxth_handle,
 609                     (uintptr_t)token, (uintptr_t)proto, (uintptr_t)result,
 610                     (uintptr_t)buf, buf_len, (uintptr_t)&rv);
 611         } else {
 612                 bcopy(token, &port, sizeof (int));
 613                 (void) lx_call6(lxt_handles[LXTH_GETSERVBYPORT_R].lxth_handle,
 614                     port, (uintptr_t)proto, (uintptr_t)result,
 615                     (uintptr_t)buf, buf_len, (uintptr_t)&rv);
 616         }
 617 
 618         if (rv == NULL) {
 619                 /* the lookup failed */
 620                 request->lxt_sa_success = 0;
 621                 request->lxt_sa_errno = errno;
 622                 *door_result = (char *)request;
 623                 *door_result_size = request_size;
 624                 return;
 625         }
 626         request->lxt_sa_success = 1;
 627         request->lxt_sa_errno = 0;
 628 
 629         /*
 630          * The result structure that we would normally return contains a
 631          * bunch of pointers, but those pointers are useless to our caller
 632          * since they are in a different address space.  So before returning
 633          * we'll convert all the result pointers into offsets.  The caller
 634          * can then map the offsets back into pointers.
 635          */
 636         for (i = 0; result->s_aliases[i] != NULL; i++) {
 637                 result->s_aliases[i] =
 638                     LXT_PTR_TO_OFFSET(result->s_aliases[i], buf);
 639         }
 640         result->s_proto = LXT_PTR_TO_OFFSET(result->s_proto, buf);
 641         result->s_aliases = LXT_PTR_TO_OFFSET(result->s_aliases, buf);
 642         result->s_name = LXT_PTR_TO_OFFSET(result->s_name, buf);
 643 
 644         *door_result = (char *)request;
 645         *door_result_size = request_size;
 646 }
 647 
 648 static void
 649 /*ARGSUSED*/
 650 lxt_server_openlog(lxt_server_arg_t *request, size_t request_size,
 651     char **door_result, size_t *door_result_size)
 652 {
 653         lxt_openlog_arg_t       *data;
 654         int                     data_size;
 655         static char             ident[128];
 656 
 657         assert(request->lxt_sa_op == LXT_SERVER_OP_OPENLOG);
 658 
 659         /*LINTED*/
 660         data = (lxt_openlog_arg_t *)&request->lxt_sa_data[0];
 661         data_size = request_size - sizeof (*request);
 662 
 663         if (data_size != sizeof (*data)) {
 664                 lx_debug("lxt_server_openlog: invalid request");
 665                 *door_result = NULL;
 666                 *door_result_size = 0;
 667                 return;
 668         }
 669 
 670         /*
 671          * Linux expects that the ident pointer passed to openlog()
 672          * points to a static string that won't go away.  Linux
 673          * saves the pointer and references with syslog() is called.
 674          * Hence we'll make a local copy of the ident string here.
 675          */
 676         (void) mutex_lock(&lxt_pid_lock);
 677         (void) strlcpy(ident, data->lxt_ol_ident, sizeof (ident));
 678         (void) mutex_unlock(&lxt_pid_lock);
 679 
 680         /* Call Linx openlog(). */
 681         (void) lx_call3(lxt_handles[LXTH_OPENLOG].lxth_handle,
 682             (uintptr_t)ident, data->lxt_ol_logopt, data->lxt_ol_facility);
 683 
 684         request->lxt_sa_success = 1;
 685         request->lxt_sa_errno = 0;
 686         *door_result = (char *)request;
 687         *door_result_size = request_size;
 688 }
 689 
 690 static void
 691 /*ARGSUSED*/
 692 lxt_server_syslog(lxt_server_arg_t *request, size_t request_size,
 693     char **door_result, size_t *door_result_size)
 694 {
 695         lxt_syslog_arg_t        *data;
 696         int                     data_size;
 697         char                    *progname_ptr_new;
 698         char                    *progname_ptr_old;
 699 
 700         assert(request->lxt_sa_op == LXT_SERVER_OP_SYSLOG);
 701 
 702         /*LINTED*/
 703         data = (lxt_syslog_arg_t *)&request->lxt_sa_data[0];
 704         data_size = request_size - sizeof (*request);
 705 
 706         if (data_size != sizeof (*data)) {
 707                 lx_debug("lxt_server_openlog: invalid request");
 708                 *door_result = NULL;
 709                 *door_result_size = 0;
 710                 return;
 711         }
 712         progname_ptr_new = data->lxt_sl_progname;
 713 
 714         (void) mutex_lock(&lxt_pid_lock);
 715 
 716         /*
 717          * Ensure the message has the correct pid.
 718          * We do this by telling our getpid() system call to return a
 719          * different value.
 720          */
 721         lxt_pid = data->lxt_sl_pid;
 722 
 723         /*
 724          * Ensure the message has the correct program name.
 725          * Normally instead of a program name an "ident" string is
 726          * used, this is the string passed to openlog().  But if
 727          * openlog() wasn't called before syslog() then Linux
 728          * syslog() will attempt to use the program name as
 729          * the ident string, and the program name is determined
 730          * by looking at the __progname variable.  So we'll just
 731          * update the Linux __progname variable while we do the
 732          * call.
 733          */
 734         (void) uucopy(lxt_handles[LXTH_PROGNAME].lxth_handle,
 735             &progname_ptr_old, sizeof (char *));
 736         (void) uucopy(&progname_ptr_new,
 737             lxt_handles[LXTH_PROGNAME].lxth_handle, sizeof (char *));
 738 
 739         /* Call Linux syslog(). */
 740         (void) lx_call2(lxt_handles[LXTH_SYSLOG].lxth_handle,
 741             data->lxt_sl_priority, (uintptr_t)data->lxt_sl_message);
 742 
 743         /* Restore pid and program name. */
 744         (void) uucopy(&progname_ptr_old,
 745             lxt_handles[LXTH_PROGNAME].lxth_handle, sizeof (char *));
 746         lxt_pid = NULL;
 747 
 748         (void) mutex_unlock(&lxt_pid_lock);
 749 
 750         request->lxt_sa_success = 1;
 751         request->lxt_sa_errno = 0;
 752         *door_result = (char *)request;
 753         *door_result_size = request_size;
 754 }
 755 
 756 static void
 757 /*ARGSUSED*/
 758 lxt_server_closelog(lxt_server_arg_t *request, size_t request_size,
 759     char **door_result, size_t *door_result_size)
 760 {
 761         int                     data_size;
 762 
 763         assert(request->lxt_sa_op == LXT_SERVER_OP_CLOSELOG);
 764 
 765         data_size = request_size - sizeof (*request);
 766         if (data_size != 0) {
 767                 lx_debug("lxt_server_closelog: invalid request");
 768                 *door_result = NULL;
 769                 *door_result_size = 0;
 770                 return;
 771         }
 772 
 773         /* Call Linux closelog(). */
 774         (void) lx_call0(lxt_handles[LXTH_CLOSELOG].lxth_handle);
 775 
 776         request->lxt_sa_success = 1;
 777         request->lxt_sa_errno = 0;
 778         *door_result = (char *)request;
 779         *door_result_size = request_size;
 780 }
 781 
 782 static void
 783 /*ARGSUSED*/
 784 lxt_server(void *cookie, char *argp, size_t request_size,
 785     door_desc_t *dp, uint_t n_desc)
 786 {
 787         /*LINTED*/
 788         lxt_server_arg_t        *request = (lxt_server_arg_t *)argp;
 789         lxt_req_t               lxt_req;
 790         char                    *door_path = cookie;
 791 
 792         /* Check if there's no callers left */
 793         if (argp == DOOR_UNREF_DATA) {
 794                 (void) fdetach(door_path);
 795                 (void) unlink(door_path);
 796                 lx_debug("lxt_thunk_server: no clients, exiting");
 797                 exit(0);
 798         }
 799 
 800         /* Sanity check the incomming request. */
 801         if (request_size < sizeof (*request)) {
 802                 /* the lookup failed */
 803                 lx_debug("lxt_thunk_server: invalid request size");
 804                 (void) door_return(NULL, 0, NULL, 0);
 805                 return;
 806         }
 807 
 808         if ((request->lxt_sa_op < LXT_SERVER_OP_MIN) ||
 809             (request->lxt_sa_op > LXT_SERVER_OP_MAX)) {
 810                 lx_debug("lxt_thunk_server: invalid request op");
 811                 (void) door_return(NULL, 0, NULL, 0);
 812                 return;
 813         }
 814 
 815         /* Handle ping requests immediatly, return here. */
 816         if (request->lxt_sa_op == LXT_SERVER_OP_PING) {
 817                 lx_debug("lxt_thunk_server: handling ping request");
 818                 request->lxt_sa_success = 1;
 819                 (void) door_return((char *)request, request_size, NULL, 0);
 820                 return;
 821         }
 822 
 823         lx_debug("lxt_thunk_server: hand off request to Linux thread, "
 824             "request = 0x%p", request);
 825 
 826         /* Pack the request up so we can pass it to a Linux thread. */
 827         lxt_req.lxtr_request = request;
 828         lxt_req.lxtr_request_size = request_size;
 829         lxt_req.lxtr_result = NULL;
 830         lxt_req.lxtr_result_size = 0;
 831         lxt_req.lxtr_complete = 0;
 832         (void) cond_init(&lxt_req.lxtr_complete_cv, USYNC_THREAD, NULL);
 833 
 834         /* Pass the request onto a Linux thread. */
 835         (void) mutex_lock(&lxt_req_lock);
 836         while (lxt_req_ptr != NULL)
 837                 (void) cond_wait(&lxt_req_cv, &lxt_req_lock);
 838         lxt_req_ptr = &lxt_req;
 839         (void) cond_broadcast(&lxt_req_cv);
 840 
 841         /* Wait for the request to be completed. */
 842         while (lxt_req.lxtr_complete == 0)
 843                 (void) cond_wait(&lxt_req.lxtr_complete_cv, &lxt_req_lock);
 844         assert(lxt_req_ptr != &lxt_req);
 845         (void) mutex_unlock(&lxt_req_lock);
 846 
 847         lx_debug("lxt_thunk_server: hand off request completed, "
 848             "request = 0x%p", request);
 849 
 850         /*
 851          * If door_return() is successfull it never returns, so if we made
 852          * it here there was some kind of error, but there's nothing we can
 853          * really do about it.
 854          */
 855         (void) door_return(
 856             lxt_req.lxtr_result, lxt_req.lxtr_result_size, NULL, 0);
 857 }
 858 
 859 static void
 860 lxt_server_loop(void)
 861 {
 862         lxt_req_t               *lxt_req;
 863         lxt_server_arg_t        *request;
 864         size_t                  request_size;
 865         char                    *door_result;
 866         size_t                  door_result_size;
 867 
 868         for (;;) {
 869                 /* Wait for a request from a doors server thread. */
 870                 (void) mutex_lock(&lxt_req_lock);
 871                 while (lxt_req_ptr == NULL)
 872                         (void) cond_wait(&lxt_req_cv, &lxt_req_lock);
 873 
 874                 /* We got a request, get a local pointer to it. */
 875                 lxt_req = lxt_req_ptr;
 876                 lxt_req_ptr = NULL;
 877                 (void) cond_broadcast(&lxt_req_cv);
 878                 (void) mutex_unlock(&lxt_req_lock);
 879 
 880                 /* Get a pointer to the request. */
 881                 request = lxt_req->lxtr_request;
 882                 request_size = lxt_req->lxtr_request_size;
 883 
 884                 lx_debug("lxt_server_loop: Linux thread request recieved, "
 885                     "request = %p", request);
 886 
 887                 /* Dispatch the request. */
 888                 assert((request->lxt_sa_op > LXT_SERVER_OP_PING) ||
 889                     (request->lxt_sa_op < LXT_SERVER_OP_MAX));
 890                 lxt_operations[request->lxt_sa_op].lxto_fp(
 891                     request, request_size, &door_result, &door_result_size);
 892 
 893                 lx_debug("lxt_server_loop: Linux thread request completed, "
 894                     "request = %p", request);
 895 
 896                 (void) mutex_lock(&lxt_req_lock);
 897 
 898                 /* Set the result pointers for the calling door thread. */
 899                 lxt_req->lxtr_result = door_result;
 900                 lxt_req->lxtr_result_size = door_result_size;
 901 
 902                 /* Let the door thread know we're done. */
 903                 lxt_req->lxtr_complete = 1;
 904                 (void) cond_signal(&lxt_req->lxtr_complete_cv);
 905 
 906                 (void) mutex_unlock(&lxt_req_lock);
 907         }
 908         /*NOTREACHED*/
 909 }
 910 
 911 static void
 912 lxt_server_enter(int fifo1_wr, int fifo2_rd)
 913 {
 914         struct stat     stat;
 915         char            door_path[MAXPATHLEN];
 916         int             i, dfd, junk = 0;
 917 
 918         /*
 919          * Do some sanity checks.  Make sure we've got the fifos
 920          * we need passed to us on the correct file descriptors.
 921          */
 922         if ((fstat(fifo1_wr, &stat) != 0) ||
 923             ((stat.st_mode & S_IFMT) != S_IFIFO) ||
 924             (fstat(fifo2_rd, &stat) != 0) ||
 925             ((stat.st_mode & S_IFMT) != S_IFIFO)) {
 926                 lx_err("lx_thunk server aborting, can't contact parent");
 927                 exit(-1);
 928         }
 929 
 930         /*
 931          * Get the initial Linux call handle so we can invoke other
 932          * Linux calls.
 933          */
 934         lxh_init = lx_call_init();
 935         if (lxh_init == NULL) {
 936                 lx_err("lx_thunk server aborting, failed Linux call init");
 937                 exit(-1);
 938         }
 939 
 940         /* Now lookup other Linux symbols we'll need access to. */
 941         for (i = 0; lxt_handles[i].lxth_name != NULL; i++) {
 942                 assert(lxt_handles[i].lxth_index == i);
 943                 if ((lxt_handles[i].lxth_handle = lx_call_dlsym(lxh_init,
 944                     lxt_handles[i].lxth_name)) == NULL) {
 945                         lx_err("lx_thunk server aborting, "
 946                             "failed Linux symbol lookup: %s",
 947                             lxt_handles[i].lxth_name);
 948                         exit(-1);
 949                 }
 950         }
 951 
 952         /* get the path to the door server */
 953         if (read(fifo2_rd, door_path, sizeof (door_path)) < 0) {
 954                 lx_err("lxt_server_enter: failed to get door path");
 955                 exit(-1);
 956         }
 957         (void) close(fifo2_rd);
 958 
 959         /* Create the door server. */
 960         if ((dfd = door_create(lxt_server, door_path,
 961             DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
 962                 lx_err("lxt_server_enter: door_create() failed");
 963                 exit(-1);
 964         }
 965 
 966         /* Attach the door to a file system path. */
 967         (void) fdetach(door_path);
 968         if (fattach(dfd, door_path) < 0) {
 969                 lx_err("lxt_server_enter: fattach() failed");
 970                 exit(-1);
 971         }
 972 
 973         /* The door server is ready, signal this via a fifo write */
 974         (void) write(fifo1_wr, &junk, 1);
 975         (void) close(fifo1_wr);
 976 
 977         lx_debug("lxt_server_enter: doors server initialized");
 978         lxt_server_loop();
 979         /*NOTREACHED*/
 980 }
 981 
 982 void
 983 lxt_server_exec_check(void)
 984 {
 985         if (lxt_server_processes == 0)
 986                 return;
 987 
 988         /*
 989          * We're a thunk server process, so we take over control of
 990          * the current Linux process here.
 991          */
 992         lx_debug("lx_thunk server initalization starting");
 993         lxt_server_enter(LXT_SERVER_FIFO_WR_FD, LXT_SERVER_FIFO_RD_FD);
 994         /*NOTREACHED*/
 995 }
 996 
 997 void
 998 lxt_server_init(int argc, char *argv[])
 999 {
1000         /*
1001          * The thunk server process is a shell script named LXT_SERVER_BINARY.
1002          * It is executed without any parameters.  Since it's a shell script
1003          * the arguments passed to the shell's main entry point are:
1004          *      1) the name of the shell
1005          *      2) the name of the script to execute
1006          *
1007          * So to check if we're the thunk server process we first check
1008          * for the expected number of arduments and then we'll look at
1009          * the second parameter to see if it's LXT_SERVER_BINARY.
1010          */
1011         if ((argc != 2) ||
1012             (strcmp(argv[1], LXT_SERVER_BINARY) != 0))
1013                 return;
1014 
1015         lxt_server_processes = 1;
1016         lx_debug("lx_thunk server detected, delaying initalization");
1017 }
1018 
1019 int
1020 lxt_server_pid(int *pid)
1021 {
1022         if (lxt_server_processes == 0)
1023                 return (0);
1024         *pid = lxt_pid;
1025         return (1);
1026 }