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 }