func (s *server) handleChanReq(chanReq ssh.NewChannel, authInfo map[string]string) { if chanReq.ChannelType() != "session" { chanReq.Reject(ssh.Prohibited, "channel type is not a session") return } ch, reqs, err := chanReq.Accept() if err != nil { log.Errorf("fail to accept channel request %v", err) return } for { req := <-reqs switch req.Type { case "env": case "exec": s.handleExec(ch, req, authInfo) return default: ch.Write([]byte(fmt.Sprintf("request type %q not allowed\r\n", req.Type))) ch.Close() return } } }
// HandleChannel handles one SSH channel func (c *Client) HandleChannel(newChannel ssh.NewChannel) error { if newChannel.ChannelType() != "session" { log.Debugf("Unknown channel type: %s", newChannel.ChannelType()) newChannel.Reject(ssh.UnknownChannelType, "unknown channel type") return nil } channel, requests, err := newChannel.Accept() if err != nil { log.Errorf("newChannel.Accept failed: %v", err) return err } c.ChannelIdx++ log.Debugf("HandleChannel.channel (client=%d channel=%d)", c.Idx, c.ChannelIdx) log.Debug("Creating pty...") c.Pty, c.Tty, err = pty.Open() if err != nil { log.Errorf("pty.Open failed: %v", err) return nil } c.HandleChannelRequests(channel, requests) return nil }
func handleChannel(chanRequest ssh.NewChannel) { handle, err := NewHandle(chanRequest.ChannelType()) if err != nil { config.Log.Debug("wrong handler %v", err) chanRequest.Reject(ssh.UnknownChannelType, err.Error()) return } ch, reqs, err := chanRequest.Accept() if err != nil { config.Log.Debug("fail to accept channel request %v", err) return } defer ch.Close() for req := range reqs { done, err := handle.Request(ch, req) if err != nil { config.Log.Debug("request errored out %v", err) _, err := ch.Write([]byte(fmt.Sprintf("%v\r\n", err))) if err != nil { config.Log.Debug(err.Error()) } } if done { return } } }
func (handler *DirectTcpipChannelHandler) HandleNewChannel(logger lager.Logger, newChannel ssh.NewChannel) { type channelOpenDirectTcpipMsg struct { TargetAddr string TargetPort uint32 OriginAddr string OriginPort uint32 } var directTcpipMessage channelOpenDirectTcpipMsg err := ssh.Unmarshal(newChannel.ExtraData(), &directTcpipMessage) if err != nil { newChannel.Reject(ssh.ConnectionFailed, "Failed to parse open channel message") return } destination := fmt.Sprintf("%s:%d", directTcpipMessage.TargetAddr, directTcpipMessage.TargetPort) conn, err := handler.dialer.Dial("tcp", destination) if err != nil { newChannel.Reject(ssh.ConnectionFailed, err.Error()) return } channel, requests, err := newChannel.Accept() go ssh.DiscardRequests(requests) wg := &sync.WaitGroup{} wg.Add(2) go helpers.CopyAndClose(logger.Session("to-target"), wg, conn, channel) go helpers.CopyAndClose(logger.Session("to-channel"), wg, channel, conn) wg.Wait() }
func handleSSHChannel(newChan ssh.NewChannel, session *Session) { ch, reqs, err := newChan.Accept() if err != nil { log.Println("handle channel failed:", err) return } exitCh := make(chan int) go func() { status := struct{ Status uint32 }{uint32(<-exitCh)} _, err = ch.SendRequest("exit-status", false, ssh.Marshal(&status)) assert(err) ch.Close() }() for req := range reqs { go func(req *ssh.Request) { if req.WantReply { req.Reply(true, nil) } switch req.Type { case "exec": var payload = struct{ Value string }{} ssh.Unmarshal(req.Payload, &payload) line := strings.Trim(payload.Value, "\n") var args []string if line != "" { args = strings.Split(line, " ") } RunCmd(args, ch, ch, ch.Stderr(), exitCh, session) } }(req) } }
func (s *Session) HandleDirectChannel(newChannel ssh.NewChannel) (bool, ssh.RejectionReason) { data, err := UnmarshalTunnelData(newChannel.ExtraData()) if err != nil { return false, ssh.UnknownChannelType } // look up session by name session, host, port := s.Gateway().LookupSessionService(data.Host, uint16(data.Port)) if session == nil { return false, ssh.ConnectionFailed } // found the service, attempt to open a channel data.Host = host data.Port = uint32(port) c2, err := session.OpenChannel("forwarded-tcpip", MarshalTunnelData(data)) if err != nil { return false, ssh.ConnectionFailed } defer func() { if c2 != nil { c2.Close() } }() // accept the channel channel, requests, err := newChannel.Accept() if err != nil { return false, ssh.ResourceShortage } // cannot return false from this point on // also need to accepted close the channel defer func() { if channel != nil { if err := channel.Close(); err != nil { glog.Warningf("failed to close accepted channel: %s", err) } } }() c, err := NewChannel(s, channel, newChannel.ChannelType(), newChannel.ExtraData()) if err != nil { glog.Errorf("failed to create accepted channel: %s", err) return true, 0 } s.AddChannel(c) // no failure go c.HandleRequests(requests) go c.HandleTunnelChannel(c2) // do not close channel on exit channel = nil c2 = nil return true, 0 }
func sshHandleChannel(conn net.Conn, newChannel ssh.NewChannel) { // Channels have a type, depending on the application level protocol // intended. In the case of a shell, the type is "session" and ServerShell // may be used to present a simple terminal interface. if newChannel.ChannelType() != "session" { newChannel.Reject(ssh.UnknownChannelType, "unknown channel type") return } channel, requests, err := newChannel.Accept() if err != nil { log.Errorln(err) return } // Sessions have out-of-band requests such as "shell", "pty-req" and "env". // Here we handle only the "shell" request. go func(in <-chan *ssh.Request) { for req := range in { ok := false switch req.Type { case "shell": ok = true if len(req.Payload) > 0 { // We don't accept any commands, only the default shell. ok = false } case "pty-req": ok = true } req.Reply(ok, nil) } }(requests) term := terminal.NewTerminal(channel, "> ") go func() { defer channel.Close() for { line, err := term.ReadLine() start := time.Now().UnixNano() if err != nil { if err != io.EOF { log.Errorln(err) } return } sshReportChan <- uint64(len(line)) // just echo the message log.Debugln("ssh received: ", line) term.Write([]byte(line)) term.Write([]byte{'\r', '\n'}) stop := time.Now().UnixNano() log.Info("ssh %v %vns", conn.RemoteAddr(), uint64(stop-start)) } }() }
func (handler *SessionChannelHandler) HandleNewChannel(logger lager.Logger, newChannel ssh.NewChannel) { channel, requests, err := newChannel.Accept() if err != nil { logger.Error("handle-new-session-channel-failed", err) return } handler.newSession(logger, channel, handler.keepalive).serviceRequests(requests) }
func (s *Server) handleChannel(ch ssh.NewChannel) { id := rand.Int() s.Debug("Handling Channel", "id", id, "chan", ch.ChannelType()) if ch.ChannelType() != "session" { s.Info("Received unknown channel type", "chan", ch.ChannelType()) ch.Reject(ssh.UnknownChannelType, "unknown channel type") return } channel, requests, err := ch.Accept() if err != nil { s.Error("Failed to accept channe", "err", err) return } var closer sync.Once closeChannel := func() { s.Debug("Closed Channel", "id", id) channel.Close() } defer closer.Do(closeChannel) for req := range requests { spew.Dump(req.Type) switch req.Type { case "exec": // Let it through case "env": if req.WantReply { if err = req.Reply(true, nil); err != nil { s.Error("Failed to ignore env command", "err", err) } } continue default: s.Info("Received unhandled request type", "type", req.Type) continue } r := &scpRequest{db: s.DB} processors := []processor{ r.ParseSCPRequest, r.DownloadFile, r.EndConnectionGracefully, } for _, proc := range processors { if err := proc(channel, req); err != nil { fmt.Fprintln(channel, "failed to process request:", err.Error()) // log.Printf("%+v", err) break } } closer.Do(closeChannel) } }
func (server *SshServer) handleChannel(user string, newChannel ssh.NewChannel) { if t := newChannel.ChannelType(); t != "session" { newChannel.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %s", t)) return } connection, requests, err := newChannel.Accept() if err != nil { fmt.Printf("Could not accept channel (%s)", err) return } defer connection.Close() logfile, err := os.Create(fmt.Sprintf("%s_%s", user, storyLogFilename(server.story))) if err != nil { panic(err) } defer logfile.Close() logger := log.New(logfile, "", log.LstdFlags) terminal := terminal.NewTerminal(connection, "") zsshterm := &gork.ZSshTerminal{Term: terminal} zm, err := gork.NewZMachine(server.mem, server.header, zsshterm, logger) if err != nil { fmt.Println(err) return } go func() { for req := range requests { switch req.Type { case "shell": if len(req.Payload) == 0 { req.Reply(true, nil) } case "pty-req": termLen := req.Payload[3] w, h := parseDims(req.Payload[termLen+4:]) terminal.SetSize(w, h) case "window-change": w, h := parseDims(req.Payload) terminal.SetSize(w, h) } } }() defer func() { recover() }() zm.InterpretAll() }
func (u *UrlDispatcher) Dispatch(c context.Context, conn *ssh.ServerConn, ch ssh.NewChannel) { defer conn.Close() // Get channel type chType := ch.ChannelType() // Parse channel URI uri, err := url.ParseRequestURI(chType) if err != nil { u.Logger.Warn("Error parsing channel type", "type", chType, "err", err) ch.Reject(InvalidChannelType, "invalid channel URI") return } else if reject(chType, uri, ch, u.Logger) { return } chType = uri.Path // Parse query params values, err := url.ParseQuery(uri.RawQuery) if err != nil { u.Logger.Warn("Error parsing query params", "values", values, "err", err) ch.Reject(InvalidQueryParams, "invalid query params in channel type") return } // Determine if channel is acceptable (has a registered handler) if !u.Router.HasRoute(chType) { u.Logger.Info("UnknownChannelType", "type", chType) ch.Reject(ssh.UnknownChannelType, chType) return } // Otherwise, accept the channel channel, requests, err := ch.Accept() if err != nil { u.Logger.Warn("Error creating channel", "type", chType, "err", err) ch.Reject(ChannelAcceptError, chType) return } // Handle the channel err = u.Router.Handle(&router.UrlContext{ Path: uri.Path, Context: c, Values: values, Channel: channel, Requests: requests, }) if err != nil { u.Logger.Warn("Error handling channel", "type", chType, "err", err) ch.Reject(ChannelHandleError, fmt.Sprintf("error handling channel: %s", err.Error())) return } }
func handleChannel(c ssh.NewChannel) { if t := c.ChannelType(); t != "session" { log.Println("rejected unknown channel type:", t) c.Reject(ssh.UnknownChannelType, "unknown channel type") } connection, requests, err := c.Accept() if err != nil { log.Println("channel not accepted:", err) return } bash := exec.Command("/bin/bash") close := func() { connection.Close() _, err := bash.Process.Wait() if err != nil { log.Println("bash not exited:", err) } log.Println("session closed") } bashf, err := pty.Start(bash) if err != nil { log.Println("pty not started:", err) close() return } var once sync.Once go func() { io.Copy(connection, bashf) once.Do(close) }() go func() { io.Copy(bashf, connection) once.Do(close) }() go func() { for req := range requests { log.Println("got request:", req.Type, "want reply:", req.WantReply) switch req.Type { case "shell": if len(req.Payload) == 0 { req.Reply(true, nil) } case "pty-req": termLen := req.Payload[3] w, h := parseDims(req.Payload[termLen+4:]) SetWinsize(bashf.Fd(), w, h) req.Reply(true, nil) case "window-change": w, h := parseDims(req.Payload) SetWinsize(bashf.Fd(), w, h) } } }() }
func handleChannel(newChannel ssh.NewChannel, sh SessionHandler) { // At this point, we have the opportunity to reject the client's // request for another logical connection channel, requests, err := newChannel.Accept() if err != nil { log.Printf("Could not accept channel (%s)", err) return } // Prepare teardown function close := func() { channel.Close() log.Printf("Session closed") } defer close() sh.SetChannel(&channel) var payload []byte ok := true for req := range requests { if len(req.Payload) == 0 { req.Reply(true, nil) } path := string(req.Payload) typ := Mode(req.Type) switch typ { // in reality, this would be an scp with the appropriate args, // but for testing this is fine. case SOURCE: ok, payload = sh.Source(path) case DEST: ok, payload = sh.Destination(path) default: return } // make sure that errors get send back if we failed if req.WantReply { log.Printf("Wants reply %s", string(payload)) req.Reply(ok, payload) } // run any pending work now that a reply has been sent pendingFn := sh.GetPendingWork() if pendingFn != nil { pendingFn() } } }
// ChannelForward establishes a secure channel forward (ssh -W) to the server // requested by the user, assuming it is a permitted host. func (s *Server) ChannelForward(session *Session, newChannel ssh.NewChannel) { var msg channelOpenDirectMsg ssh.Unmarshal(newChannel.ExtraData(), &msg) address := fmt.Sprintf("%s:%d", msg.RAddr, msg.RPort) permitted := false for _, remote := range session.Remotes { if remote == address { permitted = true break } } if !permitted { log.Printf("Disallowed access to %s for user %s", address, session.User.Name) newChannel.Reject(ssh.Prohibited, "remote host access denied for user") return } // Log the selection if s.Selected != nil { if err := s.Selected(session, address); err != nil { newChannel.Reject(ssh.Prohibited, "access denied") return } } conn, err := net.Dial("tcp", address) if err != nil { newChannel.Reject(ssh.ConnectionFailed, fmt.Sprintf("error: %v", err)) return } channel, reqs, err := newChannel.Accept() go ssh.DiscardRequests(reqs) var closer sync.Once closeFunc := func() { channel.Close() conn.Close() } go func() { io.Copy(channel, conn) closer.Do(closeFunc) }() go func() { io.Copy(conn, channel) closer.Do(closeFunc) }() }
func (s *sshServer) handleChannel(newChannel ssh.NewChannel) error { if newChannel.ChannelType() != "session" { newChannel.Reject(ssh.UnknownChannelType, "unknown channel type") return nil } channel, requests, err := newChannel.Accept() if err != nil { log.Println("newChannel accept failed: ", err) return nil } return s.handleRequests(channel, requests) }
func handleChanReq(chanReq ssh.NewChannel) { if chanReq.ChannelType() != "session" { chanReq.Reject(ssh.UnknownChannelType, "unknown channel type") return } channel, requests, err := chanReq.Accept() if err != nil { return } exitloop := false for { select { case req := <-requests: if req == nil { continue } if req.Type == "exec" { handleExec(channel, req) if req.WantReply { req.Reply(true, nil) } exitloop = true } req.Reply(false, nil) case <-time.After(3 * time.Second): log.Println("no exec chanreq received, time out") exitloop = true break } if exitloop { break } } /* todo: return exit status: byte SSH_MSG_CHANNEL_REQUEST uint32 recipient channel string "exit-status" boolean FALSE uint32 exit_status */ channel.Close() }
func (svr *sshServer) handleChanReq(chanReq ssh.NewChannel) { fmt.Fprintf(sshServerDebugStream, "channel request: %v, extra: '%v'\n", chanReq.ChannelType(), hex.EncodeToString(chanReq.ExtraData())) switch chanReq.ChannelType() { case "session": if ch, reqs, err := chanReq.Accept(); err != nil { fmt.Fprintf(sshServerDebugStream, "fail to accept channel request: %v\n", err) chanReq.Reject(ssh.ResourceShortage, "channel accept failure") } else { chsvr := &sshSessionChannelServer{ sshChannelServer: &sshChannelServer{svr, chanReq, ch, reqs}, env: append([]string{}, os.Environ()...), } chsvr.handle() } default: chanReq.Reject(ssh.UnknownChannelType, "channel type is not a session") } }
func handleSSHChannel(newChan ssh.NewChannel) { ch, reqs, err := newChan.Accept() if err != nil { log.Println("handle channel failed:", err) return } for req := range reqs { go func(req *ssh.Request) { if req.WantReply { req.Reply(true, nil) } switch req.Type { case "exec": defer ch.Close() var payload = struct{ Value string }{} ssh.Unmarshal(req.Payload, &payload) line := strings.Trim(payload.Value, "\n") var args []string if line != "" { args = strings.Split(line, " ") } cmd := exec.Command("/bin/envy", args...) cmd.Stdout = ch cmd.Stderr = ch.Stderr() err := cmd.Run() status := struct{ Status uint32 }{0} if err != nil { if exiterr, ok := err.(*exec.ExitError); ok { if stat, ok := exiterr.Sys().(syscall.WaitStatus); ok { status = struct{ Status uint32 }{uint32(stat.ExitStatus())} } else { assert(err) } } } _, err = ch.SendRequest("exit-status", false, ssh.Marshal(&status)) assert(err) return } }(req) } }
func handleChannel(newChannel ssh.NewChannel, rClient *ssh.Client) { if newChannel.ChannelType() != "session" { newChannel.Reject(ssh.UnknownChannelType, "unknown channel type: "+newChannel.ChannelType()) return } psChannel, psRequests, err := newChannel.Accept() if err != nil { panic("could not accept channel.") } sChannel, sRequests, err := rClient.OpenChannel(newChannel.ChannelType(), nil) if err != nil { panic("Failed to create session: " + err.Error()) } go pipeRequests(psChannel, sChannel, psRequests, sRequests) time.Sleep(50 * time.Millisecond) go pipe(sChannel, psChannel) go pipe(psChannel, sChannel) }
func (server *Server) handleChannel(newChannel ssh.NewChannel, conn *ssh.ServerConn) { channelType := newChannel.ChannelType() if channelType != "session" { newChannel.Reject(ssh.UnknownChannelType, fmt.Sprintf("Unknown SSH Channel Type: %s, only `session` is supported", channelType)) server.Logger.Errorf("Rejected SSH Channel Request from %s due to unknown channel type: %s", conn.RemoteAddr().String(), newChannel.ChannelType()) return } channel, requests, err := newChannel.Accept() if err != nil { newChannel.Reject(ssh.ConnectionFailed, "Failed to accept SSH Channel Request, developers are working on it.") server.Logger.Errorf("Rejected SSH Channel Request from %s due to accept request failure: %s", conn.RemoteAddr().String(), err) return } server.Logger.Debugf("Accepted new SSH Channel Request from %s", conn.RemoteAddr().String()) server.handleRequest(channel, requests, conn) }
func handleChanReq(chanReq ssh.NewChannel) { if chanReq.ChannelType() != "session" { chanReq.Reject(ssh.Prohibited, "channel type is not a session") return } ch, reqs, err := chanReq.Accept() if err != nil { log.Println("fail to accept channel request", err) return } req := <-reqs if req.Type != "exec" { ch.Write([]byte("request type '" + req.Type + "' is not 'exec'\r\n")) ch.Close() return } handleExec(ch, req) }
func handleChannel(conn *ssh.ServerConn, newChan ssh.NewChannel, execHandler []string) { ch, reqs, err := newChan.Accept() if err != nil { log.Println("newChan.Accept failed:", err) return } // Setup stdout/stderr var stdout, stderr io.Writer if *debug { stdout = io.MultiWriter(ch, os.Stdout) stderr = io.MultiWriter(ch.Stderr(), os.Stdout) } else { stdout = ch stderr = ch.Stderr() } handler := sshHandler{ ExecHandler: execHandler, channel: ch, stdout: stdout, stderr: stderr, } // Load default environment if *env { handler.Env = os.Environ() } if conn.Permissions != nil { // Using Permissions.Extensions as a way to get state from PublicKeyCallback if conn.Permissions.Extensions["environ"] != "" { handler.Env = append(handler.Env, strings.Split(conn.Permissions.Extensions["environ"], "\n")...) } handler.Env = append(handler.Env, "USER="******"user"]) } for req := range reqs { go handler.Request(req) } }
func (u *SimpleDispatcher) Dispatch(c context.Context, conn *ssh.ServerConn, ch ssh.NewChannel) { defer conn.Close() var ctx *Context if u.PanicHandler != nil { if rcv := recover(); rcv != nil { u.PanicHandler.Handle(ctx, rcv) } } // Get channel type chType := ch.ChannelType() handler, ok := u.Handlers[chType] if !ok { return } // Otherwise, accept the channel channel, requests, err := ch.Accept() if err != nil { u.Logger.Warn("Error creating channel", "type", chType, "err", err) ch.Reject(ChannelAcceptError, chType) return } // Handle the channel ctx = &Context{ Context: c, Channel: channel, Requests: requests, } err = handler.Handle(ctx) if err != nil { u.Logger.Warn("Error handling channel", "type", chType, "err", err) ch.Reject(ChannelHandleError, fmt.Sprintf("error handling channel: %s", err.Error())) return } }
func (s *SSHServer) handleChannel(newChannel ssh.NewChannel) { defer GinkgoRecover() Expect(newChannel.ChannelType()).To(Equal("session")) if s.RejectSession { Expect(newChannel.Reject(ssh.ConnectionFailed, "session rejected")).To(Succeed()) return } channel, requests, err := newChannel.Accept() Expect(err).NotTo(HaveOccurred()) go func() { defer GinkgoRecover() for request := range requests { switch request.Type { case "exec": payloadLen := binary.BigEndian.Uint32(request.Payload[:4]) Expect(request.Payload).To(HaveLen(int(payloadLen) + 4)) s.CommandChan <- string(request.Payload[4:]) Expect(request.Reply(true, nil)).To(Succeed()) _, err := channel.SendRequest("exit-status", false, []byte{0, 0, 0, s.CommandExitStatus}) Expect(err).To(Succeed()) channel.Close() break } } }() go func() { defer GinkgoRecover() io.Copy(s.Data, channel) }() }
func handleChannel(newChannel ssh.NewChannel) { // Since we're handling a shell, we expect a // channel type of "session". The also describes // "x11", "direct-tcpip" and "forwarded-tcpip" // channel types. if t := newChannel.ChannelType(); t != "session" { newChannel.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %s", t)) return } // At this point, we have the opportunity to reject the client's // request for another logical connection connection, _, err := newChannel.Accept() if err != nil { log.Printf("Could not accept channel (%s)", err) return } defer connection.Close() connection.Write([]byte("Hello!\n")) }
// Make new terminal from a session channel func NewTerminal(conn *ssh.ServerConn, ch ssh.NewChannel) (*Terminal, error) { if ch.ChannelType() != "session" { return nil, errors.New("terminal requires session channel") } channel, requests, err := ch.Accept() if err != nil { return nil, err } term := Terminal{ *terminal.NewTerminal(channel, "Connecting..."), sshConn{conn}, channel, } go term.listen(requests) go func() { // FIXME: Is this necessary? conn.Wait() channel.Close() }() return &term, nil }
func (s *Session) HandleSessionChannel(newChannel ssh.NewChannel) (bool, ssh.RejectionReason) { if len(newChannel.ExtraData()) > 0 { // do not accept extra data in session channel request return false, ssh.Prohibited } // accept the channel channel, requests, err := newChannel.Accept() if err != nil { return false, ssh.ResourceShortage } // cannot return false from this point on // also need to accepted close the channel defer func() { if channel != nil { if err := channel.Close(); err != nil { glog.Warningf("failed to close accepted channel: %s", err) } } }() c, err := NewChannel(s, channel, newChannel.ChannelType(), newChannel.ExtraData()) if err != nil { glog.Errorf("failed to create accepted channel: %s", err) return true, 0 } s.AddChannel(c) // no failure go c.HandleRequests(requests) go c.HandleSessionChannel() // do not close channel on exit channel = nil return true, 0 }
// handleUDPChannel implements UDP port forwarding. A single UDP // SSH channel follows the udpgw protocol, which multiplexes many // UDP port forwards. // // The udpgw protocol and original server implementation: // Copyright (c) 2009, Ambroz Bizjak <*****@*****.**> // https://github.com/ambrop72/badvpn // func (sshClient *sshClient) handleUDPChannel(newChannel ssh.NewChannel) { // Accept this channel immediately. This channel will replace any // previously existing UDP channel for this client. sshChannel, requests, err := newChannel.Accept() if err != nil { log.WithContextFields(LogFields{"error": err}).Warning("accept new channel failed") return } go ssh.DiscardRequests(requests) defer sshChannel.Close() sshClient.setUDPChannel(sshChannel) multiplexer := &udpPortForwardMultiplexer{ sshClient: sshClient, sshChannel: sshChannel, portForwards: make(map[uint16]*udpPortForward), portForwardLRU: psiphon.NewLRUConns(), relayWaitGroup: new(sync.WaitGroup), } multiplexer.run() }
// SessionForward performs a regular forward, providing the user with an // interactive remote host selection if necessary. This forwarding type // requires agent forwarding in order to work. func (s *Server) SessionForward(session *Session, newChannel ssh.NewChannel, chans <-chan ssh.NewChannel) { // Okay, we're handling this as a regular session sesschan, sessReqs, err := newChannel.Accept() if err != nil { return } stderr := sesschan.Stderr() remote := "" switch len(session.Remotes) { case 0: sesschan.Close() return case 1: remote = session.Remotes[0] default: comm := rw{Reader: sesschan, Writer: stderr} if s.Interactive == nil { remote, err = DefaultInteractive(comm, session) } else { remote, err = s.Interactive(comm, session) } if err != nil { sesschan.Close() return } } fmt.Fprintf(stderr, "Connecting to %s\r\n", remote) // Set up the agent agentChan, agentReqs, err := session.Conn.OpenChannel("*****@*****.**", nil) if err != nil { fmt.Fprintf(stderr, "\r\n====== sshmux ======\r\n") fmt.Fprintf(stderr, "sshmux requires either agent forwarding or secure channel forwarding.\r\n") fmt.Fprintf(stderr, "Either enable agent forwarding (-A), or use a ssh -W proxy command.\r\n") fmt.Fprintf(stderr, "For more info, see the sshmux wiki.\r\n") sesschan.Close() return } defer agentChan.Close() go ssh.DiscardRequests(agentReqs) // Set up the client ag := agent.NewClient(agentChan) clientConfig := &ssh.ClientConfig{ User: session.Conn.User(), Auth: []ssh.AuthMethod{ ssh.PublicKeysCallback(ag.Signers), }, } client, err := ssh.Dial("tcp", remote, clientConfig) if err != nil { fmt.Fprintf(stderr, "Connect failed: %v\r\n", err) sesschan.Close() return } // Handle all incoming channel requests go func() { for newChannel = range chans { if newChannel == nil { return } channel2, reqs2, err := client.OpenChannel(newChannel.ChannelType(), newChannel.ExtraData()) if err != nil { x, ok := err.(*ssh.OpenChannelError) if ok { newChannel.Reject(x.Reason, x.Message) } else { newChannel.Reject(ssh.Prohibited, "remote server denied channel request") } continue } channel, reqs, err := newChannel.Accept() if err != nil { channel2.Close() continue } go proxy(reqs, reqs2, channel, channel2) } }() // Forward the session channel channel2, reqs2, err := client.OpenChannel("session", []byte{}) if err != nil { fmt.Fprintf(stderr, "Remote session setup failed: %v\r\n", err) sesschan.Close() return } // Proxy the channel and its requests maskedReqs := make(chan *ssh.Request, 1) go func() { for req := range sessReqs { if req.Type == "*****@*****.**" { continue } maskedReqs <- req } }() proxy(maskedReqs, reqs2, sesschan, channel2) }
func (c *adapter) handleSession(newChannel ssh.NewChannel) error { channel, requests, err := newChannel.Accept() if err != nil { return err } defer channel.Close() done := make(chan struct{}) // Sessions have requests such as "pty-req", "shell", "env", and "exec". // see RFC 4254, section 6 go func(in <-chan *ssh.Request) { env := make([]envRequestPayload, 4) for req := range in { switch req.Type { case "pty-req": log.Println("ansible provisioner pty-req request") // accept pty-req requests, but don't actually do anything. Necessary for OpenSSH and sudo. req.Reply(true, nil) case "env": req, err := newEnvRequest(req) if err != nil { c.ui.Error(err.Error()) req.Reply(false, nil) continue } env = append(env, req.Payload) log.Printf("new env request: %s", req.Payload) req.Reply(true, nil) case "exec": req, err := newExecRequest(req) if err != nil { c.ui.Error(err.Error()) req.Reply(false, nil) close(done) continue } log.Printf("new exec request: %s", req.Payload) if len(req.Payload) == 0 { req.Reply(false, nil) close(done) return } go func(channel ssh.Channel) { exit := c.exec(string(req.Payload), channel, channel, channel.Stderr()) exitStatus := make([]byte, 4) binary.BigEndian.PutUint32(exitStatus, uint32(exit)) channel.SendRequest("exit-status", false, exitStatus) close(done) }(channel) req.Reply(true, nil) case "subsystem": req, err := newSubsystemRequest(req) if err != nil { c.ui.Error(err.Error()) req.Reply(false, nil) continue } log.Printf("new subsystem request: %s", req.Payload) switch req.Payload { case "sftp": sftpCmd := c.sftpCmd if len(sftpCmd) == 0 { sftpCmd = "/usr/lib/sftp-server -e" } log.Print("starting sftp subsystem") go func() { _ = c.remoteExec(sftpCmd, channel, channel, channel.Stderr()) close(done) }() req.Reply(true, nil) default: c.ui.Error(fmt.Sprintf("unsupported subsystem requested: %s", req.Payload)) req.Reply(false, nil) } default: log.Printf("rejecting %s request", req.Type) req.Reply(false, nil) } } }(requests) <-done return nil }