Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.bin / rdist / rshrcmd.c
1
2 /*
3  * This is an rcmd() replacement originally by 
4  * Chris Siebenmann <cks@utcc.utoronto.ca>.
5  */
6
7 #ifndef lint
8 static const char rcsid[] =
9   "$FreeBSD: src/usr.bin/rdist/rshrcmd.c,v 1.6 1999/08/28 01:05:08 peter Exp $";
10 #endif /* not lint */
11
12 #include        "defs.h"
13
14 #if     !defined(DIRECT_RCMD)
15
16 #include      <sys/socket.h>
17 #include      <sys/wait.h>
18 #include      <signal.h>
19 #include      <netdb.h>
20
21 static char *
22 xbasename(s)
23         char *s;
24 {
25         char *ret;
26
27         ret = strrchr(s, '/');
28         if (ret && ret[1])
29                 return (ret + 1);
30         return s;
31 }
32
33
34 /*
35  * This is a replacement rcmd() function that uses the rsh(1c)
36  * program in place of a direct rcmd() function call so as to
37  * avoid having to be root.
38  */
39 int
40 rshrcmd(ahost, port, luser, ruser, cmd, fd2p)
41         char    **ahost;
42         u_short port;
43         char    *luser, *ruser, *cmd;
44         int     *fd2p;
45 {
46         int             cpid;
47         struct hostent  *hp;
48         int             sp[2];
49
50         /* insure that we are indeed being used as we thought. */
51         if (fd2p != 0)
52                 return -1;
53         /* validate remote hostname. */
54         hp = gethostbyname(*ahost);
55         if (hp == 0) {
56                 error("%s: unknown host", *ahost);
57                 return -1;
58         }
59         /* *ahost = hp->h_name; *//* This makes me nervous. */
60
61         /* get a socketpair we'll use for stdin and stdout. */
62         if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0) {
63                 error("socketpair(AF_UNIX, SOCK_STREAM, 0) failed: %s.", 
64                       strerror(errno));
65                 return -1;
66         }
67
68         cpid = fork();
69         if (cpid < 0) {
70                 error("fork failed: %s.", strerror(errno));
71                 return -1;      /* error. */
72         }
73         if (cpid == 0) {
74                 /* child. we use sp[1] to be stdin/stdout, and close
75                    sp[0]. */
76                 (void) close(sp[0]);
77                 if (dup2(sp[1], 0) < 0 || dup2(0,1) < 0) {
78                         error("dup2 failed: %s.", strerror(errno));
79                         _exit(255);
80                 }
81                 /* fork again to lose parent. */
82                 cpid = fork();
83                 if (cpid < 0) {
84                         error("fork to lose parent failed: %s.", strerror(errno));
85                         _exit(255);
86                 }
87                 if (cpid > 0)
88                         _exit(0);
89                 /* in grandchild here. */
90
91                 /*
92                  * If we are rdist'ing to "localhost" as the same user
93                  * as we are, then avoid running remote shell for efficiency.
94                  */
95                 if (strcmp(*ahost, "localhost") == 0 &&
96                     strcmp(luser, ruser) == 0) {
97                         execlp(_PATH_BSHELL, xbasename(_PATH_BSHELL), "-c",
98                                cmd, (char *) NULL);
99                         error("execlp %s failed: %s.", _PATH_BSHELL, strerror(errno));
100                 } else {
101                         execlp(path_rsh, xbasename(path_rsh), 
102                                *ahost, "-l", ruser, cmd, (char *) NULL);
103                         error("execlp %s failed: %s.", path_rsh,
104                                 strerror(errno));
105                 }
106                 _exit(255);
107         }
108         if (cpid > 0) {
109                 /* parent. close sp[1], return sp[0]. */
110                 (void) close(sp[1]);
111                 /* reap child. */
112                 (void) wait(0);
113                 return sp[0];
114         }
115         /*NOTREACHED*/
116         return (-1);
117 }
118
119 #endif  /* !DIRECT_RCMD */