error needs to take additional arguments (jason@opal)
[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
35db6ea0 14static char sccsid[] = "@(#)rshd.c 5.5 (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>
ce4fd43b 27#include <sys/wait.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;
3f99c0f7 41char *index(), *rindex();
1d68cba5
BJ
42/* VARARGS 1 */
43int error();
bb933cc2 44
1d68cba5
BJ
45main(argc, argv)
46 int argc;
47 char **argv;
48{
bcb894cb
SL
49 struct linger linger;
50 int on = 1, fromlen;
1d68cba5 51 struct sockaddr_in from;
3f5b52bc 52
076ae92c 53 openlog("rsh", LOG_PID | LOG_ODELAY, LOG_DAEMON);
bb933cc2
MK
54 fromlen = sizeof (from);
55 if (getpeername(0, &from, &fromlen) < 0) {
56 fprintf(stderr, "%s: ", argv[0]);
57 perror("getpeername");
58 _exit(1);
3f5b52bc 59 }
bcb894cb 60 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
3f99c0f7 61 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
e7d6d17a 62 }
bcb894cb
SL
63 linger.l_onoff = 1;
64 linger.l_linger = 60; /* XXX */
bb933cc2 65 if (setsockopt(0, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger)) < 0) {
3f99c0f7 66 syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
1d68cba5 67 }
bb933cc2 68 doit(dup(0), &from);
a8e3386b
SL
69}
70
1d68cba5
BJ
71char username[20] = "USER=";
72char homedir[64] = "HOME=";
73char shell[64] = "SHELL=";
74char *envinit[] =
75 {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0};
76char **environ;
77
78doit(f, fromp)
79 int f;
80 struct sockaddr_in *fromp;
81{
82 char cmdbuf[NCARGS+1], *cp;
83 char locuser[16], remuser[16];
84 struct passwd *pwd;
d173f55d 85 int s, backoff;
3f5b52bc 86 struct hostent *hp;
4c99408e 87 struct hostent hostent;
1d68cba5
BJ
88 short port;
89 int pv[2], pid, ready, readfrom, cc;
90 char buf[BUFSIZ], sig;
91 int one = 1;
92
93 (void) signal(SIGINT, SIG_DFL);
94 (void) signal(SIGQUIT, SIG_DFL);
95 (void) signal(SIGTERM, SIG_DFL);
27890867 96#ifdef DEBUG
1d68cba5
BJ
97 { int t = open("/dev/tty", 2);
98 if (t >= 0) {
99 ioctl(t, TIOCNOTTY, (char *)0);
100 (void) close(t);
101 }
102 }
103#endif
1d68cba5 104 fromp->sin_port = ntohs((u_short)fromp->sin_port);
1d68cba5 105 if (fromp->sin_family != AF_INET ||
d173f55d 106 fromp->sin_port >= IPPORT_RESERVED) {
3f99c0f7 107 syslog(LOG_ERR, "malformed from address\n");
1d68cba5 108 exit(1);
d173f55d 109 }
1d68cba5
BJ
110 (void) alarm(60);
111 port = 0;
112 for (;;) {
113 char c;
d173f55d 114 if (read(f, &c, 1) != 1) {
3f99c0f7 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 128 syslog(LOG_ERR, "can't get stderr port: %m");
d173f55d
SL
129 exit(1);
130 }
131 if (port >= IPPORT_RESERVED) {
3f99c0f7 132 syslog(LOG_ERR, "2nd port not reserved\n");
1d68cba5 133 exit(1);
d173f55d 134 }
e23c0837 135 fromp->sin_port = htons((u_short)port);
27890867 136 if (connect(s, fromp, sizeof (*fromp), 0) < 0) {
3f99c0f7 137 syslog(LOG_ERR, "connect: %m");
1d68cba5 138 exit(1);
d173f55d 139 }
1d68cba5 140 }
d173f55d
SL
141 dup2(f, 0);
142 dup2(f, 1);
143 dup2(f, 2);
3f5b52bc
SL
144 hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
145 fromp->sin_family);
146 if (hp == 0) {
4c99408e
JB
147 /*
148 * Only the name is used below
149 */
150 hp = &hostent;
151 hp->h_name = inet_ntoa(fromp->sin_addr);
1d68cba5
BJ
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 }
792e68a4
JB
170 if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
171 ruserok(hp->h_name, pwd->pw_uid == 0, remuser, locuser) < 0) {
1d68cba5
BJ
172 error("Permission denied.\n");
173 exit(1);
174 }
175 (void) write(2, "\0", 1);
176 if (port) {
177 if (pipe(pv) < 0) {
178 error("Can't make pipe.\n");
179 exit(1);
180 }
181 pid = fork();
182 if (pid == -1) {
183 error("Try again.\n");
184 exit(1);
185 }
186 if (pid) {
187 (void) close(0); (void) close(1); (void) close(2);
188 (void) close(f); (void) close(pv[1]);
189 readfrom = (1<<s) | (1<<pv[0]);
190 ioctl(pv[1], FIONBIO, (char *)&one);
191 /* should set s nbio! */
192 do {
193 ready = readfrom;
e7d6d17a
SL
194 if (select(16, &ready, 0, 0, 0) < 0)
195 break;
1d68cba5
BJ
196 if (ready & (1<<s)) {
197 if (read(s, &sig, 1) <= 0)
198 readfrom &= ~(1<<s);
199 else
200 killpg(pid, sig);
201 }
202 if (ready & (1<<pv[0])) {
fadc6b8f 203 errno = 0;
1d68cba5
BJ
204 cc = read(pv[0], buf, sizeof (buf));
205 if (cc <= 0) {
ff24c640 206 shutdown(s, 1+1);
1d68cba5
BJ
207 readfrom &= ~(1<<pv[0]);
208 } else
209 (void) write(s, buf, cc);
210 }
211 } while (readfrom);
212 exit(0);
213 }
214 setpgrp(0, getpid());
215 (void) close(s); (void) close(pv[0]);
216 dup2(pv[1], 2);
217 }
218 if (*pwd->pw_shell == '\0')
219 pwd->pw_shell = "/bin/sh";
220 (void) close(f);
1d68cba5 221 (void) setgid(pwd->pw_gid);
80aca4ff 222 initgroups(pwd->pw_name, pwd->pw_gid);
fadc6b8f 223 (void) setuid(pwd->pw_uid);
1d68cba5
BJ
224 environ = envinit;
225 strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
226 strncat(shell, pwd->pw_shell, sizeof(shell)-7);
227 strncat(username, pwd->pw_name, sizeof(username)-6);
228 cp = rindex(pwd->pw_shell, '/');
229 if (cp)
230 cp++;
231 else
232 cp = pwd->pw_shell;
233 execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
234 perror(pwd->pw_shell);
235 exit(1);
236protofail:
237 error("rsh: protocol failure detected by remote\n");
238 exit(1);
239}
240
241/* VARARGS 1 */
35db6ea0 242error(fmt, a1, a2, a3)
1d68cba5 243 char *fmt;
35db6ea0 244 int a1, a2, a3;
1d68cba5
BJ
245{
246 char buf[BUFSIZ];
247
248 buf[0] = 1;
35db6ea0 249 (void) sprintf(buf+1, fmt, a1, a2, a3);
1d68cba5
BJ
250 (void) write(2, buf, strlen(buf));
251}
252
253getstr(buf, cnt, err)
254 char *buf;
255 int cnt;
256 char *err;
257{
258 char c;
259
260 do {
261 if (read(0, &c, 1) != 1)
262 exit(1);
263 *buf++ = c;
264 if (--cnt == 0) {
265 error("%s too long\n", err);
266 exit(1);
267 }
268 } while (c != 0);
269}