Пример #1
1
func (ctrl *Controller) terminal(ctx scope.Context, ch ssh.Channel) {
	defer ch.Close()

	lines := make(chan string)
	term := terminal.NewTerminal(ch, "> ")

	go func() {
		for ctx.Err() == nil {
			line, err := term.ReadLine()
			if err != nil {
				ctx.Terminate(err)
				return
			}
			lines <- line
		}
	}()

	for {
		var line string
		select {
		case <-ctx.Done():
			return
		case line = <-lines:
		}

		cmd := parse(line)
		fmt.Printf("[control] > %v\n", cmd)
		switch cmd[0] {
		case "":
			continue
		case "quit":
			return
		case "shutdown":
			ctrl.ctx.Terminate(fmt.Errorf("shutdown initiated from console"))
		default:
			runCommand(ctx.Fork(), ctrl, cmd[0], term, cmd[1:])
		}
	}
}
Пример #2
0
func handleSessionRequests(logger log.Logger, channel ssh.Channel, requests <-chan *ssh.Request, system datamodel.System, user datamodel.User) {
	defer channel.Close()

	// Sessions have out-of-band requests such as "shell",
	// "pty-req" and "env".  Here we handle only the
	// "shell" request.
	for req := range requests {

		ok := false
		switch req.Type {
		case "shell":
			ok = true

			if len(req.Payload) > 0 {
				fmt.Println(string(req.Payload))
				// We don't accept any
				// commands, only the
				// default shell.
				ok = false
			}

		case "pty-req":
			// Responding 'ok' here will let the client
			// know we have a pty ready for input
			ok = true

			go startTerminal(logger, channel, system, user)
		default:
			// fmt.Println("default req: ", req)
		}

		req.Reply(ok, nil)
	}
}
Пример #3
0
func (handle *handle) Request(ch ssh.Channel, req *ssh.Request) (bool, error) {
	config.Log.Debug("handle %s", req.Type)
	switch req.Type {
	case "pty-req":
		fallthrough
	case "shell":
		return true, ShellDisabled
	case "env":
		// we store these off??
		return false, nil
	case "exec":
		// it is prefixed with the length so we strip it off
		command := string(req.Payload[4:])
		config.Log.Debug("handle cmd %s", command)
		// find the correct handler and run it
		config.Log.Debug("looking for command in %d", len(repo.Commands()))
		for _, cmd := range repo.Commands() {
			if cmd.Match(command) {
				config.Log.Debug("found match", command)
				code, err := cmd.Run(command, ch)
				exitStatusBuffer := make([]byte, 4)
				binary.PutUvarint(exitStatusBuffer, uint64(code))
				config.Log.Debug("cmd finished", code, err)
				// purposefully ignoring the possible error
				ch.SendRequest("exit-status", false, exitStatusBuffer)
				return true, err
			}
		}

		return true, UnknownCommand
	}
	return true, UnkownRequest
}
Пример #4
0
func handleChannel(s *Stream, ch ssh.Channel, reqs <-chan *ssh.Request, handle func(*Stream)) {

	// handle requests receive for this Channel
	go func(in <-chan *ssh.Request) {
		for req := range in {
			logrus.Debugln("AdminTool -> Request of type:", req.Type, "len:", len(req.Type))
			logrus.Debugln("AdminTool -> Request payload:", string(req.Payload), "len:", len(req.Payload))

			if req.WantReply {
				req.Reply(false, nil)
			}
		}
		logrus.Debugln("AdminTool -> End of request GO chan")
	}(reqs)

	// read data from channel
	go func() {
		for {
			buffer := make([]byte, 64)
			n, err := ch.Read(buffer)
			if err != nil {
				if err.Error() == "EOF" {
					handleData(s, []byte{}, true)
					// all data received: handle Stream message
					handle(s)
					break
				} else {
					logrus.Fatalln("failed to read channel : " + err.Error())
				}
			}
			handleData(s, buffer[:n], false)
		}
	}()
}
Пример #5
0
func ProxyRequests(logger lager.Logger, channelType string, reqs <-chan *ssh.Request, channel ssh.Channel) {
	logger = logger.Session("proxy-requests", lager.Data{
		"channel-type": channelType,
	})

	logger.Info("started")
	defer logger.Info("completed")
	defer channel.Close()

	for req := range reqs {
		logger.Info("request", lager.Data{
			"type":      req.Type,
			"wantReply": req.WantReply,
			"payload":   req.Payload,
		})
		success, err := channel.SendRequest(req.Type, req.WantReply, req.Payload)
		if err != nil {
			logger.Error("send-request-failed", err)
			continue
		}

		if req.WantReply {
			req.Reply(success, nil)
		}
	}
}
Пример #6
0
func pipeRequests(psChannel, sChannel ssh.Channel, psRequests, sRequests <-chan *ssh.Request) {
	defer func() {
		return
		if r := recover(); r != nil {
			fmt.Println("Recovered in f", r)
		}
	}()
	defer sChannel.Close()
	defer psChannel.Close()

	for {
		select {
		case lRequest, ok := <-psRequests:
			if !ok {
				return
			}
			if err := forwardRequest(lRequest, sChannel); err != nil {
				fmt.Println("Error: " + err.Error())
				continue
			}
		case rRequest, ok := <-sRequests:
			if !ok {
				return
			}
			if err := forwardRequest(rRequest, psChannel); err != nil {
				fmt.Println("Error: " + err.Error())
				continue
			}
		}
	}
}
Пример #7
0
func attachCmd(cmd *exec.Cmd, ch ssh.Channel) (*sync.WaitGroup, error) {
	var wg sync.WaitGroup
	wg.Add(3)

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return nil, err
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return nil, err
	}
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return nil, err
	}

	go func() {
		defer wg.Done()
		io.Copy(stdin, ch)
	}()

	go func() {
		defer wg.Done()
		io.Copy(ch.Stderr(), stderr)
	}()

	go func() {
		defer wg.Done()
		io.Copy(ch, stdout)
	}()

	return &wg, nil
}
Пример #8
0
func pipe(dst, src ssh.Channel) {
	_, err := io.Copy(dst, src)
	if err != nil {
		fmt.Println(err.Error())
	}

	dst.CloseWrite()
}
Пример #9
0
// Ping handles a simple test SSH exec.
//
// Returns the string PONG and exit status 0.
//
// Params:
// 	- channel (ssh.Channel): The channel to respond on.
// 	- request (*ssh.Request): The request.
//
func Ping(channel ssh.Channel, req *ssh.Request) error {
	log.Info("PING")
	if _, err := channel.Write([]byte("pong")); err != nil {
		log.Err("Failed to write to channel: %s", err)
	}
	sendExitStatus(0, channel)
	req.Reply(true, nil)
	return nil
}
Пример #10
0
func (s *shellHandler) Handle(parentTomb tomb.Tomb, sshConn *ssh.ServerConn, channel ssh.Channel, requests <-chan *ssh.Request) error {
	defer channel.Close()

	users, err := s.system.Users()
	if err != nil {
		return err
	}

	user, err := users.Get(sshConn.Permissions.Extensions["username"])
	if err != nil {
		return err
	}

	// Create tomb for terminal goroutines
	var t tomb.Tomb

	// Sessions have out-of-band requests such as "shell",
	// "pty-req" and "env".  Here we handle only the
	// "shell" request.
	for {
		select {
		case <-parentTomb.Dying():
			t.Kill(nil)
			return t.Wait()
		case req := <-requests:

			ok := false
			switch req.Type {
			case "shell":
				ok = true

				if len(req.Payload) > 0 {
					fmt.Println(string(req.Payload))
					// We don't accept any
					// commands, only the
					// default shell.
					ok = false
				}

			case "pty-req":
				// Responding 'ok' here will let the client
				// know we have a pty ready for input
				ok = true

				go s.startTerminal(t, channel, s.system, user)
			default:
				// fmt.Println("default req: ", req)
			}

			req.Reply(ok, nil)
		}
	}
	return nil
}
Пример #11
0
func (s *shellHandler) Handle(parentTomb tomb.Tomb, sshConn *ssh.ServerConn, channel ssh.Channel, requests <-chan *ssh.Request) error {
	defer channel.Close()
	s.logger.Info("WooHoo!!! Inside Handler!")

	// Create tomb for terminal goroutines
	var t tomb.Tomb

	// Sessions have out-of-band requests such as "shell",
	// "pty-req" and "env".  Here we handle only the
	// "shell" request.
	t.Go(func() error {
	OUTER:
		for {
			select {
			case <-parentTomb.Dying():
				t.Kill(nil)
				break OUTER
			case req := <-requests:
				if req == nil {
					break OUTER
				}

				ok := false
				switch req.Type {
				case "shell":
					ok = true

					if len(req.Payload) > 0 {
						// fmt.Println(string(req.Payload))

						// We don't accept any
						// commands, only the
						// default shell.
						ok = false
					}

				case "pty-req":
					// Responding 'ok' here will let the client
					// know we have a pty ready for input
					ok = true

					t.Go(func() error {
						return s.startTerminal(t, sshConn, channel)
					})
				}

				req.Reply(ok, nil)
			}
		}
		return nil
	})
	return t.Wait()
}
Пример #12
0
// plumbCommand connects the exec in/output and the channel in/output.
//
// The sidechannel is for sending errors to logs.
func plumbCommand(cmd *exec.Cmd, channel ssh.Channel, sidechannel io.Writer) *sync.WaitGroup {
	var wg sync.WaitGroup
	inpipe, _ := cmd.StdinPipe()
	go func() {
		io.Copy(inpipe, channel)
		inpipe.Close()
	}()

	cmd.Stdout = channel
	cmd.Stderr = channel.Stderr()

	return &wg
}
Пример #13
0
func (push Push) Run(command string, ch ssh.Channel) (uint64, error) {
	//TODO make "master" be dynamic
	code, err := gitShell(ch, ch.Stderr(), command)
	if err == nil {
		newCommit := getCommit("master")
		stream := ch.Stderr()
		err = deploy.Run(stream, newCommit)
		if err != nil {
			return 1, err
		}
	}
	return code, err
}
Пример #14
0
func handleChannelRequests(logger log.Logger, channel ssh.Channel, requests <-chan *ssh.Request, system datamodel.System, user datamodel.User) {
	defer channel.Close()

	for req := range requests {
		if req.Type == "skl" {
			logger.Info("SKL request", "request", string(req.Payload))
			req.Reply(true, nil)
		} else {
			if req.WantReply {
				req.Reply(false, nil)
			}
		}
	}
}
Пример #15
0
func sendCmdResult(channel ssh.Channel, result []byte, statusCode uint32) error {
	if _, err := channel.Write(result); err != nil {
		return fmt.Errorf("failed to write to ssh-channel: %v", err)
	}
	status := struct {
		Status uint32
	}{
		statusCode,
	}
	_, err := channel.SendRequest("exit-status", false, ssh.Marshal(&status))
	if err != nil {
		return fmt.Errorf("failed to SendRequest: %v", err)
	}
	return nil
}
Пример #16
0
func (sshd *SSHD) handleChannel(channel ssh.Channel, requests <-chan *ssh.Request, container string) {
	cmd := exec.Command("docker", "exec", "-i", "-t", container, "/bin/bash")
	closeChannel := func() {
		channel.Close()
		_, err := cmd.Process.Wait()
		if err != nil {
			log.Errorf("failed to exit docker exec (%s)", err)
		}
	}

	fp, err := pty.Start(cmd)
	if err != nil {
		log.Error("pty.Start: ", err)
		closeChannel()
		return
	}

	go func() {
		for req := range requests {
			log.Debugf("new request: %s", req.Type)
			switch req.Type {
			case "shell":
				if len(req.Payload) == 0 {
					req.Reply(true, nil)
				}
			case "pty-req":
				termLen := req.Payload[3]
				w, h := sshd.parseDims(req.Payload[termLen+4:])
				sshd.setWinsize(fp.Fd(), w, h)
				req.Reply(true, nil)
			case "window-change":
				w, h := sshd.parseDims(req.Payload)
				sshd.setWinsize(fp.Fd(), w, h)
			case "env":
			}
		}
	}()

	var once sync.Once
	cp := func(dst io.Writer, src io.Reader) {
		io.Copy(dst, src)
		once.Do(closeChannel)
	}
	go cp(channel, fp)
	go cp(fp, channel)
}
Пример #17
0
func (s *shellHandler) startTerminal(parentTomb tomb.Tomb, sshConn *ssh.ServerConn, channel ssh.Channel) error {
	defer channel.Close()

	prompt := ">>> "
	term := terminal.NewTerminal(channel, prompt)

	// // Try to make the terminal raw
	// oldState, err := terminal.MakeRaw(0)
	// if err != nil {
	//     logger.Warn("Error making terminal raw: ", err.Error())
	// }
	// defer terminal.Restore(0, oldState)

	// Get username
	username, ok := sshConn.Permissions.Extensions["username"]
	if !ok {
		username = "******"
	}

	// Write ascii text
	term.Write([]byte(fmt.Sprintf("\r\n Nice job, %s! You are connected!\r\n", username)))
	defer term.Write([]byte(fmt.Sprintf("\r\nGoodbye, %s!\r\n", username)))

	// Start REPL
	for {

		select {
		case <-parentTomb.Dying():
			return nil
		default:
			s.logger.Info("Reading line...")
			input, err := term.ReadLine()
			if err != nil {
				fmt.Errorf("Readline() error")
				return err
			}

			// Process line
			line := strings.TrimSpace(input)
			if len(line) > 0 {

				// Log input and handle exit requests
				if line == "exit" || line == "quit" {
					s.logger.Info("Closing connection")
					return nil
				}

				// Echo input
				channel.Write(term.Escape.Green)
				channel.Write([]byte(line + "\r\n"))
				channel.Write(term.Escape.Reset)
			}
		}
	}
	return nil
}
Пример #18
0
//Reply handles the operation between a req and channel
func Reply(req *ssh.Request, dest ssh.Channel, c *ConnInsight) {

	dx, err := dest.SendRequest(req.Type, req.WantReply, req.Payload)

	checkError(err, fmt.Sprintf("Request %s processed", req.Type))

	if req.WantReply {
		req.Reply(dx, nil)
	}

	meta := map[string]interface{}{
		"type":    "reply",
		"name":    req.Type,
		"payload": req.Payload,
	}

	c.Aux().Emit(meta)
}
Пример #19
0
func (s *sshServer) handleRequests(channel ssh.Channel, in <-chan *ssh.Request) error {
	env := make(map[string]string)

	for req := range in {
		switch req.Type {
		default:
			log.Printf("unrecognized ssh request type=%q payload=%s wantreply=%t", req.Type, req.Payload, req.WantReply)
			req.Reply(false, nil) // unhandled; tell them so

		case "env":
			var e envReq
			if err := ssh.Unmarshal(req.Payload, &e); err != nil {
				req.Reply(false, nil)
				return err
			}
			req.Reply(true, nil)
			env[string(e.Key)] = string(e.Val)

		case "exec":
			var e execReq
			if err := ssh.Unmarshal(req.Payload, &e); err != nil {
				req.Reply(false, nil)
				return err
			}
			req.Reply(true, nil)

			var cmdbuf bytes.Buffer
			for k, v := range env {
				cmdbuf.WriteString(k)
				cmdbuf.WriteByte('=')
				cmdbuf.WriteString(v)
				cmdbuf.WriteByte(' ')
			}
			cmdbuf.Write(e.Command)

			log.Printf("Running command %q", cmdbuf.String())
			cmd := &packer.RemoteCmd{Command: cmdbuf.String()}
			cmd.Stdout = channel
			cmd.Stderr = channel.Stderr()
			var rc int
			if err := s.comm.Start(cmd); err != nil {
				rc = 255 // TODO: What is a better choice here?
			} else {
				cmd.Wait()
				rc = cmd.ExitStatus
			}
			channel.CloseWrite()
			channel.SendRequest("exit-status", false, []byte{0, 0, 0, byte(rc)})
			channel.Close()
		}
	}

	return nil
}
Пример #20
0
func handleChannel(ch ssh.Channel) {
	term := terminal.NewTerminal(ch, "> ")
	serverTerm := &ssh.ServerTerminal{
		Term:    term,
		Channel: ch,
	}
	ch.Accept()
	defer ch.Close()
	for {
		line, err := serverTerm.ReadLine()
		if err == io.EOF {
			return
		}
		if err != nil {
			log.Println("handleChannel readLine err:", err)
			continue
		}
		fmt.Println(line)
	}
}
Пример #21
0
func forwardRequest(req *ssh.Request, channel ssh.Channel) error {
	if string(req.Type) != "subsystem" && string(req.Type) != "exit-status" {
		req.Reply(false, nil)

		if req.Type == "env" {
			return nil
		}

		return fmt.Errorf("Ignoring unsupported request type: %s", string(req.Type))
	}
	reply, err := channel.SendRequest(req.Type, req.WantReply, req.Payload)
	if err != nil {
		return err
	}
	if req.WantReply {
		req.Reply(reply, nil)
	}

	return nil
}
Пример #22
0
func handleExec(ch ssh.Channel, req *ssh.Request) {
	cmd := string(req.Payload[4:])
	log.Println("received cmd", cmd)

	var msg string
	switch cmd {
	case "open", "close":
		err := sendCommand(cmd)
		if err != nil {
			log.Println("could not write to ctrl sock:", err)
			msg = "error: could not write to socket"
		} else {
			log.Printf("sent command '%s' to ctrl", cmd)
			msg = "ok"
		}
	default:
		msg = "invalid command " + cmd
	}

	ch.Write([]byte(msg + "\r\n"))
}
Пример #23
0
/* handleChannelRequests handles proxying requests read from reqs to the SSH
channel c.  info is used for logging. */
func handleChannelRequests(
	reqs <-chan *ssh.Request,
	c ssh.Channel,
	info string,
) {
	for r := range reqs {
		go handleRequest(
			r,
			func( /* Ugh, a closure */
				name string,
				wantReply bool,
				payload []byte,
			) (bool, []byte, error) {
				b, e := c.SendRequest(name, wantReply, payload)
				return b, nil, e
			},
			func() error { return c.Close() }, /* Another? */
			info,
		)
	}
}
Пример #24
0
Файл: scp.go Проект: zqzca/back
func (s *scpRequest) ParseSCPRequest(channel ssh.Channel, req *ssh.Request) error {
	var err error

	// Parse the payload received from the scp client
	if s.original, err = parsePayload(req.Payload); err != nil {
		return err
	}
	log.Println("being sent file:", s.original)

	// Acknowledge payload.
	if _, err = channel.Write(zeroByte); err != nil {
		return errors.Wrap(err, "failed to write")
	}

	// Receive SCP Header
	scpHeader := make([]byte, 2048) // size of buf in openssh
	if _, err = channel.Read(scpHeader); err != nil {
		return errors.Wrap(err, "failed to retrieve header")
	}

	if _, s.size, _, err = parseHeader(scpHeader); err != nil {
		return errors.Wrap(err, "failed to parse scp header")
	}

	// Acknowledge We have received the SCP Header
	if _, err = channel.Write(zeroByte); err != nil {
		return errors.Wrap(err, "failed to reply to scp header")
	}

	return nil
}
Пример #25
0
func (s *SSHServer) execHandler(channel ssh.Channel, request *ssh.Request) error {
	defer channel.Close()

	var payload = struct {
		Value string
	}{}
	if err := ssh.Unmarshal(request.Payload, &payload); err != nil {
		return fmt.Errorf("failed to unmarshal payload: %v", err)
	}

	result, status, err := s.runCmd(payload.Value)
	if err != nil {
		return fmt.Errorf("failed to run command: %v", err)
	}
	if err := sendCmdResult(channel, result, status); err != nil {
		return fmt.Errorf("failed to send result: %v", err)
	}
	if err := request.Reply(true, nil); err != nil {
		return fmt.Errorf("failed to send reply: %v", err)
	}
	return nil
}
Пример #26
0
// This executes the commands requested to be run on the server.
// Used to test the SSH secret backend.
func executeServerCommand(ch ssh.Channel, req *ssh.Request) {
	command := string(req.Payload[4:])
	cmd := exec.Command("/bin/bash", []string{"-c", command}...)
	req.Reply(true, nil)

	cmd.Stdout = ch
	cmd.Stderr = ch
	cmd.Stdin = ch

	err := cmd.Start()
	if err != nil {
		panic(fmt.Sprintf("Error starting the command: '%s'", err))
	}

	go func() {
		_, err := cmd.Process.Wait()
		if err != nil {
			panic(fmt.Sprintf("Error while waiting for command to finish:'%s'", err))
		}
		ch.Close()
	}()
}
Пример #27
0
func (s *SSHServer) shellHandler(channel ssh.Channel) error {
	defer channel.Close()

	term := terminal.NewTerminal(channel, "# ")
	for {
		line, err := term.ReadLine()
		if err != nil {
			break
		}
		if line == "" {
			return nil
		}

		result, status, err := s.runCmd(line)
		if err != nil {
			return fmt.Errorf("failed to run command: %v", err)
		}
		if err := sendCmdResult(channel, result, status); err != nil {
			return fmt.Errorf("failed to send result: %v", err)
		}
	}
	return nil
}
Пример #28
0
func forwardUnixSocket(channel ssh.Channel, addr string) {
	conn, err := net.Dial("unix", addr)
	if err != nil {
		return
	}

	var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		io.Copy(conn, channel)
		conn.(*net.UnixConn).CloseWrite()
		wg.Done()
	}()
	go func() {
		io.Copy(channel, conn)
		channel.CloseWrite()
		wg.Done()
	}()

	wg.Wait()
	conn.Close()
	channel.Close()
}
Пример #29
0
func proxy(reqs1, reqs2 <-chan *ssh.Request, channel1, channel2 ssh.Channel) {
	var closer sync.Once
	closeFunc := func() {
		channel1.Close()
		channel2.Close()
	}

	defer closer.Do(closeFunc)

	closerChan := make(chan bool, 1)

	go func() {
		io.Copy(channel1, channel2)
		closerChan <- true
	}()

	go func() {
		io.Copy(channel2, channel1)
		closerChan <- true
	}()

	for {
		select {
		case req := <-reqs1:
			if req == nil {
				return
			}
			b, err := channel2.SendRequest(req.Type, req.WantReply, req.Payload)
			if err != nil {
				return
			}
			req.Reply(b, nil)

		case req := <-reqs2:
			if req == nil {
				return
			}
			b, err := channel1.SendRequest(req.Type, req.WantReply, req.Payload)
			if err != nil {
				return
			}
			req.Reply(b, nil)
		case <-closerChan:
			return
		}
	}
}
Пример #30
-1
func pipe(ch ssh.Channel, client *ssh.Client, session *ssh.Session, command string) (int, error) {
	targetStderr, err := session.StderrPipe()
	if err != nil {
		return -1, errors.New("fail to pipe stderr: " + err.Error())
	}
	targetStdout, err := session.StdoutPipe()
	if err != nil {
		return -1, errors.New("fail to pipe stdout: " + err.Error())
	}
	targetStdin, err := session.StdinPipe()
	if err != nil {
		return -1, errors.New("fail to pipe stdin: " + err.Error())
	}

	go io.Copy(targetStdin, ch)
	go io.Copy(ch.Stderr(), targetStderr)
	go io.Copy(ch, targetStdout)

	err = session.Start(command)
	if err != nil {
		ch.Write([]byte("Error when starting '" + command + "': " + err.Error()))
		ch.Close()
	}

	err = session.Wait()
	if err != nil {
		if err, ok := err.(*ssh.ExitError); ok {
			return err.ExitStatus(), nil
		} else {
			return -1, errors.New("failed to wait ssh command: " + err.Error())
		}
	}

	return 0, nil
}