scp.go 21 KB

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