scp.go 23 KB

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