예제 #1
0
func handleServerConn(sConn *ssh.ServerConn) {
	defer sConn.Close()
	for {
		// Accept reads from the connection, demultiplexes packets
		// to their corresponding channels and returns when a new
		// channel request is seen. Some goroutine must always be
		// calling Accept; otherwise no messages will be forwarded
		// to the channels.
		ch, err := sConn.Accept()
		if err == io.EOF {
			return
		}
		if err != nil {
			log.Println("handleServerConn Accept:", err)
			break
		}
		// 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 ch.ChannelType() != "session" {
			ch.Reject(ssh.UnknownChannelType, "unknown channel type")
			break
		}
		go handleChannel(ch)
	}
}
예제 #2
0
파일: server.go 프로젝트: kdorland/ssh_chat
func handleSshConnection(sConn *ssh.ServerConn,
	msgchan chan<- text.Message, addchan chan<- Client, rmchan chan<- net.Conn) {

	defer sConn.Close()
	for {
		ch, err := sConn.Accept()
		if err == io.EOF {
			return
		}
		if err != nil {
			log.Println("handleServerConn Accept:", err)
			break
		}
		if ch.ChannelType() != "session" {
			ch.Reject(ssh.UnknownChannelType, "unknown channel type")
			break
		}

		log.Println("Client version:", string(sConn.ClientVersion))

		// Create terminal
		term := terminal.NewTerminal(ch, "")
		serverTerm := &ssh.ServerTerminal{
			Term:    term,
			Channel: ch,
		}
		ch.Accept()

		go handleConnection(sConn, serverTerm, term, msgchan, addchan, rmchan)
	}
}
예제 #3
0
파일: main.go 프로젝트: sandsmark/sophia
func handleUser(sConn *ssh.ServerConn) {
	if err := sConn.Handshake(); err != nil {
		fmt.Printf("failed to handshake\n")
		return
	}
	// A ServerConn multiplexes several channels, which must
	// themselves be Accepted.
	for {
		// Accept reads from the connection, demultiplexes packets
		// to their corresponding channels and returns when a new
		// channel request is seen. Some goroutine must always be
		// calling Accept; otherwise no messages will be forwarded
		// to the channels.
		channel, err := sConn.Accept()
		if err != nil {
			fmt.Printf("error from Accept\n")
			return
		}

		// 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 channel.ChannelType() != "session" {
			channel.Reject(ssh.UnknownChannelType, "unknown channel type")
			continue
		}
		channel.Accept()

		term := terminal.NewTerminal(channel, "> ")
		serverTerm := &ssh.ServerTerminal{
			Term:    term,
			Channel: channel,
		}
		go func() {
			defer channel.Close()
			for {
				line, err := serverTerm.ReadLine()
				if err != nil {
					break
				}
				fmt.Println(line)
			}
		}()
	}
}
예제 #4
0
func handleChannel(conn *ssh.ServerConn, newChan ssh.NewChannel) {
	ch, reqs, err := newChan.Accept()
	if err != nil {
		log.Println("newChan.Accept failed:", err)
		return
	}
	defer ch.Close()
	for req := range reqs {
		switch req.Type {
		case "exec":
			fail := func(at string, err error) {
				log.Printf("%s failed: %s", at, err)
				ch.Stderr().Write([]byte("Internal error.\n"))
			}
			if req.WantReply {
				req.Reply(true, nil)
			}
			cmdline := string(req.Payload[4:])
			cmdargs, err := shlex.Split(cmdline)
			if err != nil || len(cmdargs) != 2 {
				ch.Stderr().Write([]byte("Invalid arguments.\n"))
				return
			}
			if cmdargs[0] != "git-receive-pack" {
				ch.Stderr().Write([]byte("Only `git push` is supported.\n"))
				return
			}
			cmdargs[1] = strings.TrimSuffix(strings.TrimPrefix(cmdargs[1], "/"), ".git")
			if strings.Contains(cmdargs[1], "..") {
				ch.Stderr().Write([]byte("Invalid repo.\n"))
				return
			}

			if err := ensureCacheRepo(cmdargs[1]); err != nil {
				fail("ensureCacheRepo", err)
				return
			}
			cmd := exec.Command("git-shell", "-c", cmdargs[0]+" '"+cmdargs[1]+"'")
			cmd.Dir = *repoPath
			cmd.Env = append(os.Environ(),
				"RECEIVE_USER="******"RECEIVE_REPO="+cmdargs[1],
			)
			done, err := attachCmd(cmd, ch, ch.Stderr(), ch)
			if err != nil {
				fail("attachCmd", err)
				return
			}
			if err := cmd.Start(); err != nil {
				fail("cmd.Start", err)
				return
			}
			done.Wait()
			status, err := exitStatus(cmd.Wait())
			if err != nil {
				fail("exitStatus", err)
				return
			}
			if _, err := ch.SendRequest("exit-status", false, ssh.Marshal(&status)); err != nil {
				fail("sendExit", err)
			}
			return
		case "env":
			if req.WantReply {
				req.Reply(true, nil)
			}
		}
	}
}
예제 #5
0
// handleChannel runs the needed commands on a given SSH server connection against the user
// that opened the communication channel.
func handleChannel(conn *ssh.ServerConn, newChan ssh.NewChannel) {
	ch, reqs, err := newChan.Accept()
	if err != nil {
		log.Println("newChan.Accept failed:", err)
		return
	}

	defer ch.Close()

	for req := range reqs {
		switch req.Type {
		case "exec":
			assert := func(at string, err error) bool {
				if err != nil {
					log.Printf("%s failed: %s", at, err)
					ch.Stderr().Write([]byte("Internal error.\n"))
					return true
				}
				return false
			}

			defer func() {
				log.Printf("Connection lost from %s", conn.RemoteAddr().String())
			}()

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

			cmdline := string(req.Payload[4:])

			cmdargs, err := shlex.Split(cmdline)
			if assert("shlex.Split", err) {
				return
			}

			if len(cmdargs) != 2 {
				ch.Stderr().Write([]byte("Invalid arguments.\n"))
				return
			}

			if cmdargs[0] != "git-receive-pack" {
				ch.Stderr().Write([]byte("Only `git push` is supported.\n"))
				return
			}

			user := conn.Permissions.Extensions["user"]
			reponame := strings.TrimSuffix(strings.TrimPrefix(cmdargs[1], "/"), ".git")

			log.Printf("Push from %s at %s", user, reponame)

			if err := makeGitRepo(reponame); err != nil {
				ch.Stderr().Write([]byte("Error: " + err.Error()))
				return
			}

			log.Printf("Writing hooks...")

			err = ioutil.WriteFile(reponame+"/hooks/pre-receive", []byte(`#!/bin/bash
strip_remote_prefix() {
	sed -u "s/^/"$'\e[1G'"/"
}

set -eo pipefail; while read oldrev newrev refname; do
	/app/cloudchaser -etcd-machine `+*etcduplink+` pre $newrev 2>&1 | strip_remote_prefix
done`), 0755)
			if err != nil {
				return
			}

			err = ioutil.WriteFile(reponame+"/hooks/post-receive", []byte(`#!/bin/bash

strip_remote_prefix() {
	sed -u "s/^/"$'\e[1G'"/"
}

set -eo pipefail; while read oldrev newrev refname; do
	/app/builder -etcd-host `+*etcduplink+` $REPO ${refname##*/} $newrev 2>&1 | strip_remote_prefix
done`), 0755)
			if err != nil {
				return
			}

			log.Printf("Doing git receive...")

			receive := exec.Command("git-receive-pack", reponame)
			if conn.Permissions.Extensions["environ"] != "" {
				receive.Env = append(receive.Env, strings.Split(conn.Permissions.Extensions["environ"], "\n")...)
			}

			receive.Env = append(receive.Env, "USER="******"user"])
			receive.Env = append(receive.Env, "REMOTE_HOST="+conn.RemoteAddr().String())
			receive.Env = append(receive.Env, "REPO="+reponame)

			done, err := attachCmd(receive, ch, ch.Stderr(), ch)
			if err != nil {
				ch.Stderr().Write([]byte("Error: " + err.Error()))
				return
			}

			if assert("receive.Start", receive.Start()) {
				return
			}

			done.Wait()

			log.Printf("Receive done")

			status, rcvErr := exitStatus(receive.Wait())
			if rcvErr != nil {
				ch.Stderr().Write([]byte("Error: " + rcvErr.Error()))
				return
			}

			_, err = ch.SendRequest("exit-status", false, ssh.Marshal(&status))
			assert("sendExit", err)

			return

		case "env":
			if req.WantReply {
				req.Reply(true, nil)
			}
		default:
			return
		}
	}
}
예제 #6
0
func newAttacker(conn *ssh.ServerConn, username string, password string) *Attacker {
	addr := conn.RemoteAddr().String()
	addr = ipAddrFromRemoteAddr(addr)
	return &Attacker{addr, username, password}
}