internal_test.go 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870
  1. package sftpd
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "net"
  9. "os"
  10. "path/filepath"
  11. "runtime"
  12. "testing"
  13. "time"
  14. "github.com/eikenb/pipeat"
  15. "github.com/pkg/sftp"
  16. "github.com/stretchr/testify/assert"
  17. "github.com/stretchr/testify/require"
  18. "golang.org/x/crypto/ssh"
  19. "github.com/drakkan/sftpgo/common"
  20. "github.com/drakkan/sftpgo/dataprovider"
  21. "github.com/drakkan/sftpgo/utils"
  22. "github.com/drakkan/sftpgo/vfs"
  23. )
  24. const osWindows = "windows"
  25. type MockChannel struct {
  26. Buffer *bytes.Buffer
  27. StdErrBuffer *bytes.Buffer
  28. ReadError error
  29. WriteError error
  30. ShortWriteErr bool
  31. }
  32. func (c *MockChannel) Read(data []byte) (int, error) {
  33. if c.ReadError != nil {
  34. return 0, c.ReadError
  35. }
  36. return c.Buffer.Read(data)
  37. }
  38. func (c *MockChannel) Write(data []byte) (int, error) {
  39. if c.WriteError != nil {
  40. return 0, c.WriteError
  41. }
  42. if c.ShortWriteErr {
  43. return 0, nil
  44. }
  45. return c.Buffer.Write(data)
  46. }
  47. func (c *MockChannel) Close() error {
  48. return nil
  49. }
  50. func (c *MockChannel) CloseWrite() error {
  51. return nil
  52. }
  53. func (c *MockChannel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) {
  54. return true, nil
  55. }
  56. func (c *MockChannel) Stderr() io.ReadWriter {
  57. return c.StdErrBuffer
  58. }
  59. // MockOsFs mockable OsFs
  60. type MockOsFs struct {
  61. vfs.Fs
  62. err error
  63. statErr error
  64. isAtomicUploadSupported bool
  65. }
  66. // Name returns the name for the Fs implementation
  67. func (fs MockOsFs) Name() string {
  68. return "mockOsFs"
  69. }
  70. // IsUploadResumeSupported returns true if upload resume is supported
  71. func (MockOsFs) IsUploadResumeSupported() bool {
  72. return false
  73. }
  74. // IsAtomicUploadSupported returns true if atomic upload is supported
  75. func (fs MockOsFs) IsAtomicUploadSupported() bool {
  76. return fs.isAtomicUploadSupported
  77. }
  78. // Stat returns a FileInfo describing the named file
  79. func (fs MockOsFs) Stat(name string) (os.FileInfo, error) {
  80. if fs.statErr != nil {
  81. return nil, fs.statErr
  82. }
  83. return os.Stat(name)
  84. }
  85. // Lstat returns a FileInfo describing the named file
  86. func (fs MockOsFs) Lstat(name string) (os.FileInfo, error) {
  87. if fs.statErr != nil {
  88. return nil, fs.statErr
  89. }
  90. return os.Lstat(name)
  91. }
  92. // Remove removes the named file or (empty) directory.
  93. func (fs MockOsFs) Remove(name string, isDir bool) error {
  94. if fs.err != nil {
  95. return fs.err
  96. }
  97. return os.Remove(name)
  98. }
  99. // Rename renames (moves) source to target
  100. func (fs MockOsFs) Rename(source, target string) error {
  101. if fs.err != nil {
  102. return fs.err
  103. }
  104. return os.Rename(source, target)
  105. }
  106. func newMockOsFs(err, statErr error, atomicUpload bool, connectionID, rootDir string) vfs.Fs {
  107. return &MockOsFs{
  108. Fs: vfs.NewOsFs(connectionID, rootDir, nil),
  109. err: err,
  110. statErr: statErr,
  111. isAtomicUploadSupported: atomicUpload,
  112. }
  113. }
  114. func TestRemoveNonexistentQuotaScan(t *testing.T) {
  115. assert.False(t, common.QuotaScans.RemoveUserQuotaScan("username"))
  116. }
  117. func TestGetOSOpenFlags(t *testing.T) {
  118. var flags sftp.FileOpenFlags
  119. flags.Write = true
  120. flags.Excl = true
  121. osFlags := getOSOpenFlags(flags)
  122. assert.NotEqual(t, 0, osFlags&os.O_WRONLY)
  123. assert.NotEqual(t, 0, osFlags&os.O_EXCL)
  124. flags.Append = true
  125. // append flag should be ignored to allow resume
  126. assert.NotEqual(t, 0, osFlags&os.O_WRONLY)
  127. assert.NotEqual(t, 0, osFlags&os.O_EXCL)
  128. }
  129. func TestUploadResumeInvalidOffset(t *testing.T) {
  130. testfile := "testfile" //nolint:goconst
  131. file, err := os.Create(testfile)
  132. assert.NoError(t, err)
  133. user := dataprovider.User{
  134. Username: "testuser",
  135. }
  136. fs := vfs.NewOsFs("", os.TempDir(), nil)
  137. conn := common.NewBaseConnection("", common.ProtocolSFTP, user, fs)
  138. baseTransfer := common.NewBaseTransfer(file, conn, nil, file.Name(), testfile, common.TransferUpload, 10, 0, 0, false, fs)
  139. transfer := newTransfer(baseTransfer, nil, nil, nil)
  140. _, err = transfer.WriteAt([]byte("test"), 0)
  141. assert.Error(t, err, "upload with invalid offset must fail")
  142. if assert.Error(t, transfer.ErrTransfer) {
  143. assert.EqualError(t, err, transfer.ErrTransfer.Error())
  144. assert.Contains(t, transfer.ErrTransfer.Error(), "Invalid write offset")
  145. }
  146. err = transfer.Close()
  147. if assert.Error(t, err) {
  148. assert.EqualError(t, err, sftp.ErrSSHFxFailure.Error())
  149. }
  150. err = os.Remove(testfile)
  151. assert.NoError(t, err)
  152. }
  153. func TestReadWriteErrors(t *testing.T) {
  154. testfile := "testfile"
  155. file, err := os.Create(testfile)
  156. assert.NoError(t, err)
  157. user := dataprovider.User{
  158. Username: "testuser",
  159. }
  160. fs := vfs.NewOsFs("", os.TempDir(), nil)
  161. conn := common.NewBaseConnection("", common.ProtocolSFTP, user, fs)
  162. baseTransfer := common.NewBaseTransfer(file, conn, nil, file.Name(), testfile, common.TransferDownload, 0, 0, 0, false, fs)
  163. transfer := newTransfer(baseTransfer, nil, nil, nil)
  164. err = file.Close()
  165. assert.NoError(t, err)
  166. _, err = transfer.WriteAt([]byte("test"), 0)
  167. assert.Error(t, err, "writing to closed file must fail")
  168. buf := make([]byte, 32768)
  169. _, err = transfer.ReadAt(buf, 0)
  170. assert.Error(t, err, "reading from a closed file must fail")
  171. err = transfer.Close()
  172. assert.Error(t, err)
  173. r, _, err := pipeat.Pipe()
  174. assert.NoError(t, err)
  175. baseTransfer = common.NewBaseTransfer(nil, conn, nil, file.Name(), testfile, common.TransferDownload, 0, 0, 0, false, fs)
  176. transfer = newTransfer(baseTransfer, nil, r, nil)
  177. err = transfer.Close()
  178. assert.NoError(t, err)
  179. _, err = transfer.ReadAt(buf, 0)
  180. assert.Error(t, err, "reading from a closed pipe must fail")
  181. r, w, err := pipeat.Pipe()
  182. assert.NoError(t, err)
  183. pipeWriter := vfs.NewPipeWriter(w)
  184. baseTransfer = common.NewBaseTransfer(nil, conn, nil, file.Name(), testfile, common.TransferDownload, 0, 0, 0, false, fs)
  185. transfer = newTransfer(baseTransfer, pipeWriter, nil, nil)
  186. err = r.Close()
  187. assert.NoError(t, err)
  188. errFake := fmt.Errorf("fake upload error")
  189. go func() {
  190. time.Sleep(100 * time.Millisecond)
  191. pipeWriter.Done(errFake)
  192. }()
  193. err = transfer.closeIO()
  194. assert.EqualError(t, err, errFake.Error())
  195. _, err = transfer.WriteAt([]byte("test"), 0)
  196. assert.Error(t, err, "writing to closed pipe must fail")
  197. err = transfer.BaseTransfer.Close()
  198. assert.EqualError(t, err, errFake.Error())
  199. err = os.Remove(testfile)
  200. assert.NoError(t, err)
  201. assert.Len(t, conn.GetTransfers(), 0)
  202. }
  203. func TestUnsupportedListOP(t *testing.T) {
  204. fs := vfs.NewOsFs("", os.TempDir(), nil)
  205. conn := common.NewBaseConnection("", common.ProtocolSFTP, dataprovider.User{}, fs)
  206. sftpConn := Connection{
  207. BaseConnection: conn,
  208. }
  209. request := sftp.NewRequest("Unsupported", "")
  210. _, err := sftpConn.Filelist(request)
  211. assert.EqualError(t, err, sftp.ErrSSHFxOpUnsupported.Error())
  212. }
  213. func TestTransferCancelFn(t *testing.T) {
  214. testfile := "testfile"
  215. file, err := os.Create(testfile)
  216. assert.NoError(t, err)
  217. isCancelled := false
  218. cancelFn := func() {
  219. isCancelled = true
  220. }
  221. user := dataprovider.User{
  222. Username: "testuser",
  223. }
  224. fs := vfs.NewOsFs("", os.TempDir(), nil)
  225. conn := common.NewBaseConnection("", common.ProtocolSFTP, user, fs)
  226. baseTransfer := common.NewBaseTransfer(file, conn, cancelFn, file.Name(), testfile, common.TransferDownload, 0, 0, 0, false, fs)
  227. transfer := newTransfer(baseTransfer, nil, nil, nil)
  228. errFake := errors.New("fake error, this will trigger cancelFn")
  229. transfer.TransferError(errFake)
  230. err = transfer.Close()
  231. if assert.Error(t, err) {
  232. assert.EqualError(t, err, sftp.ErrSSHFxFailure.Error())
  233. }
  234. if assert.Error(t, transfer.ErrTransfer) {
  235. assert.EqualError(t, transfer.ErrTransfer, errFake.Error())
  236. }
  237. assert.True(t, isCancelled, "cancelFn not called!")
  238. err = os.Remove(testfile)
  239. assert.NoError(t, err)
  240. }
  241. func TestMockFsErrors(t *testing.T) {
  242. errFake := errors.New("fake error")
  243. fs := newMockOsFs(errFake, errFake, false, "123", os.TempDir())
  244. u := dataprovider.User{}
  245. u.Username = "test_username"
  246. u.Permissions = make(map[string][]string)
  247. u.Permissions["/"] = []string{dataprovider.PermAny}
  248. u.HomeDir = os.TempDir()
  249. c := Connection{
  250. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, u, fs),
  251. }
  252. testfile := filepath.Join(u.HomeDir, "testfile")
  253. request := sftp.NewRequest("Remove", testfile)
  254. err := ioutil.WriteFile(testfile, []byte("test"), os.ModePerm)
  255. assert.NoError(t, err)
  256. _, err = c.Filewrite(request)
  257. assert.EqualError(t, err, sftp.ErrSSHFxFailure.Error())
  258. var flags sftp.FileOpenFlags
  259. flags.Write = true
  260. flags.Trunc = false
  261. flags.Append = true
  262. _, err = c.handleSFTPUploadToExistingFile(flags, testfile, testfile, 0, "/testfile", nil)
  263. assert.EqualError(t, err, sftp.ErrSSHFxOpUnsupported.Error())
  264. fs = newMockOsFs(errFake, nil, false, "123", os.TempDir())
  265. c.BaseConnection.Fs = fs
  266. err = c.handleSFTPRemove(testfile, request)
  267. assert.EqualError(t, err, sftp.ErrSSHFxFailure.Error())
  268. request = sftp.NewRequest("Rename", filepath.Base(testfile))
  269. request.Target = filepath.Base(testfile) + "1"
  270. err = c.Rename(testfile, testfile+"1", request.Filepath, request.Target)
  271. assert.EqualError(t, err, sftp.ErrSSHFxFailure.Error())
  272. err = os.Remove(testfile)
  273. assert.NoError(t, err)
  274. }
  275. func TestUploadFiles(t *testing.T) {
  276. oldUploadMode := common.Config.UploadMode
  277. common.Config.UploadMode = common.UploadModeAtomic
  278. fs := vfs.NewOsFs("123", os.TempDir(), nil)
  279. u := dataprovider.User{}
  280. c := Connection{
  281. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, u, fs),
  282. }
  283. var flags sftp.FileOpenFlags
  284. flags.Write = true
  285. flags.Trunc = true
  286. _, err := c.handleSFTPUploadToExistingFile(flags, "missing_path", "other_missing_path", 0, "/missing_path", nil)
  287. assert.Error(t, err, "upload to existing file must fail if one or both paths are invalid")
  288. common.Config.UploadMode = common.UploadModeStandard
  289. _, err = c.handleSFTPUploadToExistingFile(flags, "missing_path", "other_missing_path", 0, "/missing_path", nil)
  290. assert.Error(t, err, "upload to existing file must fail if one or both paths are invalid")
  291. missingFile := "missing/relative/file.txt"
  292. if runtime.GOOS == osWindows {
  293. missingFile = "missing\\relative\\file.txt"
  294. }
  295. _, err = c.handleSFTPUploadToNewFile(".", missingFile, "/missing", nil)
  296. assert.Error(t, err, "upload new file in missing path must fail")
  297. c.BaseConnection.Fs = newMockOsFs(nil, nil, false, "123", os.TempDir())
  298. f, err := ioutil.TempFile("", "temp")
  299. assert.NoError(t, err)
  300. err = f.Close()
  301. assert.NoError(t, err)
  302. tr, err := c.handleSFTPUploadToExistingFile(flags, f.Name(), f.Name(), 123, f.Name(), nil)
  303. if assert.NoError(t, err) {
  304. transfer := tr.(*transfer)
  305. transfers := c.GetTransfers()
  306. if assert.Equal(t, 1, len(transfers)) {
  307. assert.Equal(t, transfers[0].ID, transfer.GetID())
  308. assert.Equal(t, int64(123), transfer.InitialSize)
  309. err = transfer.Close()
  310. assert.NoError(t, err)
  311. assert.Equal(t, 0, len(c.GetTransfers()))
  312. }
  313. }
  314. err = os.Remove(f.Name())
  315. assert.NoError(t, err)
  316. common.Config.UploadMode = oldUploadMode
  317. }
  318. func TestWithInvalidHome(t *testing.T) {
  319. u := dataprovider.User{}
  320. u.HomeDir = "home_rel_path" //nolint:goconst
  321. _, err := loginUser(u, dataprovider.LoginMethodPassword, "", nil)
  322. assert.Error(t, err, "login a user with an invalid home_dir must fail")
  323. u.HomeDir = os.TempDir()
  324. fs, err := u.GetFilesystem("123")
  325. assert.NoError(t, err)
  326. c := Connection{
  327. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, u, fs),
  328. }
  329. _, err = c.Fs.ResolvePath("../upper_path")
  330. assert.Error(t, err, "tested path is not a home subdir")
  331. }
  332. func TestSFTPCmdTargetPath(t *testing.T) {
  333. u := dataprovider.User{}
  334. if runtime.GOOS == osWindows {
  335. u.HomeDir = "C:\\invalid_home"
  336. } else {
  337. u.HomeDir = "/invalid_home"
  338. }
  339. u.Username = "testuser"
  340. u.Permissions = make(map[string][]string)
  341. u.Permissions["/"] = []string{dataprovider.PermAny}
  342. fs, err := u.GetFilesystem("123")
  343. assert.NoError(t, err)
  344. connection := Connection{
  345. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, u, fs),
  346. }
  347. _, err = connection.getSFTPCmdTargetPath("invalid_path")
  348. assert.True(t, os.IsNotExist(err))
  349. }
  350. func TestSFTPGetUsedQuota(t *testing.T) {
  351. u := dataprovider.User{}
  352. u.HomeDir = "home_rel_path"
  353. u.Username = "test_invalid_user"
  354. u.QuotaSize = 4096
  355. u.QuotaFiles = 1
  356. u.Permissions = make(map[string][]string)
  357. u.Permissions["/"] = []string{dataprovider.PermAny}
  358. connection := Connection{
  359. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, u, nil),
  360. }
  361. quotaResult := connection.HasSpace(false, "/")
  362. assert.False(t, quotaResult.HasSpace)
  363. }
  364. func TestSupportedSSHCommands(t *testing.T) {
  365. cmds := GetSupportedSSHCommands()
  366. assert.Equal(t, len(supportedSSHCommands), len(cmds))
  367. for _, c := range cmds {
  368. assert.True(t, utils.IsStringInSlice(c, supportedSSHCommands))
  369. }
  370. }
  371. func TestSSHCommandPath(t *testing.T) {
  372. buf := make([]byte, 65535)
  373. stdErrBuf := make([]byte, 65535)
  374. mockSSHChannel := MockChannel{
  375. Buffer: bytes.NewBuffer(buf),
  376. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  377. ReadError: nil,
  378. }
  379. connection := &Connection{
  380. channel: &mockSSHChannel,
  381. }
  382. sshCommand := sshCommand{
  383. command: "test",
  384. connection: connection,
  385. args: []string{},
  386. }
  387. assert.Equal(t, "", sshCommand.getDestPath())
  388. sshCommand.args = []string{"-t", "/tmp/../path"}
  389. assert.Equal(t, "/path", sshCommand.getDestPath())
  390. sshCommand.args = []string{"-t", "/tmp/"}
  391. assert.Equal(t, "/tmp/", sshCommand.getDestPath())
  392. sshCommand.args = []string{"-t", "tmp/"}
  393. assert.Equal(t, "/tmp/", sshCommand.getDestPath())
  394. sshCommand.args = []string{"-t", "/tmp/../../../path"}
  395. assert.Equal(t, "/path", sshCommand.getDestPath())
  396. sshCommand.args = []string{"-t", ".."}
  397. assert.Equal(t, "/", sshCommand.getDestPath())
  398. sshCommand.args = []string{"-t", "."}
  399. assert.Equal(t, "/", sshCommand.getDestPath())
  400. sshCommand.args = []string{"-t", "//"}
  401. assert.Equal(t, "/", sshCommand.getDestPath())
  402. sshCommand.args = []string{"-t", "../.."}
  403. assert.Equal(t, "/", sshCommand.getDestPath())
  404. sshCommand.args = []string{"-t", "/.."}
  405. assert.Equal(t, "/", sshCommand.getDestPath())
  406. sshCommand.args = []string{"-f", "/a space.txt"}
  407. assert.Equal(t, "/a space.txt", sshCommand.getDestPath())
  408. }
  409. func TestSSHParseCommandPayload(t *testing.T) {
  410. cmd := "command -a -f /ab\\ à/some\\ spaces\\ \\ \\(\\).txt"
  411. name, args, _ := parseCommandPayload(cmd)
  412. assert.Equal(t, "command", name)
  413. assert.Equal(t, 3, len(args))
  414. assert.Equal(t, "/ab à/some spaces ().txt", args[2])
  415. _, _, err := parseCommandPayload("")
  416. assert.Error(t, err, "parsing invalid command must fail")
  417. }
  418. func TestSSHCommandErrors(t *testing.T) {
  419. buf := make([]byte, 65535)
  420. stdErrBuf := make([]byte, 65535)
  421. readErr := fmt.Errorf("test read error")
  422. mockSSHChannel := MockChannel{
  423. Buffer: bytes.NewBuffer(buf),
  424. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  425. ReadError: readErr,
  426. }
  427. server, client := net.Pipe()
  428. defer func() {
  429. err := server.Close()
  430. assert.NoError(t, err)
  431. }()
  432. defer func() {
  433. err := client.Close()
  434. assert.NoError(t, err)
  435. }()
  436. user := dataprovider.User{}
  437. user.Permissions = make(map[string][]string)
  438. user.Permissions["/"] = []string{dataprovider.PermAny}
  439. fs, err := user.GetFilesystem("123")
  440. assert.NoError(t, err)
  441. connection := Connection{
  442. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, user, fs),
  443. channel: &mockSSHChannel,
  444. }
  445. cmd := sshCommand{
  446. command: "md5sum",
  447. connection: &connection,
  448. args: []string{},
  449. }
  450. err = cmd.handle()
  451. assert.Error(t, err, "ssh command must fail, we are sending a fake error")
  452. cmd = sshCommand{
  453. command: "md5sum",
  454. connection: &connection,
  455. args: []string{"/../../test_file_ftp.dat"},
  456. }
  457. err = cmd.handle()
  458. assert.Error(t, err, "ssh command must fail, we are requesting an invalid path")
  459. cmd = sshCommand{
  460. command: "git-receive-pack",
  461. connection: &connection,
  462. args: []string{"/../../testrepo"},
  463. }
  464. err = cmd.handle()
  465. assert.Error(t, err, "ssh command must fail, we are requesting an invalid path")
  466. cmd.connection.User.HomeDir = filepath.Clean(os.TempDir())
  467. cmd.connection.User.QuotaFiles = 1
  468. cmd.connection.User.UsedQuotaFiles = 2
  469. fs, err = cmd.connection.User.GetFilesystem("123")
  470. assert.NoError(t, err)
  471. cmd.connection.Fs = fs
  472. err = cmd.handle()
  473. assert.EqualError(t, err, common.ErrQuotaExceeded.Error())
  474. cmd.connection.User.QuotaFiles = 0
  475. cmd.connection.User.UsedQuotaFiles = 0
  476. cmd.connection.User.Permissions = make(map[string][]string)
  477. cmd.connection.User.Permissions["/"] = []string{dataprovider.PermListItems}
  478. err = cmd.handle()
  479. assert.EqualError(t, err, common.ErrPermissionDenied.Error())
  480. cmd.connection.User.Permissions["/"] = []string{dataprovider.PermAny}
  481. cmd.command = "invalid_command"
  482. command, err := cmd.getSystemCommand()
  483. assert.NoError(t, err)
  484. err = cmd.executeSystemCommand(command)
  485. assert.Error(t, err, "invalid command must fail")
  486. command, err = cmd.getSystemCommand()
  487. assert.NoError(t, err)
  488. _, err = command.cmd.StderrPipe()
  489. assert.NoError(t, err)
  490. err = cmd.executeSystemCommand(command)
  491. assert.Error(t, err, "command must fail, pipe was already assigned")
  492. err = cmd.executeSystemCommand(command)
  493. assert.Error(t, err, "command must fail, pipe was already assigned")
  494. command, err = cmd.getSystemCommand()
  495. assert.NoError(t, err)
  496. _, err = command.cmd.StdoutPipe()
  497. assert.NoError(t, err)
  498. err = cmd.executeSystemCommand(command)
  499. assert.Error(t, err, "command must fail, pipe was already assigned")
  500. fs, err = user.GetFilesystem("123")
  501. assert.NoError(t, err)
  502. connection.Fs = fs
  503. cmd = sshCommand{
  504. command: "sftpgo-remove",
  505. connection: &connection,
  506. args: []string{"/../../src"},
  507. }
  508. err = cmd.handle()
  509. assert.Error(t, err, "ssh command must fail, we are requesting an invalid path")
  510. cmd = sshCommand{
  511. command: "sftpgo-copy",
  512. connection: &connection,
  513. args: []string{"/../../test_src", "."},
  514. }
  515. err = cmd.handle()
  516. assert.Error(t, err, "ssh command must fail, we are requesting an invalid path")
  517. cmd.connection.User.HomeDir = filepath.Clean(os.TempDir())
  518. fs, err = cmd.connection.User.GetFilesystem("123")
  519. assert.NoError(t, err)
  520. cmd.connection.Fs = fs
  521. _, _, err = cmd.resolveCopyPaths(".", "../adir")
  522. assert.Error(t, err)
  523. cmd = sshCommand{
  524. command: "sftpgo-copy",
  525. connection: &connection,
  526. args: []string{"src", "dst"},
  527. }
  528. cmd.connection.User.Permissions = make(map[string][]string)
  529. cmd.connection.User.Permissions["/"] = []string{dataprovider.PermDownload}
  530. src, dst, err := cmd.getCopyPaths()
  531. assert.NoError(t, err)
  532. assert.False(t, cmd.hasCopyPermissions(src, dst, nil))
  533. cmd.connection.User.Permissions = make(map[string][]string)
  534. cmd.connection.User.Permissions["/"] = []string{dataprovider.PermAny}
  535. if runtime.GOOS != osWindows {
  536. aDir := filepath.Join(os.TempDir(), "adir")
  537. err = os.MkdirAll(aDir, os.ModePerm)
  538. assert.NoError(t, err)
  539. tmpFile := filepath.Join(aDir, "testcopy")
  540. err = ioutil.WriteFile(tmpFile, []byte("aaa"), os.ModePerm)
  541. assert.NoError(t, err)
  542. err = os.Chmod(aDir, 0001)
  543. assert.NoError(t, err)
  544. err = cmd.checkCopyDestination(tmpFile)
  545. assert.Error(t, err)
  546. err = os.Chmod(aDir, os.ModePerm)
  547. assert.NoError(t, err)
  548. err = os.Remove(tmpFile)
  549. assert.NoError(t, err)
  550. }
  551. }
  552. func TestCommandsWithExtensionsFilter(t *testing.T) {
  553. buf := make([]byte, 65535)
  554. stdErrBuf := make([]byte, 65535)
  555. mockSSHChannel := MockChannel{
  556. Buffer: bytes.NewBuffer(buf),
  557. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  558. }
  559. server, client := net.Pipe()
  560. defer server.Close()
  561. defer client.Close()
  562. user := dataprovider.User{
  563. Username: "test",
  564. HomeDir: os.TempDir(),
  565. Status: 1,
  566. }
  567. user.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
  568. {
  569. Path: "/subdir",
  570. AllowedExtensions: []string{".jpg"},
  571. DeniedExtensions: []string{},
  572. },
  573. }
  574. fs, err := user.GetFilesystem("123")
  575. assert.NoError(t, err)
  576. connection := &Connection{
  577. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, user, fs),
  578. channel: &mockSSHChannel,
  579. }
  580. cmd := sshCommand{
  581. command: "md5sum",
  582. connection: connection,
  583. args: []string{"subdir/test.png"},
  584. }
  585. err = cmd.handleHashCommands()
  586. assert.EqualError(t, err, common.ErrPermissionDenied.Error())
  587. cmd = sshCommand{
  588. command: "rsync",
  589. connection: connection,
  590. args: []string{"--server", "-vlogDtprze.iLsfxC", ".", "/"},
  591. }
  592. _, err = cmd.getSystemCommand()
  593. assert.EqualError(t, err, errUnsupportedConfig.Error())
  594. cmd = sshCommand{
  595. command: "git-receive-pack",
  596. connection: connection,
  597. args: []string{"/subdir"},
  598. }
  599. _, err = cmd.getSystemCommand()
  600. assert.EqualError(t, err, errUnsupportedConfig.Error())
  601. cmd = sshCommand{
  602. command: "git-receive-pack",
  603. connection: connection,
  604. args: []string{"/subdir/dir"},
  605. }
  606. _, err = cmd.getSystemCommand()
  607. assert.EqualError(t, err, errUnsupportedConfig.Error())
  608. cmd = sshCommand{
  609. command: "git-receive-pack",
  610. connection: connection,
  611. args: []string{"/adir/subdir"},
  612. }
  613. _, err = cmd.getSystemCommand()
  614. assert.NoError(t, err)
  615. }
  616. func TestSSHCommandsRemoteFs(t *testing.T) {
  617. buf := make([]byte, 65535)
  618. stdErrBuf := make([]byte, 65535)
  619. mockSSHChannel := MockChannel{
  620. Buffer: bytes.NewBuffer(buf),
  621. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  622. }
  623. server, client := net.Pipe()
  624. defer func() {
  625. err := server.Close()
  626. assert.NoError(t, err)
  627. }()
  628. defer func() {
  629. err := client.Close()
  630. assert.NoError(t, err)
  631. }()
  632. user := dataprovider.User{}
  633. user.FsConfig = dataprovider.Filesystem{
  634. Provider: dataprovider.S3FilesystemProvider,
  635. S3Config: vfs.S3FsConfig{
  636. Bucket: "s3bucket",
  637. Endpoint: "endpoint",
  638. Region: "eu-west-1",
  639. },
  640. }
  641. fs, err := user.GetFilesystem("123")
  642. assert.NoError(t, err)
  643. connection := &Connection{
  644. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, user, fs),
  645. channel: &mockSSHChannel,
  646. }
  647. cmd := sshCommand{
  648. command: "md5sum",
  649. connection: connection,
  650. args: []string{},
  651. }
  652. err = cmd.handleHashCommands()
  653. assert.Error(t, err, "command must fail for a non local filesystem")
  654. command, err := cmd.getSystemCommand()
  655. assert.NoError(t, err)
  656. err = cmd.executeSystemCommand(command)
  657. assert.Error(t, err, "command must fail for a non local filesystem")
  658. cmd = sshCommand{
  659. command: "sftpgo-copy",
  660. connection: connection,
  661. args: []string{},
  662. }
  663. err = cmd.handeSFTPGoCopy()
  664. assert.Error(t, err)
  665. cmd = sshCommand{
  666. command: "sftpgo-remove",
  667. connection: connection,
  668. args: []string{},
  669. }
  670. err = cmd.handeSFTPGoRemove()
  671. assert.Error(t, err)
  672. }
  673. func TestGitVirtualFolders(t *testing.T) {
  674. permissions := make(map[string][]string)
  675. permissions["/"] = []string{dataprovider.PermAny}
  676. user := dataprovider.User{
  677. Permissions: permissions,
  678. HomeDir: os.TempDir(),
  679. }
  680. fs, err := user.GetFilesystem("123")
  681. assert.NoError(t, err)
  682. conn := &Connection{
  683. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, user, fs),
  684. }
  685. cmd := sshCommand{
  686. command: "git-receive-pack",
  687. connection: conn,
  688. args: []string{"/vdir"},
  689. }
  690. cmd.connection.User.VirtualFolders = append(cmd.connection.User.VirtualFolders, vfs.VirtualFolder{
  691. BaseVirtualFolder: vfs.BaseVirtualFolder{
  692. MappedPath: os.TempDir(),
  693. },
  694. VirtualPath: "/vdir",
  695. })
  696. _, err = cmd.getSystemCommand()
  697. assert.NoError(t, err)
  698. cmd.args = []string{"/"}
  699. _, err = cmd.getSystemCommand()
  700. assert.EqualError(t, err, errUnsupportedConfig.Error())
  701. cmd.args = []string{"/vdir1"}
  702. _, err = cmd.getSystemCommand()
  703. assert.NoError(t, err)
  704. cmd.connection.User.VirtualFolders = nil
  705. cmd.connection.User.VirtualFolders = append(cmd.connection.User.VirtualFolders, vfs.VirtualFolder{
  706. BaseVirtualFolder: vfs.BaseVirtualFolder{
  707. MappedPath: os.TempDir(),
  708. },
  709. VirtualPath: "/vdir",
  710. })
  711. cmd.args = []string{"/vdir/subdir"}
  712. _, err = cmd.getSystemCommand()
  713. assert.NoError(t, err)
  714. cmd.args = []string{"/adir/subdir"}
  715. _, err = cmd.getSystemCommand()
  716. assert.NoError(t, err)
  717. }
  718. func TestRsyncOptions(t *testing.T) {
  719. permissions := make(map[string][]string)
  720. permissions["/"] = []string{dataprovider.PermAny}
  721. user := dataprovider.User{
  722. Permissions: permissions,
  723. HomeDir: os.TempDir(),
  724. }
  725. fs, err := user.GetFilesystem("123")
  726. assert.NoError(t, err)
  727. conn := &Connection{
  728. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, user, fs),
  729. }
  730. sshCmd := sshCommand{
  731. command: "rsync",
  732. connection: conn,
  733. args: []string{"--server", "-vlogDtprze.iLsfxC", ".", "/"},
  734. }
  735. cmd, err := sshCmd.getSystemCommand()
  736. assert.NoError(t, err)
  737. assert.True(t, utils.IsStringInSlice("--safe-links", cmd.cmd.Args),
  738. "--safe-links must be added if the user has the create symlinks permission")
  739. permissions["/"] = []string{dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermCreateDirs,
  740. dataprovider.PermListItems, dataprovider.PermOverwrite, dataprovider.PermDelete, dataprovider.PermRename}
  741. user.Permissions = permissions
  742. fs, err = user.GetFilesystem("123")
  743. assert.NoError(t, err)
  744. conn = &Connection{
  745. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, user, fs),
  746. }
  747. sshCmd = sshCommand{
  748. command: "rsync",
  749. connection: conn,
  750. args: []string{"--server", "-vlogDtprze.iLsfxC", ".", "/"},
  751. }
  752. cmd, err = sshCmd.getSystemCommand()
  753. assert.NoError(t, err)
  754. assert.True(t, utils.IsStringInSlice("--munge-links", cmd.cmd.Args),
  755. "--munge-links must be added if the user has the create symlinks permission")
  756. sshCmd.connection.User.VirtualFolders = append(sshCmd.connection.User.VirtualFolders, vfs.VirtualFolder{
  757. BaseVirtualFolder: vfs.BaseVirtualFolder{
  758. MappedPath: os.TempDir(),
  759. },
  760. VirtualPath: "/vdir",
  761. })
  762. _, err = sshCmd.getSystemCommand()
  763. assert.EqualError(t, err, errUnsupportedConfig.Error())
  764. }
  765. func TestSystemCommandSizeForPath(t *testing.T) {
  766. permissions := make(map[string][]string)
  767. permissions["/"] = []string{dataprovider.PermAny}
  768. user := dataprovider.User{
  769. Permissions: permissions,
  770. HomeDir: os.TempDir(),
  771. }
  772. fs, err := user.GetFilesystem("123")
  773. assert.NoError(t, err)
  774. conn := &Connection{
  775. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, user, fs),
  776. }
  777. sshCmd := sshCommand{
  778. command: "rsync",
  779. connection: conn,
  780. args: []string{"--server", "-vlogDtprze.iLsfxC", ".", "/"},
  781. }
  782. _, _, err = sshCmd.getSizeForPath("missing path")
  783. assert.NoError(t, err)
  784. testDir := filepath.Join(os.TempDir(), "dir")
  785. err = os.MkdirAll(testDir, os.ModePerm)
  786. assert.NoError(t, err)
  787. testFile := filepath.Join(testDir, "testfile")
  788. err = ioutil.WriteFile(testFile, []byte("test content"), os.ModePerm)
  789. assert.NoError(t, err)
  790. err = os.Symlink(testFile, testFile+".link")
  791. assert.NoError(t, err)
  792. numFiles, size, err := sshCmd.getSizeForPath(testFile + ".link")
  793. assert.NoError(t, err)
  794. assert.Equal(t, 0, numFiles)
  795. assert.Equal(t, int64(0), size)
  796. numFiles, size, err = sshCmd.getSizeForPath(testFile)
  797. assert.NoError(t, err)
  798. assert.Equal(t, 1, numFiles)
  799. assert.Equal(t, int64(12), size)
  800. if runtime.GOOS != osWindows {
  801. err = os.Chmod(testDir, 0001)
  802. assert.NoError(t, err)
  803. _, _, err = sshCmd.getSizeForPath(testFile)
  804. assert.Error(t, err)
  805. err = os.Chmod(testDir, os.ModePerm)
  806. assert.NoError(t, err)
  807. }
  808. err = os.RemoveAll(testDir)
  809. assert.NoError(t, err)
  810. }
  811. func TestSystemCommandErrors(t *testing.T) {
  812. buf := make([]byte, 65535)
  813. stdErrBuf := make([]byte, 65535)
  814. readErr := fmt.Errorf("test read error")
  815. writeErr := fmt.Errorf("test write error")
  816. mockSSHChannel := MockChannel{
  817. Buffer: bytes.NewBuffer(buf),
  818. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  819. ReadError: nil,
  820. WriteError: writeErr,
  821. }
  822. server, client := net.Pipe()
  823. defer func() {
  824. err := server.Close()
  825. assert.NoError(t, err)
  826. }()
  827. defer func() {
  828. err := client.Close()
  829. assert.NoError(t, err)
  830. }()
  831. permissions := make(map[string][]string)
  832. permissions["/"] = []string{dataprovider.PermAny}
  833. homeDir := filepath.Join(os.TempDir(), "adir")
  834. err := os.MkdirAll(homeDir, os.ModePerm)
  835. assert.NoError(t, err)
  836. err = ioutil.WriteFile(filepath.Join(homeDir, "afile"), []byte("content"), os.ModePerm)
  837. assert.NoError(t, err)
  838. user := dataprovider.User{
  839. Permissions: permissions,
  840. HomeDir: homeDir,
  841. }
  842. fs, err := user.GetFilesystem("123")
  843. assert.NoError(t, err)
  844. connection := &Connection{
  845. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, user, fs),
  846. channel: &mockSSHChannel,
  847. }
  848. var sshCmd sshCommand
  849. if runtime.GOOS == osWindows {
  850. sshCmd = sshCommand{
  851. command: "dir",
  852. connection: connection,
  853. args: []string{"/"},
  854. }
  855. } else {
  856. sshCmd = sshCommand{
  857. command: "ls",
  858. connection: connection,
  859. args: []string{"/"},
  860. }
  861. }
  862. systemCmd, err := sshCmd.getSystemCommand()
  863. assert.NoError(t, err)
  864. systemCmd.cmd.Dir = os.TempDir()
  865. // FIXME: the command completes but the fake client is unable to read the response
  866. // no error is reported in this case. We can see that the expected code is executed
  867. // reading the test coverage
  868. sshCmd.executeSystemCommand(systemCmd) //nolint:errcheck
  869. mockSSHChannel = MockChannel{
  870. Buffer: bytes.NewBuffer(buf),
  871. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  872. ReadError: readErr,
  873. WriteError: nil,
  874. }
  875. sshCmd.connection.channel = &mockSSHChannel
  876. baseTransfer := common.NewBaseTransfer(nil, sshCmd.connection.BaseConnection, nil, "", "", common.TransferDownload,
  877. 0, 0, 0, false, fs)
  878. transfer := newTransfer(baseTransfer, nil, nil, nil)
  879. destBuff := make([]byte, 65535)
  880. dst := bytes.NewBuffer(destBuff)
  881. _, err = transfer.copyFromReaderToWriter(dst, sshCmd.connection.channel)
  882. assert.EqualError(t, err, readErr.Error())
  883. mockSSHChannel = MockChannel{
  884. Buffer: bytes.NewBuffer(buf),
  885. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  886. ReadError: nil,
  887. WriteError: nil,
  888. }
  889. sshCmd.connection.channel = &mockSSHChannel
  890. transfer.MaxWriteSize = 1
  891. _, err = transfer.copyFromReaderToWriter(dst, sshCmd.connection.channel)
  892. assert.EqualError(t, err, common.ErrQuotaExceeded.Error())
  893. mockSSHChannel = MockChannel{
  894. Buffer: bytes.NewBuffer(buf),
  895. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  896. ReadError: nil,
  897. WriteError: nil,
  898. ShortWriteErr: true,
  899. }
  900. sshCmd.connection.channel = &mockSSHChannel
  901. _, err = transfer.copyFromReaderToWriter(sshCmd.connection.channel, dst)
  902. assert.EqualError(t, err, io.ErrShortWrite.Error())
  903. transfer.MaxWriteSize = -1
  904. _, err = transfer.copyFromReaderToWriter(sshCmd.connection.channel, dst)
  905. assert.EqualError(t, err, common.ErrQuotaExceeded.Error())
  906. err = os.RemoveAll(homeDir)
  907. assert.NoError(t, err)
  908. }
  909. func TestGetConnectionInfo(t *testing.T) {
  910. c := common.ConnectionStatus{
  911. Username: "test_user",
  912. ConnectionID: "123",
  913. ClientVersion: "client",
  914. RemoteAddress: "127.0.0.1:1234",
  915. Protocol: common.ProtocolSSH,
  916. Command: "sha1sum /test_file_ftp.dat",
  917. }
  918. info := c.GetConnectionInfo()
  919. assert.Contains(t, info, "sha1sum /test_file_ftp.dat")
  920. }
  921. func TestSCPFileMode(t *testing.T) {
  922. mode := getFileModeAsString(0, true)
  923. assert.Equal(t, "0755", mode)
  924. mode = getFileModeAsString(0700, true)
  925. assert.Equal(t, "0700", mode)
  926. mode = getFileModeAsString(0750, true)
  927. assert.Equal(t, "0750", mode)
  928. mode = getFileModeAsString(0777, true)
  929. assert.Equal(t, "0777", mode)
  930. mode = getFileModeAsString(0640, false)
  931. assert.Equal(t, "0640", mode)
  932. mode = getFileModeAsString(0600, false)
  933. assert.Equal(t, "0600", mode)
  934. mode = getFileModeAsString(0, false)
  935. assert.Equal(t, "0644", mode)
  936. fileMode := uint32(0777)
  937. fileMode = fileMode | uint32(os.ModeSetgid)
  938. fileMode = fileMode | uint32(os.ModeSetuid)
  939. fileMode = fileMode | uint32(os.ModeSticky)
  940. mode = getFileModeAsString(os.FileMode(fileMode), false)
  941. assert.Equal(t, "7777", mode)
  942. fileMode = uint32(0644)
  943. fileMode = fileMode | uint32(os.ModeSetgid)
  944. mode = getFileModeAsString(os.FileMode(fileMode), false)
  945. assert.Equal(t, "4644", mode)
  946. fileMode = uint32(0600)
  947. fileMode = fileMode | uint32(os.ModeSetuid)
  948. mode = getFileModeAsString(os.FileMode(fileMode), false)
  949. assert.Equal(t, "2600", mode)
  950. fileMode = uint32(0044)
  951. fileMode = fileMode | uint32(os.ModeSticky)
  952. mode = getFileModeAsString(os.FileMode(fileMode), false)
  953. assert.Equal(t, "1044", mode)
  954. }
  955. func TestSCPParseUploadMessage(t *testing.T) {
  956. buf := make([]byte, 65535)
  957. stdErrBuf := make([]byte, 65535)
  958. mockSSHChannel := MockChannel{
  959. Buffer: bytes.NewBuffer(buf),
  960. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  961. ReadError: nil,
  962. }
  963. fs := vfs.NewOsFs("", os.TempDir(), nil)
  964. connection := &Connection{
  965. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, dataprovider.User{}, fs),
  966. channel: &mockSSHChannel,
  967. }
  968. scpCommand := scpCommand{
  969. sshCommand: sshCommand{
  970. command: "scp",
  971. connection: connection,
  972. args: []string{"-t", "/tmp"},
  973. },
  974. }
  975. _, _, err := scpCommand.parseUploadMessage("invalid")
  976. assert.Error(t, err, "parsing invalid upload message must fail")
  977. _, _, err = scpCommand.parseUploadMessage("D0755 0")
  978. assert.Error(t, err, "parsing incomplete upload message must fail")
  979. _, _, err = scpCommand.parseUploadMessage("D0755 invalidsize testdir")
  980. assert.Error(t, err, "parsing upload message with invalid size must fail")
  981. _, _, err = scpCommand.parseUploadMessage("D0755 0 ")
  982. assert.Error(t, err, "parsing upload message with invalid name must fail")
  983. }
  984. func TestSCPProtocolMessages(t *testing.T) {
  985. buf := make([]byte, 65535)
  986. stdErrBuf := make([]byte, 65535)
  987. readErr := fmt.Errorf("test read error")
  988. writeErr := fmt.Errorf("test write error")
  989. mockSSHChannel := MockChannel{
  990. Buffer: bytes.NewBuffer(buf),
  991. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  992. ReadError: readErr,
  993. WriteError: writeErr,
  994. }
  995. connection := &Connection{
  996. BaseConnection: common.NewBaseConnection("", common.ProtocolSCP, dataprovider.User{}, nil),
  997. channel: &mockSSHChannel,
  998. }
  999. scpCommand := scpCommand{
  1000. sshCommand: sshCommand{
  1001. command: "scp",
  1002. connection: connection,
  1003. args: []string{"-t", "/tmp"},
  1004. },
  1005. }
  1006. _, err := scpCommand.readProtocolMessage()
  1007. assert.EqualError(t, err, readErr.Error())
  1008. err = scpCommand.sendConfirmationMessage()
  1009. assert.EqualError(t, err, writeErr.Error())
  1010. err = scpCommand.sendProtocolMessage("E\n")
  1011. assert.EqualError(t, err, writeErr.Error())
  1012. _, err = scpCommand.getNextUploadProtocolMessage()
  1013. assert.EqualError(t, err, readErr.Error())
  1014. mockSSHChannel = MockChannel{
  1015. Buffer: bytes.NewBuffer([]byte("T1183832947 0 1183833773 0\n")),
  1016. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1017. ReadError: nil,
  1018. WriteError: writeErr,
  1019. }
  1020. scpCommand.connection.channel = &mockSSHChannel
  1021. _, err = scpCommand.getNextUploadProtocolMessage()
  1022. assert.EqualError(t, err, writeErr.Error())
  1023. respBuffer := []byte{0x02}
  1024. protocolErrorMsg := "protocol error msg"
  1025. respBuffer = append(respBuffer, protocolErrorMsg...)
  1026. respBuffer = append(respBuffer, 0x0A)
  1027. mockSSHChannel = MockChannel{
  1028. Buffer: bytes.NewBuffer(respBuffer),
  1029. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1030. ReadError: nil,
  1031. WriteError: nil,
  1032. }
  1033. scpCommand.connection.channel = &mockSSHChannel
  1034. err = scpCommand.readConfirmationMessage()
  1035. if assert.Error(t, err) {
  1036. assert.Equal(t, protocolErrorMsg, err.Error())
  1037. }
  1038. }
  1039. func TestSCPTestDownloadProtocolMessages(t *testing.T) {
  1040. buf := make([]byte, 65535)
  1041. stdErrBuf := make([]byte, 65535)
  1042. readErr := fmt.Errorf("test read error")
  1043. writeErr := fmt.Errorf("test write error")
  1044. mockSSHChannel := MockChannel{
  1045. Buffer: bytes.NewBuffer(buf),
  1046. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1047. ReadError: readErr,
  1048. WriteError: writeErr,
  1049. }
  1050. connection := &Connection{
  1051. BaseConnection: common.NewBaseConnection("", common.ProtocolSCP, dataprovider.User{}, nil),
  1052. channel: &mockSSHChannel,
  1053. }
  1054. scpCommand := scpCommand{
  1055. sshCommand: sshCommand{
  1056. command: "scp",
  1057. connection: connection,
  1058. args: []string{"-f", "-p", "/tmp"},
  1059. },
  1060. }
  1061. path := "testDir"
  1062. err := os.Mkdir(path, os.ModePerm)
  1063. assert.NoError(t, err)
  1064. stat, err := os.Stat(path)
  1065. assert.NoError(t, err)
  1066. err = scpCommand.sendDownloadProtocolMessages(path, stat)
  1067. assert.EqualError(t, err, writeErr.Error())
  1068. mockSSHChannel = MockChannel{
  1069. Buffer: bytes.NewBuffer(buf),
  1070. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1071. ReadError: readErr,
  1072. WriteError: nil,
  1073. }
  1074. err = scpCommand.sendDownloadProtocolMessages(path, stat)
  1075. assert.EqualError(t, err, readErr.Error())
  1076. mockSSHChannel = MockChannel{
  1077. Buffer: bytes.NewBuffer(buf),
  1078. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1079. ReadError: readErr,
  1080. WriteError: writeErr,
  1081. }
  1082. scpCommand.args = []string{"-f", "/tmp"}
  1083. scpCommand.connection.channel = &mockSSHChannel
  1084. err = scpCommand.sendDownloadProtocolMessages(path, stat)
  1085. assert.EqualError(t, err, writeErr.Error())
  1086. mockSSHChannel = MockChannel{
  1087. Buffer: bytes.NewBuffer(buf),
  1088. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1089. ReadError: readErr,
  1090. WriteError: nil,
  1091. }
  1092. scpCommand.connection.channel = &mockSSHChannel
  1093. err = scpCommand.sendDownloadProtocolMessages(path, stat)
  1094. assert.EqualError(t, err, readErr.Error())
  1095. err = os.Remove(path)
  1096. assert.NoError(t, err)
  1097. }
  1098. func TestSCPCommandHandleErrors(t *testing.T) {
  1099. buf := make([]byte, 65535)
  1100. stdErrBuf := make([]byte, 65535)
  1101. readErr := fmt.Errorf("test read error")
  1102. writeErr := fmt.Errorf("test write error")
  1103. mockSSHChannel := MockChannel{
  1104. Buffer: bytes.NewBuffer(buf),
  1105. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1106. ReadError: readErr,
  1107. WriteError: writeErr,
  1108. }
  1109. server, client := net.Pipe()
  1110. defer func() {
  1111. err := server.Close()
  1112. assert.NoError(t, err)
  1113. }()
  1114. defer func() {
  1115. err := client.Close()
  1116. assert.NoError(t, err)
  1117. }()
  1118. connection := &Connection{
  1119. BaseConnection: common.NewBaseConnection("", common.ProtocolSCP, dataprovider.User{}, nil),
  1120. channel: &mockSSHChannel,
  1121. }
  1122. scpCommand := scpCommand{
  1123. sshCommand: sshCommand{
  1124. command: "scp",
  1125. connection: connection,
  1126. args: []string{"-f", "/tmp"},
  1127. },
  1128. }
  1129. err := scpCommand.handle()
  1130. assert.EqualError(t, err, readErr.Error())
  1131. scpCommand.args = []string{"-i", "/tmp"}
  1132. err = scpCommand.handle()
  1133. assert.Error(t, err, "invalid scp command must fail")
  1134. }
  1135. func TestSCPErrorsMockFs(t *testing.T) {
  1136. errFake := errors.New("fake error")
  1137. fs := newMockOsFs(errFake, errFake, false, "1234", os.TempDir())
  1138. u := dataprovider.User{}
  1139. u.Username = "test"
  1140. u.Permissions = make(map[string][]string)
  1141. u.Permissions["/"] = []string{dataprovider.PermAny}
  1142. u.HomeDir = os.TempDir()
  1143. buf := make([]byte, 65535)
  1144. stdErrBuf := make([]byte, 65535)
  1145. mockSSHChannel := MockChannel{
  1146. Buffer: bytes.NewBuffer(buf),
  1147. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1148. }
  1149. server, client := net.Pipe()
  1150. defer func() {
  1151. err := server.Close()
  1152. assert.NoError(t, err)
  1153. }()
  1154. defer func() {
  1155. err := client.Close()
  1156. assert.NoError(t, err)
  1157. }()
  1158. connection := &Connection{
  1159. channel: &mockSSHChannel,
  1160. BaseConnection: common.NewBaseConnection("", common.ProtocolSCP, u, fs),
  1161. }
  1162. scpCommand := scpCommand{
  1163. sshCommand: sshCommand{
  1164. command: "scp",
  1165. connection: connection,
  1166. args: []string{"-r", "-t", "/tmp"},
  1167. },
  1168. }
  1169. err := scpCommand.handleUpload("test", 0)
  1170. assert.EqualError(t, err, errFake.Error())
  1171. testfile := filepath.Join(u.HomeDir, "testfile")
  1172. err = ioutil.WriteFile(testfile, []byte("test"), os.ModePerm)
  1173. assert.NoError(t, err)
  1174. stat, err := os.Stat(u.HomeDir)
  1175. assert.NoError(t, err)
  1176. err = scpCommand.handleRecursiveDownload(u.HomeDir, stat)
  1177. assert.EqualError(t, err, errFake.Error())
  1178. scpCommand.sshCommand.connection.Fs = newMockOsFs(errFake, nil, true, "123", os.TempDir())
  1179. err = scpCommand.handleUpload(filepath.Base(testfile), 0)
  1180. assert.EqualError(t, err, errFake.Error())
  1181. err = scpCommand.handleUploadFile(testfile, testfile, 0, false, 4, "/testfile")
  1182. assert.NoError(t, err)
  1183. err = os.Remove(testfile)
  1184. assert.NoError(t, err)
  1185. }
  1186. func TestSCPRecursiveDownloadErrors(t *testing.T) {
  1187. buf := make([]byte, 65535)
  1188. stdErrBuf := make([]byte, 65535)
  1189. readErr := fmt.Errorf("test read error")
  1190. writeErr := fmt.Errorf("test write error")
  1191. mockSSHChannel := MockChannel{
  1192. Buffer: bytes.NewBuffer(buf),
  1193. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1194. ReadError: readErr,
  1195. WriteError: writeErr,
  1196. }
  1197. server, client := net.Pipe()
  1198. defer func() {
  1199. err := server.Close()
  1200. assert.NoError(t, err)
  1201. }()
  1202. defer func() {
  1203. err := client.Close()
  1204. assert.NoError(t, err)
  1205. }()
  1206. fs := vfs.NewOsFs("123", os.TempDir(), nil)
  1207. connection := &Connection{
  1208. BaseConnection: common.NewBaseConnection("", common.ProtocolSCP, dataprovider.User{}, fs),
  1209. channel: &mockSSHChannel,
  1210. }
  1211. scpCommand := scpCommand{
  1212. sshCommand: sshCommand{
  1213. command: "scp",
  1214. connection: connection,
  1215. args: []string{"-r", "-f", "/tmp"},
  1216. },
  1217. }
  1218. path := "testDir"
  1219. err := os.Mkdir(path, os.ModePerm)
  1220. assert.NoError(t, err)
  1221. stat, err := os.Stat(path)
  1222. assert.NoError(t, err)
  1223. err = scpCommand.handleRecursiveDownload("invalid_dir", stat)
  1224. assert.EqualError(t, err, writeErr.Error())
  1225. mockSSHChannel = MockChannel{
  1226. Buffer: bytes.NewBuffer(buf),
  1227. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1228. ReadError: nil,
  1229. WriteError: nil,
  1230. }
  1231. scpCommand.connection.channel = &mockSSHChannel
  1232. err = scpCommand.handleRecursiveDownload("invalid_dir", stat)
  1233. assert.Error(t, err, "recursive upload download must fail for a non existing dir")
  1234. err = os.Remove(path)
  1235. assert.NoError(t, err)
  1236. }
  1237. func TestSCPRecursiveUploadErrors(t *testing.T) {
  1238. buf := make([]byte, 65535)
  1239. stdErrBuf := make([]byte, 65535)
  1240. readErr := fmt.Errorf("test read error")
  1241. writeErr := fmt.Errorf("test write error")
  1242. mockSSHChannel := MockChannel{
  1243. Buffer: bytes.NewBuffer(buf),
  1244. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1245. ReadError: readErr,
  1246. WriteError: writeErr,
  1247. }
  1248. connection := &Connection{
  1249. BaseConnection: common.NewBaseConnection("", common.ProtocolSCP, dataprovider.User{}, nil),
  1250. channel: &mockSSHChannel,
  1251. }
  1252. scpCommand := scpCommand{
  1253. sshCommand: sshCommand{
  1254. command: "scp",
  1255. connection: connection,
  1256. args: []string{"-r", "-t", "/tmp"},
  1257. },
  1258. }
  1259. err := scpCommand.handleRecursiveUpload()
  1260. assert.Error(t, err, "recursive upload must fail, we send a fake error message")
  1261. mockSSHChannel = MockChannel{
  1262. Buffer: bytes.NewBuffer(buf),
  1263. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1264. ReadError: readErr,
  1265. WriteError: nil,
  1266. }
  1267. scpCommand.connection.channel = &mockSSHChannel
  1268. err = scpCommand.handleRecursiveUpload()
  1269. assert.Error(t, err, "recursive upload must fail, we send a fake error message")
  1270. }
  1271. func TestSCPCreateDirs(t *testing.T) {
  1272. buf := make([]byte, 65535)
  1273. stdErrBuf := make([]byte, 65535)
  1274. u := dataprovider.User{}
  1275. u.HomeDir = "home_rel_path"
  1276. u.Username = "test"
  1277. u.Permissions = make(map[string][]string)
  1278. u.Permissions["/"] = []string{dataprovider.PermAny}
  1279. mockSSHChannel := MockChannel{
  1280. Buffer: bytes.NewBuffer(buf),
  1281. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1282. ReadError: nil,
  1283. WriteError: nil,
  1284. }
  1285. fs, err := u.GetFilesystem("123")
  1286. assert.NoError(t, err)
  1287. connection := &Connection{
  1288. BaseConnection: common.NewBaseConnection("", common.ProtocolSCP, u, fs),
  1289. channel: &mockSSHChannel,
  1290. }
  1291. scpCommand := scpCommand{
  1292. sshCommand: sshCommand{
  1293. command: "scp",
  1294. connection: connection,
  1295. args: []string{"-r", "-t", "/tmp"},
  1296. },
  1297. }
  1298. err = scpCommand.handleCreateDir("invalid_dir")
  1299. assert.Error(t, err, "create invalid dir must fail")
  1300. }
  1301. func TestSCPDownloadFileData(t *testing.T) {
  1302. testfile := "testfile"
  1303. buf := make([]byte, 65535)
  1304. readErr := fmt.Errorf("test read error")
  1305. writeErr := fmt.Errorf("test write error")
  1306. stdErrBuf := make([]byte, 65535)
  1307. mockSSHChannelReadErr := MockChannel{
  1308. Buffer: bytes.NewBuffer(buf),
  1309. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1310. ReadError: readErr,
  1311. WriteError: nil,
  1312. }
  1313. mockSSHChannelWriteErr := MockChannel{
  1314. Buffer: bytes.NewBuffer(buf),
  1315. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1316. ReadError: nil,
  1317. WriteError: writeErr,
  1318. }
  1319. connection := &Connection{
  1320. BaseConnection: common.NewBaseConnection("", common.ProtocolSCP, dataprovider.User{},
  1321. vfs.NewOsFs("", os.TempDir(), nil)),
  1322. channel: &mockSSHChannelReadErr,
  1323. }
  1324. scpCommand := scpCommand{
  1325. sshCommand: sshCommand{
  1326. command: "scp",
  1327. connection: connection,
  1328. args: []string{"-r", "-f", "/tmp"},
  1329. },
  1330. }
  1331. err := ioutil.WriteFile(testfile, []byte("test"), os.ModePerm)
  1332. assert.NoError(t, err)
  1333. stat, err := os.Stat(testfile)
  1334. assert.NoError(t, err)
  1335. err = scpCommand.sendDownloadFileData(testfile, stat, nil)
  1336. assert.EqualError(t, err, readErr.Error())
  1337. scpCommand.connection.channel = &mockSSHChannelWriteErr
  1338. err = scpCommand.sendDownloadFileData(testfile, stat, nil)
  1339. assert.EqualError(t, err, writeErr.Error())
  1340. scpCommand.args = []string{"-r", "-p", "-f", "/tmp"}
  1341. err = scpCommand.sendDownloadFileData(testfile, stat, nil)
  1342. assert.EqualError(t, err, writeErr.Error())
  1343. scpCommand.connection.channel = &mockSSHChannelReadErr
  1344. err = scpCommand.sendDownloadFileData(testfile, stat, nil)
  1345. assert.EqualError(t, err, readErr.Error())
  1346. err = os.Remove(testfile)
  1347. assert.NoError(t, err)
  1348. }
  1349. func TestSCPUploadFiledata(t *testing.T) {
  1350. testfile := "testfile"
  1351. buf := make([]byte, 65535)
  1352. stdErrBuf := make([]byte, 65535)
  1353. readErr := fmt.Errorf("test read error")
  1354. writeErr := fmt.Errorf("test write error")
  1355. mockSSHChannel := MockChannel{
  1356. Buffer: bytes.NewBuffer(buf),
  1357. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1358. ReadError: readErr,
  1359. WriteError: writeErr,
  1360. }
  1361. user := dataprovider.User{
  1362. Username: "testuser",
  1363. }
  1364. fs := vfs.NewOsFs("", os.TempDir(), nil)
  1365. connection := &Connection{
  1366. BaseConnection: common.NewBaseConnection("", common.ProtocolSCP, user, fs),
  1367. channel: &mockSSHChannel,
  1368. }
  1369. scpCommand := scpCommand{
  1370. sshCommand: sshCommand{
  1371. command: "scp",
  1372. connection: connection,
  1373. args: []string{"-r", "-t", "/tmp"},
  1374. },
  1375. }
  1376. file, err := os.Create(testfile)
  1377. assert.NoError(t, err)
  1378. baseTransfer := common.NewBaseTransfer(file, scpCommand.connection.BaseConnection, nil, file.Name(),
  1379. "/"+testfile, common.TransferDownload, 0, 0, 0, true, fs)
  1380. transfer := newTransfer(baseTransfer, nil, nil, nil)
  1381. err = scpCommand.getUploadFileData(2, transfer)
  1382. assert.Error(t, err, "upload must fail, we send a fake write error message")
  1383. mockSSHChannel = MockChannel{
  1384. Buffer: bytes.NewBuffer(buf),
  1385. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1386. ReadError: readErr,
  1387. WriteError: nil,
  1388. }
  1389. scpCommand.connection.channel = &mockSSHChannel
  1390. file, err = os.Create(testfile)
  1391. assert.NoError(t, err)
  1392. transfer.File = file
  1393. transfer.isFinished = false
  1394. transfer.Connection.AddTransfer(transfer)
  1395. err = scpCommand.getUploadFileData(2, transfer)
  1396. assert.Error(t, err, "upload must fail, we send a fake read error message")
  1397. respBuffer := []byte("12")
  1398. respBuffer = append(respBuffer, 0x02)
  1399. mockSSHChannel = MockChannel{
  1400. Buffer: bytes.NewBuffer(respBuffer),
  1401. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1402. ReadError: nil,
  1403. WriteError: nil,
  1404. }
  1405. scpCommand.connection.channel = &mockSSHChannel
  1406. file, err = os.Create(testfile)
  1407. assert.NoError(t, err)
  1408. baseTransfer.File = file
  1409. transfer = newTransfer(baseTransfer, nil, nil, nil)
  1410. transfer.Connection.AddTransfer(transfer)
  1411. err = scpCommand.getUploadFileData(2, transfer)
  1412. assert.Error(t, err, "upload must fail, we have not enough data to read")
  1413. // the file is already closed so we have an error on trasfer closing
  1414. mockSSHChannel = MockChannel{
  1415. Buffer: bytes.NewBuffer(buf),
  1416. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1417. ReadError: nil,
  1418. WriteError: nil,
  1419. }
  1420. transfer.Connection.AddTransfer(transfer)
  1421. err = scpCommand.getUploadFileData(0, transfer)
  1422. if assert.Error(t, err) {
  1423. assert.EqualError(t, err, common.ErrTransferClosed.Error())
  1424. }
  1425. mockSSHChannel = MockChannel{
  1426. Buffer: bytes.NewBuffer(buf),
  1427. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1428. ReadError: nil,
  1429. WriteError: nil,
  1430. }
  1431. transfer.Connection.AddTransfer(transfer)
  1432. err = scpCommand.getUploadFileData(2, transfer)
  1433. assert.True(t, errors.Is(err, os.ErrClosed))
  1434. err = os.Remove(testfile)
  1435. assert.NoError(t, err)
  1436. }
  1437. func TestUploadError(t *testing.T) {
  1438. oldUploadMode := common.Config.UploadMode
  1439. common.Config.UploadMode = common.UploadModeAtomic
  1440. user := dataprovider.User{
  1441. Username: "testuser",
  1442. }
  1443. fs := vfs.NewOsFs("", os.TempDir(), nil)
  1444. connection := &Connection{
  1445. BaseConnection: common.NewBaseConnection("", common.ProtocolSCP, user, fs),
  1446. }
  1447. testfile := "testfile"
  1448. fileTempName := "temptestfile"
  1449. file, err := os.Create(fileTempName)
  1450. assert.NoError(t, err)
  1451. baseTransfer := common.NewBaseTransfer(file, connection.BaseConnection, nil, testfile,
  1452. testfile, common.TransferUpload, 0, 0, 0, true, fs)
  1453. transfer := newTransfer(baseTransfer, nil, nil, nil)
  1454. errFake := errors.New("fake error")
  1455. transfer.TransferError(errFake)
  1456. err = transfer.Close()
  1457. if assert.Error(t, err) {
  1458. assert.EqualError(t, err, common.ErrGenericFailure.Error())
  1459. }
  1460. if assert.Error(t, transfer.ErrTransfer) {
  1461. assert.EqualError(t, transfer.ErrTransfer, errFake.Error())
  1462. }
  1463. assert.Equal(t, int64(0), transfer.BytesReceived)
  1464. assert.NoFileExists(t, testfile)
  1465. assert.NoFileExists(t, fileTempName)
  1466. common.Config.UploadMode = oldUploadMode
  1467. }
  1468. func TestTransferFailingReader(t *testing.T) {
  1469. user := dataprovider.User{
  1470. Username: "testuser",
  1471. }
  1472. user.Permissions = make(map[string][]string)
  1473. user.Permissions["/"] = []string{dataprovider.PermAny}
  1474. fs := newMockOsFs(nil, nil, true, "", os.TempDir())
  1475. connection := &Connection{
  1476. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, user, fs),
  1477. }
  1478. request := sftp.NewRequest("Open", "afile.txt")
  1479. request.Flags = 27 // read,write,create,truncate
  1480. transfer, err := connection.handleFilewrite(request)
  1481. require.NoError(t, err)
  1482. buf := make([]byte, 32)
  1483. _, err = transfer.ReadAt(buf, 0)
  1484. assert.EqualError(t, err, sftp.ErrSSHFxOpUnsupported.Error())
  1485. if c, ok := transfer.(io.Closer); ok {
  1486. err = c.Close()
  1487. assert.NoError(t, err)
  1488. }
  1489. fsPath := filepath.Join(os.TempDir(), "afile.txt")
  1490. r, _, err := pipeat.Pipe()
  1491. assert.NoError(t, err)
  1492. baseTransfer := common.NewBaseTransfer(nil, connection.BaseConnection, nil, fsPath, filepath.Base(fsPath), common.TransferUpload, 0, 0, 0, false, fs)
  1493. errRead := errors.New("read is not allowed")
  1494. tr := newTransfer(baseTransfer, nil, r, errRead)
  1495. _, err = tr.ReadAt(buf, 0)
  1496. assert.EqualError(t, err, errRead.Error())
  1497. err = tr.Close()
  1498. assert.NoError(t, err)
  1499. tr = newTransfer(baseTransfer, nil, nil, errRead)
  1500. _, err = tr.ReadAt(buf, 0)
  1501. assert.EqualError(t, err, errRead.Error())
  1502. err = tr.Close()
  1503. assert.NoError(t, err)
  1504. err = os.Remove(fsPath)
  1505. assert.NoError(t, err)
  1506. assert.Len(t, connection.GetTransfers(), 0)
  1507. }
  1508. func TestConnectionStatusStruct(t *testing.T) {
  1509. var transfers []common.ConnectionTransfer
  1510. transferUL := common.ConnectionTransfer{
  1511. OperationType: "upload",
  1512. StartTime: utils.GetTimeAsMsSinceEpoch(time.Now()),
  1513. Size: 123,
  1514. VirtualPath: "/test.upload",
  1515. }
  1516. transferDL := common.ConnectionTransfer{
  1517. OperationType: "download",
  1518. StartTime: utils.GetTimeAsMsSinceEpoch(time.Now()),
  1519. Size: 123,
  1520. VirtualPath: "/test.download",
  1521. }
  1522. transfers = append(transfers, transferUL)
  1523. transfers = append(transfers, transferDL)
  1524. c := common.ConnectionStatus{
  1525. Username: "test",
  1526. ConnectionID: "123",
  1527. ClientVersion: "fakeClient-1.0.0",
  1528. RemoteAddress: "127.0.0.1:1234",
  1529. ConnectionTime: utils.GetTimeAsMsSinceEpoch(time.Now()),
  1530. LastActivity: utils.GetTimeAsMsSinceEpoch(time.Now()),
  1531. Protocol: "SFTP",
  1532. Transfers: transfers,
  1533. }
  1534. durationString := c.GetConnectionDuration()
  1535. assert.NotEqual(t, 0, len(durationString))
  1536. transfersString := c.GetTransfersAsString()
  1537. assert.NotEqual(t, 0, len(transfersString))
  1538. connInfo := c.GetConnectionInfo()
  1539. assert.NotEqual(t, 0, len(connInfo))
  1540. }
  1541. func TestLoadHostKeys(t *testing.T) {
  1542. configDir := ".."
  1543. serverConfig := &ssh.ServerConfig{}
  1544. c := Configuration{}
  1545. c.HostKeys = []string{".", "missing file"}
  1546. err := c.checkAndLoadHostKeys(configDir, serverConfig)
  1547. assert.Error(t, err)
  1548. testfile := filepath.Join(os.TempDir(), "invalidkey")
  1549. err = ioutil.WriteFile(testfile, []byte("some bytes"), os.ModePerm)
  1550. assert.NoError(t, err)
  1551. c.HostKeys = []string{testfile}
  1552. err = c.checkAndLoadHostKeys(configDir, serverConfig)
  1553. assert.Error(t, err)
  1554. err = os.Remove(testfile)
  1555. assert.NoError(t, err)
  1556. keysDir := filepath.Join(os.TempDir(), "keys")
  1557. err = os.MkdirAll(keysDir, os.ModePerm)
  1558. assert.NoError(t, err)
  1559. rsaKeyName := filepath.Join(keysDir, defaultPrivateRSAKeyName)
  1560. ecdsaKeyName := filepath.Join(keysDir, defaultPrivateECDSAKeyName)
  1561. ed25519KeyName := filepath.Join(keysDir, defaultPrivateEd25519KeyName)
  1562. nonDefaultKeyName := filepath.Join(keysDir, "akey")
  1563. c.HostKeys = []string{nonDefaultKeyName, rsaKeyName, ecdsaKeyName, ed25519KeyName}
  1564. err = c.checkAndLoadHostKeys(configDir, serverConfig)
  1565. assert.Error(t, err)
  1566. assert.FileExists(t, rsaKeyName)
  1567. assert.FileExists(t, ecdsaKeyName)
  1568. assert.FileExists(t, ed25519KeyName)
  1569. assert.NoFileExists(t, nonDefaultKeyName)
  1570. err = os.Remove(rsaKeyName)
  1571. assert.NoError(t, err)
  1572. err = os.Remove(ecdsaKeyName)
  1573. assert.NoError(t, err)
  1574. err = os.Remove(ed25519KeyName)
  1575. assert.NoError(t, err)
  1576. if runtime.GOOS != osWindows {
  1577. err = os.Chmod(keysDir, 0551)
  1578. assert.NoError(t, err)
  1579. c.HostKeys = nil
  1580. err = c.checkAndLoadHostKeys(keysDir, serverConfig)
  1581. assert.Error(t, err)
  1582. c.HostKeys = []string{rsaKeyName, ecdsaKeyName}
  1583. err = c.checkAndLoadHostKeys(configDir, serverConfig)
  1584. assert.Error(t, err)
  1585. c.HostKeys = []string{ecdsaKeyName, rsaKeyName}
  1586. err = c.checkAndLoadHostKeys(configDir, serverConfig)
  1587. assert.Error(t, err)
  1588. c.HostKeys = []string{ed25519KeyName}
  1589. err = c.checkAndLoadHostKeys(configDir, serverConfig)
  1590. assert.Error(t, err)
  1591. err = os.Chmod(keysDir, 0755)
  1592. assert.NoError(t, err)
  1593. }
  1594. err = os.RemoveAll(keysDir)
  1595. assert.NoError(t, err)
  1596. }
  1597. func TestCertCheckerInitErrors(t *testing.T) {
  1598. c := Configuration{}
  1599. c.TrustedUserCAKeys = []string{".", "missing file"}
  1600. err := c.initializeCertChecker("")
  1601. assert.Error(t, err)
  1602. testfile := filepath.Join(os.TempDir(), "invalidkey")
  1603. err = ioutil.WriteFile(testfile, []byte("some bytes"), os.ModePerm)
  1604. assert.NoError(t, err)
  1605. c.TrustedUserCAKeys = []string{testfile}
  1606. err = c.initializeCertChecker("")
  1607. assert.Error(t, err)
  1608. err = os.Remove(testfile)
  1609. assert.NoError(t, err)
  1610. }
  1611. func TestRecursiveCopyErrors(t *testing.T) {
  1612. permissions := make(map[string][]string)
  1613. permissions["/"] = []string{dataprovider.PermAny}
  1614. user := dataprovider.User{
  1615. Permissions: permissions,
  1616. HomeDir: os.TempDir(),
  1617. }
  1618. fs, err := user.GetFilesystem("123")
  1619. assert.NoError(t, err)
  1620. conn := &Connection{
  1621. BaseConnection: common.NewBaseConnection("", common.ProtocolSFTP, user, fs),
  1622. }
  1623. sshCmd := sshCommand{
  1624. command: "sftpgo-copy",
  1625. connection: conn,
  1626. args: []string{"adir", "another"},
  1627. }
  1628. // try to copy a missing directory
  1629. err = sshCmd.checkRecursiveCopyPermissions("adir", "another", "/another")
  1630. assert.Error(t, err)
  1631. }
  1632. func TestSFTPSubSystem(t *testing.T) {
  1633. permissions := make(map[string][]string)
  1634. permissions["/"] = []string{dataprovider.PermAny}
  1635. user := dataprovider.User{
  1636. Permissions: permissions,
  1637. HomeDir: os.TempDir(),
  1638. }
  1639. user.FsConfig.Provider = dataprovider.AzureBlobFilesystemProvider
  1640. err := ServeSubSystemConnection(user, "connID", nil, nil)
  1641. assert.Error(t, err)
  1642. user.FsConfig.Provider = dataprovider.LocalFilesystemProvider
  1643. buf := make([]byte, 0, 4096)
  1644. stdErrBuf := make([]byte, 0, 4096)
  1645. mockSSHChannel := &MockChannel{
  1646. Buffer: bytes.NewBuffer(buf),
  1647. StdErrBuffer: bytes.NewBuffer(stdErrBuf),
  1648. }
  1649. // this is 327680 and it will result in packet too long error
  1650. _, err = mockSSHChannel.Write([]byte{0x00, 0x05, 0x00, 0x00, 0x00, 0x00})
  1651. assert.NoError(t, err)
  1652. err = ServeSubSystemConnection(user, "id", mockSSHChannel, mockSSHChannel)
  1653. assert.EqualError(t, err, "packet too long")
  1654. subsystemChannel := newSubsystemChannel(mockSSHChannel, mockSSHChannel)
  1655. n, err := subsystemChannel.Write([]byte{0x00})
  1656. assert.NoError(t, err)
  1657. assert.Equal(t, n, 1)
  1658. err = subsystemChannel.Close()
  1659. assert.NoError(t, err)
  1660. }
  1661. func TestRecoverer(t *testing.T) {
  1662. c := Configuration{}
  1663. c.AcceptInboundConnection(nil, nil)
  1664. connID := "connectionID"
  1665. connection := &Connection{
  1666. BaseConnection: common.NewBaseConnection(connID, common.ProtocolSFTP, dataprovider.User{}, nil),
  1667. }
  1668. c.handleSftpConnection(nil, connection)
  1669. sshCmd := sshCommand{
  1670. command: "cd",
  1671. connection: connection,
  1672. }
  1673. err := sshCmd.handle()
  1674. assert.EqualError(t, err, common.ErrGenericFailure.Error())
  1675. scpCmd := scpCommand{
  1676. sshCommand: sshCommand{
  1677. command: "scp",
  1678. connection: connection,
  1679. },
  1680. }
  1681. err = scpCmd.handle()
  1682. assert.EqualError(t, err, common.ErrGenericFailure.Error())
  1683. assert.Len(t, common.Connections.GetStats(), 0)
  1684. }