1 /* $NetBSD: rexecd.c,v 1.6 1998/07/26 19:49:03 mycroft 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 1998/07/26 19:49:03 mycroft 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 int main __P((int, char **)); 69 void doit __P((int, struct sockaddr_in *)); 70 void getstr __P((char *, int, char *)); 71 72 char username[32 + 1] = "USER="; 73 char homedir[PATH_MAX + 1] = "HOME="; 74 char shell[PATH_MAX + 1] = "SHELL="; 75 char path[sizeof(_PATH_DEFPATH) + sizeof("PATH=")] = "PATH="; 76 char *envinit[] = { homedir, shell, path, username, 0 }; 77 char **environ; 78 int log; 79 struct sockaddr_in asin = { AF_INET }; 80 81 /* 82 * remote execute server: 83 * username\0 84 * password\0 85 * command\0 86 * data 87 */ 88 int 89 main(argc, argv) 90 int argc; 91 char **argv; 92 { 93 struct sockaddr_in from; 94 int fromlen, ch; 95 96 while ((ch = getopt(argc, argv, "l")) != -1) 97 switch (ch) { 98 case 'l': 99 log = 1; 100 openlog("rexecd", LOG_PID, LOG_DAEMON); 101 break; 102 default: 103 exit(1); 104 } 105 106 fromlen = sizeof (from); 107 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) 108 err(1, "getpeername"); 109 110 doit(0, &from); 111 exit(0); 112 } 113 114 void 115 doit(f, fromp) 116 int f; 117 struct sockaddr_in *fromp; 118 { 119 struct pollfd fds[2]; 120 char cmdbuf[NCARGS+1], *namep; 121 const char *cp; 122 char user[16], pass[16]; 123 char buf[BUFSIZ], sig; 124 struct passwd *pwd; 125 int s = -1; /* XXX gcc */ 126 int pv[2], pid, cc; 127 int one = 1; 128 in_port_t port; 129 130 (void)signal(SIGINT, SIG_DFL); 131 (void)signal(SIGQUIT, SIG_DFL); 132 (void)signal(SIGTERM, SIG_DFL); 133 dup2(f, 0); 134 dup2(f, 1); 135 dup2(f, 2); 136 (void)alarm(60); 137 port = 0; 138 for (;;) { 139 char c; 140 if (read(f, &c, 1) != 1) { 141 if (log) 142 syslog(LOG_ERR, 143 "initial read failed"); 144 exit(1); 145 } 146 if (c == 0) 147 break; 148 port = port * 10 + c - '0'; 149 } 150 (void)alarm(0); 151 if (port != 0) { 152 s = socket(AF_INET, SOCK_STREAM, 0); 153 if (s < 0) { 154 if (log) 155 syslog(LOG_ERR, "socket: %m"); 156 exit(1); 157 } 158 if (bind(s, (struct sockaddr *)&asin, sizeof (asin)) < 0) { 159 if (log) 160 syslog(LOG_ERR, "bind: %m"); 161 exit(1); 162 } 163 (void)alarm(60); 164 fromp->sin_port = htons(port); 165 if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) { 166 if (log) 167 syslog(LOG_ERR, "connect: %m"); 168 exit(1); 169 } 170 (void)alarm(0); 171 } 172 getstr(user, sizeof(user), "username"); 173 getstr(pass, sizeof(pass), "password"); 174 getstr(cmdbuf, sizeof(cmdbuf), "command"); 175 setpwent(); 176 pwd = getpwnam(user); 177 if (pwd == NULL) { 178 error("Login incorrect.\n"); 179 if (log) 180 syslog(LOG_ERR, "no such user %s", user); 181 exit(1); 182 } 183 endpwent(); 184 if (*pwd->pw_passwd != '\0') { 185 namep = crypt(pass, pwd->pw_passwd); 186 if (strcmp(namep, pwd->pw_passwd)) { 187 error("Password incorrect.\n"); /* XXX: wrong! */ 188 if (log) 189 syslog(LOG_ERR, "incorrect password for %s", 190 user); 191 exit(1); 192 } 193 } else 194 (void)crypt("dummy password", "PA"); /* must always crypt */ 195 if (chdir(pwd->pw_dir) < 0) { 196 error("No remote directory.\n"); 197 if (log) 198 syslog(LOG_ERR, "%s does not exist for %s", pwd->pw_dir, 199 user); 200 exit(1); 201 } 202 (void)write(2, "\0", 1); 203 if (port) { 204 if (pipe(pv) < 0 || (pid = fork()) == -1) { 205 error("Try again.\n"); 206 if (log) 207 syslog(LOG_ERR,"pipe or fork failed for %s: %m", 208 user); 209 exit(1); 210 } 211 if (pid) { 212 (void)close(0); 213 (void)close(1); 214 (void)close(2); 215 (void)close(f); 216 (void)close(pv[1]); 217 fds[0].fd = s; 218 fds[1].fd = pv[0]; 219 fds[0].events = fds[1].events = POLLIN; 220 if (ioctl(pv[1], FIONBIO, (char *)&one) < 0) 221 _exit(-1); 222 /* should set s nbio! */ 223 do { 224 if (poll(fds, 2, 0) < 0) { 225 close(s); 226 close(pv[0]); 227 _exit(-1); 228 } 229 if (fds[0].revents & POLLIN) { 230 if (read(s, &sig, 1) <= 0) 231 fds[0].events = 0; 232 else 233 killpg(pid, sig); 234 } 235 if (fds[1].revents & POLLIN) { 236 cc = read(pv[0], buf, sizeof (buf)); 237 if (cc <= 0) { 238 shutdown(s, 1+1); 239 fds[1].events = 0; 240 } else 241 (void)write(s, buf, cc); 242 } 243 } while ((fds[0].events | fds[1].events) & POLLIN); 244 _exit(0); 245 } 246 (void)setpgrp(0, getpid()); 247 (void)close(s); 248 (void)close(pv[0]); 249 if (dup2(pv[1], 2) < 0) { 250 error("Try again.\n"); 251 if (log) 252 syslog(LOG_ERR, "dup2 failed for %s", user); 253 exit(1); 254 } 255 } 256 if (*pwd->pw_shell == '\0') 257 pwd->pw_shell = _PATH_BSHELL; 258 if (f > 2) 259 (void)close(f); 260 if (setlogin(pwd->pw_name) < 0 || 261 initgroups(pwd->pw_name, pwd->pw_gid) < 0 || 262 setgid((gid_t)pwd->pw_gid) < 0 || 263 setuid((uid_t)pwd->pw_uid) < 0) { 264 error("Try again.\n"); 265 if (log) 266 syslog(LOG_ERR, "could not set permissions for %s: %m", 267 user); 268 exit(1); 269 } 270 (void)strcat(path, _PATH_DEFPATH); 271 environ = envinit; 272 strncat(homedir, pwd->pw_dir, sizeof(homedir) - 6); 273 strncat(shell, pwd->pw_shell, sizeof(shell) - 7); 274 strncat(username, pwd->pw_name, sizeof(username) - 6); 275 cp = strrchr(pwd->pw_shell, '/'); 276 if (cp) 277 cp++; 278 else 279 cp = pwd->pw_shell; 280 if (log) 281 syslog(LOG_INFO, "running command for %s: %s", user, cmdbuf); 282 execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); 283 perror(pwd->pw_shell); 284 if (log) 285 syslog(LOG_ERR, "execl failed for %s: %m", user); 286 exit(1); 287 } 288 289 #ifdef __STDC__ 290 #include <stdarg.h> 291 #else 292 #include <varargs.h> 293 #endif 294 295 void 296 #ifdef __STDC__ 297 error(const char *fmt, ...) 298 #else 299 error(fmt, va_alist) 300 char *fmt; 301 va_dcl 302 #endif 303 { 304 char buf[BUFSIZ]; 305 va_list ap; 306 307 #ifdef __STDC__ 308 va_start(ap, fmt); 309 #else 310 va_start(ap); 311 #endif 312 313 buf[0] = 1; 314 (void)vsnprintf(buf+1, sizeof(buf) - 1, fmt, ap); 315 (void)write(2, buf, strlen(buf)); 316 } 317 318 void 319 getstr(buf, cnt, err) 320 char *buf; 321 int cnt; 322 char *err; 323 { 324 char c; 325 326 do { 327 if (read(0, &c, 1) != 1) 328 exit(1); 329 *buf++ = c; 330 if (--cnt == 0) { 331 error("%s too long\n", err); 332 exit(1); 333 } 334 } while (c != 0); 335 } 336