Print this page
14249 pseudo-terminal nomenclature should reflect POSIX
Change-Id: Ib4a3cef899ff4c71b09cb0dc6878863c5e8357bc


 225 extern int krb5_setenv(const char *, const char *, int);
 226 /* need to know what FD to use to talk to the crypto module */
 227 static int cryptmod_fd = -1;
 228 
 229 #define LOGIN_PROGRAM "/bin/login"
 230 
 231 /*
 232  * State for recv fsm
 233  */
 234 #define TS_DATA         0       /* base state */
 235 #define TS_IAC          1       /* look for double IAC's */
 236 #define TS_CR           2       /* CR-LF ->'s CR */
 237 #define TS_SB           3       /* throw away begin's... */
 238 #define TS_SE           4       /* ...end's (suboption negotiation) */
 239 #define TS_WILL         5       /* will option negotiation */
 240 #define TS_WONT         6       /* wont " */
 241 #define TS_DO           7       /* do " */
 242 #define TS_DONT         8       /* dont " */
 243 
 244 static int      ncc;
 245 static int      master;         /* master side of pty */
 246 static int      pty;            /* side of pty that gets ioctls */
 247 static int      net;
 248 static int      inter;
 249 extern char **environ;
 250 static char     *line;
 251 static int      SYNCHing = 0;           /* we are in TELNET SYNCH mode */
 252 static int      state = TS_DATA;
 253 
 254 static int env_ovar = -1;       /* XXX.sparker */
 255 static int env_ovalue = -1;     /* XXX.sparker */
 256 static char pam_svc_name[64];
 257 static boolean_t        telmod_init_done = B_FALSE;
 258 
 259 static void     doit(int, struct sockaddr_storage *);
 260 static void     willoption(int);
 261 static void     wontoption(int);
 262 static void     dooption(int);
 263 static void     dontoption(int);
 264 static void     fatal(int, char *);
 265 static void     fatalperror(int, char *, int);


2737 doit(int f, struct sockaddr_storage *who)
2738 {
2739         char *host;
2740         char host_name[MAXHOSTNAMELEN];
2741         int p, t, tt;
2742         struct sgttyb b;
2743         int     ptmfd;  /* fd of logindmux connected to pty */
2744         int     netfd;  /* fd of logindmux connected to netf */
2745         struct  stat    buf;
2746         struct  protocol_arg    telnetp;
2747         struct  strioctl        telnetmod;
2748         struct  envlist *env, *next;
2749         int     nsize = 0;
2750         char abuf[INET6_ADDRSTRLEN];
2751         struct sockaddr_in *sin;
2752         struct sockaddr_in6 *sin6;
2753         socklen_t wholen;
2754         char username[MAXUSERNAMELEN];
2755         int len;
2756         uchar_t passthru;
2757         char *slavename;
2758 
2759         if ((p = open("/dev/ptmx", O_RDWR | O_NOCTTY)) == -1) {
2760                 fatalperror(f, "open /dev/ptmx", errno);
2761         }
2762         if (grantpt(p) == -1)
2763                 fatal(f, "could not grant slave pty");
2764         if (unlockpt(p) == -1)
2765                 fatal(f, "could not unlock slave pty");
2766         if ((slavename = ptsname(p)) == NULL)
2767                 fatal(f, "could not enable slave pty");
2768         (void) dup2(f, 0);
2769         if ((t = open(slavename, O_RDWR | O_NOCTTY)) == -1)
2770                 fatal(f, "could not open slave pty");
2771         if (ioctl(t, I_PUSH, "ptem") == -1)
2772                 fatalperror(f, "ioctl I_PUSH ptem", errno);
2773         if (ioctl(t, I_PUSH, "ldterm") == -1)
2774                 fatalperror(f, "ioctl I_PUSH ldterm", errno);
2775         if (ioctl(t, I_PUSH, "ttcompat") == -1)
2776                 fatalperror(f, "ioctl I_PUSH ttcompat", errno);
2777 
2778         line = slavename;
2779 
2780         pty = t;
2781 
2782         if (ioctl(t, TIOCGETP, &b) == -1)
2783                 syslog(LOG_INFO, "ioctl TIOCGETP pty t: %m\n");
2784         b.sg_flags = O_CRMOD|O_XTABS|O_ANYP;
2785         /* XXX - ispeed and ospeed must be non-zero */
2786         b.sg_ispeed = B38400;
2787         b.sg_ospeed = B38400;
2788         if (ioctl(t, TIOCSETN, &b) == -1)
2789                 syslog(LOG_INFO, "ioctl TIOCSETN pty t: %m\n");
2790         if (ioctl(pty, TIOCGETP, &b) == -1)
2791                 syslog(LOG_INFO, "ioctl TIOCGETP pty pty: %m\n");
2792         b.sg_flags &= ~O_ECHO;
2793         if (ioctl(pty, TIOCSETN, &b) == -1)
2794                 syslog(LOG_INFO, "ioctl TIOCSETN pty pty: %m\n");
2795 
2796         if (who->ss_family == AF_INET) {
2797                 char *addrbuf = NULL;
2798                 char *portbuf = NULL;


3022 
3023         /*
3024          * Figure out the device number of the net's mux fd, and pass that
3025          * to the ptm's mux.
3026          */
3027         if (fstat(netfd, &buf) < 0) {
3028                 fatalperror(f, "fstat netfd failed", errno);
3029         }
3030         telnetp.dev = buf.st_rdev;
3031         telnetp.flag = 1;
3032 
3033         telnetmod.ic_cmd = LOGDMX_IOC_QEXCHANGE;
3034         telnetmod.ic_timout = -1;
3035         telnetmod.ic_len = sizeof (struct protocol_arg);
3036         telnetmod.ic_dp = (char *)&telnetp;
3037 
3038         if (ioctl(ptmfd, I_STR, &telnetmod) < 0)
3039                 fatal(netfd, "ioctl LOGDMX_IOC_QEXCHANGE of ptmfd failed\n");
3040 
3041         net = netfd;
3042         master = ptmfd;
3043         cryptmod_fd = netfd;
3044 
3045         /*
3046          * Show banner that getty never gave, but
3047          * only if the user did not automatically authenticate.
3048          */
3049         if (getenv("USER") == NULL && auth_status < AUTH_USER)
3050                 showbanner();
3051 
3052         /*
3053          * If the user automatically authenticated with Kerberos
3054          * we must set the service name that PAM will use.  We
3055          * need to do it BEFORE the child fork so that 'cleanup'
3056          * in the parent can call the PAM cleanup stuff with the
3057          * same PAM service that /bin/login will use to authenticate
3058          * this session.
3059          */
3060         if (auth_level >= 0 && auth_status >= AUTH_USER &&
3061             (AuthenticatingUser != NULL) && strlen(AuthenticatingUser)) {
3062                 (void) strcpy(pam_svc_name, "ktelnet");


3083         if (!myopts[TELOPT_ECHO]) {
3084             dooption(TELOPT_ECHO);
3085         }
3086 
3087         /*
3088          * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
3089          * because 4.2 clients are unable to deal with TCP urgent data.
3090          *
3091          * To find out, we send out a "DO ECHO".  If the remote system
3092          * answers "WILL ECHO" it is probably a 4.2 client, and we note
3093          * that fact ("WILL ECHO" ==> that the client will echo what
3094          * WE, the server, sends it; it does NOT mean that the client will
3095          * echo the terminal input).
3096          */
3097         send_do(TELOPT_ECHO);
3098         remopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK;
3099 
3100         if ((pid = fork()) < 0)
3101                 fatalperror(netfd, "fork", errno);
3102         if (pid)
3103                 telnet(net, master);
3104         /*
3105          * The child process needs to be the session leader
3106          * and have the pty as its controlling tty.  Thus we need
3107          * to re-open the slave side of the pty no without
3108          * the O_NOCTTY flag that we have been careful to
3109          * use up to this point.
3110          */
3111         (void) setsid();
3112 
3113         tt = open(line, O_RDWR);
3114         if (tt < 0)
3115                 fatalperror(netfd, line, errno);
3116         (void) close(netfd);
3117         (void) close(ptmfd);
3118         (void) close(f);
3119         (void) close(p);
3120         (void) close(t);
3121         if (tt != 0)
3122                 (void) dup2(tt, 0);
3123         if (tt != 1)
3124                 (void) dup2(tt, 1);
3125         if (tt != 2)
3126                 (void) dup2(tt, 2);
3127         if (tt > 2)


3175 
3176         /* If the current auth status is less than the required level, exit */
3177         if (auth_status < auth_level) {
3178                 fatal(net, "Authentication failed\n");
3179                 exit(EXIT_FAILURE);
3180         }
3181 
3182         /*
3183          * If AUTH_VALID (proper authentication REQUIRED and we have
3184          * a krb5_name), exec '/bin/login', make sure it uses the
3185          * correct PAM service name (pam_svc_name). If possible,
3186          * make sure the krb5 authenticated user's name (krb5_name)
3187          * is in the PAM REPOSITORY for krb5.
3188          */
3189         if (auth_level >= 0 &&
3190             (auth_status == AUTH_VALID || auth_status == AUTH_USER) &&
3191             ((krb5_name != NULL) && strlen(krb5_name)) &&
3192             ((AuthenticatingUser != NULL) && strlen(AuthenticatingUser))) {
3193                 (void) execl(LOGIN_PROGRAM, "login",
3194                             "-p",
3195                             "-d", slavename,
3196                             "-h", host,
3197                             "-u", krb5_name,
3198                             "-s", pam_svc_name,
3199                             "-R", KRB5_REPOSITORY_NAME,
3200                             AuthenticatingUser, 0);
3201         } else if (auth_level >= 0 &&
3202                 auth_status >= AUTH_USER &&
3203                 (((AuthenticatingUser != NULL) && strlen(AuthenticatingUser)) ||
3204                 getenv("USER"))) {
3205                 /*
3206                  * If we only know the name but not the principal,
3207                  * login will have to authenticate further.
3208                  */
3209                 (void) execl(LOGIN_PROGRAM, "login",
3210                     "-p",
3211                     "-d", slavename,
3212                     "-h", host,
3213                     "-s", pam_svc_name, "--",
3214                     (AuthenticatingUser != NULL ? AuthenticatingUser :
3215                         getenv("USER")), 0);
3216 
3217         } else /* default, no auth. info available, login does it all */ {
3218                 (void) execl(LOGIN_PROGRAM, "login",
3219                     "-p", "-h", host, "-d", slavename, "--",
3220                     getenv("USER"), 0);
3221         }
3222 
3223         fatalperror(netfd, LOGIN_PROGRAM, errno);
3224         /*NOTREACHED*/
3225 }
3226 
3227 static void
3228 fatal(int f, char *msg)
3229 {
3230         char buf[BUFSIZ];
3231 
3232         (void) snprintf(buf, sizeof (buf), "telnetd: %s.\r\n", msg);
3233         (void) write(f, buf, strlen(buf));
3234         exit(EXIT_FAILURE);
3235         /*NOTREACHED*/
3236 }
3237 
3238 static void
3239 fatalperror(int f, char *msg, int errnum)
3240 {
3241         char buf[BUFSIZ];
3242 
3243         (void) snprintf(buf, sizeof (buf),
3244                         "%s: %s\r\n", msg, strerror(errnum));
3245         fatal(f, buf);
3246         /*NOTREACHED*/
3247 }
3248 
3249 /*
3250  * Main loop.  Select from pty and network, and
3251  * hand data to telnet receiver finite state machine
3252  * when it receives telnet protocol. Regular data
3253  * flow between pty and network takes place through
3254  * inkernel telnet streams module (telmod).
3255  */
3256 static void
3257 telnet(int net, int master)
3258 {
3259         int on = 1;
3260         char mode;
3261         struct  strioctl        telnetmod;
3262         int     nsize = 0;
3263         char    binary_in = 0;
3264         char binary_out = 0;
3265 
3266         if (ioctl(net, FIONBIO, &on) == -1)
3267                 syslog(LOG_INFO, "ioctl FIONBIO net: %m\n");
3268         if (ioctl(master, FIONBIO, &on) == -1)
3269                 syslog(LOG_INFO, "ioctl FIONBIO pty p: %m\n");
3270         (void) signal(SIGTSTP, SIG_IGN);
3271         (void) signal(SIGCHLD, (void (*)())cleanup);
3272         (void) setpgrp();
3273 
3274         /*
3275          * Call telrcv() once to pick up anything received during
3276          * terminal type negotiation.
3277          */
3278         telrcv();
3279 
3280         netflush();
3281         ptyflush();
3282 
3283         for (;;) {
3284                 fd_set ibits, obits, xbits;
3285                 int c;
3286 
3287                 if (ncc < 0)
3288                         break;
3289 
3290                 FD_ZERO(&ibits);
3291                 FD_ZERO(&obits);
3292                 FD_ZERO(&xbits);
3293 
3294                 /*
3295                  * If we couldn't flush all our output to the network,
3296                  * keep checking for when we can.
3297                  */
3298                 if (nfrontp - nbackp)
3299                         FD_SET(net, &obits);
3300                 /*
3301                  * Never look for input if there's still
3302                  * stuff in the corresponding output buffer
3303                  */
3304                 if (pfrontp - pbackp) {
3305                         FD_SET(master, &obits);
3306                 } else {
3307                         FD_SET(net, &ibits);
3308                 }
3309                 if (!SYNCHing) {
3310                         FD_SET(net, &xbits);
3311                 }
3312 
3313 #define max(x, y)       (((x) < (y)) ? (y) : (x))
3314 
3315                 /*
3316                  * make an ioctl to telnet module (net side) to send
3317                  * binary mode of telnet daemon. binary_in and
3318                  * binary_out are 0 if not in binary mode.
3319                  */
3320                 if (binary_in != myopts[TELOPT_BINARY] ||
3321                     binary_out != remopts[TELOPT_BINARY]) {
3322 
3323                         mode = 0;
3324                         if (myopts[TELOPT_BINARY] != OPT_NO)
3325                                 mode |= TEL_BINARY_IN;


3373 
3374                                 netip = netibuf;
3375                                 (void) memset(netibuf, 0, netibufsize);
3376 
3377                                 ncc = 0;
3378                         }
3379                 } else {
3380                         /*
3381                          * state not changed to TS_DATA and hence, more to read
3382                          * send ioctl to get one more message block.
3383                          */
3384                         telnetmod.ic_cmd = TEL_IOC_GETBLK;
3385                         telnetmod.ic_timout = -1;
3386                         telnetmod.ic_len = 0;
3387                         telnetmod.ic_dp = NULL;
3388 
3389                         if (ioctl(net, I_STR, &telnetmod) < 0)
3390                                 fatal(net, "ioctl TEL_IOC_GETBLK failed\n");
3391                 }
3392 
3393                 if ((c = select(max(net, master) + 1, &ibits, &obits, &xbits,
3394                     (struct timeval *)0)) < 1) {
3395                         if (c == -1) {
3396                                 if (errno == EINTR) {
3397                                         continue;
3398                                 }
3399                         }
3400                         (void) sleep(5);
3401                         continue;
3402                 }
3403 
3404                 /*
3405                  * Any urgent data?
3406                  */
3407                 if (FD_ISSET(net, &xbits)) {
3408                         SYNCHing = 1;
3409                 }
3410 
3411                 /*
3412                  * Something to read from the network...
3413                  */
3414                 if (FD_ISSET(net, &ibits)) {
3415                     ncc = read(net, netibuf, netibufsize);
3416                     if (ncc < 0 && errno == EWOULDBLOCK)
3417                         ncc = 0;
3418                     else {
3419                         if (ncc <= 0) {
3420                             break;
3421                         }
3422                         netip = netibuf;
3423                     }
3424                 }
3425 
3426                 if (FD_ISSET(net, &obits) && (nfrontp - nbackp) > 0)
3427                         netflush();
3428                 if (ncc > 0)
3429                         telrcv();
3430                 if (FD_ISSET(master, &obits) && (pfrontp - pbackp) > 0)
3431                         ptyflush();
3432         }
3433         cleanup(0);
3434 }
3435 
3436 static void
3437 telrcv(void)
3438 {
3439         int c;
3440 
3441         while (ncc > 0) {
3442                 if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
3443                         return;
3444                 c = *netip & 0377;
3445                 /*
3446                  * Once we hit data, we want to transition back to
3447                  * in-kernel processing.  However, this code is shared
3448                  * by getterminaltype()/ttloop() which run before the
3449                  * in-kernel plumbing is available.  So if we are still
3450                  * processing the initial option negotiation, even TS_DATA


4262 {
4263         struct sgttyb b;
4264         struct tchars tchars;
4265 
4266         ptyflush();     /* half-hearted */
4267         (void) ioctl(pty, TIOCGETP, &b);
4268         if (b.sg_flags & O_RAW) {
4269                 *pfrontp++ = '\0';
4270                 return;
4271         }
4272         *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
4273                 '\034' : tchars.t_quitc;
4274 }
4275 
4276 static void
4277 ptyflush(void)
4278 {
4279         int n;
4280 
4281         if ((n = pfrontp - pbackp) > 0)
4282                 n = write(master, pbackp, n);
4283         if (n < 0)
4284                 return;
4285         pbackp += n;
4286         if (pbackp == pfrontp)
4287                 pbackp = pfrontp = ptyobuf;
4288 }
4289 
4290 /*
4291  * nextitem()
4292  *
4293  *      Return the address of the next "item" in the TELNET data
4294  * stream.  This will be the address of the next character if
4295  * the current address is a user data character, or it will
4296  * be the address of the character following the TELNET command
4297  * if the current address is a TELNET IAC ("I Am a Command")
4298  * character.
4299  */
4300 
4301 static char *
4302 nextitem(char *current)


4430                 return;
4431         }
4432 
4433         nbackp += n;
4434 
4435         if (nbackp >= neturg) {
4436                 neturg = 0;
4437         }
4438         if (nbackp == nfrontp) {
4439                 nbackp = nfrontp = netobuf;
4440         }
4441 }
4442 
4443 /* ARGSUSED */
4444 static void
4445 cleanup(int signum)
4446 {
4447         /*
4448          * If the TEL_IOC_ENABLE ioctl hasn't completed, then we need to
4449          * handle closing differently.  We close "net" first and then
4450          * "master" in that order.  We do close(net) first because
4451          * we have no other way to disconnect forwarding between the network
4452          * and master.  So by issuing the close()'s we ensure that no further
4453          * data rises from TCP.  A more complex fix would be adding proper
4454          * support for throwing a "stop" switch for forwarding data between
4455          * logindmux peers.  It's possible to block in the close of the tty
4456          * while the network still receives data and the telmod module is
4457          * TEL_STOPPED.  A denial-of-service attack generates this case,
4458          * see 4102102.
4459          */
4460 
4461         if (!telmod_init_done) {
4462                 (void) close(net);
4463                 (void) close(master);
4464         }
4465         rmut();
4466 
4467         exit(EXIT_FAILURE);
4468 }
4469 
4470 static void
4471 rmut(void)
4472 {
4473         pam_handle_t    *pamh;
4474         struct utmpx *up;
4475         char user[sizeof (up->ut_user) + 1];
4476         char ttyn[sizeof (up->ut_line) + 1];
4477         char rhost[sizeof (up->ut_host) + 1];
4478 
4479         /* while cleaning up don't allow disruption */
4480         (void) signal(SIGCHLD, SIG_IGN);
4481 
4482         setutxent();
4483         while (up = getutxent()) {




 225 extern int krb5_setenv(const char *, const char *, int);
 226 /* need to know what FD to use to talk to the crypto module */
 227 static int cryptmod_fd = -1;
 228 
 229 #define LOGIN_PROGRAM "/bin/login"
 230 
 231 /*
 232  * State for recv fsm
 233  */
 234 #define TS_DATA         0       /* base state */
 235 #define TS_IAC          1       /* look for double IAC's */
 236 #define TS_CR           2       /* CR-LF ->'s CR */
 237 #define TS_SB           3       /* throw away begin's... */
 238 #define TS_SE           4       /* ...end's (suboption negotiation) */
 239 #define TS_WILL         5       /* will option negotiation */
 240 #define TS_WONT         6       /* wont " */
 241 #define TS_DO           7       /* do " */
 242 #define TS_DONT         8       /* dont " */
 243 
 244 static int      ncc;
 245 static int      manager;        /* manager side of pty */
 246 static int      pty;            /* side of pty that gets ioctls */
 247 static int      net;
 248 static int      inter;
 249 extern char **environ;
 250 static char     *line;
 251 static int      SYNCHing = 0;           /* we are in TELNET SYNCH mode */
 252 static int      state = TS_DATA;
 253 
 254 static int env_ovar = -1;       /* XXX.sparker */
 255 static int env_ovalue = -1;     /* XXX.sparker */
 256 static char pam_svc_name[64];
 257 static boolean_t        telmod_init_done = B_FALSE;
 258 
 259 static void     doit(int, struct sockaddr_storage *);
 260 static void     willoption(int);
 261 static void     wontoption(int);
 262 static void     dooption(int);
 263 static void     dontoption(int);
 264 static void     fatal(int, char *);
 265 static void     fatalperror(int, char *, int);


2737 doit(int f, struct sockaddr_storage *who)
2738 {
2739         char *host;
2740         char host_name[MAXHOSTNAMELEN];
2741         int p, t, tt;
2742         struct sgttyb b;
2743         int     ptmfd;  /* fd of logindmux connected to pty */
2744         int     netfd;  /* fd of logindmux connected to netf */
2745         struct  stat    buf;
2746         struct  protocol_arg    telnetp;
2747         struct  strioctl        telnetmod;
2748         struct  envlist *env, *next;
2749         int     nsize = 0;
2750         char abuf[INET6_ADDRSTRLEN];
2751         struct sockaddr_in *sin;
2752         struct sockaddr_in6 *sin6;
2753         socklen_t wholen;
2754         char username[MAXUSERNAMELEN];
2755         int len;
2756         uchar_t passthru;
2757         char *subsidname;
2758 
2759         if ((p = open("/dev/ptmx", O_RDWR | O_NOCTTY)) == -1) {
2760                 fatalperror(f, "open /dev/ptmx", errno);
2761         }
2762         if (grantpt(p) == -1)
2763                 fatal(f, "could not grant subsidiary pty");
2764         if (unlockpt(p) == -1)
2765                 fatal(f, "could not unlock subsidiary pty");
2766         if ((subsidname = ptsname(p)) == NULL)
2767                 fatal(f, "could not enable subsidiary pty");
2768         (void) dup2(f, 0);
2769         if ((t = open(subsidname, O_RDWR | O_NOCTTY)) == -1)
2770                 fatal(f, "could not open subsidiary pty");
2771         if (ioctl(t, I_PUSH, "ptem") == -1)
2772                 fatalperror(f, "ioctl I_PUSH ptem", errno);
2773         if (ioctl(t, I_PUSH, "ldterm") == -1)
2774                 fatalperror(f, "ioctl I_PUSH ldterm", errno);
2775         if (ioctl(t, I_PUSH, "ttcompat") == -1)
2776                 fatalperror(f, "ioctl I_PUSH ttcompat", errno);
2777 
2778         line = subsidname;
2779 
2780         pty = t;
2781 
2782         if (ioctl(t, TIOCGETP, &b) == -1)
2783                 syslog(LOG_INFO, "ioctl TIOCGETP pty t: %m\n");
2784         b.sg_flags = O_CRMOD|O_XTABS|O_ANYP;
2785         /* XXX - ispeed and ospeed must be non-zero */
2786         b.sg_ispeed = B38400;
2787         b.sg_ospeed = B38400;
2788         if (ioctl(t, TIOCSETN, &b) == -1)
2789                 syslog(LOG_INFO, "ioctl TIOCSETN pty t: %m\n");
2790         if (ioctl(pty, TIOCGETP, &b) == -1)
2791                 syslog(LOG_INFO, "ioctl TIOCGETP pty pty: %m\n");
2792         b.sg_flags &= ~O_ECHO;
2793         if (ioctl(pty, TIOCSETN, &b) == -1)
2794                 syslog(LOG_INFO, "ioctl TIOCSETN pty pty: %m\n");
2795 
2796         if (who->ss_family == AF_INET) {
2797                 char *addrbuf = NULL;
2798                 char *portbuf = NULL;


3022 
3023         /*
3024          * Figure out the device number of the net's mux fd, and pass that
3025          * to the ptm's mux.
3026          */
3027         if (fstat(netfd, &buf) < 0) {
3028                 fatalperror(f, "fstat netfd failed", errno);
3029         }
3030         telnetp.dev = buf.st_rdev;
3031         telnetp.flag = 1;
3032 
3033         telnetmod.ic_cmd = LOGDMX_IOC_QEXCHANGE;
3034         telnetmod.ic_timout = -1;
3035         telnetmod.ic_len = sizeof (struct protocol_arg);
3036         telnetmod.ic_dp = (char *)&telnetp;
3037 
3038         if (ioctl(ptmfd, I_STR, &telnetmod) < 0)
3039                 fatal(netfd, "ioctl LOGDMX_IOC_QEXCHANGE of ptmfd failed\n");
3040 
3041         net = netfd;
3042         manager = ptmfd;
3043         cryptmod_fd = netfd;
3044 
3045         /*
3046          * Show banner that getty never gave, but
3047          * only if the user did not automatically authenticate.
3048          */
3049         if (getenv("USER") == NULL && auth_status < AUTH_USER)
3050                 showbanner();
3051 
3052         /*
3053          * If the user automatically authenticated with Kerberos
3054          * we must set the service name that PAM will use.  We
3055          * need to do it BEFORE the child fork so that 'cleanup'
3056          * in the parent can call the PAM cleanup stuff with the
3057          * same PAM service that /bin/login will use to authenticate
3058          * this session.
3059          */
3060         if (auth_level >= 0 && auth_status >= AUTH_USER &&
3061             (AuthenticatingUser != NULL) && strlen(AuthenticatingUser)) {
3062                 (void) strcpy(pam_svc_name, "ktelnet");


3083         if (!myopts[TELOPT_ECHO]) {
3084             dooption(TELOPT_ECHO);
3085         }
3086 
3087         /*
3088          * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
3089          * because 4.2 clients are unable to deal with TCP urgent data.
3090          *
3091          * To find out, we send out a "DO ECHO".  If the remote system
3092          * answers "WILL ECHO" it is probably a 4.2 client, and we note
3093          * that fact ("WILL ECHO" ==> that the client will echo what
3094          * WE, the server, sends it; it does NOT mean that the client will
3095          * echo the terminal input).
3096          */
3097         send_do(TELOPT_ECHO);
3098         remopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK;
3099 
3100         if ((pid = fork()) < 0)
3101                 fatalperror(netfd, "fork", errno);
3102         if (pid)
3103                 telnet(net, manager);
3104         /*
3105          * The child process needs to be the session leader
3106          * and have the pty as its controlling tty.  Thus we need
3107          * to re-open the subsidiary side of the pty no without
3108          * the O_NOCTTY flag that we have been careful to
3109          * use up to this point.
3110          */
3111         (void) setsid();
3112 
3113         tt = open(line, O_RDWR);
3114         if (tt < 0)
3115                 fatalperror(netfd, line, errno);
3116         (void) close(netfd);
3117         (void) close(ptmfd);
3118         (void) close(f);
3119         (void) close(p);
3120         (void) close(t);
3121         if (tt != 0)
3122                 (void) dup2(tt, 0);
3123         if (tt != 1)
3124                 (void) dup2(tt, 1);
3125         if (tt != 2)
3126                 (void) dup2(tt, 2);
3127         if (tt > 2)


3175 
3176         /* If the current auth status is less than the required level, exit */
3177         if (auth_status < auth_level) {
3178                 fatal(net, "Authentication failed\n");
3179                 exit(EXIT_FAILURE);
3180         }
3181 
3182         /*
3183          * If AUTH_VALID (proper authentication REQUIRED and we have
3184          * a krb5_name), exec '/bin/login', make sure it uses the
3185          * correct PAM service name (pam_svc_name). If possible,
3186          * make sure the krb5 authenticated user's name (krb5_name)
3187          * is in the PAM REPOSITORY for krb5.
3188          */
3189         if (auth_level >= 0 &&
3190             (auth_status == AUTH_VALID || auth_status == AUTH_USER) &&
3191             ((krb5_name != NULL) && strlen(krb5_name)) &&
3192             ((AuthenticatingUser != NULL) && strlen(AuthenticatingUser))) {
3193                 (void) execl(LOGIN_PROGRAM, "login",
3194                             "-p",
3195                             "-d", subsidname,
3196                             "-h", host,
3197                             "-u", krb5_name,
3198                             "-s", pam_svc_name,
3199                             "-R", KRB5_REPOSITORY_NAME,
3200                             AuthenticatingUser, 0);
3201         } else if (auth_level >= 0 &&
3202                 auth_status >= AUTH_USER &&
3203                 (((AuthenticatingUser != NULL) && strlen(AuthenticatingUser)) ||
3204                 getenv("USER"))) {
3205                 /*
3206                  * If we only know the name but not the principal,
3207                  * login will have to authenticate further.
3208                  */
3209                 (void) execl(LOGIN_PROGRAM, "login",
3210                     "-p",
3211                     "-d", subsidname,
3212                     "-h", host,
3213                     "-s", pam_svc_name, "--",
3214                     (AuthenticatingUser != NULL ? AuthenticatingUser :
3215                         getenv("USER")), 0);
3216 
3217         } else /* default, no auth. info available, login does it all */ {
3218                 (void) execl(LOGIN_PROGRAM, "login",
3219                     "-p", "-h", host, "-d", subsidname, "--",
3220                     getenv("USER"), 0);
3221         }
3222 
3223         fatalperror(netfd, LOGIN_PROGRAM, errno);
3224         /*NOTREACHED*/
3225 }
3226 
3227 static void
3228 fatal(int f, char *msg)
3229 {
3230         char buf[BUFSIZ];
3231 
3232         (void) snprintf(buf, sizeof (buf), "telnetd: %s.\r\n", msg);
3233         (void) write(f, buf, strlen(buf));
3234         exit(EXIT_FAILURE);
3235         /*NOTREACHED*/
3236 }
3237 
3238 static void
3239 fatalperror(int f, char *msg, int errnum)
3240 {
3241         char buf[BUFSIZ];
3242 
3243         (void) snprintf(buf, sizeof (buf),
3244                         "%s: %s\r\n", msg, strerror(errnum));
3245         fatal(f, buf);
3246         /*NOTREACHED*/
3247 }
3248 
3249 /*
3250  * Main loop.  Select from pty and network, and
3251  * hand data to telnet receiver finite state machine
3252  * when it receives telnet protocol. Regular data
3253  * flow between pty and network takes place through
3254  * inkernel telnet streams module (telmod).
3255  */
3256 static void
3257 telnet(int net, int manager)
3258 {
3259         int on = 1;
3260         char mode;
3261         struct  strioctl        telnetmod;
3262         int     nsize = 0;
3263         char    binary_in = 0;
3264         char binary_out = 0;
3265 
3266         if (ioctl(net, FIONBIO, &on) == -1)
3267                 syslog(LOG_INFO, "ioctl FIONBIO net: %m\n");
3268         if (ioctl(manager, FIONBIO, &on) == -1)
3269                 syslog(LOG_INFO, "ioctl FIONBIO pty p: %m\n");
3270         (void) signal(SIGTSTP, SIG_IGN);
3271         (void) signal(SIGCHLD, (void (*)())cleanup);
3272         (void) setpgrp();
3273 
3274         /*
3275          * Call telrcv() once to pick up anything received during
3276          * terminal type negotiation.
3277          */
3278         telrcv();
3279 
3280         netflush();
3281         ptyflush();
3282 
3283         for (;;) {
3284                 fd_set ibits, obits, xbits;
3285                 int c;
3286 
3287                 if (ncc < 0)
3288                         break;
3289 
3290                 FD_ZERO(&ibits);
3291                 FD_ZERO(&obits);
3292                 FD_ZERO(&xbits);
3293 
3294                 /*
3295                  * If we couldn't flush all our output to the network,
3296                  * keep checking for when we can.
3297                  */
3298                 if (nfrontp - nbackp)
3299                         FD_SET(net, &obits);
3300                 /*
3301                  * Never look for input if there's still
3302                  * stuff in the corresponding output buffer
3303                  */
3304                 if (pfrontp - pbackp) {
3305                         FD_SET(manager, &obits);
3306                 } else {
3307                         FD_SET(net, &ibits);
3308                 }
3309                 if (!SYNCHing) {
3310                         FD_SET(net, &xbits);
3311                 }
3312 
3313 #define max(x, y)       (((x) < (y)) ? (y) : (x))
3314 
3315                 /*
3316                  * make an ioctl to telnet module (net side) to send
3317                  * binary mode of telnet daemon. binary_in and
3318                  * binary_out are 0 if not in binary mode.
3319                  */
3320                 if (binary_in != myopts[TELOPT_BINARY] ||
3321                     binary_out != remopts[TELOPT_BINARY]) {
3322 
3323                         mode = 0;
3324                         if (myopts[TELOPT_BINARY] != OPT_NO)
3325                                 mode |= TEL_BINARY_IN;


3373 
3374                                 netip = netibuf;
3375                                 (void) memset(netibuf, 0, netibufsize);
3376 
3377                                 ncc = 0;
3378                         }
3379                 } else {
3380                         /*
3381                          * state not changed to TS_DATA and hence, more to read
3382                          * send ioctl to get one more message block.
3383                          */
3384                         telnetmod.ic_cmd = TEL_IOC_GETBLK;
3385                         telnetmod.ic_timout = -1;
3386                         telnetmod.ic_len = 0;
3387                         telnetmod.ic_dp = NULL;
3388 
3389                         if (ioctl(net, I_STR, &telnetmod) < 0)
3390                                 fatal(net, "ioctl TEL_IOC_GETBLK failed\n");
3391                 }
3392 
3393                 if ((c = select(max(net, manager) + 1, &ibits, &obits, &xbits,
3394                     (struct timeval *)0)) < 1) {
3395                         if (c == -1) {
3396                                 if (errno == EINTR) {
3397                                         continue;
3398                                 }
3399                         }
3400                         (void) sleep(5);
3401                         continue;
3402                 }
3403 
3404                 /*
3405                  * Any urgent data?
3406                  */
3407                 if (FD_ISSET(net, &xbits)) {
3408                         SYNCHing = 1;
3409                 }
3410 
3411                 /*
3412                  * Something to read from the network...
3413                  */
3414                 if (FD_ISSET(net, &ibits)) {
3415                     ncc = read(net, netibuf, netibufsize);
3416                     if (ncc < 0 && errno == EWOULDBLOCK)
3417                         ncc = 0;
3418                     else {
3419                         if (ncc <= 0) {
3420                             break;
3421                         }
3422                         netip = netibuf;
3423                     }
3424                 }
3425 
3426                 if (FD_ISSET(net, &obits) && (nfrontp - nbackp) > 0)
3427                         netflush();
3428                 if (ncc > 0)
3429                         telrcv();
3430                 if (FD_ISSET(manager, &obits) && (pfrontp - pbackp) > 0)
3431                         ptyflush();
3432         }
3433         cleanup(0);
3434 }
3435 
3436 static void
3437 telrcv(void)
3438 {
3439         int c;
3440 
3441         while (ncc > 0) {
3442                 if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
3443                         return;
3444                 c = *netip & 0377;
3445                 /*
3446                  * Once we hit data, we want to transition back to
3447                  * in-kernel processing.  However, this code is shared
3448                  * by getterminaltype()/ttloop() which run before the
3449                  * in-kernel plumbing is available.  So if we are still
3450                  * processing the initial option negotiation, even TS_DATA


4262 {
4263         struct sgttyb b;
4264         struct tchars tchars;
4265 
4266         ptyflush();     /* half-hearted */
4267         (void) ioctl(pty, TIOCGETP, &b);
4268         if (b.sg_flags & O_RAW) {
4269                 *pfrontp++ = '\0';
4270                 return;
4271         }
4272         *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
4273                 '\034' : tchars.t_quitc;
4274 }
4275 
4276 static void
4277 ptyflush(void)
4278 {
4279         int n;
4280 
4281         if ((n = pfrontp - pbackp) > 0)
4282                 n = write(manager, pbackp, n);
4283         if (n < 0)
4284                 return;
4285         pbackp += n;
4286         if (pbackp == pfrontp)
4287                 pbackp = pfrontp = ptyobuf;
4288 }
4289 
4290 /*
4291  * nextitem()
4292  *
4293  *      Return the address of the next "item" in the TELNET data
4294  * stream.  This will be the address of the next character if
4295  * the current address is a user data character, or it will
4296  * be the address of the character following the TELNET command
4297  * if the current address is a TELNET IAC ("I Am a Command")
4298  * character.
4299  */
4300 
4301 static char *
4302 nextitem(char *current)


4430                 return;
4431         }
4432 
4433         nbackp += n;
4434 
4435         if (nbackp >= neturg) {
4436                 neturg = 0;
4437         }
4438         if (nbackp == nfrontp) {
4439                 nbackp = nfrontp = netobuf;
4440         }
4441 }
4442 
4443 /* ARGSUSED */
4444 static void
4445 cleanup(int signum)
4446 {
4447         /*
4448          * If the TEL_IOC_ENABLE ioctl hasn't completed, then we need to
4449          * handle closing differently.  We close "net" first and then
4450          * "manager" in that order.  We do close(net) first because
4451          * we have no other way to disconnect forwarding between the network
4452          * and manager.  So by issuing the close()'s we ensure that no further
4453          * data rises from TCP.  A more complex fix would be adding proper
4454          * support for throwing a "stop" switch for forwarding data between
4455          * logindmux peers.  It's possible to block in the close of the tty
4456          * while the network still receives data and the telmod module is
4457          * TEL_STOPPED.  A denial-of-service attack generates this case,
4458          * see 4102102.
4459          */
4460 
4461         if (!telmod_init_done) {
4462                 (void) close(net);
4463                 (void) close(manager);
4464         }
4465         rmut();
4466 
4467         exit(EXIT_FAILURE);
4468 }
4469 
4470 static void
4471 rmut(void)
4472 {
4473         pam_handle_t    *pamh;
4474         struct utmpx *up;
4475         char user[sizeof (up->ut_user) + 1];
4476         char ttyn[sizeof (up->ut_line) + 1];
4477         char rhost[sizeof (up->ut_host) + 1];
4478 
4479         /* while cleaning up don't allow disruption */
4480         (void) signal(SIGCHLD, SIG_IGN);
4481 
4482         setutxent();
4483         while (up = getutxent()) {