|
|
1.1 root 1: /*
2: * Copyright (c) 1983, 1988, 1989 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that the above copyright notice and this paragraph are
7: * duplicated in all such forms and that any documentation,
8: * advertising materials, and other materials related to such
9: * distribution and use acknowledge that the software was developed
10: * by the University of California, Berkeley. The name of the
11: * University may not be used to endorse or promote products derived
12: * from this software without specific prior written permission.
13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16: */
17:
18: #ifndef lint
19: char copyright[] =
20: "@(#) Copyright (c) 1983, 1988, 1989 The Regents of the University of California.\n\
21: All rights reserved.\n";
22: #endif /* not lint */
23:
24: #ifndef lint
25: static char sccsid[] = "@(#)rlogind.c 5.48 (Berkeley) 6/27/90";
26: #endif /* not lint */
27:
28: #ifdef KERBEROS
29: /* From:
30: * $Source: /mit/kerberos/ucb/mit/rlogind/RCS/rlogind.c,v $
31: * $Header: rlogind.c,v 5.0 89/06/26 18:31:01 kfall Locked $
32: */
33: #endif
34:
35: /*
36: * remote login server:
37: * \0
38: * remuser\0
39: * locuser\0
40: * terminal_type/speed\0
41: * data
42: */
43:
44: #define FD_SETSIZE 16 /* don't need many bits for select */
45: #include <sys/param.h>
46: #include <sys/stat.h>
47: #include <sys/socket.h>
48: #include <sys/wait.h>
49: #include <sys/file.h>
50: #include <sys/signal.h>
51: #include <sys/ioctl.h>
52: #include <sys/termios.h>
53:
54: #include <netinet/in.h>
55: #include <netinet/in_systm.h>
56: #include <netinet/ip.h>
57:
58: #include <errno.h>
59: #include <pwd.h>
60: #include <netdb.h>
61: #include <syslog.h>
62: #include <string.h>
63: #include <stdio.h>
64: #include <unistd.h>
65: #include "pathnames.h"
66:
67: #ifndef TIOCPKT_WINDOW
68: #define TIOCPKT_WINDOW 0x80
69: #endif
70:
71: #ifdef KERBEROS
72: #include <kerberosIV/des.h>
73: #include <kerberosIV/krb.h>
74: #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n"
75:
76: AUTH_DAT *kdata;
77: KTEXT ticket;
78: u_char auth_buf[sizeof(AUTH_DAT)];
79: u_char tick_buf[sizeof(KTEXT_ST)];
80: Key_schedule schedule;
81: int encrypt = 0, retval, use_kerberos = 0, vacuous = 0;
82:
83: #define ARGSTR "alnkvx"
84: #else
85: #define ARGSTR "aln"
86: #endif /* KERBEROS */
87:
88: char *env[2];
89: #define NMAX 30
90: char lusername[NMAX+1], rusername[NMAX+1];
91: static char term[64] = "TERM=";
92: #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
93: int keepalive = 1;
94: int check_all = 0;
95:
96: extern int errno;
97: int reapchild();
98: struct passwd *getpwnam(), *pwd;
99: char *malloc();
100:
101: main(argc, argv)
102: int argc;
103: char **argv;
104: {
105: extern int opterr, optind;
106: extern int _check_rhosts_file;
107: int ch;
108: int on = 1, fromlen;
109: struct sockaddr_in from;
110:
111: openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
112:
113: opterr = 0;
114: while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
115: switch (ch) {
116: case 'a':
117: check_all = 1;
118: break;
119: case 'l':
120: _check_rhosts_file = 0;
121: break;
122: case 'n':
123: keepalive = 0;
124: break;
125: #ifdef KERBEROS
126: case 'k':
127: use_kerberos = 1;
128: break;
129: case 'v':
130: vacuous = 1;
131: break;
132: case 'x':
133: encrypt = 1;
134: break;
135: #endif
136: case '?':
137: default:
138: usage();
139: break;
140: }
141: argc -= optind;
142: argv += optind;
143:
144: #ifdef KERBEROS
145: if (use_kerberos && vacuous) {
146: usage();
147: fatal(STDERR_FILENO, "only one of -k and -v allowed", 0);
148: }
149: #endif
150: fromlen = sizeof (from);
151: if (getpeername(0, &from, &fromlen) < 0) {
152: syslog(LOG_ERR,"Can't get peer name of remote host: %m");
153: fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
154: }
155: if (keepalive &&
156: setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
157: syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
158: on = IPTOS_LOWDELAY;
159: if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
160: syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
161: doit(0, &from);
162: }
163:
164: int child;
165: int cleanup();
166: int netf;
167: char line[MAXPATHLEN];
168: int confirmed;
169: extern char *inet_ntoa();
170:
171: struct winsize win = { 0, 0, 0, 0 };
172:
173:
174: doit(f, fromp)
175: int f;
176: struct sockaddr_in *fromp;
177: {
178: int i, master, pid, on = 1;
179: int authenticated = 0, hostok = 0;
180: register struct hostent *hp;
181: char remotehost[2 * MAXHOSTNAMELEN + 1];
182: struct hostent hostent;
183: char c;
184:
185: alarm(60);
186: read(f, &c, 1);
187:
188: if (c != 0)
189: exit(1);
190: #ifdef KERBEROS
191: if (vacuous)
192: fatal(f, "Remote host requires Kerberos authentication", 0);
193: #endif
194:
195: alarm(0);
196: fromp->sin_port = ntohs((u_short)fromp->sin_port);
197: hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
198: fromp->sin_family);
199: if (hp == 0) {
200: /*
201: * Only the name is used below.
202: */
203: hp = &hostent;
204: hp->h_name = inet_ntoa(fromp->sin_addr);
205: hostok++;
206: } else if (check_all || local_domain(hp->h_name)) {
207: /*
208: * If name returned by gethostbyaddr is in our domain,
209: * attempt to verify that we haven't been fooled by someone
210: * in a remote net; look up the name and check that this
211: * address corresponds to the name.
212: */
213: strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
214: remotehost[sizeof(remotehost) - 1] = 0;
215: hp = gethostbyname(remotehost);
216: if (hp)
217: for (; hp->h_addr_list[0]; hp->h_addr_list++)
218: if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr,
219: sizeof(fromp->sin_addr))) {
220: hostok++;
221: break;
222: }
223: } else
224: hostok++;
225:
226: #ifdef KERBEROS
227: if (use_kerberos) {
228: if (!hostok)
229: fatal(f, "rlogind: Host address mismatch.", 0);
230: retval = do_krb_login(hp->h_name, fromp, encrypt);
231: if (retval == 0)
232: authenticated++;
233: else if (retval > 0)
234: fatal(f, krb_err_txt[retval], 0);
235: write(f, &c, 1);
236: confirmed = 1; /* we sent the null! */
237: } else
238: #endif
239: {
240: if (fromp->sin_family != AF_INET ||
241: fromp->sin_port >= IPPORT_RESERVED ||
242: fromp->sin_port < IPPORT_RESERVED/2) {
243: syslog(LOG_NOTICE, "Connection from %s on illegal port",
244: inet_ntoa(fromp->sin_addr));
245: fatal(f, "Permission denied", 0);
246: }
247: #ifdef IP_OPTIONS
248: {
249: u_char optbuf[BUFSIZ/3], *cp;
250: char lbuf[BUFSIZ], *lp;
251: int optsize = sizeof(optbuf), ipproto;
252: struct protoent *ip;
253:
254: if ((ip = getprotobyname("ip")) != NULL)
255: ipproto = ip->p_proto;
256: else
257: ipproto = IPPROTO_IP;
258: if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
259: &optsize) == 0 && optsize != 0) {
260: lp = lbuf;
261: for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
262: sprintf(lp, " %2.2x", *cp);
263: syslog(LOG_NOTICE,
264: "Connection received using IP options (ignored):%s",
265: lbuf);
266: if (setsockopt(0, ipproto, IP_OPTIONS,
267: (char *)NULL, &optsize) != 0) {
268: syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
269: exit(1);
270: }
271: }
272: }
273: #endif
274: if (do_rlogin(hp->h_name) == 0 && hostok)
275: authenticated++;
276: }
277: if (confirmed == 0) {
278: write(f, "", 1);
279: confirmed = 1; /* we sent the null! */
280: }
281: #ifdef KERBEROS
282: if (encrypt)
283: (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE));
284:
285: if (use_kerberos == 0)
286: #endif
287: if (!authenticated && !hostok)
288: write(f, "rlogind: Host address mismatch.\r\n",
289: sizeof("rlogind: Host address mismatch.\r\n") - 1);
290:
291: netf = f;
292:
293: pid = forkpty(&master, line, NULL, &win);
294: if (pid < 0) {
295: if (errno == ENOENT)
296: fatal(f, "Out of ptys", 0);
297: else
298: fatal(f, "Forkpty", 1);
299: }
300: if (pid == 0) {
301: if (f > 2) /* f should always be 0, but... */
302: (void) close(f);
303: setup_term(0);
304: if (authenticated) {
305: #ifdef KERBEROS
306: if (use_kerberos && (pwd->pw_uid == 0))
307: syslog(LOG_INFO|LOG_AUTH,
308: "ROOT Kerberos login from %s.%s@%s on %s\n",
309: kdata->pname, kdata->pinst, kdata->prealm,
310: hp->h_name);
311: #endif
312:
313: execl(_PATH_LOGIN, "login", "-p",
314: "-h", hp->h_name, "-f", lusername, 0);
315: } else
316: execl(_PATH_LOGIN, "login", "-p",
317: "-h", hp->h_name, lusername, 0);
318: fatal(STDERR_FILENO, _PATH_LOGIN, 1);
319: /*NOTREACHED*/
320: }
321: #ifdef KERBEROS
322: /*
323: * If encrypted, don't turn on NBIO or the des read/write
324: * routines will croak.
325: */
326:
327: if (!encrypt)
328: #endif
329: ioctl(f, FIONBIO, &on);
330: ioctl(master, FIONBIO, &on);
331: ioctl(master, TIOCPKT, &on);
332: signal(SIGCHLD, cleanup);
333: protocol(f, master);
334: signal(SIGCHLD, SIG_IGN);
335: cleanup();
336: }
337:
338: char magic[2] = { 0377, 0377 };
339: char oobdata[] = {TIOCPKT_WINDOW};
340:
341: /*
342: * Handle a "control" request (signaled by magic being present)
343: * in the data stream. For now, we are only willing to handle
344: * window size changes.
345: */
346: control(pty, cp, n)
347: int pty;
348: char *cp;
349: int n;
350: {
351: struct winsize w;
352:
353: if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
354: return (0);
355: oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
356: bcopy(cp+4, (char *)&w, sizeof(w));
357: w.ws_row = ntohs(w.ws_row);
358: w.ws_col = ntohs(w.ws_col);
359: w.ws_xpixel = ntohs(w.ws_xpixel);
360: w.ws_ypixel = ntohs(w.ws_ypixel);
361: (void)ioctl(pty, TIOCSWINSZ, &w);
362: return (4+sizeof (w));
363: }
364:
365: /*
366: * rlogin "protocol" machine.
367: */
368: protocol(f, p)
369: register int f, p;
370: {
371: char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
372: register pcc = 0, fcc = 0;
373: int cc, nfd, n;
374: char cntl;
375:
376: /*
377: * Must ignore SIGTTOU, otherwise we'll stop
378: * when we try and set slave pty's window shape
379: * (our controlling tty is the master pty).
380: */
381: (void) signal(SIGTTOU, SIG_IGN);
382: send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
383: if (f > p)
384: nfd = f + 1;
385: else
386: nfd = p + 1;
387: if (nfd > FD_SETSIZE) {
388: syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
389: fatal(f, "internal error (select mask too small)", 0);
390: }
391: for (;;) {
392: fd_set ibits, obits, ebits, *omask;
393:
394: FD_ZERO(&ebits);
395: FD_ZERO(&ibits);
396: FD_ZERO(&obits);
397: omask = (fd_set *)NULL;
398: if (fcc) {
399: FD_SET(p, &obits);
400: omask = &obits;
401: } else
402: FD_SET(f, &ibits);
403: if (pcc >= 0)
404: if (pcc) {
405: FD_SET(f, &obits);
406: omask = &obits;
407: } else
408: FD_SET(p, &ibits);
409: FD_SET(p, &ebits);
410: if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
411: if (errno == EINTR)
412: continue;
413: fatal(f, "select", 1);
414: }
415: if (n == 0) {
416: /* shouldn't happen... */
417: sleep(5);
418: continue;
419: }
420: #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
421: if (FD_ISSET(p, &ebits)) {
422: cc = read(p, &cntl, 1);
423: if (cc == 1 && pkcontrol(cntl)) {
424: cntl |= oobdata[0];
425: send(f, &cntl, 1, MSG_OOB);
426: if (cntl & TIOCPKT_FLUSHWRITE) {
427: pcc = 0;
428: FD_CLR(p, &ibits);
429: }
430: }
431: }
432: if (FD_ISSET(f, &ibits)) {
433: #ifdef KERBEROS
434: if (encrypt)
435: fcc = des_read(f, fibuf, sizeof(fibuf));
436: else
437: #endif
438: fcc = read(f, fibuf, sizeof(fibuf));
439: if (fcc < 0 && errno == EWOULDBLOCK)
440: fcc = 0;
441: else {
442: register char *cp;
443: int left, n;
444:
445: if (fcc <= 0)
446: break;
447: fbp = fibuf;
448:
449: top:
450: for (cp = fibuf; cp < fibuf+fcc-1; cp++)
451: if (cp[0] == magic[0] &&
452: cp[1] == magic[1]) {
453: left = fcc - (cp-fibuf);
454: n = control(p, cp, left);
455: if (n) {
456: left -= n;
457: if (left > 0)
458: bcopy(cp+n, cp, left);
459: fcc -= n;
460: goto top; /* n^2 */
461: }
462: }
463: FD_SET(p, &obits); /* try write */
464: }
465: }
466:
467: if (FD_ISSET(p, &obits) && fcc > 0) {
468: cc = write(p, fbp, fcc);
469: if (cc > 0) {
470: fcc -= cc;
471: fbp += cc;
472: }
473: }
474:
475: if (FD_ISSET(p, &ibits)) {
476: pcc = read(p, pibuf, sizeof (pibuf));
477: pbp = pibuf;
478: if (pcc < 0 && errno == EWOULDBLOCK)
479: pcc = 0;
480: else if (pcc <= 0)
481: break;
482: else if (pibuf[0] == 0) {
483: pbp++, pcc--;
484: #ifdef KERBEROS
485: if (!encrypt)
486: #endif
487: FD_SET(f, &obits); /* try write */
488: } else {
489: if (pkcontrol(pibuf[0])) {
490: pibuf[0] |= oobdata[0];
491: send(f, &pibuf[0], 1, MSG_OOB);
492: }
493: pcc = 0;
494: }
495: }
496: if ((FD_ISSET(f, &obits)) && pcc > 0) {
497: #ifdef KERBEROS
498: if (encrypt)
499: cc = des_write(f, pbp, pcc);
500: else
501: #endif
502: cc = write(f, pbp, pcc);
503: if (cc < 0 && errno == EWOULDBLOCK) {
504: /*
505: * This happens when we try write after read
506: * from p, but some old kernels balk at large
507: * writes even when select returns true.
508: */
509: if (!FD_ISSET(p, &ibits))
510: sleep(5);
511: continue;
512: }
513: if (cc > 0) {
514: pcc -= cc;
515: pbp += cc;
516: }
517: }
518: }
519: }
520:
521: cleanup()
522: {
523: char *p;
524:
525: p = line + sizeof(_PATH_DEV) - 1;
526: if (logout(p))
527: logwtmp(p, "", "");
528: (void)chmod(line, 0666);
529: (void)chown(line, 0, 0);
530: *p = 'p';
531: (void)chmod(line, 0666);
532: (void)chown(line, 0, 0);
533: shutdown(netf, 2);
534: exit(1);
535: }
536:
537: fatal(f, msg, syserr)
538: int f, syserr;
539: char *msg;
540: {
541: int len;
542: char buf[BUFSIZ], *bp = buf;
543:
544: /*
545: * Prepend binary one to message if we haven't sent
546: * the magic null as confirmation.
547: */
548: if (!confirmed)
549: *bp++ = '\01'; /* error indicator */
550: if (syserr)
551: len = sprintf(bp, "rlogind: %s: %s.\r\n",
552: msg, strerror(errno));
553: else
554: len = sprintf(bp, "rlogind: %s.\r\n", msg);
555: (void) write(f, buf, bp + len - buf);
556: exit(1);
557: }
558:
559: do_rlogin(host)
560: char *host;
561: {
562: getstr(rusername, sizeof(rusername), "remuser too long");
563: getstr(lusername, sizeof(lusername), "locuser too long");
564: getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
565:
566: pwd = getpwnam(lusername);
567: if (pwd == NULL)
568: return(-1);
569: if (pwd->pw_uid == 0)
570: return(-1);
571: return(ruserok(host, 0, rusername, lusername));
572: }
573:
574:
575: getstr(buf, cnt, errmsg)
576: char *buf;
577: int cnt;
578: char *errmsg;
579: {
580: char c;
581:
582: do {
583: if (read(0, &c, 1) != 1)
584: exit(1);
585: if (--cnt < 0)
586: fatal(STDOUT_FILENO, errmsg, 0);
587: *buf++ = c;
588: } while (c != 0);
589: }
590:
591: extern char **environ;
592:
593: setup_term(fd)
594: int fd;
595: {
596: register char *cp = index(term+ENVSIZE, '/');
597: char *speed;
598: struct termios tt;
599:
600: #ifndef notyet
601: tcgetattr(fd, &tt);
602: if (cp) {
603: *cp++ = '\0';
604: speed = cp;
605: cp = index(speed, '/');
606: if (cp)
607: *cp++ = '\0';
608: cfsetspeed(&tt, atoi(speed));
609: }
610:
611: tt.c_iflag = TTYDEF_IFLAG;
612: tt.c_oflag = TTYDEF_OFLAG;
613: tt.c_lflag = TTYDEF_LFLAG;
614: tcsetattr(fd, TCSAFLUSH, &tt);
615: #else
616: if (cp) {
617: *cp++ = '\0';
618: speed = cp;
619: cp = index(speed, '/');
620: if (cp)
621: *cp++ = '\0';
622: tcgetattr(fd, &tt);
623: cfsetspeed(&tt, atoi(speed));
624: tcsetattr(fd, TCSAFLUSH, &tt);
625: }
626: #endif
627:
628: env[0] = term;
629: env[1] = 0;
630: environ = env;
631: }
632:
633: #ifdef KERBEROS
634: #define VERSION_SIZE 9
635:
636: /*
637: * Do the remote kerberos login to the named host with the
638: * given inet address
639: *
640: * Return 0 on valid authorization
641: * Return -1 on valid authentication, no authorization
642: * Return >0 for error conditions
643: */
644: do_krb_login(host, dest, encrypt)
645: char *host;
646: struct sockaddr_in *dest;
647: int encrypt;
648: {
649: int rc;
650: char instance[INST_SZ], version[VERSION_SIZE];
651: long authopts = 0L; /* !mutual */
652: struct sockaddr_in faddr;
653:
654: kdata = (AUTH_DAT *) auth_buf;
655: ticket = (KTEXT) tick_buf;
656:
657: instance[0] = '*';
658: instance[1] = '\0';
659:
660: if (encrypt) {
661: rc = sizeof(faddr);
662: if (getsockname(0, &faddr, &rc))
663: return(-1);
664: authopts = KOPT_DO_MUTUAL;
665: rc = krb_recvauth(
666: authopts, 0,
667: ticket, "rcmd",
668: instance, dest, &faddr,
669: kdata, "", schedule, version);
670: des_set_key(kdata->session, schedule);
671:
672: } else {
673: rc = krb_recvauth(
674: authopts, 0,
675: ticket, "rcmd",
676: instance, dest, (struct sockaddr_in *) 0,
677: kdata, "", (bit_64 *) 0, version);
678: }
679:
680: if (rc != KSUCCESS)
681: return(rc);
682:
683: getstr(lusername, sizeof(lusername), "locuser");
684: /* get the "cmd" in the rcmd protocol */
685: getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
686:
687: pwd = getpwnam(lusername);
688: if (pwd == NULL)
689: return(-1);
690:
691: /* returns nonzero for no access */
692: if (kuserok(kdata,lusername) != 0)
693: return(-1);
694:
695: return(0);
696:
697: }
698: #endif /* KERBEROS */
699:
700: usage()
701: {
702: #ifdef KERBEROS
703: syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]");
704: #else
705: syslog(LOG_ERR, "usage: rlogind [-aln]");
706: #endif
707: }
708:
709: /*
710: * Check whether host h is in our local domain,
711: * defined as sharing the last two components of the domain part,
712: * or the entire domain part if the local domain has only one component.
713: * If either name is unqualified (contains no '.'),
714: * assume that the host is local, as it will be
715: * interpreted as such.
716: */
717: local_domain(h)
718: char *h;
719: {
720: char localhost[MAXHOSTNAMELEN];
721: char *p1, *p2, *topdomain();
722:
723: localhost[0] = 0;
724: (void) gethostname(localhost, sizeof(localhost));
725: p1 = topdomain(localhost);
726: p2 = topdomain(h);
727: if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
728: return(1);
729: return(0);
730: }
731:
732: char *
733: topdomain(h)
734: char *h;
735: {
736: register char *p;
737: char *maybe = NULL;
738: int dots = 0;
739:
740: for (p = h + strlen(h); p >= h; p--) {
741: if (*p == '.') {
742: if (++dots == 2)
743: return (p);
744: maybe = p;
745: }
746: }
747: return (maybe);
748: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.