summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/rcmdsh.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/net/rcmdsh.c')
-rw-r--r--src/lib/libc/net/rcmdsh.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/lib/libc/net/rcmdsh.c b/src/lib/libc/net/rcmdsh.c
new file mode 100644
index 0000000000..93523a4c56
--- /dev/null
+++ b/src/lib/libc/net/rcmdsh.c
@@ -0,0 +1,124 @@
1/* $OpenBSD: rcmdsh.c,v 1.5 1998/04/25 16:23:58 millert Exp $ */
2
3/*
4 * This is an rcmd() replacement originally by
5 * Chris Siebenmann <cks@utcc.utoronto.ca>.
6 */
7
8#if defined(LIBC_SCCS) && !defined(lint)
9static char *rcsid = "$OpenBSD: rcmdsh.c,v 1.5 1998/04/25 16:23:58 millert Exp $";
10#endif /* LIBC_SCCS and not lint */
11
12#include <sys/types.h>
13#include <sys/socket.h>
14#include <sys/wait.h>
15#include <signal.h>
16#include <errno.h>
17#include <netdb.h>
18#include <stdio.h>
19#include <string.h>
20#include <pwd.h>
21#include <paths.h>
22#include <unistd.h>
23
24/*
25 * This is a replacement rcmd() function that uses the rsh(1)
26 * program in place of a direct rcmd(3) function call so as to
27 * avoid having to be root. Note that rport is ignored.
28 */
29/* ARGSUSED */
30int
31rcmdsh(ahost, rport, locuser, remuser, cmd, rshprog)
32 char **ahost;
33 int rport;
34 const char *locuser, *remuser, *cmd;
35 char *rshprog;
36{
37 struct hostent *hp;
38 int cpid, sp[2];
39 char *p;
40 struct passwd *pw;
41
42 /* What rsh/shell to use. */
43 if (rshprog == NULL)
44 rshprog = _PATH_RSH;
45
46 /* locuser must exist on this host. */
47 if ((pw = getpwnam(locuser)) == NULL) {
48 (void) fprintf(stderr, "rcmdsh: unknown user: %s\n", locuser);
49 return(-1);
50 }
51
52 /* Validate remote hostname. */
53 if (strcmp(*ahost, "localhost") != 0) {
54 if ((hp = gethostbyname(*ahost)) == NULL) {
55 herror(*ahost);
56 return(-1);
57 }
58 *ahost = hp->h_name;
59 }
60
61 /* Get a socketpair we'll use for stdin and stdout. */
62 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) < 0) {
63 perror("rcmdsh: socketpair");
64 return(-1);
65 }
66
67 cpid = fork();
68 if (cpid < 0) {
69 perror("rcmdsh: fork failed");
70 return(-1);
71 } else if (cpid == 0) {
72 /*
73 * Child. We use sp[1] to be stdin/stdout, and close sp[0].
74 */
75 (void) close(sp[0]);
76 if (dup2(sp[1], 0) < 0 || dup2(0, 1) < 0) {
77 perror("rcmdsh: dup2 failed");
78 _exit(255);
79 }
80 /* Fork again to lose parent. */
81 cpid = fork();
82 if (cpid < 0) {
83 perror("rcmdsh: fork to lose parent failed");
84 _exit(255);
85 }
86 if (cpid > 0)
87 _exit(0);
88
89 /* In grandchild here. Become local user for rshprog. */
90 if (setuid(pw->pw_uid)) {
91 (void) fprintf(stderr, "rcmdsh: setuid(%u): %s\n",
92 pw->pw_uid, strerror(errno));
93 _exit(255);
94 }
95
96 /*
97 * If remote host is "localhost" and local and remote user
98 * are the same, avoid running remote shell for efficiency.
99 */
100 if (!strcmp(*ahost, "localhost") && !strcmp(locuser, remuser)) {
101 if (pw->pw_shell[0] == '\0')
102 rshprog = _PATH_BSHELL;
103 else
104 rshprog = pw->pw_shell;
105 p = strrchr(rshprog, '/');
106 execlp(rshprog, p ? p+1 : rshprog, "-c", cmd,
107 (char *) NULL);
108 } else {
109 p = strrchr(rshprog, '/');
110 execlp(rshprog, p ? p+1 : rshprog, *ahost, "-l",
111 remuser, cmd, (char *) NULL);
112 }
113 (void) fprintf(stderr, "rcmdsh: execlp %s failed: %s\n",
114 rshprog, strerror(errno));
115 _exit(255);
116 } else {
117 /* Parent. close sp[1], return sp[0]. */
118 (void) close(sp[1]);
119 /* Reap child. */
120 (void) wait(NULL);
121 return(sp[0]);
122 }
123 /* NOTREACHED */
124}