unstack - fix ipcvecs
[minix.git] / commands / rshd / rshd.c
blobec15f825a976f179213d74ceda1ad09401cb99c4
1 /*
2 in.rshd.c
3 */
5 /*
6 main channel:
8 back channel\0
9 remuser\0
10 locuser\0
11 command\0
12 data
14 back channel:
15 signal\0
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>
40 #define DEBUG 0
42 #if DEBUG
43 #define where() fprintf(stderr, "%s, %d: ", __FILE__, __LINE__)
44 #endif
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];
56 #if __STDC__
57 #define PROTO(func, args) func args
58 #else
59 #define PROTO(func, args) func ()
60 #endif
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));
66 int main(argc, argv)
67 int argc;
68 char *argv[];
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;
85 prog_name= argv[0];
86 if (argc != 1)
88 fprintf(stderr, "%s: wrong number of arguments (%d)\n",
89 prog_name, argc);
90 exit(1);
93 signal(SIGINT, SIG_DFL);
94 signal(SIGQUIT, SIG_DFL);
95 signal(SIGTERM, SIG_DFL);
97 #if DEBUG
98 { where(); fprintf(stderr, "\n"); }
99 #endif
100 result= ioctl (0, NWIOGTCPCONF, &tcpconf);
101 if (result<0)
103 fprintf(stderr, "%s: ioctl(NWIOGTCPCONF)= %d : %s\n",
104 prog_name, errno, strerror(errno));
105 exit(1);
107 #if DEBUG
108 { where(); fprintf(stderr, "\n"); }
109 #endif
111 tcpport= ntohs(tcpconf.nwtc_remport);
112 if (tcpport >= TCPPORT_RESERVED || tcpport < TCPPORT_RESERVED/2)
114 printf("\1%s: unprotected port (%d)\n", prog_name, tcpport);
115 exit(1);
117 alarm(60);
118 err_port= 0;
119 for (;;)
121 char c;
122 result= read(0, &c, 1);
123 if (result <0)
125 fprintf(stderr, "%s: read= %d : %s\n", prog_name,
126 errno, strerror(errno));
128 if (result<1)
129 exit(1);
130 if (c == 0)
131 break;
132 err_port= err_port*10 + c - '0';
134 alarm(0);
135 if (err_port != 0)
137 int n, pid, lport;
139 pid= getpid();
140 lport= 1;
141 do {
142 lport= (lport << 1) | (pid & 1);
143 pid >>= 1;
144 } while (lport < TCPPORT_RESERVED/2);
146 n= TCPPORT_RESERVED/2;
149 if (--lport < TCPPORT_RESERVED/2)
150 lport= TCPPORT_RESERVED-1;
151 err_fd= open ("/dev/tcp", O_RDWR);
152 if (err_fd<0)
154 fprintf(stderr, "%s: open= %d : %s\n",
155 prog_name, errno, strerror(errno));
156 exit(1);
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;
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)
172 fprintf(stderr,
173 "%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
174 prog_name, errno, strerror(errno));
175 exit(1);
177 close(err_fd);
178 } while (--n > 0);
179 if (n == 0)
181 printf("\1can't get stderr port\n");
182 exit(1);
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)
192 fprintf(stderr,
193 "%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
194 prog_name, errno, strerror(errno));
195 exit(1);
197 #if DEBUG
198 { where(); fprintf(stderr, "\n"); }
199 #endif
200 tcpconnopt.nwtcl_flags= 0;
202 n= 20;
203 for (;;)
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)
212 fprintf(stderr,
213 "%s: ioctl(NWIOTCPCONN)= %d : %s\n",
214 prog_name, errno, strerror(errno));
215 exit(1);
217 if (--n == 0) break;
218 sleep(1);
219 #if DEBUG
220 { where(); fprintf(stderr, "\n"); }
221 #endif
223 #if USEATTACH
224 err2_fd= open ("/dev/tcp", O_RDWR);
225 close_on_exec(err2_fd);
226 if (err2_fd<0)
228 fprintf(stderr, "%s: open= %d : %s\n", errno,
229 prog_name, strerror(errno));
230 exit(1);
232 #if DEBUG
233 { where(); fprintf(stderr, "\n"); }
234 #endif
235 result= ioctl (err2_fd, NWIOSTCPCONF, &err_tcpconf);
236 if (result<0)
238 fprintf(stderr, "%s: ioctl(NWIOSTCPCONF)= %d : %s\n",
239 prog_name, errno, strerror(errno));
240 exit(1);
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)
252 fprintf(stderr, "%s: ioctl(NWIOTCPATTACH)= %d : %s\n",
253 prog_name, errno, strerror(errno));
254 exit(1);
256 #if DEBUG
257 { where(); fprintf(stderr, "\n"); }
258 #endif
259 #endif
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)
268 printf("\1Login incorrect.\n");
269 exit(1);
271 endpwent();
272 if (chdir(pwent->pw_dir) < 0)
274 chdir("/");
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)
282 printf("\1Permission denied.\n");
283 exit(1);
285 if (err_port)
287 /* Let's go to a different process group. */
288 new_pg= setsid();
289 pid= fork();
290 if (pid<0)
292 if (errno != EAGAIN)
294 fprintf(stderr, "%s: fork()= %d : %s\n",
295 prog_name, errno, strerror(errno));
297 printf("\1Try again.\n");
298 exit(1);
300 if (pid)
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 (;;)
311 #if !USEATTACH
312 if (read(err_fd, &sig, 1) <= 0)
313 #else
314 if (read(err2_fd, &sig, 1) <= 0)
315 #endif
317 #if 0
318 printf("read failed: %d\n", errno);
319 #endif
320 exit(0);
322 pid= 0;
323 #if 0
324 printf("killing %d with %d\n", -new_pg, sig);
325 #endif
326 kill(-new_pg, sig);
329 #if USEATTACH
330 close(err2_fd); /* signal channel for parent */
331 #endif
332 result= pipe(pds);
333 if (result<0)
335 printf("\1Can't make pipe\n");
336 kill(getppid(), SIGTERM);
337 exit(1);
339 pid1= fork();
340 if (pid1<0)
342 if (errno != EAGAIN)
344 fprintf(stderr, "%s: fork()= %d : %s\n",
345 prog_name, errno, strerror(errno));
347 printf("\1Try again.\n");
348 kill(-new_pg, SIGTERM);
349 exit(1);
351 if (pid1)
353 close(pds[1]); /* write side of pipe */
354 for (;;)
356 result= read(pds[0], buffer, sizeof(buffer));
357 if (result<=0)
359 kill(pid, SIGTERM);
360 exit(0);
362 buff_ptr= buffer;
363 while (result>0)
365 result1= write (err_fd, buff_ptr,
366 result);
367 if (result1 <= 0)
369 fprintf(stderr,
370 "%s: write()= %d : %s\n",
371 prog_name, errno,
372 strerror(errno));
373 kill(-new_pg, SIGTERM);
374 exit(1);
376 result -= result1;
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 */
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;
402 cp= strrchr(pwent->pw_shell, '/');
403 if (cp)
404 cp++;
405 else
406 cp= pwent->pw_shell;
408 if (!err_port)
409 dup2(1, 2);
410 write(1, "\0", 1);
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);
421 void getstr(buf, cnt, err)
422 char *buf;
423 int cnt;
424 char *err;
426 char c;
430 if (read(0, &c, 1) != 1)
431 exit(1);
432 *buf++ = c;
433 if (--cnt == 0)
435 printf("\1%s too long", err);
436 exit(1);
438 } while (c != 0);
441 void close_on_exec(fd)
442 int fd;
444 (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);