1 | /*
|
---|
2 | in.rshd.c
|
---|
3 | */
|
---|
4 |
|
---|
5 | /*
|
---|
6 | main channel:
|
---|
7 |
|
---|
8 | back channel\0
|
---|
9 | remuser\0
|
---|
10 | locuser\0
|
---|
11 | command\0
|
---|
12 | data
|
---|
13 |
|
---|
14 | back channel:
|
---|
15 | signal\0
|
---|
16 |
|
---|
17 | */
|
---|
18 |
|
---|
19 | #include <sys/types.h>
|
---|
20 | #include <errno.h>
|
---|
21 | #include <fcntl.h>
|
---|
22 | #include <limits.h>
|
---|
23 | #include <pwd.h>
|
---|
24 | #include <grp.h>
|
---|
25 | #include <signal.h>
|
---|
26 | #include <stdio.h>
|
---|
27 | #include <stdlib.h>
|
---|
28 | #include <string.h>
|
---|
29 | #include <unistd.h>
|
---|
30 | #include <sys/ioctl.h>
|
---|
31 | #include <net/gen/in.h>
|
---|
32 | #include <net/gen/inet.h>
|
---|
33 | #include <net/gen/netdb.h>
|
---|
34 | #include <net/gen/socket.h>
|
---|
35 | #include <net/gen/tcp.h>
|
---|
36 | #include <net/gen/tcp_io.h>
|
---|
37 | #include <net/hton.h>
|
---|
38 | #include <net/netlib.h>
|
---|
39 |
|
---|
40 | #define DEBUG 0
|
---|
41 |
|
---|
42 | #if DEBUG
|
---|
43 | #define where() fprintf(stderr, "%s, %d: ", __FILE__, __LINE__)
|
---|
44 | #endif
|
---|
45 |
|
---|
46 | char cmdbuf[_POSIX_ARG_MAX+1], locuser[16], remuser[16];
|
---|
47 | extern char **environ;
|
---|
48 | char username[20]="USER=";
|
---|
49 | char homedir[64]="HOME=";
|
---|
50 | char shell[64]="SHELL=";
|
---|
51 | char tz[1024]="TZ=";
|
---|
52 | char *envinit[]= {homedir, shell, username, tz, "PATH=:/bin:/usr/bin", 0};
|
---|
53 | char *prog_name;
|
---|
54 | char buffer[PIPE_BUF];
|
---|
55 |
|
---|
56 | #if __STDC__
|
---|
57 | #define PROTO(func, args) func args
|
---|
58 | #else
|
---|
59 | #define PROTO(func, args) func ()
|
---|
60 | #endif
|
---|
61 |
|
---|
62 | PROTO (int main, (int argc, char *argv[]));
|
---|
63 | PROTO (void getstr, (char*buf, int cnt, char *err));
|
---|
64 | PROTO (void close_on_exec, (int fd));
|
---|
65 |
|
---|
66 | int main(argc, argv)
|
---|
67 | int argc;
|
---|
68 | char *argv[];
|
---|
69 | {
|
---|
70 | int result, result1;
|
---|
71 | nwio_tcpconf_t tcpconf, err_tcpconf;
|
---|
72 | nwio_tcpcl_t tcpconnopt;
|
---|
73 | nwio_tcpatt_t tcpattachopt;
|
---|
74 | tcpport_t tcpport;
|
---|
75 | tcpport_t err_port;
|
---|
76 | int err_fd, pds[2];
|
---|
77 | pid_t pid, pid1, new_pg;
|
---|
78 | #if USEATTACH
|
---|
79 | int err2_fd;
|
---|
80 | #endif
|
---|
81 | struct passwd *pwent;
|
---|
82 | char *cp, *buff_ptr, *TZ;
|
---|
83 | char sig;
|
---|
84 |
|
---|
85 | prog_name= argv[0];
|
---|
86 | if (argc != 1)
|
---|
87 | {
|
---|
88 | fprintf(stderr, "%s: wrong number of arguments (%d)\n",
|
---|
89 | prog_name, argc);
|
---|
90 | exit(1);
|
---|
91 | }
|
---|
92 |
|
---|
93 | signal(SIGINT, SIG_DFL);
|
---|
94 | signal(SIGQUIT, SIG_DFL);
|
---|
95 | signal(SIGTERM, SIG_DFL);
|
---|
96 |
|
---|
97 | #if DEBUG
|
---|
98 | { where(); fprintf(stderr, "\n"); }
|
---|
99 | #endif
|
---|
100 | result= ioctl (0, NWIOGTCPCONF, &tcpconf);
|
---|
101 | if (result<0)
|
---|
102 | {
|
---|
103 | fprintf(stderr, "%s: ioctl(NWIOGTCPCONF)= %d : %s\n",
|
---|
104 | prog_name, errno, strerror(errno));
|
---|
105 | exit(1);
|
---|
106 | }
|
---|
107 | #if DEBUG
|
---|
108 | { where(); fprintf(stderr, "\n"); }
|
---|
109 | #endif
|
---|
110 |
|
---|
111 | tcpport= ntohs(tcpconf.nwtc_remport);
|
---|
112 | if (tcpport >= TCPPORT_RESERVED || tcpport < TCPPORT_RESERVED/2)
|
---|
113 | {
|
---|
114 | printf("\1%s: unprotected port (%d)\n", prog_name, tcpport);
|
---|
115 | exit(1);
|
---|
116 | }
|
---|
117 | alarm(60);
|
---|
118 | err_port= 0;
|
---|
119 | for (;;)
|
---|
120 | {
|
---|
121 | char c;
|
---|
122 | result= read(0, &c, 1);
|
---|
123 | if (result <0)
|
---|
124 | {
|
---|
125 | fprintf(stderr, "%s: read= %d : %s\n", prog_name,
|
---|
126 | errno, strerror(errno));
|
---|
127 | }
|
---|
128 | if (result<1)
|
---|
129 | exit(1);
|
---|
130 | if (c == 0)
|
---|
131 | break;
|
---|
132 | err_port= err_port*10 + c - '0';
|
---|
133 | }
|
---|
134 | alarm(0);
|
---|
135 | if (err_port != 0)
|
---|
136 | {
|
---|
137 | int n, pid, lport;
|
---|
138 |
|
---|
139 | pid= getpid();
|
---|
140 | lport= 1;
|
---|
141 | do {
|
---|
142 | lport= (lport << 1) | (pid & 1);
|
---|
143 | pid >>= 1;
|
---|
144 | } while (lport < TCPPORT_RESERVED/2);
|
---|
145 |
|
---|
146 | n= TCPPORT_RESERVED/2;
|
---|
147 | do
|
---|
148 | {
|
---|
149 | if (--lport < TCPPORT_RESERVED/2)
|
---|
150 | lport= TCPPORT_RESERVED-1;
|
---|
151 | err_fd= open ("/dev/tcp", O_RDWR);
|
---|
152 | if (err_fd<0)
|
---|
153 | {
|
---|
154 | fprintf(stderr, "%s: open= %d : %s\n",
|
---|
155 | prog_name, errno, strerror(errno));
|
---|
156 | exit(1);
|
---|
157 | }
|
---|
158 | close_on_exec(err_fd);
|
---|
159 | err_tcpconf.nwtc_flags= NWTC_LP_SET | NWTC_SET_RA |
|
---|
160 | NWTC_SET_RP | NWTC_EXCL;
|
---|
161 | err_tcpconf.nwtc_locport= htons(lport);
|
---|
162 | err_tcpconf.nwtc_remport= htons(err_port);
|
---|
163 | err_tcpconf.nwtc_remaddr= tcpconf.nwtc_remaddr;
|
---|
164 |
|
---|
165 | #if DEBUG
|
---|
166 | { where(); fprintf(stderr, "\n"); }
|
---|
167 | #endif
|
---|
168 | result= ioctl (err_fd, NWIOSTCPCONF, &err_tcpconf);
|
---|
169 | if (result == 0) break;
|
---|
170 | if (errno != EADDRINUSE)
|
---|
171 | {
|
---|
172 | fprintf(stderr,
|
---|
173 | "%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
|
---|
174 | prog_name, errno, strerror(errno));
|
---|
175 | exit(1);
|
---|
176 | }
|
---|
177 | close(err_fd);
|
---|
178 | } while (--n > 0);
|
---|
179 | if (n == 0)
|
---|
180 | {
|
---|
181 | printf("\1can't get stderr port\n");
|
---|
182 | exit(1);
|
---|
183 | }
|
---|
184 |
|
---|
185 | err_tcpconf.nwtc_flags= NWTC_SHARED;
|
---|
186 | #if DEBUG
|
---|
187 | { where(); fprintf(stderr, "\n"); }
|
---|
188 | #endif
|
---|
189 | result= ioctl (err_fd, NWIOSTCPCONF, &err_tcpconf);
|
---|
190 | if (result<0)
|
---|
191 | {
|
---|
192 | fprintf(stderr,
|
---|
193 | "%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
|
---|
194 | prog_name, errno, strerror(errno));
|
---|
195 | exit(1);
|
---|
196 | }
|
---|
197 | #if DEBUG
|
---|
198 | { where(); fprintf(stderr, "\n"); }
|
---|
199 | #endif
|
---|
200 | tcpconnopt.nwtcl_flags= 0;
|
---|
201 |
|
---|
202 | n= 20;
|
---|
203 | for (;;)
|
---|
204 | {
|
---|
205 | #if DEBUG
|
---|
206 | { where(); fprintf(stderr, "\n"); }
|
---|
207 | #endif
|
---|
208 | result= ioctl (err_fd, NWIOTCPCONN, &tcpconnopt);
|
---|
209 | if (result == 0) break;
|
---|
210 | if (errno != EAGAIN && errno != ECONNREFUSED)
|
---|
211 | {
|
---|
212 | fprintf(stderr,
|
---|
213 | "%s: ioctl(NWIOTCPCONN)= %d : %s\n",
|
---|
214 | prog_name, errno, strerror(errno));
|
---|
215 | exit(1);
|
---|
216 | }
|
---|
217 | if (--n == 0) break;
|
---|
218 | sleep(1);
|
---|
219 | #if DEBUG
|
---|
220 | { where(); fprintf(stderr, "\n"); }
|
---|
221 | #endif
|
---|
222 | }
|
---|
223 | #if USEATTACH
|
---|
224 | err2_fd= open ("/dev/tcp", O_RDWR);
|
---|
225 | close_on_exec(err2_fd);
|
---|
226 | if (err2_fd<0)
|
---|
227 | {
|
---|
228 | fprintf(stderr, "%s: open= %d : %s\n", errno,
|
---|
229 | prog_name, strerror(errno));
|
---|
230 | exit(1);
|
---|
231 | }
|
---|
232 | #if DEBUG
|
---|
233 | { where(); fprintf(stderr, "\n"); }
|
---|
234 | #endif
|
---|
235 | result= ioctl (err2_fd, NWIOSTCPCONF, &err_tcpconf);
|
---|
236 | if (result<0)
|
---|
237 | {
|
---|
238 | fprintf(stderr, "%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
|
---|
239 | prog_name, errno, strerror(errno));
|
---|
240 | exit(1);
|
---|
241 | }
|
---|
242 | #if DEBUG
|
---|
243 | { where(); fprintf(stderr, "\n"); }
|
---|
244 | #endif
|
---|
245 | tcpattachopt.nwta_flags= 0;
|
---|
246 | #if DEBUG
|
---|
247 | { where(); fprintf(stderr, "\n"); }
|
---|
248 | #endif
|
---|
249 | result= ioctl (err2_fd, NWIOTCPATTACH, &tcpattachopt);
|
---|
250 | if (result<0)
|
---|
251 | {
|
---|
252 | fprintf(stderr, "%s: ioctl(NWIOTCPATTACH)= %d : %s\n",
|
---|
253 | prog_name, errno, strerror(errno));
|
---|
254 | exit(1);
|
---|
255 | }
|
---|
256 | #if DEBUG
|
---|
257 | { where(); fprintf(stderr, "\n"); }
|
---|
258 | #endif
|
---|
259 | #endif
|
---|
260 | }
|
---|
261 | getstr(remuser, sizeof(remuser), "remuser");
|
---|
262 | getstr(locuser, sizeof(locuser), "locuser");
|
---|
263 | getstr(cmdbuf, sizeof(cmdbuf), "cmdbuf");
|
---|
264 | setpwent();
|
---|
265 | pwent= getpwnam(locuser);
|
---|
266 | if (!pwent)
|
---|
267 | {
|
---|
268 | printf("\1Login incorrect.\n");
|
---|
269 | exit(1);
|
---|
270 | }
|
---|
271 | endpwent();
|
---|
272 | if (chdir(pwent->pw_dir) < 0)
|
---|
273 | {
|
---|
274 | chdir("/");
|
---|
275 | }
|
---|
276 | #if DEBUG
|
---|
277 | { where(); fprintf(stderr, "calling iruserok(%s, %d, %s, %s)\n",
|
---|
278 | inet_ntoa(tcpconf.nwtc_remaddr), 0, remuser, locuser); }
|
---|
279 | #endif
|
---|
280 | if (iruserok(tcpconf.nwtc_remaddr, 0, remuser, locuser) < 0)
|
---|
281 | {
|
---|
282 | printf("\1Permission denied.\n");
|
---|
283 | exit(1);
|
---|
284 | }
|
---|
285 | if (err_port)
|
---|
286 | {
|
---|
287 | /* Let's go to a different process group. */
|
---|
288 | new_pg= setsid();
|
---|
289 | pid= fork();
|
---|
290 | if (pid<0)
|
---|
291 | {
|
---|
292 | if (errno != EAGAIN)
|
---|
293 | {
|
---|
294 | fprintf(stderr, "%s: fork()= %d : %s\n",
|
---|
295 | prog_name, errno, strerror(errno));
|
---|
296 | }
|
---|
297 | printf("\1Try again.\n");
|
---|
298 | exit(1);
|
---|
299 | }
|
---|
300 | if (pid)
|
---|
301 | {
|
---|
302 | close(0); /* stdin */
|
---|
303 | close(1); /* stdout */
|
---|
304 | #if USEATTACH
|
---|
305 | close(err_fd); /* stderr for shell */
|
---|
306 | #endif
|
---|
307 | dup2(2,0);
|
---|
308 | dup2(2,1);
|
---|
309 | for (;;)
|
---|
310 | {
|
---|
311 | #if !USEATTACH
|
---|
312 | if (read(err_fd, &sig, 1) <= 0)
|
---|
313 | #else
|
---|
314 | if (read(err2_fd, &sig, 1) <= 0)
|
---|
315 | #endif
|
---|
316 | {
|
---|
317 | #if 0
|
---|
318 | printf("read failed: %d\n", errno);
|
---|
319 | #endif
|
---|
320 | exit(0);
|
---|
321 | }
|
---|
322 | pid= 0;
|
---|
323 | #if 0
|
---|
324 | printf("killing %d with %d\n", -new_pg, sig);
|
---|
325 | #endif
|
---|
326 | kill(-new_pg, sig);
|
---|
327 | }
|
---|
328 | }
|
---|
329 | #if USEATTACH
|
---|
330 | close(err2_fd); /* signal channel for parent */
|
---|
331 | #endif
|
---|
332 | result= pipe(pds);
|
---|
333 | if (result<0)
|
---|
334 | {
|
---|
335 | printf("\1Can't make pipe\n");
|
---|
336 | kill(getppid(), SIGTERM);
|
---|
337 | exit(1);
|
---|
338 | }
|
---|
339 | pid1= fork();
|
---|
340 | if (pid1<0)
|
---|
341 | {
|
---|
342 | if (errno != EAGAIN)
|
---|
343 | {
|
---|
344 | fprintf(stderr, "%s: fork()= %d : %s\n",
|
---|
345 | prog_name, errno, strerror(errno));
|
---|
346 | }
|
---|
347 | printf("\1Try again.\n");
|
---|
348 | kill(-new_pg, SIGTERM);
|
---|
349 | exit(1);
|
---|
350 | }
|
---|
351 | if (pid1)
|
---|
352 | {
|
---|
353 | close(pds[1]); /* write side of pipe */
|
---|
354 | for (;;)
|
---|
355 | {
|
---|
356 | result= read(pds[0], buffer, sizeof(buffer));
|
---|
357 | if (result<=0)
|
---|
358 | {
|
---|
359 | kill(pid, SIGTERM);
|
---|
360 | exit(0);
|
---|
361 | }
|
---|
362 | buff_ptr= buffer;
|
---|
363 | while (result>0)
|
---|
364 | {
|
---|
365 | result1= write (err_fd, buff_ptr,
|
---|
366 | result);
|
---|
367 | if (result1 <= 0)
|
---|
368 | {
|
---|
369 | fprintf(stderr,
|
---|
370 | "%s: write()= %d : %s\n",
|
---|
371 | prog_name, errno,
|
---|
372 | strerror(errno));
|
---|
373 | kill(-new_pg, SIGTERM);
|
---|
374 | exit(1);
|
---|
375 | }
|
---|
376 | result -= result1;
|
---|
377 | }
|
---|
378 | }
|
---|
379 | }
|
---|
380 | close(err_fd); /* file descriptor for error channel */
|
---|
381 | close (pds[0]); /* read side of pipe */
|
---|
382 | dup2(pds[1], 2);
|
---|
383 | close (pds[1]); /* write side of pipe */
|
---|
384 | }
|
---|
385 | if (*pwent->pw_shell == '\0')
|
---|
386 | pwent->pw_shell= "/bin/sh";
|
---|
387 | #if __minix_vmd
|
---|
388 | initgroups(pwent->pw_name, pwent->pw_gid);
|
---|
389 | #endif
|
---|
390 | setgid(pwent->pw_gid);
|
---|
391 | setuid(pwent->pw_uid);
|
---|
392 | TZ=getenv("TZ");
|
---|
393 | environ= envinit;
|
---|
394 | strncat(homedir, pwent->pw_dir, sizeof(homedir)-6);
|
---|
395 | strncat(shell, pwent->pw_shell, sizeof(shell)-7);
|
---|
396 | strncat(username, pwent->pw_name, sizeof(username)-6);
|
---|
397 | if (TZ)
|
---|
398 | strncat(tz, TZ, sizeof(tz)-4);
|
---|
399 | else
|
---|
400 | envinit[3]= NULL;
|
---|
401 |
|
---|
402 | cp= strrchr(pwent->pw_shell, '/');
|
---|
403 | if (cp)
|
---|
404 | cp++;
|
---|
405 | else
|
---|
406 | cp= pwent->pw_shell;
|
---|
407 |
|
---|
408 | if (!err_port)
|
---|
409 | dup2(1, 2);
|
---|
410 | write(1, "\0", 1);
|
---|
411 |
|
---|
412 | execl(pwent->pw_shell, cp, "-c", cmdbuf, 0);
|
---|
413 | close(2);
|
---|
414 | open("/dev/tty", O_RDWR);
|
---|
415 | fprintf(stderr, "%s: execl(%s, %s, .., %s)= %d : %s\n", prog_name,
|
---|
416 | pwent->pw_shell, cp, cmdbuf, errno, strerror(errno));
|
---|
417 | kill(getppid(), SIGTERM);
|
---|
418 | exit(1);
|
---|
419 | }
|
---|
420 |
|
---|
421 | void getstr(buf, cnt, err)
|
---|
422 | char *buf;
|
---|
423 | int cnt;
|
---|
424 | char *err;
|
---|
425 | {
|
---|
426 | char c;
|
---|
427 |
|
---|
428 | do
|
---|
429 | {
|
---|
430 | if (read(0, &c, 1) != 1)
|
---|
431 | exit(1);
|
---|
432 | *buf++ = c;
|
---|
433 | if (--cnt == 0)
|
---|
434 | {
|
---|
435 | printf("\1%s too long", err);
|
---|
436 | exit(1);
|
---|
437 | }
|
---|
438 | } while (c != 0);
|
---|
439 | }
|
---|
440 |
|
---|
441 | void close_on_exec(fd)
|
---|
442 | int fd;
|
---|
443 | {
|
---|
444 | (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
|
---|
445 | }
|
---|