scp.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816
  1. // Copyright (C) 2019-2023 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. package sftpd
  15. import (
  16. "errors"
  17. "fmt"
  18. "io"
  19. "math"
  20. "os"
  21. "path"
  22. "path/filepath"
  23. "runtime/debug"
  24. "strconv"
  25. "strings"
  26. "github.com/drakkan/sftpgo/v2/internal/common"
  27. "github.com/drakkan/sftpgo/v2/internal/dataprovider"
  28. "github.com/drakkan/sftpgo/v2/internal/logger"
  29. "github.com/drakkan/sftpgo/v2/internal/util"
  30. "github.com/drakkan/sftpgo/v2/internal/vfs"
  31. )
  32. var (
  33. okMsg = []byte{0x00}
  34. warnMsg = []byte{0x01} // must be followed by an optional message and a newline
  35. errMsg = []byte{0x02} // must be followed by an optional message and a newline
  36. newLine = []byte{0x0A}
  37. )
  38. type scpCommand struct {
  39. sshCommand
  40. }
  41. func (c *scpCommand) handle() (err error) {
  42. defer func() {
  43. if r := recover(); r != nil {
  44. logger.Error(logSender, "", "panic in handle scp command: %#v stack trace: %v", r, string(debug.Stack()))
  45. err = common.ErrGenericFailure
  46. }
  47. }()
  48. if err := common.Connections.Add(c.connection); err != nil {
  49. logger.Info(logSender, "", "unable to add SCP connection: %v", err)
  50. return err
  51. }
  52. defer common.Connections.Remove(c.connection.GetID())
  53. destPath := c.getDestPath()
  54. commandType := c.getCommandType()
  55. c.connection.Log(logger.LevelDebug, "handle scp command, args: %v user: %v command type: %v, dest path: %#v",
  56. c.args, c.connection.User.Username, commandType, destPath)
  57. if commandType == "-t" {
  58. // -t means "to", so upload
  59. err = c.sendConfirmationMessage()
  60. if err != nil {
  61. return err
  62. }
  63. err = c.handleRecursiveUpload()
  64. if err != nil {
  65. return err
  66. }
  67. } else if commandType == "-f" {
  68. // -f means "from" so download
  69. err = c.readConfirmationMessage()
  70. if err != nil {
  71. return err
  72. }
  73. err = c.handleDownload(destPath)
  74. if err != nil {
  75. return err
  76. }
  77. } else {
  78. err = fmt.Errorf("scp command not supported, args: %v", c.args)
  79. c.connection.Log(logger.LevelDebug, "unsupported scp command, args: %v", c.args)
  80. }
  81. c.sendExitStatus(err)
  82. return err
  83. }
  84. func (c *scpCommand) handleRecursiveUpload() error {
  85. numDirs := 0
  86. destPath := c.getDestPath()
  87. for {
  88. fs, err := c.connection.User.GetFilesystemForPath(destPath, c.connection.ID)
  89. if err != nil {
  90. c.connection.Log(logger.LevelError, "error uploading file %#v: %+v", destPath, err)
  91. c.sendErrorMessage(nil, fmt.Errorf("unable to get fs for path %#v", destPath))
  92. return err
  93. }
  94. command, err := c.getNextUploadProtocolMessage()
  95. if err != nil {
  96. if errors.Is(err, io.EOF) {
  97. return nil
  98. }
  99. c.sendErrorMessage(fs, err)
  100. return err
  101. }
  102. if strings.HasPrefix(command, "E") {
  103. numDirs--
  104. c.connection.Log(logger.LevelDebug, "received end dir command, num dirs: %v", numDirs)
  105. if numDirs < 0 {
  106. err = errors.New("unacceptable end dir command")
  107. c.sendErrorMessage(nil, err)
  108. return err
  109. }
  110. // the destination dir is now the parent directory
  111. destPath = path.Join(destPath, "..")
  112. } else {
  113. sizeToRead, name, err := c.parseUploadMessage(fs, command)
  114. if err != nil {
  115. return err
  116. }
  117. if strings.HasPrefix(command, "D") {
  118. numDirs++
  119. destPath = path.Join(destPath, name)
  120. fs, err = c.connection.User.GetFilesystemForPath(destPath, c.connection.ID)
  121. if err != nil {
  122. c.connection.Log(logger.LevelError, "error uploading file %#v: %+v", destPath, err)
  123. c.sendErrorMessage(nil, fmt.Errorf("unable to get fs for path %#v", destPath))
  124. return err
  125. }
  126. err = c.handleCreateDir(fs, destPath)
  127. if err != nil {
  128. return err
  129. }
  130. c.connection.Log(logger.LevelDebug, "received start dir command, num dirs: %v destPath: %#v", numDirs, destPath)
  131. } else if strings.HasPrefix(command, "C") {
  132. err = c.handleUpload(c.getFileUploadDestPath(fs, destPath, name), sizeToRead)
  133. if err != nil {
  134. return err
  135. }
  136. }
  137. }
  138. err = c.sendConfirmationMessage()
  139. if err != nil {
  140. return err
  141. }
  142. }
  143. }
  144. func (c *scpCommand) handleCreateDir(fs vfs.Fs, dirPath string) error {
  145. c.connection.UpdateLastActivity()
  146. p, err := fs.ResolvePath(dirPath)
  147. if err != nil {
  148. c.connection.Log(logger.LevelError, "error creating dir: %#v, invalid file path, err: %v", dirPath, err)
  149. c.sendErrorMessage(fs, err)
  150. return err
  151. }
  152. if !c.connection.User.HasPerm(dataprovider.PermCreateDirs, path.Dir(dirPath)) {
  153. c.connection.Log(logger.LevelError, "error creating dir: %#v, permission denied", dirPath)
  154. c.sendErrorMessage(fs, common.ErrPermissionDenied)
  155. return common.ErrPermissionDenied
  156. }
  157. info, err := c.connection.DoStat(dirPath, 1, true)
  158. if err == nil && info.IsDir() {
  159. return nil
  160. }
  161. err = c.createDir(fs, p)
  162. if err != nil {
  163. return err
  164. }
  165. c.connection.Log(logger.LevelDebug, "created dir %q", dirPath)
  166. return nil
  167. }
  168. // we need to close the transfer if we have an error
  169. func (c *scpCommand) getUploadFileData(sizeToRead int64, transfer *transfer) error {
  170. err := c.sendConfirmationMessage()
  171. if err != nil {
  172. transfer.TransferError(err)
  173. transfer.Close()
  174. return err
  175. }
  176. if sizeToRead > 0 {
  177. // we could replace this method with io.CopyN implementing "Write" method in transfer struct
  178. remaining := sizeToRead
  179. buf := make([]byte, int64(math.Min(32768, float64(sizeToRead))))
  180. for {
  181. n, err := c.connection.channel.Read(buf)
  182. if err != nil {
  183. c.sendErrorMessage(transfer.Fs, err)
  184. transfer.TransferError(err)
  185. transfer.Close()
  186. return err
  187. }
  188. _, err = transfer.WriteAt(buf[:n], sizeToRead-remaining)
  189. if err != nil {
  190. c.sendErrorMessage(transfer.Fs, err)
  191. transfer.Close()
  192. return err
  193. }
  194. remaining -= int64(n)
  195. if remaining <= 0 {
  196. break
  197. }
  198. if remaining < int64(len(buf)) {
  199. buf = make([]byte, remaining)
  200. }
  201. }
  202. }
  203. err = c.readConfirmationMessage()
  204. if err != nil {
  205. transfer.TransferError(err)
  206. transfer.Close()
  207. return err
  208. }
  209. err = transfer.Close()
  210. if err != nil {
  211. c.sendErrorMessage(transfer.Fs, err)
  212. return err
  213. }
  214. return nil
  215. }
  216. func (c *scpCommand) handleUploadFile(fs vfs.Fs, resolvedPath, filePath string, sizeToRead int64, isNewFile bool, fileSize int64, requestPath string) error {
  217. diskQuota, transferQuota := c.connection.HasSpace(isNewFile, false, requestPath)
  218. if !diskQuota.HasSpace || !transferQuota.HasUploadSpace() {
  219. err := fmt.Errorf("denying file write due to quota limits")
  220. c.connection.Log(logger.LevelError, "error uploading file: %#v, err: %v", filePath, err)
  221. c.sendErrorMessage(nil, err)
  222. return err
  223. }
  224. _, err := common.ExecutePreAction(c.connection.BaseConnection, common.OperationPreUpload, resolvedPath, requestPath,
  225. fileSize, os.O_TRUNC)
  226. if err != nil {
  227. c.connection.Log(logger.LevelDebug, "upload for file %#v denied by pre action: %v", requestPath, err)
  228. err = c.connection.GetPermissionDeniedError()
  229. c.sendErrorMessage(fs, err)
  230. return err
  231. }
  232. maxWriteSize, _ := c.connection.GetMaxWriteSize(diskQuota, false, fileSize, fs.IsUploadResumeSupported())
  233. file, w, cancelFn, err := fs.Create(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC)
  234. if err != nil {
  235. c.connection.Log(logger.LevelError, "error creating file %#v: %v", resolvedPath, err)
  236. c.sendErrorMessage(fs, err)
  237. return err
  238. }
  239. initialSize := int64(0)
  240. truncatedSize := int64(0) // bytes truncated and not included in quota
  241. if !isNewFile {
  242. if vfs.HasTruncateSupport(fs) {
  243. vfolder, err := c.connection.User.GetVirtualFolderForPath(path.Dir(requestPath))
  244. if err == nil {
  245. dataprovider.UpdateVirtualFolderQuota(&vfolder.BaseVirtualFolder, 0, -fileSize, false) //nolint:errcheck
  246. if vfolder.IsIncludedInUserQuota() {
  247. dataprovider.UpdateUserQuota(&c.connection.User, 0, -fileSize, false) //nolint:errcheck
  248. }
  249. } else {
  250. dataprovider.UpdateUserQuota(&c.connection.User, 0, -fileSize, false) //nolint:errcheck
  251. }
  252. } else {
  253. initialSize = fileSize
  254. truncatedSize = initialSize
  255. }
  256. if maxWriteSize > 0 {
  257. maxWriteSize += fileSize
  258. }
  259. }
  260. vfs.SetPathPermissions(fs, filePath, c.connection.User.GetUID(), c.connection.User.GetGID())
  261. baseTransfer := common.NewBaseTransfer(file, c.connection.BaseConnection, cancelFn, resolvedPath, filePath, requestPath,
  262. common.TransferUpload, 0, initialSize, maxWriteSize, truncatedSize, isNewFile, fs, transferQuota)
  263. t := newTransfer(baseTransfer, w, nil, nil)
  264. return c.getUploadFileData(sizeToRead, t)
  265. }
  266. func (c *scpCommand) handleUpload(uploadFilePath string, sizeToRead int64) error {
  267. c.connection.UpdateLastActivity()
  268. fs, p, err := c.connection.GetFsAndResolvedPath(uploadFilePath)
  269. if err != nil {
  270. c.connection.Log(logger.LevelError, "error uploading file: %#v, err: %v", uploadFilePath, err)
  271. c.sendErrorMessage(nil, err)
  272. return err
  273. }
  274. if ok, _ := c.connection.User.IsFileAllowed(uploadFilePath); !ok {
  275. c.connection.Log(logger.LevelWarn, "writing file %#v is not allowed", uploadFilePath)
  276. c.sendErrorMessage(fs, c.connection.GetPermissionDeniedError())
  277. return common.ErrPermissionDenied
  278. }
  279. filePath := p
  280. if common.Config.IsAtomicUploadEnabled() && fs.IsAtomicUploadSupported() {
  281. filePath = fs.GetAtomicUploadPath(p)
  282. }
  283. stat, statErr := fs.Lstat(p)
  284. if (statErr == nil && stat.Mode()&os.ModeSymlink != 0) || fs.IsNotExist(statErr) {
  285. if !c.connection.User.HasPerm(dataprovider.PermUpload, path.Dir(uploadFilePath)) {
  286. c.connection.Log(logger.LevelWarn, "cannot upload file: %#v, permission denied", uploadFilePath)
  287. c.sendErrorMessage(fs, common.ErrPermissionDenied)
  288. return common.ErrPermissionDenied
  289. }
  290. return c.handleUploadFile(fs, p, filePath, sizeToRead, true, 0, uploadFilePath)
  291. }
  292. if statErr != nil {
  293. c.connection.Log(logger.LevelError, "error performing file stat %#v: %v", p, statErr)
  294. c.sendErrorMessage(fs, statErr)
  295. return statErr
  296. }
  297. if stat.IsDir() {
  298. c.connection.Log(logger.LevelError, "attempted to open a directory for writing to: %#v", p)
  299. err = fmt.Errorf("attempted to open a directory for writing: %#v", p)
  300. c.sendErrorMessage(fs, err)
  301. return err
  302. }
  303. if !c.connection.User.HasPerm(dataprovider.PermOverwrite, uploadFilePath) {
  304. c.connection.Log(logger.LevelWarn, "cannot overwrite file: %#v, permission denied", uploadFilePath)
  305. c.sendErrorMessage(fs, common.ErrPermissionDenied)
  306. return common.ErrPermissionDenied
  307. }
  308. if common.Config.IsAtomicUploadEnabled() && fs.IsAtomicUploadSupported() {
  309. _, _, err = fs.Rename(p, filePath)
  310. if err != nil {
  311. c.connection.Log(logger.LevelError, "error renaming existing file for atomic upload, source: %#v, dest: %#v, err: %v",
  312. p, filePath, err)
  313. c.sendErrorMessage(fs, err)
  314. return err
  315. }
  316. }
  317. return c.handleUploadFile(fs, p, filePath, sizeToRead, false, stat.Size(), uploadFilePath)
  318. }
  319. func (c *scpCommand) sendDownloadProtocolMessages(virtualDirPath string, stat os.FileInfo) error {
  320. var err error
  321. if c.sendFileTime() {
  322. modTime := stat.ModTime().UnixNano() / 1000000000
  323. tCommand := fmt.Sprintf("T%v 0 %v 0\n", modTime, modTime)
  324. err = c.sendProtocolMessage(tCommand)
  325. if err != nil {
  326. return err
  327. }
  328. err = c.readConfirmationMessage()
  329. if err != nil {
  330. return err
  331. }
  332. }
  333. dirName := path.Base(virtualDirPath)
  334. if dirName == "/" || dirName == "." {
  335. dirName = c.connection.User.Username
  336. }
  337. fileMode := fmt.Sprintf("D%v 0 %v\n", getFileModeAsString(stat.Mode(), stat.IsDir()), dirName)
  338. err = c.sendProtocolMessage(fileMode)
  339. if err != nil {
  340. return err
  341. }
  342. err = c.readConfirmationMessage()
  343. return err
  344. }
  345. // We send first all the files in the root directory and then the directories.
  346. // For each directory we recursively call this method again
  347. func (c *scpCommand) handleRecursiveDownload(fs vfs.Fs, dirPath, virtualPath string, stat os.FileInfo) error {
  348. var err error
  349. if c.isRecursive() {
  350. c.connection.Log(logger.LevelDebug, "recursive download, dir path %#v virtual path %#v", dirPath, virtualPath)
  351. err = c.sendDownloadProtocolMessages(virtualPath, stat)
  352. if err != nil {
  353. return err
  354. }
  355. files, err := fs.ReadDir(dirPath)
  356. if err != nil {
  357. c.sendErrorMessage(fs, err)
  358. return err
  359. }
  360. files = c.connection.User.FilterListDir(files, fs.GetRelativePath(dirPath))
  361. var dirs []string
  362. for _, file := range files {
  363. filePath := fs.GetRelativePath(fs.Join(dirPath, file.Name()))
  364. if file.Mode().IsRegular() || file.Mode()&os.ModeSymlink != 0 {
  365. err = c.handleDownload(filePath)
  366. if err != nil {
  367. break
  368. }
  369. } else if file.IsDir() {
  370. dirs = append(dirs, filePath)
  371. }
  372. }
  373. if err != nil {
  374. c.sendErrorMessage(fs, err)
  375. return err
  376. }
  377. for _, dir := range dirs {
  378. err = c.handleDownload(dir)
  379. if err != nil {
  380. break
  381. }
  382. }
  383. if err != nil {
  384. c.sendErrorMessage(fs, err)
  385. return err
  386. }
  387. err = c.sendProtocolMessage("E\n")
  388. if err != nil {
  389. return err
  390. }
  391. return c.readConfirmationMessage()
  392. }
  393. err = fmt.Errorf("unable to send directory for non recursive copy")
  394. c.sendErrorMessage(nil, err)
  395. return err
  396. }
  397. func (c *scpCommand) sendDownloadFileData(fs vfs.Fs, filePath string, stat os.FileInfo, transfer *transfer) error {
  398. var err error
  399. if c.sendFileTime() {
  400. modTime := stat.ModTime().UnixNano() / 1000000000
  401. tCommand := fmt.Sprintf("T%v 0 %v 0\n", modTime, modTime)
  402. err = c.sendProtocolMessage(tCommand)
  403. if err != nil {
  404. return err
  405. }
  406. err = c.readConfirmationMessage()
  407. if err != nil {
  408. return err
  409. }
  410. }
  411. if vfs.IsCryptOsFs(fs) {
  412. stat = fs.(*vfs.CryptFs).ConvertFileInfo(stat)
  413. }
  414. fileSize := stat.Size()
  415. readed := int64(0)
  416. fileMode := fmt.Sprintf("C%v %v %v\n", getFileModeAsString(stat.Mode(), stat.IsDir()), fileSize, filepath.Base(filePath))
  417. err = c.sendProtocolMessage(fileMode)
  418. if err != nil {
  419. return err
  420. }
  421. err = c.readConfirmationMessage()
  422. if err != nil {
  423. return err
  424. }
  425. // we could replace this method with io.CopyN implementing "Read" method in transfer struct
  426. buf := make([]byte, 32768)
  427. var n int
  428. for {
  429. n, err = transfer.ReadAt(buf, readed)
  430. if err == nil || err == io.EOF {
  431. if n > 0 {
  432. _, err = c.connection.channel.Write(buf[:n])
  433. }
  434. }
  435. readed += int64(n)
  436. if err != nil {
  437. break
  438. }
  439. }
  440. if err != io.EOF {
  441. c.sendErrorMessage(fs, err)
  442. return err
  443. }
  444. err = c.sendConfirmationMessage()
  445. if err != nil {
  446. return err
  447. }
  448. err = c.readConfirmationMessage()
  449. return err
  450. }
  451. func (c *scpCommand) handleDownload(filePath string) error {
  452. c.connection.UpdateLastActivity()
  453. transferQuota := c.connection.GetTransferQuota()
  454. if !transferQuota.HasDownloadSpace() {
  455. c.connection.Log(logger.LevelInfo, "denying file read due to quota limits")
  456. c.sendErrorMessage(nil, c.connection.GetReadQuotaExceededError())
  457. return c.connection.GetReadQuotaExceededError()
  458. }
  459. var err error
  460. fs, p, err := c.connection.GetFsAndResolvedPath(filePath)
  461. if err != nil {
  462. c.connection.Log(logger.LevelError, "error downloading file %q: %+v", filePath, err)
  463. c.sendErrorMessage(nil, fmt.Errorf("unable to download file %q: %w", filePath, err))
  464. return err
  465. }
  466. var stat os.FileInfo
  467. if stat, err = fs.Stat(p); err != nil {
  468. c.connection.Log(logger.LevelError, "error downloading file: %#v->%#v, err: %v", filePath, p, err)
  469. c.sendErrorMessage(fs, err)
  470. return err
  471. }
  472. if stat.IsDir() {
  473. if !c.connection.User.HasPerm(dataprovider.PermDownload, filePath) {
  474. c.connection.Log(logger.LevelWarn, "error downloading dir: %#v, permission denied", filePath)
  475. c.sendErrorMessage(fs, common.ErrPermissionDenied)
  476. return common.ErrPermissionDenied
  477. }
  478. err = c.handleRecursiveDownload(fs, p, filePath, stat)
  479. return err
  480. }
  481. if !c.connection.User.HasPerm(dataprovider.PermDownload, path.Dir(filePath)) {
  482. c.connection.Log(logger.LevelWarn, "error downloading dir: %#v, permission denied", filePath)
  483. c.sendErrorMessage(fs, common.ErrPermissionDenied)
  484. return common.ErrPermissionDenied
  485. }
  486. if ok, policy := c.connection.User.IsFileAllowed(filePath); !ok {
  487. c.connection.Log(logger.LevelWarn, "reading file %#v is not allowed", filePath)
  488. c.sendErrorMessage(fs, c.connection.GetErrorForDeniedFile(policy))
  489. return common.ErrPermissionDenied
  490. }
  491. if _, err := common.ExecutePreAction(c.connection.BaseConnection, common.OperationPreDownload, p, filePath, 0, 0); err != nil {
  492. c.connection.Log(logger.LevelDebug, "download for file %#v denied by pre action: %v", filePath, err)
  493. c.sendErrorMessage(fs, common.ErrPermissionDenied)
  494. return common.ErrPermissionDenied
  495. }
  496. file, r, cancelFn, err := fs.Open(p, 0)
  497. if err != nil {
  498. c.connection.Log(logger.LevelError, "could not open file %#v for reading: %v", p, err)
  499. c.sendErrorMessage(fs, err)
  500. return err
  501. }
  502. baseTransfer := common.NewBaseTransfer(file, c.connection.BaseConnection, cancelFn, p, p, filePath,
  503. common.TransferDownload, 0, 0, 0, 0, false, fs, transferQuota)
  504. t := newTransfer(baseTransfer, nil, r, nil)
  505. err = c.sendDownloadFileData(fs, p, stat, t)
  506. // we need to call Close anyway and return close error if any and
  507. // if we have no previous error
  508. if err == nil {
  509. err = t.Close()
  510. } else {
  511. t.TransferError(err)
  512. t.Close()
  513. }
  514. return err
  515. }
  516. func (c *scpCommand) getCommandType() string {
  517. return c.args[len(c.args)-2]
  518. }
  519. func (c *scpCommand) sendFileTime() bool {
  520. return util.Contains(c.args, "-p")
  521. }
  522. func (c *scpCommand) isRecursive() bool {
  523. return util.Contains(c.args, "-r")
  524. }
  525. // read the SCP confirmation message and the optional text message
  526. // the channel will be closed on errors
  527. func (c *scpCommand) readConfirmationMessage() error {
  528. var msg strings.Builder
  529. buf := make([]byte, 1)
  530. n, err := c.connection.channel.Read(buf)
  531. if err != nil {
  532. c.connection.channel.Close()
  533. return err
  534. }
  535. if n == 1 && (buf[0] == warnMsg[0] || buf[0] == errMsg[0]) {
  536. isError := buf[0] == errMsg[0]
  537. for {
  538. n, err = c.connection.channel.Read(buf)
  539. readed := buf[:n]
  540. if err != nil || (n == 1 && readed[0] == newLine[0]) {
  541. break
  542. }
  543. if n > 0 {
  544. msg.Write(readed)
  545. }
  546. }
  547. c.connection.Log(logger.LevelInfo, "scp error message received: %v is error: %v", msg.String(), isError)
  548. err = fmt.Errorf("%v", msg.String())
  549. c.connection.channel.Close()
  550. }
  551. return err
  552. }
  553. // protool messages are newline terminated
  554. func (c *scpCommand) readProtocolMessage() (string, error) {
  555. var command strings.Builder
  556. var err error
  557. buf := make([]byte, 1)
  558. for {
  559. var n int
  560. n, err = c.connection.channel.Read(buf)
  561. if err != nil {
  562. break
  563. }
  564. if n > 0 {
  565. readed := buf[:n]
  566. if n == 1 && readed[0] == newLine[0] {
  567. break
  568. }
  569. command.Write(readed)
  570. }
  571. }
  572. if err != nil && !errors.Is(err, io.EOF) {
  573. c.connection.channel.Close()
  574. }
  575. return command.String(), err
  576. }
  577. // sendErrorMessage sends an error message and close the channel
  578. // we don't check write errors here, we have to close the channel anyway
  579. //
  580. //nolint:errcheck
  581. func (c *scpCommand) sendErrorMessage(fs vfs.Fs, err error) {
  582. c.connection.channel.Write(errMsg)
  583. if fs != nil {
  584. c.connection.channel.Write([]byte(c.connection.GetFsError(fs, err).Error()))
  585. } else {
  586. c.connection.channel.Write([]byte(err.Error()))
  587. }
  588. c.connection.channel.Write(newLine)
  589. c.connection.channel.Close()
  590. }
  591. // send scp confirmation message and close the channel if an error happen
  592. func (c *scpCommand) sendConfirmationMessage() error {
  593. _, err := c.connection.channel.Write(okMsg)
  594. if err != nil {
  595. c.connection.channel.Close()
  596. }
  597. return err
  598. }
  599. // sends a protocol message and close the channel on error
  600. func (c *scpCommand) sendProtocolMessage(message string) error {
  601. _, err := c.connection.channel.Write([]byte(message))
  602. if err != nil {
  603. c.connection.Log(logger.LevelError, "error sending protocol message: %v, err: %v", message, err)
  604. c.connection.channel.Close()
  605. }
  606. return err
  607. }
  608. // get the next upload protocol message ignoring T command if any
  609. func (c *scpCommand) getNextUploadProtocolMessage() (string, error) {
  610. var command string
  611. var err error
  612. for {
  613. command, err = c.readProtocolMessage()
  614. if err != nil {
  615. return command, err
  616. }
  617. if strings.HasPrefix(command, "T") {
  618. err = c.sendConfirmationMessage()
  619. if err != nil {
  620. return command, err
  621. }
  622. } else {
  623. break
  624. }
  625. }
  626. return command, err
  627. }
  628. func (c *scpCommand) createDir(fs vfs.Fs, dirPath string) error {
  629. err := fs.Mkdir(dirPath)
  630. if err != nil {
  631. c.connection.Log(logger.LevelError, "error creating dir %#v: %v", dirPath, err)
  632. c.sendErrorMessage(fs, err)
  633. return err
  634. }
  635. vfs.SetPathPermissions(fs, dirPath, c.connection.User.GetUID(), c.connection.User.GetGID())
  636. return err
  637. }
  638. // parse protocol messages such as:
  639. // D0755 0 testdir
  640. // or:
  641. // C0644 6 testfile
  642. // and returns file size and file/directory name
  643. func (c *scpCommand) parseUploadMessage(fs vfs.Fs, command string) (int64, string, error) {
  644. var size int64
  645. var name string
  646. var err error
  647. if !strings.HasPrefix(command, "C") && !strings.HasPrefix(command, "D") {
  648. err = fmt.Errorf("unknown or invalid upload message: %v args: %v user: %v",
  649. command, c.args, c.connection.User.Username)
  650. c.connection.Log(logger.LevelError, "error: %v", err)
  651. c.sendErrorMessage(fs, err)
  652. return size, name, err
  653. }
  654. parts := strings.SplitN(command, " ", 3)
  655. if len(parts) == 3 {
  656. size, err = strconv.ParseInt(parts[1], 10, 64)
  657. if err != nil {
  658. c.connection.Log(logger.LevelError, "error getting size from upload message: %v", err)
  659. c.sendErrorMessage(fs, err)
  660. return size, name, err
  661. }
  662. name = parts[2]
  663. if name == "" {
  664. err = fmt.Errorf("error getting name from upload message, cannot be empty")
  665. c.connection.Log(logger.LevelError, "error: %v", err)
  666. c.sendErrorMessage(fs, err)
  667. return size, name, err
  668. }
  669. } else {
  670. err = fmt.Errorf("unable to split upload message: %#v", command)
  671. c.connection.Log(logger.LevelError, "error: %v", err)
  672. c.sendErrorMessage(fs, err)
  673. return size, name, err
  674. }
  675. return size, name, err
  676. }
  677. func (c *scpCommand) getFileUploadDestPath(fs vfs.Fs, scpDestPath, fileName string) string {
  678. if !c.isRecursive() {
  679. // if the upload is not recursive and the destination path does not end with "/"
  680. // then scpDestPath is the wanted filename, for example:
  681. // scp fileName.txt [email protected]:/newFileName.txt
  682. // or
  683. // scp fileName.txt [email protected]:/fileName.txt
  684. if !strings.HasSuffix(scpDestPath, "/") {
  685. // but if scpDestPath is an existing directory then we put the uploaded file
  686. // inside that directory this is as scp command works, for example:
  687. // scp fileName.txt [email protected]:/existing_dir
  688. if p, err := fs.ResolvePath(scpDestPath); err == nil {
  689. if stat, err := fs.Stat(p); err == nil {
  690. if stat.IsDir() {
  691. return path.Join(scpDestPath, fileName)
  692. }
  693. }
  694. }
  695. return scpDestPath
  696. }
  697. }
  698. // if the upload is recursive or scpDestPath has the "/" suffix then the destination
  699. // file is relative to scpDestPath
  700. return path.Join(scpDestPath, fileName)
  701. }
  702. func getFileModeAsString(fileMode os.FileMode, isDir bool) string {
  703. var defaultMode string
  704. if isDir {
  705. defaultMode = "0755"
  706. } else {
  707. defaultMode = "0644"
  708. }
  709. if fileMode == 0 {
  710. return defaultMode
  711. }
  712. modeString := []byte(fileMode.String())
  713. nullPerm := []byte("-")
  714. u := 0
  715. g := 0
  716. o := 0
  717. s := 0
  718. lastChar := len(modeString) - 1
  719. if fileMode&os.ModeSticky != 0 {
  720. s++
  721. }
  722. if fileMode&os.ModeSetuid != 0 {
  723. s += 2
  724. }
  725. if fileMode&os.ModeSetgid != 0 {
  726. s += 4
  727. }
  728. if modeString[lastChar-8] != nullPerm[0] {
  729. u += 4
  730. }
  731. if modeString[lastChar-7] != nullPerm[0] {
  732. u += 2
  733. }
  734. if modeString[lastChar-6] != nullPerm[0] {
  735. u++
  736. }
  737. if modeString[lastChar-5] != nullPerm[0] {
  738. g += 4
  739. }
  740. if modeString[lastChar-4] != nullPerm[0] {
  741. g += 2
  742. }
  743. if modeString[lastChar-3] != nullPerm[0] {
  744. g++
  745. }
  746. if modeString[lastChar-2] != nullPerm[0] {
  747. o += 4
  748. }
  749. if modeString[lastChar-1] != nullPerm[0] {
  750. o += 2
  751. }
  752. if modeString[lastChar] != nullPerm[0] {
  753. o++
  754. }
  755. return fmt.Sprintf("%v%v%v%v", s, u, g, o)
  756. }