sftpd

package
v0.8.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 9, 2026 License: AGPL-3.0 Imports: 20 Imported by: 0

Documentation

Overview

Package sftpd serves SFTP for game servers. It runs as a user of its own with no access to the volumes: the panel says who may log in and to which server, and every file operation goes to the core as a typed request. It speaks only the sftp subsystem, with no shell, no commands and no forwarding.

Index

Constants

View Source
const DefaultPanelSocket = "/run/zelie-panel/panel.sock"

DefaultPanelSocket is where the panel listens.

Variables

View Source
var ErrDenied = errors.New("login refused")

ErrDenied is what a login that is not allowed comes back with. It says nothing about why, so it cannot be used to find out who has an account.

Functions

func LimitKey added in v0.7.4

func LimitKey(ip string) string

LimitKey is the address a per-address limit counts under. A whole /64 shares one, since that is what a single IPv6 customer gets to rotate through; IPv4, and IPv6 written as IPv4, is kept as it is.

Types

type AuthRequest

type AuthRequest struct {
	Server   string `json:"server"`
	Password string `json:"password,omitempty"`
	Key      []byte `json:"key,omitempty"` // SSH wire format
	IP       string `json:"ip"`
}

The requests and answers of the panel's SFTP routes, which only this process may call.

type Files

type Files interface {
	OpenFolder(ctx context.Context, ref core.FileRef, dir string) (core.Folder, error)
	StatFile(ctx context.Context, ref core.FileRef, p string) (core.FileEntry, error)
	DownloadRange(ctx context.Context, ref core.FileRef, p string, offset, length int64) (io.ReadCloser, int64, error)
	UploadFile(ctx context.Context, ref core.FileRef, p string, size int64, body io.Reader) error
	MakeFolder(ctx context.Context, ref core.FileRef, p string) error
	RenameFile(ctx context.Context, ref core.FileRef, from, to string) error
	RemoveFile(ctx context.Context, ref core.FileRef, p string) error
	SetFileMode(ctx context.Context, ref core.FileRef, p string, mode fs.FileMode) error
	TruncateFile(ctx context.Context, ref core.FileRef, p string, size int64) error
	SetFileTimes(ctx context.Context, ref core.FileRef, p string, atime, mtime time.Time) error
}

Files is the part of the core's file API that SFTP uses.

type Grant

type Grant struct {
	Server string `json:"server"`
	Volume string `json:"volume"`
	UID    uint32 `json:"uid"`
	GID    uint32 `json:"gid"`
	// Account is who logged in, for the log. It is 0 for a password, which
	// belongs to the server and not to a person.
	Account int64 `json:"account,omitempty"`
	// Cred names the credential the login used: a fingerprint of the
	// password hash, or of the key. The panel compares it again later, so a
	// changed password or a removed key ends the connection. It is opaque
	// here and holds nothing that can log in.
	Cred string `json:"cred"`
}

Grant is what the panel lets a login use: one server's files.

type Panel

type Panel interface {
	// Password checks a server's SFTP password.
	Password(ctx context.Context, server, password, ip string) (Grant, error)
	// Key checks that the key belongs to an account that may use the
	// server. The caller has not seen the client sign anything yet.
	Key(ctx context.Context, server string, key ssh.PublicKey, ip string) (Grant, error)
	// Check asks whether a grant still holds, with no password. It returns
	// ErrDenied when it does not, and another error when the panel could
	// not say.
	Check(ctx context.Context, g Grant) error
	// Room is how many more bytes the server's disk limit leaves, or nil
	// when that is not known.
	Room(ctx context.Context, server string) (*int64, error)
}

Panel is what the SFTP service asks of the panel. The panel decides who may log in; this process only holds the connection.

type PanelClient

type PanelClient struct {
	// contains filtered or unexported fields
}

PanelClient is Panel over the panel's Unix socket.

func NewPanelClient

func NewPanelClient(socket string) *PanelClient

func (*PanelClient) Check added in v0.7.4

func (c *PanelClient) Check(ctx context.Context, g Grant) error

func (*PanelClient) Key

func (c *PanelClient) Key(ctx context.Context, server string, key ssh.PublicKey, ip string) (Grant, error)

func (*PanelClient) Password

func (c *PanelClient) Password(ctx context.Context, server, password, ip string) (Grant, error)

func (*PanelClient) Room

func (c *PanelClient) Room(ctx context.Context, server string) (*int64, error)

type RoomRequest

type RoomRequest struct {
	Server string `json:"server"`
}

The requests and answers of the panel's SFTP routes, which only this process may call.

type RoomResponse

type RoomResponse struct {
	Room *int64 `json:"room,omitempty"`
}

The requests and answers of the panel's SFTP routes, which only this process may call.

type Server

type Server struct {
	Panel Panel
	Files Files
	Log   *slog.Logger
	// HostKeyPath is where the host key is kept. The core makes it; this
	// server only reads it.
	HostKeyPath string
	// MaxPerIP is how many connections one address may hold open. Zero
	// means the default of 8.
	MaxPerIP int
	// MaxHandshakes is how many connections may be logging in at once,
	// whatever their addresses. Zero means 64.
	MaxHandshakes int
	// CheckEvery is how often a live connection's grant is put to the panel
	// again. Zero means a minute.
	CheckEvery time.Duration
	// IdleTimeout closes a logged-in connection that has carried no SFTP
	// traffic for this long. Zero means 15 minutes.
	IdleTimeout time.Duration
	// IdleExit is how long the server stays up with no connection open.
	// Zero means five minutes.
	IdleExit time.Duration
	// contains filtered or unexported fields
}

Server is the SFTP service.

func (*Server) Fingerprint

func (s *Server) Fingerprint() string

Fingerprint is the SHA-256 fingerprint of the host key, as ssh shows it.

func (*Server) LoadHostKey

func (s *Server) LoadHostKey() error

LoadHostKey reads the host key. A missing key is an error: the socket starts the server again once the core has made it.

func (*Server) Serve

func (s *Server) Serve(ctx context.Context, l net.Listener) error

Serve accepts connections on l until l is closed, ctx ends, or no connection has been open for IdleExit. It returns nil in each case. The listener belongs to systemd, which keeps the port and starts the server again when someone connects, so closing it here loses nothing.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
⌂ 换网址