func (sess *session) handleExecRequest(request *ssh.Request) {
	logger := sess.logger.Session("handle-exec-request")

	type execMsg struct {
		Command string
	}
	var execMessage execMsg

	err := ssh.Unmarshal(request.Payload, &execMessage)
	if err != nil {
		logger.Error("unmarshal-failed", err)
		if request.WantReply {
			request.Reply(false, nil)
		}
		return
	}

	if scpRegex.MatchString(execMessage.Command) {
		logger.Info("handling-scp-command", lager.Data{"Command": execMessage.Command})
		sess.executeSCP(execMessage.Command, request)
	} else {
		logger.Info("executeShell", lager.Data{"request": request, "command": execMessage.Command})
		sess.executeShell(request, "-c", execMessage.Command)
	}
}
예제 #2
0
파일: server.go 프로젝트: aledbf/builder
func (s *server) runReceive(
	req *ssh.Request,
	sshConn *ssh.ServerConn,
	channel ssh.Channel,
	repoName string,
	parts []string,
	connData string,
) func() error {
	return func() error {
		req.Reply(true, nil) // We processed. Yay.
		if !strings.Contains(sshConn.Permissions.Extensions["apps"], repoName) {
			return errBuildAppPerm
		}
		repo := repoName + ".git"
		recvErr := git.Receive(
			repo,
			parts[0],
			s.gitHome,
			channel,
			sshConn.Permissions.Extensions["fingerprint"],
			sshConn.Permissions.Extensions["user"],
			connData,
			s.receivetype,
		)
		if recvErr != nil {
			return recvErr
		}
		return nil
	}
}
예제 #3
0
func (h *sshHandler) handleEnv(req *ssh.Request) {
	var pair EnvVar
	ssh.Unmarshal(req.Payload, &pair)
	envvar := fmt.Sprintf("%s=%s", pair.Name, pair.Value)
	h.Env = append(h.Env, envvar)
	req.Reply(true, nil)
}
func (sess *session) handleSignalRequest(request *ssh.Request) {
	logger := sess.logger.Session("handle-signal-request")

	type signalMsg struct {
		Signal string
	}
	var signalMessage signalMsg

	err := ssh.Unmarshal(request.Payload, &signalMessage)
	if err != nil {
		logger.Error("unmarshal-failed", err)
		if request.WantReply {
			request.Reply(false, nil)
		}
		return
	}

	sess.Lock()
	defer sess.Unlock()

	cmd := sess.command

	if cmd != nil {
		signal := signals.SyscallSignals[ssh.Signal(signalMessage.Signal)]
		err := sess.runner.Signal(cmd, signal)
		if err != nil {
			logger.Error("process-signal-failed", err)
		}
	}

	if request.WantReply {
		request.Reply(true, nil)
	}
}
func (sess *session) handlePtyRequest(request *ssh.Request) {
	logger := sess.logger.Session("handle-pty-request")

	var ptyRequestMessage ptyRequestMsg

	err := ssh.Unmarshal(request.Payload, &ptyRequestMessage)
	if err != nil {
		logger.Error("unmarshal-failed", err)
		if request.WantReply {
			request.Reply(false, nil)
		}
		return
	}

	sess.Lock()
	defer sess.Unlock()

	sess.allocPty = true
	sess.ptyRequest = ptyRequestMessage
	sess.env["TERM"] = ptyRequestMessage.Term

	if request.WantReply {
		request.Reply(true, nil)
	}
}
예제 #6
0
func rejectRequest(req *ssh.Request) error {
	fmt.Fprintf(sshServerDebugStream, "ssh rejecting request, type: %s\n", req.Type)
	err := req.Reply(false, []byte{})
	if err != nil {
		fmt.Fprintf(sshServerDebugStream, "ssh request reply had error: %v\n", err)
	}
	return err
}
예제 #7
0
파일: server.go 프로젝트: aledbf/builder
// 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
}
예제 #8
0
func (chsvr *sshSessionChannelServer) handleSubsystem(req *ssh.Request) error {
	defer func() {
		err1 := chsvr.ch.CloseWrite()
		err2 := chsvr.ch.Close()
		fmt.Fprintf(sshServerDebugStream, "ssh server subsystem request complete, err: %v %v\n", err1, err2)
	}()

	subsystemReq := &sshSubsystemRequest{}
	if err := ssh.Unmarshal(req.Payload, subsystemReq); err != nil {
		return rejectRequestUnmarshalError(req, subsystemReq, err)
	}

	// reply to the ssh client

	// no idea if this is actually correct spec-wise.
	// just enough for an sftp server to start.
	if subsystemReq.Name != "sftp" {
		return req.Reply(false, nil)
	}

	req.Reply(true, nil)

	if !chsvr.svr.useSubsystem {
		// use the openssh sftp server backend; this is to test the ssh code, not the sftp code,
		// or is used for comparison between our sftp subsystem and the openssh sftp subsystem
		cmd := exec.Command(*testSftp, "-e", "-l", "DEBUG") // log to stderr
		cmd.Stdin = chsvr.ch
		cmd.Stdout = chsvr.ch
		cmd.Stderr = sftpServerDebugStream
		if err := cmd.Start(); err != nil {
			return err
		}
		return cmd.Wait()
	}

	sftpServer, err := NewServer(
		chsvr.ch,
		chsvr.ch,
		WithDebug(sftpServerDebugStream),
	)
	if err != nil {
		return err
	}

	// wait for the session to close
	runErr := sftpServer.Serve()
	exitStatus := uint32(1)
	if runErr == nil {
		exitStatus = uint32(0)
	}

	_, exitStatusErr := chsvr.ch.SendRequest("exit-status", false, ssh.Marshal(sshSubsystemExitStatus{exitStatus}))
	return exitStatusErr
}
예제 #9
0
func (h *sshHandler) Request(req *ssh.Request) {
	switch req.Type {
	case "exec":
		h.handleExec(req)
	case "pty-req":
		h.handlePty(req)
	case "window-change":
		h.handleWinch(req)
	default:
		if req.WantReply {
			req.Reply(true, nil)
		}
	}
}
func (sess *session) executeSCP(command string, request *ssh.Request) {
	logger := sess.logger.Session("execute-scp")

	if request.WantReply {
		request.Reply(true, nil)
	}

	copier, err := scp.NewFromCommand(command, sess.channel, sess.channel, sess.channel.Stderr(), logger)
	if err == nil {
		err = copier.Copy()
	}

	sess.sendSCPExitMessage(err)
	sess.destroy()
}
예제 #11
0
func (c *Channel) HandleRequest(request *ssh.Request) {
	glog.V(9).Infof("request received: type = %s, want_reply = %v, payload = %v", request.Type, request.WantReply, request.Payload)

	// check parameters
	ok := false
	switch request.Type {
	case "env":
		// just ignore the env settings from client
		ok = true

	case "shell":
		// let client open shell without any command
		if len(request.Payload) > 0 {
			break
		}
		ok = true
	}

	// reply to client
	if request.WantReply {
		if err := request.Reply(ok, nil); err != nil {
			glog.Warningf("failed to reply to request: %s", err)
		}
	}

	// do actual work here
	switch request.Type {
	case "shell":
		defer c.Close()
		status := c.Session().Gateway().Status()
		encoded, err := json.MarshalIndent(status, "", "  ")
		if err != nil {
			glog.Warningf("failed to marshal status: %s", err)
			break
		}

		if _, err := c.Write(encoded); err != nil {
			glog.Warningf("failed to send status: %s", err)
			break
		}

		if _, err := c.Write([]byte("\n")); err != nil {
			glog.Warningf("failed to send status: %s", err)
			break
		}
	}
}
예제 #12
0
func (s *Session) HandleRequest(request *ssh.Request) {
	glog.V(9).Infof("request received: type = %s, want_reply = %v, payload = %v", request.Type, request.WantReply, request.Payload)

	ok := false
	switch request.Type {
	case "tcpip-forward":
		request, err := UnmarshalForwardRequest(request.Payload)
		if err != nil {
			glog.Errorf("failed to decode request: %s", err)
			break
		}

		if request.Port == 0 {
			glog.Errorf("requested forwarding port is not allowed: %d", request.Port)
			break
		}

		if err := s.RegisterService(request.Host, uint16(request.Port)); err != nil {
			glog.Errorf("failed to register service in session: %s", err)
			break
		}

		ok = true

	case "cancel-tcpip-forward":
		request, err := UnmarshalForwardRequest(request.Payload)
		if err != nil {
			glog.Errorf("failed to decode request: %s", err)
			break
		}

		if err := s.DeregisterService(request.Host, uint16(request.Port)); err != nil {
			glog.Errorf("failed to register service in session: %s", err)
			break
		}

		ok = true

	}

	if request.WantReply {
		if err := request.Reply(ok, nil); err != nil {
			glog.Warningf("failed to reply to request: %s", err)
		}
	}
}
예제 #13
0
파일: ssh.go 프로젝트: influx6/proxies
//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)
}
예제 #14
0
/* handleRequest handles proxying a request r via sr, which should be a closure
which sends the request passed to it on a channel or SSH connection.  If the
request can't be proxied, cl will be called to close whatever sr sends r on.
info is used for logging. */
func handleRequest(
	r *ssh.Request,
	sr func(
		name string,
		wantReply bool,
		payload []byte,
	) (bool, []byte, error),
	cl func() error,
	info string) {
	/* If this is the wrong sort of request, respond no */
	if s, ok := delayedReqs[r.Type]; ok {
		log.Printf(
			"%v Type:%v Delay:%v",
			info,
			r.Type,
			s,
		)
		time.Sleep(s)
	}
	logRequest(r, info)
	/* Ask the other side */
	ok, data, err := sr(r.Type, r.WantReply, r.Payload)
	if nil != err {
		log.Printf(
			"%v Unable to receive reply for %v request: %v",
			info,
			r.Type,
			err,
		)
		cl()
		return
	}
	logRequestResponse(r, ok, data, info)
	/* Proxy back */
	if err := r.Reply(ok, nil); nil != err {
		log.Printf(
			"%v Unable to reply to %v request: %v",
			info,
			r.Type,
			err,
		)
		cl()
	}
}
예제 #15
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
}
예제 #16
0
func (chsvr *sshSessionChannelServer) handleEnv(req *ssh.Request) error {
	envReq := &sshEnvRequest{}
	if err := ssh.Unmarshal(req.Payload, envReq); err != nil {
		return rejectRequestUnmarshalError(req, envReq, err)
	}
	req.Reply(true, nil)

	found := false
	for i, envstr := range chsvr.env {
		if strings.HasPrefix(envstr, envReq.Envvar+"=") {
			found = true
			chsvr.env[i] = envReq.Envvar + "=" + envReq.Value
		}
	}
	if !found {
		chsvr.env = append(chsvr.env, envReq.Envvar+"="+envReq.Value)
	}

	return nil
}
예제 #17
0
func (h *sshHandler) handleExec(req *ssh.Request) {
	h.Lock()
	defer h.Unlock()

	var payload = struct{ Value string }{}
	ssh.Unmarshal(req.Payload, &payload)
	cmdline := payload.Value

	// Initialize Cmd
	var cmd *exec.Cmd
	if *shell {
		shellcmd := flag.Arg(1) + " " + cmdline
		cmd = exec.Command(os.Getenv("SHELL"), "-c", shellcmd)
	} else {
		cmdargs, err := shlex.Split(cmdline)
		if h.assert("exec shlex.Split", err) {
			h.channel.Close()
			return
		}
		cmd = exec.Command(h.ExecHandler[0], append(h.ExecHandler[1:], cmdargs...)...)
	}

	cmd.Env = append(h.Env, "SSH_ORIGINAL_COMMAND="+cmdline)
	cmd.Stdout = h.stdout
	cmd.Stderr = h.stderr

	// cmd.Wait closes the stdin when it's done, so we need to proxy it through a pipe
	stdinPipe, err := cmd.StdinPipe()
	if h.assert("exec cmd.StdinPipe", err) {
		h.channel.Close()
		return
	}
	go io.Copy(stdinPipe, h.channel)

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

	// We run inline to prevent concurrent exec requests for the channel as the lock is held.
	h.Exit(cmd.Run())
}
예제 #18
0
// Payload: int: command size, string: command
func handleExec(ch ssh.Channel, req *ssh.Request) {
	command := string(req.Payload[4:])
	gitCmds := []string{"git-receive-pack", "git-upload-pack"}

	valid := false
	for _, cmd := range gitCmds {
		if strings.HasPrefix(command, cmd) {
			valid = true
		}
	}
	req.Reply(true, []byte("0\r\n"))
	if !valid {
		ch.Write([]byte("command is not a GIT command\r\n"))

		ch.Close()
		return
	}

	ch.Write([]byte("well done!\r\n"))
	ch.Close()
}
예제 #19
0
func (sess *session) handleSubsystemRequest(request *ssh.Request) {
	logger := sess.logger.Session("handle-subsystem-request")
	logger.Info("starting")
	defer logger.Info("finished")

	type subsysMsg struct {
		Subsystem string
	}
	var subsystemMessage subsysMsg

	err := ssh.Unmarshal(request.Payload, &subsystemMessage)
	if err != nil {
		logger.Error("unmarshal-failed", err)
		if request.WantReply {
			request.Reply(false, nil)
		}
		return
	}

	if subsystemMessage.Subsystem != "sftp" {
		logger.Info("unsupported-subsystem", lager.Data{"subsystem": subsystemMessage.Subsystem})
		if request.WantReply {
			request.Reply(false, nil)
		}
		return
	}

	lagerWriter := helpers.NewLagerWriter(logger.Session("sftp-server"))
	sftpServer, err := sftp.NewServer(sess.channel, sess.channel, sftp.WithDebug(lagerWriter))
	if err != nil {
		logger.Error("sftp-new-server-failed", err)
		if request.WantReply {
			request.Reply(false, nil)
		}
		return
	}

	if request.WantReply {
		request.Reply(true, nil)
	}

	logger.Info("starting-server")
	go func() {
		defer sess.destroy()
		err = sftpServer.Serve()
		if err != nil {
			logger.Error("sftp-serve-error", err)
		}
	}()
}
예제 #20
0
/* handleRequest handles a single request, which is proxied to rable and logged
via lg. */
func handleRequest(
	r *ssh.Request,
	rable Requestable,
	lg *log.Logger,
	direction string,
) {
	rl := fmt.Sprintf(
		"Type:%q WantReply:%v Payload:%q Direction:%q",
		r.Type,
		r.WantReply,
		r.Payload,
		direction,
	)
	/* Ignore certain requests, because we're bad people */
	if IGNORENMS {
		for _, ir := range IGNOREREQUESTS {
			if 1 == subtle.ConstantTimeCompare(
				[]byte(r.Type),
				[]byte(ir),
			) {
				lg.Printf("Ignoring Request %s", rl)
				return
			}
		}
	}
	/* Proxy to server */
	ok, data, err := rable.SendRequest(r.Type, r.WantReply, r.Payload)
	if nil != err {
		lg.Printf("Unable to proxy request %s Error:%v", rl, err)
		return
	}

	/* TODO: Pass to server */
	if err := r.Reply(ok, data); nil != err {
		lg.Printf("Unable to respond to request %s Error:%v", rl, err)
		return
	}

	lg.Printf("Request %s Ok:%v Response:%q", rl, ok, data)
}
예제 #21
0
func (h *sshHandler) handlePty(req *ssh.Request) {
	h.Lock()
	defer h.Unlock()

	if h.ptyShell != nil {
		// Only allow one pty per channel
		req.Reply(false, nil)
		return
	}

	width, height, okSize := parsePtyRequest(req.Payload)

	// Initialize Cmd
	var cmd *exec.Cmd
	if *shell {
		cmd = exec.Command(os.Getenv("SHELL"))
	} else {
		cmd = exec.Command(h.ExecHandler[0], h.ExecHandler[1:]...)
	}
	cmd.Env = h.Env

	// attachShell does cmd.Start() so we need to do cmd.Wait() later
	ptyShell, _, err := attachShell(cmd, h.stdout, h.channel)
	if h.assert("pty attachShell", err) {
		h.channel.Close()
		return
	}
	h.ptyShell = ptyShell

	if okSize {
		setWinsize(ptyShell.Fd(), width, height)
	}

	// Ready to receive input
	req.Reply(true, nil)

	// We run this concurrently so that the lock is released for window-change events.
	go h.Exit(cmd.Wait())
}
예제 #22
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()
	}()
}
예제 #23
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
}
func (sess *session) handleWindowChangeRequest(request *ssh.Request) {
	logger := sess.logger.Session("handle-window-change")

	type windowChangeMsg struct {
		Columns  uint32
		Rows     uint32
		WidthPx  uint32
		HeightPx uint32
	}
	var windowChangeMessage windowChangeMsg

	err := ssh.Unmarshal(request.Payload, &windowChangeMessage)
	if err != nil {
		logger.Error("unmarshal-failed", err)
		if request.WantReply {
			request.Reply(false, nil)
		}
		return
	}

	sess.Lock()
	defer sess.Unlock()

	if sess.allocPty {
		sess.ptyRequest.Columns = windowChangeMessage.Columns
		sess.ptyRequest.Rows = windowChangeMessage.Rows
	}

	if sess.ptyMaster != nil {
		err = setWindowSize(logger, sess.ptyMaster, sess.ptyRequest.Columns, sess.ptyRequest.Rows)
		if err != nil {
			logger.Error("failed-to-set-window-size", err)
		}
	}

	if request.WantReply {
		request.Reply(true, nil)
	}
}
예제 #25
0
func (h *sshHandler) handlePty(req *ssh.Request) {
	h.Lock()
	defer h.Unlock()

	if h.ptyShell != nil {
		// Only allow one pty per channel
		req.Reply(false, nil)
		return
	}

	width, height, okSize := parsePtyRequest(req.Payload)

	cmd, err := handlerCmd(flag.Arg(0))
	if err != nil {
		debug("failed handler init:", err)
		h.channel.Close()
		return
	}
	cmd.Env = h.Env

	// attachShell does cmd.Start() so we need to do cmd.Wait() later
	ptyShell, _, err := attachShell(cmd, h.stdout, h.channel)
	if h.assert("pty attachShell", err) {
		h.channel.Close()
		return
	}
	h.ptyShell = ptyShell

	if okSize {
		setWinsize(ptyShell.Fd(), width, height)
	}

	// Ready to receive input
	req.Reply(true, nil)

	// We run this concurrently so that the lock is released for window-change events.
	go h.Exit(cmd.Wait())
}
예제 #26
0
func (h *sshHandler) handleExec(req *ssh.Request) {
	h.Lock()
	defer h.Unlock()

	var payload = struct{ Value string }{}
	ssh.Unmarshal(req.Payload, &payload)
	cmdargs, err := shlex.Split(payload.Value)
	if err != nil {
		debug("failed exec split:", err)
		h.channel.Close()
		return
	}

	cmd, err := handlerCmd(flag.Arg(0), cmdargs...)
	if err != nil {
		debug("failed handler init:", err)
		h.channel.Close()
		return
	}
	cmd.Env = append(h.Env, "SSH_ORIGINAL_COMMAND="+strings.Join(cmdargs, " "))
	cmd.Stdout = h.stdout
	cmd.Stderr = h.stderr

	// cmd.Wait closes the stdin when it's done, so we need to proxy it through a pipe
	stdinPipe, err := cmd.StdinPipe()
	if h.assert("exec cmd.StdinPipe", err) {
		h.channel.Close()
		return
	}
	go io.Copy(stdinPipe, h.channel)

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

	// We run inline to prevent concurrent exec requests for the channel as the lock is held.
	h.Exit(cmd.Run())
}
func (sess *session) executeShell(request *ssh.Request, args ...string) {
	logger := sess.logger.Session("execute-shell")

	sess.Lock()
	cmd, err := sess.createCommand(args...)
	if err != nil {
		sess.Unlock()
		logger.Error("failed-to-create-command", err)
		if request.WantReply {
			request.Reply(false, nil)
		}
		return
	}

	if request.WantReply {
		request.Reply(true, nil)
	}

	if sess.allocPty {
		err = sess.runWithPty(cmd)
	} else {
		err = sess.run(cmd)
	}

	sess.Unlock()

	if err != nil {
		sess.sendExitMessage(err)
		sess.destroy()
		return
	}

	go func() {
		err := sess.wait(cmd)
		sess.sendExitMessage(err)
		sess.destroy()
	}()
}
예제 #28
0
파일: sftp.go 프로젝트: pdxjohnny/cftp
func (chsvr *sshSessionChannelServer) handleSubsystem(req *ssh.Request) error {
	defer func() {
		err1 := chsvr.ch.CloseWrite()
		err2 := chsvr.ch.Close()
		fmt.Fprintf(sshServerDebugStream, "ssh server subsystem request complete, err: %v %v\n", err1, err2)
	}()

	subsystemReq := &sshSubsystemRequest{}
	if err := ssh.Unmarshal(req.Payload, subsystemReq); err != nil {
		return rejectRequestUnmarshalError(req, subsystemReq, err)
	}

	// reply to the ssh client

	// no idea if this is actually correct spec-wise.
	// just enough for an sftp server to start.
	if subsystemReq.Name == "sftp" {
		req.Reply(true, nil)

		sftpServer, err := sftp.NewServer(chsvr.ch, chsvr.ch, sftpServerDebugStream, 0, false, ".")
		if err != nil {
			return err
		}

		// wait for the session to close
		runErr := sftpServer.Serve()
		exitStatus := uint32(1)
		if runErr == nil {
			exitStatus = uint32(0)
		}

		_, exitStatusErr := chsvr.ch.SendRequest("exit-status", false, ssh.Marshal(sshSubsystemExitStatus{exitStatus}))
		return exitStatusErr
	} else {
		return req.Reply(false, nil)
	}
}
func (sess *session) handleEnvironmentRequest(request *ssh.Request) {
	logger := sess.logger.Session("handle-environment-request")

	type envMsg struct {
		Name  string
		Value string
	}
	var envMessage envMsg

	err := ssh.Unmarshal(request.Payload, &envMessage)
	if err != nil {
		logger.Error("unmarshal-failed", err)
		request.Reply(false, nil)
		return
	}

	sess.Lock()
	sess.env[envMessage.Name] = envMessage.Value
	sess.Unlock()

	if request.WantReply {
		request.Reply(true, nil)
	}
}
예제 #30
0
파일: server.go 프로젝트: gamorejon/chisel
func (s *Server) handleWS(ws *websocket.Conn) {
	// Before use, a handshake must be performed on the incoming net.Conn.
	sshConn, chans, reqs, err := ssh.NewServerConn(ws, s.sshConfig)
	if err != nil {
		s.Debugf("Failed to handshake (%s)", err)
		return
	}

	//load user
	var user *chshare.User
	if len(s.Users) > 0 {
		sid := string(sshConn.SessionID())
		user = s.sessions[sid]
		defer delete(s.sessions, sid)
	}

	//verify configuration
	s.Debugf("Verifying configuration")

	//wait for request, with timeout
	var r *ssh.Request
	select {
	case r = <-reqs:
	case <-time.After(10 * time.Second):
		sshConn.Close()
		return
	}

	failed := func(err error) {
		r.Reply(false, []byte(err.Error()))
	}
	if r.Type != "config" {
		failed(s.Errorf("expecting config request"))
		return
	}
	c, err := chshare.DecodeConfig(r.Payload)
	if err != nil {
		failed(s.Errorf("invalid config"))
		return
	}
	//if user is provided, ensure they have
	//access to the desired remotes
	if user != nil {
		for _, r := range c.Remotes {
			addr := r.RemoteHost + ":" + r.RemotePort
			if !user.HasAccess(addr) {
				failed(s.Errorf("access to '%s' denied", addr))
				return
			}
		}
	}
	//success!
	r.Reply(true, nil)

	//prepare connection logger
	s.wsCount++
	id := s.wsCount
	l := s.Fork("session#%d", id)

	l.Debugf("Open")
	l.Debugf("Test")

	go func() {
		for r := range reqs {
			switch r.Type {
			case "ping":
				r.Reply(true, nil)
			default:
				l.Debugf("Unknown request: %s", r.Type)
			}
		}
	}()

	go func() {
		var streamCount int
		l.Debugf("look at the channels...")
		/*stream, reqs, err := sshConn.OpenChannel("session", nil)
		if err != nil {
			l.Debugf("Failed to open channel", err)
			return
		}
		go ssh.DiscardRequests(reqs)
		*/

		for ch := range chans {
			l.Debugf("channel %d", streamCount)

			//addr := string(ch.ExtraData())

			stream, reqs, err := ch.Accept()
			if err != nil {
				l.Debugf("Failed to accept stream: %s", err)
				continue
			}

			streamCount++
			//id := streamCount
			l.Debugf("Request Shell")
			var succ bool
			succ, err = stream.SendRequest("shell", true, nil)
			if !succ || err != nil {
				l.Debugf("Failed to get shell: %s", err)
				continue
			}

			go ssh.DiscardRequests(reqs)
			go io.Copy(stream, os.Stdout)
			go io.Copy(os.Stdin, stream)
			//go handleShellStream(l.Fork("stream#%d", id), stream, addr)
		}
	}()
	//go chshare.ConnectStreams(l, chans)
	sshConn.Wait()
	l.Debugf("Close")
}