rexecd.c revision 1.11 1 /* $NetBSD: rexecd.c,v 1.11 2002/06/05 23:05:34 itojun 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.11 2002/06/05 23:05:34 itojun 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 <stdarg.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <unistd.h>
67
68 void error __P((const char *, ...))
69 __attribute__((__format__(__printf__, 1, 2)));
70 int main __P((int, char **));
71 void doit __P((int, struct sockaddr *));
72 void getstr __P((char *, int, char *));
73
74 char username[32 + 1] = "USER=";
75 char homedir[PATH_MAX + 1] = "HOME=";
76 char shell[PATH_MAX + 1] = "SHELL=";
77 char path[sizeof(_PATH_DEFPATH) + sizeof("PATH=")] = "PATH=";
78 char *envinit[] = { homedir, shell, path, username, 0 };
79 char **environ;
80 int log;
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_storage 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, (struct sockaddr *)&from);
112 exit(0);
113 }
114
115 void
116 doit(f, fromp)
117 int f;
118 struct sockaddr *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(fromp->sa_family, SOCK_STREAM, 0);
154 if (s < 0) {
155 if (log)
156 syslog(LOG_ERR, "socket: %m");
157 exit(1);
158 }
159 (void)alarm(60);
160 switch (fromp->sa_family) {
161 case AF_INET:
162 ((struct sockaddr_in *)fromp)->sin_port = htons(port);
163 break;
164 case AF_INET6:
165 ((struct sockaddr_in6 *)fromp)->sin6_port = htons(port);
166 break;
167 default:
168 syslog(LOG_ERR, "unsupported address family");
169 exit(1);
170 }
171 if (connect(s, (struct sockaddr *)fromp, fromp->sa_len) < 0) {
172 if (log)
173 syslog(LOG_ERR, "connect: %m");
174 exit(1);
175 }
176 (void)alarm(0);
177 }
178 getstr(user, sizeof(user), "username");
179 getstr(pass, sizeof(pass), "password");
180 getstr(cmdbuf, sizeof(cmdbuf), "command");
181 setpwent();
182 pwd = getpwnam(user);
183 if (pwd == NULL) {
184 error("Login incorrect.\n");
185 if (log)
186 syslog(LOG_ERR, "no such user %s", user);
187 exit(1);
188 }
189 endpwent();
190 if (*pwd->pw_passwd != '\0') {
191 namep = crypt(pass, pwd->pw_passwd);
192 if (strcmp(namep, pwd->pw_passwd)) {
193 error("Password incorrect.\n"); /* XXX: wrong! */
194 if (log)
195 syslog(LOG_ERR, "incorrect password for %s",
196 user);
197 exit(1);
198 }
199 } else
200 (void)crypt("dummy password", "PA"); /* must always crypt */
201 if (chdir(pwd->pw_dir) < 0) {
202 error("No remote directory.\n");
203 if (log)
204 syslog(LOG_ERR, "%s does not exist for %s", pwd->pw_dir,
205 user);
206 exit(1);
207 }
208 (void)write(2, "\0", 1);
209 if (port) {
210 if (pipe(pv) < 0 || (pid = fork()) == -1) {
211 error("Try again.\n");
212 if (log)
213 syslog(LOG_ERR,"pipe or fork failed for %s: %m",
214 user);
215 exit(1);
216 }
217 if (pid) {
218 (void)close(0);
219 (void)close(1);
220 (void)close(2);
221 (void)close(f);
222 (void)close(pv[1]);
223 fds[0].fd = s;
224 fds[1].fd = pv[0];
225 fds[0].events = fds[1].events = POLLIN;
226 if (ioctl(pv[1], FIONBIO, (char *)&one) < 0)
227 _exit(1);
228 /* should set s nbio! */
229 do {
230 if (poll(fds, 2, 0) < 0) {
231 close(s);
232 close(pv[0]);
233 _exit(1);
234 }
235 if (fds[0].revents & POLLIN) {
236 if (read(s, &sig, 1) <= 0)
237 fds[0].events = 0;
238 else
239 killpg(pid, sig);
240 }
241 if (fds[1].revents & POLLIN) {
242 cc = read(pv[0], buf, sizeof (buf));
243 if (cc <= 0) {
244 shutdown(s, 1+1);
245 fds[1].events = 0;
246 } else
247 (void)write(s, buf, cc);
248 }
249 } while ((fds[0].events | fds[1].events) & POLLIN);
250 _exit(0);
251 }
252 (void)setpgrp(0, getpid());
253 (void)close(s);
254 (void)close(pv[0]);
255 if (dup2(pv[1], 2) < 0) {
256 error("Try again.\n");
257 if (log)
258 syslog(LOG_ERR, "dup2 failed for %s", user);
259 exit(1);
260 }
261 }
262 if (*pwd->pw_shell == '\0')
263 pwd->pw_shell = _PATH_BSHELL;
264 if (f > 2)
265 (void)close(f);
266 if (setlogin(pwd->pw_name) < 0 ||
267 initgroups(pwd->pw_name, pwd->pw_gid) < 0 ||
268 setgid((gid_t)pwd->pw_gid) < 0 ||
269 setuid((uid_t)pwd->pw_uid) < 0) {
270 error("Try again.\n");
271 if (log)
272 syslog(LOG_ERR, "could not set permissions for %s: %m",
273 user);
274 exit(1);
275 }
276 (void)strcat(path, _PATH_DEFPATH);
277 environ = envinit;
278 strncat(homedir, pwd->pw_dir, sizeof(homedir) - 6);
279 strncat(shell, pwd->pw_shell, sizeof(shell) - 7);
280 strncat(username, pwd->pw_name, sizeof(username) - 6);
281 cp = strrchr(pwd->pw_shell, '/');
282 if (cp)
283 cp++;
284 else
285 cp = pwd->pw_shell;
286 if (log)
287 syslog(LOG_INFO, "running command for %s: %s", user, cmdbuf);
288 execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
289 perror(pwd->pw_shell);
290 if (log)
291 syslog(LOG_ERR, "execl failed for %s: %m", user);
292 exit(1);
293 }
294
295 void
296 error(const char *fmt, ...)
297 {
298 char buf[BUFSIZ];
299 va_list ap;
300
301 va_start(ap, fmt);
302 buf[0] = 1;
303 (void)vsnprintf(buf+1, sizeof(buf) - 1, fmt, ap);
304 (void)write(2, buf, strlen(buf));
305 va_end(ap);
306 }
307
308 void
309 getstr(buf, cnt, err)
310 char *buf;
311 int cnt;
312 char *err;
313 {
314 char c;
315
316 do {
317 if (read(0, &c, 1) != 1)
318 exit(1);
319 *buf++ = c;
320 if (--cnt == 0) {
321 error("%s too long\n", err);
322 exit(1);
323 }
324 } while (c != 0);
325 }
326