Documentation
¶
Overview ¶
Package ironport provides an embeddable, security-hardened SFTP and FTP server.
Core features:
- Per-user jail roots enforced via path resolution and symlink checks.
- Password and SSH public-key authentication with constant-time comparisons.
- Fine-grained CanRead / CanWrite per-user permission flags.
- Runtime user management (AddUser, RemoveUser, RemoveAllUsers, AddUserKey, RemoveUserKey).
- Optional SSH algorithm pinning for key exchange, ciphers, MACs, and public-key auth signatures.
- Graceful shutdown via Close; upload-completion notifications via CompletedUploads; authentication/session notifications via AuthEvents.
- Optional FTP listener sharing the same users, jails, permissions, temp-extension handling, CompletedUploads stream, and AuthEvents stream as SFTP. FTP uses passive mode by default; active mode can be enabled explicitly.
- Optional FTPS (RFC 4217 explicit TLS via AUTH TLS) over the FTP listener. Set Config.FtpTLSConfig to enable it and Config.FtpRequireTLS to require protected login and data channels.
Typical usage:
cfg := ironport.DefaultConfig() cfg.SftpAddr = ":2022" cfg.FtpAddr = ":2121" cfg.Users = users cfg.SftpSigner = signer srv := ironport.NewServer(cfg) log.Fatal(srv.ListenAndServe())
Index ¶
- Constants
- func NewSignerFromFile(path string) (ssh.Signer, error)
- func WithHTTPControl(next http.Handler) http.Handler
- type AuthEvent
- type AuthEventType
- type AuthFailureReason
- type AuthLimitConfig
- type CompletedUpload
- type Config
- type ResourceLimitConfig
- type Server
- func (s *Server) AddUser(username string, info UserInfo)
- func (s *Server) AddUserKey(username string, key ssh.PublicKey)
- func (s *Server) AuthEvents() <-chan AuthEvent
- func (s *Server) Close() error
- func (s *Server) CompletedUploads() <-chan CompletedUpload
- func (s *Server) FTPListeningAddr() net.Addr
- func (s *Server) HttpIngest() http.HandlerFunc
- func (s *Server) ListenAndServe() error
- func (s *Server) ListeningAddr() net.Addr
- func (s *Server) RemoveAllUsers()
- func (s *Server) RemoveUser(username string)
- func (s *Server) RemoveUserKey(username string, key ssh.PublicKey)
- func (s *Server) Shutdown(ctx context.Context) error
- func (s *Server) ValidateJailRoots() error
- type UserInfo
Constants ¶
const ( // CompletedUploadProtocolSFTP identifies an upload completed through SFTP. CompletedUploadProtocolSFTP = "SFTP" // CompletedUploadProtocolFTP identifies an upload completed through FTP. CompletedUploadProtocolFTP = "FTP" )
const ( // CompletedUploadProtocolHTTP identifies an upload completed through the // HTTP ingest endpoint (HttpIngest). CompletedUploadProtocolHTTP = "HTTP" )
Variables ¶
This section is empty.
Functions ¶
func NewSignerFromFile ¶
NewSignerFromFile reads a PEM-encoded private key from the given file path and returns an ssh.Signer suitable for use as a server host key. It supports any key type accepted by ssh.ParsePrivateKey (RSA, ECDSA, Ed25519).
func WithHTTPControl ¶ added in v1.0.53
WithHTTPControl preserves the HTTP transport controls needed to terminate rejected upload bodies, even when downstream middleware hides optional ResponseWriter interfaces. It also keeps original-body cleanup under the upload admission limit when middleware replaces or limits the body. Install it outside the entire middleware chain:
server := &http.Server{Handler: ironport.WithHTTPControl(middleware(mux))}
Middleware must preserve the request context. Nested calls retain the outermost controller, which is invalidated when this wrapper returns so late handlers cannot affect a reused connection. This changes neither routing nor admission limits. It is optional when middleware preserves the complete request body and every ResponseWriter wrapper implements Unwrap() http.ResponseWriter, as required by http.ResponseController.
Types ¶
type AuthEvent ¶ added in v0.1.7
type AuthEvent struct {
// Type is the authentication event kind.
Type AuthEventType
// Reason distinguishes credential rejection from authentication throttling
// for AuthEventLoginFailed. It is empty for successful login and logout.
Reason AuthFailureReason
// Username is the username supplied by the client for this event.
Username string
// ClientIP is the remote IP address of the client, without the port. It is
// empty if the address could not be parsed.
ClientIP string
// Protocol is the file-transfer protocol used for the event.
// It is CompletedUploadProtocolSFTP, CompletedUploadProtocolFTP, or CompletedUploadProtocolHTTP.
Protocol string
}
AuthEvent describes an authentication or session-lifecycle event. It is the payload delivered on the server's AuthEvents stream.
type AuthEventType ¶ added in v0.1.7
type AuthEventType string
AuthEventType identifies the kind of authentication event delivered on the AuthEvents channel (login success, login failure, or logout).
const ( // AuthEventLoginSuccess identifies a successful user login. AuthEventLoginSuccess AuthEventType = "LoginSuccess" // AuthEventLoginFailed identifies a rejected user login attempt. AuthEventLoginFailed AuthEventType = "LoginFailed" // AuthEventLogout identifies the end of an authenticated session. AuthEventLogout AuthEventType = "Logout" )
type AuthFailureReason ¶ added in v1.0.53
type AuthFailureReason string
AuthFailureReason identifies why a login attempt was rejected. It is empty for successful login and logout events.
const ( // AuthFailureCredentials identifies a login rejected during credential validation. // It includes SSH key eligibility rejections, which do not advance backoff. AuthFailureCredentials AuthFailureReason = "Credentials" // AuthFailureThrottled identifies a login rejected by authentication limits. AuthFailureThrottled AuthFailureReason = "Throttled" )
type AuthLimitConfig ¶ added in v1.0.53
type AuthLimitConfig struct {
// GlobalBurst and GlobalInterval default to 200 attempts and one token per
// 10 ms. IPBurst/IPInterval default to 30 and one per second; UserBurst/
// UserInterval default to 20 and one per second.
GlobalBurst int
GlobalInterval time.Duration
IPBurst int
IPInterval time.Duration
UserBurst int
UserInterval time.Duration
// MaxEntries bounds source and username buckets (default 8192).
// A positive value must be at least two. Half the slots serve sources and
// the remainder serve usernames. Private hashing assigns stable slots;
// collisions share budgets and backoff rather than evicting active state
// or rejecting all new identities when storage fills. Smaller limits
// increase collateral throttling. EntryTTL is the minimum idle time before
// resetting a slot, defaults to 15 minutes, and is never shorter than the
// maximum backoff. Reset also requires full tokens, elapsed cooldown, and
// fully decayed failures, so a short EntryTTL cannot restart backoff early.
MaxEntries int
EntryTTL time.Duration
// Backoff starts after three failed verifications and doubles after each
// further failure. Defaults are 250 ms initial and 30 seconds maximum.
// SSH key eligibility rejections consume tokens but do not advance backoff.
// When BackoffInitial is unset, it is capped by BackoffMax. Explicit positive
// values with BackoffInitial greater than BackoffMax fail Config.Validate.
// An unset maximum is raised to an explicit initial value above 30 seconds.
// Backoff rejects attempts immediately; it never sleeps in a handler.
// Successful authentication clears a username slot's failure history only
// when all retained failures belong to that username. Unsigned key queries
// do not change failure ownership. Source and mixed-username failure state
// is not cleared by success; each slot forgets one failure per BackoffMax
// without another failure, so a finished attack's penalties fade while the
// slot stays active. Steady failures still hold maximum backoff for any
// EntryTTL.
BackoffInitial time.Duration
BackoffMax time.Duration
}
AuthLimitConfig bounds authentication work across SSH, FTP, and HTTP. All non-positive fields select secure defaults; limits cannot be disabled. Limits apply to successful and failed authentication attempts. Source budgets use individual IPv4 addresses and IPv6 /64 prefixes. Addresses come only from the transport peer; forwarded headers are never trusted. Every supplied username consumes the same budgets, whether or not the account currently exists.
type CompletedUpload ¶
type CompletedUpload struct {
// Username is the authenticated SFTP, FTP, or HTTP user that performed the upload.
Username string
// FullFilePath is the absolute path of the uploaded file on the server's
// local filesystem, constructed from the root path at authentication. This
// reporting path may become stale if the root or a parent directory is moved;
// filesystem operations remain pinned to the originally opened directory.
FullFilePath string
// FilePath is the file path as seen by the client, relative to the
// user's jail root (e.g. "/incoming/foo.txt").
FilePath string
// ClientIP is the remote IP address of the client that performed
// the upload, without the port. It is empty if the address could not
// be parsed.
ClientIP string
// Protocol is the file-transfer protocol used for the upload.
// It is CompletedUploadProtocolSFTP, CompletedUploadProtocolFTP, or CompletedUploadProtocolHTTP.
Protocol string
}
CompletedUpload describes a file upload that has finished successfully. It is the payload delivered on the server's CompletedUploads stream.
type Config ¶ added in v0.1.17
type Config struct {
SftpAddr string
FtpAddr string
FtpPassivePortRange string
// FtpDataAcceptTimeout bounds how long passive-mode FTP data listeners wait
// for the client data connection after PASV/EPSV, and how long active-mode
// FTP dials may take after PORT/EPRT. Zero selects the package default
// (30 seconds); negative disables active-mode dial deadlines, but passive
// reservations still expire after 30 seconds.
FtpDataAcceptTimeout time.Duration
// FtpAllowActiveMode enables FTP active mode (PORT/EPRT). It defaults to
// false because active mode requires outbound connections from the server.
// When enabled, this server only dials the same IP as the control connection.
FtpAllowActiveMode bool
// FtpTLSConfig, when non-nil, enables explicit FTPS (RFC 4217). The
// AUTH TLS command upgrades the control connection using this config,
// and PROT P wraps the data connection. A private config pair and ticket
// key are derived for each control session so data connections can only
// resume that control session. Callers should populate Certificates (or a
// GetCertificate callback) but otherwise leave session-ticket settings at
// their defaults. Custom WrapSession and UnwrapSession callbacks are not
// supported because they can bypass the control-session binding. Leave nil
// to disable FTPS.
FtpTLSConfig *tls.Config
// FtpRequireTLS, when true, refuses USER/PASS over the FTP control
// connection until AUTH TLS has succeeded and refuses data-transfer
// commands until the client has negotiated PBSZ followed by PROT P.
// When FTP is enabled, ListenAndServe requires FtpTLSConfig to be set and
// fails before opening listeners if it is nil. Ignored when FTP is disabled.
FtpRequireTLS bool
// FtpPassiveAdvertisedIP optionally overrides the IPv4 address sent to
// clients in the PASV (227) reply. By default the control connection's
// local IP is advertised, which is wrong behind NAT or a port-forward:
// the address the server sees on its own socket is the internal one,
// not the public address the client must dial. Set this to the
// external/advertised IPv4 address in such deployments. It only affects
// the PASV reply; EPSV does not carry an address. Leave empty to
// advertise the control connection's local IP.
FtpPassiveAdvertisedIP string
Users map[string]UserInfo
SftpSigner ssh.Signer
// CompletedUploadSize sets the CompletedUploads channel capacity.
// Non-positive values select the default of 65,536.
CompletedUploadSize int
// AuthEventSize sets the AuthEvents channel capacity.
// Non-positive values select the default of 64.
AuthEventSize int
// SSHKeyExchanges, SSHCiphers, SSHMACs, and
// SSHPublicKeyAuthAlgorithms optionally pin SSH negotiation and public-key
// auth signature algorithms. Nil slices use golang.org/x/crypto/ssh
// defaults.
SSHKeyExchanges []string
SSHCiphers []string
SSHMACs []string
SSHPublicKeyAuthAlgorithms []string
// ResourceLimits bounds connections, channels, handles, listeners, and HTTP
// requests. Non-positive fields select finite defaults.
ResourceLimits ResourceLimitConfig
// AuthLimits bounds authentication attempts and retry backoff jointly
// across SSH, FTP, and HTTP. Zero fields select secure defaults.
AuthLimits AuthLimitConfig
// TempExtensions marks file extensions that should defer completion
// notifications until a later rename to a non-temp name. Matching is
// case-insensitive.
TempExtensions []string
// IdleTimeout bounds authenticated SFTP connection inactivity and FTP
// control-session inactivity between commands. Zero selects the package
// default; negative disables the idle timeout.
IdleTimeout time.Duration
// TCPKeepAlivePeriod controls the SO_KEEPALIVE idle period applied to
// accepted SFTP and FTP control connections. Zero selects the package
// default (30 seconds); a negative value disables keepalive entirely.
// Probes keep idle control connections alive through stateful
// firewalls/NAT and surface half-open peers as read errors.
TCPKeepAlivePeriod time.Duration
// SftpAllowChown controls whether SFTP clients may change file ownership
// inside their jail through pathname SETSTAT. It defaults to false.
// Attribute updates through an open handle (FSETSTAT) are unsupported.
SftpAllowChown bool
}
Config holds the values used to construct a server.
func DefaultConfig ¶ added in v0.1.17
func DefaultConfig() *Config
DefaultConfig returns a fresh server configuration with package defaults applied. Callers should set Users before starting the server. Set SftpSigner to use a stable host key; when SftpSigner is nil, ListenAndServe generates an ephemeral in-memory host key.
func (*Config) Validate ¶ added in v1.0.53
Validate checks authentication-limit bounds before constructing a server. Nil and zero-valued configurations use defaults and are valid. Non-positive limit settings select defaults; MaxEntries must be at least two when set, and an explicit BackoffInitial must not exceed an explicit BackoffMax. Listener addresses, TLS settings, and kernel support are checked separately when starting listeners. NewServer retains validation failures: ListenAndServe returns the error and HttpIngest rejects requests with HTTP 503.
type ResourceLimitConfig ¶ added in v1.0.53
type ResourceLimitConfig struct {
// SSHMaxChannels limits simultaneous session channels per SSH connection.
// Non-positive values select the default of 16.
SSHMaxChannels int
// MaxConnections and MaxConnectionsPerIP bound accepted SFTP and FTP
// control connections together, including unauthenticated connections.
// Non-positive values select 128 and 32 respectively.
MaxConnections int
MaxConnectionsPerIP int
// FTPAuthTimeout is the absolute time allowed to authenticate an FTP
// control session. Commands such as NOOP do not extend it. Non-positive
// values select 30 seconds. Logging out starts a new authentication window.
FTPAuthTimeout time.Duration
// SFTPMaxHandles, SFTPMaxHandlesPerUser, and SFTPMaxHandlesPerConnection
// bound open files and directories globally, per username (across SSH
// connections), and per SSH connection (across channels). Non-positive
// values select 256, 64, and 32. CLOSE and channel teardown release slots.
SFTPMaxHandles int
SFTPMaxHandlesPerUser int
SFTPMaxHandlesPerConnection int
// HTTPMaxConcurrentRequests caps requests executing in HttpIngest across
// every handler created from this Server. Non-positive values select 32.
// Requests over the limit are rejected immediately with 503 before their
// Authorization header or body is processed.
HTTPMaxConcurrentRequests int
// HTTPMaxAuthorizationBytes limits the raw Authorization header before
// Basic authentication decoding. Non-positive values select 4096 bytes.
HTTPMaxAuthorizationBytes int
// HTTPMaxUsernameBytes and HTTPMaxPasswordBytes limit decoded Basic-auth
// credentials. Non-positive values select 256 and 1024 bytes respectively.
HTTPMaxUsernameBytes int
HTTPMaxPasswordBytes int
// FTPMaxPassiveListeners caps outstanding PASV/EPSV listeners server-wide.
// Zero or negative selects the default of 64.
FTPMaxPassiveListeners int
// FTPMaxPassiveListenersPerUser caps outstanding PASV/EPSV listeners for
// one authenticated username. Zero or negative selects the default of 2.
FTPMaxPassiveListenersPerUser int
// FTPMaxPassiveListenersPerIP caps outstanding PASV/EPSV listeners for one
// control-connection source IP. Zero or negative selects the default of 8.
FTPMaxPassiveListenersPerIP int
// FTPMaxAuthFailures closes a control session after this many failed
// password attempts. Non-positive values select five; USER/REIN and
// successful login do not reset it.
FTPMaxAuthFailures int
}
ResourceLimitConfig bounds resources shared by one Server. Non-positive values select finite defaults; these limits cannot be disabled. Configure limits before NewServer, which copies the settings.
type Server ¶ added in v0.1.18
type Server struct {
// contains filtered or unexported fields
}
Server is a self-contained SFTP server with optional FTP support.
func NewServer ¶
NewServer creates a new Server from config. Call Config.Validate to check admission settings first. Invalid settings make ListenAndServe return an error and HttpIngest reject requests with HTTP 503. Pass FtpAddr as "" to disable FTP. Leave FtpPassivePortRange empty to use OS-assigned passive data ports.
CompletedUploadSize sets the buffer capacity of the CompletedUploads channel. A non-positive value falls back to the package default (65,536). AuthEventSize sets the buffer capacity of the AuthEvents channel. A non-positive value falls back to the package default (64):
cfg := ironport.DefaultConfig() cfg.Users = users cfg.SftpSigner = signer cfg.CompletedUploadSize = 131_072 cfg.AuthEventSize = 256 srv := ironport.NewServer(cfg)
func (*Server) AddUser ¶ added in v0.1.18
AddUser adds or replaces a user entry in the server's user map. An effective change to credentials, root, or permissions invalidates pending logins and closes the user's established SFTP/FTP sessions. Equivalent replacements preserve sessions; authorized keys are compared as sets of wire-format values, ignoring order, duplicates, and nil entries. After publishing the update and closing revoked sessions, it checks the root and logs a warning if it cannot be opened. Invalid roots do not prevent user registration. This diagnostic may block on filesystem or logger I/O. It is safe to call concurrently with active connections.
func (*Server) AddUserKey ¶ added in v0.1.18
AddUserKey appends key to the AuthorizedKeys of an existing user. If the key is already present (by wire-format equality) it is not added again. It is a no-op when username does not exist or key is nil. Adding a key does not revoke authority held by an existing session, so active sessions are left connected. The revision still changes to linearize the new authentication configuration with logins already in flight. It is safe to call concurrently with active connections.
func (*Server) AuthEvents ¶ added in v0.1.18
AuthEvents returns a receive-only stream of authentication/session notifications. Each AuthEvent includes the protocol that produced it. The channel is buffered; sends are non-blocking so a slow consumer never stalls authentication or logout handling. Callers should drain the stream continuously. A full channel drops events. Throttled login failures are sampled even when the channel has capacity, so this stream is not a complete audit trail or an exact count of rejected attempts. Credential failures, successful logins, and logouts are not sampled.
The buffer capacity is set by Config.AuthEventSize. A non-positive value falls back to the package default (64).
func (*Server) Close ¶ added in v0.1.18
Close stops both listeners, causing ListenAndServe to return nil. It is safe to call concurrently with active connections; in-flight connections are not terminated, and the server can be started again after Close returns. Calling Close before ListenAndServe has been called, or after it has already returned, is a no-op.
func (*Server) CompletedUploads ¶ added in v0.1.18
func (s *Server) CompletedUploads() <-chan CompletedUpload
CompletedUploads returns a receive-only stream of successful upload notifications. Each CompletedUpload includes the protocol that produced it. The channel is buffered; sends are non-blocking so a slow consumer never stalls an upload. Callers should drain the stream continuously.
The buffer capacity is set by Config.CompletedUploadSize. A non-positive value falls back to the package default (65,536).
func (*Server) FTPListeningAddr ¶ added in v0.1.18
FTPListeningAddr returns the actual FTP network address the server is listening on, or nil if FTP is disabled or not currently listening.
func (*Server) HttpIngest ¶ added in v1.0.33
func (s *Server) HttpIngest() http.HandlerFunc
HttpIngest returns an http.HandlerFunc that accepts a file upload over HTTP and stores it in the authenticated user's jail, exactly as an SFTP or FTP STOR would. The handler is meant to be registered by the caller on their own HTTP server, so the endpoint URL is chosen by the application:
srv := ironport.NewServer(config)
mux := http.NewServeMux()
mux.HandleFunc("/upload", srv.HttpIngest())
Request contract:
- Method must be POST; anything else gets 405 with an Allow header.
- HTTP Basic authentication is required. The username and password are the same credentials used for SFTP/FTP/FTPS and are checked with the same constant-time password comparison. A missing or invalid credential gets 401 with a WWW-Authenticate challenge; only an attempt that supplied a wrong credential (not a bare unauthenticated probe) emits a LoginFailed AuthEvent. Oversized raw Authorization headers get 431 before decoding; oversized decoded credentials get 401 without logging or events. Throttled attempts get 429 with Retry-After.
- HTTPMaxConcurrentRequests bounds in-flight work across every handler created from this Server; saturation gets 503 with Retry-After.
- The authenticated user must have CanWrite; otherwise the request gets 403.
- The body must be multipart/form-data carrying one or more parts under the form field "file" (key=file). Each part's filename becomes the destination path, relative to the user's jail root. A nested name such as "reports/2026/q2.csv" (or "/reports/2026/q2.csv") is stored at that path and any missing parent directories are created. The path is resolved through the same openat2, no-symlink jail used by SFTP/FTP, so ".." segments are collapsed and contained, and a crafted name can neither traverse out of the jail nor follow a symlink.
Multiple "file" parts in one request are each stored independently (a standard multi-file form, e.g. curl -F file=@a -F file=@b), and each stored file is announced separately on the CompletedUploads stream (Protocol CompletedUploadProtocolHTTP) — honouring TempExtensions and dotfile deferral the same way SFTP/FTP do, so a ".tmp"/dotfile upload is intentionally not announced until a later rename. The handler replies 201 Created when at least one file was stored and none failed; if any file failed it replies with an error status (400 for client errors such as an invalid filename or no "file" part, 500 for a server-side write error) and a plain-text body listing each file's outcome, so a partial failure is never silent.
Like the other protocols, the handler never blocks on the notification streams: a slow CompletedUploads/AuthEvents consumer drops events rather than stalling an upload. The handler streams the body straight into the destination file without buffering the whole upload in memory or staging it in a temp directory. It imposes no size limit of its own (matching SFTP/FTP); callers that want one can wrap the handler with http.MaxBytesReader or bound the body at a reverse proxy.
Middleware must preserve ResponseController access via Unwrap, or callers must install WithHTTPControl outside the complete middleware chain. This allows early rejections to stop body reads before returning request capacity. Middleware that replaces or limits the request body also needs WithHTTPControl so the original body is consumed before successful uploads return capacity. Without transport control, HTTP/1 cleanup depends on the caller's read timeout.
Creating the handler checks kernel support and warns about unusable jail roots, including in HTTP-only deployments. A failed capability check makes requests return 503 until a later probe succeeds; root warnings remain advisory.
func (*Server) ListenAndServe ¶ added in v0.1.18
ListenAndServe starts the SFTP server and, when configured, the FTP server too. It blocks until Close or Shutdown is called or an unexpected listener error occurs. It returns nil when stopped via Close or Shutdown.
A stopped server can be started again by calling ListenAndServe after Close or Shutdown returns. Concurrent ListenAndServe calls are rejected.
func (*Server) ListeningAddr ¶ added in v0.1.18
ListeningAddr returns the actual SFTP network address the server is listening on, or nil if the SFTP listener is not currently listening. It is useful when the server was started with port 0 (OS-assigned port).
func (*Server) RemoveAllUsers ¶ added in v0.1.18
func (s *Server) RemoveAllUsers()
RemoveAllUsers removes every user and closes their authenticated SFTP/FTP connections. Pending logins cannot commit their old authentication snapshots, even if the same users are added again. Already-authorized HTTP requests continue, and no on-disk user data is removed. It is safe to call concurrently with active connections.
func (*Server) RemoveUser ¶ added in v0.1.18
RemoveUser removes a user and closes their authenticated SFTP/FTP connections, including FTP data operations. Pending logins using the old user are rejected. HTTP requests already authorized continue; subsequent authentication fails. It is safe to call concurrently with active connections.
func (*Server) RemoveUserKey ¶ added in v0.1.18
RemoveUserKey removes key from the AuthorizedKeys of an existing user. It is a no-op when username does not exist, the key is not found, or key is nil. Removing an effective key disconnects that user's established SFTP/FTP sessions so a compromised credential cannot retain access through an old session. No-op removals leave existing sessions untouched. It is safe to call concurrently with active connections.
func (*Server) Shutdown ¶ added in v0.1.18
Shutdown gracefully stops the server. It closes the listeners so no new connections are accepted, then waits for every in-flight handler goroutine to return.
If ctx is canceled or its deadline passes before all handlers finish, Shutdown forcibly closes every remaining tracked connection (which causes each handler's network I/O to fail and the handler to return), waits for those handlers to exit, and returns ctx.Err(). Passing context.Background() blocks until all handlers exit.
Shutdown is safe to call concurrently with Close and with itself. After Shutdown returns, ListenAndServe (if it was running) will have returned nil, and the server can be started again. Calling Shutdown before ListenAndServe has been started, or after it has already returned and all handlers have exited, returns immediately with nil.
func (*Server) ValidateJailRoots ¶ added in v1.0.63
ValidateJailRoots checks kernel support and logs warnings for configured roots that cannot currently be opened securely. Only a capability-probe failure is returned as an error. Unusable roots are advisory: applications may provision directories after registering users, but authentication fails until the root can be opened. It does not check file permissions for later I/O operations.
ListenAndServe and HttpIngest call this automatically before serving requests. It is safe to call concurrently with user changes and active connections. Checks and logging run outside the user lock and may block on filesystem or logger I/O. Diagnostic handles are closed immediately; authentication still opens and retains its own root, so validation does not guarantee a later login.
type UserInfo ¶
type UserInfo struct {
Password string
AuthorizedKeys []ssh.PublicKey // public keys allowed for SFTP authentication; nil or empty means public-key auth is disabled for this user
Root string // jail root on disk, e.g. /srv/sftp/alice
CanRead bool // allow read/download/list operations
CanWrite bool // allow write/upload/delete/rename operations
}
UserInfo holds the credentials and jail root for a single SFTP/FTP/HTTP user. Root must name an existing directory when authenticating. Symlinks in any configured root component and literal ".." components are rejected. Relative roots are resolved from the working directory at authentication time.
Source Files
¶
- auth_limits.go
- auth_linux.go
- config_linux.go
- events_linux.go
- ftp_commands_linux.go
- ftp_data_linux.go
- ftp_limits.go
- ftp_session_linux.go
- ftp_transfer_linux.go
- ftps_linux.go
- http_control.go
- http_linux.go
- ironport.go
- jail_roots_linux.go
- resource_limits.go
- server_linux.go
- sftp_auth_linux.go
- sftp_directory_linux.go
- sftp_handlers_linux.go
- sftp_linux.go
- users_linux.go
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
ironport-demo
command
Command ironport-demo is a runnable library demo for the ironport package.
|
Command ironport-demo is a runnable library demo for the ironport package. |
|
internal
|
|
|
authlimit
Package authlimit bounds authentication work with shared token buckets and backoff.
|
Package authlimit bounds authentication work with shared token buckets and backoff. |
|
jailfs
Package jailfs provides a jailed filesystem backend built on Linux openat2.
|
Package jailfs provides a jailed filesystem backend built on Linux openat2. |
|
netconn
Package netconn provides connection deadlines, keepalive, and address helpers.
|
Package netconn provides connection deadlines, keepalive, and address helpers. |