@@ -683,6 +683,104 @@ mod channels {
683683 )
684684 . await ;
685685 }
686+
687+ /// What a client sends in a pty-req is what the application on the server
688+ /// side must see: exactly those modes, with no padding behind them.
689+ #[ tokio:: test]
690+ async fn test_pty_req_modes_are_delivered_unpadded ( ) {
691+ let modes = vec ! [ ( Pty :: VINTR , 3 ) , ( Pty :: VQUIT , 28 ) ] ;
692+ assert_eq ! ( send_pty_req( modes. clone( ) ) . await , modes) ;
693+ }
694+
695+ /// A mode list padded with TTY_OP_END entries -- the shape an application
696+ /// proxying a pty-req ends up holding -- must still produce a well formed
697+ /// request. The encoder skips those entries, so the length it declares for
698+ /// the modes string must not count them, or the receiver reads the rest of
699+ /// the packet as terminal modes and rejects it.
700+ #[ tokio:: test]
701+ async fn test_pty_req_with_padded_modes_is_well_formed ( ) {
702+ let mut padded = vec ! [ ( Pty :: VINTR , 3 ) ] ;
703+ padded. resize ( 130 , ( Pty :: TTY_OP_END , 0 ) ) ;
704+ assert_eq ! ( send_pty_req( padded) . await , vec![ ( Pty :: VINTR , 3 ) ] ) ;
705+ }
706+
707+ /// Send one pty-req and return the modes the server side received.
708+ async fn send_pty_req ( modes : Vec < ( Pty , u32 ) > ) -> Vec < ( Pty , u32 ) > {
709+ struct Client { }
710+
711+ impl client:: Handler for Client {
712+ type Error = crate :: Error ;
713+
714+ async fn check_server_key (
715+ & mut self ,
716+ _server_public_key : & PublicKeyOrCertificate ,
717+ ) -> Result < bool , Self :: Error > {
718+ Ok ( true )
719+ }
720+ }
721+
722+ struct ServerHandle {
723+ seen : tokio:: sync:: mpsc:: UnboundedSender < Vec < ( Pty , u32 ) > > ,
724+ }
725+
726+ impl server:: Handler for ServerHandle {
727+ type Error = crate :: Error ;
728+
729+ async fn auth_publickey (
730+ & mut self ,
731+ _: & str ,
732+ _: & crate :: keys:: ssh_key:: PublicKey ,
733+ ) -> Result < server:: Auth , Self :: Error > {
734+ Ok ( server:: Auth :: Accept )
735+ }
736+
737+ async fn channel_open_session (
738+ & mut self ,
739+ mut channel : Channel < server:: Msg > ,
740+ reply : server:: ChannelOpenHandle ,
741+ session : & mut Session ,
742+ ) -> Result < ( ) , Self :: Error > {
743+ reply. accept ( ) . await ;
744+
745+ let seen = self . seen . clone ( ) ;
746+ let handle = session. handle ( ) ;
747+ let id = channel. id ( ) ;
748+ tokio:: spawn ( async move {
749+ while let Some ( msg) = channel. wait ( ) . await {
750+ if let ChannelMsg :: RequestPty { terminal_modes, .. } = msg {
751+ let _ = seen. send ( terminal_modes) ;
752+ // Answer, so the client knows we are done looking.
753+ let _ = handle. channel_success ( id) . await ;
754+ break ;
755+ }
756+ }
757+ } ) ;
758+ Ok ( ( ) )
759+ }
760+ }
761+
762+ let ( seen, mut received) = tokio:: sync:: mpsc:: unbounded_channel ( ) ;
763+ test_session (
764+ Client { } ,
765+ ServerHandle { seen } ,
766+ move |client| async move {
767+ let mut channel = client. channel_open_session ( ) . await . unwrap ( ) ;
768+ channel
769+ . request_pty ( true , "xterm" , 80 , 24 , 0 , 0 , & modes)
770+ . await
771+ . unwrap ( ) ;
772+ match channel. wait ( ) . await {
773+ Some ( ChannelMsg :: Success ) => ( ) ,
774+ other => panic ! ( "pty request was not accepted: {other:?}" ) ,
775+ }
776+ client
777+ } ,
778+ |server| async move { server } ,
779+ )
780+ . await ;
781+
782+ received. try_recv ( ) . expect ( "server never saw the pty request" )
783+ }
686784}
687785
688786mod gex {
0 commit comments