extend virtual folders support to all storage backends

Fixes #241
This commit is contained in:
Nicola Murino
2021-03-21 19:15:47 +01:00
parent 0286da2356
commit d6dc3a507e
70 changed files with 6825 additions and 3740 deletions

View File

@@ -4,7 +4,6 @@ import (
"bytes"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net"
@@ -400,10 +399,14 @@ func (c *Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Serve
loginType := sconn.Permissions.Extensions["sftpgo_login_method"]
connectionID := hex.EncodeToString(sconn.SessionID())
if err = checkRootPath(&user, connectionID); err != nil {
if err = user.CheckFsRoot(connectionID); err != nil {
errClose := user.CloseFs()
logger.Warn(logSender, connectionID, "unable to check fs root: %v close fs error: %v", err, errClose)
return
}
defer user.CloseFs() //nolint:errcheck
logger.Log(logger.LevelInfo, common.ProtocolSSH, connectionID,
"User id: %d, logged in with: %#v, username: %#v, home_dir: %#v remote addr: %#v",
user.ID, loginType, user.Username, user.HomeDir, ipAddr)
@@ -445,34 +448,24 @@ func (c *Configuration) AcceptInboundConnection(conn net.Conn, config *ssh.Serve
switch req.Type {
case "subsystem":
if string(req.Payload[4:]) == "sftp" {
fs, err := user.GetFilesystem(connID)
if err == nil {
ok = true
connection := Connection{
BaseConnection: common.NewBaseConnection(connID, common.ProtocolSFTP, user, fs),
ClientVersion: string(sconn.ClientVersion()),
RemoteAddr: conn.RemoteAddr(),
channel: channel,
}
go c.handleSftpConnection(channel, &connection)
} else {
logger.Debug(logSender, connID, "unable to create filesystem: %v", err)
}
}
case "exec":
// protocol will be set later inside processSSHCommand it could be SSH or SCP
fs, err := user.GetFilesystem(connID)
if err == nil {
ok = true
connection := Connection{
BaseConnection: common.NewBaseConnection(connID, "sshd_exec", user, fs),
BaseConnection: common.NewBaseConnection(connID, common.ProtocolSFTP, user),
ClientVersion: string(sconn.ClientVersion()),
RemoteAddr: conn.RemoteAddr(),
channel: channel,
}
ok = processSSHCommand(req.Payload, &connection, c.EnabledSSHCommands)
} else {
logger.Debug(sshCommandLogSender, connID, "unable to create filesystem: %v", err)
go c.handleSftpConnection(channel, &connection)
}
case "exec":
// protocol will be set later inside processSSHCommand it could be SSH or SCP
connection := Connection{
BaseConnection: common.NewBaseConnection(connID, "sshd_exec", user),
ClientVersion: string(sconn.ClientVersion()),
RemoteAddr: conn.RemoteAddr(),
channel: channel,
}
ok = processSSHCommand(req.Payload, &connection, c.EnabledSSHCommands)
}
if req.WantReply {
req.Reply(ok, nil) //nolint:errcheck
@@ -541,21 +534,6 @@ func checkAuthError(ip string, err error) {
}
}
func checkRootPath(user *dataprovider.User, connectionID string) error {
if user.FsConfig.Provider != dataprovider.SFTPFilesystemProvider {
// for sftp fs check root path does nothing so don't open a useless SFTP connection
fs, err := user.GetFilesystem(connectionID)
if err != nil {
logger.Warn(logSender, "", "could not create filesystem for user %#v err: %v", user.Username, err)
return err
}
fs.CheckRootPath(user.Username, user.GetUID(), user.GetGID())
fs.Close()
}
return nil
}
func loginUser(user *dataprovider.User, loginMethod, publicKey string, conn ssh.ConnMetadata) (*ssh.Permissions, error) {
connectionID := ""
if conn != nil {
@@ -568,7 +546,7 @@ func loginUser(user *dataprovider.User, loginMethod, publicKey string, conn ssh.
}
if utils.IsStringInSlice(common.ProtocolSSH, user.Filters.DeniedProtocols) {
logger.Debug(logSender, connectionID, "cannot login user %#v, protocol SSH is not allowed", user.Username)
return nil, fmt.Errorf("Protocol SSH is not allowed for user %#v", user.Username)
return nil, fmt.Errorf("protocol SSH is not allowed for user %#v", user.Username)
}
if user.MaxSessions > 0 {
activeSessions := common.Connections.GetActiveSessions(user.Username)
@@ -580,17 +558,12 @@ func loginUser(user *dataprovider.User, loginMethod, publicKey string, conn ssh.
}
if !user.IsLoginMethodAllowed(loginMethod, conn.PartialSuccessMethods()) {
logger.Debug(logSender, connectionID, "cannot login user %#v, login method %#v is not allowed", user.Username, loginMethod)
return nil, fmt.Errorf("Login method %#v is not allowed for user %#v", loginMethod, user.Username)
}
if dataprovider.GetQuotaTracking() > 0 && user.HasOverlappedMappedPaths() {
logger.Debug(logSender, connectionID, "cannot login user %#v, overlapping mapped folders are allowed only with quota tracking disabled",
user.Username)
return nil, errors.New("overlapping mapped folders are allowed only with quota tracking disabled")
return nil, fmt.Errorf("login method %#v is not allowed for user %#v", loginMethod, user.Username)
}
remoteAddr := conn.RemoteAddr().String()
if !user.IsLoginFromAddrAllowed(remoteAddr) {
logger.Debug(logSender, connectionID, "cannot login user %#v, remote address is not allowed: %v", user.Username, remoteAddr)
return nil, fmt.Errorf("Login for user %#v is not allowed from this address: %v", user.Username, remoteAddr)
return nil, fmt.Errorf("login for user %#v is not allowed from this address: %v", user.Username, remoteAddr)
}
json, err := json.Marshal(user)