connection.go 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  1. package common
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. "path"
  7. "strings"
  8. "sync"
  9. "sync/atomic"
  10. "time"
  11. "github.com/pkg/sftp"
  12. "github.com/drakkan/sftpgo/dataprovider"
  13. "github.com/drakkan/sftpgo/logger"
  14. "github.com/drakkan/sftpgo/utils"
  15. "github.com/drakkan/sftpgo/vfs"
  16. )
  17. // BaseConnection defines common fields for a connection using any supported protocol
  18. type BaseConnection struct {
  19. // last activity for this connection.
  20. // Since this is accessed atomically we put as first element of the struct achieve 64 bit alignment
  21. lastActivity int64
  22. // Unique identifier for the connection
  23. ID string
  24. // user associated with this connection if any
  25. User dataprovider.User
  26. // start time for this connection
  27. startTime time.Time
  28. protocol string
  29. Fs vfs.Fs
  30. sync.RWMutex
  31. transferID uint64
  32. activeTransfers []ActiveTransfer
  33. }
  34. // NewBaseConnection returns a new BaseConnection
  35. func NewBaseConnection(ID, protocol string, user dataprovider.User, fs vfs.Fs) *BaseConnection {
  36. connID := ID
  37. if utils.IsStringInSlice(protocol, supportedProtocols) {
  38. connID = fmt.Sprintf("%v_%v", protocol, ID)
  39. }
  40. return &BaseConnection{
  41. ID: connID,
  42. User: user,
  43. startTime: time.Now(),
  44. protocol: protocol,
  45. Fs: fs,
  46. lastActivity: time.Now().UnixNano(),
  47. transferID: 0,
  48. }
  49. }
  50. // Log outputs a log entry to the configured logger
  51. func (c *BaseConnection) Log(level logger.LogLevel, format string, v ...interface{}) {
  52. logger.Log(level, c.protocol, c.ID, format, v...)
  53. }
  54. // GetTransferID returns an unique transfer ID for this connection
  55. func (c *BaseConnection) GetTransferID() uint64 {
  56. return atomic.AddUint64(&c.transferID, 1)
  57. }
  58. // GetID returns the connection ID
  59. func (c *BaseConnection) GetID() string {
  60. return c.ID
  61. }
  62. // GetUsername returns the authenticated username associated with this connection if any
  63. func (c *BaseConnection) GetUsername() string {
  64. return c.User.Username
  65. }
  66. // GetProtocol returns the protocol for the connection
  67. func (c *BaseConnection) GetProtocol() string {
  68. return c.protocol
  69. }
  70. // SetProtocol sets the protocol for this connection
  71. func (c *BaseConnection) SetProtocol(protocol string) {
  72. c.protocol = protocol
  73. if utils.IsStringInSlice(c.protocol, supportedProtocols) {
  74. c.ID = fmt.Sprintf("%v_%v", c.protocol, c.ID)
  75. }
  76. }
  77. // GetConnectionTime returns the initial connection time
  78. func (c *BaseConnection) GetConnectionTime() time.Time {
  79. return c.startTime
  80. }
  81. // UpdateLastActivity updates last activity for this connection
  82. func (c *BaseConnection) UpdateLastActivity() {
  83. atomic.StoreInt64(&c.lastActivity, time.Now().UnixNano())
  84. }
  85. // GetLastActivity returns the last connection activity
  86. func (c *BaseConnection) GetLastActivity() time.Time {
  87. return time.Unix(0, atomic.LoadInt64(&c.lastActivity))
  88. }
  89. // CloseFS closes the underlying fs
  90. func (c *BaseConnection) CloseFS() error {
  91. if c.Fs != nil {
  92. return c.Fs.Close()
  93. }
  94. return nil
  95. }
  96. // AddTransfer associates a new transfer to this connection
  97. func (c *BaseConnection) AddTransfer(t ActiveTransfer) {
  98. c.Lock()
  99. defer c.Unlock()
  100. c.activeTransfers = append(c.activeTransfers, t)
  101. c.Log(logger.LevelDebug, "transfer added, id: %v, active transfers: %v", t.GetID(), len(c.activeTransfers))
  102. }
  103. // RemoveTransfer removes the specified transfer from the active ones
  104. func (c *BaseConnection) RemoveTransfer(t ActiveTransfer) {
  105. c.Lock()
  106. defer c.Unlock()
  107. indexToRemove := -1
  108. for i, v := range c.activeTransfers {
  109. if v.GetID() == t.GetID() {
  110. indexToRemove = i
  111. break
  112. }
  113. }
  114. if indexToRemove >= 0 {
  115. c.activeTransfers[indexToRemove] = c.activeTransfers[len(c.activeTransfers)-1]
  116. c.activeTransfers[len(c.activeTransfers)-1] = nil
  117. c.activeTransfers = c.activeTransfers[:len(c.activeTransfers)-1]
  118. c.Log(logger.LevelDebug, "transfer removed, id: %v active transfers: %v", t.GetID(), len(c.activeTransfers))
  119. } else {
  120. c.Log(logger.LevelWarn, "transfer to remove not found!")
  121. }
  122. }
  123. // GetTransfers returns the active transfers
  124. func (c *BaseConnection) GetTransfers() []ConnectionTransfer {
  125. c.RLock()
  126. defer c.RUnlock()
  127. transfers := make([]ConnectionTransfer, 0, len(c.activeTransfers))
  128. for _, t := range c.activeTransfers {
  129. var operationType string
  130. switch t.GetType() {
  131. case TransferDownload:
  132. operationType = operationDownload
  133. case TransferUpload:
  134. operationType = operationUpload
  135. }
  136. transfers = append(transfers, ConnectionTransfer{
  137. ID: t.GetID(),
  138. OperationType: operationType,
  139. StartTime: utils.GetTimeAsMsSinceEpoch(t.GetStartTime()),
  140. Size: t.GetSize(),
  141. VirtualPath: t.GetVirtualPath(),
  142. })
  143. }
  144. return transfers
  145. }
  146. // SignalTransfersAbort signals to the active transfers to exit as soon as possible
  147. func (c *BaseConnection) SignalTransfersAbort() error {
  148. c.RLock()
  149. defer c.RUnlock()
  150. if len(c.activeTransfers) == 0 {
  151. return errors.New("no active transfer found")
  152. }
  153. for _, t := range c.activeTransfers {
  154. t.SignalClose()
  155. }
  156. return nil
  157. }
  158. func (c *BaseConnection) getRealFsPath(fsPath string) string {
  159. c.RLock()
  160. defer c.RUnlock()
  161. for _, t := range c.activeTransfers {
  162. if p := t.GetRealFsPath(fsPath); len(p) > 0 {
  163. return p
  164. }
  165. }
  166. return fsPath
  167. }
  168. func (c *BaseConnection) truncateOpenHandle(fsPath string, size int64) (int64, error) {
  169. c.RLock()
  170. defer c.RUnlock()
  171. for _, t := range c.activeTransfers {
  172. initialSize, err := t.Truncate(fsPath, size)
  173. if err != errTransferMismatch {
  174. return initialSize, err
  175. }
  176. }
  177. return 0, errNoTransfer
  178. }
  179. // ListDir reads the directory named by fsPath and returns a list of directory entries
  180. func (c *BaseConnection) ListDir(fsPath, virtualPath string) ([]os.FileInfo, error) {
  181. if !c.User.HasPerm(dataprovider.PermListItems, virtualPath) {
  182. return nil, c.GetPermissionDeniedError()
  183. }
  184. files, err := c.Fs.ReadDir(fsPath)
  185. if err != nil {
  186. c.Log(logger.LevelWarn, "error listing directory: %+v", err)
  187. return nil, c.GetFsError(err)
  188. }
  189. return c.User.AddVirtualDirs(files, virtualPath), nil
  190. }
  191. // CreateDir creates a new directory at the specified fsPath
  192. func (c *BaseConnection) CreateDir(fsPath, virtualPath string) error {
  193. if !c.User.HasPerm(dataprovider.PermCreateDirs, path.Dir(virtualPath)) {
  194. return c.GetPermissionDeniedError()
  195. }
  196. if c.User.IsVirtualFolder(virtualPath) {
  197. c.Log(logger.LevelWarn, "mkdir not allowed %#v is a virtual folder", virtualPath)
  198. return c.GetPermissionDeniedError()
  199. }
  200. if err := c.Fs.Mkdir(fsPath); err != nil {
  201. c.Log(logger.LevelWarn, "error creating dir: %#v error: %+v", fsPath, err)
  202. return c.GetFsError(err)
  203. }
  204. vfs.SetPathPermissions(c.Fs, fsPath, c.User.GetUID(), c.User.GetGID())
  205. logger.CommandLog(mkdirLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "", -1)
  206. return nil
  207. }
  208. // IsRemoveFileAllowed returns an error if removing this file is not allowed
  209. func (c *BaseConnection) IsRemoveFileAllowed(fsPath, virtualPath string) error {
  210. if !c.User.HasPerm(dataprovider.PermDelete, path.Dir(virtualPath)) {
  211. return c.GetPermissionDeniedError()
  212. }
  213. if !c.User.IsFileAllowed(virtualPath) {
  214. c.Log(logger.LevelDebug, "removing file %#v is not allowed", fsPath)
  215. return c.GetPermissionDeniedError()
  216. }
  217. return nil
  218. }
  219. // RemoveFile removes a file at the specified fsPath
  220. func (c *BaseConnection) RemoveFile(fsPath, virtualPath string, info os.FileInfo) error {
  221. if err := c.IsRemoveFileAllowed(fsPath, virtualPath); err != nil {
  222. return err
  223. }
  224. size := info.Size()
  225. action := newActionNotification(&c.User, operationPreDelete, fsPath, "", "", c.protocol, size, nil)
  226. actionErr := actionHandler.Handle(action)
  227. if actionErr == nil {
  228. c.Log(logger.LevelDebug, "remove for path %#v handled by pre-delete action", fsPath)
  229. } else {
  230. if err := c.Fs.Remove(fsPath, false); err != nil {
  231. c.Log(logger.LevelWarn, "failed to remove a file/symlink %#v: %+v", fsPath, err)
  232. return c.GetFsError(err)
  233. }
  234. }
  235. logger.CommandLog(removeLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "", -1)
  236. if info.Mode()&os.ModeSymlink == 0 {
  237. vfolder, err := c.User.GetVirtualFolderForPath(path.Dir(virtualPath))
  238. if err == nil {
  239. dataprovider.UpdateVirtualFolderQuota(vfolder.BaseVirtualFolder, -1, -size, false) //nolint:errcheck
  240. if vfolder.IsIncludedInUserQuota() {
  241. dataprovider.UpdateUserQuota(c.User, -1, -size, false) //nolint:errcheck
  242. }
  243. } else {
  244. dataprovider.UpdateUserQuota(c.User, -1, -size, false) //nolint:errcheck
  245. }
  246. }
  247. if actionErr != nil {
  248. action := newActionNotification(&c.User, operationDelete, fsPath, "", "", c.protocol, size, nil)
  249. go actionHandler.Handle(action) // nolint:errcheck
  250. }
  251. return nil
  252. }
  253. // IsRemoveDirAllowed returns an error if removing this directory is not allowed
  254. func (c *BaseConnection) IsRemoveDirAllowed(fsPath, virtualPath string) error {
  255. if c.Fs.GetRelativePath(fsPath) == "/" {
  256. c.Log(logger.LevelWarn, "removing root dir is not allowed")
  257. return c.GetPermissionDeniedError()
  258. }
  259. if c.User.IsVirtualFolder(virtualPath) {
  260. c.Log(logger.LevelWarn, "removing a virtual folder is not allowed: %#v", virtualPath)
  261. return c.GetPermissionDeniedError()
  262. }
  263. if c.User.HasVirtualFoldersInside(virtualPath) {
  264. c.Log(logger.LevelWarn, "removing a directory with a virtual folder inside is not allowed: %#v", virtualPath)
  265. return c.GetOpUnsupportedError()
  266. }
  267. if c.User.IsMappedPath(fsPath) {
  268. c.Log(logger.LevelWarn, "removing a directory mapped as virtual folder is not allowed: %#v", fsPath)
  269. return c.GetPermissionDeniedError()
  270. }
  271. if !c.User.HasPerm(dataprovider.PermDelete, path.Dir(virtualPath)) {
  272. return c.GetPermissionDeniedError()
  273. }
  274. return nil
  275. }
  276. // RemoveDir removes a directory at the specified fsPath
  277. func (c *BaseConnection) RemoveDir(fsPath, virtualPath string) error {
  278. if err := c.IsRemoveDirAllowed(fsPath, virtualPath); err != nil {
  279. return err
  280. }
  281. var fi os.FileInfo
  282. var err error
  283. if fi, err = c.Fs.Lstat(fsPath); err != nil {
  284. // see #149
  285. if c.Fs.IsNotExist(err) && c.Fs.HasVirtualFolders() {
  286. return nil
  287. }
  288. c.Log(logger.LevelWarn, "failed to remove a dir %#v: stat error: %+v", fsPath, err)
  289. return c.GetFsError(err)
  290. }
  291. if !fi.IsDir() || fi.Mode()&os.ModeSymlink != 0 {
  292. c.Log(logger.LevelDebug, "cannot remove %#v is not a directory", fsPath)
  293. return c.GetGenericError(nil)
  294. }
  295. if err := c.Fs.Remove(fsPath, true); err != nil {
  296. c.Log(logger.LevelWarn, "failed to remove directory %#v: %+v", fsPath, err)
  297. return c.GetFsError(err)
  298. }
  299. logger.CommandLog(rmdirLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "", -1)
  300. return nil
  301. }
  302. // Rename renames (moves) fsSourcePath to fsTargetPath
  303. func (c *BaseConnection) Rename(fsSourcePath, fsTargetPath, virtualSourcePath, virtualTargetPath string) error {
  304. if c.User.IsMappedPath(fsSourcePath) {
  305. c.Log(logger.LevelWarn, "renaming a directory mapped as virtual folder is not allowed: %#v", fsSourcePath)
  306. return c.GetPermissionDeniedError()
  307. }
  308. if c.User.IsMappedPath(fsTargetPath) {
  309. c.Log(logger.LevelWarn, "renaming to a directory mapped as virtual folder is not allowed: %#v", fsTargetPath)
  310. return c.GetPermissionDeniedError()
  311. }
  312. srcInfo, err := c.Fs.Lstat(fsSourcePath)
  313. if err != nil {
  314. return c.GetFsError(err)
  315. }
  316. if !c.isRenamePermitted(fsSourcePath, virtualSourcePath, virtualTargetPath, srcInfo) {
  317. return c.GetPermissionDeniedError()
  318. }
  319. initialSize := int64(-1)
  320. if dstInfo, err := c.Fs.Lstat(fsTargetPath); err == nil {
  321. if dstInfo.IsDir() {
  322. c.Log(logger.LevelWarn, "attempted to rename %#v overwriting an existing directory %#v",
  323. fsSourcePath, fsTargetPath)
  324. return c.GetOpUnsupportedError()
  325. }
  326. // we are overwriting an existing file/symlink
  327. if dstInfo.Mode().IsRegular() {
  328. initialSize = dstInfo.Size()
  329. }
  330. if !c.User.HasPerm(dataprovider.PermOverwrite, path.Dir(virtualTargetPath)) {
  331. c.Log(logger.LevelDebug, "renaming is not allowed, %#v -> %#v. Target exists but the user "+
  332. "has no overwrite permission", virtualSourcePath, virtualTargetPath)
  333. return c.GetPermissionDeniedError()
  334. }
  335. }
  336. if srcInfo.IsDir() {
  337. if c.User.HasVirtualFoldersInside(virtualSourcePath) {
  338. c.Log(logger.LevelDebug, "renaming the folder %#v is not supported: it has virtual folders inside it",
  339. virtualSourcePath)
  340. return c.GetOpUnsupportedError()
  341. }
  342. if err = c.checkRecursiveRenameDirPermissions(fsSourcePath, fsTargetPath); err != nil {
  343. c.Log(logger.LevelDebug, "error checking recursive permissions before renaming %#v: %+v", fsSourcePath, err)
  344. return c.GetFsError(err)
  345. }
  346. }
  347. if !c.hasSpaceForRename(virtualSourcePath, virtualTargetPath, initialSize, fsSourcePath) {
  348. c.Log(logger.LevelInfo, "denying cross rename due to space limit")
  349. return c.GetGenericError(ErrQuotaExceeded)
  350. }
  351. if err := c.Fs.Rename(fsSourcePath, fsTargetPath); err != nil {
  352. c.Log(logger.LevelWarn, "failed to rename %#v -> %#v: %+v", fsSourcePath, fsTargetPath, err)
  353. return c.GetFsError(err)
  354. }
  355. if dataprovider.GetQuotaTracking() > 0 {
  356. c.updateQuotaAfterRename(virtualSourcePath, virtualTargetPath, fsTargetPath, initialSize) //nolint:errcheck
  357. }
  358. logger.CommandLog(renameLogSender, fsSourcePath, fsTargetPath, c.User.Username, "", c.ID, c.protocol, -1, -1,
  359. "", "", "", -1)
  360. action := newActionNotification(&c.User, operationRename, fsSourcePath, fsTargetPath, "", c.protocol, 0, nil)
  361. // the returned error is used in test cases only, we already log the error inside action.execute
  362. go actionHandler.Handle(action) // nolint:errcheck
  363. return nil
  364. }
  365. // CreateSymlink creates fsTargetPath as a symbolic link to fsSourcePath
  366. func (c *BaseConnection) CreateSymlink(fsSourcePath, fsTargetPath, virtualSourcePath, virtualTargetPath string) error {
  367. if c.Fs.GetRelativePath(fsSourcePath) == "/" {
  368. c.Log(logger.LevelWarn, "symlinking root dir is not allowed")
  369. return c.GetPermissionDeniedError()
  370. }
  371. if c.User.IsVirtualFolder(virtualTargetPath) {
  372. c.Log(logger.LevelWarn, "symlinking a virtual folder is not allowed")
  373. return c.GetPermissionDeniedError()
  374. }
  375. if !c.User.HasPerm(dataprovider.PermCreateSymlinks, path.Dir(virtualTargetPath)) {
  376. return c.GetPermissionDeniedError()
  377. }
  378. if c.isCrossFoldersRequest(virtualSourcePath, virtualTargetPath) {
  379. c.Log(logger.LevelWarn, "cross folder symlink is not supported, src: %v dst: %v", virtualSourcePath, virtualTargetPath)
  380. return c.GetOpUnsupportedError()
  381. }
  382. if c.User.IsMappedPath(fsSourcePath) {
  383. c.Log(logger.LevelWarn, "symlinking a directory mapped as virtual folder is not allowed: %#v", fsSourcePath)
  384. return c.GetPermissionDeniedError()
  385. }
  386. if c.User.IsMappedPath(fsTargetPath) {
  387. c.Log(logger.LevelWarn, "symlinking to a directory mapped as virtual folder is not allowed: %#v", fsTargetPath)
  388. return c.GetPermissionDeniedError()
  389. }
  390. if err := c.Fs.Symlink(fsSourcePath, fsTargetPath); err != nil {
  391. c.Log(logger.LevelWarn, "failed to create symlink %#v -> %#v: %+v", fsSourcePath, fsTargetPath, err)
  392. return c.GetFsError(err)
  393. }
  394. logger.CommandLog(symlinkLogSender, fsSourcePath, fsTargetPath, c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "", -1)
  395. return nil
  396. }
  397. func (c *BaseConnection) getPathForSetStatPerms(fsPath, virtualPath string) string {
  398. pathForPerms := virtualPath
  399. if fi, err := c.Fs.Lstat(fsPath); err == nil {
  400. if fi.IsDir() {
  401. pathForPerms = path.Dir(virtualPath)
  402. }
  403. }
  404. return pathForPerms
  405. }
  406. // DoStat execute a Stat if mode = 0, Lstat if mode = 1
  407. func (c *BaseConnection) DoStat(fsPath string, mode int) (os.FileInfo, error) {
  408. var info os.FileInfo
  409. var err error
  410. if mode == 1 {
  411. info, err = c.Fs.Lstat(c.getRealFsPath(fsPath))
  412. } else {
  413. info, err = c.Fs.Stat(c.getRealFsPath(fsPath))
  414. }
  415. if err == nil && vfs.IsCryptOsFs(c.Fs) {
  416. info = c.Fs.(*vfs.CryptFs).ConvertFileInfo(info)
  417. }
  418. return info, err
  419. }
  420. func (c *BaseConnection) ignoreSetStat() bool {
  421. if Config.SetstatMode == 1 {
  422. return true
  423. }
  424. if Config.SetstatMode == 2 && !vfs.IsLocalOrSFTPFs(c.Fs) {
  425. return true
  426. }
  427. return false
  428. }
  429. func (c *BaseConnection) handleChmod(fsPath, pathForPerms string, attributes *StatAttributes) error {
  430. if !c.User.HasPerm(dataprovider.PermChmod, pathForPerms) {
  431. return c.GetPermissionDeniedError()
  432. }
  433. if c.ignoreSetStat() {
  434. return nil
  435. }
  436. if err := c.Fs.Chmod(c.getRealFsPath(fsPath), attributes.Mode); err != nil {
  437. c.Log(logger.LevelWarn, "failed to chmod path %#v, mode: %v, err: %+v", fsPath, attributes.Mode.String(), err)
  438. return c.GetFsError(err)
  439. }
  440. logger.CommandLog(chmodLogSender, fsPath, "", c.User.Username, attributes.Mode.String(), c.ID, c.protocol,
  441. -1, -1, "", "", "", -1)
  442. return nil
  443. }
  444. func (c *BaseConnection) handleChown(fsPath, pathForPerms string, attributes *StatAttributes) error {
  445. if !c.User.HasPerm(dataprovider.PermChown, pathForPerms) {
  446. return c.GetPermissionDeniedError()
  447. }
  448. if c.ignoreSetStat() {
  449. return nil
  450. }
  451. if err := c.Fs.Chown(c.getRealFsPath(fsPath), attributes.UID, attributes.GID); err != nil {
  452. c.Log(logger.LevelWarn, "failed to chown path %#v, uid: %v, gid: %v, err: %+v", fsPath, attributes.UID,
  453. attributes.GID, err)
  454. return c.GetFsError(err)
  455. }
  456. logger.CommandLog(chownLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, attributes.UID, attributes.GID,
  457. "", "", "", -1)
  458. return nil
  459. }
  460. func (c *BaseConnection) handleChtimes(fsPath, pathForPerms string, attributes *StatAttributes) error {
  461. if !c.User.HasPerm(dataprovider.PermChtimes, pathForPerms) {
  462. return c.GetPermissionDeniedError()
  463. }
  464. if c.ignoreSetStat() {
  465. return nil
  466. }
  467. if err := c.Fs.Chtimes(c.getRealFsPath(fsPath), attributes.Atime, attributes.Mtime); err != nil {
  468. c.Log(logger.LevelWarn, "failed to chtimes for path %#v, access time: %v, modification time: %v, err: %+v",
  469. fsPath, attributes.Atime, attributes.Mtime, err)
  470. return c.GetFsError(err)
  471. }
  472. accessTimeString := attributes.Atime.Format(chtimesFormat)
  473. modificationTimeString := attributes.Mtime.Format(chtimesFormat)
  474. logger.CommandLog(chtimesLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1,
  475. accessTimeString, modificationTimeString, "", -1)
  476. return nil
  477. }
  478. // SetStat set StatAttributes for the specified fsPath
  479. func (c *BaseConnection) SetStat(fsPath, virtualPath string, attributes *StatAttributes) error {
  480. pathForPerms := c.getPathForSetStatPerms(fsPath, virtualPath)
  481. if attributes.Flags&StatAttrPerms != 0 {
  482. return c.handleChmod(fsPath, pathForPerms, attributes)
  483. }
  484. if attributes.Flags&StatAttrUIDGID != 0 {
  485. return c.handleChown(fsPath, pathForPerms, attributes)
  486. }
  487. if attributes.Flags&StatAttrTimes != 0 {
  488. return c.handleChtimes(fsPath, pathForPerms, attributes)
  489. }
  490. if attributes.Flags&StatAttrSize != 0 {
  491. if !c.User.HasPerm(dataprovider.PermOverwrite, pathForPerms) {
  492. return c.GetPermissionDeniedError()
  493. }
  494. if err := c.truncateFile(fsPath, virtualPath, attributes.Size); err != nil {
  495. c.Log(logger.LevelWarn, "failed to truncate path %#v, size: %v, err: %+v", fsPath, attributes.Size, err)
  496. return c.GetFsError(err)
  497. }
  498. logger.CommandLog(truncateLogSender, fsPath, "", c.User.Username, "", c.ID, c.protocol, -1, -1, "", "", "", attributes.Size)
  499. }
  500. return nil
  501. }
  502. func (c *BaseConnection) truncateFile(fsPath, virtualPath string, size int64) error {
  503. // check first if we have an open transfer for the given path and try to truncate the file already opened
  504. // if we found no transfer we truncate by path.
  505. var initialSize int64
  506. var err error
  507. initialSize, err = c.truncateOpenHandle(fsPath, size)
  508. if err == errNoTransfer {
  509. c.Log(logger.LevelDebug, "file path %#v not found in active transfers, execute trucate by path", fsPath)
  510. var info os.FileInfo
  511. info, err = c.Fs.Stat(fsPath)
  512. if err != nil {
  513. return err
  514. }
  515. initialSize = info.Size()
  516. err = c.Fs.Truncate(fsPath, size)
  517. }
  518. if err == nil && vfs.IsLocalOrSFTPFs(c.Fs) {
  519. sizeDiff := initialSize - size
  520. vfolder, err := c.User.GetVirtualFolderForPath(path.Dir(virtualPath))
  521. if err == nil {
  522. dataprovider.UpdateVirtualFolderQuota(vfolder.BaseVirtualFolder, 0, -sizeDiff, false) //nolint:errcheck
  523. if vfolder.IsIncludedInUserQuota() {
  524. dataprovider.UpdateUserQuota(c.User, 0, -sizeDiff, false) //nolint:errcheck
  525. }
  526. } else {
  527. dataprovider.UpdateUserQuota(c.User, 0, -sizeDiff, false) //nolint:errcheck
  528. }
  529. }
  530. return err
  531. }
  532. func (c *BaseConnection) checkRecursiveRenameDirPermissions(sourcePath, targetPath string) error {
  533. dstPerms := []string{
  534. dataprovider.PermCreateDirs,
  535. dataprovider.PermUpload,
  536. dataprovider.PermCreateSymlinks,
  537. }
  538. err := c.Fs.Walk(sourcePath, func(walkedPath string, info os.FileInfo, err error) error {
  539. if err != nil {
  540. return err
  541. }
  542. dstPath := strings.Replace(walkedPath, sourcePath, targetPath, 1)
  543. virtualSrcPath := c.Fs.GetRelativePath(walkedPath)
  544. virtualDstPath := c.Fs.GetRelativePath(dstPath)
  545. // walk scans the directory tree in order, checking the parent directory permissions we are sure that all contents
  546. // inside the parent path was checked. If the current dir has no subdirs with defined permissions inside it
  547. // and it has all the possible permissions we can stop scanning
  548. if !c.User.HasPermissionsInside(path.Dir(virtualSrcPath)) && !c.User.HasPermissionsInside(path.Dir(virtualDstPath)) {
  549. if c.User.HasPerm(dataprovider.PermRename, path.Dir(virtualSrcPath)) &&
  550. c.User.HasPerm(dataprovider.PermRename, path.Dir(virtualDstPath)) {
  551. return ErrSkipPermissionsCheck
  552. }
  553. if c.User.HasPerm(dataprovider.PermDelete, path.Dir(virtualSrcPath)) &&
  554. c.User.HasPerms(dstPerms, path.Dir(virtualDstPath)) {
  555. return ErrSkipPermissionsCheck
  556. }
  557. }
  558. if !c.isRenamePermitted(walkedPath, virtualSrcPath, virtualDstPath, info) {
  559. c.Log(logger.LevelInfo, "rename %#v -> %#v is not allowed, virtual destination path: %#v",
  560. walkedPath, dstPath, virtualDstPath)
  561. return os.ErrPermission
  562. }
  563. return nil
  564. })
  565. if err == ErrSkipPermissionsCheck {
  566. err = nil
  567. }
  568. return err
  569. }
  570. func (c *BaseConnection) isRenamePermitted(fsSourcePath, virtualSourcePath, virtualTargetPath string, fi os.FileInfo) bool {
  571. if c.Fs.GetRelativePath(fsSourcePath) == "/" {
  572. c.Log(logger.LevelWarn, "renaming root dir is not allowed")
  573. return false
  574. }
  575. if c.User.IsVirtualFolder(virtualSourcePath) || c.User.IsVirtualFolder(virtualTargetPath) {
  576. c.Log(logger.LevelWarn, "renaming a virtual folder is not allowed")
  577. return false
  578. }
  579. if !c.User.IsFileAllowed(virtualSourcePath) || !c.User.IsFileAllowed(virtualTargetPath) {
  580. if fi != nil && fi.Mode().IsRegular() {
  581. c.Log(logger.LevelDebug, "renaming file is not allowed, source: %#v target: %#v",
  582. virtualSourcePath, virtualTargetPath)
  583. return false
  584. }
  585. }
  586. if c.User.HasPerm(dataprovider.PermRename, path.Dir(virtualSourcePath)) &&
  587. c.User.HasPerm(dataprovider.PermRename, path.Dir(virtualTargetPath)) {
  588. return true
  589. }
  590. if !c.User.HasPerm(dataprovider.PermDelete, path.Dir(virtualSourcePath)) {
  591. return false
  592. }
  593. if fi != nil {
  594. if fi.IsDir() {
  595. return c.User.HasPerm(dataprovider.PermCreateDirs, path.Dir(virtualTargetPath))
  596. } else if fi.Mode()&os.ModeSymlink != 0 {
  597. return c.User.HasPerm(dataprovider.PermCreateSymlinks, path.Dir(virtualTargetPath))
  598. }
  599. }
  600. return c.User.HasPerm(dataprovider.PermUpload, path.Dir(virtualTargetPath))
  601. }
  602. func (c *BaseConnection) hasSpaceForRename(virtualSourcePath, virtualTargetPath string, initialSize int64,
  603. fsSourcePath string) bool {
  604. if dataprovider.GetQuotaTracking() == 0 {
  605. return true
  606. }
  607. sourceFolder, errSrc := c.User.GetVirtualFolderForPath(path.Dir(virtualSourcePath))
  608. dstFolder, errDst := c.User.GetVirtualFolderForPath(path.Dir(virtualTargetPath))
  609. if errSrc != nil && errDst != nil {
  610. // rename inside the user home dir
  611. return true
  612. }
  613. if errSrc == nil && errDst == nil {
  614. // rename between virtual folders
  615. if sourceFolder.MappedPath == dstFolder.MappedPath {
  616. // rename inside the same virtual folder
  617. return true
  618. }
  619. }
  620. if errSrc != nil && dstFolder.IsIncludedInUserQuota() {
  621. // rename between user root dir and a virtual folder included in user quota
  622. return true
  623. }
  624. quotaResult := c.HasSpace(true, virtualTargetPath)
  625. return c.hasSpaceForCrossRename(quotaResult, initialSize, fsSourcePath)
  626. }
  627. // hasSpaceForCrossRename checks the quota after a rename between different folders
  628. func (c *BaseConnection) hasSpaceForCrossRename(quotaResult vfs.QuotaCheckResult, initialSize int64, sourcePath string) bool {
  629. if !quotaResult.HasSpace && initialSize == -1 {
  630. // we are over quota and this is not a file replace
  631. return false
  632. }
  633. fi, err := c.Fs.Lstat(sourcePath)
  634. if err != nil {
  635. c.Log(logger.LevelWarn, "cross rename denied, stat error for path %#v: %v", sourcePath, err)
  636. return false
  637. }
  638. var sizeDiff int64
  639. var filesDiff int
  640. if fi.Mode().IsRegular() {
  641. sizeDiff = fi.Size()
  642. filesDiff = 1
  643. if initialSize != -1 {
  644. sizeDiff -= initialSize
  645. filesDiff = 0
  646. }
  647. } else if fi.IsDir() {
  648. filesDiff, sizeDiff, err = c.Fs.GetDirSize(sourcePath)
  649. if err != nil {
  650. c.Log(logger.LevelWarn, "cross rename denied, error getting size for directory %#v: %v", sourcePath, err)
  651. return false
  652. }
  653. }
  654. if !quotaResult.HasSpace && initialSize != -1 {
  655. // we are over quota but we are overwriting an existing file so we check if the quota size after the rename is ok
  656. if quotaResult.QuotaSize == 0 {
  657. return true
  658. }
  659. c.Log(logger.LevelDebug, "cross rename overwrite, source %#v, used size %v, size to add %v",
  660. sourcePath, quotaResult.UsedSize, sizeDiff)
  661. quotaResult.UsedSize += sizeDiff
  662. return quotaResult.GetRemainingSize() >= 0
  663. }
  664. if quotaResult.QuotaFiles > 0 {
  665. remainingFiles := quotaResult.GetRemainingFiles()
  666. c.Log(logger.LevelDebug, "cross rename, source %#v remaining file %v to add %v", sourcePath,
  667. remainingFiles, filesDiff)
  668. if remainingFiles < filesDiff {
  669. return false
  670. }
  671. }
  672. if quotaResult.QuotaSize > 0 {
  673. remainingSize := quotaResult.GetRemainingSize()
  674. c.Log(logger.LevelDebug, "cross rename, source %#v remaining size %v to add %v", sourcePath,
  675. remainingSize, sizeDiff)
  676. if remainingSize < sizeDiff {
  677. return false
  678. }
  679. }
  680. return true
  681. }
  682. // GetMaxWriteSize returns the allowed size for an upload or an error
  683. // if no enough size is available for a resume/append
  684. func (c *BaseConnection) GetMaxWriteSize(quotaResult vfs.QuotaCheckResult, isResume bool, fileSize int64) (int64, error) {
  685. maxWriteSize := quotaResult.GetRemainingSize()
  686. if isResume {
  687. if !c.Fs.IsUploadResumeSupported() {
  688. return 0, c.GetOpUnsupportedError()
  689. }
  690. if c.User.Filters.MaxUploadFileSize > 0 && c.User.Filters.MaxUploadFileSize <= fileSize {
  691. return 0, ErrQuotaExceeded
  692. }
  693. if c.User.Filters.MaxUploadFileSize > 0 {
  694. maxUploadSize := c.User.Filters.MaxUploadFileSize - fileSize
  695. if maxUploadSize < maxWriteSize || maxWriteSize == 0 {
  696. maxWriteSize = maxUploadSize
  697. }
  698. }
  699. } else {
  700. if maxWriteSize > 0 {
  701. maxWriteSize += fileSize
  702. }
  703. if c.User.Filters.MaxUploadFileSize > 0 && (c.User.Filters.MaxUploadFileSize < maxWriteSize || maxWriteSize == 0) {
  704. maxWriteSize = c.User.Filters.MaxUploadFileSize
  705. }
  706. }
  707. return maxWriteSize, nil
  708. }
  709. // HasSpace checks user's quota usage
  710. func (c *BaseConnection) HasSpace(checkFiles bool, requestPath string) vfs.QuotaCheckResult {
  711. result := vfs.QuotaCheckResult{
  712. HasSpace: true,
  713. AllowedSize: 0,
  714. AllowedFiles: 0,
  715. UsedSize: 0,
  716. UsedFiles: 0,
  717. QuotaSize: 0,
  718. QuotaFiles: 0,
  719. }
  720. if dataprovider.GetQuotaTracking() == 0 {
  721. return result
  722. }
  723. var err error
  724. var vfolder vfs.VirtualFolder
  725. vfolder, err = c.User.GetVirtualFolderForPath(path.Dir(requestPath))
  726. if err == nil && !vfolder.IsIncludedInUserQuota() {
  727. if vfolder.HasNoQuotaRestrictions(checkFiles) {
  728. return result
  729. }
  730. result.QuotaSize = vfolder.QuotaSize
  731. result.QuotaFiles = vfolder.QuotaFiles
  732. result.UsedFiles, result.UsedSize, err = dataprovider.GetUsedVirtualFolderQuota(vfolder.MappedPath)
  733. } else {
  734. if c.User.HasNoQuotaRestrictions(checkFiles) {
  735. return result
  736. }
  737. result.QuotaSize = c.User.QuotaSize
  738. result.QuotaFiles = c.User.QuotaFiles
  739. result.UsedFiles, result.UsedSize, err = dataprovider.GetUsedQuota(c.User.Username)
  740. }
  741. if err != nil {
  742. c.Log(logger.LevelWarn, "error getting used quota for %#v request path %#v: %v", c.User.Username, requestPath, err)
  743. result.HasSpace = false
  744. return result
  745. }
  746. result.AllowedFiles = result.QuotaFiles - result.UsedFiles
  747. result.AllowedSize = result.QuotaSize - result.UsedSize
  748. if (checkFiles && result.QuotaFiles > 0 && result.UsedFiles >= result.QuotaFiles) ||
  749. (result.QuotaSize > 0 && result.UsedSize >= result.QuotaSize) {
  750. c.Log(logger.LevelDebug, "quota exceed for user %#v, request path %#v, num files: %v/%v, size: %v/%v check files: %v",
  751. c.User.Username, requestPath, result.UsedFiles, result.QuotaFiles, result.UsedSize, result.QuotaSize, checkFiles)
  752. result.HasSpace = false
  753. return result
  754. }
  755. return result
  756. }
  757. func (c *BaseConnection) isCrossFoldersRequest(virtualSourcePath, virtualTargetPath string) bool {
  758. sourceFolder, errSrc := c.User.GetVirtualFolderForPath(virtualSourcePath)
  759. dstFolder, errDst := c.User.GetVirtualFolderForPath(virtualTargetPath)
  760. if errSrc != nil && errDst != nil {
  761. return false
  762. }
  763. if errSrc == nil && errDst == nil {
  764. return sourceFolder.MappedPath != dstFolder.MappedPath
  765. }
  766. return true
  767. }
  768. func (c *BaseConnection) updateQuotaMoveBetweenVFolders(sourceFolder, dstFolder vfs.VirtualFolder, initialSize,
  769. filesSize int64, numFiles int) {
  770. if sourceFolder.MappedPath == dstFolder.MappedPath {
  771. // both files are inside the same virtual folder
  772. if initialSize != -1 {
  773. dataprovider.UpdateVirtualFolderQuota(dstFolder.BaseVirtualFolder, -numFiles, -initialSize, false) //nolint:errcheck
  774. if dstFolder.IsIncludedInUserQuota() {
  775. dataprovider.UpdateUserQuota(c.User, -numFiles, -initialSize, false) //nolint:errcheck
  776. }
  777. }
  778. return
  779. }
  780. // files are inside different virtual folders
  781. dataprovider.UpdateVirtualFolderQuota(sourceFolder.BaseVirtualFolder, -numFiles, -filesSize, false) //nolint:errcheck
  782. if sourceFolder.IsIncludedInUserQuota() {
  783. dataprovider.UpdateUserQuota(c.User, -numFiles, -filesSize, false) //nolint:errcheck
  784. }
  785. if initialSize == -1 {
  786. dataprovider.UpdateVirtualFolderQuota(dstFolder.BaseVirtualFolder, numFiles, filesSize, false) //nolint:errcheck
  787. if dstFolder.IsIncludedInUserQuota() {
  788. dataprovider.UpdateUserQuota(c.User, numFiles, filesSize, false) //nolint:errcheck
  789. }
  790. } else {
  791. // we cannot have a directory here, initialSize != -1 only for files
  792. dataprovider.UpdateVirtualFolderQuota(dstFolder.BaseVirtualFolder, 0, filesSize-initialSize, false) //nolint:errcheck
  793. if dstFolder.IsIncludedInUserQuota() {
  794. dataprovider.UpdateUserQuota(c.User, 0, filesSize-initialSize, false) //nolint:errcheck
  795. }
  796. }
  797. }
  798. func (c *BaseConnection) updateQuotaMoveFromVFolder(sourceFolder vfs.VirtualFolder, initialSize, filesSize int64, numFiles int) {
  799. // move between a virtual folder and the user home dir
  800. dataprovider.UpdateVirtualFolderQuota(sourceFolder.BaseVirtualFolder, -numFiles, -filesSize, false) //nolint:errcheck
  801. if sourceFolder.IsIncludedInUserQuota() {
  802. dataprovider.UpdateUserQuota(c.User, -numFiles, -filesSize, false) //nolint:errcheck
  803. }
  804. if initialSize == -1 {
  805. dataprovider.UpdateUserQuota(c.User, numFiles, filesSize, false) //nolint:errcheck
  806. } else {
  807. // we cannot have a directory here, initialSize != -1 only for files
  808. dataprovider.UpdateUserQuota(c.User, 0, filesSize-initialSize, false) //nolint:errcheck
  809. }
  810. }
  811. func (c *BaseConnection) updateQuotaMoveToVFolder(dstFolder vfs.VirtualFolder, initialSize, filesSize int64, numFiles int) {
  812. // move between the user home dir and a virtual folder
  813. dataprovider.UpdateUserQuota(c.User, -numFiles, -filesSize, false) //nolint:errcheck
  814. if initialSize == -1 {
  815. dataprovider.UpdateVirtualFolderQuota(dstFolder.BaseVirtualFolder, numFiles, filesSize, false) //nolint:errcheck
  816. if dstFolder.IsIncludedInUserQuota() {
  817. dataprovider.UpdateUserQuota(c.User, numFiles, filesSize, false) //nolint:errcheck
  818. }
  819. } else {
  820. // we cannot have a directory here, initialSize != -1 only for files
  821. dataprovider.UpdateVirtualFolderQuota(dstFolder.BaseVirtualFolder, 0, filesSize-initialSize, false) //nolint:errcheck
  822. if dstFolder.IsIncludedInUserQuota() {
  823. dataprovider.UpdateUserQuota(c.User, 0, filesSize-initialSize, false) //nolint:errcheck
  824. }
  825. }
  826. }
  827. func (c *BaseConnection) updateQuotaAfterRename(virtualSourcePath, virtualTargetPath, targetPath string, initialSize int64) error {
  828. // we don't allow to overwrite an existing directory so targetPath can be:
  829. // - a new file, a symlink is as a new file here
  830. // - a file overwriting an existing one
  831. // - a new directory
  832. // initialSize != -1 only when overwriting files
  833. sourceFolder, errSrc := c.User.GetVirtualFolderForPath(path.Dir(virtualSourcePath))
  834. dstFolder, errDst := c.User.GetVirtualFolderForPath(path.Dir(virtualTargetPath))
  835. if errSrc != nil && errDst != nil {
  836. // both files are contained inside the user home dir
  837. if initialSize != -1 {
  838. // we cannot have a directory here
  839. dataprovider.UpdateUserQuota(c.User, -1, -initialSize, false) //nolint:errcheck
  840. }
  841. return nil
  842. }
  843. filesSize := int64(0)
  844. numFiles := 1
  845. if fi, err := c.Fs.Stat(targetPath); err == nil {
  846. if fi.Mode().IsDir() {
  847. numFiles, filesSize, err = c.Fs.GetDirSize(targetPath)
  848. if err != nil {
  849. c.Log(logger.LevelWarn, "failed to update quota after rename, error scanning moved folder %#v: %v",
  850. targetPath, err)
  851. return err
  852. }
  853. } else {
  854. filesSize = fi.Size()
  855. }
  856. } else {
  857. c.Log(logger.LevelWarn, "failed to update quota after rename, file %#v stat error: %+v", targetPath, err)
  858. return err
  859. }
  860. if errSrc == nil && errDst == nil {
  861. c.updateQuotaMoveBetweenVFolders(sourceFolder, dstFolder, initialSize, filesSize, numFiles)
  862. }
  863. if errSrc == nil && errDst != nil {
  864. c.updateQuotaMoveFromVFolder(sourceFolder, initialSize, filesSize, numFiles)
  865. }
  866. if errSrc != nil && errDst == nil {
  867. c.updateQuotaMoveToVFolder(dstFolder, initialSize, filesSize, numFiles)
  868. }
  869. return nil
  870. }
  871. // GetPermissionDeniedError returns an appropriate permission denied error for the connection protocol
  872. func (c *BaseConnection) GetPermissionDeniedError() error {
  873. switch c.protocol {
  874. case ProtocolSFTP:
  875. return sftp.ErrSSHFxPermissionDenied
  876. case ProtocolWebDAV, ProtocolFTP:
  877. return os.ErrPermission
  878. default:
  879. return ErrPermissionDenied
  880. }
  881. }
  882. // GetNotExistError returns an appropriate not exist error for the connection protocol
  883. func (c *BaseConnection) GetNotExistError() error {
  884. switch c.protocol {
  885. case ProtocolSFTP:
  886. return sftp.ErrSSHFxNoSuchFile
  887. case ProtocolWebDAV, ProtocolFTP:
  888. return os.ErrNotExist
  889. default:
  890. return ErrNotExist
  891. }
  892. }
  893. // GetOpUnsupportedError returns an appropriate operation not supported error for the connection protocol
  894. func (c *BaseConnection) GetOpUnsupportedError() error {
  895. switch c.protocol {
  896. case ProtocolSFTP:
  897. return sftp.ErrSSHFxOpUnsupported
  898. default:
  899. return ErrOpUnsupported
  900. }
  901. }
  902. // GetGenericError returns an appropriate generic error for the connection protocol
  903. func (c *BaseConnection) GetGenericError(err error) error {
  904. switch c.protocol {
  905. case ProtocolSFTP:
  906. return sftp.ErrSSHFxFailure
  907. default:
  908. if err == ErrPermissionDenied || err == ErrNotExist || err == ErrOpUnsupported || err == ErrQuotaExceeded {
  909. return err
  910. }
  911. return ErrGenericFailure
  912. }
  913. }
  914. // GetFsError converts a filesystem error to a protocol error
  915. func (c *BaseConnection) GetFsError(err error) error {
  916. if c.Fs.IsNotExist(err) {
  917. return c.GetNotExistError()
  918. } else if c.Fs.IsPermission(err) {
  919. return c.GetPermissionDeniedError()
  920. } else if c.Fs.IsNotSupported(err) {
  921. return c.GetOpUnsupportedError()
  922. } else if err != nil {
  923. return c.GetGenericError(err)
  924. }
  925. return nil
  926. }