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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * rexd - a remote execution daemon based on SUN Remote Procedure Calls 24 * 25 * Copyright 1985-2003 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 #include <errno.h> 32 #include <netdb.h> 33 #include <signal.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #include <netinet/in.h> 40 #include <rpc/rpc.h> 41 #include <rpc/svc_soc.h> 42 #include <rpc/key_prot.h> 43 #include <sys/fcntl.h> 44 #include <sys/ioctl.h> 45 #include <sys/param.h> 46 #include <sys/socket.h> 47 #include <sys/sockio.h> 48 #include <sys/mntent.h> 49 #include <sys/mnttab.h> 50 #include <sys/stat.h> 51 #include <sys/time.h> 52 #include <wait.h> 53 #include <sys/systeminfo.h> 54 55 #include <sys/ttold.h> 56 57 #include "rex.h" 58 59 #include <security/pam_appl.h> 60 #include <stropts.h> 61 #include <sys/stream.h> 62 /* #include <sys/termios.h> XXX */ 63 #include <sys/ttcompat.h> 64 65 #include <bsm/audit.h> 66 67 /* #define stderr stdout */ /* XXX */ 68 69 #define ListnerTimeout 300 /* seconds listner stays alive */ 70 #define WaitLimit 10 /* seconds to wait after io is closed */ 71 #define MOUNTED "/etc/mnttab" 72 #define TempDir "/tmp_rex" /* directory to hold temp mounts */ 73 static char TempName[] = "/tmp_rex/rexdXXXXXX"; 74 /* name template for temp mount points */ 75 #define TempMatch 13 /* unique prefix of above */ 76 77 SVCXPRT *ListnerTransp; /* non-null means still a listner */ 78 79 static char **Argv; /* saved argument vector (for ps) */ 80 static char *LastArgv; /* saved end-of-argument vector */ 81 int OutputSocket; /* socket for stop/cont notification */ 82 int MySocket; /* transport socket */ 83 int HasHelper = 0; /* must kill helpers (interactive mode) */ 84 int DesOnly = 0; /* unix credentials too weak */ 85 int confd; /* console fd */ 86 87 int Debug = 0; 88 89 pam_handle_t *pamh; /* PAM handle */ 90 91 time_t time_now; 92 93 extern int Master; /* half of the pty */ 94 extern char **environ; 95 96 int child = 0; /* pid of the executed process */ 97 int ChildStatus = 0; /* saved return status of child */ 98 int ChildDied = 0; /* true when above is valid */ 99 char nfsdir[MAXPATHLEN]; /* file system we mounted */ 100 char *tmpdir; /* where above is mounted, NULL if none */ 101 102 extern void rex_cleanup(void); 103 extern int ValidUser(char *host, uid_t uid, gid_t gid, 104 char *error, char *shell, 105 char *dir, struct rex_start *rst); 106 107 extern void audit_rexd_fail(char *, char *, char *, uid_t, gid_t, 108 char *, char **); 109 extern void audit_rexd_success(char *, char *, uid_t, gid_t, 110 char *, char **); 111 extern void audit_rexd_setup(); 112 113 extern int audit_settid(int); 114 115 /* process rex requests */ 116 void dorex(struct svc_req *rqstp, SVCXPRT *transp); 117 void ListnerTimer(int); /* destroy listener */ 118 void CatchChild(int); /* handle child signals */ 119 void oob(int); /* out of band signals */ 120 void sigwinch(int); /* window change signals -- dummy */ 121 FILE *setmntent(char *fname, char *flag); 122 extern void HelperRead(pollfd_t *fdp, int, int *); 123 124 void 125 main(argc, argv) 126 int argc; 127 char **argv; 128 { 129 /* 130 * the server is a typical RPC daemon, except that we only 131 * accept TCP connections. 132 */ 133 int pollretval; 134 int npollfds = 0; 135 pollfd_t *pollset = NULL; 136 struct sockaddr_in addr; 137 int maxrecsz = RPC_MAXDATASIZE; 138 139 audit_rexd_setup(); /* BSM */ 140 141 /* 142 * Remember the start and extent of argv for setproctitle(). 143 * Open the console for error printouts, but don't let it be 144 * our controlling terminal. 145 */ 146 if (argc > 1) { 147 if (strcmp("-s", argv[1]) == 0) 148 DesOnly = 1; 149 150 if (strcmp("-d", argv[1]) == 0) 151 Debug = 1; 152 } 153 154 if (argc > 2) { 155 if (strcmp("-s", argv[2]) == 0) 156 DesOnly = 1; 157 158 if (strcmp("-d", argv[2]) == 0) 159 Debug = 1; 160 } 161 162 /* 163 * argv start and extent for setproctitle() 164 */ 165 Argv = argv; 166 if (argc > 0) 167 LastArgv = argv[argc-1] + strlen(argv[argc-1]); 168 else 169 LastArgv = NULL; 170 171 /* 172 * console open for errors w/o being the controlling terminal 173 */ 174 175 if ((confd = open("/dev/console", 1)) > 0) { 176 close(1); 177 close(2); 178 confd = dup2(confd, 1); /* console fd copied to stdout */ 179 dup(1); /* console fd copied to stderr */ 180 } 181 182 setsid(); /* get rid of controlling terminal */ 183 184 /* 185 * setup signals 186 */ 187 sigset(SIGCHLD, CatchChild); 188 sigset(SIGPIPE, SIG_IGN); 189 sigset(SIGALRM, ListnerTimer); 190 191 /* 192 * Enable non-blocking mode and maximum record size checks for 193 * connection oriented transports. 194 */ 195 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) { 196 fprintf(stderr, "rexd: unable to set RPC max record size\n"); 197 } 198 199 /* 200 * determine how we started to see if we are already in the background 201 * and get appropriately registered with rpcbind (portmapper) 202 */ 203 204 if (isfrominetd(0)) { 205 /* 206 * Started from inetd: use fd 0 as socket 207 */ 208 if (Debug) 209 printf("Started from inetd\n"); 210 211 if ((ListnerTransp = svctcp_create(0, 0, 0)) == NULL) { 212 fprintf(stderr, "rexd: svctcp_create error\n"); 213 exit(1); 214 } 215 216 if (!svc_register(ListnerTransp, REXPROG, REXVERS, dorex, 0)) { 217 fprintf(stderr, "rexd: service register error\n"); 218 exit(1); 219 } 220 221 alarm(ListnerTimeout); 222 } else { 223 224 if (Debug) 225 printf("started from shell\n"); 226 if (!Debug) { 227 /* 228 * Started from shell, background 229 * thyself and run forever. 230 */ 231 232 int pid = fork(); 233 234 if (pid < 0) { /* fork error */ 235 perror("rpc.rexd: can't fork"); 236 exit(1); 237 } 238 239 if (pid) { /* parent terminates */ 240 exit(0); 241 } 242 } 243 244 /* 245 * child process continues to establish connections 246 */ 247 248 if (Debug) 249 printf("before svctcp_create() call\n"); 250 if ((ListnerTransp = svctcp_create(RPC_ANYSOCK, 0, 0)) 251 == NULL) { 252 fprintf(stderr, "rexd: svctcp_create: error\n"); 253 exit(1); 254 } 255 256 pmap_unset(REXPROG, REXVERS); 257 258 if (!svc_register(ListnerTransp, REXPROG, REXVERS, 259 dorex, IPPROTO_TCP)) { 260 fprintf(stderr, "rexd: service rpc register: error\n"); 261 exit(1); 262 } 263 } 264 265 /* 266 * Create a private temporary directory to hold rexd's mounts 267 */ 268 if (mkdir(TempDir, 0777) < 0) 269 if (errno != EEXIST) { 270 perror("rexd: mkdir"); 271 fprintf(stderr, 272 "rexd: can't create temp directory %s\n", 273 TempDir); 274 exit(1); 275 } 276 277 if (Debug) 278 printf("created temporary directory\n"); 279 280 281 /* 282 * normally we would call svc_run() at this point, but we need to be 283 * informed of when the RPC connection is broken, in case the other 284 * side crashes. 285 */ 286 while (TRUE) { 287 if (Debug) 288 printf("Entered While loop\n"); 289 290 if (MySocket) { 291 int i; 292 char *waste; 293 294 /* try to find MySocket in the pollfd set */ 295 for (i = 0; i < svc_max_pollfd; i++) 296 if (svc_pollfd[i].fd == MySocket) 297 break; 298 /* 299 * If we didn't find it, the connection died for 300 * some random reason, e.g. client crashed. 301 */ 302 if (i == svc_max_pollfd) { 303 if (Debug) 304 printf("Connection died\n"); 305 (void) rex_wait(&waste); 306 rex_cleanup(); 307 exit(1); 308 } 309 } 310 311 /* 312 * Get existing array of pollfd's, should really compress 313 * this but it shouldn't get very large (or sparse). 314 */ 315 if (npollfds != svc_max_pollfd) { 316 pollset = realloc(pollset, 317 sizeof (pollfd_t) * svc_max_pollfd); 318 npollfds = svc_max_pollfd; 319 } 320 321 if (npollfds == 0) 322 break; /* None waiting, hence return */ 323 324 (void) memcpy(pollset, svc_pollfd, 325 sizeof (pollfd_t) * svc_max_pollfd); 326 327 if (Debug) 328 printf("Before select readfds\n"); 329 switch (pollretval = poll(pollset, npollfds, -1)) { 330 case -1: 331 if (Debug) 332 printf("Poll failed\n"); 333 if (errno == EINTR) 334 continue; 335 perror("rexd: poll failed"); 336 exit(1); 337 338 case 0: 339 if (Debug) 340 printf("Poll returned zero\n"); 341 fprintf(stderr, "rexd: poll returned zero\r\n"); 342 continue; 343 344 default: 345 if (Debug) 346 printf("Before HelperRead\n"); 347 if (HasHelper) 348 HelperRead(pollset, npollfds, &pollretval); 349 if (Debug) 350 printf("After HelperRead\n"); 351 time_now = time((time_t *)0); 352 if (Debug) 353 printf("before svc_getreq_poll\n"); 354 svc_getreq_poll(pollset, pollretval); 355 } 356 if (Debug) 357 printf("After switch\n"); 358 } 359 } 360 361 /* 362 * This function gets called after the listner has timed out waiting 363 * for any new connections coming in. 364 */ 365 void 366 ListnerTimer(int junk) 367 { 368 /* 369 * svc_destroy not done here due to problems with M_ERROR 370 * on stream head and inetd 371 */ 372 exit(0); 373 } 374 375 struct authunix_parms 376 *authdes_to_unix(des_cred) 377 struct authdes_cred *des_cred; 378 { 379 struct authunix_parms *unix_cred; 380 static struct authunix_parms au; 381 static uint_t stuff[32]; 382 char publickey[HEXKEYBYTES+1]; 383 384 385 unix_cred = &au; 386 387 unix_cred->aup_gids = (gid_t *)stuff; 388 389 unix_cred->aup_machname = ""; 390 if (getpublickey(des_cred->adc_fullname.name, publickey) == 0) 391 return (NULL); 392 393 if (netname2user(des_cred->adc_fullname.name, 394 &(unix_cred->aup_uid), 395 &(unix_cred->aup_gid), 396 (int *)&(unix_cred->aup_len), 397 unix_cred->aup_gids) == FALSE) 398 return (NULL); 399 else 400 return (unix_cred); 401 } 402 403 /* 404 * dorex - handle one of the rex procedure calls, dispatching to the 405 * correct function. 406 */ 407 void 408 dorex(rqstp, transp) 409 struct svc_req *rqstp; 410 SVCXPRT *transp; 411 { 412 struct rex_start *rst; 413 struct rex_result result; 414 struct authunix_parms *unix_cred; 415 struct sockaddr_in *calleraddr; 416 417 418 if (ListnerTransp) { 419 420 /* 421 * First call - fork a server for this connection 422 */ 423 int fd, pid, count; 424 425 for (count = 0; (pid = fork()) < 0; count++) { 426 if (count > 4) 427 { 428 perror("rexd: cannot fork"); 429 break; 430 } 431 sleep(5); 432 } 433 434 if (pid != 0) { 435 436 /* 437 * Parent - return to service loop to accept further 438 * connections. 439 */ 440 alarm(ListnerTimeout); 441 svc_destroy(transp); 442 return; 443 } 444 445 /* 446 * child - close listner transport to avoid confusion 447 * Also need to close all other service transports 448 * besides the one we are interested in. 449 * Save ours so that we know when it goes away. 450 */ 451 if (Debug) 452 printf("child server process\n"); 453 454 alarm(0); 455 456 457 458 if (transp != ListnerTransp) { 459 460 close(ListnerTransp->xp_sock); 461 xprt_unregister(ListnerTransp); 462 } 463 ListnerTransp = NULL; 464 465 MySocket = transp->xp_sock; 466 467 /* temp workaround to restore sanity in TLI state */ 468 if (transp->xp_sock != 0) 469 t_close(0); /* opened in parent possibly by inetd */ 470 471 /* 472 * XXX: svc_pollfd[] is a read-only structure. This 473 * appears to be dead code, which should be removed. 474 * However, until it can be clearly understood, leaving 475 * in. 476 */ 477 for (fd = 1; fd < svc_max_pollfd; fd++) { 478 if (fd != transp->xp_sock && svc_pollfd[fd].fd == fd) { 479 480 printf("close of fd %d\n", fd); 481 close(fd); 482 svc_pollfd[fd].fd = -1; 483 svc_pollfd[fd].events = 0; 484 svc_pollfd[fd].revents = 0; 485 } 486 } 487 } 488 489 /* 490 * execute the requested prodcedure 491 */ 492 switch (rqstp->rq_proc) { 493 case NULLPROC: 494 if (Debug) /* XXX */ 495 printf("dorex: call to NULLPROC\n"); 496 497 if (svc_sendreply(transp, xdr_void, 0) == FALSE) { 498 499 fprintf(stderr, "rexd: nullproc err"); 500 exit(1); 501 } 502 return; 503 504 case REXPROC_START: 505 if (Debug) /* XXX */ 506 printf("dorex: call to REXPROC_START\n"); 507 508 509 rst = (struct rex_start *)malloc(sizeof (struct rex_start)); 510 memset((char *)rst, '\0', sizeof (*rst)); 511 512 if (svc_getargs(transp, xdr_rex_start, (char *)rst) == FALSE) { 513 514 svcerr_decode(transp); 515 exit(1); 516 } 517 if (Debug) 518 printf("svc_getargs: suceeded\n"); 519 520 if (rqstp->rq_cred.oa_flavor == AUTH_DES) { 521 522 unix_cred = authdes_to_unix(rqstp->rq_clntcred); 523 524 } else if (rqstp->rq_cred.oa_flavor == AUTH_UNIX) { 525 526 if (DesOnly) { 527 fprintf(stderr, 528 "Unix too weak auth(DesOnly)!\n"); 529 unix_cred = NULL; 530 } else 531 unix_cred = 532 (struct authunix_parms *)rqstp->rq_clntcred; 533 534 } else { 535 536 fprintf(stderr, "Unknown weak auth!\n"); 537 svcerr_weakauth(transp); 538 sleep(5); 539 exit(1); 540 } 541 542 if (unix_cred == NULL) { 543 544 svcerr_weakauth(transp); 545 sleep(5); 546 exit(1); 547 } 548 549 calleraddr = svc_getcaller(transp); 550 551 result.rlt_stat = (int)rex_startup(rst, 552 unix_cred, 553 (char **)&result.rlt_message, 554 calleraddr); 555 556 if (Debug) 557 printf("rex_startup: completed\n"); 558 559 if (svc_sendreply(transp, xdr_rex_result, (char *)&result) 560 == FALSE) { 561 fprintf(stderr, "rexd: reply failed\n"); 562 rex_cleanup(); 563 exit(1); 564 } 565 566 if (Debug) 567 printf("svc_sendreply: suceeded\n"); 568 569 if (result.rlt_stat) { 570 571 rex_cleanup(); 572 exit(0); 573 } 574 return; 575 576 case REXPROC_MODES: 577 { 578 struct rex_ttymode mode; 579 580 if (Debug) /* XXX */ 581 printf("dorex: call to REXPROC_MODES\n"); 582 583 if (svc_getargs(transp, xdr_rex_ttymode, 584 (char *)&mode) == FALSE) { 585 svcerr_decode(transp); 586 exit(1); 587 } 588 if (Debug) 589 printf("svc_getargs succ REXPROC_MODES call\n"); 590 591 SetPtyMode(&mode); /* XXX Fix? */ 592 593 if (svc_sendreply(transp, xdr_void, 0) == FALSE) { 594 595 fprintf(stderr, "rexd: mode reply failed"); 596 exit(1); 597 } 598 } 599 return; 600 601 case REXPROC_WINCH: /* XXX Fix? */ 602 { 603 struct rex_ttysize size; 604 605 if (Debug) /* XXX */ 606 printf("dorex: call to REXPROC_WINCH\n"); 607 608 if (svc_getargs(transp, xdr_rex_ttysize, (char *)&size) 609 == FALSE) { 610 svcerr_decode(transp); 611 exit(1); 612 } 613 614 SetPtySize(&size); 615 616 if (svc_sendreply(transp, xdr_void, 0) == FALSE) { 617 618 fprintf(stderr, 619 "rexd: window change reply failed"); 620 exit(1); 621 } 622 } 623 return; 624 625 case REXPROC_SIGNAL: 626 { 627 int sigNumber; 628 629 if (Debug) /* XXX */ 630 printf("dorex: call to REXPROC_SIGNAL\n"); 631 632 if (svc_getargs(transp, xdr_int, 633 (char *)&sigNumber) == FALSE) { 634 svcerr_decode(transp); 635 exit(1); 636 } 637 638 SendSignal(sigNumber); 639 640 if (svc_sendreply(transp, xdr_void, 0) == FALSE) { 641 fprintf(stderr, "rexd: signal reply failed"); 642 exit(1); 643 } 644 } 645 return; 646 647 case REXPROC_WAIT: 648 if (Debug) /* XXX */ 649 printf("dorex: call to REXPROC_WAIT\n"); 650 651 result.rlt_stat = rex_wait(&result.rlt_message); 652 653 if (svc_sendreply(transp, xdr_rex_result, (char *)&result) 654 == FALSE) { 655 fprintf(stderr, "rexd: reply failed\n"); 656 exit(1); 657 } 658 659 rex_cleanup(); 660 exit(0); 661 662 /* NOTREACHED */ 663 default: 664 if (Debug) 665 printf("dorex: call to bad process!\n"); 666 667 svcerr_noproc(transp); 668 exit(1); 669 } 670 } 671 672 /* 673 * signal handler for SIGCHLD - called when user process dies or is stopped 674 */ 675 void 676 CatchChild(int junk) 677 { 678 pid_t pid; 679 int status; 680 681 if (Debug) 682 printf("Enter Catchild\n"); 683 684 while ((pid = waitpid((pid_t)-1, &status, WNOHANG|WUNTRACED)) > 0) { 685 686 if (Debug) printf("After waitpid\n"); 687 if (pid == child) { 688 if (Debug) 689 printf("pid==child\n"); 690 if (WIFSTOPPED(status)) { 691 sigset_t nullsigset; 692 693 if (Debug) 694 printf("WIFSTOPPED\n"); 695 /* tell remote client to stop */ 696 send(OutputSocket, "", 1, MSG_OOB); 697 698 sigemptyset(&nullsigset); 699 /* port of BSD sigpause(0); */ 700 sigsuspend(&nullsigset); 701 /* restart child */ 702 /* killpg() of SunOS 4.1.1 */ 703 kill((-child), SIGCONT); 704 return; 705 } 706 707 /* 708 * XXX this probably does not cover all interesting 709 * exit cases hence reread the man page to determine 710 * if we need more data or more test cases 711 */ 712 713 ChildStatus = status; 714 ChildDied = 1; 715 716 if (HasHelper && svc_pollfd[Master].fd == -1) { 717 if (Debug) 718 printf("Within If HasHelper\n"); 719 KillHelper(child); 720 HasHelper = 0; 721 } 722 } 723 } 724 } 725 726 /* 727 * oob -- called when we should restart the stopped child. 728 */ 729 void 730 oob(int junk) 731 { 732 int atmark; 733 char waste[BUFSIZ], mark; 734 735 for (;;) { 736 737 if (ioctl(OutputSocket, SIOCATMARK, &atmark) < 0) { 738 perror("ioctl"); 739 break; 740 } 741 742 if (atmark) 743 break; 744 745 (void) read(OutputSocket, waste, sizeof (waste)); 746 } 747 748 (void) recv(OutputSocket, &mark, 1, MSG_OOB); 749 } 750 751 /* 752 * rex_wait - wait for command to finish, unmount the file system, 753 * and return the exit status. 754 * message gets an optional string error message. 755 */ 756 int 757 rex_wait(message) 758 char **message; 759 { 760 static char error[1024]; 761 int count; 762 763 *message = error; 764 strcpy(error, ""); 765 if (child == 0) { 766 errprintf(error, "No process to wait for!\n"); 767 rex_cleanup(); 768 return (1); 769 } 770 771 kill(child, SIGHUP); 772 773 for (count = 0; !ChildDied && count < WaitLimit; count++) 774 sleep(1); 775 776 if (ChildStatus & 0xFF) 777 return (ChildStatus); 778 779 return (ChildStatus >> 8); 780 } 781 782 783 /* 784 * cleanup - unmount and remove our temporary directory 785 */ 786 void 787 rex_cleanup() 788 { 789 790 if (tmpdir) { 791 792 if (child && !ChildDied) { 793 794 fprintf(stderr, 795 "rexd: child killed to unmount %s\r\n", 796 nfsdir); 797 kill(child, SIGKILL); 798 } 799 chdir("/"); 800 801 if (nfsdir[0] && umount_nfs(nfsdir, tmpdir)) 802 fprintf(stderr, "rexd: couldn't umount %s from %s\r\n", 803 nfsdir, 804 tmpdir); 805 if (rmdir(tmpdir) < 0) 806 if (errno != EBUSY) 807 perror("rmdir"); 808 tmpdir = NULL; 809 810 } 811 812 if (Debug) 813 printf("rex_cleaup: HasHelper=%d\n", HasHelper); 814 if (HasHelper) 815 KillHelper(child); 816 817 HasHelper = 0; 818 } 819 820 821 /* 822 * This function does the server work to get a command executed 823 * Returns 0 if OK, nonzero if error 824 */ 825 int 826 rex_startup(rst, ucred, message, calleraddr) 827 struct rex_start *rst; 828 struct authunix_parms *ucred; 829 char **message; 830 struct sockaddr_in *calleraddr; 831 { 832 char hostname[255]; 833 char *p, *wdhost, *fsname, *subdir; 834 char dirbuf[1024]; 835 static char error[1024]; 836 char defaultShell[1024]; /* command executed if none given */ 837 char defaultDir[1024]; /* directory used if none given */ 838 int len; 839 int fd0, fd1, fd2; 840 extern pam_handle_t *pamh; 841 char *user = NULL; 842 843 if (Debug) 844 printf("Beginning of Rex_Startup\n"); 845 846 if (child) { /* already started */ 847 if (Debug) 848 printf("Killing \"child\" process\n"); 849 kill((-child), SIGKILL); /* killpg() of SunOS 4.1.1 */ 850 return (1); 851 } 852 853 854 *message = error; 855 (void) strcpy(error, ""); 856 /* sigset(SIGCHLD, CatchChild); */ 857 858 859 if (ValidUser(ucred->aup_machname, 860 (uid_t)ucred->aup_uid, 861 (gid_t)ucred->aup_gid, 862 error, 863 defaultShell, defaultDir, rst)) 864 return (1); 865 866 if (rst->rst_fsname && strlen(rst->rst_fsname)) { 867 fsname = rst->rst_fsname; 868 subdir = rst->rst_dirwithin; 869 wdhost = rst->rst_host; 870 } else { 871 fsname = defaultDir; 872 subdir = ""; 873 wdhost = hostname; 874 } 875 876 sysinfo(SI_HOSTNAME, hostname, 255); 877 878 if (Debug) 879 printf("rexd: errno %d after gethostname\n", errno); 880 881 if (Debug) { 882 printf("rex_startup on host %s:\nrequests fsname=%s", 883 hostname, fsname); 884 printf("\t\tsubdir=%s\t\twdhost=%s\n", subdir, wdhost); 885 } 886 if (strcmp(wdhost, hostname) == 0) { 887 888 /* 889 * The requested directory is local to our machine, 890 * so just change to it. 891 */ 892 strcpy(dirbuf, fsname); 893 } else { 894 895 static char wanted[1024]; 896 static char mountedon[1024]; 897 898 strcpy(wanted, wdhost); 899 strcat(wanted, ":"); 900 strcat(wanted, fsname); 901 902 if (AlreadyMounted(wanted, mountedon)) { 903 904 if (Debug) 905 printf("AlreadyMounted (%d)\n", errno); 906 907 /* 908 * The requested directory is already mounted. If the 909 * mount is not by another rexd, just change to it. 910 * Otherwise, mount it again. If just changing to 911 * the mounted directy, be careful. It might be mounted 912 * in a different place. 913 * (dirbuf is modified in place!) 914 */ 915 if (strncmp(mountedon, TempName, TempMatch) == 0) { 916 tmpdir = mktemp(TempName); 917 /* 918 * XXX errno is set to ENOENT on success 919 * of mktemp because of accesss checks for file 920 */ 921 if (errno == ENOENT) 922 errno = 0; 923 924 if (mkdir(tmpdir, 0777)) { 925 perror("Already Mounted"); 926 if (pamh) { 927 pam_end(pamh, PAM_ABORT); 928 pamh = NULL; 929 } 930 return (1); 931 } 932 933 if (Debug) 934 printf("created %s (%d)\n", 935 tmpdir, errno); 936 937 strcpy(nfsdir, wanted); 938 939 if (mount_nfs(wanted, tmpdir, error)) { 940 if (Debug) 941 printf("mount_nfs:error return\n"); 942 if (pamh) { 943 pam_end(pamh, PAM_ABORT); 944 pamh = NULL; 945 } 946 return (1); 947 } 948 if (Debug) 949 printf("mount_nfs: success return\n"); 950 951 strcpy(dirbuf, tmpdir); 952 953 } else 954 strcpy(dirbuf, mountedon); 955 956 } else { 957 if (Debug) 958 printf("not AlreadyMounted (%d)\n", errno); 959 /* 960 * The requested directory is not mounted anywhere, 961 * so try to mount our own copy of it. We set nfsdir 962 * so that it gets unmounted later, and tmpdir so that 963 * it also gets removed when we are done. 964 */ 965 tmpdir = mktemp(TempName); 966 967 /* 968 * XXX errno is set to ENOENT on success of mktemp 969 * becuase of accesss checks for file 970 */ 971 if (errno == ENOENT) 972 errno = 0; 973 if (mkdir(tmpdir, 0777)) { 974 perror("Not Already Mounted"); 975 if (pamh) { 976 pam_end(pamh, PAM_ABORT); 977 pamh = NULL; 978 } 979 return (1); 980 } 981 982 if (Debug) 983 printf("created %s (%d)\n", tmpdir, errno); 984 985 strcpy(nfsdir, wanted); 986 987 if (mount_nfs(wanted, tmpdir, error)) { 988 if (Debug) 989 printf("mount_nfs:error return\n"); 990 if (pamh) { 991 pam_end(pamh, PAM_ABORT); 992 pamh = NULL; 993 } 994 return (1); 995 } 996 if (Debug) 997 printf("mount_nfs: success return\n"); 998 strcpy(dirbuf, tmpdir); 999 } 1000 } 1001 1002 /* 1003 * "dirbuf" now contains the local mount point, so just tack on 1004 * the subdirectory to get the pathname to which we "chdir" 1005 */ 1006 strcat(dirbuf, subdir); 1007 1008 1009 fd0 = socket(AF_INET, SOCK_STREAM, 0); 1010 if (Debug) 1011 printf("Before doconnect\n"); 1012 fd0 = doconnect(calleraddr, rst->rst_port0, fd0); 1013 OutputSocket = fd0; 1014 1015 /* 1016 * Arrange for fd0 to send the SIGURG signal when out-of-band data 1017 * arrives, which indicates that we should send the stopped child a 1018 * SIGCONT signal so that we can resume work. 1019 */ 1020 (void) fcntl(fd0, F_SETOWN, getpid()); 1021 /* ioctl(fd0, SIOCSPGRP, ?X?); */ 1022 sigset(SIGURG, oob); 1023 1024 if (Debug) 1025 printf("Before \"use same port\"\n"); 1026 if (rst->rst_port0 == rst->rst_port1) { 1027 /* 1028 * use the same connection for both stdin and stdout 1029 */ 1030 fd1 = fd0; 1031 } 1032 1033 if (rst->rst_flags & REX_INTERACTIVE) { 1034 /* 1035 * allocate a pseudo-terminal if necessary 1036 */ 1037 if (Debug) 1038 printf("Before AllocatePty call\n"); 1039 1040 /* AllocatePty has grantpt() call which has bug */ 1041 /* Hence clear SIGCHLD handler setting */ 1042 sigset(SIGCHLD, SIG_DFL); 1043 if (AllocatePty(fd0, fd1)) { 1044 errprintf(error, "rexd: cannot allocate a pty\n"); 1045 if (pamh) { 1046 pam_end(pamh, PAM_ABORT); 1047 pamh = NULL; 1048 } 1049 return (1); 1050 } 1051 HasHelper = 1; 1052 } 1053 /* 1054 * this sigset()call moved to after AllocatePty() call 1055 * because a bug in waitpid() inside grantpt() 1056 * causes CatchChild() to be invoked. 1057 */ 1058 1059 sigset(SIGCHLD, CatchChild); 1060 1061 if (rst->rst_flags & REX_INTERACTIVE) { 1062 sigset(SIGWINCH, sigwinch); /* a dummy signal handler */ 1063 /* block the sigpause until signal in */ 1064 /* child releases the signal */ 1065 sighold(SIGWINCH); 1066 } 1067 1068 if (Debug) 1069 printf("Before a \"child\" fork\n"); 1070 1071 child = fork(); 1072 1073 if (child < 0) { 1074 errprintf(error, "rexd: can't fork\n"); 1075 if (pamh) { 1076 pam_end(pamh, PAM_ABORT); 1077 pamh = NULL; 1078 } 1079 return (1); 1080 } 1081 1082 if (child) { 1083 /* 1084 * parent rexd: close network connections if needed, 1085 * then return to the main loop. 1086 */ 1087 if ((rst->rst_flags & REX_INTERACTIVE) == 0) { 1088 close(fd0); 1089 close(fd1); 1090 } 1091 if (Debug) 1092 printf("Parent ret to main loop, child does startup\n"); 1093 if (pamh) { 1094 pam_end(pamh, PAM_SUCCESS); 1095 pamh = NULL; 1096 } 1097 return (0); 1098 } 1099 1100 /* child rexd */ 1101 1102 if (Debug) 1103 printf("Child rexd\n"); 1104 1105 /* setpgrp(0, 0) */ 1106 setsid(); /* make session leader */ 1107 1108 if (Debug) 1109 printf("After setsid\n"); 1110 1111 if (rst->rst_flags & REX_INTERACTIVE) { 1112 if (Debug) 1113 printf("Before OpenPtySlave\n"); 1114 /* reopen slave so that child has controlling tty */ 1115 OpenPtySlave(); 1116 if (Debug) 1117 printf("After OpenPtySlave\n"); 1118 } 1119 1120 if (rst->rst_port0 != rst->rst_port1) { 1121 1122 if (Debug) 1123 printf("rst_port0 != rst_port1\n"); /* XXX */ 1124 1125 fd1 = socket(AF_INET, SOCK_STREAM, 0); 1126 shutdown(fd0, 1); /* 1=>further sends disallowed */ 1127 fd1 = doconnect(calleraddr, rst->rst_port1, fd1); 1128 shutdown(fd1, 0); /* 0=>further receives disallowed */ 1129 } 1130 1131 if (rst->rst_port1 == rst->rst_port2) { 1132 if (Debug) 1133 printf("rst_port1 == rst_port2\n"); /* XXX */ 1134 1135 /* 1136 * Use the same connection for both stdout and stderr 1137 */ 1138 fd2 = fd1; 1139 } else { 1140 if (Debug) 1141 printf("rst_port1 != rst_port2\n"); /* XXX */ 1142 1143 fd2 = socket(AF_INET, SOCK_STREAM, 0); 1144 fd2 = doconnect(calleraddr, rst->rst_port2, fd2); 1145 shutdown(fd2, 0); /* 0=>further receives disallowed */ 1146 } 1147 1148 if (rst->rst_flags & REX_INTERACTIVE) { 1149 1150 /* 1151 * use ptys instead of sockets in interactive mode 1152 */ 1153 DoHelper(&fd0, &fd1, &fd2); 1154 LoginUser(); 1155 } 1156 1157 dup2(fd0, 0); 1158 dup2(fd1, 1); 1159 dup2(fd2, 2); 1160 1161 /* setup terminal ID (use read file descriptor) */ 1162 if (audit_settid(fd0) != 0) { 1163 errprintf("cannot set audit characteristics\n"); 1164 return (1); 1165 } 1166 1167 closefrom(3); 1168 1169 if (Debug) 1170 printf("After close-all-fds-loop-- errno=%d\n", errno); 1171 1172 environ = rst->rst_env; 1173 1174 if (pam_get_item(pamh, PAM_USER, (void **)&user) != PAM_SUCCESS) { 1175 audit_rexd_fail("user id is not valid", 1176 ucred->aup_machname, 1177 user, 1178 ucred->aup_uid, 1179 ucred->aup_gid, 1180 defaultShell, 1181 rst->rst_cmd); /* BSM */ 1182 fprintf(stderr, "rexd: invalid uid/gid.\n"); 1183 exit(1); 1184 } 1185 1186 /* set the real (and effective) GID */ 1187 if (setgid(ucred->aup_gid) == -1) { 1188 fprintf(stderr, "rexd: invalid gid.\n"); 1189 exit(1); 1190 } 1191 /* Set the supplementary group access list. */ 1192 if (setgroups(ucred->aup_len, (gid_t *)ucred->aup_gids) == -1) { 1193 fprintf(stderr, "rexd: invalid group list.\n"); 1194 exit(1); 1195 } 1196 1197 if (pam_setcred(pamh, PAM_ESTABLISH_CRED) != PAM_SUCCESS) { 1198 audit_rexd_fail("user id is not valid", 1199 ucred->aup_machname, 1200 user, 1201 ucred->aup_uid, 1202 ucred->aup_gid, 1203 defaultShell, 1204 rst->rst_cmd); /* BSM */ 1205 fprintf(stderr, "rexd: invalid uid/gid.\n"); 1206 exit(1); 1207 } 1208 1209 audit_rexd_success(ucred->aup_machname, 1210 user, 1211 ucred->aup_uid, 1212 ucred->aup_gid, 1213 defaultShell, 1214 rst->rst_cmd); /* BSM */ 1215 1216 /* set the real (and effective) UID */ 1217 if (setuid(ucred->aup_uid) == -1) { 1218 fprintf(stderr, "rexd: invalid uid.\n"); 1219 exit(1); 1220 } 1221 1222 if (pamh) { 1223 pam_end(pamh, PAM_SUCCESS); 1224 pamh = NULL; 1225 } 1226 1227 if (Debug) /* XXX */ 1228 fprintf(stderr, "uid %d gid %d (%d)\n", 1229 ucred->aup_uid, ucred->aup_gid, errno); 1230 1231 if (chdir(dirbuf)) { 1232 fprintf(stderr, "rexd: can't chdir to %s\n", dirbuf); 1233 exit(1); 1234 } 1235 1236 sigset(SIGINT, SIG_DFL); 1237 sigset(SIGHUP, SIG_DFL); 1238 sigset(SIGQUIT, SIG_DFL); 1239 1240 if (rst->rst_flags & REX_INTERACTIVE) { 1241 /* pause to sync with first SIGWINCH sent as part of */ 1242 sigpause(SIGWINCH); 1243 /* protocol and handled by parent doing other rex primitves */ 1244 sigrelse(SIGWINCH); 1245 sigset(SIGWINCH, SIG_DFL); 1246 } 1247 1248 if (rst->rst_cmd == (char **)NULL) { 1249 1250 /* 1251 * Null command means execute the default shell for this user 1252 */ 1253 char *args[2]; 1254 1255 args[0] = defaultShell; 1256 args[1] = NULL; 1257 1258 execvp(defaultShell, args); 1259 1260 fprintf(stderr, "rexd: can't exec shell %s\n", defaultShell); 1261 exit(1); 1262 } 1263 1264 if (Debug) 1265 for (len = 0; rst->rst_cmd[len] != (char *)NULL && 1266 *rst->rst_cmd[len] != NULL; len++) 1267 printf("cmds: %s (%d)\n", rst->rst_cmd[len], errno); 1268 1269 1270 /* XXX */ 1271 if (Debug) 1272 for (len = 0; rst->rst_env[len] != (char *)NULL && 1273 *rst->rst_env[len] != NULL; len++) 1274 printf("envs: %s\n", rst->rst_env[len]); 1275 1276 1277 execvp(rst->rst_cmd[0], rst->rst_cmd); 1278 1279 /* XXX get rid of errno in parens */ 1280 fprintf(stderr, "rexd: can't exec %s (%d)\n", *rst->rst_cmd, errno); 1281 exit(1); 1282 } 1283 1284 /* 1285 * Search the mount table to see if the given file system is already 1286 * mounted. If so, return the place that it is mounted on. 1287 */ 1288 int 1289 AlreadyMounted(fsname, mountedon) 1290 char *fsname; 1291 char *mountedon; 1292 { 1293 FILE *table; 1294 struct mnttab mt; 1295 1296 table = setmntent(MOUNTED, "r"); 1297 if (table == NULL) 1298 return (0); 1299 1300 while ((getmntent(table, &mt)) != (-1)) { 1301 1302 if (strcmp(mt.mnt_special, fsname) == 0) { 1303 strcpy(mountedon, mt.mnt_mountp); 1304 endmntent(table); 1305 return (1); 1306 } 1307 } 1308 endmntent(table); 1309 1310 return (0); 1311 } 1312 1313 1314 /* 1315 * connect to the indicated IP address/port, and return the 1316 * resulting file descriptor. 1317 */ 1318 int 1319 doconnect(sin, port, fd) 1320 struct sockaddr_in *sin; 1321 short port; 1322 int fd; 1323 { 1324 sin->sin_port = ntohs(port); 1325 1326 if (connect(fd, (struct sockaddr *)sin, sizeof (*sin))) { 1327 1328 perror("rexd: connect"); 1329 exit(1); 1330 } 1331 1332 return (fd); 1333 } 1334 1335 void 1336 sigwinch(int junk) 1337 { 1338 } 1339 1340 /* 1341 * SETPROCTITLE -- set the title of this process for "ps" 1342 * 1343 * Does nothing if there were not enough arguments on the command 1344 * line for the information. 1345 * 1346 * Side Effects: 1347 * Clobbers argv[] of our main procedure. 1348 */ 1349 void 1350 setproctitle(user, host) 1351 char *user, *host; 1352 { 1353 register char *tohere; 1354 1355 tohere = Argv[0]; 1356 if ((int)(LastArgv == NULL) || 1357 (int)(strlen(user)+strlen(host)+3) > 1358 (int)(LastArgv - tohere)) 1359 return; 1360 1361 *tohere++ = '-'; /* So ps prints (rpc.rexd) */ 1362 sprintf(tohere, "%s@%s", user, host); 1363 while (*tohere++) /* Skip to end of printf output */ 1364 ; 1365 while (tohere < LastArgv) /* Avoid confusing ps */ 1366 *tohere++ = ' '; 1367 } 1368 1369 1370 /* 1371 * Determine if started from inetd or not 1372 */ 1373 1374 int 1375 isfrominetd(fd) 1376 int fd; 1377 { 1378 /* 1379 * If fd looks like a TLI endpoint, we assume 1380 * that we were started by a port monitor. If 1381 * t_getstate fails with TBADF, this is not a 1382 * TLI endpoint. 1383 */ 1384 if (t_getstate(0) != -1 || t_errno != TBADF) 1385 return (1); 1386 return (0); 1387 } 1388