rexecd.c revision 1.6.2.1 1 /* $NetBSD: rexecd.c,v 1.6.2.1 2000/10/10 21:48:10 he Exp $ */
2
3 /*
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. 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 the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
39 The Regents of the University of California. All rights reserved.\n");
40 #if 0
41 static char sccsid[] = "from: @(#)rexecd.c 8.1 (Berkeley) 6/4/93";
42 #else
43 __RCSID("$NetBSD: rexecd.c,v 1.6.2.1 2000/10/10 21:48:10 he Exp $");
44 #endif
45 #endif /* not lint */
46
47 #include <sys/param.h>
48 #include <sys/ioctl.h>
49 #include <sys/poll.h>
50 #include <sys/socket.h>
51 #include <sys/syslog.h>
52 #include <sys/time.h>
53
54 #include <netinet/in.h>
55
56 #include <err.h>
57 #include <errno.h>
58 #include <netdb.h>
59 #include <paths.h>
60 #include <pwd.h>
61 #include <signal.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66
67 void error __P((const char *, ...))
68 __attribute__((__format__(__printf__, 1, 2)));
69 int main __P((int, char **));
70 void doit __P((int, struct sockaddr_in *));
71 void getstr __P((char *, int, char *));
72
73 char username[32 + 1] = "USER=";
74 char homedir[PATH_MAX + 1] = "HOME=";
75 char shell[PATH_MAX + 1] = "SHELL=";
76 char path[sizeof(_PATH_DEFPATH) + sizeof("PATH=")] = "PATH=";
77 char *envinit[] = { homedir, shell, path, username, 0 };
78 char **environ;
79 int log;
80 struct sockaddr_in asin = { AF_INET };
81
82 /*
83 * remote execute server:
84 * username\0
85 * password\0
86 * command\0
87 * data
88 */
89 int
90 main(argc, argv)
91 int argc;
92 char **argv;
93 {
94 struct sockaddr_in from;
95 int fromlen, ch;
96
97 while ((ch = getopt(argc, argv, "l")) != -1)
98 switch (ch) {
99 case 'l':
100 log = 1;
101 openlog("rexecd", LOG_PID, LOG_DAEMON);
102 break;
103 default:
104 exit(1);
105 }
106
107 fromlen = sizeof (from);
108 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0)
109 err(1, "getpeername");
110
111 doit(0, &from);
112 exit(0);
113 }
114
115 void
116 doit(f, fromp)
117 int f;
118 struct sockaddr_in *fromp;
119 {
120 struct pollfd fds[2];
121 char cmdbuf[NCARGS+1], *namep;
122 const char *cp;
123 char user[16], pass[16];
124 char buf[BUFSIZ], sig;
125 struct passwd *pwd;
126 int s = -1; /* XXX gcc */
127 int pv[2], pid, cc;
128 int one = 1;
129 in_port_t port;
130
131 (void)signal(SIGINT, SIG_DFL);
132 (void)signal(SIGQUIT, SIG_DFL);
133 (void)signal(SIGTERM, SIG_DFL);
134 dup2(f, 0);
135 dup2(f, 1);
136 dup2(f, 2);
137 (void)alarm(60);
138 port = 0;
139 for (;;) {
140 char c;
141 if (read(f, &c, 1) != 1) {
142 if (log)
143 syslog(LOG_ERR,
144 "initial read failed");
145 exit(1);
146 }
147 if (c == 0)
148 break;
149 port = port * 10 + c - '0';
150 }
151 (void)alarm(0);
152 if (port != 0) {
153 s = socket(AF_INET, SOCK_STREAM, 0);
154 if (s < 0) {
155 if (log)
156 syslog(LOG_ERR, "socket: %m");
157 exit(1);
158 }
159 if (bind(s, (struct sockaddr *)&asin, sizeof (asin)) < 0) {
160 if (log)
161 syslog(LOG_ERR, "bind: %m");
162 exit(1);
163 }
164 (void)alarm(60);
165 fromp->sin_port = htons(port);
166 if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) {
167 if (log)
168 syslog(LOG_ERR, "connect: %m");
169 exit(1);
170 }
171 (void)alarm(0);
172 }
173 getstr(user, sizeof(user), "username");
174 getstr(pass, sizeof(pass), "password");
175 getstr(cmdbuf, sizeof(cmdbuf), "command");
176 setpwent();
177 pwd = getpwnam(user);
178 if (pwd == NULL) {
179 error("Login incorrect.\n");
180 if (log)
181 syslog(LOG_ERR, "no such user %s", user);
182 exit(1);
183 }
184 endpwent();
185 if (*pwd->pw_passwd != '\0') {
186 namep = crypt(pass, pwd->pw_passwd);
187 if (strcmp(namep, pwd->pw_passwd)) {
188 error("Password incorrect.\n"); /* XXX: wrong! */
189 if (log)
190 syslog(LOG_ERR, "incorrect password for %s",
191 user);
192 exit(1);
193 }
194 } else
195 (void)crypt("dummy password", "PA"); /* must always crypt */
196 if (chdir(pwd->pw_dir) < 0) {
197 error("No remote directory.\n");
198 if (log)
199 syslog(LOG_ERR, "%s does not exist for %s", pwd->pw_dir,
200 user);
201 exit(1);
202 }
203 (void)write(2, "\0", 1);
204 if (port) {
205 if (pipe(pv) < 0 || (pid = fork()) == -1) {
206 error("Try again.\n");
207 if (log)
208 syslog(LOG_ERR,"pipe or fork failed for %s: %m",
209 user);
210 exit(1);
211 }
212 if (pid) {
213 (void)close(0);
214 (void)close(1);
215 (void)close(2);
216 (void)close(f);
217 (void)close(pv[1]);
218 fds[0].fd = s;
219 fds[1].fd = pv[0];
220 fds[0].events = fds[1].events = POLLIN;
221 if (ioctl(pv[1], FIONBIO, (char *)&one) < 0)
222 _exit(-1);
223 /* should set s nbio! */
224 do {
225 if (poll(fds, 2, 0) < 0) {
226 close(s);
227 close(pv[0]);
228 _exit(-1);
229 }
230 if (fds[0].revents & POLLIN) {
231 if (read(s, &sig, 1) <= 0)
232 fds[0].events = 0;
233 else
234 killpg(pid, sig);
235 }
236 if (fds[1].revents & POLLIN) {
237 cc = read(pv[0], buf, sizeof (buf));
238 if (cc <= 0) {
239 shutdown(s, 1+1);
240 fds[1].events = 0;
241 } else
242 (void)write(s, buf, cc);
243 }
244 } while ((fds[0].events | fds[1].events) & POLLIN);
245 _exit(0);
246 }
247 (void)setpgrp(0, getpid());
248 (void)close(s);
249 (void)close(pv[0]);
250 if (dup2(pv[1], 2) < 0) {
251 error("Try again.\n");
252 if (log)
253 syslog(LOG_ERR, "dup2 failed for %s", user);
254 exit(1);
255 }
256 }
257 if (*pwd->pw_shell == '\0')
258 pwd->pw_shell = _PATH_BSHELL;
259 if (f > 2)
260 (void)close(f);
261 if (setlogin(pwd->pw_name) < 0 ||
262 initgroups(pwd->pw_name, pwd->pw_gid) < 0 ||
263 setgid((gid_t)pwd->pw_gid) < 0 ||
264 setuid((uid_t)pwd->pw_uid) < 0) {
265 error("Try again.\n");
266 if (log)
267 syslog(LOG_ERR, "could not set permissions for %s: %m",
268 user);
269 exit(1);
270 }
271 (void)strcat(path, _PATH_DEFPATH);
272 environ = envinit;
273 strncat(homedir, pwd->pw_dir, sizeof(homedir) - 6);
274 strncat(shell, pwd->pw_shell, sizeof(shell) - 7);
275 strncat(username, pwd->pw_name, sizeof(username) - 6);
276 cp = strrchr(pwd->pw_shell, '/');
277 if (cp)
278 cp++;
279 else
280 cp = pwd->pw_shell;
281 if (log)
282 syslog(LOG_INFO, "running command for %s: %s", user, cmdbuf);
283 execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
284 perror(pwd->pw_shell);
285 if (log)
286 syslog(LOG_ERR, "execl failed for %s: %m", user);
287 exit(1);
288 }
289
290 #ifdef __STDC__
291 #include <stdarg.h>
292 #else
293 #include <varargs.h>
294 #endif
295
296 void
297 #ifdef __STDC__
298 error(const char *fmt, ...)
299 #else
300 error(fmt, va_alist)
301 char *fmt;
302 va_dcl
303 #endif
304 {
305 char buf[BUFSIZ];
306 va_list ap;
307
308 #ifdef __STDC__
309 va_start(ap, fmt);
310 #else
311 va_start(ap);
312 #endif
313
314 buf[0] = 1;
315 (void)vsnprintf(buf+1, sizeof(buf) - 1, fmt, ap);
316 (void)write(2, buf, strlen(buf));
317 }
318
319 void
320 getstr(buf, cnt, err)
321 char *buf;
322 int cnt;
323 char *err;
324 {
325 char c;
326
327 do {
328 if (read(0, &c, 1) != 1)
329 exit(1);
330 *buf++ = c;
331 if (--cnt == 0) {
332 error("%s too long\n", err);
333 exit(1);
334 }
335 } while (c != 0);
336 }
337