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.c190
1 files changed, 190 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..28f0ca88a6
--- /dev/null
+++ b/src/lib/libc/net/rcmdsh.c
@@ -0,0 +1,190 @@
1/* $OpenBSD: rcmdsh.c,v 1.10 2005/03/25 13:24:12 otto Exp $ */
2
3/*
4 * Copyright (c) 2001, MagniComp
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the MagniComp nor the names of its contributors may
16 * be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
28 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/*
32 * This is an rcmd() replacement originally by
33 * Chris Siebenmann <cks@utcc.utoronto.ca>.
34 */
35
36#if defined(LIBC_SCCS) && !defined(lint)
37static char *rcsid = "$OpenBSD: rcmdsh.c,v 1.10 2005/03/25 13:24:12 otto Exp $";
38#endif /* LIBC_SCCS and not lint */
39
40#include <sys/types.h>
41#include <sys/socket.h>
42#include <sys/wait.h>
43#include <signal.h>
44#include <errno.h>
45#include <netdb.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <pwd.h>
50#include <paths.h>
51#include <unistd.h>
52
53/*
54 * This is a replacement rcmd() function that uses the rsh(1)
55 * program in place of a direct rcmd(3) function call so as to
56 * avoid having to be root. Note that rport is ignored.
57 */
58/* ARGSUSED */
59int
60rcmdsh(char **ahost, int rport, const char *locuser, const char *remuser,
61 const char *cmd, char *rshprog)
62{
63 struct hostent *hp;
64 int sp[2];
65 pid_t cpid;
66 char *p;
67 struct passwd *pw;
68
69 /* What rsh/shell to use. */
70 if (rshprog == NULL)
71 rshprog = _PATH_RSH;
72
73 /* locuser must exist on this host. */
74 if ((pw = getpwnam(locuser)) == NULL) {
75 (void) fprintf(stderr, "rcmdsh: unknown user: %s\n", locuser);
76 return(-1);
77 }
78
79 /* Validate remote hostname. */
80 if (strcmp(*ahost, "localhost") != 0) {
81 if (((hp = gethostbyname2(*ahost, AF_INET)) == NULL) &&
82 ((hp = gethostbyname2(*ahost, AF_INET6)) == NULL)) {
83 herror(*ahost);
84 return(-1);
85 }
86 *ahost = hp->h_name;
87 }
88
89 /* Get a socketpair we'll use for stdin and stdout. */
90 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) < 0) {
91 perror("rcmdsh: socketpair");
92 return(-1);
93 }
94
95 cpid = fork();
96 if (cpid < 0) {
97 perror("rcmdsh: fork failed");
98 return(-1);
99 } else if (cpid == 0) {
100 /*
101 * Child. We use sp[1] to be stdin/stdout, and close sp[0].
102 */
103 (void) close(sp[0]);
104 if (dup2(sp[1], 0) < 0 || dup2(0, 1) < 0) {
105 perror("rcmdsh: dup2 failed");
106 _exit(255);
107 }
108 /* Fork again to lose parent. */
109 cpid = fork();
110 if (cpid < 0) {
111 perror("rcmdsh: fork to lose parent failed");
112 _exit(255);
113 }
114 if (cpid > 0)
115 _exit(0);
116
117 /* In grandchild here. Become local user for rshprog. */
118 if (setuid(pw->pw_uid)) {
119 (void) fprintf(stderr, "rcmdsh: setuid(%u): %s\n",
120 pw->pw_uid, strerror(errno));
121 _exit(255);
122 }
123
124 /*
125 * If remote host is "localhost" and local and remote user
126 * are the same, avoid running remote shell for efficiency.
127 */
128 if (!strcmp(*ahost, "localhost") && !strcmp(locuser, remuser)) {
129 char *argv[4];
130 if (pw->pw_shell[0] == '\0')
131 rshprog = _PATH_BSHELL;
132 else
133 rshprog = pw->pw_shell;
134 p = strrchr(rshprog, '/');
135 argv[0] = p ? p + 1 : rshprog;
136 argv[1] = "-c";
137 argv[2] = (char *)cmd;
138 argv[3] = NULL;
139 execvp(rshprog, argv);
140 } else if ((p = strchr(rshprog, ' ')) == NULL) {
141 /* simple case */
142 char *argv[6];
143 p = strrchr(rshprog, '/');
144 argv[0] = p ? p + 1 : rshprog;
145 argv[1] = "-l";
146 argv[2] = (char *)remuser;
147 argv[3] = *ahost;
148 argv[4] = (char *)cmd;
149 argv[5] = NULL;
150 execvp(rshprog, argv);
151 } else {
152 /* must pull args out of rshprog and dyn alloc argv */
153 char **argv, **ap;
154 int n;
155 for (n = 7; (p = strchr(++p, ' ')) != NULL; n++)
156 continue;
157 rshprog = strdup(rshprog);
158 ap = argv = malloc(sizeof(char *) * n);
159 if (rshprog == NULL || argv == NULL) {
160 perror("rcmdsh");
161 _exit(255);
162 }
163 while ((p = strsep(&rshprog, " ")) != NULL) {
164 if (*p == '\0')
165 continue;
166 *ap++ = p;
167 }
168 if (ap != argv) /* all spaces?!? */
169 rshprog = argv[0];
170 if ((p = strrchr(argv[0], '/')) != NULL)
171 argv[0] = p + 1;
172 *ap++ = "-l";
173 *ap++ = (char *)remuser;
174 *ap++ = *ahost;
175 *ap++ = (char *)cmd;
176 *ap++ = NULL;
177 execvp(rshprog, argv);
178 }
179 (void) fprintf(stderr, "rcmdsh: execvp %s failed: %s\n",
180 rshprog, strerror(errno));
181 _exit(255);
182 } else {
183 /* Parent. close sp[1], return sp[0]. */
184 (void) close(sp[1]);
185 /* Reap child. */
186 (void) wait(NULL);
187 return(sp[0]);
188 }
189 /* NOTREACHED */
190}