add ifdef's for KERBEROS
[unix-history] / usr / src / usr.bin / rlogin / rlogin.c
CommitLineData
66dc50f6 1/*
17f00b96
KB
2 * Copyright (c) 1983, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
438b541c 4 *
86dc635c 5 * %sccs.include.redist.c%
f42904bc
DF
6 */
7
8#ifndef lint
17f00b96
KB
9static char copyright[] =
10"@(#) Copyright (c) 1983, 1990, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
438b541c 12#endif /* not lint */
f42904bc 13
5567b76f 14#ifndef lint
17f00b96 15static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) %G%";
438b541c 16#endif /* not lint */
5567b76f 17
4ca10280
SL
18/*
19 * rlogin - remote login
20 */
545e8847 21#include <sys/param.h>
5567b76f 22#include <sys/socket.h>
a9b12987
KM
23#include <sys/time.h>
24#include <sys/resource.h>
840fc587 25#include <sys/wait.h>
86a16a64 26
c6c678f1 27#include <netinet/in.h>
66dc50f6
MK
28#include <netinet/in_systm.h>
29#include <netinet/ip.h>
86a16a64 30
999d0d08 31#include <errno.h>
e113d331
KB
32#include <fcntl.h>
33#include <netdb.h>
5567b76f 34#include <pwd.h>
e113d331
KB
35#include <setjmp.h>
36#include <sgtty.h>
37#include <signal.h>
afe1e594 38#include <stdio.h>
e113d331 39#include <stdlib.h>
38dde0cd 40#include <string.h>
e113d331 41#include <unistd.h>
e86d8e67 42
bbd924bb
KB
43#ifdef __STDC__
44#include <stdarg.h>
45#else
46#include <varargs.h>
47#endif
48
afe1e594 49#ifdef KERBEROS
4f10ae0d 50#include <kerberosIV/des.h>
63fc53d2 51#include <kerberosIV/krb.h>
afe1e594 52
e113d331
KB
53#include "krb.h"
54
afe1e594
KB
55CREDENTIALS cred;
56Key_schedule schedule;
cae07225 57int use_kerberos = 1, doencrypt;
afe1e594 58char dst_realm_buf[REALM_SZ], *dest_realm = NULL;
afe1e594
KB
59#endif
60
61#ifndef TIOCPKT_WINDOW
62#define TIOCPKT_WINDOW 0x80
63#endif
64
65/* concession to Sun */
66#ifndef SIGUSR1
67#define SIGUSR1 30
545e8847 68#endif
afe1e594 69
afe1e594 70int eight, litout, rem;
999d0d08
KB
71
72int noescape;
73u_char escapechar = '~';
74
afe1e594
KB
75char *speeds[] = {
76 "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200",
77 "1800", "2400", "4800", "9600", "19200", "38400"
78};
79
5f8f5f64 80#ifdef OLDSUN
545e8847
MK
81struct winsize {
82 unsigned short ws_row, ws_col;
83 unsigned short ws_xpixel, ws_ypixel;
84};
e113d331
KB
85#else
86#define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp)
afe1e594 87#endif
a9b12987 88struct winsize winsize;
86a16a64 89
e113d331
KB
90void catch_child __P((int));
91void copytochild __P((int));
92__dead void doit __P((long));
93__dead void done __P((int));
94void echo __P((char));
95u_int getescape __P((char *));
96void lostpeer __P((int));
97void mode __P((int));
98void msg __P((char *));
99void oob __P((int));
100int reader __P((int));
101void sendwindow __P((void));
102void setsignal __P((int));
103void sigwinch __P((int));
104void stop __P((char));
105__dead void usage __P((void));
106void writer __P((void));
107void writeroob __P((int));
108
109#ifdef KERBEROS
110void warning __P((const char *, ...));
111#endif
5f8f5f64 112#ifdef OLDSUN
e113d331 113int get_window_size __P((int, struct winsize *));
afe1e594 114#endif
a9b12987 115
e113d331 116int
5567b76f
BJ
117main(argc, argv)
118 int argc;
e113d331 119 char *argv[];
5567b76f 120{
afe1e594
KB
121 extern char *optarg;
122 extern int optind;
123 struct passwd *pw;
86a16a64 124 struct servent *sp;
afe1e594
KB
125 struct sgttyb ttyb;
126 long omask;
127 int argoff, ch, dflag, one, uid;
128 char *host, *p, *user, term[1024];
afe1e594
KB
129
130 argoff = dflag = 0;
131 one = 1;
132 host = user = NULL;
afe1e594
KB
133
134 if (p = rindex(argv[0], '/'))
135 ++p;
5567b76f 136 else
afe1e594
KB
137 p = argv[0];
138
139 if (strcmp(p, "rlogin"))
140 host = p;
0b6d50a1 141
afe1e594
KB
142 /* handle "rlogin host flags" */
143 if (!host && argc > 2 && argv[1][0] != '-') {
144 host = argv[1];
145 argoff = 1;
0b6d50a1 146 }
afe1e594
KB
147
148#ifdef KERBEROS
999d0d08 149#define OPTIONS "8EKLde:k:l:x"
afe1e594 150#else
999d0d08 151#define OPTIONS "8EKLde:l:"
afe1e594
KB
152#endif
153 while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
154 switch(ch) {
155 case '8':
156 eight = 1;
157 break;
999d0d08
KB
158 case 'E':
159 noescape = 1;
160 break;
0783ed7b
KB
161 case 'K':
162#ifdef KERBEROS
163 use_kerberos = 0;
164#endif
165 break;
afe1e594
KB
166 case 'L':
167 litout = 1;
168 break;
169 case 'd':
170 dflag = 1;
171 break;
172 case 'e':
888732ab 173 noescape = 0;
999d0d08 174 escapechar = getescape(optarg);
afe1e594
KB
175 break;
176#ifdef KERBEROS
177 case 'k':
178 dest_realm = dst_realm_buf;
179 (void)strncpy(dest_realm, optarg, REALM_SZ);
180 break;
181#endif
182 case 'l':
183 user = optarg;
184 break;
afe1e594
KB
185 case '?':
186 default:
187 usage();
52bf4a7f 188 }
afe1e594
KB
189 optind += argoff;
190 argc -= optind;
191 argv += optind;
52bf4a7f 192
afe1e594
KB
193 /* if haven't gotten a host yet, do so */
194 if (!host && !(host = *argv++))
195 usage();
0b6d50a1 196
afe1e594
KB
197 if (*argv)
198 usage();
199
200 if (!(pw = getpwuid(uid = getuid()))) {
201 (void)fprintf(stderr, "rlogin: unknown user id.\n");
5567b76f
BJ
202 exit(1);
203 }
afe1e594
KB
204 if (!user)
205 user = pw->pw_name;
206
0783ed7b 207 sp = NULL;
afe1e594 208#ifdef KERBEROS
0783ed7b 209 if (use_kerberos) {
cae07225 210 sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp");
0783ed7b
KB
211 if (sp == NULL) {
212 use_kerberos = 0;
213 warning("can't get entry for %s/tcp service",
cae07225 214 doencrypt ? "eklogin" : "klogin");
0783ed7b 215 }
028330cc 216 }
028330cc 217#endif
0783ed7b
KB
218 if (sp == NULL)
219 sp = getservbyname("login", "tcp");
afe1e594
KB
220 if (sp == NULL) {
221 (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n");
222 exit(1);
86a16a64 223 }
afe1e594
KB
224
225 (void)strcpy(term, (p = getenv("TERM")) ? p : "network");
119312d1 226 if (ioctl(0, TIOCGETP, &ttyb) == 0) {
afe1e594 227 (void)strcat(term, "/");
e113d331 228 (void)strcat(term, speeds[(int)ttyb.sg_ospeed]);
5567b76f 229 }
afe1e594
KB
230
231 (void)get_window_size(0, &winsize);
232
233 (void)signal(SIGPIPE, lostpeer);
a9b12987 234 /* will use SIGUSR1 for window size hack, so hold it off */
afe1e594 235 omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
9bccbd7c
KM
236 /*
237 * We set SIGURG and SIGUSR1 below so that an
238 * incoming signal will be held pending rather than being
239 * discarded. Note that these routines will be ready to get
240 * a signal by the time that they are unblocked below.
241 */
242 (void)signal(SIGURG, copytochild);
243 (void)signal(SIGUSR1, writeroob);
0b6d50a1 244
afe1e594 245#ifdef KERBEROS
028330cc 246try_connect:
afe1e594 247 if (use_kerberos) {
e113d331
KB
248 struct hostent *hp;
249
250 /* Fully qualify hostname (needed for krb_realmofhost). */
05d73ecb
EA
251 hp = gethostbyname(host);
252 if (hp != NULL && !(host = strdup(hp->h_name))) {
e113d331
KB
253 (void)fprintf(stderr, "rlogin: %s\n",
254 strerror(ENOMEM));
05d73ecb
EA
255 exit(1);
256 }
257
028330cc 258 rem = KSUCCESS;
afe1e594 259 errno = 0;
e0817634
KF
260 if (dest_realm == NULL)
261 dest_realm = krb_realmofhost(host);
262
afe1e594
KB
263 rem = krcmd(&host, sp->s_port, user, term, 0,
264 dest_realm);
e0817634 265 if (rem < 0) {
028330cc 266 use_kerberos = 0;
c458f00a 267 sp = getservbyname("login", "tcp");
afe1e594
KB
268 if (sp == NULL) {
269 (void)fprintf(stderr,
270 "rlogin: unknown service login/tcp.\n");
c458f00a
KF
271 exit(1);
272 }
e0817634 273 if (errno == ECONNREFUSED)
afe1e594 274 warning("remote host doesn't support Kerberos");
e0817634 275 if (errno == ENOENT)
afe1e594 276 warning("can't provide Kerberos auth data");
028330cc 277 goto try_connect;
0b6d50a1
KF
278 }
279 } else {
afe1e594 280 rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
0b6d50a1 281 }
028330cc 282#else
afe1e594 283 rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
8293b217 284#endif /* KERBEROS */
0b6d50a1 285
afe1e594 286 if (rem < 0)
0b6d50a1
KF
287 exit(1);
288
afe1e594
KB
289 if (dflag &&
290 setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
291 (void)fprintf(stderr, "rlogin: setsockopt: %s.\n",
292 strerror(errno));
66dc50f6
MK
293 one = IPTOS_LOWDELAY;
294 if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
295 perror("rlogin: setsockopt TOS (ignored)");
afe1e594
KB
296
297 (void)setuid(uid);
298 doit(omask);
86a16a64 299 /*NOTREACHED*/
5567b76f
BJ
300}
301
afe1e594
KB
302int child, defflags, deflflags, tabflag;
303char deferase, defkill;
304struct tchars deftc;
305struct ltchars defltc;
306struct tchars notc = { -1, -1, -1, -1, -1, -1 };
307struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
86a16a64 308
e113d331 309void
afe1e594
KB
310doit(omask)
311 long omask;
5567b76f 312{
9da647e3 313 struct sgttyb sb;
5567b76f 314
afe1e594 315 (void)ioctl(0, TIOCGETP, (char *)&sb);
9da647e3 316 defflags = sb.sg_flags;
c887373b 317 tabflag = defflags & TBDELAY;
c64cdfb4 318 defflags &= ECHO | CRMOD;
9da647e3
SL
319 deferase = sb.sg_erase;
320 defkill = sb.sg_kill;
e113d331
KB
321 (void)ioctl(0, TIOCLGET, &deflflags);
322 (void)ioctl(0, TIOCGETC, &deftc);
9da647e3
SL
323 notc.t_startc = deftc.t_startc;
324 notc.t_stopc = deftc.t_stopc;
e113d331 325 (void)ioctl(0, TIOCGLTC, &defltc);
afe1e594 326 (void)signal(SIGINT, SIG_IGN);
e113d331
KB
327 setsignal(SIGHUP);
328 setsignal(SIGQUIT);
86a16a64
SL
329 child = fork();
330 if (child == -1) {
afe1e594 331 (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno));
c3140eff 332 done(1);
86a16a64 333 }
86a16a64 334 if (child == 0) {
e86d8e67 335 mode(1);
afe1e594
KB
336 if (reader(omask) == 0) {
337 msg("connection closed.");
c3140eff
MK
338 exit(0);
339 }
c887373b 340 sleep(1);
afe1e594
KB
341 msg("\007connection closed.");
342 exit(1);
5567b76f 343 }
a9b12987
KM
344
345 /*
afe1e594 346 * We may still own the socket, and may have a pending SIGURG (or might
9bccbd7c
KM
347 * receive one soon) that we really want to send to the reader. When
348 * one of these comes in, the trap copytochild simply copies such
349 * signals to the child. We can now unblock SIGURG and SIGUSR1
350 * that were set above.
a9b12987 351 */
afe1e594
KB
352 (void)sigsetmask(omask);
353 (void)signal(SIGCHLD, catch_child);
86a16a64 354 writer();
afe1e594 355 msg("closed connection.");
c3140eff 356 done(0);
5567b76f
BJ
357}
358
afe1e594 359/* trap a signal, unless it is being ignored. */
e113d331
KB
360void
361setsignal(sig)
afe1e594 362 int sig;
a9b12987
KM
363{
364 int omask = sigblock(sigmask(sig));
365
e113d331 366 if (signal(sig, exit) == SIG_IGN)
afe1e594
KB
367 (void)signal(sig, SIG_IGN);
368 (void)sigsetmask(omask);
a9b12987
KM
369}
370
e113d331 371__dead void
c3140eff
MK
372done(status)
373 int status;
5567b76f 374{
cae07225 375 int w, wstatus;
5567b76f
BJ
376
377 mode(0);
a9b12987 378 if (child > 0) {
afe1e594
KB
379 /* make sure catch_child does not snap it up */
380 (void)signal(SIGCHLD, SIG_DFL);
a9b12987 381 if (kill(child, SIGKILL) >= 0)
cae07225 382 while ((w = wait(&wstatus)) > 0 && w != child);
a9b12987 383 }
c3140eff 384 exit(status);
5567b76f
BJ
385}
386
afe1e594 387int dosigwinch;
a9b12987 388
e86d8e67
KM
389/*
390 * This is called when the reader process gets the out-of-band (urgent)
391 * request to turn on the window-changing protocol.
392 */
afe1e594 393void
e113d331
KB
394writeroob(signo)
395 int signo;
e86d8e67 396{
ffc36ece 397 if (dosigwinch == 0) {
bedc18e4 398 sendwindow();
afe1e594 399 (void)signal(SIGWINCH, sigwinch);
ffc36ece 400 }
e86d8e67 401 dosigwinch = 1;
e86d8e67
KM
402}
403
afe1e594 404void
e113d331
KB
405catch_child(signo)
406 int signo;
33953861
EW
407{
408 union wait status;
409 int pid;
410
afe1e594 411 for (;;) {
47820fac 412 pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL);
afe1e594
KB
413 if (pid == 0)
414 return;
415 /* if the child (reader) dies, just quit */
e113d331 416 if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
afe1e594
KB
417 done((int)(status.w_termsig | status.w_retcode));
418 }
419 /* NOTREACHED */
33953861
EW
420}
421
5567b76f 422/*
86a16a64 423 * writer: write to remote: 0 -> line.
999d0d08
KB
424 * ~. terminate
425 * ~^Z suspend rlogin process.
426 * ~<delayed-suspend char> suspend rlogin process, but leave reader alone.
5567b76f 427 */
e113d331 428void
86a16a64 429writer()
5567b76f 430{
afe1e594 431 register int bol, local, n;
999d0d08 432 char c;
5567b76f 433
afe1e594
KB
434 bol = 1; /* beginning of line */
435 local = 0;
4d3ce186 436 for (;;) {
afe1e594 437 n = read(STDIN_FILENO, &c, 1);
119312d1
SL
438 if (n <= 0) {
439 if (n < 0 && errno == EINTR)
33953861 440 continue;
119312d1
SL
441 break;
442 }
86a16a64 443 /*
afe1e594
KB
444 * If we're at the beginning of the line and recognize a
445 * command character, then we echo locally. Otherwise,
446 * characters are echo'd remotely. If the command character
447 * is doubled, this acts as a force and local echo is
448 * suppressed.
86a16a64 449 */
4d3ce186
JB
450 if (bol) {
451 bol = 0;
999d0d08 452 if (!noescape && c == escapechar) {
4d3ce186
JB
453 local = 1;
454 continue;
86a16a64 455 }
4d3ce186
JB
456 } else if (local) {
457 local = 0;
458 if (c == '.' || c == deftc.t_eofc) {
459 echo(c);
460 break;
461 }
462 if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
463 bol = 1;
464 echo(c);
465 stop(c);
466 continue;
5567b76f 467 }
999d0d08 468 if (c != escapechar)
999d0d08 469 (void)write(rem, &escapechar, 1);
5567b76f 470 }
0b6d50a1 471
0b6d50a1 472 if (write(rem, &c, 1) == 0) {
afe1e594 473 msg("line gone");
0b6d50a1
KF
474 break;
475 }
4d3ce186 476 bol = c == defkill || c == deftc.t_eofc ||
c3140eff 477 c == deftc.t_intrc || c == defltc.t_suspc ||
4d3ce186 478 c == '\r' || c == '\n';
119312d1
SL
479 }
480}
481
e113d331
KB
482void
483#if __STDC__
484echo(register char c)
485#else
4d3ce186 486echo(c)
e113d331
KB
487 register char c;
488#endif
4d3ce186 489{
afe1e594 490 register char *p;
4d3ce186 491 char buf[8];
4d3ce186 492
afe1e594 493 p = buf;
4d3ce186 494 c &= 0177;
999d0d08 495 *p++ = escapechar;
4d3ce186
JB
496 if (c < ' ') {
497 *p++ = '^';
498 *p++ = c + '@';
499 } else if (c == 0177) {
500 *p++ = '^';
501 *p++ = '?';
502 } else
503 *p++ = c;
504 *p++ = '\r';
505 *p++ = '\n';
999d0d08 506 (void)write(STDOUT_FILENO, buf, p - buf);
4d3ce186
JB
507}
508
e113d331
KB
509void
510#if __STDC__
511stop(char cmdc)
512#else
119312d1
SL
513stop(cmdc)
514 char cmdc;
e113d331 515#endif
119312d1 516{
119312d1 517 mode(0);
afe1e594
KB
518 (void)signal(SIGCHLD, SIG_IGN);
519 (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
520 (void)signal(SIGCHLD, catch_child);
119312d1 521 mode(1);
e113d331 522 sigwinch(0); /* check for size changes */
119312d1
SL
523}
524
afe1e594 525void
e113d331
KB
526sigwinch(signo)
527 int signo;
119312d1
SL
528{
529 struct winsize ws;
530
a9b12987 531 if (dosigwinch && get_window_size(0, &ws) == 0 &&
afe1e594 532 bcmp(&ws, &winsize, sizeof(ws))) {
119312d1 533 winsize = ws;
e86d8e67 534 sendwindow();
5567b76f 535 }
5567b76f
BJ
536}
537
e86d8e67
KM
538/*
539 * Send the window size to the server via the magic escape
540 */
e113d331 541void
e86d8e67
KM
542sendwindow()
543{
afe1e594 544 struct winsize *wp;
e86d8e67 545 char obuf[4 + sizeof (struct winsize)];
e86d8e67 546
afe1e594 547 wp = (struct winsize *)(obuf+4);
e86d8e67
KM
548 obuf[0] = 0377;
549 obuf[1] = 0377;
550 obuf[2] = 's';
551 obuf[3] = 's';
552 wp->ws_row = htons(winsize.ws_row);
553 wp->ws_col = htons(winsize.ws_col);
554 wp->ws_xpixel = htons(winsize.ws_xpixel);
555 wp->ws_ypixel = htons(winsize.ws_ypixel);
0b6d50a1 556
afe1e594 557 (void)write(rem, obuf, sizeof(obuf));
e86d8e67
KM
558}
559
c3140eff
MK
560/*
561 * reader: read from remote: line -> 1
562 */
563#define READING 1
564#define WRITING 2
565
afe1e594
KB
566jmp_buf rcvtop;
567int ppid, rcvcnt, rcvstate;
568char rcvbuf[8 * 1024];
c3140eff 569
afe1e594 570void
e113d331
KB
571oob(signo)
572 int signo;
5567b76f 573{
e86d8e67 574 struct sgttyb sb;
afe1e594
KB
575 int atmark, n, out, rcvd;
576 char waste[BUFSIZ], mark;
5567b76f 577
ce27669d 578 out = O_RDWR;
afe1e594 579 rcvd = 0;
5f8f5f64 580 while (recv(rem, &mark, 1, MSG_OOB) < 0) {
c3140eff 581 switch (errno) {
c3140eff
MK
582 case EWOULDBLOCK:
583 /*
afe1e594
KB
584 * Urgent data not here yet. It may not be possible
585 * to send it yet if we are blocked for output and
586 * our input buffer is full.
c3140eff
MK
587 */
588 if (rcvcnt < sizeof(rcvbuf)) {
589 n = read(rem, rcvbuf + rcvcnt,
afe1e594 590 sizeof(rcvbuf) - rcvcnt);
c3140eff
MK
591 if (n <= 0)
592 return;
593 rcvd += n;
594 } else {
595 n = read(rem, waste, sizeof(waste));
596 if (n <= 0)
597 return;
598 }
599 continue;
c3140eff
MK
600 default:
601 return;
5f8f5f64 602 }
5567b76f 603 }
c3140eff 604 if (mark & TIOCPKT_WINDOW) {
afe1e594
KB
605 /* Let server know about window size changes */
606 (void)kill(ppid, SIGUSR1);
e86d8e67 607 }
c3140eff 608 if (!eight && (mark & TIOCPKT_NOSTOP)) {
afe1e594 609 (void)ioctl(0, TIOCGETP, (char *)&sb);
e86d8e67
KM
610 sb.sg_flags &= ~CBREAK;
611 sb.sg_flags |= RAW;
afe1e594 612 (void)ioctl(0, TIOCSETN, (char *)&sb);
9da647e3
SL
613 notc.t_stopc = -1;
614 notc.t_startc = -1;
afe1e594 615 (void)ioctl(0, TIOCSETC, (char *)&notc);
5567b76f 616 }
c3140eff 617 if (!eight && (mark & TIOCPKT_DOSTOP)) {
afe1e594 618 (void)ioctl(0, TIOCGETP, (char *)&sb);
e86d8e67
KM
619 sb.sg_flags &= ~RAW;
620 sb.sg_flags |= CBREAK;
afe1e594 621 (void)ioctl(0, TIOCSETN, (char *)&sb);
9da647e3
SL
622 notc.t_stopc = deftc.t_stopc;
623 notc.t_startc = deftc.t_startc;
afe1e594 624 (void)ioctl(0, TIOCSETC, (char *)&notc);
5567b76f 625 }
c3140eff 626 if (mark & TIOCPKT_FLUSHWRITE) {
afe1e594 627 (void)ioctl(1, TIOCFLUSH, (char *)&out);
c3140eff
MK
628 for (;;) {
629 if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
afe1e594
KB
630 (void)fprintf(stderr, "rlogin: ioctl: %s.\n",
631 strerror(errno));
c3140eff
MK
632 break;
633 }
634 if (atmark)
635 break;
636 n = read(rem, waste, sizeof (waste));
637 if (n <= 0)
638 break;
639 }
640 /*
afe1e594
KB
641 * Don't want any pending data to be output, so clear the recv
642 * buffer. If we were hanging on a write when interrupted,
643 * don't want it to restart. If we were reading, restart
644 * anyway.
c3140eff
MK
645 */
646 rcvcnt = 0;
647 longjmp(rcvtop, 1);
648 }
a9b12987 649
afe1e594 650 /* oob does not do FLUSHREAD (alas!) */
a9b12987 651
c3140eff 652 /*
afe1e594
KB
653 * If we filled the receive buffer while a read was pending, longjmp
654 * to the top to restart appropriately. Don't abort a pending write,
655 * however, or we won't know how much was written.
c3140eff
MK
656 */
657 if (rcvd && rcvstate == READING)
658 longjmp(rcvtop, 1);
5567b76f
BJ
659}
660
afe1e594 661/* reader: read from remote: line -> 1 */
e113d331 662int
afe1e594
KB
663reader(omask)
664 int omask;
5567b76f 665{
5f8f5f64
CT
666 int pid, n, remaining;
667 char *bufp;
afe1e594 668
5f8f5f64
CT
669#if BSD >= 43 || defined(SUNOS4)
670 pid = getpid(); /* modern systems use positives for pid */
545e8847 671#else
5f8f5f64 672 pid = -getpid(); /* old broken systems use negatives */
545e8847 673#endif
afe1e594
KB
674 (void)signal(SIGTTOU, SIG_IGN);
675 (void)signal(SIGURG, oob);
545e8847 676 ppid = getppid();
afe1e594
KB
677 (void)fcntl(rem, F_SETOWN, pid);
678 (void)setjmp(rcvtop);
679 (void)sigsetmask(omask);
5f8f5f64 680 bufp = rcvbuf;
5567b76f 681 for (;;) {
c3140eff
MK
682 while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
683 rcvstate = WRITING;
999d0d08 684 n = write(STDOUT_FILENO, bufp, remaining);
c3140eff
MK
685 if (n < 0) {
686 if (errno != EINTR)
e113d331 687 return (-1);
c3140eff
MK
688 continue;
689 }
690 bufp += n;
691 }
692 bufp = rcvbuf;
693 rcvcnt = 0;
694 rcvstate = READING;
0b6d50a1 695
0b6d50a1 696 rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf));
c3140eff
MK
697 if (rcvcnt == 0)
698 return (0);
699 if (rcvcnt < 0) {
86a16a64 700 if (errno == EINTR)
5567b76f 701 continue;
afe1e594
KB
702 (void)fprintf(stderr, "rlogin: read: %s.\n",
703 strerror(errno));
e113d331 704 return (-1);
5567b76f 705 }
5567b76f
BJ
706 }
707}
708
e113d331 709void
5567b76f 710mode(f)
e113d331 711 int f;
5567b76f 712{
9da647e3
SL
713 struct ltchars *ltc;
714 struct sgttyb sb;
afe1e594
KB
715 struct tchars *tc;
716 int lflags;
c64cdfb4 717
afe1e594
KB
718 (void)ioctl(0, TIOCGETP, (char *)&sb);
719 (void)ioctl(0, TIOCLGET, (char *)&lflags);
720 switch(f) {
c64cdfb4 721 case 0:
9da647e3
SL
722 sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
723 sb.sg_flags |= defflags|tabflag;
c64cdfb4 724 tc = &deftc;
9da647e3
SL
725 ltc = &defltc;
726 sb.sg_kill = defkill;
727 sb.sg_erase = deferase;
39a44641 728 lflags = deflflags;
c64cdfb4 729 break;
c64cdfb4 730 case 1:
9da647e3
SL
731 sb.sg_flags |= (eight ? RAW : CBREAK);
732 sb.sg_flags &= ~defflags;
c887373b 733 /* preserve tab delays, but turn off XTABS */
9da647e3
SL
734 if ((sb.sg_flags & TBDELAY) == XTABS)
735 sb.sg_flags &= ~TBDELAY;
c64cdfb4 736 tc = &notc;
9da647e3
SL
737 ltc = &noltc;
738 sb.sg_kill = sb.sg_erase = -1;
39a44641
JB
739 if (litout)
740 lflags |= LLITOUT;
c64cdfb4 741 break;
c64cdfb4
SL
742 default:
743 return;
5567b76f 744 }
afe1e594
KB
745 (void)ioctl(0, TIOCSLTC, (char *)ltc);
746 (void)ioctl(0, TIOCSETC, (char *)tc);
747 (void)ioctl(0, TIOCSETN, (char *)&sb);
748 (void)ioctl(0, TIOCLSET, (char *)&lflags);
749}
750
751void
e113d331
KB
752lostpeer(signo)
753 int signo;
afe1e594
KB
754{
755 (void)signal(SIGPIPE, SIG_IGN);
756 msg("\007connection closed.");
757 done(1);
5567b76f
BJ
758}
759
afe1e594
KB
760/* copy SIGURGs to the child process. */
761void
e113d331
KB
762copytochild(signo)
763 int signo;
5567b76f 764{
afe1e594
KB
765 (void)kill(child, SIGURG);
766}
a9b12987 767
e113d331 768void
afe1e594
KB
769msg(str)
770 char *str;
771{
772 (void)fprintf(stderr, "rlogin: %s\r\n", str);
5567b76f
BJ
773}
774
afe1e594
KB
775#ifdef KERBEROS
776/* VARARGS */
e113d331
KB
777void
778#if __STDC__
779warning(const char *fmt, ...)
780#else
781warning(fmt, va_alist)
782 char *fmt;
783 va_dcl
784#endif
5567b76f 785{
afe1e594 786 va_list ap;
afe1e594
KB
787
788 (void)fprintf(stderr, "rlogin: warning, using standard rlogin: ");
e113d331
KB
789#ifdef __STDC__
790 va_start(ap, fmt);
791#else
afe1e594 792 va_start(ap);
e113d331 793#endif
afe1e594
KB
794 vfprintf(stderr, fmt, ap);
795 va_end(ap);
796 (void)fprintf(stderr, ".\n");
797}
798#endif
a9b12987 799
e113d331 800__dead void
afe1e594
KB
801usage()
802{
803 (void)fprintf(stderr,
804 "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
805#ifdef KERBEROS
47820fac 806 "8EKL", " [-k realm] ");
afe1e594 807#else
999d0d08 808 "8EL", " ");
afe1e594
KB
809#endif
810 exit(1);
5567b76f 811}
028330cc 812
afe1e594 813/*
5f8f5f64 814 * The following routine provides compatibility (such as it is) between older
afe1e594
KB
815 * Suns and others. Suns have only a `ttysize', so we convert it to a winsize.
816 */
5f8f5f64 817#ifdef OLDSUN
e113d331 818int
afe1e594
KB
819get_window_size(fd, wp)
820 int fd;
821 struct winsize *wp;
028330cc 822{
afe1e594
KB
823 struct ttysize ts;
824 int error;
825
826 if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
e113d331 827 return (error);
afe1e594
KB
828 wp->ws_row = ts.ts_lines;
829 wp->ws_col = ts.ts_cols;
830 wp->ws_xpixel = 0;
831 wp->ws_ypixel = 0;
e113d331 832 return (0);
028330cc 833}
afe1e594 834#endif
999d0d08 835
e113d331 836u_int
999d0d08
KB
837getescape(p)
838 register char *p;
839{
840 long val;
841 int len;
842
843 if ((len = strlen(p)) == 1) /* use any single char, including '\' */
e113d331 844 return ((u_int)*p);
999d0d08
KB
845 /* otherwise, \nnn */
846 if (*p == '\\' && len >= 2 && len <= 4) {
e113d331 847 val = strtol(++p, NULL, 8);
999d0d08
KB
848 for (;;) {
849 if (!*++p)
e113d331 850 return ((u_int)val);
999d0d08
KB
851 if (*p < '0' || *p > '8')
852 break;
853 }
854 }
855 msg("illegal option value -- e");
856 usage();
857 /* NOTREACHED */
858}