sftpd_test.go 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464
  1. package sftpd_test
  2. import (
  3. "crypto/rand"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "net"
  8. "net/http"
  9. "os"
  10. "path/filepath"
  11. "runtime"
  12. "testing"
  13. "time"
  14. _ "github.com/go-sql-driver/mysql"
  15. _ "github.com/lib/pq"
  16. _ "github.com/mattn/go-sqlite3"
  17. "golang.org/x/crypto/ssh"
  18. "github.com/drakkan/sftpgo/api"
  19. "github.com/drakkan/sftpgo/config"
  20. "github.com/drakkan/sftpgo/dataprovider"
  21. "github.com/drakkan/sftpgo/logger"
  22. "github.com/drakkan/sftpgo/sftpd"
  23. "github.com/pkg/sftp"
  24. "github.com/rs/zerolog"
  25. )
  26. const (
  27. logSender = "sftpdTesting"
  28. sftpServerAddr = "127.0.0.1:2022"
  29. defaultUsername = "test_user_sftp"
  30. defaultPassword = "test_password"
  31. testPubKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC03jj0D+djk7pxIf/0OhrxrchJTRZklofJ1NoIu4752Sq02mdXmarMVsqJ1cAjV5LBVy3D1F5U6XW4rppkXeVtd04Pxb09ehtH0pRRPaoHHlALiJt8CoMpbKYMA8b3KXPPriGxgGomvtU2T2RMURSwOZbMtpsugfjYSWenyYX+VORYhylWnSXL961LTyC21ehd6d6QnW9G7E5hYMITMY9TuQZz3bROYzXiTsgN0+g6Hn7exFQp50p45StUMfV/SftCMdCxlxuyGny2CrN/vfjO7xxOo2uv7q1qm10Q46KPWJQv+pgZ/OfL+EDjy07n5QVSKHlbx+2nT4Q0EgOSQaCTYwn3YjtABfIxWwgAFdyj6YlPulCL22qU4MYhDcA6PSBwDdf8hvxBfvsiHdM+JcSHvv8/VeJhk6CmnZxGY0fxBupov27z3yEO8nAg8k+6PaUiW1MSUfuGMF/ktB8LOstXsEPXSszuyXiOv4DaryOXUiSn7bmRqKcEFlJusO6aZP0= nicola@p1"
  32. testPubKey1 = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCd60+/j+y8f0tLftihWV1YN9RSahMI9btQMDIMqts/jeNbD8jgoogM3nhF7KxfcaMKURuD47KC4Ey6iAJUJ0sWkSNNxOcIYuvA+5MlspfZDsa8Ag76Fe1vyz72WeHMHMeh/hwFo2TeIeIXg480T1VI6mzfDrVp2GzUx0SS0dMsQBjftXkuVR8YOiOwMCAH2a//M1OrvV7d/NBk6kBN0WnuIBb2jKm15PAA7+jQQG7tzwk2HedNH3jeL5GH31xkSRwlBczRK0xsCQXehAlx6cT/e/s44iJcJTHfpPKoSk6UAhPJYe7Z1QnuoawY9P9jQaxpyeImBZxxUEowhjpj2avBxKdRGBVK8R7EL8tSOeLbhdyWe5Mwc1+foEbq9Zz5j5Kd+hn3Wm1UnsGCrXUUUoZp1jnlNl0NakCto+5KmqnT9cHxaY+ix2RLUWAZyVFlRq71OYux1UHJnEJPiEI1/tr4jFBSL46qhQZv/TfpkfVW8FLz0lErfqu0gQEZnNHr3Fc= nicola@p1"
  33. testPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY-----
  34. b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
  35. NhAAAAAwEAAQAAAYEAtN449A/nY5O6cSH/9Doa8a3ISU0WZJaHydTaCLuO+dkqtNpnV5mq
  36. zFbKidXAI1eSwVctw9ReVOl1uK6aZF3lbXdOD8W9PXobR9KUUT2qBx5QC4ibfAqDKWymDA
  37. PG9ylzz64hsYBqJr7VNk9kTFEUsDmWzLabLoH42Elnp8mF/lTkWIcpVp0ly/etS08gttXo
  38. XenekJ1vRuxOYWDCEzGPU7kGc920TmM14k7IDdPoOh5+3sRUKedKeOUrVDH1f0n7QjHQsZ
  39. cbshp8tgqzf734zu8cTqNrr+6taptdEOOij1iUL/qYGfzny/hA48tO5+UFUih5W8ftp0+E
  40. NBIDkkGgk2MJ92I7QAXyMVsIABXco+mJT7pQi9tqlODGIQ3AOj0gcA3X/Ib8QX77Ih3TPi
  41. XEh77/P1XiYZOgpp2cRmNH8QbqaL9u898hDvJwIPJPuj2lIltTElH7hjBf5LQfCzrLV7BD
  42. 10rM7sl4jr+A2q8jl1Ikp+25kainBBZSbrDummT9AAAFgDU/VLk1P1S5AAAAB3NzaC1yc2
  43. EAAAGBALTeOPQP52OTunEh//Q6GvGtyElNFmSWh8nU2gi7jvnZKrTaZ1eZqsxWyonVwCNX
  44. ksFXLcPUXlTpdbiummRd5W13Tg/FvT16G0fSlFE9qgceUAuIm3wKgylspgwDxvcpc8+uIb
  45. GAaia+1TZPZExRFLA5lsy2my6B+NhJZ6fJhf5U5FiHKVadJcv3rUtPILbV6F3p3pCdb0bs
  46. TmFgwhMxj1O5BnPdtE5jNeJOyA3T6Doeft7EVCnnSnjlK1Qx9X9J+0Ix0LGXG7IafLYKs3
  47. +9+M7vHE6ja6/urWqbXRDjoo9YlC/6mBn858v4QOPLTuflBVIoeVvH7adPhDQSA5JBoJNj
  48. CfdiO0AF8jFbCAAV3KPpiU+6UIvbapTgxiENwDo9IHAN1/yG/EF++yId0z4lxIe+/z9V4m
  49. GToKadnEZjR/EG6mi/bvPfIQ7ycCDyT7o9pSJbUxJR+4YwX+S0Hws6y1ewQ9dKzO7JeI6/
  50. gNqvI5dSJKftuZGopwQWUm6w7ppk/QAAAAMBAAEAAAGAHKnC+Nq0XtGAkIFE4N18e6SAwy
  51. 0WSWaZqmCzFQM0S2AhJnweOIG/0ZZHjsRzKKauOTmppQk40dgVsejpytIek9R+aH172gxJ
  52. 2n4Cx0UwduRU5x8FFQlNc/kl722B0JWfJuB/snOZXv6LJ4o5aObIkozt2w9tVFeAqjYn2S
  53. 1UsNOfRHBXGsTYwpRDwFWP56nKo2d2wBBTHDhCy6fb2dLW1fvSi/YspueOGIlHpvlYKi2/
  54. CWqvs9xVrwcScMtiDoQYq0khhO0efLCxvg/o+W9CLMVM2ms4G1zoSUQKN0oYWWQJyW4+VI
  55. YneWO8UpN0J3ElXKi7bhgAat7dBaM1g9IrAzk153DiEFZNsPxGOgL/+YdQN7zUBx/z7EkI
  56. jyv80RV7fpUXvcq2p+qNl6UVig3VSzRrnsaJkUWu/A0u59ha7ocv6NxDIXjxpIDJme16GF
  57. quiGVBQNnYJymS/vFEbGf6bgf7iRmMCRUMG4nqLA6fPYP9uAtch+CmDfVLZC/fIdC5AAAA
  58. wQCDissV4zH6bfqgxJSuYNk8Vbb+19cF3b7gH1rVlB3zxpCAgcRgMHC+dP1z2NRx7UW9MR
  59. nye6kjpkzZZ0OigLqo7TtEq8uTglD9o6W7mRXqhy5A/ySOmqPL3ernHHQhGuoNODYAHkOU
  60. u2Rh8HXi+VLwKZcLInPOYJvcuLG4DxN8WfeVvlMHwhAOaTNNOtL4XZDHQeIPc4qHmJymmv
  61. sV7GuyQ6yW5C10uoGdxRPd90Bh4z4h2bKfZFjvEBbSBVkqrlAAAADBAN/zNtNayd/dX7Cr
  62. Nb4sZuzCh+CW4BH8GOePZWNCATwBbNXBVb5cR+dmuTqYm+Ekz0VxVQRA1TvKncluJOQpoa
  63. Xj8r0xdIgqkehnfDPMKtYVor06B9Fl1jrXtXU0Vrr6QcBWruSVyK1ZxqcmcNK/+KolVepe
  64. A6vcl/iKaG4U7su166nxLST06M2EgcSVsFJHpKn5+WAXC+X0Gx8kNjWIIb3GpiChdc0xZD
  65. mq02xZthVJrTCVw/e7gfDoB2QRsNV8HwAAAMEAzsCghZVp+0YsYg9oOrw4tEqcbEXEMhwY
  66. 0jW8JNL8Spr1Ibp5Dw6bRSk5azARjmJtnMJhJ3oeHfF0eoISqcNuQXGndGQbVM9YzzAzc1
  67. NbbCNsVroqKlChT5wyPNGS+phi2bPARBno7WSDvshTZ7dAVEP2c9MJW0XwoSevwKlhgSdt
  68. RLFFQ/5nclJSdzPBOmQouC0OBcMFSrYtMeknJ4VvueVvve5HcHFaEsaMc7ABAGaLYaBQOm
  69. iixITGvaNZh/tjAAAACW5pY29sYUBwMQE=
  70. -----END OPENSSH PRIVATE KEY-----`
  71. configDir = ".."
  72. )
  73. var (
  74. allPerms = []string{dataprovider.PermAny}
  75. homeBasePath string
  76. )
  77. func TestMain(m *testing.M) {
  78. logfilePath := filepath.Join(configDir, "sftpgo_sftpd_test.log")
  79. logger.InitLogger(logfilePath, 5, 1, 28, false, zerolog.DebugLevel)
  80. config.LoadConfig(configDir, "")
  81. providerConf := config.GetProviderConf()
  82. err := dataprovider.Initialize(providerConf, configDir)
  83. if err != nil {
  84. logger.Warn(logSender, "error initializing data provider: %v", err)
  85. os.Exit(1)
  86. }
  87. dataProvider := dataprovider.GetProvider()
  88. sftpdConf := config.GetSFTPDConfig()
  89. httpdConf := config.GetHTTPDConfig()
  90. router := api.GetHTTPRouter()
  91. sftpdConf.BindPort = 2022
  92. // we run the test cases with UploadMode atomic. The non atomic code path
  93. // simply does not execute some code so if it works in atomic mode will
  94. // work in non atomic mode too
  95. sftpdConf.UploadMode = 1
  96. if runtime.GOOS == "windows" {
  97. homeBasePath = "C:\\"
  98. } else {
  99. homeBasePath = "/tmp"
  100. sftpdConf.Actions.ExecuteOn = []string{"download", "upload", "rename", "delete"}
  101. sftpdConf.Actions.Command = "/usr/bin/true"
  102. sftpdConf.Actions.HTTPNotificationURL = "http://127.0.0.1:8080/"
  103. }
  104. sftpd.SetDataProvider(dataProvider)
  105. api.SetDataProvider(dataProvider)
  106. go func() {
  107. logger.Debug(logSender, "initializing SFTP server with config %+v", sftpdConf)
  108. if err := sftpdConf.Initialize(configDir); err != nil {
  109. logger.Error(logSender, "could not start SFTP server: %v", err)
  110. }
  111. }()
  112. go func() {
  113. logger.Debug(logSender, "initializing HTTP server with config %+v", httpdConf)
  114. s := &http.Server{
  115. Addr: fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort),
  116. Handler: router,
  117. ReadTimeout: 300 * time.Second,
  118. WriteTimeout: 300 * time.Second,
  119. MaxHeaderBytes: 1 << 20, // 1MB
  120. }
  121. if err := s.ListenAndServe(); err != nil {
  122. logger.Error(logSender, "could not start HTTP server: %v", err)
  123. }
  124. }()
  125. waitTCPListening(fmt.Sprintf("%s:%d", sftpdConf.BindAddress, sftpdConf.BindPort))
  126. waitTCPListening(fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort))
  127. exitCode := m.Run()
  128. os.Remove(logfilePath)
  129. os.Exit(exitCode)
  130. }
  131. func TestInitialization(t *testing.T) {
  132. config.LoadConfig(configDir, "")
  133. sftpdConf := config.GetSFTPDConfig()
  134. sftpdConf.Umask = "invalid umask"
  135. sftpdConf.BindPort = 2022
  136. err := sftpdConf.Initialize(configDir)
  137. if err == nil {
  138. t.Errorf("Inizialize must fail, a SFTP server should be already running")
  139. }
  140. }
  141. func TestBasicSFTPHandling(t *testing.T) {
  142. usePubKey := false
  143. u := getTestUser(usePubKey)
  144. u.QuotaSize = 6553600
  145. user, _, err := api.AddUser(u, http.StatusOK)
  146. if err != nil {
  147. t.Errorf("unable to add user: %v", err)
  148. }
  149. client, err := getSftpClient(user, usePubKey)
  150. if err != nil {
  151. t.Errorf("unable to create sftp client: %v", err)
  152. } else {
  153. defer client.Close()
  154. testFileName := "test_file.dat"
  155. testFilePath := filepath.Join(homeBasePath, testFileName)
  156. testFileSize := int64(65535)
  157. expectedQuotaSize := user.UsedQuotaSize + testFileSize
  158. expectedQuotaFiles := user.UsedQuotaFiles + 1
  159. err = createTestFile(testFilePath, testFileSize)
  160. if err != nil {
  161. t.Errorf("unable to create test file: %v", err)
  162. }
  163. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  164. if err != nil {
  165. t.Errorf("file upload error: %v", err)
  166. }
  167. localDownloadPath := filepath.Join(homeBasePath, "test_download.dat")
  168. err = sftpDownloadFile(testFileName, localDownloadPath, testFileSize, client)
  169. if err != nil {
  170. t.Errorf("file download error: %v", err)
  171. }
  172. user, _, err = api.GetUserByID(user.ID, http.StatusOK)
  173. if err != nil {
  174. t.Errorf("error getting user: %v", err)
  175. }
  176. if expectedQuotaFiles != user.UsedQuotaFiles {
  177. t.Errorf("quota files does not match, expected: %v, actual: %v", expectedQuotaFiles, user.UsedQuotaFiles)
  178. }
  179. if expectedQuotaSize != user.UsedQuotaSize {
  180. t.Errorf("quota size does not match, expected: %v, actual: %v", expectedQuotaSize, user.UsedQuotaSize)
  181. }
  182. err = client.Remove(testFileName)
  183. if err != nil {
  184. t.Errorf("error removing uploaded file: %v", err)
  185. }
  186. _, err = client.Lstat(testFileName)
  187. if err == nil {
  188. t.Errorf("stat for deleted file must not succeed")
  189. }
  190. user, _, err = api.GetUserByID(user.ID, http.StatusOK)
  191. if err != nil {
  192. t.Errorf("error getting user: %v", err)
  193. }
  194. if (expectedQuotaFiles - 1) != user.UsedQuotaFiles {
  195. t.Errorf("quota files does not match after delete, expected: %v, actual: %v", expectedQuotaFiles-1, user.UsedQuotaFiles)
  196. }
  197. if (expectedQuotaSize - testFileSize) != user.UsedQuotaSize {
  198. t.Errorf("quota size does not match, expected: %v, actual: %v", expectedQuotaSize-testFileSize, user.UsedQuotaSize)
  199. }
  200. }
  201. _, err = api.RemoveUser(user, http.StatusOK)
  202. if err != nil {
  203. t.Errorf("unable to remove user: %v", err)
  204. }
  205. }
  206. func TestDirCommands(t *testing.T) {
  207. usePubKey := false
  208. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  209. if err != nil {
  210. t.Errorf("unable to add user: %v", err)
  211. }
  212. // remove the home dir to test auto creation
  213. _, err = os.Stat(user.HomeDir)
  214. if err == nil {
  215. os.RemoveAll(user.HomeDir)
  216. }
  217. client, err := getSftpClient(user, usePubKey)
  218. if err != nil {
  219. t.Errorf("unable to create sftp client: %v", err)
  220. } else {
  221. defer client.Close()
  222. err = client.Mkdir("test")
  223. if err != nil {
  224. t.Errorf("error mkdir: %v", err)
  225. }
  226. err = client.Rename("test", "test1")
  227. if err != nil {
  228. t.Errorf("error rename: %v", err)
  229. }
  230. err = client.Remove("test1")
  231. if err != nil {
  232. t.Errorf("error rmdir: %v", err)
  233. }
  234. err = client.Mkdir("/test/test1")
  235. if err != nil {
  236. t.Errorf("error mkdir all: %v", err)
  237. }
  238. testFileName := "/test_file.dat"
  239. testFilePath := filepath.Join(homeBasePath, testFileName)
  240. testFileSize := int64(65535)
  241. err = createTestFile(testFilePath, testFileSize)
  242. if err != nil {
  243. t.Errorf("unable to create test file: %v", err)
  244. }
  245. err = sftpUploadFile(testFilePath, filepath.Join("/test", testFileName), testFileSize, client)
  246. if err != nil {
  247. t.Errorf("file upload error: %v", err)
  248. }
  249. // internally client.Remove will call RemoveDirectory on failure
  250. // the first remove will fail since test directory is not empty
  251. // the RemoveDirectory called internally by client.Remove will succeed
  252. err = client.Remove("/test")
  253. if err != nil {
  254. t.Errorf("error rmdir all: %v", err)
  255. }
  256. _, err = client.Lstat("/test")
  257. if err == nil {
  258. t.Errorf("stat for deleted dir must not succeed")
  259. }
  260. err = client.Remove("/test")
  261. if err == nil {
  262. t.Errorf("remove missing path must fail")
  263. }
  264. }
  265. _, err = api.RemoveUser(user, http.StatusOK)
  266. if err != nil {
  267. t.Errorf("unable to remove user: %v", err)
  268. }
  269. }
  270. func TestSymlink(t *testing.T) {
  271. usePubKey := false
  272. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  273. if err != nil {
  274. t.Errorf("unable to add user: %v", err)
  275. }
  276. client, err := getSftpClient(user, usePubKey)
  277. if err != nil {
  278. t.Errorf("unable to create sftp client: %v", err)
  279. } else {
  280. defer client.Close()
  281. testFileName := "test_file.dat"
  282. testFilePath := filepath.Join(homeBasePath, testFileName)
  283. testFileSize := int64(65535)
  284. err = createTestFile(testFilePath, testFileSize)
  285. if err != nil {
  286. t.Errorf("unable to create test file: %v", err)
  287. }
  288. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  289. if err != nil {
  290. t.Errorf("file upload error: %v", err)
  291. }
  292. err = client.Symlink(testFileName, testFileName+".link")
  293. if err != nil {
  294. t.Errorf("error creating symlink: %v", err)
  295. }
  296. err = client.Symlink(testFileName, testFileName+".link")
  297. if err == nil {
  298. t.Errorf("creating a symlink to an existing one must fail")
  299. }
  300. err = client.Remove(testFileName + ".link")
  301. if err != nil {
  302. t.Errorf("error removing symlink: %v", err)
  303. }
  304. err = client.Remove(testFileName)
  305. if err != nil {
  306. t.Errorf("error removing uploaded file: %v", err)
  307. }
  308. }
  309. _, err = api.RemoveUser(user, http.StatusOK)
  310. if err != nil {
  311. t.Errorf("unable to remove user: %v", err)
  312. }
  313. }
  314. func TestStat(t *testing.T) {
  315. usePubKey := false
  316. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  317. if err != nil {
  318. t.Errorf("unable to add user: %v", err)
  319. }
  320. client, err := getSftpClient(user, usePubKey)
  321. if err != nil {
  322. t.Errorf("unable to create sftp client: %v", err)
  323. } else {
  324. defer client.Close()
  325. testFileName := "test_file.dat"
  326. testFilePath := filepath.Join(homeBasePath, testFileName)
  327. testFileSize := int64(65535)
  328. err = createTestFile(testFilePath, testFileSize)
  329. if err != nil {
  330. t.Errorf("unable to create test file: %v", err)
  331. }
  332. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  333. if err != nil {
  334. t.Errorf("file upload error: %v", err)
  335. }
  336. fi, err := client.Lstat(testFileName)
  337. if err != nil {
  338. t.Errorf("stat error: %v", err)
  339. }
  340. err = client.Chown(testFileName, 1000, 1000)
  341. if err != nil {
  342. t.Errorf("chown error: %v", err)
  343. }
  344. err = client.Chmod(testFileName, 0600)
  345. if err != nil {
  346. t.Errorf("chmod error: %v", err)
  347. }
  348. newFi, err := client.Lstat(testFileName)
  349. if err != nil {
  350. t.Errorf("stat error: %v", err)
  351. }
  352. if fi.Mode().Perm() != newFi.Mode().Perm() {
  353. t.Errorf("stat must remain unchanged")
  354. }
  355. _, err = client.ReadLink(testFileName)
  356. if err == nil {
  357. t.Errorf("readlink is not supported and must fail")
  358. }
  359. err = client.Remove(testFileName)
  360. if err != nil {
  361. t.Errorf("error removing uploaded file: %v", err)
  362. }
  363. }
  364. _, err = api.RemoveUser(user, http.StatusOK)
  365. if err != nil {
  366. t.Errorf("unable to remove user: %v", err)
  367. }
  368. }
  369. // basic tests to verify virtual chroot, should be improved to cover more cases ...
  370. func TestEscapeHomeDir(t *testing.T) {
  371. usePubKey := true
  372. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  373. if err != nil {
  374. t.Errorf("unable to add user: %v", err)
  375. }
  376. client, err := getSftpClient(user, usePubKey)
  377. if err != nil {
  378. t.Errorf("unable to create sftp client: %v", err)
  379. } else {
  380. defer client.Close()
  381. _, err := client.Getwd()
  382. if err != nil {
  383. t.Errorf("unable to get working dir: %v", err)
  384. }
  385. testDir := "testDir"
  386. linkPath := filepath.Join(homeBasePath, defaultUsername, testDir)
  387. err = os.Symlink(homeBasePath, linkPath)
  388. if err != nil {
  389. t.Errorf("error making local symlink: %v", err)
  390. }
  391. _, err = client.ReadDir(testDir)
  392. if err == nil {
  393. t.Errorf("reading a symbolic link outside home dir should not succeeded")
  394. }
  395. os.Remove(linkPath)
  396. testFileName := "test_file.dat"
  397. testFilePath := filepath.Join(homeBasePath, testFileName)
  398. testFileSize := int64(65535)
  399. err = createTestFile(testFilePath, testFileSize)
  400. if err != nil {
  401. t.Errorf("unable to create test file: %v", err)
  402. }
  403. remoteDestPath := filepath.Join("..", "..", testFileName)
  404. err = sftpUploadFile(testFilePath, remoteDestPath, testFileSize, client)
  405. if err != nil {
  406. t.Errorf("file upload error: %v", err)
  407. }
  408. _, err = client.Lstat(testFileName)
  409. if err != nil {
  410. t.Errorf("file stat error: %v the file was created outside the user dir!", err)
  411. }
  412. err = client.Remove(testFileName)
  413. if err != nil {
  414. t.Errorf("error removing uploaded file: %v", err)
  415. }
  416. linkPath = filepath.Join(homeBasePath, defaultUsername, testFileName)
  417. err = os.Symlink(homeBasePath, linkPath)
  418. if err != nil {
  419. t.Errorf("error making local symlink: %v", err)
  420. }
  421. err = sftpDownloadFile(testFileName, testFilePath, 0, client)
  422. if err == nil {
  423. t.Errorf("download file outside home dir must fail")
  424. }
  425. err = sftpUploadFile(testFilePath, remoteDestPath, testFileSize, client)
  426. if err == nil {
  427. t.Errorf("overwrite a file outside home dir must fail")
  428. }
  429. err = client.Chmod(remoteDestPath, 0644)
  430. if err == nil {
  431. t.Errorf("setstat on a file outside home dir must fail")
  432. }
  433. os.Remove(linkPath)
  434. }
  435. _, err = api.RemoveUser(user, http.StatusOK)
  436. if err != nil {
  437. t.Errorf("unable to remove user: %v", err)
  438. }
  439. }
  440. func TestHomeSpecialChars(t *testing.T) {
  441. usePubKey := true
  442. u := getTestUser(usePubKey)
  443. u.HomeDir = filepath.Join(homeBasePath, "abc açà#&%lk")
  444. user, _, err := api.AddUser(u, http.StatusOK)
  445. if err != nil {
  446. t.Errorf("unable to add user: %v", err)
  447. }
  448. client, err := getSftpClient(user, usePubKey)
  449. if err != nil {
  450. t.Errorf("unable to create sftp client: %v", err)
  451. } else {
  452. defer client.Close()
  453. _, err := client.Getwd()
  454. if err != nil {
  455. t.Errorf("unable to get working dir: %v", err)
  456. }
  457. testFileName := "test_file.dat"
  458. testFilePath := filepath.Join(homeBasePath, testFileName)
  459. testFileSize := int64(65535)
  460. err = createTestFile(testFilePath, testFileSize)
  461. if err != nil {
  462. t.Errorf("unable to create test file: %v", err)
  463. }
  464. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  465. if err != nil {
  466. t.Errorf("file upload error: %v", err)
  467. }
  468. files, err := client.ReadDir(".")
  469. if err != nil {
  470. t.Errorf("unable to read remote dir: %v", err)
  471. }
  472. if len(files) < 1 {
  473. t.Errorf("expected at least 1 file in this dir")
  474. }
  475. err = client.Remove(testFileName)
  476. if err != nil {
  477. t.Errorf("error removing uploaded file: %v", err)
  478. }
  479. }
  480. _, err = api.RemoveUser(user, http.StatusOK)
  481. if err != nil {
  482. t.Errorf("unable to remove user: %v", err)
  483. }
  484. }
  485. func TestLogin(t *testing.T) {
  486. u := getTestUser(false)
  487. u.PublicKeys = []string{testPubKey}
  488. user, _, err := api.AddUser(u, http.StatusOK)
  489. if err != nil {
  490. t.Errorf("unable to add user: %v", err)
  491. }
  492. client, err := getSftpClient(user, false)
  493. if err != nil {
  494. t.Errorf("unable to create sftp client: %v", err)
  495. } else {
  496. defer client.Close()
  497. _, err := client.Getwd()
  498. if err != nil {
  499. t.Errorf("sftp client with valid password must work")
  500. }
  501. }
  502. client, err = getSftpClient(user, true)
  503. if err != nil {
  504. t.Errorf("unable to create sftp client: %v", err)
  505. } else {
  506. defer client.Close()
  507. _, err := client.Getwd()
  508. if err != nil {
  509. t.Errorf("sftp client with valid public key must work")
  510. }
  511. }
  512. user.Password = "invalid password"
  513. client, err = getSftpClient(user, false)
  514. if err == nil {
  515. t.Errorf("login with invalid password must fail")
  516. defer client.Close()
  517. }
  518. // testPubKey1 is not authorized
  519. user.PublicKeys = []string{testPubKey1}
  520. user.Password = ""
  521. _, _, err = api.UpdateUser(user, http.StatusOK)
  522. if err != nil {
  523. t.Errorf("unable to update user: %v", err)
  524. }
  525. client, err = getSftpClient(user, true)
  526. if err == nil {
  527. t.Errorf("login with invalid public key must fail")
  528. defer client.Close()
  529. }
  530. // login a user with multiple public keys, only the second one is valid
  531. user.PublicKeys = []string{testPubKey1, testPubKey}
  532. user.Password = ""
  533. _, _, err = api.UpdateUser(user, http.StatusOK)
  534. if err != nil {
  535. t.Errorf("unable to update user: %v", err)
  536. }
  537. client, err = getSftpClient(user, true)
  538. if err != nil {
  539. t.Errorf("unable to create sftp client: %v", err)
  540. } else {
  541. defer client.Close()
  542. _, err := client.Getwd()
  543. if err != nil {
  544. t.Errorf("sftp client with multiple public key must work if at least one public key is valid")
  545. }
  546. }
  547. _, err = api.RemoveUser(user, http.StatusOK)
  548. if err != nil {
  549. t.Errorf("unable to remove user: %v", err)
  550. }
  551. }
  552. func TestLoginAfterUserUpdateEmptyPwd(t *testing.T) {
  553. usePubKey := false
  554. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  555. if err != nil {
  556. t.Errorf("unable to add user: %v", err)
  557. }
  558. user.Password = ""
  559. user.PublicKeys = []string{}
  560. // password and public key should remain unchanged
  561. _, _, err = api.UpdateUser(user, http.StatusOK)
  562. if err != nil {
  563. t.Errorf("unable to update user: %v", err)
  564. }
  565. client, err := getSftpClient(user, usePubKey)
  566. if err != nil {
  567. t.Errorf("unable to create sftp client: %v", err)
  568. } else {
  569. defer client.Close()
  570. _, err := client.Getwd()
  571. if err != nil {
  572. t.Errorf("unable to get working dir: %v", err)
  573. }
  574. _, err = client.ReadDir(".")
  575. if err != nil {
  576. t.Errorf("unable to read remote dir: %v", err)
  577. }
  578. }
  579. _, err = api.RemoveUser(user, http.StatusOK)
  580. if err != nil {
  581. t.Errorf("unable to remove user: %v", err)
  582. }
  583. }
  584. func TestLoginAfterUserUpdateEmptyPubKey(t *testing.T) {
  585. usePubKey := true
  586. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  587. if err != nil {
  588. t.Errorf("unable to add user: %v", err)
  589. }
  590. user.Password = ""
  591. user.PublicKeys = []string{}
  592. // password and public key should remain unchanged
  593. _, _, err = api.UpdateUser(user, http.StatusOK)
  594. if err != nil {
  595. t.Errorf("unable to update user: %v", err)
  596. }
  597. client, err := getSftpClient(user, usePubKey)
  598. if err != nil {
  599. t.Errorf("unable to create sftp client: %v", err)
  600. } else {
  601. defer client.Close()
  602. _, err := client.Getwd()
  603. if err != nil {
  604. t.Errorf("unable to get working dir: %v", err)
  605. }
  606. _, err = client.ReadDir(".")
  607. if err != nil {
  608. t.Errorf("unable to read remote dir: %v", err)
  609. }
  610. }
  611. _, err = api.RemoveUser(user, http.StatusOK)
  612. if err != nil {
  613. t.Errorf("unable to remove user: %v", err)
  614. }
  615. }
  616. func TestMaxSessions(t *testing.T) {
  617. usePubKey := false
  618. u := getTestUser(usePubKey)
  619. u.MaxSessions = 1
  620. user, _, err := api.AddUser(u, http.StatusOK)
  621. if err != nil {
  622. t.Errorf("unable to add user: %v", err)
  623. }
  624. client, err := getSftpClient(user, usePubKey)
  625. if err != nil {
  626. t.Errorf("unable to create sftp client: %v", err)
  627. } else {
  628. defer client.Close()
  629. _, err := client.Getwd()
  630. if err != nil {
  631. t.Errorf("unable to get working dir: %v", err)
  632. }
  633. _, err = client.ReadDir(".")
  634. if err != nil {
  635. t.Errorf("unable to read remote dir: %v", err)
  636. }
  637. _, err = getSftpClient(user, usePubKey)
  638. if err == nil {
  639. t.Errorf("max sessions exceeded, new login should not succeed")
  640. }
  641. }
  642. _, err = api.RemoveUser(user, http.StatusOK)
  643. if err != nil {
  644. t.Errorf("unable to remove user: %v", err)
  645. }
  646. }
  647. func TestQuotaFileReplace(t *testing.T) {
  648. usePubKey := false
  649. u := getTestUser(usePubKey)
  650. u.QuotaFiles = 1000
  651. user, _, err := api.AddUser(u, http.StatusOK)
  652. if err != nil {
  653. t.Errorf("unable to add user: %v", err)
  654. }
  655. testFileSize := int64(65535)
  656. testFileName := "test_file.dat"
  657. testFilePath := filepath.Join(homeBasePath, testFileName)
  658. client, err := getSftpClient(user, usePubKey)
  659. if err != nil {
  660. t.Errorf("unable to create sftp client: %v", err)
  661. } else {
  662. defer client.Close()
  663. expectedQuotaSize := user.UsedQuotaSize + testFileSize
  664. expectedQuotaFiles := user.UsedQuotaFiles + 1
  665. err = createTestFile(testFilePath, testFileSize)
  666. if err != nil {
  667. t.Errorf("unable to create test file: %v", err)
  668. }
  669. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  670. if err != nil {
  671. t.Errorf("file upload error: %v", err)
  672. }
  673. user, _, err = api.GetUserByID(user.ID, http.StatusOK)
  674. if err != nil {
  675. t.Errorf("error getting user: %v", err)
  676. }
  677. // now replace the same file, the quota must not change
  678. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  679. if err != nil {
  680. t.Errorf("file upload error: %v", err)
  681. }
  682. user, _, err = api.GetUserByID(user.ID, http.StatusOK)
  683. if err != nil {
  684. t.Errorf("error getting user: %v", err)
  685. }
  686. if expectedQuotaFiles != user.UsedQuotaFiles {
  687. t.Errorf("quota files does not match, expected: %v, actual: %v", expectedQuotaFiles, user.UsedQuotaFiles)
  688. }
  689. if expectedQuotaSize != user.UsedQuotaSize {
  690. t.Errorf("quota size does not match, expected: %v, actual: %v", expectedQuotaSize, user.UsedQuotaSize)
  691. }
  692. }
  693. // now set a quota size restriction and upload the same fail, upload should fail for space limit exceeded
  694. user.QuotaSize = testFileSize - 1
  695. user, _, err = api.UpdateUser(user, http.StatusOK)
  696. if err != nil {
  697. t.Errorf("error updating user: %v", err)
  698. }
  699. client, err = getSftpClient(user, usePubKey)
  700. if err != nil {
  701. t.Errorf("unable to create sftp client: %v", err)
  702. } else {
  703. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  704. if err == nil {
  705. t.Errorf("quota size exceeded, file upload must fail")
  706. }
  707. err = client.Remove(testFileName)
  708. if err != nil {
  709. t.Errorf("error removing uploaded file: %v", err)
  710. }
  711. }
  712. _, err = api.RemoveUser(user, http.StatusOK)
  713. if err != nil {
  714. t.Errorf("unable to remove user: %v", err)
  715. }
  716. }
  717. func TestQuotaScan(t *testing.T) {
  718. usePubKey := false
  719. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  720. if err != nil {
  721. t.Errorf("unable to add user: %v", err)
  722. }
  723. testFileSize := int64(65535)
  724. expectedQuotaSize := user.UsedQuotaSize + testFileSize
  725. expectedQuotaFiles := user.UsedQuotaFiles + 1
  726. client, err := getSftpClient(user, usePubKey)
  727. if err != nil {
  728. t.Errorf("unable to create sftp client: %v", err)
  729. } else {
  730. defer client.Close()
  731. testFileName := "test_file.dat"
  732. testFilePath := filepath.Join(homeBasePath, testFileName)
  733. err = createTestFile(testFilePath, testFileSize)
  734. if err != nil {
  735. t.Errorf("unable to create test file: %v", err)
  736. }
  737. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  738. if err != nil {
  739. t.Errorf("file upload error: %v", err)
  740. }
  741. }
  742. _, err = api.RemoveUser(user, http.StatusOK)
  743. if err != nil {
  744. t.Errorf("unable to remove user: %v", err)
  745. }
  746. // create user with the same home dir, so there is at least an untracked file
  747. user, _, err = api.AddUser(getTestUser(usePubKey), http.StatusOK)
  748. if err != nil {
  749. t.Errorf("unable to add user: %v", err)
  750. }
  751. _, err = api.StartQuotaScan(user, http.StatusCreated)
  752. if err != nil {
  753. t.Errorf("error starting quota scan: %v", err)
  754. }
  755. scans, _, err := api.GetQuotaScans(http.StatusOK)
  756. if err != nil {
  757. t.Errorf("error getting active quota scans: %v", err)
  758. }
  759. for len(scans) > 0 {
  760. scans, _, err = api.GetQuotaScans(http.StatusOK)
  761. if err != nil {
  762. t.Errorf("error getting active quota scans: %v", err)
  763. break
  764. }
  765. }
  766. user, _, err = api.GetUserByID(user.ID, http.StatusOK)
  767. if err != nil {
  768. t.Errorf("error getting user: %v", err)
  769. }
  770. if expectedQuotaFiles != user.UsedQuotaFiles {
  771. t.Errorf("quota files does not match after scan, expected: %v, actual: %v", expectedQuotaFiles, user.UsedQuotaFiles)
  772. }
  773. if expectedQuotaSize != user.UsedQuotaSize {
  774. t.Errorf("quota size does not match after scan, expected: %v, actual: %v", expectedQuotaSize, user.UsedQuotaSize)
  775. }
  776. _, err = api.RemoveUser(user, http.StatusOK)
  777. if err != nil {
  778. t.Errorf("unable to remove user: %v", err)
  779. }
  780. }
  781. func TestMultipleQuotaScans(t *testing.T) {
  782. if !sftpd.AddQuotaScan(defaultUsername) {
  783. t.Errorf("add quota failed")
  784. }
  785. if sftpd.AddQuotaScan(defaultUsername) {
  786. t.Errorf("add quota must fail if another scan is already active")
  787. }
  788. sftpd.RemoveQuotaScan(defaultPassword)
  789. }
  790. func TestQuotaSize(t *testing.T) {
  791. usePubKey := false
  792. testFileSize := int64(65535)
  793. u := getTestUser(usePubKey)
  794. u.QuotaFiles = 1
  795. u.QuotaSize = testFileSize - 1
  796. user, _, err := api.AddUser(u, http.StatusOK)
  797. if err != nil {
  798. t.Errorf("unable to add user: %v", err)
  799. }
  800. client, err := getSftpClient(user, usePubKey)
  801. if err != nil {
  802. t.Errorf("unable to create sftp client: %v", err)
  803. } else {
  804. defer client.Close()
  805. testFileName := "test_file.dat"
  806. testFilePath := filepath.Join(homeBasePath, testFileName)
  807. err = createTestFile(testFilePath, testFileSize)
  808. if err != nil {
  809. t.Errorf("unable to create test file: %v", err)
  810. }
  811. err = sftpUploadFile(testFilePath, testFileName+".quota", testFileSize, client)
  812. if err != nil {
  813. t.Errorf("file upload error: %v", err)
  814. }
  815. err = sftpUploadFile(testFilePath, testFileName+".quota.1", testFileSize, client)
  816. if err == nil {
  817. t.Errorf("user is over quota file upload must fail")
  818. }
  819. err = client.Remove(testFileName + ".quota")
  820. if err != nil {
  821. t.Errorf("error removing uploaded file: %v", err)
  822. }
  823. }
  824. _, err = api.RemoveUser(user, http.StatusOK)
  825. if err != nil {
  826. t.Errorf("unable to remove user: %v", err)
  827. }
  828. }
  829. func TestBandwidthAndConnections(t *testing.T) {
  830. usePubKey := false
  831. testFileSize := int64(131072)
  832. u := getTestUser(usePubKey)
  833. u.UploadBandwidth = 30
  834. u.DownloadBandwidth = 25
  835. wantedUploadElapsed := 1000 * (testFileSize / 1000) / u.UploadBandwidth
  836. wantedDownloadElapsed := 1000 * (testFileSize / 1000) / u.DownloadBandwidth
  837. // 100 ms tolerance
  838. wantedUploadElapsed -= 100
  839. wantedDownloadElapsed -= 100
  840. user, _, err := api.AddUser(u, http.StatusOK)
  841. if err != nil {
  842. t.Errorf("unable to add user: %v", err)
  843. }
  844. client, err := getSftpClient(user, usePubKey)
  845. if err != nil {
  846. t.Errorf("unable to create sftp client: %v", err)
  847. } else {
  848. defer client.Close()
  849. testFileName := "test_file.dat"
  850. testFilePath := filepath.Join(homeBasePath, testFileName)
  851. err = createTestFile(testFilePath, testFileSize)
  852. if err != nil {
  853. t.Errorf("unable to create test file: %v", err)
  854. }
  855. startTime := time.Now()
  856. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  857. if err != nil {
  858. t.Errorf("file upload error: %v", err)
  859. }
  860. elapsed := time.Since(startTime).Nanoseconds() / 1000000
  861. if elapsed < (wantedUploadElapsed) {
  862. t.Errorf("upload bandwidth throttling not respected, elapsed: %v, wanted: %v", elapsed, wantedUploadElapsed)
  863. }
  864. startTime = time.Now()
  865. localDownloadPath := filepath.Join(homeBasePath, "test_download.dat")
  866. c := sftpDownloadNonBlocking(testFileName, localDownloadPath, testFileSize, client)
  867. waitForActiveTransfer()
  868. // wait some additional arbitrary time to wait for transfer activity to happen
  869. // it is need to reach all the code in CheckIdleConnections
  870. time.Sleep(100 * time.Millisecond)
  871. sftpd.CheckIdleConnections()
  872. err = <-c
  873. if err != nil {
  874. t.Errorf("file download error: %v", err)
  875. }
  876. elapsed = time.Since(startTime).Nanoseconds() / 1000000
  877. if elapsed < (wantedDownloadElapsed) {
  878. t.Errorf("download bandwidth throttling not respected, elapsed: %v, wanted: %v", elapsed, wantedDownloadElapsed)
  879. }
  880. // test disconnection
  881. c = sftpUploadNonBlocking(testFilePath, testFileName+"_partial", testFileSize, client)
  882. waitForActiveTransfer()
  883. time.Sleep(100 * time.Millisecond)
  884. sftpd.CheckIdleConnections()
  885. stats := sftpd.GetConnectionsStats()
  886. for _, stat := range stats {
  887. sftpd.CloseActiveConnection(stat.ConnectionID)
  888. }
  889. err = <-c
  890. if err == nil {
  891. t.Errorf("connection closed upload must fail")
  892. }
  893. }
  894. _, err = api.RemoveUser(user, http.StatusOK)
  895. if err != nil {
  896. t.Errorf("unable to remove user: %v", err)
  897. }
  898. }
  899. func TestMissingFile(t *testing.T) {
  900. usePubKey := false
  901. u := getTestUser(usePubKey)
  902. user, _, err := api.AddUser(u, http.StatusOK)
  903. if err != nil {
  904. t.Errorf("unable to add user: %v", err)
  905. }
  906. client, err := getSftpClient(user, usePubKey)
  907. if err != nil {
  908. t.Errorf("unable to create sftp client: %v", err)
  909. } else {
  910. defer client.Close()
  911. localDownloadPath := filepath.Join(homeBasePath, "test_download.dat")
  912. err = sftpDownloadFile("missing_file", localDownloadPath, 0, client)
  913. if err == nil {
  914. t.Errorf("download missing file must fail")
  915. }
  916. }
  917. _, err = api.RemoveUser(user, http.StatusOK)
  918. if err != nil {
  919. t.Errorf("unable to remove user: %v", err)
  920. }
  921. }
  922. func TestOverwriteDirWithFile(t *testing.T) {
  923. usePubKey := false
  924. u := getTestUser(usePubKey)
  925. user, _, err := api.AddUser(u, http.StatusOK)
  926. if err != nil {
  927. t.Errorf("unable to add user: %v", err)
  928. }
  929. client, err := getSftpClient(user, usePubKey)
  930. if err != nil {
  931. t.Errorf("unable to create sftp client: %v", err)
  932. } else {
  933. defer client.Close()
  934. testFileSize := int64(65535)
  935. testFileName := "test_file.dat"
  936. testDirName := "test_dir"
  937. testFilePath := filepath.Join(homeBasePath, testFileName)
  938. err = createTestFile(testFilePath, testFileSize)
  939. if err != nil {
  940. t.Errorf("unable to create test file: %v", err)
  941. }
  942. err = client.Mkdir(testDirName)
  943. if err != nil {
  944. t.Errorf("mkdir error: %v", err)
  945. }
  946. err = sftpUploadFile(testFilePath, testDirName, testFileSize, client)
  947. if err == nil {
  948. t.Errorf("copying a file over an existing dir must fail")
  949. }
  950. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  951. if err != nil {
  952. t.Errorf("file upload error: %v", err)
  953. }
  954. err = client.Rename(testFileName, testDirName)
  955. if err == nil {
  956. t.Errorf("rename a file over an existing dir must fail")
  957. }
  958. err = client.RemoveDirectory(testDirName)
  959. if err != nil {
  960. t.Errorf("dir remove error: %v", err)
  961. }
  962. err = client.Remove(testFileName)
  963. if err != nil {
  964. t.Errorf("error removing uploaded file: %v", err)
  965. }
  966. }
  967. _, err = api.RemoveUser(user, http.StatusOK)
  968. if err != nil {
  969. t.Errorf("unable to remove user: %v", err)
  970. }
  971. }
  972. func TestPermList(t *testing.T) {
  973. usePubKey := true
  974. u := getTestUser(usePubKey)
  975. u.Permissions = []string{dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermDelete, dataprovider.PermRename,
  976. dataprovider.PermCreateDirs, dataprovider.PermCreateSymlinks}
  977. user, _, err := api.AddUser(u, http.StatusOK)
  978. if err != nil {
  979. t.Errorf("unable to add user: %v", err)
  980. }
  981. client, err := getSftpClient(user, usePubKey)
  982. if err != nil {
  983. t.Errorf("unable to create sftp client: %v", err)
  984. } else {
  985. defer client.Close()
  986. _, err = client.ReadDir(".")
  987. if err == nil {
  988. t.Errorf("read remote dir without permission should not succeed")
  989. }
  990. _, err = client.Stat("test_file")
  991. if err == nil {
  992. t.Errorf("stat remote file without permission should not succeed")
  993. }
  994. }
  995. _, err = api.RemoveUser(user, http.StatusOK)
  996. if err != nil {
  997. t.Errorf("unable to remove user: %v", err)
  998. }
  999. }
  1000. func TestPermDownload(t *testing.T) {
  1001. usePubKey := true
  1002. u := getTestUser(usePubKey)
  1003. u.Permissions = []string{dataprovider.PermListItems, dataprovider.PermUpload, dataprovider.PermDelete, dataprovider.PermRename,
  1004. dataprovider.PermCreateDirs, dataprovider.PermCreateSymlinks}
  1005. user, _, err := api.AddUser(u, http.StatusOK)
  1006. if err != nil {
  1007. t.Errorf("unable to add user: %v", err)
  1008. }
  1009. client, err := getSftpClient(user, usePubKey)
  1010. if err != nil {
  1011. t.Errorf("unable to create sftp client: %v", err)
  1012. } else {
  1013. defer client.Close()
  1014. testFileName := "test_file.dat"
  1015. testFilePath := filepath.Join(homeBasePath, testFileName)
  1016. testFileSize := int64(65535)
  1017. err = createTestFile(testFilePath, testFileSize)
  1018. if err != nil {
  1019. t.Errorf("unable to create test file: %v", err)
  1020. }
  1021. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  1022. if err != nil {
  1023. t.Errorf("file upload error: %v", err)
  1024. }
  1025. localDownloadPath := filepath.Join(homeBasePath, "test_download.dat")
  1026. err = sftpDownloadFile(testFileName, localDownloadPath, testFileSize, client)
  1027. if err == nil {
  1028. t.Errorf("file download without permission should not succeed")
  1029. }
  1030. err = client.Remove(testFileName)
  1031. if err != nil {
  1032. t.Errorf("error removing uploaded file: %v", err)
  1033. }
  1034. }
  1035. _, err = api.RemoveUser(user, http.StatusOK)
  1036. if err != nil {
  1037. t.Errorf("unable to remove user: %v", err)
  1038. }
  1039. }
  1040. func TestPermUpload(t *testing.T) {
  1041. usePubKey := false
  1042. u := getTestUser(usePubKey)
  1043. u.Permissions = []string{dataprovider.PermListItems, dataprovider.PermDownload, dataprovider.PermDelete, dataprovider.PermRename,
  1044. dataprovider.PermCreateDirs, dataprovider.PermCreateSymlinks}
  1045. user, _, err := api.AddUser(u, http.StatusOK)
  1046. if err != nil {
  1047. t.Errorf("unable to add user: %v", err)
  1048. }
  1049. client, err := getSftpClient(user, usePubKey)
  1050. if err != nil {
  1051. t.Errorf("unable to create sftp client: %v", err)
  1052. } else {
  1053. defer client.Close()
  1054. testFileName := "test_file.dat"
  1055. testFilePath := filepath.Join(homeBasePath, testFileName)
  1056. testFileSize := int64(65535)
  1057. err = createTestFile(testFilePath, testFileSize)
  1058. if err != nil {
  1059. t.Errorf("unable to create test file: %v", err)
  1060. }
  1061. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  1062. if err == nil {
  1063. t.Errorf("file upload without permission should not succeed")
  1064. }
  1065. }
  1066. _, err = api.RemoveUser(user, http.StatusOK)
  1067. if err != nil {
  1068. t.Errorf("unable to remove user: %v", err)
  1069. }
  1070. }
  1071. func TestPermDelete(t *testing.T) {
  1072. usePubKey := false
  1073. u := getTestUser(usePubKey)
  1074. u.Permissions = []string{dataprovider.PermListItems, dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermRename,
  1075. dataprovider.PermCreateDirs, dataprovider.PermCreateSymlinks}
  1076. user, _, err := api.AddUser(u, http.StatusOK)
  1077. if err != nil {
  1078. t.Errorf("unable to add user: %v", err)
  1079. }
  1080. client, err := getSftpClient(user, usePubKey)
  1081. if err != nil {
  1082. t.Errorf("unable to create sftp client: %v", err)
  1083. } else {
  1084. defer client.Close()
  1085. testFileName := "test_file.dat"
  1086. testFilePath := filepath.Join(homeBasePath, testFileName)
  1087. testFileSize := int64(65535)
  1088. err = createTestFile(testFilePath, testFileSize)
  1089. if err != nil {
  1090. t.Errorf("unable to create test file: %v", err)
  1091. }
  1092. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  1093. if err != nil {
  1094. t.Errorf("file upload error: %v", err)
  1095. }
  1096. err = client.Remove(testFileName)
  1097. if err == nil {
  1098. t.Errorf("delete without permission should not succeed")
  1099. }
  1100. }
  1101. _, err = api.RemoveUser(user, http.StatusOK)
  1102. if err != nil {
  1103. t.Errorf("unable to remove user: %v", err)
  1104. }
  1105. }
  1106. func TestPermRename(t *testing.T) {
  1107. usePubKey := false
  1108. u := getTestUser(usePubKey)
  1109. u.Permissions = []string{dataprovider.PermListItems, dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermDelete,
  1110. dataprovider.PermCreateDirs, dataprovider.PermCreateSymlinks}
  1111. user, _, err := api.AddUser(u, http.StatusOK)
  1112. if err != nil {
  1113. t.Errorf("unable to add user: %v", err)
  1114. }
  1115. client, err := getSftpClient(user, usePubKey)
  1116. if err != nil {
  1117. t.Errorf("unable to create sftp client: %v", err)
  1118. } else {
  1119. defer client.Close()
  1120. testFileName := "test_file.dat"
  1121. testFilePath := filepath.Join(homeBasePath, testFileName)
  1122. testFileSize := int64(65535)
  1123. err = createTestFile(testFilePath, testFileSize)
  1124. if err != nil {
  1125. t.Errorf("unable to create test file: %v", err)
  1126. }
  1127. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  1128. if err != nil {
  1129. t.Errorf("file upload error: %v", err)
  1130. }
  1131. err = client.Rename(testFileName, testFileName+".rename")
  1132. if err == nil {
  1133. t.Errorf("rename without permission should not succeed")
  1134. }
  1135. err = client.Remove(testFileName)
  1136. if err != nil {
  1137. t.Errorf("error removing uploaded file: %v", err)
  1138. }
  1139. }
  1140. _, err = api.RemoveUser(user, http.StatusOK)
  1141. if err != nil {
  1142. t.Errorf("unable to remove user: %v", err)
  1143. }
  1144. }
  1145. func TestPermCreateDirs(t *testing.T) {
  1146. usePubKey := false
  1147. u := getTestUser(usePubKey)
  1148. u.Permissions = []string{dataprovider.PermListItems, dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermDelete,
  1149. dataprovider.PermRename, dataprovider.PermCreateSymlinks}
  1150. user, _, err := api.AddUser(u, http.StatusOK)
  1151. if err != nil {
  1152. t.Errorf("unable to add user: %v", err)
  1153. }
  1154. client, err := getSftpClient(user, usePubKey)
  1155. if err != nil {
  1156. t.Errorf("unable to create sftp client: %v", err)
  1157. } else {
  1158. defer client.Close()
  1159. err = client.Mkdir("testdir")
  1160. if err == nil {
  1161. t.Errorf("mkdir without permission should not succeed")
  1162. }
  1163. testFileName := "test_file.dat"
  1164. testFilePath := filepath.Join(homeBasePath, testFileName)
  1165. testFileSize := int64(65535)
  1166. err = createTestFile(testFilePath, testFileSize)
  1167. if err != nil {
  1168. t.Errorf("unable to create test file: %v", err)
  1169. }
  1170. err = sftpUploadFile(testFilePath, "/dir/subdir/test_file.dat", testFileSize, client)
  1171. if err == nil {
  1172. t.Errorf("mkdir without permission should not succeed")
  1173. }
  1174. }
  1175. _, err = api.RemoveUser(user, http.StatusOK)
  1176. if err != nil {
  1177. t.Errorf("unable to remove user: %v", err)
  1178. }
  1179. }
  1180. func TestPermSymlink(t *testing.T) {
  1181. usePubKey := false
  1182. u := getTestUser(usePubKey)
  1183. u.Permissions = []string{dataprovider.PermListItems, dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermDelete,
  1184. dataprovider.PermRename, dataprovider.PermCreateDirs}
  1185. user, _, err := api.AddUser(u, http.StatusOK)
  1186. if err != nil {
  1187. t.Errorf("unable to add user: %v", err)
  1188. }
  1189. client, err := getSftpClient(user, usePubKey)
  1190. if err != nil {
  1191. t.Errorf("unable to create sftp client: %v", err)
  1192. } else {
  1193. defer client.Close()
  1194. testFileName := "test_file.dat"
  1195. testFilePath := filepath.Join(homeBasePath, testFileName)
  1196. testFileSize := int64(65535)
  1197. err = createTestFile(testFilePath, testFileSize)
  1198. if err != nil {
  1199. t.Errorf("unable to create test file: %v", err)
  1200. }
  1201. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  1202. if err != nil {
  1203. t.Errorf("file upload error: %v", err)
  1204. }
  1205. err = client.Symlink(testFilePath, testFilePath+".symlink")
  1206. if err == nil {
  1207. t.Errorf("symlink without permission should not succeed")
  1208. }
  1209. err = client.Remove(testFileName)
  1210. if err != nil {
  1211. t.Errorf("error removing uploaded file: %v", err)
  1212. }
  1213. }
  1214. _, err = api.RemoveUser(user, http.StatusOK)
  1215. if err != nil {
  1216. t.Errorf("unable to remove user: %v", err)
  1217. }
  1218. }
  1219. func TestSSHConnection(t *testing.T) {
  1220. usePubKey := false
  1221. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  1222. if err != nil {
  1223. t.Errorf("unable to add user: %v", err)
  1224. }
  1225. err = doSSH(user, usePubKey)
  1226. if err == nil {
  1227. t.Errorf("ssh connection must fail: %v", err)
  1228. }
  1229. _, err = api.RemoveUser(user, http.StatusOK)
  1230. if err != nil {
  1231. t.Errorf("unable to remove user: %v", err)
  1232. }
  1233. }
  1234. func waitTCPListening(address string) {
  1235. for {
  1236. conn, err := net.Dial("tcp", address)
  1237. if err != nil {
  1238. logger.WarnToConsole("tcp server %v not listening: %v\n", address, err)
  1239. time.Sleep(100 * time.Millisecond)
  1240. continue
  1241. }
  1242. logger.InfoToConsole("tcp server %v now listening\n", address)
  1243. defer conn.Close()
  1244. break
  1245. }
  1246. }
  1247. func getTestUser(usePubKey bool) dataprovider.User {
  1248. user := dataprovider.User{
  1249. Username: defaultUsername,
  1250. Password: defaultPassword,
  1251. HomeDir: filepath.Join(homeBasePath, defaultUsername),
  1252. Permissions: allPerms,
  1253. }
  1254. if usePubKey {
  1255. user.PublicKeys = []string{testPubKey}
  1256. user.Password = ""
  1257. }
  1258. return user
  1259. }
  1260. func doSSH(user dataprovider.User, usePubKey bool) error {
  1261. var sshSession *ssh.Session
  1262. config := &ssh.ClientConfig{
  1263. User: defaultUsername,
  1264. HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
  1265. return nil
  1266. },
  1267. }
  1268. if usePubKey {
  1269. key, err := ssh.ParsePrivateKey([]byte(testPrivateKey))
  1270. if err != nil {
  1271. return err
  1272. }
  1273. config.Auth = []ssh.AuthMethod{ssh.PublicKeys(key)}
  1274. } else {
  1275. config.Auth = []ssh.AuthMethod{ssh.Password(defaultPassword)}
  1276. }
  1277. conn, err := ssh.Dial("tcp", sftpServerAddr, config)
  1278. if err != nil {
  1279. return err
  1280. }
  1281. defer conn.Close()
  1282. sshSession, err = conn.NewSession()
  1283. if err != nil {
  1284. return err
  1285. }
  1286. _, err = sshSession.CombinedOutput("ls")
  1287. return err
  1288. }
  1289. func getSftpClient(user dataprovider.User, usePubKey bool) (*sftp.Client, error) {
  1290. var sftpClient *sftp.Client
  1291. config := &ssh.ClientConfig{
  1292. User: user.Username,
  1293. HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
  1294. return nil
  1295. },
  1296. }
  1297. if usePubKey {
  1298. key, err := ssh.ParsePrivateKey([]byte(testPrivateKey))
  1299. if err != nil {
  1300. return nil, err
  1301. }
  1302. config.Auth = []ssh.AuthMethod{ssh.PublicKeys(key)}
  1303. } else {
  1304. if len(user.Password) > 0 {
  1305. config.Auth = []ssh.AuthMethod{ssh.Password(user.Password)}
  1306. } else {
  1307. config.Auth = []ssh.AuthMethod{ssh.Password(defaultPassword)}
  1308. }
  1309. }
  1310. conn, err := ssh.Dial("tcp", sftpServerAddr, config)
  1311. if err != nil {
  1312. return sftpClient, err
  1313. }
  1314. sftpClient, err = sftp.NewClient(conn)
  1315. return sftpClient, err
  1316. }
  1317. func createTestFile(path string, size int64) error {
  1318. content := make([]byte, size)
  1319. _, err := rand.Read(content)
  1320. if err != nil {
  1321. return err
  1322. }
  1323. return ioutil.WriteFile(path, content, 0666)
  1324. }
  1325. func sftpUploadFile(localSourcePath string, remoteDestPath string, expectedSize int64, client *sftp.Client) error {
  1326. srcFile, err := os.Open(localSourcePath)
  1327. if err != nil {
  1328. return err
  1329. }
  1330. defer srcFile.Close()
  1331. destFile, err := client.Create(remoteDestPath)
  1332. if err != nil {
  1333. return err
  1334. }
  1335. _, err = io.Copy(destFile, srcFile)
  1336. if err != nil {
  1337. destFile.Close()
  1338. return err
  1339. }
  1340. // we need to close the file to trigger the close method on server
  1341. // we cannot defer closing or Lstat will fail for upload atomic mode
  1342. destFile.Close()
  1343. if expectedSize > 0 {
  1344. fi, err := client.Lstat(remoteDestPath)
  1345. if err != nil {
  1346. return err
  1347. }
  1348. if fi.Size() != expectedSize {
  1349. return fmt.Errorf("uploaded file size does not match, actual: %v, expected: %v", fi.Size(), expectedSize)
  1350. }
  1351. }
  1352. return err
  1353. }
  1354. func sftpDownloadFile(remoteSourcePath string, localDestPath string, expectedSize int64, client *sftp.Client) error {
  1355. downloadDest, err := os.Create(localDestPath)
  1356. if err != nil {
  1357. return err
  1358. }
  1359. defer downloadDest.Close()
  1360. sftpSrcFile, err := client.Open(remoteSourcePath)
  1361. if err != nil {
  1362. return err
  1363. }
  1364. defer sftpSrcFile.Close()
  1365. _, err = io.Copy(downloadDest, sftpSrcFile)
  1366. if err != nil {
  1367. return err
  1368. }
  1369. err = downloadDest.Sync()
  1370. if err != nil {
  1371. return err
  1372. }
  1373. if expectedSize > 0 {
  1374. fi, err := downloadDest.Stat()
  1375. if err != nil {
  1376. return err
  1377. }
  1378. if fi.Size() != expectedSize {
  1379. return fmt.Errorf("downloaded file size does not match, actual: %v, expected: %v", fi.Size(), expectedSize)
  1380. }
  1381. }
  1382. return err
  1383. }
  1384. func sftpUploadNonBlocking(localSourcePath string, remoteDestPath string, expectedSize int64, client *sftp.Client) <-chan error {
  1385. c := make(chan error)
  1386. go func() {
  1387. c <- sftpUploadFile(localSourcePath, remoteDestPath, expectedSize, client)
  1388. }()
  1389. return c
  1390. }
  1391. func sftpDownloadNonBlocking(remoteSourcePath string, localDestPath string, expectedSize int64, client *sftp.Client) <-chan error {
  1392. c := make(chan error)
  1393. go func() {
  1394. c <- sftpDownloadFile(remoteSourcePath, localDestPath, expectedSize, client)
  1395. }()
  1396. return c
  1397. }
  1398. func waitForActiveTransfer() {
  1399. stats := sftpd.GetConnectionsStats()
  1400. for len(stats) < 1 {
  1401. stats = sftpd.GetConnectionsStats()
  1402. }
  1403. activeTransferFound := false
  1404. for !activeTransferFound {
  1405. stats = sftpd.GetConnectionsStats()
  1406. if len(stats) == 0 {
  1407. break
  1408. }
  1409. for _, stat := range stats {
  1410. if len(stat.Transfers) > 0 {
  1411. activeTransferFound = true
  1412. }
  1413. }
  1414. }
  1415. }