include-afsconfig-before-param-h-20010712
[openafs.git] / src / rsh / rlogin.c
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 /*
8  * rlogin - remote login
9  */
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID("$Header$");
14
15 #if     !defined(AFS_HPUX_ENV) && !defined(AFS_SUN5_ENV) && !defined(AFS_SGI_ENV) && !defined(AFS_LINUX20_ENV)
16 #include <sys/param.h>
17 #include <sys/types.h>
18 #include <sys/file.h>
19 #include <sys/socket.h>
20 #include <sys/wait.h>
21
22 #include <netinet/in.h>
23
24 #include <stdio.h>
25 #include <sgtty.h>
26 #include <errno.h>
27 #include <pwd.h>
28 #include <signal.h>
29 #include <netdb.h>
30
31 # ifndef TIOCPKT_WINDOW
32 # define TIOCPKT_WINDOW 0x80
33 # endif /* TIOCPKT_WINDOW */
34
35 char    *index(), *rindex(), *malloc(), *getenv();
36 struct  passwd *getpwuid();
37 char    *name;
38 int     rem;
39 char    cmdchar = '~';
40 int     eight;
41 int     litout;
42 char    *speeds[] =
43     { "0", "50", "75", "110", "134", "150", "200", "300",
44       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
45 char    term[256] = "network";
46 extern  int errno;
47 int     lostpeer();
48 #ifndef COMPAT
49 int     dosigwinch = 0;
50 int     nosigwin = 0;
51 struct  winsize winsize;
52 int     sigwinch(), oob();
53 #else /* COMPAT */
54 #define sigmask(s)      (1 << (s-1))
55 int     oob();
56 #endif /* COMPAT */
57
58 #ifdef  AFS_AIX32_ENV
59 #if defined(NLS) || defined(KJI)
60 #include <locale.h>
61 #endif
62 #endif
63
64 #include "AFS_component_version_number.c"
65
66 main(argc, argv)
67         int argc;
68         char **argv;
69 {
70         char *host, *cp;
71         struct sgttyb ttyb;
72         struct passwd *pwd;
73         struct servent *sp;
74         int uid, options = 0, oldmask;
75         int on = 1;
76
77 #if defined(AFS_AIX32_ENV) && (defined(NLS) || defined(KJI))
78         setlocale(LC_ALL,"");
79 #endif
80
81         host = rindex(argv[0], '/');
82         if (host)
83                 host++;
84         else
85                 host = argv[0];
86         argv++, --argc;
87         if (!strcmp(host, "rlogin"))
88                 host = *argv++, --argc;
89 another:
90         if (argc > 0 && !strcmp(*argv, "-d")) {
91                 argv++, argc--;
92                 options |= SO_DEBUG;
93                 goto another;
94         }
95         if (argc > 0 && !strcmp(*argv, "-l")) {
96                 argv++, argc--;
97                 if (argc == 0)
98                         goto usage;
99                 name = *argv++; argc--;
100                 goto another;
101         }
102         if (argc > 0 && !strncmp(*argv, "-e", 2)) {
103                 cmdchar = argv[0][2];
104                 argv++, argc--;
105                 goto another;
106         }
107         if (argc > 0 && !strcmp(*argv, "-8")) {
108                 eight = 1;
109                 argv++, argc--;
110                 goto another;
111         }
112         if (argc > 0 && !strcmp(*argv, "-L")) {
113                 litout = 1;
114                 argv++, argc--;
115                 goto another;
116         }
117 #ifndef COMPAT
118         if (argc > 0 && !strcmp(*argv, "-w")) {
119                 nosigwin++;
120                 argv++, argc--;
121                 goto another;
122         }
123 #endif /* COMPAT */
124         if (host == 0)
125                 goto usage;
126         if (argc > 0)
127                 goto usage;
128         pwd = getpwuid(getuid());
129         if (pwd == 0) {
130                 fprintf(stderr, "Who are you?\n");
131                 exit(1);
132         }
133         sp = getservbyname("login", "tcp");
134         if (sp == 0) {
135                 fprintf(stderr, "rlogin: login/tcp: unknown service\n");
136                 exit(2);
137         }
138         cp = getenv("TERM");
139         if (cp)
140                 strcpy(term, cp);
141         if (ioctl(0, TIOCGETP, &ttyb) == 0) {
142                 strcat(term, "/");
143                 strcat(term, speeds[ttyb.sg_ospeed]);
144         }
145 #ifndef COMPAT
146 #ifdef TIOCGWINSZ
147         (void) ioctl(0, TIOCGWINSZ, &winsize);
148 #else
149         (void) ioctl(0, TIOCGSIZE, &winsize);
150 #endif
151 #endif /* COMPAT */
152         signal(SIGPIPE, lostpeer);
153         signal(SIGURG, oob);
154         oldmask = sigblock(sigmask(SIGURG));
155         rem = rcmd(&host, sp->s_port, pwd->pw_name,
156 #ifdef  AFS_AIX32_ENV
157             name ? name : pwd->pw_name, term, 0, 0);
158 #else
159             name ? name : pwd->pw_name, term, 0);
160 #endif
161         if (rem < 0)
162                 exit(1);
163         if (options & SO_DEBUG &&
164             setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
165                 perror("rlogin: setsockopt (SO_DEBUG)");
166         uid = getuid();
167         if (setuid(uid) < 0) {
168                 perror("rlogin: setuid");
169                 exit(1);
170         }
171         doit(oldmask);
172         /*NOTREACHED*/
173 usage:
174         fprintf(stderr,
175             "usage: rlogin host [ -ex ] [ -l username ] [ -8 ] [ -L ] [ -w ]\n");
176         exit(1);
177 }
178
179 #define CRLF "\r\n"
180
181 int     child;
182 int     catchild();
183 int     writeroob();
184
185 int     defflags, tabflag;
186 int     deflflags;
187 char    deferase, defkill;
188 struct  tchars deftc;
189 struct  ltchars defltc;
190 struct  tchars notc =   { -1, -1, -1, -1, -1, -1 };
191 struct  ltchars noltc = { -1, -1, -1, -1, -1, -1 };
192
193 doit(oldmask)
194 {
195         int exit();
196         struct sgttyb sb;
197
198         ioctl(0, TIOCGETP, (char *)&sb);
199         defflags = sb.sg_flags;
200         tabflag = defflags & TBDELAY;
201         defflags &= ECHO | CRMOD;
202         deferase = sb.sg_erase;
203         defkill = sb.sg_kill;
204         ioctl(0, TIOCLGET, (char *)&deflflags);
205         ioctl(0, TIOCGETC, (char *)&deftc);
206         notc.t_startc = deftc.t_startc;
207         notc.t_stopc = deftc.t_stopc;
208         ioctl(0, TIOCGLTC, (char *)&defltc);
209         signal(SIGINT, SIG_IGN);
210         signal(SIGHUP, exit);
211         signal(SIGQUIT, exit);
212         child = fork();
213         if (child == -1) {
214                 perror("rlogin: fork");
215                 done();
216         }
217         if (child == 0) {
218                 mode(1);
219                 sigsetmask(oldmask);
220                 reader();
221                 sleep(1);
222                 prf("\007Connection closed.");
223                 exit(3);
224         }
225 #ifndef COMPAT
226         signal(SIGURG, writeroob);
227 #endif /* COMPAT */
228         sigsetmask(oldmask);
229         signal(SIGCHLD, catchild);
230 #ifndef COMPAT
231         if (!nosigwin)
232                 signal(SIGWINCH, sigwinch);
233 #endif /* COMPAT */
234         writer();
235         prf("Closed connection.");
236         done();
237 }
238
239 done()
240 {
241
242         mode(0);
243         if (child > 0 && kill(child, SIGKILL) >= 0)
244                 wait((int *)0);
245         exit(0);
246 }
247 #ifndef COMPAT
248 /*
249  * This is called when the reader process gets the out-of-band (urgent)
250  * request to turn on the window-changing protocol.
251  */
252 writeroob()
253 {
254
255         if (dosigwinch == 0)
256                 sendwindow();
257         dosigwinch = 1;
258 }
259 #endif /* COMPAT */
260 catchild()
261 {
262         int status;
263         int pid;
264
265 again:
266         pid = wait3(&status, WNOHANG|WUNTRACED, 0);
267         if (pid == 0)
268                 return;
269         /*
270          * if the child (reader) dies, just quit
271          */
272         if (pid < 0 || pid == child && !WIFSTOPPED(status))
273                 done();
274         goto again;
275 }
276
277 /*
278  * writer: write to remote: 0 -> line.
279  * ~.   terminate
280  * ~^Z  suspend rlogin process.
281  * ~^Y  suspend rlogin process, but leave reader alone.
282  */
283 writer()
284 {
285         char c;
286         register n;
287         register bol = 1;               /* beginning of line */
288         register local = 0;
289
290         for (;;) {
291                 n = read(0, &c, 1);
292                 if (n <= 0) {
293                         if (n < 0 && errno == EINTR)
294                                 continue;
295                         break;
296                 }
297                 /*
298                  * If we're at the beginning of the line
299                  * and recognize a command character, then
300                  * we echo locally.  Otherwise, characters
301                  * are echo'd remotely.  If the command
302                  * character is doubled, this acts as a 
303                  * force and local echo is suppressed.
304                  */
305                 if (bol) {
306                         bol = 0;
307                         if (c == cmdchar) {
308                                 bol = 0;
309                                 local = 1;
310                                 continue;
311                         }
312                 } else if (local) {
313                         local = 0;
314                         if (c == '.' || c == deftc.t_eofc) {
315                                 echo(c);
316                                 break;
317                         }
318                         if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
319                                 bol = 1;
320                                 echo(c);
321                                 stop(c);
322                                 continue;
323                         }
324                         if (c != cmdchar)
325                                 write(rem, &cmdchar, 1);
326                 }
327                 if (write(rem, &c, 1) == 0) {
328                         prf("line gone");
329                         break;
330                 }
331                 bol = c == defkill || c == deftc.t_eofc ||
332                     c == '\r' || c == '\n';
333         }
334 }
335
336 echo(c)
337 register char c;
338 {
339         char buf[8];
340         register char *p = buf;
341
342         c &= 0177;
343         *p++ = cmdchar;
344         if (c < ' ') {
345                 *p++ = '^';
346                 *p++ = c + '@';
347         } else if (c == 0177) {
348                 *p++ = '^';
349                 *p++ = '?';
350         } else
351                 *p++ = c;
352         *p++ = '\r';
353         *p++ = '\n';
354         write(1, buf, p - buf);
355 }
356
357 stop(cmdc)
358         char cmdc;
359 {
360         mode(0);
361         signal(SIGCHLD, SIG_IGN);
362         kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
363         signal(SIGCHLD, catchild);
364         mode(1);
365 #ifndef COMPAT
366         sigwinch();                     /* check for size changes */
367 #endif /* COMPAT */
368 }
369 #ifndef COMPAT
370 sigwinch()
371 {
372         struct winsize ws;
373
374         if (dosigwinch && !nosigwin && ioctl(0, TIOCGWINSZ, &ws) == 0 &&
375             bcmp(&ws, &winsize, sizeof (ws))) {
376                 winsize = ws;
377                 sendwindow();
378         }
379 }
380
381 /*
382  * Send the window size to the server via the magic escape
383  */
384 sendwindow()
385 {
386         char obuf[4 + sizeof (struct winsize)];
387         struct winsize *wp = (struct winsize *)(obuf+4);
388
389         obuf[0] = 0377;
390         obuf[1] = 0377;
391         obuf[2] = 's';
392         obuf[3] = 's';
393         wp->ws_row = htons(winsize.ws_row);
394         wp->ws_col = htons(winsize.ws_col);
395         wp->ws_xpixel = htons(winsize.ws_xpixel);
396         wp->ws_ypixel = htons(winsize.ws_ypixel);
397         (void) write(rem, obuf, sizeof(obuf));
398 }
399 #endif /* COMPAT */
400 oob()
401 {
402         int out = 1+1, atmark;
403         char waste[BUFSIZ], mark;
404         struct sgttyb sb;
405         static int didnotify = 0;
406
407         ioctl(1, TIOCFLUSH, (char *)&out);
408         for (;;) {
409                 int rv;
410                 if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
411                         perror("ioctl");
412                         break;
413                 }
414                 if (atmark)
415                         break;
416                 rv = read(rem, waste, sizeof (waste));
417                 if (rv <= 0)
418                         break;
419         }
420         recv(rem, &mark, 1, MSG_OOB);
421         if (didnotify == 0 && (mark & TIOCPKT_WINDOW)) {
422                 /*
423                  * Let server know about window size changes
424                  */
425                 kill(getppid(), SIGURG);
426                 didnotify = 1;
427         }
428         if (eight)
429                 return;
430         if (mark & TIOCPKT_NOSTOP) {
431                 ioctl(0, TIOCGETP, (char *)&sb);
432                 sb.sg_flags &= ~CBREAK;
433                 sb.sg_flags |= RAW;
434                 ioctl(0, TIOCSETN, (char *)&sb);
435                 notc.t_stopc = -1;
436                 notc.t_startc = -1;
437                 ioctl(0, TIOCSETC, (char *)&notc);
438         }
439         if (mark & TIOCPKT_DOSTOP) {
440                 ioctl(0, TIOCGETP, (char *)&sb);
441                 sb.sg_flags &= ~RAW;
442                 sb.sg_flags |= CBREAK;
443                 ioctl(0, TIOCSETN, (char *)&sb);
444                 notc.t_stopc = deftc.t_stopc;
445                 notc.t_startc = deftc.t_startc;
446                 ioctl(0, TIOCSETC, (char *)&notc);
447         }
448 }
449
450 /*
451  * reader: read from remote: line -> 1
452  */
453 reader()
454 {
455         char rb[BUFSIZ];
456         register int cnt;
457
458         signal(SIGTTOU, SIG_IGN);
459         { int pid = getpid();
460           fcntl(rem, F_SETOWN, pid); }
461         for (;;) {
462                 cnt = read(rem, rb, sizeof (rb));
463                 if (cnt == 0)
464                         break;
465                 if (cnt < 0) {
466                         if (errno == EINTR)
467                                 continue;
468                         break;
469                 }
470                 write(1, rb, cnt);
471         }
472 }
473
474 mode(f)
475 {
476         struct tchars *tc;
477         struct ltchars *ltc;
478         struct sgttyb sb;
479         int     lflags;
480
481         ioctl(0, TIOCGETP, (char *)&sb);
482         ioctl(0, TIOCLGET, (char *)&lflags);
483         switch (f) {
484
485         case 0:
486                 sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
487                 sb.sg_flags |= defflags|tabflag;
488                 tc = &deftc;
489                 ltc = &defltc;
490                 sb.sg_kill = defkill;
491                 sb.sg_erase = deferase;
492                 lflags = deflflags;
493                 break;
494
495         case 1:
496                 sb.sg_flags |= (eight ? RAW : CBREAK);
497                 sb.sg_flags &= ~defflags;
498                 /* preserve tab delays, but turn off XTABS */
499                 if ((sb.sg_flags & TBDELAY) == XTABS)
500                         sb.sg_flags &= ~TBDELAY;
501                 tc = &notc;
502                 ltc = &noltc;
503                 sb.sg_kill = sb.sg_erase = -1;
504                 if (litout)
505                         lflags |= LLITOUT;
506                 break;
507
508         default:
509                 return;
510         }
511         ioctl(0, TIOCSLTC, (char *)ltc);
512         ioctl(0, TIOCSETC, (char *)tc);
513         ioctl(0, TIOCSETN, (char *)&sb);
514         ioctl(0, TIOCLSET, (char *)&lflags);
515 }
516
517 /*VARARGS*/
518 prf(f, a1, a2, a3, a4, a5)
519         char *f;
520 {
521         fprintf(stderr, f, a1, a2, a3, a4, a5);
522         fprintf(stderr, CRLF);
523 }
524
525 lostpeer()
526 {
527         signal(SIGPIPE, SIG_IGN);
528         prf("\007Connection closed.");
529         done();
530 }
531 #else
532
533 #include "AFS_component_version_number.c"
534
535 main(argc, argv)
536     int argc;
537     char *argv[];
538 {
539     printf("afs rlogin: Not supported for this system ...\n");
540 }
541 #endif  /* !defined(AFS_HPUX_ENV) */
542