|
|
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.50.1.1 (Berkeley) 10/21/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: #endif
133: case '?':
134: default:
135: usage();
136: break;
137: }
138: argc -= optind;
139: argv += optind;
140:
141: #ifdef KERBEROS
142: if (use_kerberos && vacuous) {
143: usage();
144: fatal(STDERR_FILENO, "only one of -k and -v allowed", 0);
145: }
146: #endif
147: fromlen = sizeof (from);
148: if (getpeername(0, &from, &fromlen) < 0) {
149: syslog(LOG_ERR,"Can't get peer name of remote host: %m");
150: fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
151: }
152: if (keepalive &&
153: setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
154: syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
155: on = IPTOS_LOWDELAY;
156: if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
157: syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
158: doit(0, &from);
159: }
160:
161: int child;
162: int cleanup();
163: int netf;
164: char line[MAXPATHLEN];
165: int confirmed;
166: extern char *inet_ntoa();
167:
168: struct winsize win = { 0, 0, 0, 0 };
169:
170:
171: doit(f, fromp)
172: int f;
173: struct sockaddr_in *fromp;
174: {
175: int i, master, pid, on = 1;
176: int authenticated = 0, hostok = 0;
177: register struct hostent *hp;
178: char remotehost[2 * MAXHOSTNAMELEN + 1];
179: struct hostent hostent;
180: char c;
181:
182: alarm(60);
183: read(f, &c, 1);
184:
185: if (c != 0)
186: exit(1);
187: #ifdef KERBEROS
188: if (vacuous)
189: fatal(f, "Remote host requires Kerberos authentication", 0);
190: #endif
191:
192: alarm(0);
193: fromp->sin_port = ntohs((u_short)fromp->sin_port);
194: hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
195: fromp->sin_family);
196: if (hp == 0) {
197: /*
198: * Only the name is used below.
199: */
200: hp = &hostent;
201: hp->h_name = inet_ntoa(fromp->sin_addr);
202: hostok++;
203: } else if (check_all || local_domain(hp->h_name)) {
204: /*
205: * If name returned by gethostbyaddr is in our domain,
206: * attempt to verify that we haven't been fooled by someone
207: * in a remote net; look up the name and check that this
208: * address corresponds to the name.
209: */
210: strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
211: remotehost[sizeof(remotehost) - 1] = 0;
212: hp = gethostbyname(remotehost);
213: if (hp)
214: for (; hp->h_addr_list[0]; hp->h_addr_list++)
215: if (!bcmp(hp->h_addr_list[0], (caddr_t)&fromp->sin_addr,
216: sizeof(fromp->sin_addr))) {
217: hostok++;
218: break;
219: }
220: } else
221: hostok++;
222:
223: #ifdef KERBEROS
224: if (use_kerberos) {
225: if (!hostok)
226: fatal(f, "rlogind: Host address mismatch.", 0);
227: retval = do_krb_login(hp->h_name, fromp, encrypt);
228: if (retval == 0)
229: authenticated++;
230: else if (retval > 0)
231: fatal(f, krb_err_txt[retval], 0);
232: write(f, &c, 1);
233: confirmed = 1; /* we sent the null! */
234: } else
235: #endif
236: {
237: if (fromp->sin_family != AF_INET ||
238: fromp->sin_port >= IPPORT_RESERVED ||
239: fromp->sin_port < IPPORT_RESERVED/2) {
240: syslog(LOG_NOTICE, "Connection from %s on illegal port",
241: inet_ntoa(fromp->sin_addr));
242: fatal(f, "Permission denied", 0);
243: }
244: #ifdef IP_OPTIONS
245: {
246: u_char optbuf[BUFSIZ/3], *cp;
247: char lbuf[BUFSIZ], *lp;
248: int optsize = sizeof(optbuf), ipproto;
249: struct protoent *ip;
250:
251: if ((ip = getprotobyname("ip")) != NULL)
252: ipproto = ip->p_proto;
253: else
254: ipproto = IPPROTO_IP;
255: if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf,
256: &optsize) == 0 && optsize != 0) {
257: lp = lbuf;
258: for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
259: sprintf(lp, " %2.2x", *cp);
260: syslog(LOG_NOTICE,
261: "Connection received using IP options (ignored):%s",
262: lbuf);
263: if (setsockopt(0, ipproto, IP_OPTIONS,
264: (char *)NULL, &optsize) != 0) {
265: syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
266: exit(1);
267: }
268: }
269: }
270: #endif
271: if (do_rlogin(hp->h_name) == 0 && hostok)
272: authenticated++;
273: }
274: if (confirmed == 0) {
275: write(f, "", 1);
276: confirmed = 1; /* we sent the null! */
277: }
278: #ifdef KERBEROS
279: if (use_kerberos == 0)
280: #endif
281: if (!authenticated && !hostok)
282: write(f, "rlogind: Host address mismatch.\r\n",
283: sizeof("rlogind: Host address mismatch.\r\n") - 1);
284:
285: netf = f;
286:
287: pid = forkpty(&master, line, NULL, &win);
288: if (pid < 0) {
289: if (errno == ENOENT)
290: fatal(f, "Out of ptys", 0);
291: else
292: fatal(f, "Forkpty", 1);
293: }
294: if (pid == 0) {
295: if (f > 2) /* f should always be 0, but... */
296: (void) close(f);
297: setup_term(0);
298: if (authenticated) {
299: #ifdef KERBEROS
300: if (use_kerberos && (pwd->pw_uid == 0))
301: syslog(LOG_INFO|LOG_AUTH,
302: "ROOT Kerberos login from %s.%s@%s on %s\n",
303: kdata->pname, kdata->pinst, kdata->prealm,
304: hp->h_name);
305: #endif
306:
307: execl(_PATH_LOGIN, "login", "-p",
308: "-h", hp->h_name, "-f", lusername, 0);
309: } else
310: execl(_PATH_LOGIN, "login", "-p",
311: "-h", hp->h_name, lusername, 0);
312: fatal(STDERR_FILENO, _PATH_LOGIN, 1);
313: /*NOTREACHED*/
314: }
315: ioctl(f, FIONBIO, &on);
316: ioctl(master, FIONBIO, &on);
317: ioctl(master, TIOCPKT, &on);
318: signal(SIGCHLD, cleanup);
319: protocol(f, master);
320: signal(SIGCHLD, SIG_IGN);
321: cleanup();
322: }
323:
324: char magic[2] = { 0377, 0377 };
325: char oobdata[] = {TIOCPKT_WINDOW};
326:
327: /*
328: * Handle a "control" request (signaled by magic being present)
329: * in the data stream. For now, we are only willing to handle
330: * window size changes.
331: */
332: control(pty, cp, n)
333: int pty;
334: char *cp;
335: int n;
336: {
337: struct winsize w;
338:
339: if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
340: return (0);
341: oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
342: bcopy(cp+4, (char *)&w, sizeof(w));
343: w.ws_row = ntohs(w.ws_row);
344: w.ws_col = ntohs(w.ws_col);
345: w.ws_xpixel = ntohs(w.ws_xpixel);
346: w.ws_ypixel = ntohs(w.ws_ypixel);
347: (void)ioctl(pty, TIOCSWINSZ, &w);
348: return (4+sizeof (w));
349: }
350:
351: /*
352: * rlogin "protocol" machine.
353: */
354: protocol(f, p)
355: register int f, p;
356: {
357: char pibuf[1024+1], fibuf[1024], *pbp, *fbp;
358: register pcc = 0, fcc = 0;
359: int cc, nfd, n;
360: char cntl;
361:
362: /*
363: * Must ignore SIGTTOU, otherwise we'll stop
364: * when we try and set slave pty's window shape
365: * (our controlling tty is the master pty).
366: */
367: (void) signal(SIGTTOU, SIG_IGN);
368: send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
369: if (f > p)
370: nfd = f + 1;
371: else
372: nfd = p + 1;
373: if (nfd > FD_SETSIZE) {
374: syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE");
375: fatal(f, "internal error (select mask too small)", 0);
376: }
377: for (;;) {
378: fd_set ibits, obits, ebits, *omask;
379:
380: FD_ZERO(&ebits);
381: FD_ZERO(&ibits);
382: FD_ZERO(&obits);
383: omask = (fd_set *)NULL;
384: if (fcc) {
385: FD_SET(p, &obits);
386: omask = &obits;
387: } else
388: FD_SET(f, &ibits);
389: if (pcc >= 0)
390: if (pcc) {
391: FD_SET(f, &obits);
392: omask = &obits;
393: } else
394: FD_SET(p, &ibits);
395: FD_SET(p, &ebits);
396: if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) {
397: if (errno == EINTR)
398: continue;
399: fatal(f, "select", 1);
400: }
401: if (n == 0) {
402: /* shouldn't happen... */
403: sleep(5);
404: continue;
405: }
406: #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
407: if (FD_ISSET(p, &ebits)) {
408: cc = read(p, &cntl, 1);
409: if (cc == 1 && pkcontrol(cntl)) {
410: cntl |= oobdata[0];
411: send(f, &cntl, 1, MSG_OOB);
412: if (cntl & TIOCPKT_FLUSHWRITE) {
413: pcc = 0;
414: FD_CLR(p, &ibits);
415: }
416: }
417: }
418: if (FD_ISSET(f, &ibits)) {
419: fcc = read(f, fibuf, sizeof(fibuf));
420: if (fcc < 0 && errno == EWOULDBLOCK)
421: fcc = 0;
422: else {
423: register char *cp;
424: int left, n;
425:
426: if (fcc <= 0)
427: break;
428: fbp = fibuf;
429:
430: top:
431: for (cp = fibuf; cp < fibuf+fcc-1; cp++)
432: if (cp[0] == magic[0] &&
433: cp[1] == magic[1]) {
434: left = fcc - (cp-fibuf);
435: n = control(p, cp, left);
436: if (n) {
437: left -= n;
438: if (left > 0)
439: bcopy(cp+n, cp, left);
440: fcc -= n;
441: goto top; /* n^2 */
442: }
443: }
444: FD_SET(p, &obits); /* try write */
445: }
446: }
447:
448: if (FD_ISSET(p, &obits) && fcc > 0) {
449: cc = write(p, fbp, fcc);
450: if (cc > 0) {
451: fcc -= cc;
452: fbp += cc;
453: }
454: }
455:
456: if (FD_ISSET(p, &ibits)) {
457: pcc = read(p, pibuf, sizeof (pibuf));
458: pbp = pibuf;
459: if (pcc < 0 && errno == EWOULDBLOCK)
460: pcc = 0;
461: else if (pcc <= 0)
462: break;
463: else if (pibuf[0] == 0) {
464: pbp++, pcc--;
465: FD_SET(f, &obits); /* try write */
466: } else {
467: if (pkcontrol(pibuf[0])) {
468: pibuf[0] |= oobdata[0];
469: send(f, &pibuf[0], 1, MSG_OOB);
470: }
471: pcc = 0;
472: }
473: }
474: if ((FD_ISSET(f, &obits)) && pcc > 0) {
475: cc = write(f, pbp, pcc);
476: if (cc < 0 && errno == EWOULDBLOCK) {
477: /*
478: * This happens when we try write after read
479: * from p, but some old kernels balk at large
480: * writes even when select returns true.
481: */
482: if (!FD_ISSET(p, &ibits))
483: sleep(5);
484: continue;
485: }
486: if (cc > 0) {
487: pcc -= cc;
488: pbp += cc;
489: }
490: }
491: }
492: }
493:
494: cleanup()
495: {
496: char *p;
497:
498: p = line + sizeof(_PATH_DEV) - 1;
499: if (logout(p))
500: logwtmp(p, "", "");
501: (void)chmod(line, 0666);
502: (void)chown(line, 0, 0);
503: *p = 'p';
504: (void)chmod(line, 0666);
505: (void)chown(line, 0, 0);
506: shutdown(netf, 2);
507: exit(1);
508: }
509:
510: fatal(f, msg, syserr)
511: int f, syserr;
512: char *msg;
513: {
514: int len;
515: char buf[BUFSIZ], *bp = buf;
516:
517: /*
518: * Prepend binary one to message if we haven't sent
519: * the magic null as confirmation.
520: */
521: if (!confirmed)
522: *bp++ = '\01'; /* error indicator */
523: if (syserr)
524: len = sprintf(bp, "rlogind: %s: %s.\r\n",
525: msg, strerror(errno));
526: else
527: len = sprintf(bp, "rlogind: %s.\r\n", msg);
528: (void) write(f, buf, bp + len - buf);
529: exit(1);
530: }
531:
532: do_rlogin(host)
533: char *host;
534: {
535: getstr(rusername, sizeof(rusername), "remuser too long");
536: getstr(lusername, sizeof(lusername), "locuser too long");
537: getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long");
538:
539: pwd = getpwnam(lusername);
540: if (pwd == NULL)
541: return(-1);
542: if (pwd->pw_uid == 0)
543: return(-1);
544: return(ruserok(host, 0, rusername, lusername));
545: }
546:
547:
548: getstr(buf, cnt, errmsg)
549: char *buf;
550: int cnt;
551: char *errmsg;
552: {
553: char c;
554:
555: do {
556: if (read(0, &c, 1) != 1)
557: exit(1);
558: if (--cnt < 0)
559: fatal(STDOUT_FILENO, errmsg, 0);
560: *buf++ = c;
561: } while (c != 0);
562: }
563:
564: extern char **environ;
565:
566: setup_term(fd)
567: int fd;
568: {
569: register char *cp = index(term+ENVSIZE, '/');
570: char *speed;
571: struct termios tt;
572:
573: #ifndef notyet
574: tcgetattr(fd, &tt);
575: if (cp) {
576: *cp++ = '\0';
577: speed = cp;
578: cp = index(speed, '/');
579: if (cp)
580: *cp++ = '\0';
581: cfsetspeed(&tt, atoi(speed));
582: }
583:
584: tt.c_iflag = TTYDEF_IFLAG;
585: tt.c_oflag = TTYDEF_OFLAG;
586: tt.c_lflag = TTYDEF_LFLAG;
587: tcsetattr(fd, TCSAFLUSH, &tt);
588: #else
589: if (cp) {
590: *cp++ = '\0';
591: speed = cp;
592: cp = index(speed, '/');
593: if (cp)
594: *cp++ = '\0';
595: tcgetattr(fd, &tt);
596: cfsetspeed(&tt, atoi(speed));
597: tcsetattr(fd, TCSAFLUSH, &tt);
598: }
599: #endif
600:
601: env[0] = term;
602: env[1] = 0;
603: environ = env;
604: }
605:
606: #ifdef KERBEROS
607: #define VERSION_SIZE 9
608:
609: /*
610: * Do the remote kerberos login to the named host with the
611: * given inet address
612: *
613: * Return 0 on valid authorization
614: * Return -1 on valid authentication, no authorization
615: * Return >0 for error conditions
616: */
617: do_krb_login(host, dest, encrypt)
618: char *host;
619: struct sockaddr_in *dest;
620: int encrypt;
621: {
622: int rc;
623: char instance[INST_SZ], version[VERSION_SIZE];
624: long authopts = 0L; /* !mutual */
625: struct sockaddr_in faddr;
626:
627: kdata = (AUTH_DAT *) auth_buf;
628: ticket = (KTEXT) tick_buf;
629:
630: instance[0] = '*';
631: instance[1] = '\0';
632:
633: rc = krb_recvauth(
634: authopts, 0,
635: ticket, "rcmd",
636: instance, dest, (struct sockaddr_in *) 0,
637: kdata, "", (bit_64 *) 0, version);
638:
639: if (rc != KSUCCESS)
640: return(rc);
641:
642: getstr(lusername, sizeof(lusername), "locuser");
643: /* get the "cmd" in the rcmd protocol */
644: getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type");
645:
646: pwd = getpwnam(lusername);
647: if (pwd == NULL)
648: return(-1);
649:
650: /* returns nonzero for no access */
651: if (kuserok(kdata,lusername) != 0)
652: return(-1);
653:
654: return(0);
655:
656: }
657: #endif /* KERBEROS */
658:
659: usage()
660: {
661: #ifdef KERBEROS
662: syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]");
663: #else
664: syslog(LOG_ERR, "usage: rlogind [-aln]");
665: #endif
666: }
667:
668: /*
669: * Check whether host h is in our local domain,
670: * defined as sharing the last two components of the domain part,
671: * or the entire domain part if the local domain has only one component.
672: * If either name is unqualified (contains no '.'),
673: * assume that the host is local, as it will be
674: * interpreted as such.
675: */
676: local_domain(h)
677: char *h;
678: {
679: char localhost[MAXHOSTNAMELEN];
680: char *p1, *p2, *topdomain();
681:
682: localhost[0] = 0;
683: (void) gethostname(localhost, sizeof(localhost));
684: p1 = topdomain(localhost);
685: p2 = topdomain(h);
686: if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
687: return(1);
688: return(0);
689: }
690:
691: char *
692: topdomain(h)
693: char *h;
694: {
695: register char *p;
696: char *maybe = NULL;
697: int dots = 0;
698:
699: for (p = h + strlen(h); p >= h; p--) {
700: if (*p == '.') {
701: if (++dots == 2)
702: return (p);
703: maybe = p;
704: }
705: }
706: return (maybe);
707: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.