scp.go 21 KB

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