internal_test.go 44 KB

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