make it more robust
[unix-history] / usr / src / libexec / rshd / rshd.c
CommitLineData
8c5eec2f
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1983 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
1d68cba5 13#ifndef lint
71419d2d 14static char sccsid[] = "@(#)rshd.c 5.8 (Berkeley) %G%";
8c5eec2f 15#endif not lint
1d68cba5 16
bb933cc2
MK
17/*
18 * remote shell server:
19 * remuser\0
20 * locuser\0
21 * command\0
22 * data
23 */
1d68cba5
BJ
24#include <sys/ioctl.h>
25#include <sys/param.h>
26#include <sys/socket.h>
d4413a13 27#include <sys/time.h>
e7d6d17a
SL
28
29#include <netinet/in.h>
30
4c99408e
JB
31#include <arpa/inet.h>
32
e7d6d17a 33#include <stdio.h>
1d68cba5
BJ
34#include <errno.h>
35#include <pwd.h>
1d68cba5 36#include <signal.h>
3f5b52bc 37#include <netdb.h>
3f99c0f7 38#include <syslog.h>
1d68cba5
BJ
39
40int errno;
d4413a13
JL
41char *index(), *rindex(), *strncat();
42/*VARARGS1*/
1d68cba5 43int error();
bb933cc2 44
d4413a13 45/*ARGSUSED*/
1d68cba5
BJ
46main(argc, argv)
47 int argc;
48 char **argv;
49{
bcb894cb
SL
50 struct linger linger;
51 int on = 1, fromlen;
1d68cba5 52 struct sockaddr_in from;
3f5b52bc 53
076ae92c 54 openlog("rsh", LOG_PID | LOG_ODELAY, LOG_DAEMON);
bb933cc2
MK
55 fromlen = sizeof (from);
56 if (getpeername(0, &from, &fromlen) < 0) {
57 fprintf(stderr, "%s: ", argv[0]);
58 perror("getpeername");
59 _exit(1);
3f5b52bc 60 }
d4413a13
JL
61 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
62 sizeof (on)) < 0)
3f99c0f7 63 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
bcb894cb
SL
64 linger.l_onoff = 1;
65 linger.l_linger = 60; /* XXX */
d4413a13
JL
66 if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
67 sizeof (linger)) < 0)
3f99c0f7 68 syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
bb933cc2 69 doit(dup(0), &from);
a8e3386b
SL
70}
71
1d68cba5
BJ
72char username[20] = "USER=";
73char homedir[64] = "HOME=";
74char shell[64] = "SHELL=";
75char *envinit[] =
76 {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0};
77char **environ;
78
79doit(f, fromp)
80 int f;
81 struct sockaddr_in *fromp;
82{
83 char cmdbuf[NCARGS+1], *cp;
84 char locuser[16], remuser[16];
85 struct passwd *pwd;
d4413a13 86 int s;
3f5b52bc 87 struct hostent *hp;
7ad57ed0 88 char *hostname;
1d68cba5
BJ
89 short port;
90 int pv[2], pid, ready, readfrom, cc;
91 char buf[BUFSIZ], sig;
92 int one = 1;
93
94 (void) signal(SIGINT, SIG_DFL);
95 (void) signal(SIGQUIT, SIG_DFL);
96 (void) signal(SIGTERM, SIG_DFL);
27890867 97#ifdef DEBUG
1d68cba5
BJ
98 { int t = open("/dev/tty", 2);
99 if (t >= 0) {
100 ioctl(t, TIOCNOTTY, (char *)0);
101 (void) close(t);
102 }
103 }
104#endif
1d68cba5 105 fromp->sin_port = ntohs((u_short)fromp->sin_port);
1d68cba5 106 if (fromp->sin_family != AF_INET ||
d173f55d 107 fromp->sin_port >= IPPORT_RESERVED) {
3f99c0f7 108 syslog(LOG_ERR, "malformed from address\n");
1d68cba5 109 exit(1);
d173f55d 110 }
1d68cba5
BJ
111 (void) alarm(60);
112 port = 0;
113 for (;;) {
114 char c;
d173f55d 115 if (read(f, &c, 1) != 1) {
3f99c0f7 116 syslog(LOG_ERR, "read: %m");
fadc6b8f 117 shutdown(f, 1+1);
1d68cba5 118 exit(1);
d173f55d 119 }
1d68cba5
BJ
120 if (c == 0)
121 break;
122 port = port * 10 + c - '0';
123 }
124 (void) alarm(0);
125 if (port != 0) {
d4413a13 126 int lport = IPPORT_RESERVED - 1;
3b0e7dec 127 s = rresvport(&lport);
d173f55d 128 if (s < 0) {
3f99c0f7 129 syslog(LOG_ERR, "can't get stderr port: %m");
d173f55d
SL
130 exit(1);
131 }
132 if (port >= IPPORT_RESERVED) {
3f99c0f7 133 syslog(LOG_ERR, "2nd port not reserved\n");
1d68cba5 134 exit(1);
d173f55d 135 }
e23c0837 136 fromp->sin_port = htons((u_short)port);
d4413a13 137 if (connect(s, fromp, sizeof (*fromp)) < 0) {
7ad57ed0 138 syslog(LOG_INFO, "connect second port: %m");
1d68cba5 139 exit(1);
d173f55d 140 }
1d68cba5 141 }
d173f55d
SL
142 dup2(f, 0);
143 dup2(f, 1);
144 dup2(f, 2);
d4413a13 145 hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
3f5b52bc 146 fromp->sin_family);
7ad57ed0
MK
147 if (hp)
148 hostname = hp->h_name;
149 else
150 hostname = inet_ntoa(fromp->sin_addr);
1d68cba5
BJ
151 getstr(remuser, sizeof(remuser), "remuser");
152 getstr(locuser, sizeof(locuser), "locuser");
153 getstr(cmdbuf, sizeof(cmdbuf), "command");
154 setpwent();
155 pwd = getpwnam(locuser);
156 if (pwd == NULL) {
157 error("Login incorrect.\n");
158 exit(1);
159 }
160 endpwent();
161 if (chdir(pwd->pw_dir) < 0) {
d4413a13 162 (void) chdir("/");
bb933cc2 163#ifdef notdef
1d68cba5
BJ
164 error("No remote directory.\n");
165 exit(1);
bb933cc2 166#endif
1d68cba5 167 }
792e68a4 168 if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
7ad57ed0 169 ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) {
1d68cba5
BJ
170 error("Permission denied.\n");
171 exit(1);
172 }
173 (void) write(2, "\0", 1);
174 if (port) {
175 if (pipe(pv) < 0) {
176 error("Can't make pipe.\n");
177 exit(1);
178 }
179 pid = fork();
180 if (pid == -1) {
181 error("Try again.\n");
182 exit(1);
183 }
184 if (pid) {
185 (void) close(0); (void) close(1); (void) close(2);
186 (void) close(f); (void) close(pv[1]);
187 readfrom = (1<<s) | (1<<pv[0]);
71419d2d 188 ioctl(pv[0], FIONBIO, (char *)&one);
1d68cba5
BJ
189 /* should set s nbio! */
190 do {
191 ready = readfrom;
d4413a13
JL
192 if (select(16, &ready, (fd_set *)0,
193 (fd_set *)0, (struct timeval *)0) < 0)
e7d6d17a 194 break;
1d68cba5
BJ
195 if (ready & (1<<s)) {
196 if (read(s, &sig, 1) <= 0)
197 readfrom &= ~(1<<s);
198 else
199 killpg(pid, sig);
200 }
201 if (ready & (1<<pv[0])) {
fadc6b8f 202 errno = 0;
1d68cba5
BJ
203 cc = read(pv[0], buf, sizeof (buf));
204 if (cc <= 0) {
ff24c640 205 shutdown(s, 1+1);
1d68cba5
BJ
206 readfrom &= ~(1<<pv[0]);
207 } else
208 (void) write(s, buf, cc);
209 }
210 } while (readfrom);
211 exit(0);
212 }
213 setpgrp(0, getpid());
214 (void) close(s); (void) close(pv[0]);
215 dup2(pv[1], 2);
216 }
217 if (*pwd->pw_shell == '\0')
218 pwd->pw_shell = "/bin/sh";
219 (void) close(f);
d4413a13 220 (void) setgid((gid_t)pwd->pw_gid);
80aca4ff 221 initgroups(pwd->pw_name, pwd->pw_gid);
d4413a13 222 (void) setuid((uid_t)pwd->pw_uid);
1d68cba5
BJ
223 environ = envinit;
224 strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
225 strncat(shell, pwd->pw_shell, sizeof(shell)-7);
226 strncat(username, pwd->pw_name, sizeof(username)-6);
227 cp = rindex(pwd->pw_shell, '/');
228 if (cp)
229 cp++;
230 else
231 cp = pwd->pw_shell;
232 execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
233 perror(pwd->pw_shell);
234 exit(1);
1d68cba5
BJ
235}
236
d4413a13 237/*VARARGS1*/
35db6ea0 238error(fmt, a1, a2, a3)
1d68cba5 239 char *fmt;
35db6ea0 240 int a1, a2, a3;
1d68cba5
BJ
241{
242 char buf[BUFSIZ];
243
244 buf[0] = 1;
35db6ea0 245 (void) sprintf(buf+1, fmt, a1, a2, a3);
1d68cba5
BJ
246 (void) write(2, buf, strlen(buf));
247}
248
249getstr(buf, cnt, err)
250 char *buf;
251 int cnt;
252 char *err;
253{
254 char c;
255
256 do {
257 if (read(0, &c, 1) != 1)
258 exit(1);
259 *buf++ = c;
260 if (--cnt == 0) {
261 error("%s too long\n", err);
262 exit(1);
263 }
264 } while (c != 0);
265}