install with -s
[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
8c5eec2f
DF
14static char sccsid[] = "@(#)rshd.c 5.1 (Berkeley) %G%";
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>
ce4fd43b 27#include <sys/wait.h>
e7d6d17a
SL
28
29#include <netinet/in.h>
30
31#include <stdio.h>
1d68cba5
BJ
32#include <errno.h>
33#include <pwd.h>
1d68cba5 34#include <signal.h>
3f5b52bc 35#include <netdb.h>
3f99c0f7 36#include <syslog.h>
1d68cba5
BJ
37
38int errno;
3f99c0f7 39char *index(), *rindex();
1d68cba5
BJ
40/* VARARGS 1 */
41int error();
bb933cc2 42
1d68cba5
BJ
43main(argc, argv)
44 int argc;
45 char **argv;
46{
bcb894cb
SL
47 struct linger linger;
48 int on = 1, fromlen;
1d68cba5 49 struct sockaddr_in from;
3f5b52bc 50
bb933cc2
MK
51 fromlen = sizeof (from);
52 if (getpeername(0, &from, &fromlen) < 0) {
53 fprintf(stderr, "%s: ", argv[0]);
54 perror("getpeername");
55 _exit(1);
3f5b52bc 56 }
bcb894cb 57 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
3f99c0f7
RC
58 openlog(argv[0], LOG_PID, 0);
59 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
e7d6d17a 60 }
bcb894cb
SL
61 linger.l_onoff = 1;
62 linger.l_linger = 60; /* XXX */
bb933cc2 63 if (setsockopt(0, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger)) < 0) {
3f99c0f7
RC
64 openlog(argv[0], LOG_PID, 0);
65 syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
1d68cba5 66 }
bb933cc2 67 doit(dup(0), &from);
a8e3386b
SL
68}
69
1d68cba5
BJ
70char username[20] = "USER=";
71char homedir[64] = "HOME=";
72char shell[64] = "SHELL=";
73char *envinit[] =
74 {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0};
75char **environ;
76
77doit(f, fromp)
78 int f;
79 struct sockaddr_in *fromp;
80{
81 char cmdbuf[NCARGS+1], *cp;
82 char locuser[16], remuser[16];
83 struct passwd *pwd;
d173f55d 84 int s, backoff;
3f5b52bc 85 struct hostent *hp;
1d68cba5
BJ
86 short port;
87 int pv[2], pid, ready, readfrom, cc;
88 char buf[BUFSIZ], sig;
89 int one = 1;
90
91 (void) signal(SIGINT, SIG_DFL);
92 (void) signal(SIGQUIT, SIG_DFL);
93 (void) signal(SIGTERM, SIG_DFL);
27890867 94#ifdef DEBUG
1d68cba5
BJ
95 { int t = open("/dev/tty", 2);
96 if (t >= 0) {
97 ioctl(t, TIOCNOTTY, (char *)0);
98 (void) close(t);
99 }
100 }
101#endif
1d68cba5 102 fromp->sin_port = ntohs((u_short)fromp->sin_port);
1d68cba5 103 if (fromp->sin_family != AF_INET ||
d173f55d 104 fromp->sin_port >= IPPORT_RESERVED) {
3f99c0f7
RC
105 openlog("rshd", LOG_PID, 0);
106 syslog(LOG_ERR, "malformed from address\n");
1d68cba5 107 exit(1);
d173f55d 108 }
1d68cba5
BJ
109 (void) alarm(60);
110 port = 0;
111 for (;;) {
112 char c;
d173f55d 113 if (read(f, &c, 1) != 1) {
3f99c0f7
RC
114 openlog("rshd", LOG_PID, 0);
115 syslog(LOG_ERR, "read: %m");
fadc6b8f 116 shutdown(f, 1+1);
1d68cba5 117 exit(1);
d173f55d 118 }
1d68cba5
BJ
119 if (c == 0)
120 break;
121 port = port * 10 + c - '0';
122 }
123 (void) alarm(0);
124 if (port != 0) {
d173f55d 125 int lport = IPPORT_RESERVED - 1, retryshift;
3b0e7dec 126 s = rresvport(&lport);
d173f55d 127 if (s < 0) {
3f99c0f7
RC
128 openlog("rshd", LOG_PID, 0);
129 syslog(LOG_ERR, "can't get stderr port: %m");
d173f55d
SL
130 exit(1);
131 }
132 if (port >= IPPORT_RESERVED) {
3f99c0f7
RC
133 openlog("rshd", LOG_PID, 0);
134 syslog(LOG_ERR, "2nd port not reserved\n");
1d68cba5 135 exit(1);
d173f55d 136 }
e23c0837 137 fromp->sin_port = htons((u_short)port);
27890867 138 if (connect(s, fromp, sizeof (*fromp), 0) < 0) {
3f99c0f7
RC
139 openlog("rshd", LOG_PID, 0);
140 syslog(LOG_ERR, "connect: %m");
1d68cba5 141 exit(1);
d173f55d 142 }
1d68cba5 143 }
d173f55d
SL
144 dup2(f, 0);
145 dup2(f, 1);
146 dup2(f, 2);
3f5b52bc
SL
147 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
148 fromp->sin_family);
149 if (hp == 0) {
1d68cba5
BJ
150 error("Host name for your address unknown\n");
151 exit(1);
152 }
153 getstr(remuser, sizeof(remuser), "remuser");
154 getstr(locuser, sizeof(locuser), "locuser");
155 getstr(cmdbuf, sizeof(cmdbuf), "command");
156 setpwent();
157 pwd = getpwnam(locuser);
158 if (pwd == NULL) {
159 error("Login incorrect.\n");
160 exit(1);
161 }
162 endpwent();
163 if (chdir(pwd->pw_dir) < 0) {
bb933cc2
MK
164 chdir("/");
165#ifdef notdef
1d68cba5
BJ
166 error("No remote directory.\n");
167 exit(1);
bb933cc2 168#endif
1d68cba5 169 }
fadc6b8f 170 if (ruserok(hp->h_name, pwd->pw_uid == 0, remuser, locuser) < 0) {
1d68cba5
BJ
171 error("Permission denied.\n");
172 exit(1);
173 }
174 (void) write(2, "\0", 1);
175 if (port) {
176 if (pipe(pv) < 0) {
177 error("Can't make pipe.\n");
178 exit(1);
179 }
180 pid = fork();
181 if (pid == -1) {
182 error("Try again.\n");
183 exit(1);
184 }
185 if (pid) {
186 (void) close(0); (void) close(1); (void) close(2);
187 (void) close(f); (void) close(pv[1]);
188 readfrom = (1<<s) | (1<<pv[0]);
189 ioctl(pv[1], FIONBIO, (char *)&one);
190 /* should set s nbio! */
191 do {
192 ready = readfrom;
e7d6d17a
SL
193 if (select(16, &ready, 0, 0, 0) < 0)
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);
1d68cba5 220 (void) setgid(pwd->pw_gid);
80aca4ff 221 initgroups(pwd->pw_name, pwd->pw_gid);
fadc6b8f 222 (void) setuid(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);
235protofail:
236 error("rsh: protocol failure detected by remote\n");
237 exit(1);
238}
239
240/* VARARGS 1 */
241error(fmt)
242 char *fmt;
243{
244 char buf[BUFSIZ];
245
246 buf[0] = 1;
247 (void) sprintf(buf+1, fmt);
248 (void) write(2, buf, strlen(buf));
249}
250
251getstr(buf, cnt, err)
252 char *buf;
253 int cnt;
254 char *err;
255{
256 char c;
257
258 do {
259 if (read(0, &c, 1) != 1)
260 exit(1);
261 *buf++ = c;
262 if (--cnt == 0) {
263 error("%s too long\n", err);
264 exit(1);
265 }
266 } while (c != 0);
267}