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 (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 } } }
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 } } }
// 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 (handler *SessionChannelHandler) HandleNewChannel(logger lager.Logger, newChannel ssh.NewChannel) { err := newChannel.Reject(ssh.Prohibited, "SSH is not supported on windows cells") if err != nil { logger.Error("handle-new-session-channel-failed", err) } return }
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 (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 (sshClient *sshClient) rejectNewChannel(newChannel ssh.NewChannel, reason ssh.RejectionReason, message string) { // TODO: log more details? log.WithContextFields( LogFields{ "channelType": newChannel.ChannelType(), "rejectMessage": message, "rejectReason": reason, }).Warning("reject new channel") newChannel.Reject(reason, message) }
func (s *Server) HandleNewChannel(session *Session, newChannel ssh.NewChannel) { log.Printf("New Channel: %s", newChannel) switch newChannel.ChannelType() { case "direct-tcpip": s.ChannelForward(session, newChannel) default: log.Printf("Unknown SSH channel type: %s", newChannel.ChannelType()) newChannel.Reject(ssh.UnknownChannelType, "connection flow not supported by sshmux") } }
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 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 (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 (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") } }
// 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 { newChannel.Reject(ssh.Prohibited, "remote host access denied for user") 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 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 (s *Session) HandleChannel(newChannel ssh.NewChannel) { glog.V(9).Infof("new channel: type = %s, data = %v", newChannel.ChannelType(), newChannel.ExtraData()) ok := false rejection := ssh.UnknownChannelType switch newChannel.ChannelType() { case "session": ok, rejection = s.HandleSessionChannel(newChannel) case "direct-tcpip": ok, rejection = s.HandleDirectChannel(newChannel) } if !ok { // reject the channel if err := newChannel.Reject(rejection, ""); err != nil { glog.Warningf("failed to reject channel: %s", err) } } }
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 (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")) }
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 } }
/* rejectChannel tells the attacker the channel's been rejected by the real server. It requires the error from the channel request to the real server, the channel request log string, the channel request from the attacker, and the logger for the connection. */ func rejectChannel(nce error, crl string, nc ssh.NewChannel, lg *log.Logger) { /* Values to return to the attacker */ reason := ssh.Prohibited message := nce.Error() /* Try and get the real story */ if oce, ok := nce.(*ssh.OpenChannelError); ok { reason = oce.Reason message = oce.Message } lg.Printf( "Channel Rejection %v Reason:%v Message:%q", crl, reason, message, ) /* Send the rejection */ if err := nc.Reject(reason, message); nil != err { lg.Printf( "Unable to respond to channel request of type %q: %v", nc.ChannelType(), err, ) } }
func reject(chType string, uri *url.URL, ch ssh.NewChannel, logger log.Logger) bool { if uri.Scheme != "" { logger.Warn("URI schemes not supported", "type", chType) ch.Reject(SchemeNotSupported, "schemes are not supported in the channel URI") return true } else if uri.User != nil { logger.Warn("URI users not supported", "type", chType) ch.Reject(UserNotSupported, "users are not supported in the channel URI") return true } else if uri.Host != "" { logger.Warn("URI hosts not supported", "type", chType) ch.Reject(HostNotSupported, "hosts are not supported in the channel URI") return true } return false }
// 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 handleChannel(newChannel ssh.NewChannel, config *SSHTestServer) { 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 { lo.G.Info("Could not accept channel (%s)", err) return } bash := exec.Command("bash") close := func() { connection.Close() _, err := bash.Process.Wait() if err != nil { lo.G.Info("Failed to exit bash (%s)", err) } lo.G.Info("Session closed") } lo.G.Info("Creating pty...") bashf, err := pty.Start(bash) if err != nil { lo.G.Info("Could not start pty (%s)", err) close() return } var once sync.Once var cmdBuffer = bytes.NewBufferString("") multiBashf := io.MultiWriter(cmdBuffer, bashf) go func() { io.Copy(multiBashf, connection) lo.G.Debug("done reading executor") once.Do(close) }() go func() { for { if strings.Contains(cmdBuffer.String(), config.SSHCommandMatch) { io.Copy(connection, bytes.NewBuffer(config.FakeResponseBytes)) cmdBuffer.Reset() } } }() go func() { io.Copy(cmdBuffer, bashf) once.Do(close) }() go func() { for req := range requests { switch req.Type { case "shell": // We only accept the default shell // (i.e. no command in the Payload) 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) // Responding true (OK) here will let the client // know we have a pty ready for input req.Reply(true, nil) case "window-change": w, h := parseDims(req.Payload) SetWinsize(bashf.Fd(), w, h) } } }() }
func handleChannel(newChannel ssh.NewChannel, h *handler.Handler) { 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 } //http://play.golang.org/p/uN46-Pvd4O // Sessions have out-of-band requests such as "shell", "pty-req" and "env" go func() { for req := range requests { switch req.Type { case "pty-req": req.Reply(true, nil) break case "env": req.Reply(true, nil) break case "shell": // We only accept the default shell // (i.e. no command in the Payload) if len(req.Payload) == 0 { req.Reply(true, nil) } break default: req.Reply(true, nil) } } }() /* //http://play.golang.org/p/uN46-Pvd4O // Sessions have out-of-band requests such as "shell", "pty-req" and "env" //we try to utilize it go func() { for req := range requests { switch req.Type { case "shell": if len(req.Payload) == 0 { fmt.Println("Normal login.") req.Reply(true, nil) } else { cmd := fmt.Sprintf("Trying to execute command via `shell`: %v\n", string(req.Payload)) connection.Write([]byte(cmd)) fmt.Println(cmd) req.Reply(false, nil) } break case "exec": cmd := fmt.Sprintf("Trying to execute command via `exec`: %v\n", string(req.Payload)) connection.Write([]byte(cmd)) req.Reply(false, nil) fmt.Println(cmd) break default: req.Reply(true, nil) } } }() */ handler.Board[h.SessionID] = h term := terminal.NewTerminal(connection, h.PrintPrompt()) term.AutoCompleteCallback = h.AutoCompleteCallback h.Term = term h.Connection = connection h.PrintHelpForUser([]string{}) msgs, err := h.GetMessages(100) if err != nil { panic(err) } for _, v := range msgs { h.PrintNotification(&v) } go func() { for { n1 := <-h.Nerve h.PrintNotification(&n1) } }() go func() { defer func() { connection.Close() delete(handler.Board, h.SessionID) h.Leave([]string{}) }() for { line, err := term.ReadLine() if err != nil { break } h.ProcessCommand(line) } }() }
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, requests, err := newChannel.Accept() if err != nil { log.Printf("Could not accept channel (%s)", err) return } // Fire up bash for this session bash := exec.Command("bash") // Prepare teardown function close := func() { connection.Close() _, err := bash.Process.Wait() if err != nil { log.Printf("Failed to exit bash (%s)", err) } log.Printf("Session closed") } // Allocate a terminal for this channel log.Print("Creating pty...") bashf, err := pty.Start(bash) if err != nil { log.Printf("Could not start pty (%s)", err) close() return } //pipe session to bash and visa-versa var once sync.Once go func() { io.Copy(connection, bashf) once.Do(close) }() go func() { io.Copy(bashf, connection) once.Do(close) }() // Sessions have out-of-band requests such as "shell", "pty-req" and "env" go func() { for req := range requests { switch req.Type { case "shell": // We only accept the default shell // (i.e. no command in the Payload) 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) // Responding true (OK) here will let the client // know we have a pty ready for input req.Reply(true, nil) case "window-change": w, h := parseDims(req.Payload) SetWinsize(bashf.Fd(), w, h) } } }() }
/* handleChannel proxies a channel request command or shell to the ssh connection sc. */ func handleNewChannel(cr ssh.NewChannel, sc ssh.Conn, info string) { log.Printf( "%v Type:%q Data:%q NewChannel", info, cr.ChannelType(), cr.ExtraData(), ) /* Make the same request to the other side */ och, oreqs, err := sc.OpenChannel(cr.ChannelType(), cr.ExtraData()) if nil != err { /* If we can't log it, and reject the client */ oe, ok := err.(*ssh.OpenChannelError) var ( reason ssh.RejectionReason message string ) if !ok { log.Printf( "%v Type:%q Data:%q Unable to open channel: "+ "%v", info, cr.ChannelType(), cr.ExtraData(), err, ) reason = ssh.ConnectionFailed message = "Fail" message = err.Error() } else { log.Printf( "%v Type:%q Data:%q Reason:%q Message:%q "+ "Unable to open channel", info, cr.ChannelType(), cr.ExtraData(), oe.Reason.String(), oe.Message, ) reason = oe.Reason message = oe.Message } if err := cr.Reject(reason, message); nil != err { log.Printf( "%v Unable to pass on channel rejecton "+ "request: %v", info, err, ) } return } defer och.Close() /* Accept the channel request from the requestor */ rch, rreqs, err := cr.Accept() if nil != err { log.Printf( "%v Unable to accept request for a channel of type "+ "%q: %v", cr.ChannelType(), info, err, ) return } defer rch.Close() /* Handle passing requests between channels */ hcrinfo := fmt.Sprintf(" %v ChannelType:%q", info, cr.ChannelType()) go handleChannelRequests( rreqs, och, hcrinfo+" ReqDir:AsDirection", ) go handleChannelRequests( oreqs, rch, hcrinfo+" ReqDir:AgainstDirection", ) log.Printf( "%v Type:%q Data:%q Opened", info, cr.ChannelType(), cr.ExtraData(), ) /* For now, print out read data */ done := make(chan struct{}, 4) go copyOut(och, rch, done) go copyOut(rch, och, done) go copyOut(och.Stderr(), rch.Stderr(), done) go copyOut(rch.Stderr(), och.Stderr(), done) /* Wait for a pipe to break */ <-done fmt.Printf("\nDone.\n") }