| 721 | } |
| 722 | |
| 723 | func (s *Server) startPTYSession(logger slog.Logger, session ptySession, magicTypeLabel string, cmd *pty.Cmd, sshPty ssh.Pty, windowSize <-chan ssh.Window) (retErr error) { |
| 724 | s.metrics.sessionsTotal.WithLabelValues(magicTypeLabel, "yes").Add(1) |
| 725 | |
| 726 | ctx := session.Context() |
| 727 | // Disable minimal PTY emulation set by gliderlabs/ssh (NL-to-CRNL). |
| 728 | // See https://github.com/coder/coder/issues/3371. |
| 729 | session.DisablePTYEmulation() |
| 730 | |
| 731 | if isLoginShell(session.RawCommand()) { |
| 732 | banners := s.config.AnnouncementBanners() |
| 733 | if banners != nil { |
| 734 | for _, banner := range *banners { |
| 735 | err := showAnnouncementBanner(session, banner) |
| 736 | if err != nil { |
| 737 | logger.Error(ctx, "agent failed to show announcement banner", slog.Error(err)) |
| 738 | s.metrics.sessionErrors.WithLabelValues(magicTypeLabel, "yes", "announcement_banner").Add(1) |
| 739 | break |
| 740 | } |
| 741 | } |
| 742 | } |
| 743 | } |
| 744 | |
| 745 | if !isQuietLogin(s.fs, session.RawCommand()) { |
| 746 | err := showMOTD(s.fs, session, s.config.MOTDFile()) |
| 747 | if err != nil { |
| 748 | logger.Error(ctx, "agent failed to show MOTD", slog.Error(err)) |
| 749 | s.metrics.sessionErrors.WithLabelValues(magicTypeLabel, "yes", "motd").Add(1) |
| 750 | } |
| 751 | } |
| 752 | |
| 753 | cmd.Env = append(cmd.Env, fmt.Sprintf("TERM=%s", sshPty.Term)) |
| 754 | |
| 755 | // The pty package sets `SSH_TTY` on supported platforms. |
| 756 | ptty, process, err := pty.Start(cmd, pty.WithPTYOption( |
| 757 | pty.WithSSHRequest(sshPty), |
| 758 | pty.WithLogger(slog.Stdlib(ctx, logger, slog.LevelInfo)), |
| 759 | )) |
| 760 | if err != nil { |
| 761 | s.metrics.sessionErrors.WithLabelValues(magicTypeLabel, "yes", "start_command").Add(1) |
| 762 | return xerrors.Errorf("start command: %w", err) |
| 763 | } |
| 764 | defer func() { |
| 765 | closeErr := ptty.Close() |
| 766 | if closeErr != nil { |
| 767 | logger.Warn(ctx, "failed to close tty", slog.Error(closeErr)) |
| 768 | s.metrics.sessionErrors.WithLabelValues(magicTypeLabel, "yes", "close").Add(1) |
| 769 | if retErr == nil { |
| 770 | retErr = closeErr |
| 771 | } |
| 772 | } |
| 773 | }() |
| 774 | sigs := make(chan ssh.Signal, 1) |
| 775 | session.Signals(sigs) |
| 776 | defer func() { |
| 777 | session.Signals(nil) |
| 778 | close(sigs) |
| 779 | }() |
| 780 | go func() { |