Beispiel #1
0
func main() {
	var (
		readOnly      bool
		debugLevelStr string
		debugLevel    int
		debugStderr   bool
	)

	flag.BoolVar(&readOnly, "R", false, "read-only server")
	flag.BoolVar(&debugStderr, "e", false, "debug to stderr")
	flag.StringVar(&debugLevelStr, "l", "none", "debug level")
	flag.Parse()

	debugStream := ioutil.Discard
	if debugStderr {
		debugStream = os.Stderr
		debugLevel = 1
	}

	svr, _ := sftp.NewServer(os.Stdin, os.Stdout, debugStream, debugLevel, readOnly, "")
	if err := svr.Serve(); err != nil {
		fmt.Fprintf(debugStream, "sftp server completed with error: %v", err)
		os.Exit(1)
	}
}
Beispiel #2
0
func main() {
	var (
		readOnly    bool
		debugStderr bool
	)

	flag.BoolVar(&readOnly, "R", false, "read-only server")
	flag.BoolVar(&debugStderr, "e", false, "debug to stderr")
	flag.Parse()

	debugStream := ioutil.Discard
	if debugStderr {
		debugStream = os.Stderr
	}

	svr, _ := sftp.NewServer(
		os.Stdin,
		os.Stdout,
		"",
		sftp.WithDebug(debugStream),
		sftp.ReadOnly(),
	)
	if err := svr.Serve(); err != nil {
		fmt.Fprintf(debugStream, "sftp server completed with error: %v", err)
		os.Exit(1)
	}
}
Beispiel #3
0
func main() {
	var (
		readOnly    bool
		debugStderr bool
		debugLevel  string
	)

	flag.BoolVar(&readOnly, "R", false, "read-only server")
	flag.BoolVar(&debugStderr, "e", false, "debug to stderr")
	flag.StringVar(&debugLevel, "l", "none", "debug level (ignored)")
	flag.Parse()

	debugStream := ioutil.Discard
	if debugStderr {
		debugStream = os.Stderr
	}

	svr, _ := sftp.NewServer(
		struct {
			io.Reader
			io.WriteCloser
		}{os.Stdin,
			os.Stdout,
		},
		sftp.WithDebug(debugStream),
		sftp.ReadOnly(),
	)
	if err := svr.Serve(); err != nil {
		fmt.Fprintf(debugStream, "sftp server completed with error: %v", err)
		os.Exit(1)
	}
}
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)
		}
	}()
}
Beispiel #5
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" {
		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)
	}
}
Beispiel #6
0
// Based on example server code from golang.org/x/crypto/ssh and server_standalone from github.com/pkg/sftp
func main() {
	var (
		readOnly               bool
		debugStderr            bool
		authUser, authPassword string
		addr                   string
		rootDir                string
	)

	flag.BoolVar(&readOnly, "ro", true, "read-only server")
	flag.BoolVar(&debugStderr, "d", false, "debug to stderr")
	flag.StringVar(&addr, "addr", "0.0.0.0:2022", "address for server to listen on")
	flag.StringVar(&authUser, "usr", "testuser", "user name to require for authentication")
	flag.StringVar(&authPassword, "pwd", "tiger", "password to require for authentication")
	flag.StringVar(&rootDir, "dir", "", "root directory to serve from")
	flag.Parse()

	debugStream = ioutil.Discard
	if debugStderr {
		debugStream = os.Stderr
	}

	// An SSH server is represented by a ServerConfig, which holds
	// certificate details and handles authentication of ServerConns.
	config := &ssh.ServerConfig{
		PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
			debug("Login: %s", c.User())
			if c.User() == authUser && string(pass) == authPassword {
				return nil, nil
			}
			return nil, fmt.Errorf("password rejected for %q", c.User())
		},
	}

	privateBytes, err := ioutil.ReadFile("id_rsa")
	if err != nil {
		log.Fatal("failed to load private key", err)
	}

	private, err := ssh.ParsePrivateKey(privateBytes)
	if err != nil {
		log.Fatal("failed to parse private key", err)
	}

	config.AddHostKey(private)

	// Once a ServerConfig has been configured, connections can be
	// accepted.
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal("failed to listen for connection", err)
	}
	log.Printf("Listening on %v\n", listener.Addr())

	for {
		nConn, err := listener.Accept()
		if err != nil {
			log.Printf("failed to accept incoming connection: %v\n", err)
			continue
		}

		// Before use, a handshake must be performed on the incoming
		// net.Conn.
		_, chans, reqs, err := ssh.NewServerConn(nConn, config)
		if err != nil {
			log.Printf("failed to handshake: %v\n", err)
			continue
		}
		debug("SSH server established")

		// The incoming Request channel must be serviced.
		go ssh.DiscardRequests(reqs)

		// Service the incoming Channel channel.
		for newChannel := range chans {
			// Channels have a type, depending on the application level
			// protocol intended. In the case of an SFTP session, this is "subsystem"
			// with a payload string of "<length=4>sftp"
			debug("Incoming channel: %s", newChannel.ChannelType())
			if newChannel.ChannelType() != "session" {
				newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
				debug("Unknown channel type: %s", newChannel.ChannelType())
				continue
			}
			channel, requests, err := newChannel.Accept()
			if err != nil {
				log.Printf("could not accept channel: %v\n", err)
				continue
			}
			debug("Channel accepted")

			// Sessions have out-of-band requests such as "shell",
			// "pty-req" and "env".  Here we handle only the
			// "subsystem" request.
			go func(in <-chan *ssh.Request) {
				for req := range in {
					debug("Request: %v", req.Type)
					ok := false
					switch req.Type {
					case "subsystem":
						debug("Subsystem: %s", req.Payload[4:])
						if string(req.Payload[4:]) == "sftp" {
							ok = true
						}
					}
					debug(" - accepted: %v", ok)
					req.Reply(ok, nil)
				}
			}(requests)

			options := append([]sftp.ServerOption{}, sftp.WithDebug(debugStream))
			options = append(options, sftp.WithRootDir(rootDir))
			if readOnly {
				options = append(options, sftp.ReadOnly())
			}

			server, err := sftp.NewServer(channel, channel, options...)
			if err != nil {
				log.Printf("cannot start server: %v\n", err)
				continue
			}
			if err := server.Serve(); err != nil && err != io.EOF {
				log.Printf("server completed with error: %v\n", err)
				continue
			}
		}
	}
}
Beispiel #7
0
// Based on example server code from golang.org/x/crypto/ssh and server_standalone
func main() {

	var (
		readOnly    bool
		debugStderr bool
	)

	flag.BoolVar(&readOnly, "R", false, "read-only server")
	flag.BoolVar(&debugStderr, "e", false, "debug to stderr")
	flag.Parse()

	debugStream := ioutil.Discard
	if debugStderr {
		debugStream = os.Stderr
	}

	// An SSH server is represented by a ServerConfig, which holds
	// certificate details and handles authentication of ServerConns.
	config := &ssh.ServerConfig{
		PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
			// Should use constant-time compare (or better, salt+hash) in
			// a production setting.
			fmt.Fprintf(debugStream, "Login: %s\n", c.User())
			if c.User() == "testuser" && string(pass) == "tiger" {
				return nil, nil
			}
			return nil, fmt.Errorf("password rejected for %q", c.User())
		},
	}

	privateBytes, err := ioutil.ReadFile("id_rsa")
	if err != nil {
		log.Fatal("Failed to load private key", err)
	}

	private, err := ssh.ParsePrivateKey(privateBytes)
	if err != nil {
		log.Fatal("Failed to parse private key", err)
	}

	config.AddHostKey(private)

	// Once a ServerConfig has been configured, connections can be
	// accepted.
	listener, err := net.Listen("tcp", "0.0.0.0:2022")
	if err != nil {
		log.Fatal("failed to listen for connection", err)
	}
	fmt.Printf("Listening on %v\n", listener.Addr())

	nConn, err := listener.Accept()
	if err != nil {
		log.Fatal("failed to accept incoming connection", err)
	}

	// Before use, a handshake must be performed on the incoming
	// net.Conn.
	_, chans, reqs, err := ssh.NewServerConn(nConn, config)
	if err != nil {
		log.Fatal("failed to handshake", err)
	}
	fmt.Fprintf(debugStream, "SSH server established\n")

	// The incoming Request channel must be serviced.
	go ssh.DiscardRequests(reqs)

	// Service the incoming Channel channel.
	for newChannel := range chans {
		// Channels have a type, depending on the application level
		// protocol intended. In the case of an SFTP session, this is "subsystem"
		// with a payload string of "<length=4>sftp"
		fmt.Fprintf(debugStream, "Incoming channel: %s\n", newChannel.ChannelType())
		if newChannel.ChannelType() != "session" {
			newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
			fmt.Fprintf(debugStream, "Unknown channel type: %s\n", newChannel.ChannelType())
			continue
		}
		channel, requests, err := newChannel.Accept()
		if err != nil {
			log.Fatal("could not accept channel.", err)
		}
		fmt.Fprintf(debugStream, "Channel accepted\n")

		// Sessions have out-of-band requests such as "shell",
		// "pty-req" and "env".  Here we handle only the
		// "subsystem" request.
		go func(in <-chan *ssh.Request) {
			for req := range in {
				fmt.Fprintf(debugStream, "Request: %v\n", req.Type)
				ok := false
				switch req.Type {
				case "subsystem":
					fmt.Fprintf(debugStream, "Subsystem: %s\n", req.Payload[4:])
					if string(req.Payload[4:]) == "sftp" {
						ok = true
					}
				}
				fmt.Fprintf(debugStream, " - accepted: %v\n", ok)
				req.Reply(ok, nil)
			}
		}(requests)

		server, err := sftp.NewServer(
			channel,
			channel,
			sftp.WithDebug(debugStream),
			sftp.ReadOnly(),
		)
		if err != nil {
			log.Fatal(err)
		}
		if err := server.Serve(); err != nil {
			log.Fatal("sftp server completed with error:", err)
		}
	}
}