sftpd_test.go 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460
  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. confName = "sftpgo.conf"
  73. )
  74. var (
  75. allPerms = []string{dataprovider.PermAny}
  76. homeBasePath string
  77. configFilePath = filepath.Join(configDir, confName)
  78. )
  79. func TestMain(m *testing.M) {
  80. logfilePath := filepath.Join(configDir, "sftpgo_sftpd_test.log")
  81. logger.InitLogger(logfilePath, 5, 1, 28, false, zerolog.DebugLevel)
  82. config.LoadConfig(configFilePath)
  83. providerConf := config.GetProviderConf()
  84. err := dataprovider.Initialize(providerConf, configDir)
  85. if err != nil {
  86. logger.Warn(logSender, "error initializing data provider: %v", err)
  87. os.Exit(1)
  88. }
  89. dataProvider := dataprovider.GetProvider()
  90. sftpdConf := config.GetSFTPDConfig()
  91. httpdConf := config.GetHTTPDConfig()
  92. router := api.GetHTTPRouter()
  93. // we run the test cases with UploadMode atomic. The non atomic code path
  94. // simply does not execute some code so if it works in atomic mode will
  95. // work in non atomic mode too
  96. sftpdConf.UploadMode = 1
  97. if runtime.GOOS == "windows" {
  98. homeBasePath = "C:\\"
  99. } else {
  100. homeBasePath = "/tmp"
  101. sftpdConf.Actions.ExecuteOn = []string{"download", "upload", "rename", "delete"}
  102. sftpdConf.Actions.Command = "/bin/true"
  103. sftpdConf.Actions.HTTPNotificationURL = "http://127.0.0.1:8080/"
  104. }
  105. sftpd.SetDataProvider(dataProvider)
  106. api.SetDataProvider(dataProvider)
  107. go func() {
  108. logger.Debug(logSender, "initializing SFTP server with config %+v", sftpdConf)
  109. if err := sftpdConf.Initialize(configDir); err != nil {
  110. logger.Error(logSender, "could not start SFTP server: %v", err)
  111. }
  112. }()
  113. go func() {
  114. logger.Debug(logSender, "initializing HTTP server with config %+v", httpdConf)
  115. s := &http.Server{
  116. Addr: fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort),
  117. Handler: router,
  118. ReadTimeout: 300 * time.Second,
  119. WriteTimeout: 300 * time.Second,
  120. MaxHeaderBytes: 1 << 20, // 1MB
  121. }
  122. if err := s.ListenAndServe(); err != nil {
  123. logger.Error(logSender, "could not start HTTP server: %v", err)
  124. }
  125. }()
  126. waitTCPListening(fmt.Sprintf("%s:%d", sftpdConf.BindAddress, sftpdConf.BindPort))
  127. waitTCPListening(fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort))
  128. exitCode := m.Run()
  129. os.Remove(logfilePath)
  130. os.Exit(exitCode)
  131. }
  132. func TestInitialization(t *testing.T) {
  133. config.LoadConfig(configFilePath)
  134. sftpdConf := config.GetSFTPDConfig()
  135. sftpdConf.Umask = "invalid umask"
  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.Remove(testFileName + ".link")
  297. if err != nil {
  298. t.Errorf("error removing symlink: %v", err)
  299. }
  300. err = client.Remove(testFileName)
  301. if err != nil {
  302. t.Errorf("error removing uploaded file: %v", err)
  303. }
  304. }
  305. _, err = api.RemoveUser(user, http.StatusOK)
  306. if err != nil {
  307. t.Errorf("unable to remove user: %v", err)
  308. }
  309. }
  310. func TestStat(t *testing.T) {
  311. usePubKey := false
  312. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  313. if err != nil {
  314. t.Errorf("unable to add user: %v", err)
  315. }
  316. client, err := getSftpClient(user, usePubKey)
  317. if err != nil {
  318. t.Errorf("unable to create sftp client: %v", err)
  319. } else {
  320. defer client.Close()
  321. testFileName := "test_file.dat"
  322. testFilePath := filepath.Join(homeBasePath, testFileName)
  323. testFileSize := int64(65535)
  324. err = createTestFile(testFilePath, testFileSize)
  325. if err != nil {
  326. t.Errorf("unable to create test file: %v", err)
  327. }
  328. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  329. if err != nil {
  330. t.Errorf("file upload error: %v", err)
  331. }
  332. fi, err := client.Lstat(testFileName)
  333. if err != nil {
  334. t.Errorf("stat error: %v", err)
  335. }
  336. err = client.Chown(testFileName, 1000, 1000)
  337. if err != nil {
  338. t.Errorf("chown error: %v", err)
  339. }
  340. err = client.Chmod(testFileName, 0600)
  341. if err != nil {
  342. t.Errorf("chmod error: %v", err)
  343. }
  344. newFi, err := client.Lstat(testFileName)
  345. if err != nil {
  346. t.Errorf("stat error: %v", err)
  347. }
  348. if fi.Mode().Perm() != newFi.Mode().Perm() {
  349. t.Errorf("stat must remain unchanged")
  350. }
  351. _, err = client.ReadLink(testFileName)
  352. if err == nil {
  353. t.Errorf("readlink is not supported and must fail")
  354. }
  355. err = client.Remove(testFileName)
  356. if err != nil {
  357. t.Errorf("error removing uploaded file: %v", err)
  358. }
  359. }
  360. _, err = api.RemoveUser(user, http.StatusOK)
  361. if err != nil {
  362. t.Errorf("unable to remove user: %v", err)
  363. }
  364. }
  365. // basic tests to verify virtual chroot, should be improved to cover more cases ...
  366. func TestEscapeHomeDir(t *testing.T) {
  367. usePubKey := true
  368. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  369. if err != nil {
  370. t.Errorf("unable to add user: %v", err)
  371. }
  372. client, err := getSftpClient(user, usePubKey)
  373. if err != nil {
  374. t.Errorf("unable to create sftp client: %v", err)
  375. } else {
  376. defer client.Close()
  377. _, err := client.Getwd()
  378. if err != nil {
  379. t.Errorf("unable to get working dir: %v", err)
  380. }
  381. testDir := "testDir"
  382. linkPath := filepath.Join(homeBasePath, defaultUsername, testDir)
  383. err = os.Symlink(homeBasePath, linkPath)
  384. if err != nil {
  385. t.Errorf("error making local symlink: %v", err)
  386. }
  387. _, err = client.ReadDir(testDir)
  388. if err == nil {
  389. t.Errorf("reading a symbolic link outside home dir should not succeeded")
  390. }
  391. os.Remove(linkPath)
  392. testFileName := "test_file.dat"
  393. testFilePath := filepath.Join(homeBasePath, testFileName)
  394. testFileSize := int64(65535)
  395. err = createTestFile(testFilePath, testFileSize)
  396. if err != nil {
  397. t.Errorf("unable to create test file: %v", err)
  398. }
  399. remoteDestPath := filepath.Join("..", "..", testFileName)
  400. err = sftpUploadFile(testFilePath, remoteDestPath, testFileSize, client)
  401. if err != nil {
  402. t.Errorf("file upload error: %v", err)
  403. }
  404. _, err = client.Lstat(testFileName)
  405. if err != nil {
  406. t.Errorf("file stat error: %v the file was created outside the user dir!", err)
  407. }
  408. err = client.Remove(testFileName)
  409. if err != nil {
  410. t.Errorf("error removing uploaded file: %v", err)
  411. }
  412. linkPath = filepath.Join(homeBasePath, defaultUsername, testFileName)
  413. err = os.Symlink(homeBasePath, linkPath)
  414. if err != nil {
  415. t.Errorf("error making local symlink: %v", err)
  416. }
  417. err = sftpDownloadFile(testFileName, testFilePath, 0, client)
  418. if err == nil {
  419. t.Errorf("download file outside home dir must fail")
  420. }
  421. err = sftpUploadFile(testFilePath, remoteDestPath, testFileSize, client)
  422. if err == nil {
  423. t.Errorf("overwrite a file outside home dir must fail")
  424. }
  425. err = client.Chmod(remoteDestPath, 0644)
  426. if err == nil {
  427. t.Errorf("setstat on a file outside home dir must fail")
  428. }
  429. os.Remove(linkPath)
  430. }
  431. _, err = api.RemoveUser(user, http.StatusOK)
  432. if err != nil {
  433. t.Errorf("unable to remove user: %v", err)
  434. }
  435. }
  436. func TestHomeSpecialChars(t *testing.T) {
  437. usePubKey := true
  438. u := getTestUser(usePubKey)
  439. u.HomeDir = filepath.Join(homeBasePath, "abc açà#&%lk")
  440. user, _, err := api.AddUser(u, http.StatusOK)
  441. if err != nil {
  442. t.Errorf("unable to add user: %v", err)
  443. }
  444. client, err := getSftpClient(user, usePubKey)
  445. if err != nil {
  446. t.Errorf("unable to create sftp client: %v", err)
  447. } else {
  448. defer client.Close()
  449. _, err := client.Getwd()
  450. if err != nil {
  451. t.Errorf("unable to get working dir: %v", err)
  452. }
  453. testFileName := "test_file.dat"
  454. testFilePath := filepath.Join(homeBasePath, testFileName)
  455. testFileSize := int64(65535)
  456. err = createTestFile(testFilePath, testFileSize)
  457. if err != nil {
  458. t.Errorf("unable to create test file: %v", err)
  459. }
  460. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  461. if err != nil {
  462. t.Errorf("file upload error: %v", err)
  463. }
  464. files, err := client.ReadDir(".")
  465. if err != nil {
  466. t.Errorf("unable to read remote dir: %v", err)
  467. }
  468. if len(files) < 1 {
  469. t.Errorf("expected at least 1 file in this dir")
  470. }
  471. err = client.Remove(testFileName)
  472. if err != nil {
  473. t.Errorf("error removing uploaded file: %v", err)
  474. }
  475. }
  476. _, err = api.RemoveUser(user, http.StatusOK)
  477. if err != nil {
  478. t.Errorf("unable to remove user: %v", err)
  479. }
  480. }
  481. func TestLogin(t *testing.T) {
  482. u := getTestUser(false)
  483. u.PublicKey = []string{testPubKey}
  484. user, _, err := api.AddUser(u, http.StatusOK)
  485. if err != nil {
  486. t.Errorf("unable to add user: %v", err)
  487. }
  488. client, err := getSftpClient(user, false)
  489. if err != nil {
  490. t.Errorf("unable to create sftp client: %v", err)
  491. } else {
  492. defer client.Close()
  493. _, err := client.Getwd()
  494. if err != nil {
  495. t.Errorf("sftp client with valid password must work")
  496. }
  497. }
  498. client, err = getSftpClient(user, true)
  499. if err != nil {
  500. t.Errorf("unable to create sftp client: %v", err)
  501. } else {
  502. defer client.Close()
  503. _, err := client.Getwd()
  504. if err != nil {
  505. t.Errorf("sftp client with valid public key must work")
  506. }
  507. }
  508. user.Password = "invalid password"
  509. client, err = getSftpClient(user, false)
  510. if err == nil {
  511. t.Errorf("login with invalid password must fail")
  512. defer client.Close()
  513. }
  514. // testPubKey1 is not authorized
  515. user.PublicKey = []string{testPubKey1}
  516. user.Password = ""
  517. _, _, err = api.UpdateUser(user, http.StatusOK)
  518. if err != nil {
  519. t.Errorf("unable to update user: %v", err)
  520. }
  521. client, err = getSftpClient(user, true)
  522. if err == nil {
  523. t.Errorf("login with invalid public key must fail")
  524. defer client.Close()
  525. }
  526. // login a user with multiple public keys, only the second one is valid
  527. user.PublicKey = []string{testPubKey1, testPubKey}
  528. user.Password = ""
  529. _, _, err = api.UpdateUser(user, http.StatusOK)
  530. if err != nil {
  531. t.Errorf("unable to update user: %v", err)
  532. }
  533. client, err = getSftpClient(user, true)
  534. if err != nil {
  535. t.Errorf("unable to create sftp client: %v", err)
  536. } else {
  537. defer client.Close()
  538. _, err := client.Getwd()
  539. if err != nil {
  540. t.Errorf("sftp client with multiple public key must work if at least one public key is valid")
  541. }
  542. }
  543. _, err = api.RemoveUser(user, http.StatusOK)
  544. if err != nil {
  545. t.Errorf("unable to remove user: %v", err)
  546. }
  547. }
  548. func TestLoginAfterUserUpdateEmptyPwd(t *testing.T) {
  549. usePubKey := false
  550. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  551. if err != nil {
  552. t.Errorf("unable to add user: %v", err)
  553. }
  554. user.Password = ""
  555. user.PublicKey = []string{}
  556. // password and public key should remain unchanged
  557. _, _, err = api.UpdateUser(user, http.StatusOK)
  558. if err != nil {
  559. t.Errorf("unable to update user: %v", err)
  560. }
  561. client, err := getSftpClient(user, usePubKey)
  562. if err != nil {
  563. t.Errorf("unable to create sftp client: %v", err)
  564. } else {
  565. defer client.Close()
  566. _, err := client.Getwd()
  567. if err != nil {
  568. t.Errorf("unable to get working dir: %v", err)
  569. }
  570. _, err = client.ReadDir(".")
  571. if err != nil {
  572. t.Errorf("unable to read remote dir: %v", err)
  573. }
  574. }
  575. _, err = api.RemoveUser(user, http.StatusOK)
  576. if err != nil {
  577. t.Errorf("unable to remove user: %v", err)
  578. }
  579. }
  580. func TestLoginAfterUserUpdateEmptyPubKey(t *testing.T) {
  581. usePubKey := true
  582. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  583. if err != nil {
  584. t.Errorf("unable to add user: %v", err)
  585. }
  586. user.Password = ""
  587. user.PublicKey = []string{}
  588. // password and public key should remain unchanged
  589. _, _, err = api.UpdateUser(user, http.StatusOK)
  590. if err != nil {
  591. t.Errorf("unable to update user: %v", err)
  592. }
  593. client, err := getSftpClient(user, usePubKey)
  594. if err != nil {
  595. t.Errorf("unable to create sftp client: %v", err)
  596. } else {
  597. defer client.Close()
  598. _, err := client.Getwd()
  599. if err != nil {
  600. t.Errorf("unable to get working dir: %v", err)
  601. }
  602. _, err = client.ReadDir(".")
  603. if err != nil {
  604. t.Errorf("unable to read remote dir: %v", err)
  605. }
  606. }
  607. _, err = api.RemoveUser(user, http.StatusOK)
  608. if err != nil {
  609. t.Errorf("unable to remove user: %v", err)
  610. }
  611. }
  612. func TestMaxSessions(t *testing.T) {
  613. usePubKey := false
  614. u := getTestUser(usePubKey)
  615. u.MaxSessions = 1
  616. user, _, err := api.AddUser(u, http.StatusOK)
  617. if err != nil {
  618. t.Errorf("unable to add user: %v", err)
  619. }
  620. client, err := getSftpClient(user, usePubKey)
  621. if err != nil {
  622. t.Errorf("unable to create sftp client: %v", err)
  623. } else {
  624. defer client.Close()
  625. _, err := client.Getwd()
  626. if err != nil {
  627. t.Errorf("unable to get working dir: %v", err)
  628. }
  629. _, err = client.ReadDir(".")
  630. if err != nil {
  631. t.Errorf("unable to read remote dir: %v", err)
  632. }
  633. _, err = getSftpClient(user, usePubKey)
  634. if err == nil {
  635. t.Errorf("max sessions exceeded, new login should not succeed")
  636. }
  637. }
  638. _, err = api.RemoveUser(user, http.StatusOK)
  639. if err != nil {
  640. t.Errorf("unable to remove user: %v", err)
  641. }
  642. }
  643. func TestQuotaFileReplace(t *testing.T) {
  644. usePubKey := false
  645. u := getTestUser(usePubKey)
  646. u.QuotaFiles = 1000
  647. user, _, err := api.AddUser(u, http.StatusOK)
  648. if err != nil {
  649. t.Errorf("unable to add user: %v", err)
  650. }
  651. testFileSize := int64(65535)
  652. testFileName := "test_file.dat"
  653. testFilePath := filepath.Join(homeBasePath, testFileName)
  654. client, err := getSftpClient(user, usePubKey)
  655. if err != nil {
  656. t.Errorf("unable to create sftp client: %v", err)
  657. } else {
  658. defer client.Close()
  659. expectedQuotaSize := user.UsedQuotaSize + testFileSize
  660. expectedQuotaFiles := user.UsedQuotaFiles + 1
  661. err = createTestFile(testFilePath, testFileSize)
  662. if err != nil {
  663. t.Errorf("unable to create test file: %v", err)
  664. }
  665. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  666. if err != nil {
  667. t.Errorf("file upload error: %v", err)
  668. }
  669. user, _, err = api.GetUserByID(user.ID, http.StatusOK)
  670. if err != nil {
  671. t.Errorf("error getting user: %v", err)
  672. }
  673. // now replace the same file, the quota must not change
  674. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  675. if err != nil {
  676. t.Errorf("file upload error: %v", err)
  677. }
  678. user, _, err = api.GetUserByID(user.ID, http.StatusOK)
  679. if err != nil {
  680. t.Errorf("error getting user: %v", err)
  681. }
  682. if expectedQuotaFiles != user.UsedQuotaFiles {
  683. t.Errorf("quota files does not match, expected: %v, actual: %v", expectedQuotaFiles, user.UsedQuotaFiles)
  684. }
  685. if expectedQuotaSize != user.UsedQuotaSize {
  686. t.Errorf("quota size does not match, expected: %v, actual: %v", expectedQuotaSize, user.UsedQuotaSize)
  687. }
  688. }
  689. // now set a quota size restriction and upload the same fail, upload should fail for space limit exceeded
  690. user.QuotaSize = testFileSize - 1
  691. user, _, err = api.UpdateUser(user, http.StatusOK)
  692. if err != nil {
  693. t.Errorf("error updating user: %v", err)
  694. }
  695. client, err = getSftpClient(user, usePubKey)
  696. if err != nil {
  697. t.Errorf("unable to create sftp client: %v", err)
  698. } else {
  699. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  700. if err == nil {
  701. t.Errorf("quota size exceeded, file upload must fail")
  702. }
  703. err = client.Remove(testFileName)
  704. if err != nil {
  705. t.Errorf("error removing uploaded file: %v", err)
  706. }
  707. }
  708. _, err = api.RemoveUser(user, http.StatusOK)
  709. if err != nil {
  710. t.Errorf("unable to remove user: %v", err)
  711. }
  712. }
  713. func TestQuotaScan(t *testing.T) {
  714. usePubKey := false
  715. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  716. if err != nil {
  717. t.Errorf("unable to add user: %v", err)
  718. }
  719. testFileSize := int64(65535)
  720. expectedQuotaSize := user.UsedQuotaSize + testFileSize
  721. expectedQuotaFiles := user.UsedQuotaFiles + 1
  722. client, err := getSftpClient(user, usePubKey)
  723. if err != nil {
  724. t.Errorf("unable to create sftp client: %v", err)
  725. } else {
  726. defer client.Close()
  727. testFileName := "test_file.dat"
  728. testFilePath := filepath.Join(homeBasePath, testFileName)
  729. err = createTestFile(testFilePath, testFileSize)
  730. if err != nil {
  731. t.Errorf("unable to create test file: %v", err)
  732. }
  733. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  734. if err != nil {
  735. t.Errorf("file upload error: %v", err)
  736. }
  737. }
  738. _, err = api.RemoveUser(user, http.StatusOK)
  739. if err != nil {
  740. t.Errorf("unable to remove user: %v", err)
  741. }
  742. // create user with the same home dir, so there is at least an untracked file
  743. user, _, err = api.AddUser(getTestUser(usePubKey), http.StatusOK)
  744. if err != nil {
  745. t.Errorf("unable to add user: %v", err)
  746. }
  747. _, err = api.StartQuotaScan(user, http.StatusCreated)
  748. if err != nil {
  749. t.Errorf("error starting quota scan: %v", err)
  750. }
  751. scans, _, err := api.GetQuotaScans(http.StatusOK)
  752. if err != nil {
  753. t.Errorf("error getting active quota scans: %v", err)
  754. }
  755. for len(scans) > 0 {
  756. scans, _, err = api.GetQuotaScans(http.StatusOK)
  757. if err != nil {
  758. t.Errorf("error getting active quota scans: %v", err)
  759. break
  760. }
  761. }
  762. user, _, err = api.GetUserByID(user.ID, http.StatusOK)
  763. if err != nil {
  764. t.Errorf("error getting user: %v", err)
  765. }
  766. if expectedQuotaFiles != user.UsedQuotaFiles {
  767. t.Errorf("quota files does not match after scan, expected: %v, actual: %v", expectedQuotaFiles, user.UsedQuotaFiles)
  768. }
  769. if expectedQuotaSize != user.UsedQuotaSize {
  770. t.Errorf("quota size does not match after scan, expected: %v, actual: %v", expectedQuotaSize, user.UsedQuotaSize)
  771. }
  772. _, err = api.RemoveUser(user, http.StatusOK)
  773. if err != nil {
  774. t.Errorf("unable to remove user: %v", err)
  775. }
  776. }
  777. func TestMultipleQuotaScans(t *testing.T) {
  778. if !sftpd.AddQuotaScan(defaultUsername) {
  779. t.Errorf("add quota failed")
  780. }
  781. if sftpd.AddQuotaScan(defaultUsername) {
  782. t.Errorf("add quota must fail if another scan is already active")
  783. }
  784. sftpd.RemoveQuotaScan(defaultPassword)
  785. }
  786. func TestQuotaSize(t *testing.T) {
  787. usePubKey := false
  788. testFileSize := int64(65535)
  789. u := getTestUser(usePubKey)
  790. u.QuotaFiles = 1
  791. u.QuotaSize = testFileSize - 1
  792. user, _, err := api.AddUser(u, http.StatusOK)
  793. if err != nil {
  794. t.Errorf("unable to add user: %v", err)
  795. }
  796. client, err := getSftpClient(user, usePubKey)
  797. if err != nil {
  798. t.Errorf("unable to create sftp client: %v", err)
  799. } else {
  800. defer client.Close()
  801. testFileName := "test_file.dat"
  802. testFilePath := filepath.Join(homeBasePath, testFileName)
  803. err = createTestFile(testFilePath, testFileSize)
  804. if err != nil {
  805. t.Errorf("unable to create test file: %v", err)
  806. }
  807. err = sftpUploadFile(testFilePath, testFileName+".quota", testFileSize, client)
  808. if err != nil {
  809. t.Errorf("file upload error: %v", err)
  810. }
  811. err = sftpUploadFile(testFilePath, testFileName+".quota.1", testFileSize, client)
  812. if err == nil {
  813. t.Errorf("user is over quota file upload must fail")
  814. }
  815. err = client.Remove(testFileName + ".quota")
  816. if err != nil {
  817. t.Errorf("error removing uploaded file: %v", err)
  818. }
  819. }
  820. _, err = api.RemoveUser(user, http.StatusOK)
  821. if err != nil {
  822. t.Errorf("unable to remove user: %v", err)
  823. }
  824. }
  825. func TestBandwidthAndConnections(t *testing.T) {
  826. usePubKey := false
  827. testFileSize := int64(131072)
  828. u := getTestUser(usePubKey)
  829. u.UploadBandwidth = 30
  830. u.DownloadBandwidth = 25
  831. wantedUploadElapsed := 1000 * (testFileSize / 1000) / u.UploadBandwidth
  832. wantedDownloadElapsed := 1000 * (testFileSize / 1000) / u.DownloadBandwidth
  833. // 100 ms tolerance
  834. wantedUploadElapsed -= 100
  835. wantedDownloadElapsed -= 100
  836. user, _, err := api.AddUser(u, http.StatusOK)
  837. if err != nil {
  838. t.Errorf("unable to add user: %v", err)
  839. }
  840. client, err := getSftpClient(user, usePubKey)
  841. if err != nil {
  842. t.Errorf("unable to create sftp client: %v", err)
  843. } else {
  844. defer client.Close()
  845. testFileName := "test_file.dat"
  846. testFilePath := filepath.Join(homeBasePath, testFileName)
  847. err = createTestFile(testFilePath, testFileSize)
  848. if err != nil {
  849. t.Errorf("unable to create test file: %v", err)
  850. }
  851. startTime := time.Now()
  852. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  853. if err != nil {
  854. t.Errorf("file upload error: %v", err)
  855. }
  856. elapsed := time.Since(startTime).Nanoseconds() / 1000000
  857. if elapsed < (wantedUploadElapsed) {
  858. t.Errorf("upload bandwidth throttling not respected, elapsed: %v, wanted: %v", elapsed, wantedUploadElapsed)
  859. }
  860. startTime = time.Now()
  861. localDownloadPath := filepath.Join(homeBasePath, "test_download.dat")
  862. c := sftpDownloadNonBlocking(testFileName, localDownloadPath, testFileSize, client)
  863. waitForActiveTransfer()
  864. // wait some additional arbitrary time to wait for transfer activity to happen
  865. // it is need to reach all the code in CheckIdleConnections
  866. time.Sleep(100 * time.Millisecond)
  867. sftpd.CheckIdleConnections()
  868. err = <-c
  869. if err != nil {
  870. t.Errorf("file download error: %v", err)
  871. }
  872. elapsed = time.Since(startTime).Nanoseconds() / 1000000
  873. if elapsed < (wantedDownloadElapsed) {
  874. t.Errorf("download bandwidth throttling not respected, elapsed: %v, wanted: %v", elapsed, wantedDownloadElapsed)
  875. }
  876. // test disconnection
  877. c = sftpUploadNonBlocking(testFilePath, testFileName+"_partial", testFileSize, client)
  878. waitForActiveTransfer()
  879. time.Sleep(100 * time.Millisecond)
  880. sftpd.CheckIdleConnections()
  881. stats := sftpd.GetConnectionsStats()
  882. for _, stat := range stats {
  883. sftpd.CloseActiveConnection(stat.ConnectionID)
  884. }
  885. err = <-c
  886. if err == nil {
  887. t.Errorf("connection closed upload must fail")
  888. }
  889. }
  890. _, err = api.RemoveUser(user, http.StatusOK)
  891. if err != nil {
  892. t.Errorf("unable to remove user: %v", err)
  893. }
  894. }
  895. func TestMissingFile(t *testing.T) {
  896. usePubKey := false
  897. u := getTestUser(usePubKey)
  898. user, _, err := api.AddUser(u, http.StatusOK)
  899. if err != nil {
  900. t.Errorf("unable to add user: %v", err)
  901. }
  902. client, err := getSftpClient(user, usePubKey)
  903. if err != nil {
  904. t.Errorf("unable to create sftp client: %v", err)
  905. } else {
  906. defer client.Close()
  907. localDownloadPath := filepath.Join(homeBasePath, "test_download.dat")
  908. err = sftpDownloadFile("missing_file", localDownloadPath, 0, client)
  909. if err == nil {
  910. t.Errorf("download missing file must fail")
  911. }
  912. }
  913. _, err = api.RemoveUser(user, http.StatusOK)
  914. if err != nil {
  915. t.Errorf("unable to remove user: %v", err)
  916. }
  917. }
  918. func TestOverwriteDirWithFile(t *testing.T) {
  919. usePubKey := false
  920. u := getTestUser(usePubKey)
  921. user, _, err := api.AddUser(u, http.StatusOK)
  922. if err != nil {
  923. t.Errorf("unable to add user: %v", err)
  924. }
  925. client, err := getSftpClient(user, usePubKey)
  926. if err != nil {
  927. t.Errorf("unable to create sftp client: %v", err)
  928. } else {
  929. defer client.Close()
  930. testFileSize := int64(65535)
  931. testFileName := "test_file.dat"
  932. testDirName := "test_dir"
  933. testFilePath := filepath.Join(homeBasePath, testFileName)
  934. err = createTestFile(testFilePath, testFileSize)
  935. if err != nil {
  936. t.Errorf("unable to create test file: %v", err)
  937. }
  938. err = client.Mkdir(testDirName)
  939. if err != nil {
  940. t.Errorf("mkdir error: %v", err)
  941. }
  942. err = sftpUploadFile(testFilePath, testDirName, testFileSize, client)
  943. if err == nil {
  944. t.Errorf("copying a file over an existing dir must fail")
  945. }
  946. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  947. if err != nil {
  948. t.Errorf("file upload error: %v", err)
  949. }
  950. err = client.Rename(testFileName, testDirName)
  951. if err == nil {
  952. t.Errorf("rename a file over an existing dir must fail")
  953. }
  954. err = client.RemoveDirectory(testDirName)
  955. if err != nil {
  956. t.Errorf("dir remove error: %v", err)
  957. }
  958. err = client.Remove(testFileName)
  959. if err != nil {
  960. t.Errorf("error removing uploaded file: %v", err)
  961. }
  962. }
  963. _, err = api.RemoveUser(user, http.StatusOK)
  964. if err != nil {
  965. t.Errorf("unable to remove user: %v", err)
  966. }
  967. }
  968. func TestPermList(t *testing.T) {
  969. usePubKey := true
  970. u := getTestUser(usePubKey)
  971. u.Permissions = []string{dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermDelete, dataprovider.PermRename,
  972. dataprovider.PermCreateDirs, dataprovider.PermCreateSymlinks}
  973. user, _, err := api.AddUser(u, http.StatusOK)
  974. if err != nil {
  975. t.Errorf("unable to add user: %v", err)
  976. }
  977. client, err := getSftpClient(user, usePubKey)
  978. if err != nil {
  979. t.Errorf("unable to create sftp client: %v", err)
  980. } else {
  981. defer client.Close()
  982. _, err = client.ReadDir(".")
  983. if err == nil {
  984. t.Errorf("read remote dir without permission should not succeed")
  985. }
  986. _, err = client.Stat("test_file")
  987. if err == nil {
  988. t.Errorf("stat remote file without permission should not succeed")
  989. }
  990. }
  991. _, err = api.RemoveUser(user, http.StatusOK)
  992. if err != nil {
  993. t.Errorf("unable to remove user: %v", err)
  994. }
  995. }
  996. func TestPermDownload(t *testing.T) {
  997. usePubKey := true
  998. u := getTestUser(usePubKey)
  999. u.Permissions = []string{dataprovider.PermListItems, dataprovider.PermUpload, dataprovider.PermDelete, dataprovider.PermRename,
  1000. dataprovider.PermCreateDirs, dataprovider.PermCreateSymlinks}
  1001. user, _, err := api.AddUser(u, http.StatusOK)
  1002. if err != nil {
  1003. t.Errorf("unable to add user: %v", err)
  1004. }
  1005. client, err := getSftpClient(user, usePubKey)
  1006. if err != nil {
  1007. t.Errorf("unable to create sftp client: %v", err)
  1008. } else {
  1009. defer client.Close()
  1010. testFileName := "test_file.dat"
  1011. testFilePath := filepath.Join(homeBasePath, testFileName)
  1012. testFileSize := int64(65535)
  1013. err = createTestFile(testFilePath, testFileSize)
  1014. if err != nil {
  1015. t.Errorf("unable to create test file: %v", err)
  1016. }
  1017. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  1018. if err != nil {
  1019. t.Errorf("file upload error: %v", err)
  1020. }
  1021. localDownloadPath := filepath.Join(homeBasePath, "test_download.dat")
  1022. err = sftpDownloadFile(testFileName, localDownloadPath, testFileSize, client)
  1023. if err == nil {
  1024. t.Errorf("file download without permission should not succeed")
  1025. }
  1026. err = client.Remove(testFileName)
  1027. if err != nil {
  1028. t.Errorf("error removing uploaded file: %v", err)
  1029. }
  1030. }
  1031. _, err = api.RemoveUser(user, http.StatusOK)
  1032. if err != nil {
  1033. t.Errorf("unable to remove user: %v", err)
  1034. }
  1035. }
  1036. func TestPermUpload(t *testing.T) {
  1037. usePubKey := false
  1038. u := getTestUser(usePubKey)
  1039. u.Permissions = []string{dataprovider.PermListItems, dataprovider.PermDownload, dataprovider.PermDelete, dataprovider.PermRename,
  1040. dataprovider.PermCreateDirs, dataprovider.PermCreateSymlinks}
  1041. user, _, err := api.AddUser(u, http.StatusOK)
  1042. if err != nil {
  1043. t.Errorf("unable to add user: %v", err)
  1044. }
  1045. client, err := getSftpClient(user, usePubKey)
  1046. if err != nil {
  1047. t.Errorf("unable to create sftp client: %v", err)
  1048. } else {
  1049. defer client.Close()
  1050. testFileName := "test_file.dat"
  1051. testFilePath := filepath.Join(homeBasePath, testFileName)
  1052. testFileSize := int64(65535)
  1053. err = createTestFile(testFilePath, testFileSize)
  1054. if err != nil {
  1055. t.Errorf("unable to create test file: %v", err)
  1056. }
  1057. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  1058. if err == nil {
  1059. t.Errorf("file upload without permission should not succeed")
  1060. }
  1061. }
  1062. _, err = api.RemoveUser(user, http.StatusOK)
  1063. if err != nil {
  1064. t.Errorf("unable to remove user: %v", err)
  1065. }
  1066. }
  1067. func TestPermDelete(t *testing.T) {
  1068. usePubKey := false
  1069. u := getTestUser(usePubKey)
  1070. u.Permissions = []string{dataprovider.PermListItems, dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermRename,
  1071. dataprovider.PermCreateDirs, dataprovider.PermCreateSymlinks}
  1072. user, _, err := api.AddUser(u, http.StatusOK)
  1073. if err != nil {
  1074. t.Errorf("unable to add user: %v", err)
  1075. }
  1076. client, err := getSftpClient(user, usePubKey)
  1077. if err != nil {
  1078. t.Errorf("unable to create sftp client: %v", err)
  1079. } else {
  1080. defer client.Close()
  1081. testFileName := "test_file.dat"
  1082. testFilePath := filepath.Join(homeBasePath, testFileName)
  1083. testFileSize := int64(65535)
  1084. err = createTestFile(testFilePath, testFileSize)
  1085. if err != nil {
  1086. t.Errorf("unable to create test file: %v", err)
  1087. }
  1088. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  1089. if err != nil {
  1090. t.Errorf("file upload error: %v", err)
  1091. }
  1092. err = client.Remove(testFileName)
  1093. if err == nil {
  1094. t.Errorf("delete without permission should not succeed")
  1095. }
  1096. }
  1097. _, err = api.RemoveUser(user, http.StatusOK)
  1098. if err != nil {
  1099. t.Errorf("unable to remove user: %v", err)
  1100. }
  1101. }
  1102. func TestPermRename(t *testing.T) {
  1103. usePubKey := false
  1104. u := getTestUser(usePubKey)
  1105. u.Permissions = []string{dataprovider.PermListItems, dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermDelete,
  1106. dataprovider.PermCreateDirs, dataprovider.PermCreateSymlinks}
  1107. user, _, err := api.AddUser(u, http.StatusOK)
  1108. if err != nil {
  1109. t.Errorf("unable to add user: %v", err)
  1110. }
  1111. client, err := getSftpClient(user, usePubKey)
  1112. if err != nil {
  1113. t.Errorf("unable to create sftp client: %v", err)
  1114. } else {
  1115. defer client.Close()
  1116. testFileName := "test_file.dat"
  1117. testFilePath := filepath.Join(homeBasePath, testFileName)
  1118. testFileSize := int64(65535)
  1119. err = createTestFile(testFilePath, testFileSize)
  1120. if err != nil {
  1121. t.Errorf("unable to create test file: %v", err)
  1122. }
  1123. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  1124. if err != nil {
  1125. t.Errorf("file upload error: %v", err)
  1126. }
  1127. err = client.Rename(testFileName, testFileName+".rename")
  1128. if err == nil {
  1129. t.Errorf("rename without permission should not succeed")
  1130. }
  1131. err = client.Remove(testFileName)
  1132. if err != nil {
  1133. t.Errorf("error removing uploaded file: %v", err)
  1134. }
  1135. }
  1136. _, err = api.RemoveUser(user, http.StatusOK)
  1137. if err != nil {
  1138. t.Errorf("unable to remove user: %v", err)
  1139. }
  1140. }
  1141. func TestPermCreateDirs(t *testing.T) {
  1142. usePubKey := false
  1143. u := getTestUser(usePubKey)
  1144. u.Permissions = []string{dataprovider.PermListItems, dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermDelete,
  1145. dataprovider.PermRename, dataprovider.PermCreateSymlinks}
  1146. user, _, err := api.AddUser(u, http.StatusOK)
  1147. if err != nil {
  1148. t.Errorf("unable to add user: %v", err)
  1149. }
  1150. client, err := getSftpClient(user, usePubKey)
  1151. if err != nil {
  1152. t.Errorf("unable to create sftp client: %v", err)
  1153. } else {
  1154. defer client.Close()
  1155. err = client.Mkdir("testdir")
  1156. if err == nil {
  1157. t.Errorf("mkdir without permission should not succeed")
  1158. }
  1159. testFileName := "test_file.dat"
  1160. testFilePath := filepath.Join(homeBasePath, testFileName)
  1161. testFileSize := int64(65535)
  1162. err = createTestFile(testFilePath, testFileSize)
  1163. if err != nil {
  1164. t.Errorf("unable to create test file: %v", err)
  1165. }
  1166. err = sftpUploadFile(testFilePath, "/dir/subdir/test_file.dat", testFileSize, client)
  1167. if err == nil {
  1168. t.Errorf("mkdir without permission should not succeed")
  1169. }
  1170. }
  1171. _, err = api.RemoveUser(user, http.StatusOK)
  1172. if err != nil {
  1173. t.Errorf("unable to remove user: %v", err)
  1174. }
  1175. }
  1176. func TestPermSymlink(t *testing.T) {
  1177. usePubKey := false
  1178. u := getTestUser(usePubKey)
  1179. u.Permissions = []string{dataprovider.PermListItems, dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermDelete,
  1180. dataprovider.PermRename, dataprovider.PermCreateDirs}
  1181. user, _, err := api.AddUser(u, http.StatusOK)
  1182. if err != nil {
  1183. t.Errorf("unable to add user: %v", err)
  1184. }
  1185. client, err := getSftpClient(user, usePubKey)
  1186. if err != nil {
  1187. t.Errorf("unable to create sftp client: %v", err)
  1188. } else {
  1189. defer client.Close()
  1190. testFileName := "test_file.dat"
  1191. testFilePath := filepath.Join(homeBasePath, testFileName)
  1192. testFileSize := int64(65535)
  1193. err = createTestFile(testFilePath, testFileSize)
  1194. if err != nil {
  1195. t.Errorf("unable to create test file: %v", err)
  1196. }
  1197. err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
  1198. if err != nil {
  1199. t.Errorf("file upload error: %v", err)
  1200. }
  1201. err = client.Symlink(testFilePath, testFilePath+".symlink")
  1202. if err == nil {
  1203. t.Errorf("symlink without permission should not succeed")
  1204. }
  1205. err = client.Remove(testFileName)
  1206. if err != nil {
  1207. t.Errorf("error removing uploaded file: %v", err)
  1208. }
  1209. }
  1210. _, err = api.RemoveUser(user, http.StatusOK)
  1211. if err != nil {
  1212. t.Errorf("unable to remove user: %v", err)
  1213. }
  1214. }
  1215. func TestSSHConnection(t *testing.T) {
  1216. usePubKey := false
  1217. user, _, err := api.AddUser(getTestUser(usePubKey), http.StatusOK)
  1218. if err != nil {
  1219. t.Errorf("unable to add user: %v", err)
  1220. }
  1221. err = doSSH(user, usePubKey)
  1222. if err == nil {
  1223. t.Errorf("ssh connection must fail: %v", err)
  1224. }
  1225. _, err = api.RemoveUser(user, http.StatusOK)
  1226. if err != nil {
  1227. t.Errorf("unable to remove user: %v", err)
  1228. }
  1229. }
  1230. func waitTCPListening(address string) {
  1231. for {
  1232. conn, err := net.Dial("tcp", address)
  1233. if err != nil {
  1234. logger.WarnToConsole("tcp server %v not listening: %v\n", address, err)
  1235. time.Sleep(100 * time.Millisecond)
  1236. continue
  1237. }
  1238. logger.InfoToConsole("tcp server %v now listening\n", address)
  1239. defer conn.Close()
  1240. break
  1241. }
  1242. }
  1243. func getTestUser(usePubKey bool) dataprovider.User {
  1244. user := dataprovider.User{
  1245. Username: defaultUsername,
  1246. Password: defaultPassword,
  1247. HomeDir: filepath.Join(homeBasePath, defaultUsername),
  1248. Permissions: allPerms,
  1249. }
  1250. if usePubKey {
  1251. user.PublicKey = []string{testPubKey}
  1252. user.Password = ""
  1253. }
  1254. return user
  1255. }
  1256. func doSSH(user dataprovider.User, usePubKey bool) error {
  1257. var sshSession *ssh.Session
  1258. config := &ssh.ClientConfig{
  1259. User: defaultUsername,
  1260. HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
  1261. return nil
  1262. },
  1263. }
  1264. if usePubKey {
  1265. key, err := ssh.ParsePrivateKey([]byte(testPrivateKey))
  1266. if err != nil {
  1267. return err
  1268. }
  1269. config.Auth = []ssh.AuthMethod{ssh.PublicKeys(key)}
  1270. } else {
  1271. config.Auth = []ssh.AuthMethod{ssh.Password(defaultPassword)}
  1272. }
  1273. conn, err := ssh.Dial("tcp", sftpServerAddr, config)
  1274. if err != nil {
  1275. return err
  1276. }
  1277. defer conn.Close()
  1278. sshSession, err = conn.NewSession()
  1279. if err != nil {
  1280. return err
  1281. }
  1282. _, err = sshSession.CombinedOutput("ls")
  1283. return err
  1284. }
  1285. func getSftpClient(user dataprovider.User, usePubKey bool) (*sftp.Client, error) {
  1286. var sftpClient *sftp.Client
  1287. config := &ssh.ClientConfig{
  1288. User: user.Username,
  1289. HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
  1290. return nil
  1291. },
  1292. }
  1293. if usePubKey {
  1294. key, err := ssh.ParsePrivateKey([]byte(testPrivateKey))
  1295. if err != nil {
  1296. return nil, err
  1297. }
  1298. config.Auth = []ssh.AuthMethod{ssh.PublicKeys(key)}
  1299. } else {
  1300. if len(user.Password) > 0 {
  1301. config.Auth = []ssh.AuthMethod{ssh.Password(user.Password)}
  1302. } else {
  1303. config.Auth = []ssh.AuthMethod{ssh.Password(defaultPassword)}
  1304. }
  1305. }
  1306. conn, err := ssh.Dial("tcp", sftpServerAddr, config)
  1307. if err != nil {
  1308. return sftpClient, err
  1309. }
  1310. sftpClient, err = sftp.NewClient(conn)
  1311. return sftpClient, err
  1312. }
  1313. func createTestFile(path string, size int64) error {
  1314. content := make([]byte, size)
  1315. _, err := rand.Read(content)
  1316. if err != nil {
  1317. return err
  1318. }
  1319. return ioutil.WriteFile(path, content, 0666)
  1320. }
  1321. func sftpUploadFile(localSourcePath string, remoteDestPath string, expectedSize int64, client *sftp.Client) error {
  1322. srcFile, err := os.Open(localSourcePath)
  1323. if err != nil {
  1324. return err
  1325. }
  1326. defer srcFile.Close()
  1327. destFile, err := client.Create(remoteDestPath)
  1328. if err != nil {
  1329. return err
  1330. }
  1331. _, err = io.Copy(destFile, srcFile)
  1332. if err != nil {
  1333. destFile.Close()
  1334. return err
  1335. }
  1336. // we need to close the file to trigger the close method on server
  1337. // we cannot defer closing or Lstat will fail for upload atomic mode
  1338. destFile.Close()
  1339. if expectedSize > 0 {
  1340. fi, err := client.Lstat(remoteDestPath)
  1341. if err != nil {
  1342. return err
  1343. }
  1344. if fi.Size() != expectedSize {
  1345. return fmt.Errorf("uploaded file size does not match, actual: %v, expected: %v", fi.Size(), expectedSize)
  1346. }
  1347. }
  1348. return err
  1349. }
  1350. func sftpDownloadFile(remoteSourcePath string, localDestPath string, expectedSize int64, client *sftp.Client) error {
  1351. downloadDest, err := os.Create(localDestPath)
  1352. if err != nil {
  1353. return err
  1354. }
  1355. defer downloadDest.Close()
  1356. sftpSrcFile, err := client.Open(remoteSourcePath)
  1357. if err != nil {
  1358. return err
  1359. }
  1360. defer sftpSrcFile.Close()
  1361. _, err = io.Copy(downloadDest, sftpSrcFile)
  1362. if err != nil {
  1363. return err
  1364. }
  1365. err = downloadDest.Sync()
  1366. if err != nil {
  1367. return err
  1368. }
  1369. if expectedSize > 0 {
  1370. fi, err := downloadDest.Stat()
  1371. if err != nil {
  1372. return err
  1373. }
  1374. if fi.Size() != expectedSize {
  1375. return fmt.Errorf("downloaded file size does not match, actual: %v, expected: %v", fi.Size(), expectedSize)
  1376. }
  1377. }
  1378. return err
  1379. }
  1380. func sftpUploadNonBlocking(localSourcePath string, remoteDestPath string, expectedSize int64, client *sftp.Client) <-chan error {
  1381. c := make(chan error)
  1382. go func() {
  1383. c <- sftpUploadFile(localSourcePath, remoteDestPath, expectedSize, client)
  1384. }()
  1385. return c
  1386. }
  1387. func sftpDownloadNonBlocking(remoteSourcePath string, localDestPath string, expectedSize int64, client *sftp.Client) <-chan error {
  1388. c := make(chan error)
  1389. go func() {
  1390. c <- sftpDownloadFile(remoteSourcePath, localDestPath, expectedSize, client)
  1391. }()
  1392. return c
  1393. }
  1394. func waitForActiveTransfer() {
  1395. stats := sftpd.GetConnectionsStats()
  1396. for len(stats) < 1 {
  1397. stats = sftpd.GetConnectionsStats()
  1398. }
  1399. activeTransferFound := false
  1400. for !activeTransferFound {
  1401. stats = sftpd.GetConnectionsStats()
  1402. if len(stats) == 0 {
  1403. break
  1404. }
  1405. for _, stat := range stats {
  1406. if len(stat.Transfers) > 0 {
  1407. activeTransferFound = true
  1408. }
  1409. }
  1410. }
  1411. }