internal_test.go 45 KB

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