2 * Copyright (c) 1983, 1988 The Regents of the University of California.
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.
19 #include <afsconfig.h>
20 #include <afs/param.h>
25 #include "rlogind_msg.h"
26 #define MF_LIBC "libc.cat"
28 #define MSGSTR(n,s) NLgetamsg(MF_RLOGIND, MS_RLOGIND, n, s)
35 * remote login server:
39 * terminal_type/speed\0
42 * Automatic login protocol is done here, using login -f upon success,
43 * unless OLD_LOGIN is defined (then done in login, ala 4.2/4.3BSD).
46 #include <afs/param.h>
49 #include <sys/ioctl.h>
53 #include <sys/param.h>
55 #include <sys/socket.h>
62 #include <netinet/in.h>
71 #include <sys/ioctl.h>
76 #include <sys/access.h>
83 #include <sys/lockf.h>
90 #include <sys/param.h>
92 #include <sys/socket.h>
95 #include <sys/signal.h>
96 #include <sys/ioctl.h>
97 #include <netinet/in.h>
98 #include <netinet/in_systm.h>
99 #include <netinet/ip.h>
101 #include <sys/termios.h>
102 #define _PATH_LOGIN "/usr/bin/login"
105 #if defined(AFS_HPUX_ENV)
107 #include <sys/ptyio.h>
108 #endif /* defined(AFS_HPUX_ENV) */
111 #define DEF_UTMP "Active tty entry not found in utmp file.\n"
113 #define NOLOGIN "/etc/nologin"
114 #define BSHELL "/bin/sh"
120 #include <afs/auth.h>
121 #include <afs/cellconfig.h>
125 #define UT_NAMESIZE sizeof(utmp.ut_user)
126 #define UTSIZ (sizeof (struct utmp))
128 static void loginlog();
131 #ifndef TIOCPKT_WINDOW
132 #define TIOCPKT_WINDOW 0x80
137 char lusername[NMAX + 1], rusername[NMAX + 1];
138 static char term[64] = "TERM=";
139 #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */
146 #define SUPERUSER(pwd) ((pwd)->pw_uid == 0)
150 struct passwd *getpwnam(), *pwd;
153 struct s_passwd *s_pwd, *getspwnam();
156 #if defined(AFS_AIX32_ENV) && (defined(NLS) || defined(KJI))
161 #include "AFS_component_version_number.c"
167 extern int opterr, optind, _check_rhosts_file;
170 struct sockaddr_in from;
173 void trace_handler(int);
175 #if defined(NLS) || defined(KJI)
176 setlocale(LC_ALL, "");
179 openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
185 while ((ch = getopt(argc, argv, "ln")) != EOF)
193 _check_rhosts_file = 0;
212 syslog(LOG_ERR, "usage: rlogind [-v] [-l] [-n] [-s]");
214 syslog(LOG_ERR, "usage: rlogind [-l] [-n] [-s]");
218 syslog(LOG_ERR, "usage: rlogind [-l] [-n] [-a] [-s]");
220 syslog(LOG_ERR, "usage: rlogind [-l] [-n]");
228 fromlen = sizeof(from);
229 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
230 syslog(LOG_ERR, "Couldn't get peer name of remote host: %m");
231 fatalperror("Can't get peer name of host");
234 && setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
236 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
239 && setsockopt(0, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on)) < 0)
240 syslog(LOG_WARNING, MSGSTR(SETDEBUG, "setsockopt (SO_DEBUG): %m"));
242 /* set-up signal handler routines for SRC TRACE ON/OFF support */
243 memset((char *)&sa, 0, sizeof(sa));
244 sa.sa_mask.losigs = sigmask(SIGUSR2);
245 sa.sa_handler = trace_handler;
246 sa.sa_flags = SA_RESTART;
247 sigaction(SIGUSR1, &sa, NULL);
248 sa.sa_mask.losigs = sigmask(SIGUSR1);
249 sa.sa_handler = trace_handler;
250 sa.sa_flags = SA_RESTART;
251 sigaction(SIGUSR2, &sa, NULL);
255 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
256 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
263 * trace_handler - SRC TRACE ON/OFF signal handler
266 trace_handler(int sig)
270 onoff = (sig == SIGUSR1) ? 1 : 0;
271 if (setsockopt(0, SOL_SOCKET, SO_DEBUG, &onoff, sizeof(onoff)) < 0)
272 syslog(LOG_WARNING, MSGSTR(SETDEBUG, "setsockopt (SO_DEBUG): %m"));
280 char line[MAXPATHLEN];
285 char tbuf[MAXPATHLEN + 2];
287 struct hostent hostent;
290 extern char *inet_ntoa();
293 char master[MAXPATHLEN], slave[MAXPATHLEN], tname[MAXPATHLEN];
296 #if defined(TIOCSWINSZ) || defined(AFS_OSF_ENV)
297 struct winsize win = { 0, 0, 0, 0 };
298 #else /* ~TIOCWINSIZ */
300 * Window/terminal size structure.
301 * This information is stored by the kernel
302 * in order to provide a consistent interface,
303 * but is not used by the kernel.
305 * Type must be "unsigned short" so that types.h not required.
308 unsigned short ws_row; /* rows, in characters */
309 unsigned short ws_col; /* columns, in characters */
310 unsigned short ws_xpixel; /* horizontal size, pixels */
311 unsigned short ws_ypixel; /* vertical size, pixels */
313 #endif /* ~TIOCWINSIZ */
317 struct sockaddr_in *fromp;
319 int i, p, t, pid, on = 1;
330 int authenticated = 0, hostok = 0;
331 char remotehost[2 * MAXHOSTNAMELEN + 1];
334 register struct hostent *hp;
335 struct hostent hostent;
339 #if defined(AFS_HPUX_ENV)
341 #endif /* defined(AFS_HPUX_ENV) */
349 fromp->sin_port = ntohs((u_short) fromp->sin_port);
350 hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr),
354 * Only the name is used below.
357 hp->h_name = inet_ntoa(fromp->sin_addr);
364 else if (errno != ECONNREFUSED) {
367 else if (check_all || local_domain(hp->h_name)) {
369 else if (local_domain(hp->h_name)) {
373 * If name returned by gethostbyaddr is in our domain,
374 * attempt to verify that we haven't been fooled by someone
375 * in a remote net; look up the name and check that this
376 * address corresponds to the name.
378 strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
379 remotehost[sizeof(remotehost) - 1] = 0;
380 hp = gethostbyname(remotehost);
384 (hp->h_addr, (caddr_t) & fromp->sin_addr,
385 sizeof(fromp->sin_addr))) {
387 for (; hp->h_addr_list[0]; hp->h_addr_list++)
389 (hp->h_addr_list[0], (caddr_t) & fromp->sin_addr,
390 sizeof(fromp->sin_addr))) {
401 if (fromp->sin_family != AF_INET || fromp->sin_port >= IPPORT_RESERVED
402 || fromp->sin_port < IPPORT_RESERVED / 2) {
403 syslog(LOG_NOTICE, "Connection from %s on illegal port",
404 inet_ntoa(fromp->sin_addr));
405 fatal(f, "Permission denied");
409 u_char optbuf[BUFSIZ / 3], *cp;
410 char lbuf[BUFSIZ], *lp;
411 int optsize = sizeof(optbuf), ipproto;
414 if ((ip = getprotobyname("ip")) != NULL)
415 ipproto = ip->p_proto;
417 ipproto = IPPROTO_IP;
418 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) == 0
421 for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
422 sprintf(lp, " %2.2x", *cp);
424 "Connection received using IP options (ignored):%s", lbuf);
425 if (setsockopt(0, ipproto, IP_OPTIONS, (char *)NULL, optsize) !=
427 syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
435 if (do_rlogin(hp->h_name) == 0) {
439 write(f, "rlogind: Host address mismatch.\r\n",
440 sizeof("rlogind: Host address mismatch.\r\n") - 1);
446 fprintf(stderr, "%s: invalid remote authentication\n", "login");
455 pid = forkpty(&master, line, NULL, &win);
458 fatal(f, "Out of ptys", 0);
460 fatal(f, "Forkpty", 1);
463 if (f > 2) /* f should always be 0, but... */
467 execl(_PATH_LOGIN, "login", "-p", "-h", hp->h_name, "-f",
470 char *sp = lusername;
473 if (!strncmp(sp, "-f", 2)) {
474 syslog(LOG_ERR, "Can't use '-f' in username");
477 execl(_PATH_LOGIN, "login", "-p", "-h", hp->h_name, lusername,
480 fatalperror(2, _PATH_LOGIN);
482 ioctl(f, FIONBIO, &on);
483 ioctl(master, FIONBIO, &on);
484 ioctl(master, TIOCPKT, &on);
485 signal(SIGCHLD, cleanup);
487 signal(SIGCHLD, SIG_IGN);
490 #if defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV) && defined(notdef)
492 * Find an unused pty. A security hole exists if we
493 * allow any other process to hold the slave side of the
494 * pty open while we are setting up. The other process
495 * could read from the slave side at the time that in.rlogind
496 * is forwarding the "rlogin authentication" string from the
497 * rlogin client through the pty to the login program. If the
498 * other process grabs this string, the user at the rlogin
499 * client program can forge an authentication string.
500 * This problem would not exist if the pty subsystem
501 * would fail the open of the master side when there are
502 * existing open instances of the slave side.
503 * Until the pty driver is changed to work this way, we use
504 * a side effect of one particular ioctl to test whether
505 * any process has the slave open.
508 for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
512 /* make sure this "bank" of ptys exists */
514 line[strlen("/dev/pty")] = *cp;
515 line[strlen("/dev/ptyp")] = '0';
516 if (stat(line, &stb) < 0)
518 for (i = 0; i < 16; i++) {
519 line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
520 line[strlen("/dev/")] = 'p';
523 * Test to see if this pty is unused. The open
524 * on the master side of the pty will fail if
525 * any other process has it open.
527 if ((p = open(line, O_RDWR | O_NOCTTY)) == -1)
531 * Lock the slave side so that no one else can
532 * open it after this.
534 line[strlen("/dev/")] = 't';
535 if (chmod(line, 0600) == -1) {
541 * XXX - Use a side effect of TIOCGPGRP on ptys
542 * to test whether any process is holding the
543 * slave side open. May not work as we expect
544 * in anything other than SunOS 4.1.
546 if ((ioctl(p, TIOCGPGRP, &pgrp) == -1) && (errno == EIO))
549 (void)chmod(line, 0666);
554 fatal(f, "Out of ptys");
555 /*NOTREACHED*/ gotpty:
556 (void)ioctl(p, TIOCSWINSZ, &win);
558 line[strlen("/dev/")] = 't';
559 t = open(line, O_RDWR | O_NOCTTY);
561 fatalperror(f, line);
563 /* These should be converted to termios ioctls. */
567 if (gtty(t, &b) == -1)
569 b.sg_flags = RAW | ANYP;
570 /* XXX - ispeed and ospeed must be non-zero */
571 b.sg_ispeed = B38400;
572 b.sg_ospeed = B38400;
573 if (stty(t, &b) == -1)
576 * Turn off PASS8 mode, since "login" no longer does so.
578 if (ioctl(t, TIOCLSET, &zero) == -1)
579 perror("ioctl TIOCLSET");
584 if ((p = open("/dev/ptc", O_RDWR)) >= 0) {
587 fatal(f, MSGSTR(NOPTY, "Out of ptys"));
592 if (getpty(&p, master, slave) != 0)
593 fatal(f, "Unable to allocate pty on remote host");
594 /* Global copies for use by SIGCHLD handler */
598 /* Slave becomes controlling terminal for this session. */
599 t_ = open(slave, O_RDWR);
601 fatalperror(f, slave);
602 /* Remove any reference to the current control terminal */
604 fatalperror(f, "rlogind: vhangup()");
605 /* reopen the slave pseudo-terminal */
606 t = open(slave, O_RDWR);
608 fatalperror(f, slave);
610 /* Get the line name for utmp accounting. */
615 strcpy(tname, slave);
617 (void)ioctl(p, TIOCSWINSZ, &win);
618 #endif /* TIOCSWINSZ */
621 #endif /* ~OLD_LOGIN */
623 /* Lock the pty so that the parent can then synchronize setting up
624 * the child's process group and controlling terminal with the
625 * login process. The login process won't be able to read from
626 * the pty until the parent unlocks it.
630 for (c = 'p'; c <= 'z'; c++) {
633 line[strlen("/dev/pty")] = c;
634 line[strlen("/dev/ptyp")] = '0';
635 if (stat(line, &stb) < 0)
637 for (i = 0; i < 16; i++) {
638 line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
639 p = open(line, O_RDWR);
644 fatal(f, "Out of ptys");
645 /*NOTREACHED*/ gotpty:
654 pline[strlen("/dev/")] = 't';
659 if ((p = open(line, O_RDWR)) < 0)
660 fatal(f, "Bad open");
668 (void)ioctl(p, TIOCSWINSZ, &win);
671 (void)ioctl(p, TXSETWINSZ, &win);
672 #endif /* TXSETWINSZ */
673 #endif /* TIOCSWINSZ */
676 (void)ioctl(p, TIOCSWINSZ, &win);
680 line[strlen("/dev/")] = 't';
681 t = open(line, O_RDWR);
683 fatalperror(f, line);
686 fatalperror(f, line);
687 (void)signal(SIGHUP, SIG_IGN);
688 #if ! defined(AFS_HPUX_ENV) && ! defined(AFS_OSF_ENV)
690 #endif /* !defined(AFS_HPUX_ENV) */
691 (void)signal(SIGHUP, SIG_DFL);
693 t = open(line, O_RDWR);
695 fatalperror(f, line);
698 #endif /* !AFS_SUN_ENV && !AFS_SUN5_ENV */
701 int tt = open("/dev/tty", O_RDWR);
703 (void)ioctl(tt, TIOCNOTTY, 0);
708 #endif /* !AFS_HPUX_ENV */
714 #if defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV) && defined(notdef)
717 /* The child process needs to be the session leader
718 * and have the pty as its controlling tty
721 tt = open(line, O_RDWR);
723 fatalperror(f, line);
724 close(f), close(p), close(t);
735 dup2(t, 0), dup2(t, 1), dup2(t, 2);
741 t = open(line, O_RDWR);
743 fatalperror(f, line);
744 if (acl_fset(t, NO_ACC, NO_ACC, NO_ACC))
745 fatalperror(f, line);
746 (void)signal(SIGHUP, SIG_IGN);
751 memset((char *)&sa, 0, sizeof(sa));
752 sa.sa_handler = SIG_DFL;
753 sigaction(SIGQUIT, &sa, NULL);
754 sa.sa_handler = SIG_DFL;
755 sigaction(SIGHUP, &sa, NULL);
758 t = open(line, O_RDWR);
760 fatalperror(f, line);
765 (void)ioctl(t, TIOCSCTTY, 0);
766 #endif /* AFS_OSF_ENV */
768 /* Wait for the parent to setup our process group and controlling tty. */
770 lockf(p, F_ULOCK, 0);
773 dup2(t, 0), dup2(t, 1), dup2(t, 2);
775 #endif /* AFS_SUN_ENV */
778 * Reset SIGUSR1 and SIGUSR2 to non-restartable so children
779 * of rlogind do not get clobbered by the way rlogind handles
785 memset((char *)&sa, 0, sizeof(sa));
786 sa.sa_mask.losigs = sigmask(SIGUSR2);
787 sa.sa_handler = trace_handler;
788 sigaction(SIGUSR1, &sa, NULL);
789 sa.sa_mask.losigs = sigmask(SIGUSR1);
790 sa.sa_handler = trace_handler;
791 sigaction(SIGUSR2, &sa, NULL);
794 (void)loginlog(lusername, line, hp->h_name);
797 execl("/bin/login", "login", "-r", hp->h_name, 0);
798 #else /* OLD_LOGIN */
801 execl("/bin/login.afs", "login", /*"-v", */ "-p", "-h",
802 hp->h_name, "-f", "--", lusername, 0);
804 execl("/bin/login", "login", "-p", "-h", hp->h_name, "-f",
808 char *sp = lusername;
811 if (!strncmp(sp, "-f", 2)) {
812 syslog(LOG_ERR, "Can't use '-f' in username");
816 execl("/bin/login.afs", "login", /*"-v", */ "-p", "-h",
817 hp->h_name, "--", lusername, 0);
819 execl("/bin/login", "login", "-p", "-h", hp->h_name, lusername,
823 #endif /* OLD_LOGIN */
824 fatalperror(2, "/bin/login");
827 /* Set the child up as a process group leader.
828 * It must not be part of the parent's process group,
829 * because signals issued in the child's process group
830 * must not affect the parent.
834 /* Make the pty slave the controlling terminal for the child's process group. */
836 /* Close our controlling terminal. */
839 /* Let the child know that it is a process group leader and has a controlling tty. */
840 lockf(p, F_ULOCK, 0);
841 ioctl(f, FIONBIO, &on);
842 ioctl(p, FIONBIO, &on);
843 ioctl(p, TIOCPKT, &on);
844 signal(SIGTSTP, SIG_IGN);
845 signal(SIGCHLD, cleanup);
846 #ifdef AFS_HPUX102_ENV
847 signal(SIGTERM, cleanup);
848 signal(SIGPIPE, cleanup);
850 signal(SIGTERM, cleanup,
851 sigmask(SIGCLD) | sigmask(SIGTERM) | sigmask(SIGPIPE));
852 signal(SIGPIPE, cleanup,
853 sigmask(SIGCLD) | sigmask(SIGTERM) | sigmask(SIGPIPE));
857 signal(SIGCHLD, SIG_IGN);
858 signal(SIGTERM, SIG_IGN);
859 signal(SIGPIPE, SIG_IGN);
867 ioctl(f, FIONBIO, &on);
869 #if !defined(AFS_HPUX_ENV)
870 ioctl(p, FIONBIO, &on);
871 #else /* !defined(AFS_HPUX_ENV) */
872 /* HPUX does not support FIONBIO on ptys, so, we do it the hard way */
873 ptyStatusFlags = fcntl(p, F_GETFL, 0);
874 fcntl(p, F_SETFL, ptyStatusFlags | O_NDELAY);
875 #endif /* !defined(AFS_HPUX_ENV) */
877 #if !defined(AFS_SUN5_ENV)
878 ioctl(p, TIOCPKT, &on);
879 signal(SIGTSTP, SIG_IGN);
880 #if defined(AFS_HPUX_ENV)
881 signal(SIGINT, SIG_IGN);
882 signal(SIGQUIT, SIG_IGN);
883 #endif /* defined(AFS_HPUX_ENV) */
884 #endif /* !defined(AFS_SUN5_ENV) */
885 signal(SIGCHLD, cleanup);
887 #ifdef AFS_HPUX102_ENV
895 (void)signal(SIGCHLD, SIG_IGN);
899 signal(SIGCHLD, SIG_IGN);
902 #endif /* AFS_OSF_ENV */
905 char magic[2] = { 0377, 0377 };
906 char oobdata[] = { TIOCPKT_WINDOW };
909 * Handle a "control" request (signaled by magic being present)
910 * in the data stream. For now, we are only willing to handle
911 * window size changes.
920 if (n < 4 + sizeof(w) || cp[2] != 's' || cp[3] != 's')
922 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */
923 memcpy((char *)&w, cp + 4, sizeof(w));
924 w.ws_row = ntohs(w.ws_row);
925 w.ws_col = ntohs(w.ws_col);
926 w.ws_xpixel = ntohs(w.ws_xpixel);
927 w.ws_ypixel = ntohs(w.ws_ypixel);
930 (void)ioctl(pty, TIOCSWINSZ, &w);
932 (void)ioctl(pty, TXSETWINSZ, &w);
936 (void)ioctl(pty, TIOCSWINSZ, &w);
939 return (4 + sizeof(w));
943 * rlogin "protocol" machine.
954 char pibuf[1024], fibuf[1024], *pbp, *fbp;
955 register pcc = 0, fcc = 0;
956 int cc, nfd, pmask, fmask;
960 * Must ignore SIGTTOU, otherwise we'll stop
961 * when we try and set slave pty's window shape
962 * (our controlling tty is the master pty).
964 (void)signal(SIGTTOU, SIG_IGN);
966 /* delay TIOCPKT_WINDOW oobdata, for backward compatibility */
969 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */
977 int ibits, obits, ebits;
992 if (select(nfd, &ibits, obits ? &obits : (int *)NULL, &ebits, 0) < 0) {
998 fatalperror(f, "select");
1000 if (ibits == 0 && obits == 0 && ebits == 0) {
1001 /* shouldn't happen... */
1005 #if !defined(AFS_SUN5_ENV)
1006 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
1007 if (ebits & pmask) {
1008 cc = read(p, &cntl, 1);
1009 if (cc == 1 && pkcontrol(cntl)) {
1011 send(f, &cntl, 1, MSG_OOB);
1012 if (cntl & TIOCPKT_FLUSHWRITE) {
1018 #endif /* !defined(AFS_SUN5_ENV) */
1020 if (ibits & fmask) {
1021 fcc = read(f, fibuf, sizeof(fibuf));
1022 if (fcc < 0 && errno == EWOULDBLOCK)
1033 for (cp = fibuf; cp < fibuf + fcc - 1; cp++)
1034 if (cp[0] == magic[0] && cp[1] == magic[1]) {
1035 left = fcc - (cp - fibuf);
1036 n = control(p, cp, left);
1040 memcpy(cp, cp + n, left);
1045 obits |= pmask; /* try write */
1049 if ((obits & pmask) && fcc > 0) {
1050 cc = write(p, fbp, fcc);
1057 if (ibits & pmask) {
1058 pcc = read(p, pibuf, sizeof(pibuf));
1060 if (pcc < 0 && errno == EWOULDBLOCK)
1064 else if (pibuf[0] == 0) {
1066 obits |= fmask; /* try a write */
1068 #if !defined(AFS_SUN5_ENV)
1069 if (pkcontrol(pibuf[0])) {
1070 pibuf[0] |= oobdata[0];
1071 send(f, &pibuf[0], 1, MSG_OOB);
1073 #endif /* !defined(AFS_SUN5_ENV) */
1078 if ((obits & fmask) && pcc > 0) {
1079 cc = write(f, pbp, pcc);
1080 if (cc < 0 && errno == EWOULDBLOCK) {
1081 /* also shouldn't happen */
1093 #ifdef AFS_AIX32_ENV
1106 fcntl(netp, F_SETFL, O_NDELAY);
1107 if ((cc = read(netp, buf, sizeof buf)) > 0) {
1108 write(netf, buf, cc);
1111 chmod(master, 0666);
1112 chown(master, 0, 0);
1117 #ifdef AFS_AIX32_ENV
1119 int found = 0, f, t;
1123 p = line + sizeof("/dev/") - 1;
1127 (void)acl_set(line, R_ACC | W_ACC | X_ACC, R_ACC | W_ACC | X_ACC,
1128 R_ACC | W_ACC | X_ACC);
1130 (void)chmod(line, 0666);
1132 (void)chown(line, 0, 0);
1135 (void)acl_set(line, R_ACC | W_ACC | X_ACC, R_ACC | W_ACC | X_ACC,
1136 R_ACC | W_ACC | X_ACC);
1138 (void)chmod(line, 0666);
1141 p = line + sizeof("/dev/") - 1;
1144 (void)chmod(line, 0666);
1145 (void)chown(line, 0, 0);
1147 (void)chmod(line, 0666);
1149 (void)chown(line, 0, 0);
1161 buf[0] = '\01'; /* error indicator */
1162 (void)sprintf(buf + 1, "rlogind: %s.\r\n", msg);
1163 (void)write(f, buf, strlen(buf));
1173 extern int sys_nerr;
1174 extern char *sys_errlist[];
1176 if ((unsigned)errno < sys_nerr)
1177 (void)sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
1179 (void)sprintf(buf, "%s: Error %d", msg, errno);
1190 getstr(rusername, sizeof(rusername), "remuser too long");
1191 getstr(lusername, sizeof(lusername), "locuser too long");
1192 getstr(term + ENVSIZE, sizeof(term) - ENVSIZE, "Terminal type too long");
1196 pwd = getpwnam(lusername);
1200 #define SUPERUSER(pwd) ((pwd)->pw_uid == 0)
1201 #define SECUREPASS "/.secure/etc/passwd"
1202 /* If /.secure/etc/passwd file exists then make sure that user has
1203 * a valid entry in both password files.
1204 * Initialize s_pwd to point to pwd so check won't fail if the
1205 * secure password file doesn't exists.
1207 s_pwd = (struct s_passwd *)pwd;
1208 if (stat(SECUREPASS, &s_pfile) == 0)
1209 s_pwd = getspwnam(lusername);
1210 if (s_pwd == NULL) {
1216 if (*pwd->pw_shell == '\0')
1217 pwd->pw_shell = BSHELL;
1218 /* check for disabled logins before */
1219 /* authenticating based on .rhosts */
1221 if (checknologin() == 0)
1224 ru = ruserok(host, SUPERUSER(pwd), rusername, lusername);
1229 getstr(buf, cnt, errmsg)
1237 if (read(0, &c, 1) != 1)
1245 extern char **environ;
1253 if (strcmp(speed, "38400") == 0)
1255 if (strcmp(speed, "19200") == 0)
1257 if (strcmp(speed, "9600") == 0)
1259 if (strcmp(speed, "4800") == 0)
1261 if (strcmp(speed, "2400") == 0)
1263 if (strcmp(speed, "1800") == 0)
1265 if (strcmp(speed, "1200") == 0)
1267 if (strcmp(speed, "600") == 0)
1269 if (strcmp(speed, "300") == 0)
1271 if (strcmp(speed, "200") == 0)
1273 if (strcmp(speed, "150") == 0)
1275 if (strcmp(speed, "134") == 0)
1277 if (strcmp(speed, "110") == 0)
1279 if (strcmp(speed, "75") == 0)
1281 if (strcmp(speed, "50") == 0)
1283 if (strcmp(speed, "0") == 0)
1289 "0", "50", "75", "110", "134", "150", "200", "300", "600",
1290 "1200", "1800", "2400", "4800", "9600", "19200", "38400",
1296 #define NSPEEDS (sizeof(speeds) / sizeof(speeds[0]))
1303 register char *cp = strchr(term, '/'), **cpp;
1305 #ifdef AFS_AIX32_ENV
1308 struct termios termios;
1310 struct sgttyb sgttyb;
1319 tcgetattr(fd, &termios);
1322 ioctl(fd, TCGETA, &tp);
1324 (void)ioctl(fd, TIOCGETP, &sgttyb);
1330 cp = strchr(speed, '/');
1335 /* Setup PTY with some reasonable defaults */
1336 termios.c_cc[VINTR] = CINTR;
1337 termios.c_cc[VQUIT] = CQUIT;
1338 termios.c_cc[VERASE] = CERASE;
1339 termios.c_cc[VKILL] = CKILL;
1340 termios.c_cc[VEOF] = CEOF;
1341 #if defined (NLS) || defined (KJI)
1342 /* For NLS environments, we need 8 bit data stream. */
1343 termios.c_iflag = IXON | BRKINT | IGNPAR | ICRNL;
1344 termios.c_cflag = PARENB | CS8 | HUPCL | CREAD;
1346 termios.c_iflag = IXON | BRKINT | IGNPAR | ISTRIP | ICRNL;
1347 termios.c_cflag = PARENB | CS7 | HUPCL | CREAD;
1349 termios.c_oflag = OPOST | ONLCR | TAB3;
1351 ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOKE | ECHOCTL | IEXTEN;
1352 cfsetispeed(&termios, speeds(speed));
1353 cfsetospeed(&termios, speeds(speed));
1355 for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
1356 if (strcmp(*cpp, speed) == 0) {
1358 tp.c_cflag &= ~CBAUD;
1359 tp.c_cflag |= cpp - speeds;
1361 sgttyb.sg_ispeed = sgttyb.sg_ospeed = cpp - speeds;
1369 tcsetattr(fd, TCSANOW, &termios);
1372 tp.c_iflag &= ~INPCK;
1373 tp.c_iflag |= ICRNL | IXON;
1374 tp.c_oflag |= OPOST | ONLCR | TAB3;
1375 tp.c_oflag &= ~ONLRET;
1376 tp.c_lflag |= (ECHO | ECHOE | ECHOK | ISIG | ICANON);
1377 tp.c_cflag &= ~PARENB;
1381 tp.c_cc[VEOF] = CEOF;
1382 ioctl(fd, TCSETAF, &tp);
1384 sgttyb.sg_flags = ECHO | CRMOD | ANYP | XTABS;
1385 (void)ioctl(fd, TIOCSETP, &sgttyb);
1389 #else /* AFS_AIX32_ENV */
1392 register char *cp = strchr(term + ENVSIZE, '/');
1400 cp = strchr(speed, '/');
1403 cfsetspeed(&tt, atoi(speed));
1406 tt.c_iflag = TTYDEF_IFLAG;
1407 tt.c_oflag = TTYDEF_OFLAG;
1408 tt.c_lflag = TTYDEF_LFLAG;
1409 memcpy(tt.c_cc, ttydefchars, sizeof(tt.c_cc));
1410 tcsetattr(fd, TCSAFLUSH, &tt);
1412 struct sgttyb sgttyb;
1415 (void)ioctl(fd, TIOCGETP, &sgttyb);
1419 cp = strchr(speed, '/');
1422 for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
1423 if (strcmp(*cpp, speed) == 0) {
1424 sgttyb.sg_ispeed = sgttyb.sg_ospeed = cpp - speeds;
1428 sgttyb.sg_flags = ECHO | CRMOD | ANYP | XTABS;
1429 (void)ioctl(fd, TIOCSETP, &sgttyb);
1431 #endif /* AFS_AIX32_ENV */
1438 * Check whether host h is in our local domain,
1439 * as determined by the part of the name following
1440 * the first '.' in its name and in ours.
1441 * If either name is unqualified (contains no '.'),
1442 * assume that the host is local, as it will be
1443 * interpreted as such.
1448 char localhost[MAXHOSTNAMELEN];
1449 char *p1, *p2 = strchr(h, '.');
1456 (void)gethostname(localhost, sizeof(localhost));
1458 p1 = topdomain(localhost);
1461 p1 = strchr(localhost, '.');
1463 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
1467 #endif /* OLD_LOGIN */
1479 for (p = h + strlen(h); p >= h; p--) {
1493 * NAME: getnonflatname()
1495 * FUNCTION: gets the name in /etc/passwd and replaces the
1496 * flattened name that might have been passed in.
1498 * EXECUTION ENVIRONMENT: static
1505 getnonflatname(char *user)
1507 struct passwd *pw; /* return from getpwent() */
1508 char currflat[UT_NAMESIZE + 1]; /* name we are looking for */
1509 char dataflat[UT_NAMESIZE + 1]; /* name from data base */
1511 register int members = 0;
1516 while ((pw = getpwent()) != NULL) {
1517 /* Map NLS characters in name to ascii */
1518 NLflatstr(user, currflat, UT_NAMESIZE + 1);
1519 NLflatstr(pw->pw_name, dataflat, UT_NAMESIZE + 1);
1520 if (strcmp(currflat, dataflat) == 0) {
1521 strcpy(user, pw->pw_name);
1534 if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) {
1545 * FUNCTION: log the login
1547 * EXECUTION ENVIRONMENT: static
1549 * record login in utmp and wtmp files
1555 loginlog(user, tty, hostname)
1560 char *home; /* user's home directory */
1561 char *dev; /* final portion of tty name [ with hft# ] */
1562 char hush[PATH_MAX]; /* .hushlogin file */
1563 int t; /* index into the utmp file */
1564 int found = 0; /* utmp entry was found */
1565 int f; /* file descriptor */
1566 uid_t uid; /* the user ID */
1567 off_t offset; /* for keeping wtmp file un-corrupted */
1568 struct utmp utmp; /* utmp structure being created */
1569 struct utmp outmp; /* utmp entry from /etc/utmp file */
1570 struct utmp *up; /* pointer to entry in utmp file */
1575 * Initialize a utmp file entry to be filled in and written
1576 * to UTMP_FILE and WTMP_FILE.
1579 memset(&utmp, 0, UTSIZ);
1583 * The last portion of the device name is placed in the utmp
1584 * entry. If the last portion is all digits it is assumed to
1585 * be a multiplexed device, such as an hft, and the pointer
1586 * is backed up to find the previous portion.
1589 if (dev = strrchr(tty, '/')) {
1590 if (!*(dev + strspn(dev, "/0123456789")))
1591 while (dev != tty && *--dev != '/');
1600 strncpy(up->ut_line, tty, sizeof up->ut_line);
1603 * The remainder of the utmp entry is filled in. The process
1604 * id and tty line should already have been present, however,
1605 * these are set here for completeness.
1608 strncpy(up->ut_user, user, sizeof up->ut_user);
1609 up->ut_pid = getpid();
1610 up->ut_type = LOGIN_PROCESS;
1611 up->ut_time = time((time_t *) 0);
1614 strncpy(up->ut_host, hostname, sizeof up->ut_host);
1616 /* Scan the utmp file. If an entry is found that */
1617 /* is the same as this tty, use this slot to create the */
1618 /* new entry. This slot has to be an empty slot. */
1619 /* Re-using the same slot used by the tty (with an */
1620 /* empty type) will avoid printing of empty slots on */
1621 /* "who -a" output. */
1623 if ((f = open(UTMP_FILE, O_RDWR)) >= 0) {
1624 lseek(f, (off_t) 0, SEEK_SET);
1625 rcode = lockf(f, F_LOCK, 0);
1627 while (read(f, (char *)&outmp, UTSIZ) == UTSIZ) {
1628 if ((!strcmp(outmp.ut_line, tty)) && outmp.ut_type == EMPTY) {
1633 lseek(f, (off_t) (t * UTSIZ), 0);
1634 write(f, (char *)up, UTSIZ);
1635 lseek(f, (off_t) 0, SEEK_SET);
1636 rcode = lockf(f, F_ULOCK, 0);
1641 * The utmp entry is appended to the wtmp file to maintain a
1642 * log of all login activity.
1644 if ((f = open(WTMP_FILE, O_WRONLY | O_APPEND)) >= 0) {
1645 offset = lseek(f, 0L, 2);
1647 write(f, (char *)up, UTSIZ - (offset % UTSIZ));
1649 write(f, (char *)up, UTSIZ);
1656 #define MAXLOCALTOKENS 4
1657 #define HEADER_SIZE 18
1662 * This routine accepts a token on the specified file handle;
1663 * The input format for a token is:
1665 * Field # Contents description
1666 * (1) Version # unsigned integer (< 2^32)
1667 * (2) Length unsigned integer (< 2^32)
1668 * (3) startTime unsigned afs_int32 (< 2^32)
1669 * (4) endTime unsigned afs_int32 (< 2^32)
1670 * (5) sessionKey char[8]
1671 * (6) kvno short (< 2^16)
1672 * (7) ticketLen unsigned integer (< 2^32)
1673 * (8) ticket char[MAXKTCTICKETLEN]
1674 * (9) AFS name char[MAXKTCNAMELEN]
1675 * (10) Cell Name char[MAXKTCREALMLEN]
1677 * Each field is comma separated except (5) and (6), and (8) and (9); the
1678 * ticket is variable length. The * converted token is placed into the
1679 * token structure pointed to by the variable "token". The first and second
1680 * fields are padded with spaces on the right so that they can be fixed length.
1681 * This is required so that the length can be read in before reading in the
1690 char buf[512 * MAXLOCALTOKENS], *bp;
1691 int length, readed, count;
1692 unsigned index, version;
1693 struct ktc_token token;
1694 struct ktc_principal tclient, tserver;
1702 ** Read in the first two fields.
1707 while (readed < HEADER_SIZE) {
1708 count = read(s, (char *)((int)buf + readed), HEADER_SIZE - readed);
1710 perror("intokens read");
1713 readed = readed + count;
1720 for (index = 0; (index + bp - buf) < count && bp[index] != ','; index++);
1722 if ((index + bp - buf) == count) {
1723 fprintf(stderr, "overran buffer while searching for version #\n");
1727 if (bp[index] != ',') {
1728 fprintf(stderr, "Didn't stop on a comma, searching for version #\n");
1734 sscanf(bp, "%u", &version);
1737 fprintf(stderr, "intokens: incompatible version encountered: %d\n",
1742 bp = bp + index + 1;
1745 for (index = 0; (index + bp - buf) < count && bp[index] != ','; index++);
1747 if ((index + bp - buf) == count) {
1748 fprintf(stderr, "overran buffer while searching for length #\n");
1752 if (bp[index] != ',') {
1753 fprintf(stderr, "Didn't stop on a comma, searching for length\n");
1759 sscanf(bp, "%u", &length);
1761 bp = bp + index + 1;
1764 while (readed < length) {
1765 count = read(s, (char *)((int)buf + readed), length - readed);
1767 perror("intokens read");
1770 readed = readed + count;
1776 ** Terminate looping through the list of tokens when we hit a null byte.
1781 for (index = 0; (index + bp - buf) < count && bp[index] != ',';
1784 if ((index + bp - buf) == count) {
1786 "overran buffer while searching for startTime #\n");
1790 if (bp[index] != ',') {
1792 "Didn't stop on a comma, searching for startTime #\n");
1798 sscanf(bp, "%u", &token.startTime);
1802 bp = bp + index + 1;
1804 for (index = 0; (index + bp - buf) < count && bp[index] != ',';
1807 if ((index + bp - buf) == count) {
1808 fprintf(stderr, "overran buffer while searching for endTime #\n");
1812 if (bp[index] != ',') {
1814 "Didn't stop on a comma, searching for endTime #\n");
1820 sscanf(bp, "%u", &token.endTime);
1822 /* (5) sessionKey */
1824 bp = bp + index + 1;
1825 memcpy(token.sessionKey.data, bp, 8);
1830 for (index = 0; (index + bp - buf) < count && bp[index] != ',';
1833 if ((index + bp - buf) == count) {
1834 fprintf(stderr, "overran buffer while searching for kvno\n");
1838 if (bp[index] != ',') {
1839 fprintf(stderr, "Didn't stop on a comma, searching for kvno\n");
1845 token.kvno = atoi(bp);
1849 bp = bp + index + 1;
1851 for (index = 0; (index + bp - buf) < count && bp[index] != ',';
1854 if ((index + bp - buf) == count) {
1855 fprintf(stderr, "overran buffer while searching for ticketLen\n");
1859 if (bp[index] != ',') {
1861 "Didn't stop on a comma, searching for ticketLen\n");
1867 sscanf(bp, "%u", &token.ticketLen);
1871 bp = bp + index + 1;
1873 if ((index + bp - buf) + token.ticketLen > count) {
1874 fprintf(stderr, "overran buffer while copying ticket\n");
1878 memcpy(token.ticket, bp, token.ticketLen);
1880 bp = bp + token.ticketLen;
1884 for (index = 0; (index + bp - buf) < count && bp[index] != ',';
1887 if ((index + bp - buf) == count) {
1888 fprintf(stderr, "overran buffer while searching for Cell Name\n");
1893 tclient.instance[0] = '\0';
1894 strncpy(tclient.name, bp, MAXKTCNAMELEN);
1896 /* (10) Cell name */
1898 bp = bp + index + 1;
1900 for (index = 0; (index + bp - buf) < count && bp[index] != ',';
1903 if ((index + bp - buf) == count) {
1904 fprintf(stderr, "overran buffer while searching for end\n");
1909 strncpy(tclient.cell, bp, MAXKTCREALMLEN);
1910 bp = bp + index + 1;
1912 strcpy(tserver.name, "afs");
1913 tserver.instance[0] = '\0';
1914 strncpy(tserver.cell, tclient.cell, MAXKTCREALMLEN);
1916 if (ktc_SetToken(&tserver, &token, &tclient, 0)) {
1917 fprintf(stderr, "intokens: ktc_SetToken failed for %s\n",
1927 #include <sys/stat.h>
1932 # define MAX_PTY_LEN MAXPATHLEN+1
1933 # define CLONE_DRV "/dev/ptym/clone"
1936 ** Ugh! The following is gross, but there is no other simple way
1937 ** to tell if a file is a master pty without looking at its major
1938 ** device number. Lets put it in ifdefs so it will fail to compile
1939 ** on other architectures without modification.
1942 #define PTY_MASTER_MAJOR_NUMBER 16
1945 #define PTY_MASTER_MAJOR_NUMBER 16
1949 struct stat m_stbuf; /* stat buffer for master pty */
1950 struct stat s_stbuf; /* stat buffer for slave pty */
1953 ** ptymdirs -- directories to search for master ptys
1954 ** ptysdirs -- directories to search for slave ptys
1955 ** ptymloc -- full path to pty master
1956 ** ptysloc -- full path to pty slave
1958 char *ptymdirs[] = { "/dev/ptym/", "/dev/", (char *)0 };
1959 char *ptysdirs[] = { "/dev/pty/", "/dev/", (char *)0 };
1960 char ptymloc[MAX_PTY_LEN];
1961 char ptysloc[MAX_PTY_LEN];
1964 ** oltrs -- legal first char of pty name (letter) (old style)
1965 ** onums -- legal second char of pty name (number) for namespace 1
1967 ** ltrs -- legal first char of pty name (letter) (new style)
1968 ** nums -- legal second and third char of pty name (number) (new style)
1969 ** nums -- legal second, third and fourth char of pty name for names
1972 char oltrs[] = "onmlkjihgfecbazyxwvutsrqp";
1973 char onums[] = "0123456789abcdef";
1974 char ltrs[] = "pqrstuvwxyzabcefghijklmno";
1975 char nums[] = "0123456789";
1978 ** getpty() -- get a pty pair
1981 ** Output -- zero if pty pair gotten; non-zero if not
1982 ** [value parameter mfd]
1983 ** mfd Master FD for the pty pair
1984 ** [optional value parameters -- only set if != NULL]
1985 ** mname Master pty file name
1986 ** sname Slave pty file name
1988 ** NOTE: This routine does not open the slave pty. Therefore, if you
1989 ** want to quickly find the slave pty to open, it is recommended that
1990 ** you *not* pass sname as NULL.
1994 ** Modified 3/28/89 by Peter Notess to search the new, expanded naming
1995 ** convention. The search is intended to proceed efficiently for both
1996 ** large and small configurations, assuming that the ptys are created
1997 ** in a pre-specified order. This routine will do a last-ditch,
1998 ** brute-force search of all files in the pty directories if the more
1999 ** efficient search fails. This is intended to make the search robust
2000 ** in the case where the pty configuration is a non-standard one,
2001 ** although it might take longer to find a pty in this case. The
2002 ** assumed order of creation is:
2003 ** /dev/ptym/pty[p-z][0-f]
2004 ** /dev/ptym/pty[a-ce-o][0-f]
2005 ** /dev/ptym/pty[p-z][0-9][0-9]
2006 ** /dev/ptym/pty[a-ce-o][0-9][0-9]
2007 ** with /dev/ptym/pty[p-r][0-f] linked into /dev. The search will
2008 ** proceed in an order that leaves the ptys which also appear in /dev
2009 ** searched last so that they remain available for other applications
2010 ** as long as possible.
2014 * Modified by Glen A. Foster, September 23, 1986 to get around a problem
2015 * with 4.2BSD job control in the HP-UX (a.k.a. system V) kernel. Before
2016 * this fix, getpty() used to find a master pty to use, then open the cor-
2017 * responding slave side, just to see if it was there (kind of a sanity
2018 * check), then close the slave side, fork(), and let the child re-open
2019 * the slave side in order to get the proper controlling terminal. This
2020 * was an excellent solution EXCEPT for the case when another process was
2021 * already associated with the same slave side before we (telnetd) were
2022 * exec()ed. In that case, the controlling tty stuff gets all messed up,
2023 * and the solution is to NOT open the slave side in the parent (before the
2024 * fork()), but to let the child be the first to open it after its setpgrp()
2025 * call. This works in all cases. This stuff is black magic, really!
2027 * This is necessary due to HP's implementation of 4.2BSD job control.
2031 * Modified by Byron Deadwiler, March 9, 1992 to add access to the clone
2032 * driver to get ptys faster. Also added code to access ptys using
2033 * a new namespace (naming convention) that increases the number of
2034 * pty's that can be configured on a system.
2036 * Name-Space It is a union of three name-spaces, the earlier two
2037 * being supported for compatibility. The name comprises
2038 * a generic name (/dev/pty/tty) followed by an alphabet
2039 * followed by one to three numerals. The alphabet is one
2040 * of the 25 in alpha[], which has 'p' thro' 'o' excluding
2041 * 'd'. The numeral is either hex or decimal.
2042 * ------------------------------------
2043 * | minor | name | Remarks |
2044 * |----------------------------------|
2045 * | 0| ttyp0| Modulo 16 hex |
2046 * | :| :| representation. |
2056 * | 399| ttyof| Total 400 |
2057 * |----------------------------------|
2058 * | 400| ttyp00| Modulo hundred |
2059 * | :| :| decimal repr. |
2069 * | 2899| ttyo99| Total 2500 |
2070 * |----------------------------------|
2071 * | 2900|ttyp000| Modulo thousand |
2072 * | :| :| decimal repr. |
2076 * | 12899|ttyz999| |
2077 * | 13900|ttya000| |
2079 * | 16899|ttyc999| |
2080 * | 16900|ttye000| |
2082 * | 27899|ttyo999| Total 25000 |
2083 * | 27900| | invalid |
2084 * ------------------------------------
2088 ** NOTE: this routine should be put into a library somewhere, since
2089 ** both rlogin and telnet need it! also, other programs might want to
2090 ** call it some day to get a pty pair ...
2092 getpty(mfd, mname, sname)
2094 char *mname, *sname;
2096 int loc, ltr, num, num2;
2097 register int mlen, slen;
2100 if ((*mfd = open(CLONE_DRV, O_RDWR)) != -1) {
2101 s_path = ptsname(*mfd);
2102 strcpy(sname, s_path);
2103 (void)chmod(sname, 0622);
2104 /* get master path name */
2105 s = strrchr(sname, '/') + 2; /* Must succeed since slave_pty */
2106 /* begins with /dev/ */
2107 sprintf(mname, "%s%s%s", ptymdirs[0], "p", s);
2112 for (loc = 0; ptymdirs[loc] != NULL; loc++) {
2113 if (stat(ptymdirs[loc], &stb)) /* no directory ... */
2114 continue; /* so try next one */
2116 /* first, try the 3rd name space ptyp000-ptyo999 */
2117 /* generate the master pty path */
2118 if (namesp3(mfd, mname, sname, loc) == 0) {
2122 /* second, try the 2nd name space ptyp00-ptyo99 */
2123 /* generate the master pty path */
2124 (void)strcpy(ptymloc, ptymdirs[loc]);
2125 (void)strcat(ptymloc, "ptyLNN");
2126 mlen = strlen(ptymloc);
2128 /* generate the slave pty path */
2129 (void)strcpy(ptysloc, ptysdirs[loc]);
2130 (void)strcat(ptysloc, "ttyLNN");
2131 slen = strlen(ptysloc);
2133 for (ltr = 0; ltrs[ltr] != '\0'; ltr++) {
2134 ptymloc[mlen - 3] = ltrs[ltr];
2135 ptymloc[mlen - 2] = '0';
2136 ptymloc[mlen - 1] = '0';
2137 if (stat(ptymloc, &stb)) /* no ptyL00 ... */
2138 break; /* go try old style names */
2140 for (num = 0; nums[num] != '\0'; num++)
2141 for (num2 = 0; nums[num2] != '\0'; num2++) {
2142 ptymloc[mlen - 2] = nums[num];
2143 ptymloc[mlen - 1] = nums[num2];
2144 if ((*mfd = open(ptymloc, O_RDWR)) < 0) /* no master */
2145 continue; /* try next num */
2147 ptysloc[slen - 3] = ltrs[ltr];
2148 ptysloc[slen - 2] = nums[num];
2149 ptysloc[slen - 1] = nums[num2];
2152 ** NOTE: changed to only stat the slave device; see
2153 ** comments all over the place about job control ...
2155 if (fstat(*mfd, &m_stbuf) < 0
2156 || stat(ptysloc, &s_stbuf) < 0) {
2161 ** sanity check: are the minor numbers the same??
2163 if (minor(m_stbuf.st_rdev) != minor(s_stbuf.st_rdev)) {
2165 continue; /* try next num */
2168 /* else we got both a master and a slave pty */
2169 got_one:(void)chmod(ptysloc, 0622);
2172 (void)strcpy(mname, ptymloc);
2174 (void)strcpy(sname, ptysloc);
2175 return 0; /* return OK */
2179 /* now, check old-style names */
2180 /* the 1st name-space ptyp0-ptyof */
2181 /* generate the master pty path */
2182 (void)strcpy(ptymloc, ptymdirs[loc]);
2183 (void)strcat(ptymloc, "ptyLN");
2184 mlen = strlen(ptymloc);
2186 /* generate the slave pty path */
2187 (void)strcpy(ptysloc, ptysdirs[loc]);
2188 (void)strcat(ptysloc, "ttyLN");
2189 slen = strlen(ptysloc);
2191 for (ltr = 0; oltrs[ltr] != '\0'; ltr++) {
2192 ptymloc[mlen - 2] = oltrs[ltr];
2193 ptymloc[mlen - 1] = '0';
2194 if (stat(ptymloc, &stb)) /* no ptyL0 ... */
2195 continue; /* try next ltr */
2197 for (num = 0; onums[num] != '\0'; num++) {
2198 ptymloc[mlen - 1] = onums[num];
2199 if ((*mfd = open(ptymloc, O_RDWR)) < 0) /* no master */
2200 continue; /* try next num */
2202 ptysloc[slen - 2] = oltrs[ltr];
2203 ptysloc[slen - 1] = onums[num];
2206 ** NOTE: changed to only stat the slave device; see
2207 ** comments all over the place about job control ...
2209 if (fstat(*mfd, &m_stbuf) < 0 || stat(ptysloc, &s_stbuf) < 0) {
2214 ** sanity check: are the minor numbers the same??
2216 if (minor(m_stbuf.st_rdev) != minor(s_stbuf.st_rdev)) {
2218 continue; /* try next num */
2221 /* else we got both a master and a slave pty */
2226 /* we failed in our search--we now try the slow brute-force method */
2227 for (loc = 0; ptymdirs[loc] != NULL; loc++) {
2231 if ((dirp = opendir(ptymdirs[loc])) == NULL) /* no directory ... */
2232 continue; /* so try next one */
2234 (void)strcpy(ptymloc, ptymdirs[loc]);
2235 mlen = strlen(ptymloc);
2236 (void)strcpy(ptysloc, ptysdirs[loc]);
2237 slen = strlen(ptysloc);
2239 while ((dp = readdir(dirp)) != NULL) {
2240 /* stat, open, go for it, else continue */
2241 ptymloc[mlen] = '\0';
2242 (void)strcat(ptymloc, dp->d_name);
2244 if (stat(ptymloc, &m_stbuf)
2245 || (m_stbuf.st_mode & S_IFMT) != S_IFCHR
2246 || major(m_stbuf.st_rdev) != PTY_MASTER_MAJOR_NUMBER)
2249 if ((*mfd = open(ptymloc, O_RDWR)) < 0) /* busy master */
2250 continue; /* try next entry */
2252 ptysloc[slen] = '\0'; /* guess at corresponding slave name */
2253 (void)strcat(ptysloc, dp->d_name);
2254 if (ptysloc[slen] == 'p')
2255 ptysloc[slen] = 't';
2257 if (stat(ptysloc, &s_stbuf) < 0
2258 || minor(m_stbuf.st_rdev) != minor(s_stbuf.st_rdev)) {
2268 /* we were not able to get the master/slave pty pair */
2272 namesp3(mfd, mname, sname, loc)
2274 char *mname, *sname;
2276 int ltr, num, num2, num3;
2277 register int mlen, slen;
2279 /* first, try the new naming convention */
2280 /* generate the master pty path */
2281 (void)strcpy(ptymloc, ptymdirs[loc]);
2282 (void)strcat(ptymloc, "ptyLNNN");
2283 mlen = strlen(ptymloc);
2285 /* generate the slave pty path */
2286 (void)strcpy(ptysloc, ptysdirs[loc]);
2287 (void)strcat(ptysloc, "ttyLNNN");
2288 slen = strlen(ptysloc);
2290 for (ltr = 0; ltrs[ltr] != '\0'; ltr++) {
2291 ptymloc[mlen - 4] = ltrs[ltr];
2292 ptymloc[mlen - 3] = '0';
2293 ptymloc[mlen - 2] = '0';
2294 ptymloc[mlen - 1] = '0';
2295 if (stat(ptymloc, &stb)) /* no ptyL00 ... */
2296 break; /* go try old style names */
2298 for (num = 0; nums[num] != '\0'; num++)
2299 for (num2 = 0; nums[num2] != '\0'; num2++)
2300 for (num3 = 0; nums[num3] != '\0'; num3++) {
2301 ptymloc[mlen - 3] = nums[num];
2302 ptymloc[mlen - 2] = nums[num2];
2303 ptymloc[mlen - 1] = nums[num3];
2304 if ((*mfd = open(ptymloc, O_RDWR)) < 0) /* no master */
2305 continue; /* try next num */
2307 ptysloc[slen - 4] = ltrs[ltr];
2308 ptysloc[slen - 3] = nums[num];
2309 ptysloc[slen - 2] = nums[num2];
2310 ptysloc[slen - 1] = nums[num3];
2313 ** NOTE: changed to only stat the slave device; see
2314 ** comments all over the place about job control ...
2316 if (fstat(*mfd, &m_stbuf) < 0
2317 || stat(ptysloc, &s_stbuf) < 0) {
2322 ** sanity check: are the minor numbers the same??
2324 if (minor(m_stbuf.st_rdev) != minor(s_stbuf.st_rdev)) {
2326 continue; /* try next num */
2329 /* else we got both a master and a slave pty */
2330 (void)chmod(ptysloc, 0622); /* not readable */
2332 (void)strcpy(mname, ptymloc);
2334 (void)strcpy(sname, ptysloc);
2335 return 0; /* return OK */