remove-rx-2tier-freepacketq-20050403
[openafs.git] / src / rlogind / rlogind.c
1 /*
2  * Copyright (c) 1983, 1988 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 /*
19 #include <afsconfig.h>
20 #include <afs/param.h>
21
22 RCSID("$Header$");
23
24 #ifdef MSG
25 #include "rlogind_msg.h"
26 #define MF_LIBC "libc.cat"
27 #define MS_LIBC 1
28 #define MSGSTR(n,s) NLgetamsg(MF_RLOGIND, MS_RLOGIND, n, s)
29 #else*/
30 #define MSGSTR(n,s) s
31 /*#endif*/
32
33
34 /*
35  * remote login server:
36  *      \0
37  *      remuser\0
38  *      locuser\0
39  *      terminal_type/speed\0
40  *      data
41  *
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).
44  */
45
46 #include <afs/param.h>
47 #ifdef  AFS_SUN5_ENV
48 #define BSD_COMP
49 #include <sys/ioctl.h>
50 #endif
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <sys/param.h>
54 #include <sys/stat.h>
55 #include <sys/socket.h>
56 #include <sys/wait.h>
57 #include <sys/file.h>
58 #ifdef  AFS_SUN5_ENV
59 #include <fcntl.h>
60 #endif
61
62 #include <netinet/in.h>
63
64 #include <errno.h>
65 #include <pwd.h>
66 #include <signal.h>
67 #ifdef _AIX
68 #include <utmp.h>
69 /* POSIX TERMIOS */
70 #include <termios.h>
71 #include <sys/ioctl.h>
72 #ifndef AFS_AIX41_ENV
73 #include <sys/tty.h>
74 #endif
75 #include <sys/acl.h>
76 #include <sys/access.h>
77 #else /* _AIX */
78 #include <sgtty.h>
79 #endif /* _AIX */
80 #include <stdio.h>
81 #include <netdb.h>
82 #ifdef  AFS_AIX32_ENV
83 #include <sys/lockf.h>
84 #endif
85 #include <syslog.h>
86 #include <strings.h>
87
88 #ifdef  AFS_OSF_ENV
89 #include <unistd.h>
90 #include <sys/param.h>
91 #include <sys/stat.h>
92 #include <sys/socket.h>
93 #include <sys/wait.h>
94 #include <sys/file.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>
100 #define TTYDEFCHARS
101 #include <sys/termios.h>
102 #define _PATH_LOGIN        "/usr/bin/login"
103 #endif
104
105 #if defined(AFS_HPUX_ENV)
106 #include <fcntl.h>
107 #include <sys/ptyio.h>
108 #endif /* defined(AFS_HPUX_ENV) */
109
110 #ifdef _AIX
111 #define DEF_UTMP        "Active tty entry not found in utmp file.\n"
112
113 #define NOLOGIN         "/etc/nologin"
114 #define BSHELL          "/bin/sh"
115
116 /*#define KAUTH*/
117
118 #ifdef KAUTH
119 int pass_tokens;
120 #include <afs/auth.h>
121 #include <afs/cellconfig.h>
122 #endif /* KAUTH */
123
124 struct utmp utmp;
125 #define UT_NAMESIZE     sizeof(utmp.ut_user)
126 #define UTSIZ           (sizeof (struct utmp))
127
128 static void loginlog();
129 #endif /* _AIX */
130
131 #ifndef TIOCPKT_WINDOW
132 #define TIOCPKT_WINDOW 0x80
133 #endif
134
135 char *env[2];
136 #define NMAX 30
137 char lusername[NMAX + 1], rusername[NMAX + 1];
138 static char term[64] = "TERM=";
139 #define ENVSIZE (sizeof("TERM=")-1)     /* skip null for concatenation */
140 int keepalive = 1;
141 int tracing = 0;
142 #ifdef  AFS_OSF_ENV
143 int check_all = 0;
144 #endif
145
146 #define SUPERUSER(pwd)  ((pwd)->pw_uid == 0)
147
148 extern int errno;
149 int reapchild();
150 struct passwd *getpwnam(), *pwd;
151 #ifdef  AFS_HPUX_ENV
152 #include <unistd.h>
153 struct s_passwd *s_pwd, *getspwnam();
154 struct stat s_pfile;
155 #endif
156 #if defined(AFS_AIX32_ENV) && (defined(NLS) || defined(KJI))
157 #include <locale.h>
158 #endif
159
160
161 #include "AFS_component_version_number.c"
162
163 main(argc, argv)
164      int argc;
165      char **argv;
166 {
167     extern int opterr, optind, _check_rhosts_file;
168     int ch;
169     int on = 1, fromlen;
170     struct sockaddr_in from;
171 #ifdef  AFS_AIX32_ENV
172     struct sigaction sa;
173     void trace_handler(int);
174
175 #if defined(NLS) || defined(KJI)
176     setlocale(LC_ALL, "");
177 #endif
178 #endif
179     openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
180
181 #ifdef  KAUTH
182     pass_tokens = 0;
183 #endif
184     opterr = 0;
185     while ((ch = getopt(argc, argv, "ln")) != EOF)
186         switch (ch) {
187 #ifdef  AFS_OSF_ENV
188         case 'a':
189             check_all = 1;
190             break;
191 #endif
192         case 'l':
193             _check_rhosts_file = 0;
194             break;
195         case 'n':
196             keepalive = 0;
197             break;
198 #ifdef  AFS_AIX32_ENV
199 #ifdef KAUTH
200         case 'v':
201             pass_tokens = 1;
202             break;
203 #endif /* KAUTH */
204         case 's':
205             tracing = 1;
206             break;
207 #endif
208         case '?':
209         default:
210 #ifdef  AFS_AIX32_ENV
211 #ifdef KAUTH
212             syslog(LOG_ERR, "usage: rlogind [-v] [-l] [-n] [-s]");
213 #else /* KAUTH */
214             syslog(LOG_ERR, "usage: rlogind [-l] [-n] [-s]");
215 #endif /* KAUTH */
216 #else
217 #ifdef  AFS_OSF_ENV
218             syslog(LOG_ERR, "usage: rlogind [-l] [-n] [-a] [-s]");
219 #else
220             syslog(LOG_ERR, "usage: rlogind [-l] [-n]");
221 #endif
222 #endif
223             break;
224         }
225     argc -= optind;
226     argv += optind;
227
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");
232     }
233     if (keepalive
234         && setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
235                       sizeof(on)) < 0)
236         syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
237 #ifdef  AFS_AIX32_ENV
238     if (tracing
239         && setsockopt(0, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof(on)) < 0)
240         syslog(LOG_WARNING, MSGSTR(SETDEBUG, "setsockopt (SO_DEBUG): %m"));
241      /*MSG*/
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);
252 #endif
253 #ifdef  AFS_OSF_ENV
254     on = IPTOS_LOWDELAY;
255     if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
256         syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
257 #endif
258     doit(0, &from);
259 }
260
261 #ifdef  AFS_AIX32_ENV
262 /*
263  * trace_handler - SRC TRACE ON/OFF signal handler
264  */
265 void
266 trace_handler(int sig)
267 {
268     int onoff;
269
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"));
273  /*MSG*/}
274 #endif
275
276 int child;
277 void cleanup();
278 int netf;
279 #ifdef  AFS_OSF_ENV
280 char line[MAXPATHLEN];
281 #else
282 char *line;
283 #endif
284 #ifdef _AIX
285 char tbuf[MAXPATHLEN + 2];
286 struct hostent *hp;
287 struct hostent hostent;
288 #endif /* _AIX */
289
290 extern char *inet_ntoa();
291 #ifdef  AFS_HPUX_ENV
292 int netp;
293 char master[MAXPATHLEN], slave[MAXPATHLEN], tname[MAXPATHLEN];
294 #endif
295
296 #if     defined(TIOCSWINSZ) || defined(AFS_OSF_ENV)
297 struct winsize win = { 0, 0, 0, 0 };
298 #else /* ~TIOCWINSIZ */
299 /*
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.
304  *
305  * Type must be "unsigned short" so that types.h not required.
306  */
307 struct winsize {
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 */
312 };
313 #endif /* ~TIOCWINSIZ */
314
315 doit(f, fromp)
316      int f;
317      struct sockaddr_in *fromp;
318 {
319     int i, p, t, pid, on = 1;
320 #ifdef  AFS_OSF_ENV
321     int master;
322 #endif
323 #ifdef  AFS_HPUX_ENV
324     int t_;
325     char *tn;
326 #endif
327     char pline[16];
328
329 #ifndef OLD_LOGIN
330     int authenticated = 0, hostok = 0;
331     char remotehost[2 * MAXHOSTNAMELEN + 1];
332 #endif
333 #ifndef _AIX
334     register struct hostent *hp;
335     struct hostent hostent;
336 #endif
337     char c, *cp;
338
339 #if defined(AFS_HPUX_ENV)
340     int ptyStatusFlags;
341 #endif /* defined(AFS_HPUX_ENV) */
342
343     alarm(60);
344     read(f, &c, 1);
345     if (c != 0)
346         exit(1);
347
348     alarm(0);
349     fromp->sin_port = ntohs((u_short) fromp->sin_port);
350     hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr),
351                        fromp->sin_family);
352     if (hp == 0) {
353         /*
354          * Only the name is used below.
355          */
356         hp = &hostent;
357         hp->h_name = inet_ntoa(fromp->sin_addr);
358 #ifndef OLD_LOGIN
359         hostok++;
360 #endif
361     }
362 #ifndef OLD_LOGIN
363 #ifdef  AFS_HPUX_ENV
364     else if (errno != ECONNREFUSED) {
365 #else
366 #ifdef  AFS_OSF_ENV
367     else if (check_all || local_domain(hp->h_name)) {
368 #else
369     else if (local_domain(hp->h_name)) {
370 #endif
371 #endif
372         /*
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.
377          */
378         strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
379         remotehost[sizeof(remotehost) - 1] = 0;
380         hp = gethostbyname(remotehost);
381         if (hp)
382 #if defined(BSD_42)
383             if (!memcmp
384                 (hp->h_addr, (caddr_t) & fromp->sin_addr,
385                  sizeof(fromp->sin_addr))) {
386 #else /* BSD_42 */
387             for (; hp->h_addr_list[0]; hp->h_addr_list++)
388                 if (!memcmp
389                     (hp->h_addr_list[0], (caddr_t) & fromp->sin_addr,
390                      sizeof(fromp->sin_addr))) {
391 #endif /* BSD_42 */
392                     hostok++;
393 #if !defined(BSD_42)
394                     break;
395 #endif
396                 }
397     } else
398         hostok++;
399 #endif
400
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");
406     }
407 #ifdef IP_OPTIONS
408     {
409         u_char optbuf[BUFSIZ / 3], *cp;
410         char lbuf[BUFSIZ], *lp;
411         int optsize = sizeof(optbuf), ipproto;
412         struct protoent *ip;
413
414         if ((ip = getprotobyname("ip")) != NULL)
415             ipproto = ip->p_proto;
416         else
417             ipproto = IPPROTO_IP;
418         if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) == 0
419             && optsize != 0) {
420             lp = lbuf;
421             for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
422                 sprintf(lp, " %2.2x", *cp);
423             syslog(LOG_NOTICE,
424                    "Connection received using IP options (ignored):%s", lbuf);
425             if (setsockopt(0, ipproto, IP_OPTIONS, (char *)NULL, optsize) !=
426                 0) {
427                 syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
428                 exit(1);
429             }
430         }
431     }
432 #endif
433     write(f, "", 1);
434 #ifndef OLD_LOGIN
435     if (do_rlogin(hp->h_name) == 0) {
436         if (hostok)
437             authenticated++;
438         else
439             write(f, "rlogind: Host address mismatch.\r\n",
440                   sizeof("rlogind: Host address mismatch.\r\n") - 1);
441     }
442 #endif
443 #ifdef KAUTH
444     if (pass_tokens) {
445         if (intokens(0)) {
446             fprintf(stderr, "%s: invalid remote authentication\n", "login");
447             exit(1);
448         }
449     }
450 #endif /* KAUTH */
451
452 #ifdef  AFS_OSF_ENV
453     netf = f;
454
455     pid = forkpty(&master, line, NULL, &win);
456     if (pid < 0) {
457         if (errno == ENOENT)
458             fatal(f, "Out of ptys", 0);
459         else
460             fatal(f, "Forkpty", 1);
461     }
462     if (pid == 0) {
463         if (f > 2)              /* f should always be 0, but... */
464             (void)close(f);
465         setup_term(0);
466         if (authenticated) {
467             execl(_PATH_LOGIN, "login", "-p", "-h", hp->h_name, "-f",
468                   lusername, NULL);
469         } else {
470             char *sp = lusername;
471             while (*sp == ' ')
472                 sp++;
473             if (!strncmp(sp, "-f", 2)) {
474                 syslog(LOG_ERR, "Can't use '-f' in username");
475                 exit(1);
476             }
477             execl(_PATH_LOGIN, "login", "-p", "-h", hp->h_name, lusername,
478                   NULL);
479         }
480         fatalperror(2, _PATH_LOGIN);
481      /*NOTREACHED*/}
482     ioctl(f, FIONBIO, &on);
483     ioctl(master, FIONBIO, &on);
484     ioctl(master, TIOCPKT, &on);
485     signal(SIGCHLD, cleanup);
486     protocol(f, master);
487     signal(SIGCHLD, SIG_IGN);
488     cleanup();
489 #else
490 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV) && defined(notdef)
491     /*
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.
506      */
507
508     for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
509         struct stat stb;
510         int pgrp;
511
512         /* make sure this "bank" of ptys exists */
513         line = "/dev/ptyXX";
514         line[strlen("/dev/pty")] = *cp;
515         line[strlen("/dev/ptyp")] = '0';
516         if (stat(line, &stb) < 0)
517             break;
518         for (i = 0; i < 16; i++) {
519             line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
520             line[strlen("/dev/")] = 'p';
521
522             /*
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.
526              */
527             if ((p = open(line, O_RDWR | O_NOCTTY)) == -1)
528                 continue;
529
530             /* 
531              * Lock the slave side so that no one else can 
532              * open it after this.
533              */
534             line[strlen("/dev/")] = 't';
535             if (chmod(line, 0600) == -1) {
536                 (void)close(p);
537                 continue;
538             }
539
540             /*
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.
545              */
546             if ((ioctl(p, TIOCGPGRP, &pgrp) == -1) && (errno == EIO))
547                 goto gotpty;
548             else {
549                 (void)chmod(line, 0666);
550                 (void)close(p);
551             }
552         }
553     }
554     fatal(f, "Out of ptys");
555    /*NOTREACHED*/ gotpty:
556     (void)ioctl(p, TIOCSWINSZ, &win);
557     netf = f;
558     line[strlen("/dev/")] = 't';
559     t = open(line, O_RDWR | O_NOCTTY);
560     if (t < 0)
561         fatalperror(f, line);
562     {
563         /* These should be converted to termios ioctls. */
564         struct sgttyb b;
565         int zero = 0;
566
567         if (gtty(t, &b) == -1)
568             perror("gtty");
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)
574             perror("stty");
575         /*
576          * Turn off PASS8 mode, since "login" no longer does so.
577          */
578         if (ioctl(t, TIOCLSET, &zero) == -1)
579             perror("ioctl TIOCLSET");
580     }
581 #else
582 #ifdef _AIX
583     (void)setsid();
584     if ((p = open("/dev/ptc", O_RDWR)) >= 0) {
585         line = ttyname(p);
586     } else {
587         fatal(f, MSGSTR(NOPTY, "Out of ptys"));
588      /*MSG*/}
589
590 #else
591 #ifdef  AFS_HPUX_ENV
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 */
595     netf = f;
596     netp = p;
597
598     /* Slave becomes controlling terminal for this session. */
599     t_ = open(slave, O_RDWR);
600     if (t_ < 0)
601         fatalperror(f, slave);
602     /*  Remove any reference to the current control terminal */
603     if (vhangup() < 0)
604         fatalperror(f, "rlogind: vhangup()");
605     /* reopen the slave pseudo-terminal */
606     t = open(slave, O_RDWR);
607     if (t < 0)
608         fatalperror(f, slave);
609     close(t_);
610     /* Get the line name for utmp accounting. */
611     tn = ttyname(t);
612     if (tn != NULL)
613         strcpy(tname, tn);
614     else
615         strcpy(tname, slave);
616 #ifdef TIOCSWINSZ
617     (void)ioctl(p, TIOCSWINSZ, &win);
618 #endif /* TIOCSWINSZ */
619 #ifndef OLD_LOGIN
620     setup_term(t);
621 #endif /* ~OLD_LOGIN */
622
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.
627      */
628     lockf(p, F_LOCK, 0);
629 #else
630     for (c = 'p'; c <= 'z'; c++) {
631         struct stat stb;
632         line = "/dev/ptyXX";
633         line[strlen("/dev/pty")] = c;
634         line[strlen("/dev/ptyp")] = '0';
635         if (stat(line, &stb) < 0)
636             break;
637         for (i = 0; i < 16; i++) {
638             line[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
639             p = open(line, O_RDWR);
640             if (p > 0)
641                 goto gotpty;
642         }
643     }
644     fatal(f, "Out of ptys");
645    /*NOTREACHED*/ gotpty:
646 #endif
647 #endif /* _AIX */
648
649 #ifdef AFS_SUN_ENV
650
651     /* defect #2976 */
652
653     strcpy(pline, line);
654     pline[strlen("/dev/")] = 't';
655     chmod(pline, 0620);
656
657     if (close(p) < 0)
658         goto L1;
659     if ((p = open(line, O_RDWR)) < 0)
660         fatal(f, "Bad open");
661
662   L1:
663 #endif
664
665 #ifndef AFS_HPUX_ENV
666 #ifdef  AFS_AIX32_ENV
667 #ifdef  TIOCSWINSZ
668     (void)ioctl(p, TIOCSWINSZ, &win);
669 #else
670 #ifdef  TXSETWINSZ
671     (void)ioctl(p, TXSETWINSZ, &win);
672 #endif /* TXSETWINSZ */
673 #endif /* TIOCSWINSZ */
674 #endif
675 #ifdef  TIOCSWINSZ
676     (void)ioctl(p, TIOCSWINSZ, &win);
677 #endif
678     netf = f;
679 #ifndef _AIX
680     line[strlen("/dev/")] = 't';
681     t = open(line, O_RDWR);
682     if (t < 0)
683         fatalperror(f, line);
684 #if !defined(ultrix)
685     if (fchmod(t, 0))
686         fatalperror(f, line);
687     (void)signal(SIGHUP, SIG_IGN);
688 #if ! defined(AFS_HPUX_ENV) && ! defined(AFS_OSF_ENV)
689     vhangup();
690 #endif /* !defined(AFS_HPUX_ENV) */
691     (void)signal(SIGHUP, SIG_DFL);
692 #endif /* ultrix */
693     t = open(line, O_RDWR);
694     if (t < 0)
695         fatalperror(f, line);
696     setup_term(t);
697 #endif /* _AIX */
698 #endif /* !AFS_SUN_ENV && !AFS_SUN5_ENV */
699 #ifdef DEBUG
700     {
701         int tt = open("/dev/tty", O_RDWR);
702         if (tt > 0) {
703             (void)ioctl(tt, TIOCNOTTY, 0);
704             (void)close(tt);
705         }
706     }
707 #endif
708 #endif /* !AFS_HPUX_ENV */
709     pid = fork();
710     if (pid < 0) {
711         fatalperror(f, "");
712     }
713     if (pid == 0) {
714 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV)  && defined(notdef)
715         int tt;
716
717         /* The child process needs to be the session leader
718          * and have the pty as its controlling tty
719          */
720         setpgrp(0, 0);
721         tt = open(line, O_RDWR);
722         if (tt < 0)
723             fatalperror(f, line);
724         close(f), close(p), close(t);
725         if (tt != 0)
726             dup2(tt, 0);
727         if (tt != 1)
728             dup2(tt, 1);
729         if (tt != 2)
730             dup2(tt, 2);
731         if (tt > 2)
732             close(tt);
733 #ifdef  notdef
734         close(f), close(p);
735         dup2(t, 0), dup2(t, 1), dup2(t, 2);
736         close(t);
737 #endif
738 #else
739 #ifdef _AIX
740         (void)setsid();
741         t = open(line, O_RDWR);
742         if (t < 0)
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);
747         /* frevoke(t); */
748
749         {
750             struct sigaction sa;
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);
756         }
757
758         t = open(line, O_RDWR);
759         if (t < 0)
760             fatalperror(f, line);
761         setup_term(t);
762 #endif /* _AIX */
763 #ifdef  AFS_OSF_ENV
764         (void)setsid();
765         (void)ioctl(t, TIOCSCTTY, 0);
766 #endif /* AFS_OSF_ENV */
767 #ifdef  AFS_HPUX_ENV
768         /* Wait for the parent to setup our process group and controlling tty. */
769         lockf(p, F_LOCK, 0);
770         lockf(p, F_ULOCK, 0);
771 #endif
772         close(f), close(p);
773         dup2(t, 0), dup2(t, 1), dup2(t, 2);
774         close(t);
775 #endif /* AFS_SUN_ENV */
776 #ifdef  AFS_AIX32_ENV
777         /*
778          * Reset SIGUSR1 and SIGUSR2 to non-restartable so children
779          * of rlogind do not get clobbered by the way rlogind handles
780          * these signals.
781          */
782         {
783             struct sigaction sa;
784
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);
792         }
793
794         (void)loginlog(lusername, line, hp->h_name);
795 #endif
796 #ifdef OLD_LOGIN
797         execl("/bin/login", "login", "-r", hp->h_name, 0);
798 #else /* OLD_LOGIN */
799         if (authenticated) {
800 #ifdef AFS_AIX32_ENV
801             execl("/bin/login.afs", "login", /*"-v", */ "-p", "-h",
802                   hp->h_name, "-f", "--", lusername, 0);
803 #else
804             execl("/bin/login", "login", "-p", "-h", hp->h_name, "-f",
805                   lusername, 0);
806 #endif
807         } else {
808             char *sp = lusername;
809             while (*sp == ' ')
810                 sp++;
811             if (!strncmp(sp, "-f", 2)) {
812                 syslog(LOG_ERR, "Can't use '-f' in username");
813                 exit(1);
814             }
815 #ifdef  AFS_AIX32_ENV
816             execl("/bin/login.afs", "login", /*"-v", */ "-p", "-h",
817                   hp->h_name, "--", lusername, 0);
818 #else
819             execl("/bin/login", "login", "-p", "-h", hp->h_name, lusername,
820                   0);
821 #endif
822         }
823 #endif /* OLD_LOGIN */
824         fatalperror(2, "/bin/login");
825      /*NOTREACHED*/}
826 #ifdef  AFS_HPUX_ENV
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.
831      */
832     setpgid(pid, pid);
833
834     /* Make the pty slave the controlling terminal for the child's process group. */
835     tcsetpgrp(t, pid);
836     /* Close our controlling terminal. */
837     close(t);
838
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);
849 #else
850     signal(SIGTERM, cleanup,
851            sigmask(SIGCLD) | sigmask(SIGTERM) | sigmask(SIGPIPE));
852     signal(SIGPIPE, cleanup,
853            sigmask(SIGCLD) | sigmask(SIGTERM) | sigmask(SIGPIPE));
854 #endif
855     setpgid(0, 0);
856     protocol(f, p);
857     signal(SIGCHLD, SIG_IGN);
858     signal(SIGTERM, SIG_IGN);
859     signal(SIGPIPE, SIG_IGN);
860     cleanup();
861     return;
862 #endif
863 #ifndef _AIX
864     close(t);
865 #endif
866
867     ioctl(f, FIONBIO, &on);
868
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) */
876
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);
886 #ifndef _AIX
887 #ifdef AFS_HPUX102_ENV
888     setpgrp();
889 #else
890     setpgrp(0, 0);
891 #endif
892 #endif
893 #ifdef  AFS_AIX32_ENV
894     protocol(f, p, pid);
895     (void)signal(SIGCHLD, SIG_IGN);
896     cleanup(pid);
897 #else
898     protocol(f, p);
899     signal(SIGCHLD, SIG_IGN);
900     cleanup();
901 #endif
902 #endif /* AFS_OSF_ENV */
903 }
904
905 char magic[2] = { 0377, 0377 };
906 char oobdata[] = { TIOCPKT_WINDOW };
907
908 /*
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.
912  */
913 control(pty, cp, n)
914      int pty;
915      char *cp;
916      int n;
917 {
918     struct winsize w;
919
920     if (n < 4 + sizeof(w) || cp[2] != 's' || cp[3] != 's')
921         return (0);
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);
928 #ifdef  AFS_AIX32_ENV
929 #ifdef  TIOCSWINSZ
930     (void)ioctl(pty, TIOCSWINSZ, &w);
931 #else
932     (void)ioctl(pty, TXSETWINSZ, &w);
933 #endif
934 #else
935 #ifdef  TIOCSWINSZ
936     (void)ioctl(pty, TIOCSWINSZ, &w);
937 #endif
938 #endif
939     return (4 + sizeof(w));
940 }
941
942 /*
943  * rlogin "protocol" machine.
944  */
945 #ifdef  AFS_AIX32_ENV
946 protocol(f, p, pid)
947      int f, p;
948      pid_t pid;
949 #else
950 protocol(f, p)
951      int f, p;
952 #endif
953 {
954     char pibuf[1024], fibuf[1024], *pbp, *fbp;
955     register pcc = 0, fcc = 0;
956     int cc, nfd, pmask, fmask;
957     char cntl;
958
959     /*
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).
963      */
964     (void)signal(SIGTTOU, SIG_IGN);
965 #ifdef  AFS_OSF_ENV
966     /* delay TIOCPKT_WINDOW oobdata, for backward compatibility */
967     sleep(1);
968 #endif
969     send(f, oobdata, 1, MSG_OOB);       /* indicate new rlogin */
970     if (f > p)
971         nfd = f + 1;
972     else
973         nfd = p + 1;
974     fmask = 1 << f;
975     pmask = 1 << p;
976     for (;;) {
977         int ibits, obits, ebits;
978
979         ibits = 0;
980         obits = 0;
981         if (fcc)
982             obits |= pmask;
983         else
984             ibits |= fmask;
985         if (pcc >= 0)
986             if (pcc)
987                 obits |= fmask;
988             else
989                 ibits |= pmask;
990         ebits = pmask;
991
992         if (select(nfd, &ibits, obits ? &obits : (int *)NULL, &ebits, 0) < 0) {
993             if (errno == EINTR)
994                 continue;
995 #ifdef  AFS_AIX32_ENV
996             cleanup(pid);
997 #endif
998             fatalperror(f, "select");
999         }
1000         if (ibits == 0 && obits == 0 && ebits == 0) {
1001             /* shouldn't happen... */
1002             sleep(5);
1003             continue;
1004         }
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)) {
1010                 cntl |= oobdata[0];
1011                 send(f, &cntl, 1, MSG_OOB);
1012                 if (cntl & TIOCPKT_FLUSHWRITE) {
1013                     pcc = 0;
1014                     ibits &= ~pmask;
1015                 }
1016             }
1017         }
1018 #endif /* !defined(AFS_SUN5_ENV) */
1019
1020         if (ibits & fmask) {
1021             fcc = read(f, fibuf, sizeof(fibuf));
1022             if (fcc < 0 && errno == EWOULDBLOCK)
1023                 fcc = 0;
1024             else {
1025                 register char *cp;
1026                 int left, n;
1027
1028                 if (fcc <= 0)
1029                     break;
1030                 fbp = fibuf;
1031
1032               top:
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);
1037                         if (n) {
1038                             left -= n;
1039                             if (left > 0)
1040                                 memcpy(cp, cp + n, left);
1041                             fcc -= n;
1042                             goto top;   /* n^2 */
1043                         }
1044                     }
1045                 obits |= pmask; /* try write */
1046             }
1047         }
1048
1049         if ((obits & pmask) && fcc > 0) {
1050             cc = write(p, fbp, fcc);
1051             if (cc > 0) {
1052                 fcc -= cc;
1053                 fbp += cc;
1054             }
1055         }
1056
1057         if (ibits & pmask) {
1058             pcc = read(p, pibuf, sizeof(pibuf));
1059             pbp = pibuf;
1060             if (pcc < 0 && errno == EWOULDBLOCK)
1061                 pcc = 0;
1062             else if (pcc <= 0)
1063                 break;
1064             else if (pibuf[0] == 0) {
1065                 pbp++, pcc--;
1066                 obits |= fmask; /* try a write */
1067             } else {
1068 #if !defined(AFS_SUN5_ENV)
1069                 if (pkcontrol(pibuf[0])) {
1070                     pibuf[0] |= oobdata[0];
1071                     send(f, &pibuf[0], 1, MSG_OOB);
1072                 }
1073 #endif /* !defined(AFS_SUN5_ENV) */
1074                 pcc = 0;
1075             }
1076         }
1077
1078         if ((obits & fmask) && pcc > 0) {
1079             cc = write(f, pbp, pcc);
1080             if (cc < 0 && errno == EWOULDBLOCK) {
1081                 /* also shouldn't happen */
1082                 sleep(5);
1083                 continue;
1084             }
1085             if (cc > 0) {
1086                 pcc -= cc;
1087                 pbp += cc;
1088             }
1089         }
1090     }
1091 }
1092
1093 #ifdef  AFS_AIX32_ENV
1094 void
1095 cleanup(pid_t pid)
1096 #else
1097 void
1098 cleanup()
1099 #endif
1100 {
1101     char *p;
1102 #ifdef  AFS_HPUX_ENV
1103     char buf[BUFSIZ];
1104     int cc;
1105
1106     fcntl(netp, F_SETFL, O_NDELAY);
1107     if ((cc = read(netp, buf, sizeof buf)) > 0) {
1108         write(netf, buf, cc);
1109     }
1110     {
1111         chmod(master, 0666);
1112         chown(master, 0, 0);
1113         chmod(slave, 0666);
1114         chown(slave, 0, 0);
1115     }
1116 #else
1117 #ifdef  AFS_AIX32_ENV
1118     struct utmp cutmp;
1119     int found = 0, f, t;
1120     int rcode;
1121     off_t offset;
1122
1123     p = line + sizeof("/dev/") - 1;
1124     if (logout(p))
1125         logwtmp(p, "", "");
1126 #ifdef _AIX
1127     (void)acl_set(line, R_ACC | W_ACC | X_ACC, R_ACC | W_ACC | X_ACC,
1128                   R_ACC | W_ACC | X_ACC);
1129 #else
1130     (void)chmod(line, 0666);
1131 #endif /* _AIX */
1132     (void)chown(line, 0, 0);
1133     *p = 'p';
1134 #ifdef _AIX
1135     (void)acl_set(line, R_ACC | W_ACC | X_ACC, R_ACC | W_ACC | X_ACC,
1136                   R_ACC | W_ACC | X_ACC);
1137 #else
1138     (void)chmod(line, 0666);
1139 #endif /* _AIX */
1140 #else
1141     p = line + sizeof("/dev/") - 1;
1142     if (logout(p))
1143         logwtmp(p, "", "");
1144     (void)chmod(line, 0666);
1145     (void)chown(line, 0, 0);
1146     *p = 'p';
1147     (void)chmod(line, 0666);
1148 #endif
1149     (void)chown(line, 0, 0);
1150 #endif
1151     shutdown(netf, 2);
1152     exit(1);
1153 }
1154
1155 fatal(f, msg)
1156      int f;
1157      char *msg;
1158 {
1159     char buf[BUFSIZ];
1160
1161     buf[0] = '\01';             /* error indicator */
1162     (void)sprintf(buf + 1, "rlogind: %s.\r\n", msg);
1163     (void)write(f, buf, strlen(buf));
1164
1165     exit(1);
1166 }
1167
1168 fatalperror(f, msg)
1169      int f;
1170      char *msg;
1171 {
1172     char buf[BUFSIZ];
1173     extern int sys_nerr;
1174     extern char *sys_errlist[];
1175
1176     if ((unsigned)errno < sys_nerr)
1177         (void)sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
1178     else
1179         (void)sprintf(buf, "%s: Error %d", msg, errno);
1180
1181     fatal(f, buf);
1182 }
1183
1184 #ifndef OLD_LOGIN
1185 do_rlogin(host)
1186      char *host;
1187 {
1188
1189     int ru;
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");
1193
1194     if (getuid())
1195         return (-1);
1196     pwd = getpwnam(lusername);
1197     if (pwd == NULL)
1198         return (-1);
1199 #ifdef  AFS_HPUX_ENV
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.
1206      */
1207     s_pwd = (struct s_passwd *)pwd;
1208     if (stat(SECUREPASS, &s_pfile) == 0)
1209         s_pwd = getspwnam(lusername);
1210     if (s_pwd == NULL) {
1211         return (-1);
1212     }
1213 #endif
1214
1215 #ifdef _AIX
1216     if (*pwd->pw_shell == '\0')
1217         pwd->pw_shell = BSHELL;
1218     /* check for disabled logins before */
1219     /* authenticating based on .rhosts  */
1220     if (pwd->pw_uid)
1221         if (checknologin() == 0)
1222             return (-1);
1223 #endif /* _AIX */
1224     ru = ruserok(host, SUPERUSER(pwd), rusername, lusername);
1225     return (ru);
1226 }
1227
1228
1229 getstr(buf, cnt, errmsg)
1230      char *buf;
1231      int cnt;
1232      char *errmsg;
1233 {
1234     char c;
1235
1236     do {
1237         if (read(0, &c, 1) != 1)
1238             exit(1);
1239         if (--cnt < 0)
1240             fatal(1, errmsg);
1241         *buf++ = c;
1242     } while (c != 0);
1243 }
1244
1245 extern char **environ;
1246
1247 #ifdef _AIX
1248 /* POSIX TERMIOS */
1249 speed_t
1250 speeds(speed)
1251      char *speed;
1252 {
1253     if (strcmp(speed, "38400") == 0)
1254         return (B38400);
1255     if (strcmp(speed, "19200") == 0)
1256         return (B19200);
1257     if (strcmp(speed, "9600") == 0)
1258         return (B9600);
1259     if (strcmp(speed, "4800") == 0)
1260         return (B4800);
1261     if (strcmp(speed, "2400") == 0)
1262         return (B2400);
1263     if (strcmp(speed, "1800") == 0)
1264         return (B1800);
1265     if (strcmp(speed, "1200") == 0)
1266         return (B1200);
1267     if (strcmp(speed, "600") == 0)
1268         return (B600);
1269     if (strcmp(speed, "300") == 0)
1270         return (B300);
1271     if (strcmp(speed, "200") == 0)
1272         return (B200);
1273     if (strcmp(speed, "150") == 0)
1274         return (B150);
1275     if (strcmp(speed, "134") == 0)
1276         return (B134);
1277     if (strcmp(speed, "110") == 0)
1278         return (B110);
1279     if (strcmp(speed, "75") == 0)
1280         return (B75);
1281     if (strcmp(speed, "50") == 0)
1282         return (B50);
1283     if (strcmp(speed, "0") == 0)
1284         return (B0);
1285     return (B0);
1286 }
1287 #else
1288 char *speeds[] = {
1289     "0", "50", "75", "110", "134", "150", "200", "300", "600",
1290     "1200", "1800", "2400", "4800", "9600", "19200", "38400",
1291 #ifdef  AFS_HPUX_ENV
1292     "EXTA", "EXTB"
1293 #endif
1294 };
1295
1296 #define NSPEEDS (sizeof(speeds) / sizeof(speeds[0]))
1297 #endif
1298
1299 setup_term(fd)
1300      int fd;
1301 {
1302 #ifndef AFS_OSF_ENV
1303     register char *cp = strchr(term, '/'), **cpp;
1304 #endif
1305 #ifdef  AFS_AIX32_ENV
1306 #ifdef _AIX
1307     /* POSIX TERMIOS */
1308     struct termios termios;
1309 #else /* _AIX */
1310     struct sgttyb sgttyb;
1311 #endif /* _AIX */
1312     char *speed;
1313 #ifdef  AFS_HPUX_ENV
1314     struct termio tp;
1315 #endif
1316
1317 #ifdef _AIX
1318     /* POSIX TERMIOS */
1319     tcgetattr(fd, &termios);
1320 #else /* _AIX */
1321 #ifdef  AFS_HPUX_ENV
1322     ioctl(fd, TCGETA, &tp);
1323 #else
1324     (void)ioctl(fd, TIOCGETP, &sgttyb);
1325 #endif
1326 #endif /* _AIX */
1327     if (cp) {
1328         *cp++ = '\0';
1329         speed = cp;
1330         cp = strchr(speed, '/');
1331         if (cp)
1332             *cp++ = '\0';
1333 #ifdef _AIX
1334         /* POSIX TERMIOS */
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;
1345 #else
1346         termios.c_iflag = IXON | BRKINT | IGNPAR | ISTRIP | ICRNL;
1347         termios.c_cflag = PARENB | CS7 | HUPCL | CREAD;
1348 #endif /* NLS */
1349         termios.c_oflag = OPOST | ONLCR | TAB3;
1350         termios.c_lflag =
1351             ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOKE | ECHOCTL | IEXTEN;
1352         cfsetispeed(&termios, speeds(speed));
1353         cfsetospeed(&termios, speeds(speed));
1354 #else /* _AIX */
1355         for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
1356             if (strcmp(*cpp, speed) == 0) {
1357 #ifdef  AFS_HPUX_ENV
1358                 tp.c_cflag &= ~CBAUD;
1359                 tp.c_cflag |= cpp - speeds;
1360 #else
1361                 sgttyb.sg_ispeed = sgttyb.sg_ospeed = cpp - speeds;
1362 #endif
1363                 break;
1364             }
1365 #endif /* _AIX */
1366     }
1367 #ifdef _AIX
1368     /* POSIX TERMIOS */
1369     tcsetattr(fd, TCSANOW, &termios);
1370 #else /* _AIX */
1371 #ifdef  AFS_HPUX_ENV
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;
1378     tp.c_cflag |= CS8;
1379     tp.c_cc[VMIN] = 1;
1380     tp.c_cc[VTIME] = 0;
1381     tp.c_cc[VEOF] = CEOF;
1382     ioctl(fd, TCSETAF, &tp);
1383 #else
1384     sgttyb.sg_flags = ECHO | CRMOD | ANYP | XTABS;
1385     (void)ioctl(fd, TIOCSETP, &sgttyb);
1386 #endif
1387 #endif /* _AIX */
1388
1389 #else /* AFS_AIX32_ENV */
1390
1391 #ifdef  AFS_OSF_ENV
1392     register char *cp = strchr(term + ENVSIZE, '/');
1393     char *speed;
1394     struct termios tt;
1395
1396     tcgetattr(fd, &tt);
1397     if (cp) {
1398         *cp++ = '\0';
1399         speed = cp;
1400         cp = strchr(speed, '/');
1401         if (cp)
1402             *cp++ = '\0';
1403         cfsetspeed(&tt, atoi(speed));
1404     }
1405
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);
1411 #else
1412     struct sgttyb sgttyb;
1413     char *speed;
1414
1415     (void)ioctl(fd, TIOCGETP, &sgttyb);
1416     if (cp) {
1417         *cp++ = '\0';
1418         speed = cp;
1419         cp = strchr(speed, '/');
1420         if (cp)
1421             *cp++ = '\0';
1422         for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
1423             if (strcmp(*cpp, speed) == 0) {
1424                 sgttyb.sg_ispeed = sgttyb.sg_ospeed = cpp - speeds;
1425                 break;
1426             }
1427     }
1428     sgttyb.sg_flags = ECHO | CRMOD | ANYP | XTABS;
1429     (void)ioctl(fd, TIOCSETP, &sgttyb);
1430 #endif
1431 #endif /* AFS_AIX32_ENV */
1432     env[0] = term;
1433     env[1] = 0;
1434     environ = env;
1435 }
1436
1437 /*
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.
1444  */
1445 local_domain(h)
1446      char *h;
1447 {
1448     char localhost[MAXHOSTNAMELEN];
1449     char *p1, *p2 = strchr(h, '.');
1450 #ifdef  AFS_OSF_ENV
1451     char *topdomain();
1452
1453     localhost[0] = 0;
1454 #endif
1455
1456     (void)gethostname(localhost, sizeof(localhost));
1457 #ifdef  AFS_OSF_ENV
1458     p1 = topdomain(localhost);
1459     p2 = topdomain(h);
1460 #else
1461     p1 = strchr(localhost, '.');
1462 #endif
1463     if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
1464         return (1);
1465     return (0);
1466 }
1467 #endif /* OLD_LOGIN */
1468
1469
1470 #ifdef  AFS_OSF_ENV
1471 char *
1472 topdomain(h)
1473      char *h;
1474 {
1475     register char *p;
1476     char *maybe = NULL;
1477     int dots = 0;
1478
1479     for (p = h + strlen(h); p >= h; p--) {
1480         if (*p == '.') {
1481             if (++dots == 2)
1482                 return (p);
1483             maybe = p;
1484         }
1485     }
1486     return (maybe);
1487 }
1488 #endif
1489
1490
1491 #ifdef _AIX
1492 /*
1493  * NAME: getnonflatname()
1494  *                                                                    
1495  * FUNCTION: gets the name in /etc/passwd and replaces the
1496  *              flattened name that might have been passed in.
1497  *                                                                    
1498  * EXECUTION ENVIRONMENT: static
1499  *                                                                   
1500  * RETURNS: none.
1501  *
1502  */
1503
1504 void
1505 getnonflatname(char *user)
1506 {
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 */
1510     register int siz;
1511     register int members = 0;
1512
1513 #ifndef _KJI
1514     setpwent();
1515
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);
1522             break;
1523         }
1524     }
1525     endpwent();
1526 #endif
1527 }
1528
1529
1530 checknologin()
1531 {
1532     register int fd;
1533
1534     if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) {
1535         return (0);
1536         close(fd);
1537     } else
1538         return (-1);
1539 }
1540
1541
1542 /*
1543  * NAME: loginlog
1544  *                                                                    
1545  * FUNCTION: log the login
1546  *                                                                    
1547  * EXECUTION ENVIRONMENT: static
1548  *
1549  *              record login in utmp and wtmp files
1550  *                                                                   
1551  * RETURNS: void
1552  */
1553
1554 static void
1555 loginlog(user, tty, hostname)
1556      char *user;
1557      char *tty;
1558      char *hostname;
1559 {
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 */
1571
1572     int rcode;
1573
1574     /*
1575      * Initialize a utmp file entry to be filled in and written
1576      * to UTMP_FILE and WTMP_FILE.
1577      */
1578
1579     memset(&utmp, 0, UTSIZ);
1580     up = &utmp;
1581
1582     /*
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.
1587      */
1588
1589     if (dev = strrchr(tty, '/')) {
1590         if (!*(dev + strspn(dev, "/0123456789")))
1591             while (dev != tty && *--dev != '/');
1592
1593         if (*dev == '/')
1594             dev++;
1595
1596         tty = dev;
1597     }
1598
1599     if (tty)
1600         strncpy(up->ut_line, tty, sizeof up->ut_line);
1601
1602     /*
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.
1606      */
1607
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);
1612
1613     if (hostname)
1614         strncpy(up->ut_host, hostname, sizeof up->ut_host);
1615
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.                                     */
1622
1623     if ((f = open(UTMP_FILE, O_RDWR)) >= 0) {
1624         lseek(f, (off_t) 0, SEEK_SET);
1625         rcode = lockf(f, F_LOCK, 0);
1626         t = 0;
1627         while (read(f, (char *)&outmp, UTSIZ) == UTSIZ) {
1628             if ((!strcmp(outmp.ut_line, tty)) && outmp.ut_type == EMPTY) {
1629                 break;
1630             } else
1631                 t++;
1632         }
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);
1637         close(f);
1638     }
1639
1640     /*
1641      * The utmp entry is appended to the wtmp file to maintain a
1642      * log of all login activity.
1643      */
1644     if ((f = open(WTMP_FILE, O_WRONLY | O_APPEND)) >= 0) {
1645         offset = lseek(f, 0L, 2);
1646         if (offset % UTSIZ)
1647             write(f, (char *)up, UTSIZ - (offset % UTSIZ));
1648
1649         write(f, (char *)up, UTSIZ);
1650         close(f);
1651     }
1652
1653 }
1654
1655 #ifdef  KAUTH
1656 #define MAXLOCALTOKENS 4
1657 #define HEADER_SIZE 18
1658
1659 /*
1660  * intkens:
1661  *
1662  * This routine accepts a token on the specified file handle;
1663  * The input format for a token is:
1664  *
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]
1676  *
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
1682  * whole packet.
1683  */
1684
1685 extern int errno;
1686
1687 intokens(s)
1688      int s;
1689 {
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;
1695
1696     if (setpag()) {
1697         perror("setpag");
1698         exit(1);
1699     }
1700
1701 /*
1702 **      Read in the first two fields.
1703 */
1704
1705     readed = 0;
1706     errno = 0;
1707     while (readed < HEADER_SIZE) {
1708         count = read(s, (char *)((int)buf + readed), HEADER_SIZE - readed);
1709         if (count <= 0) {
1710             perror("intokens read");
1711             exit(1);
1712         }
1713         readed = readed + count;
1714     }
1715
1716     count = readed;
1717     bp = buf;
1718
1719     /* (1) Version # */
1720     for (index = 0; (index + bp - buf) < count && bp[index] != ','; index++);
1721
1722     if ((index + bp - buf) == count) {
1723         fprintf(stderr, "overran buffer while searching for version #\n");
1724         exit(1);
1725     }
1726
1727     if (bp[index] != ',') {
1728         fprintf(stderr, "Didn't stop on a comma, searching for version #\n");
1729         exit(1);
1730     }
1731
1732     bp[index] = '\0';
1733
1734     sscanf(bp, "%u", &version);
1735
1736     if (version != 2) {
1737         fprintf(stderr, "intokens: incompatible version encountered: %d\n",
1738                 version);
1739         exit(1);
1740     }
1741
1742     bp = bp + index + 1;
1743
1744     /* (2) Length # */
1745     for (index = 0; (index + bp - buf) < count && bp[index] != ','; index++);
1746
1747     if ((index + bp - buf) == count) {
1748         fprintf(stderr, "overran buffer while searching for length #\n");
1749         exit(1);
1750     }
1751
1752     if (bp[index] != ',') {
1753         fprintf(stderr, "Didn't stop on a comma, searching for length\n");
1754         exit(1);
1755     }
1756
1757     bp[index] = '\0';
1758
1759     sscanf(bp, "%u", &length);
1760
1761     bp = bp + index + 1;
1762
1763     errno = 0;
1764     while (readed < length) {
1765         count = read(s, (char *)((int)buf + readed), length - readed);
1766         if (count <= 0) {
1767             perror("intokens read");
1768             exit(1);
1769         }
1770         readed = readed + count;
1771     }
1772
1773     count = readed;
1774
1775 /*
1776 **      Terminate looping through the list of tokens when we hit a null byte.
1777 */
1778     while (*bp) {
1779         /* (3) startTime */
1780
1781         for (index = 0; (index + bp - buf) < count && bp[index] != ',';
1782              index++);
1783
1784         if ((index + bp - buf) == count) {
1785             fprintf(stderr,
1786                     "overran buffer while searching for startTime #\n");
1787             exit(1);
1788         }
1789
1790         if (bp[index] != ',') {
1791             fprintf(stderr,
1792                     "Didn't stop on a comma, searching for startTime #\n");
1793             exit(1);
1794         }
1795
1796         bp[index] = '\0';
1797
1798         sscanf(bp, "%u", &token.startTime);
1799
1800         /* (4) endTime */
1801
1802         bp = bp + index + 1;
1803
1804         for (index = 0; (index + bp - buf) < count && bp[index] != ',';
1805              index++);
1806
1807         if ((index + bp - buf) == count) {
1808             fprintf(stderr, "overran buffer while searching for endTime #\n");
1809             exit(1);
1810         }
1811
1812         if (bp[index] != ',') {
1813             fprintf(stderr,
1814                     "Didn't stop on a comma, searching for endTime #\n");
1815             exit(1);
1816         }
1817
1818         bp[index] = '\0';
1819
1820         sscanf(bp, "%u", &token.endTime);
1821
1822         /* (5) sessionKey */
1823
1824         bp = bp + index + 1;
1825         memcpy(token.sessionKey.data, bp, 8);
1826
1827         /* (6) kvno */
1828
1829         bp = bp + 8;
1830         for (index = 0; (index + bp - buf) < count && bp[index] != ',';
1831              index++);
1832
1833         if ((index + bp - buf) == count) {
1834             fprintf(stderr, "overran buffer while searching for kvno\n");
1835             exit(1);
1836         }
1837
1838         if (bp[index] != ',') {
1839             fprintf(stderr, "Didn't stop on a comma, searching for kvno\n");
1840             exit(1);
1841         }
1842
1843         bp[index] = '\0';
1844
1845         token.kvno = atoi(bp);
1846
1847         /* (7) ticketLen */
1848
1849         bp = bp + index + 1;
1850
1851         for (index = 0; (index + bp - buf) < count && bp[index] != ',';
1852              index++);
1853
1854         if ((index + bp - buf) == count) {
1855             fprintf(stderr, "overran buffer while searching for ticketLen\n");
1856             exit(1);
1857         }
1858
1859         if (bp[index] != ',') {
1860             fprintf(stderr,
1861                     "Didn't stop on a comma, searching for ticketLen\n");
1862             exit(1);
1863         }
1864
1865         bp[index] = '\0';
1866
1867         sscanf(bp, "%u", &token.ticketLen);
1868
1869         /* (8) ticketLen */
1870
1871         bp = bp + index + 1;
1872
1873         if ((index + bp - buf) + token.ticketLen > count) {
1874             fprintf(stderr, "overran buffer while copying ticket\n");
1875             exit(1);
1876         }
1877
1878         memcpy(token.ticket, bp, token.ticketLen);
1879
1880         bp = bp + token.ticketLen;
1881
1882         /* (9) User name */
1883
1884         for (index = 0; (index + bp - buf) < count && bp[index] != ',';
1885              index++);
1886
1887         if ((index + bp - buf) == count) {
1888             fprintf(stderr, "overran buffer while searching for Cell Name\n");
1889             exit(1);
1890         }
1891
1892         bp[index] = '\0';
1893         tclient.instance[0] = '\0';
1894         strncpy(tclient.name, bp, MAXKTCNAMELEN);
1895
1896         /* (10) Cell name */
1897
1898         bp = bp + index + 1;
1899
1900         for (index = 0; (index + bp - buf) < count && bp[index] != ',';
1901              index++);
1902
1903         if ((index + bp - buf) == count) {
1904             fprintf(stderr, "overran buffer while searching for end\n");
1905             exit(1);
1906         }
1907
1908         bp[index] = '\0';
1909         strncpy(tclient.cell, bp, MAXKTCREALMLEN);
1910         bp = bp + index + 1;
1911
1912         strcpy(tserver.name, "afs");
1913         tserver.instance[0] = '\0';
1914         strncpy(tserver.cell, tclient.cell, MAXKTCREALMLEN);
1915
1916         if (ktc_SetToken(&tserver, &token, &tclient, 0)) {
1917             fprintf(stderr, "intokens: ktc_SetToken failed for %s\n",
1918                     tclient.cell);
1919         }
1920     }
1921     return (0);
1922 }
1923 #endif /* KAUTH */
1924 #endif /* _AIX */
1925
1926 #ifdef  AFS_HPUX_ENV
1927 #include <sys/stat.h>
1928 #include <fcntl.h>
1929 #include <dirent.h>
1930 #include <stdio.h>
1931
1932 # define        MAX_PTY_LEN     MAXPATHLEN+1
1933 # define        CLONE_DRV       "/dev/ptym/clone"
1934
1935 /*
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.
1940 */
1941 #ifdef __hp9000s300
1942 #define PTY_MASTER_MAJOR_NUMBER 16
1943 #endif
1944 #ifdef __hp9000s800
1945 #define PTY_MASTER_MAJOR_NUMBER 16
1946 #endif
1947
1948 struct stat stb;
1949 struct stat m_stbuf;            /* stat buffer for master pty */
1950 struct stat s_stbuf;            /* stat buffer for slave pty */
1951
1952 /*
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
1957 */
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];
1962
1963 /*
1964 **      oltrs   --      legal first char of pty name (letter) (old style)
1965 **      onums   --      legal second char of pty name (number) for namespace 1
1966 **              (old style)
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
1970 **              space 3. 
1971 */
1972 char oltrs[] = "onmlkjihgfecbazyxwvutsrqp";
1973 char onums[] = "0123456789abcdef";
1974 char ltrs[] = "pqrstuvwxyzabcefghijklmno";
1975 char nums[] = "0123456789";
1976
1977 /*
1978 **      getpty()        --      get a pty pair
1979 **
1980 **      Input   --      none
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
1987 **
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.
1991 */
1992
1993 /*
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.
2011 */
2012
2013 /*
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!
2026  *
2027  * This is necessary due to HP's implementation of 4.2BSD job control.
2028  */
2029
2030 /*
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.
2035  *
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. |
2047  *                      |     15|  ttypf|                  |
2048  *                      |     16|  ttyq0|                  |
2049  *                      |      :|      :|                  |
2050  *                      |    175|  ttyzf|                  |
2051  *                      |    176|  ttya0|                  |
2052  *                      |      :|      :|                  |
2053  *                      |    223|  ttycf|                  |
2054  *                      |    224|  ttye0|                  |
2055  *                      |      :|      :|                  |
2056  *                      |    399|  ttyof|  Total 400       |
2057  *                      |----------------------------------|
2058  *                      |    400| ttyp00|  Modulo hundred  |
2059  *                      |      :|      :|  decimal repr.   |
2060  *                      |    499| ttyp99|                  |
2061  *                      |    500| ttyq00|                  |
2062  *                      |      :|      :|                  |
2063  *                      |   1499| ttyz99|                  |
2064  *                      |   1500| ttya00|                  |
2065  *                      |      :|      :|                  |
2066  *                      |   1799| ttyc99|                  |
2067  *                      |   1800| ttye00|                  |
2068  *                      |      :|      :|                  |
2069  *                      |   2899| ttyo99|  Total 2500      |
2070  *                      |----------------------------------|
2071  *                      |   2900|ttyp000|  Modulo thousand |
2072  *                      |      :|      :|  decimal repr.   |
2073  *                      |   3899|ttyp999|                  |
2074  *                      |   4900|ttyq000|                  |
2075  *                      |      :|      :|                  |
2076  *                      |  12899|ttyz999|                  |
2077  *                      |  13900|ttya000|                  |
2078  *                      |      :|      :|                  |
2079  *                      |  16899|ttyc999|                  |
2080  *                      |  16900|ttye000|                  |
2081  *                      |      :|      :|                  |
2082  *                      |  27899|ttyo999|  Total 25000     |
2083  *                      |  27900|       |     invalid      |
2084  *                      ------------------------------------
2085  */
2086
2087 /*
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 ...
2091 */
2092 getpty(mfd, mname, sname)
2093      int *mfd;
2094      char *mname, *sname;
2095 {
2096     int loc, ltr, num, num2;
2097     register int mlen, slen;
2098     char *s, *s_path;
2099
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);
2108         return 0;
2109     }
2110
2111
2112     for (loc = 0; ptymdirs[loc] != NULL; loc++) {
2113         if (stat(ptymdirs[loc], &stb))  /* no directory ... */
2114             continue;           /*  so try next one */
2115
2116         /*      first, try the 3rd name space ptyp000-ptyo999  */
2117         /*      generate the master pty path    */
2118         if (namesp3(mfd, mname, sname, loc) == 0) {
2119             return 0;
2120         }
2121
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);
2127
2128         /*      generate the slave pty path     */
2129         (void)strcpy(ptysloc, ptysdirs[loc]);
2130         (void)strcat(ptysloc, "ttyLNN");
2131         slen = strlen(ptysloc);
2132
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 */
2139
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 */
2146
2147                     ptysloc[slen - 3] = ltrs[ltr];
2148                     ptysloc[slen - 2] = nums[num];
2149                     ptysloc[slen - 1] = nums[num2];
2150
2151                     /*
2152                      **     NOTE:   changed to only stat the slave device; see
2153                      **     comments all over the place about job control ...
2154                      */
2155                     if (fstat(*mfd, &m_stbuf) < 0
2156                         || stat(ptysloc, &s_stbuf) < 0) {
2157                         close(*mfd);
2158                         continue;
2159                     }
2160                     /*
2161                      **     sanity check: are the minor numbers the same??
2162                      */
2163                     if (minor(m_stbuf.st_rdev) != minor(s_stbuf.st_rdev)) {
2164                         close(*mfd);
2165                         continue;       /* try next num */
2166                     }
2167
2168                     /*      else we got both a master and a slave pty       */
2169                   got_one:(void)chmod(ptysloc, 0622);
2170                     /* not readable */
2171                     if (mname != NULL)
2172                         (void)strcpy(mname, ptymloc);
2173                     if (sname != NULL)
2174                         (void)strcpy(sname, ptysloc);
2175                     return 0;   /* return OK    */
2176                 }
2177         }
2178
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);
2185
2186         /*      generate the slave pty path     */
2187         (void)strcpy(ptysloc, ptysdirs[loc]);
2188         (void)strcat(ptysloc, "ttyLN");
2189         slen = strlen(ptysloc);
2190
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 */
2196
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 */
2201
2202                 ptysloc[slen - 2] = oltrs[ltr];
2203                 ptysloc[slen - 1] = onums[num];
2204
2205                 /*
2206                  **     NOTE:   changed to only stat the slave device; see
2207                  **     comments all over the place about job control ...
2208                  */
2209                 if (fstat(*mfd, &m_stbuf) < 0 || stat(ptysloc, &s_stbuf) < 0) {
2210                     close(*mfd);
2211                     continue;
2212                 }
2213                 /*
2214                  **     sanity check: are the minor numbers the same??
2215                  */
2216                 if (minor(m_stbuf.st_rdev) != minor(s_stbuf.st_rdev)) {
2217                     close(*mfd);
2218                     continue;   /* try next num */
2219                 }
2220
2221                 /*      else we got both a master and a slave pty       */
2222                 goto got_one;
2223             }
2224         }
2225     }
2226     /* we failed in our search--we now try the slow brute-force method */
2227     for (loc = 0; ptymdirs[loc] != NULL; loc++) {
2228         DIR *dirp;
2229         struct dirent *dp;
2230
2231         if ((dirp = opendir(ptymdirs[loc])) == NULL)    /* no directory ... */
2232             continue;           /*  so try next one */
2233
2234         (void)strcpy(ptymloc, ptymdirs[loc]);
2235         mlen = strlen(ptymloc);
2236         (void)strcpy(ptysloc, ptysdirs[loc]);
2237         slen = strlen(ptysloc);
2238
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);
2243
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)
2247                 continue;
2248
2249             if ((*mfd = open(ptymloc, O_RDWR)) < 0)     /* busy master      */
2250                 continue;       /* try next entry */
2251
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';
2256
2257             if (stat(ptysloc, &s_stbuf) < 0
2258                 || minor(m_stbuf.st_rdev) != minor(s_stbuf.st_rdev)) {
2259                 close(*mfd);
2260                 continue;
2261             }
2262             goto got_one;
2263         }
2264
2265         closedir(dirp);
2266     }
2267
2268     /*  we were not able to get the master/slave pty pair       */
2269     return -1;
2270 }
2271
2272 namesp3(mfd, mname, sname, loc)
2273      int *mfd, loc;
2274      char *mname, *sname;
2275 {
2276     int ltr, num, num2, num3;
2277     register int mlen, slen;
2278
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);
2284
2285     /*      generate the slave pty path     */
2286     (void)strcpy(ptysloc, ptysdirs[loc]);
2287     (void)strcat(ptysloc, "ttyLNNN");
2288     slen = strlen(ptysloc);
2289
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 */
2297
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 */
2306
2307                     ptysloc[slen - 4] = ltrs[ltr];
2308                     ptysloc[slen - 3] = nums[num];
2309                     ptysloc[slen - 2] = nums[num2];
2310                     ptysloc[slen - 1] = nums[num3];
2311
2312                     /*
2313                      **     NOTE:   changed to only stat the slave device; see
2314                      **     comments all over the place about job control ...
2315                      */
2316                     if (fstat(*mfd, &m_stbuf) < 0
2317                         || stat(ptysloc, &s_stbuf) < 0) {
2318                         close(*mfd);
2319                         continue;
2320                     }
2321                     /*
2322                      **     sanity check: are the minor numbers the same??
2323                      */
2324                     if (minor(m_stbuf.st_rdev) != minor(s_stbuf.st_rdev)) {
2325                         close(*mfd);
2326                         continue;       /* try next num */
2327                     }
2328
2329                     /*      else we got both a master and a slave pty       */
2330                     (void)chmod(ptysloc, 0622); /* not readable */
2331                     if (mname != NULL)
2332                         (void)strcpy(mname, ptymloc);
2333                     if (sname != NULL)
2334                         (void)strcpy(sname, ptysloc);
2335                     return 0;   /* return OK    */
2336                 }
2337     }
2338     return 1;
2339 }
2340 #endif