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

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/cmd-inet/usr.sbin/in.telnetd.c
          +++ new/usr/src/cmd/cmd-inet/usr.sbin/in.telnetd.c
↓ open down ↓ 234 lines elided ↑ open up ↑
 235  235  #define TS_IAC          1       /* look for double IAC's */
 236  236  #define TS_CR           2       /* CR-LF ->'s CR */
 237  237  #define TS_SB           3       /* throw away begin's... */
 238  238  #define TS_SE           4       /* ...end's (suboption negotiation) */
 239  239  #define TS_WILL         5       /* will option negotiation */
 240  240  #define TS_WONT         6       /* wont " */
 241  241  #define TS_DO           7       /* do " */
 242  242  #define TS_DONT         8       /* dont " */
 243  243  
 244  244  static int      ncc;
 245      -static int      master;         /* master side of pty */
      245 +static int      manager;        /* manager side of pty */
 246  246  static int      pty;            /* side of pty that gets ioctls */
 247  247  static int      net;
 248  248  static int      inter;
 249  249  extern char **environ;
 250  250  static char     *line;
 251  251  static int      SYNCHing = 0;           /* we are in TELNET SYNCH mode */
 252  252  static int      state = TS_DATA;
 253  253  
 254  254  static int env_ovar = -1;       /* XXX.sparker */
 255  255  static int env_ovalue = -1;     /* XXX.sparker */
↓ open down ↓ 2491 lines elided ↑ open up ↑
2747 2747          struct  strioctl        telnetmod;
2748 2748          struct  envlist *env, *next;
2749 2749          int     nsize = 0;
2750 2750          char abuf[INET6_ADDRSTRLEN];
2751 2751          struct sockaddr_in *sin;
2752 2752          struct sockaddr_in6 *sin6;
2753 2753          socklen_t wholen;
2754 2754          char username[MAXUSERNAMELEN];
2755 2755          int len;
2756 2756          uchar_t passthru;
2757      -        char *slavename;
     2757 +        char *subsidname;
2758 2758  
2759 2759          if ((p = open("/dev/ptmx", O_RDWR | O_NOCTTY)) == -1) {
2760 2760                  fatalperror(f, "open /dev/ptmx", errno);
2761 2761          }
2762 2762          if (grantpt(p) == -1)
2763      -                fatal(f, "could not grant slave pty");
     2763 +                fatal(f, "could not grant subsidiary pty");
2764 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");
     2765 +                fatal(f, "could not unlock subsidiary pty");
     2766 +        if ((subsidname = ptsname(p)) == NULL)
     2767 +                fatal(f, "could not enable subsidiary pty");
2768 2768          (void) dup2(f, 0);
2769      -        if ((t = open(slavename, O_RDWR | O_NOCTTY)) == -1)
2770      -                fatal(f, "could not open slave pty");
     2769 +        if ((t = open(subsidname, O_RDWR | O_NOCTTY)) == -1)
     2770 +                fatal(f, "could not open subsidiary pty");
2771 2771          if (ioctl(t, I_PUSH, "ptem") == -1)
2772 2772                  fatalperror(f, "ioctl I_PUSH ptem", errno);
2773 2773          if (ioctl(t, I_PUSH, "ldterm") == -1)
2774 2774                  fatalperror(f, "ioctl I_PUSH ldterm", errno);
2775 2775          if (ioctl(t, I_PUSH, "ttcompat") == -1)
2776 2776                  fatalperror(f, "ioctl I_PUSH ttcompat", errno);
2777 2777  
2778      -        line = slavename;
     2778 +        line = subsidname;
2779 2779  
2780 2780          pty = t;
2781 2781  
2782 2782          if (ioctl(t, TIOCGETP, &b) == -1)
2783 2783                  syslog(LOG_INFO, "ioctl TIOCGETP pty t: %m\n");
2784 2784          b.sg_flags = O_CRMOD|O_XTABS|O_ANYP;
2785 2785          /* XXX - ispeed and ospeed must be non-zero */
2786 2786          b.sg_ispeed = B38400;
2787 2787          b.sg_ospeed = B38400;
2788 2788          if (ioctl(t, TIOCSETN, &b) == -1)
↓ open down ↓ 243 lines elided ↑ open up ↑
3032 3032  
3033 3033          telnetmod.ic_cmd = LOGDMX_IOC_QEXCHANGE;
3034 3034          telnetmod.ic_timout = -1;
3035 3035          telnetmod.ic_len = sizeof (struct protocol_arg);
3036 3036          telnetmod.ic_dp = (char *)&telnetp;
3037 3037  
3038 3038          if (ioctl(ptmfd, I_STR, &telnetmod) < 0)
3039 3039                  fatal(netfd, "ioctl LOGDMX_IOC_QEXCHANGE of ptmfd failed\n");
3040 3040  
3041 3041          net = netfd;
3042      -        master = ptmfd;
     3042 +        manager = ptmfd;
3043 3043          cryptmod_fd = netfd;
3044 3044  
3045 3045          /*
3046 3046           * Show banner that getty never gave, but
3047 3047           * only if the user did not automatically authenticate.
3048 3048           */
3049 3049          if (getenv("USER") == NULL && auth_status < AUTH_USER)
3050 3050                  showbanner();
3051 3051  
3052 3052          /*
↓ open down ↓ 40 lines elided ↑ open up ↑
3093 3093           * that fact ("WILL ECHO" ==> that the client will echo what
3094 3094           * WE, the server, sends it; it does NOT mean that the client will
3095 3095           * echo the terminal input).
3096 3096           */
3097 3097          send_do(TELOPT_ECHO);
3098 3098          remopts[TELOPT_ECHO] = OPT_YES_BUT_ALWAYS_LOOK;
3099 3099  
3100 3100          if ((pid = fork()) < 0)
3101 3101                  fatalperror(netfd, "fork", errno);
3102 3102          if (pid)
3103      -                telnet(net, master);
     3103 +                telnet(net, manager);
3104 3104          /*
3105 3105           * The child process needs to be the session leader
3106 3106           * and have the pty as its controlling tty.  Thus we need
3107      -         * to re-open the slave side of the pty no without
     3107 +         * to re-open the subsidiary side of the pty no without
3108 3108           * the O_NOCTTY flag that we have been careful to
3109 3109           * use up to this point.
3110 3110           */
3111 3111          (void) setsid();
3112 3112  
3113 3113          tt = open(line, O_RDWR);
3114 3114          if (tt < 0)
3115 3115                  fatalperror(netfd, line, errno);
3116 3116          (void) close(netfd);
3117 3117          (void) close(ptmfd);
↓ open down ↓ 5 lines elided ↑ open up ↑
3123 3123          if (tt != 1)
3124 3124                  (void) dup2(tt, 1);
3125 3125          if (tt != 2)
3126 3126                  (void) dup2(tt, 2);
3127 3127          if (tt > 2)
3128 3128                  (void) close(tt);
3129 3129  
3130 3130          if (terminaltype)
3131 3131                  (void) local_setenv("TERM", terminaltype+5, 1);
3132 3132          /*
3133      -         *      -h : pass on name of host.
     3133 +         *      -h : pass on name of host.
3134 3134           *              WARNING:  -h is accepted by login if and only if
3135 3135           *                      getuid() == 0.
3136      -         *      -p : don't clobber the environment (so terminal type stays set).
     3136 +         *      -p : don't clobber the environment (so terminal type stays set).
3137 3137           */
3138 3138          {
3139 3139                  /* System V login expects a utmp entry to already be there */
3140 3140                  struct utmpx ut;
3141 3141                  (void) memset((char *)&ut, 0, sizeof (ut));
3142 3142                  (void) strncpy(ut.ut_user, ".telnet", sizeof (ut.ut_user));
3143 3143                  (void) strncpy(ut.ut_line, line, sizeof (ut.ut_line));
3144 3144                  ut.ut_pid = getpid();
3145 3145                  ut.ut_id[0] = 't';
3146 3146                  ut.ut_id[1] = (char)SC_WILDC;
↓ open down ↓ 38 lines elided ↑ open up ↑
3185 3185           * correct PAM service name (pam_svc_name). If possible,
3186 3186           * make sure the krb5 authenticated user's name (krb5_name)
3187 3187           * is in the PAM REPOSITORY for krb5.
3188 3188           */
3189 3189          if (auth_level >= 0 &&
3190 3190              (auth_status == AUTH_VALID || auth_status == AUTH_USER) &&
3191 3191              ((krb5_name != NULL) && strlen(krb5_name)) &&
3192 3192              ((AuthenticatingUser != NULL) && strlen(AuthenticatingUser))) {
3193 3193                  (void) execl(LOGIN_PROGRAM, "login",
3194 3194                              "-p",
3195      -                            "-d", slavename,
     3195 +                            "-d", subsidname,
3196 3196                              "-h", host,
3197 3197                              "-u", krb5_name,
3198 3198                              "-s", pam_svc_name,
3199 3199                              "-R", KRB5_REPOSITORY_NAME,
3200 3200                              AuthenticatingUser, 0);
3201 3201          } else if (auth_level >= 0 &&
3202 3202                  auth_status >= AUTH_USER &&
3203 3203                  (((AuthenticatingUser != NULL) && strlen(AuthenticatingUser)) ||
3204 3204                  getenv("USER"))) {
3205 3205                  /*
3206 3206                   * If we only know the name but not the principal,
3207 3207                   * login will have to authenticate further.
3208 3208                   */
3209 3209                  (void) execl(LOGIN_PROGRAM, "login",
3210 3210                      "-p",
3211      -                    "-d", slavename,
     3211 +                    "-d", subsidname,
3212 3212                      "-h", host,
3213 3213                      "-s", pam_svc_name, "--",
3214 3214                      (AuthenticatingUser != NULL ? AuthenticatingUser :
3215 3215                          getenv("USER")), 0);
3216 3216  
3217 3217          } else /* default, no auth. info available, login does it all */ {
3218 3218                  (void) execl(LOGIN_PROGRAM, "login",
3219      -                    "-p", "-h", host, "-d", slavename, "--",
     3219 +                    "-p", "-h", host, "-d", subsidname, "--",
3220 3220                      getenv("USER"), 0);
3221 3221          }
3222 3222  
3223 3223          fatalperror(netfd, LOGIN_PROGRAM, errno);
3224 3224          /*NOTREACHED*/
3225 3225  }
3226 3226  
3227 3227  static void
3228 3228  fatal(int f, char *msg)
3229 3229  {
↓ open down ↓ 17 lines elided ↑ open up ↑
3247 3247  }
3248 3248  
3249 3249  /*
3250 3250   * Main loop.  Select from pty and network, and
3251 3251   * hand data to telnet receiver finite state machine
3252 3252   * when it receives telnet protocol. Regular data
3253 3253   * flow between pty and network takes place through
3254 3254   * inkernel telnet streams module (telmod).
3255 3255   */
3256 3256  static void
3257      -telnet(int net, int master)
     3257 +telnet(int net, int manager)
3258 3258  {
3259 3259          int on = 1;
3260 3260          char mode;
3261 3261          struct  strioctl        telnetmod;
3262 3262          int     nsize = 0;
3263 3263          char    binary_in = 0;
3264 3264          char binary_out = 0;
3265 3265  
3266 3266          if (ioctl(net, FIONBIO, &on) == -1)
3267 3267                  syslog(LOG_INFO, "ioctl FIONBIO net: %m\n");
3268      -        if (ioctl(master, FIONBIO, &on) == -1)
     3268 +        if (ioctl(manager, FIONBIO, &on) == -1)
3269 3269                  syslog(LOG_INFO, "ioctl FIONBIO pty p: %m\n");
3270 3270          (void) signal(SIGTSTP, SIG_IGN);
3271 3271          (void) signal(SIGCHLD, (void (*)())cleanup);
3272 3272          (void) setpgrp();
3273 3273  
3274 3274          /*
3275 3275           * Call telrcv() once to pick up anything received during
3276 3276           * terminal type negotiation.
3277 3277           */
3278 3278          telrcv();
↓ open down ↓ 16 lines elided ↑ open up ↑
3295 3295                   * If we couldn't flush all our output to the network,
3296 3296                   * keep checking for when we can.
3297 3297                   */
3298 3298                  if (nfrontp - nbackp)
3299 3299                          FD_SET(net, &obits);
3300 3300                  /*
3301 3301                   * Never look for input if there's still
3302 3302                   * stuff in the corresponding output buffer
3303 3303                   */
3304 3304                  if (pfrontp - pbackp) {
3305      -                        FD_SET(master, &obits);
     3305 +                        FD_SET(manager, &obits);
3306 3306                  } else {
3307 3307                          FD_SET(net, &ibits);
3308 3308                  }
3309 3309                  if (!SYNCHing) {
3310 3310                          FD_SET(net, &xbits);
3311 3311                  }
3312 3312  
3313 3313  #define max(x, y)       (((x) < (y)) ? (y) : (x))
3314 3314  
3315 3315                  /*
↓ open down ↓ 67 lines elided ↑ open up ↑
3383 3383                           */
3384 3384                          telnetmod.ic_cmd = TEL_IOC_GETBLK;
3385 3385                          telnetmod.ic_timout = -1;
3386 3386                          telnetmod.ic_len = 0;
3387 3387                          telnetmod.ic_dp = NULL;
3388 3388  
3389 3389                          if (ioctl(net, I_STR, &telnetmod) < 0)
3390 3390                                  fatal(net, "ioctl TEL_IOC_GETBLK failed\n");
3391 3391                  }
3392 3392  
3393      -                if ((c = select(max(net, master) + 1, &ibits, &obits, &xbits,
     3393 +                if ((c = select(max(net, manager) + 1, &ibits, &obits, &xbits,
3394 3394                      (struct timeval *)0)) < 1) {
3395 3395                          if (c == -1) {
3396 3396                                  if (errno == EINTR) {
3397 3397                                          continue;
3398 3398                                  }
3399 3399                          }
3400 3400                          (void) sleep(5);
3401 3401                          continue;
3402 3402                  }
3403 3403  
↓ open down ↓ 16 lines elided ↑ open up ↑
3420 3420                              break;
3421 3421                          }
3422 3422                          netip = netibuf;
3423 3423                      }
3424 3424                  }
3425 3425  
3426 3426                  if (FD_ISSET(net, &obits) && (nfrontp - nbackp) > 0)
3427 3427                          netflush();
3428 3428                  if (ncc > 0)
3429 3429                          telrcv();
3430      -                if (FD_ISSET(master, &obits) && (pfrontp - pbackp) > 0)
     3430 +                if (FD_ISSET(manager, &obits) && (pfrontp - pbackp) > 0)
3431 3431                          ptyflush();
3432 3432          }
3433 3433          cleanup(0);
3434 3434  }
3435 3435  
3436 3436  static void
3437 3437  telrcv(void)
3438 3438  {
3439 3439          int c;
3440 3440  
↓ open down ↓ 831 lines elided ↑ open up ↑
4272 4272          *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
4273 4273                  '\034' : tchars.t_quitc;
4274 4274  }
4275 4275  
4276 4276  static void
4277 4277  ptyflush(void)
4278 4278  {
4279 4279          int n;
4280 4280  
4281 4281          if ((n = pfrontp - pbackp) > 0)
4282      -                n = write(master, pbackp, n);
     4282 +                n = write(manager, pbackp, n);
4283 4283          if (n < 0)
4284 4284                  return;
4285 4285          pbackp += n;
4286 4286          if (pbackp == pfrontp)
4287 4287                  pbackp = pfrontp = ptyobuf;
4288 4288  }
4289 4289  
4290 4290  /*
4291 4291   * nextitem()
4292 4292   *
↓ open down ↓ 147 lines elided ↑ open up ↑
4440 4440          }
4441 4441  }
4442 4442  
4443 4443  /* ARGSUSED */
4444 4444  static void
4445 4445  cleanup(int signum)
4446 4446  {
4447 4447          /*
4448 4448           * If the TEL_IOC_ENABLE ioctl hasn't completed, then we need to
4449 4449           * handle closing differently.  We close "net" first and then
4450      -         * "master" in that order.  We do close(net) first because
     4450 +         * "manager" in that order.  We do close(net) first because
4451 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
     4452 +         * and manager.  So by issuing the close()'s we ensure that no further
4453 4453           * data rises from TCP.  A more complex fix would be adding proper
4454 4454           * support for throwing a "stop" switch for forwarding data between
4455 4455           * logindmux peers.  It's possible to block in the close of the tty
4456 4456           * while the network still receives data and the telmod module is
4457 4457           * TEL_STOPPED.  A denial-of-service attack generates this case,
4458 4458           * see 4102102.
4459 4459           */
4460 4460  
4461 4461          if (!telmod_init_done) {
4462 4462                  (void) close(net);
4463      -                (void) close(master);
     4463 +                (void) close(manager);
4464 4464          }
4465 4465          rmut();
4466 4466  
4467 4467          exit(EXIT_FAILURE);
4468 4468  }
4469 4469  
4470 4470  static void
4471 4471  rmut(void)
4472 4472  {
4473 4473          pam_handle_t    *pamh;
↓ open down ↓ 455 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX