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