server.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. package sftp
  2. // sftp server counterpart
  3. import (
  4. "encoding"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "os"
  10. "path/filepath"
  11. "strconv"
  12. "sync"
  13. "syscall"
  14. "time"
  15. )
  16. const (
  17. // SftpServerWorkerCount defines the number of workers for the SFTP server
  18. SftpServerWorkerCount = 8
  19. )
  20. // Server is an SSH File Transfer Protocol (sftp) server.
  21. // This is intended to provide the sftp subsystem to an ssh server daemon.
  22. // This implementation currently supports most of sftp server protocol version 3,
  23. // as specified at https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt
  24. type Server struct {
  25. *serverConn
  26. debugStream io.Writer
  27. readOnly bool
  28. pktMgr *packetManager
  29. openFiles map[string]*os.File
  30. openFilesLock sync.RWMutex
  31. handleCount int
  32. workDir string
  33. }
  34. func (svr *Server) nextHandle(f *os.File) string {
  35. svr.openFilesLock.Lock()
  36. defer svr.openFilesLock.Unlock()
  37. svr.handleCount++
  38. handle := strconv.Itoa(svr.handleCount)
  39. svr.openFiles[handle] = f
  40. return handle
  41. }
  42. func (svr *Server) closeHandle(handle string) error {
  43. svr.openFilesLock.Lock()
  44. defer svr.openFilesLock.Unlock()
  45. if f, ok := svr.openFiles[handle]; ok {
  46. delete(svr.openFiles, handle)
  47. return f.Close()
  48. }
  49. return EBADF
  50. }
  51. func (svr *Server) getHandle(handle string) (*os.File, bool) {
  52. svr.openFilesLock.RLock()
  53. defer svr.openFilesLock.RUnlock()
  54. f, ok := svr.openFiles[handle]
  55. return f, ok
  56. }
  57. type serverRespondablePacket interface {
  58. encoding.BinaryUnmarshaler
  59. id() uint32
  60. respond(svr *Server) responsePacket
  61. }
  62. // NewServer creates a new Server instance around the provided streams, serving
  63. // content from the root of the filesystem. Optionally, ServerOption
  64. // functions may be specified to further configure the Server.
  65. //
  66. // A subsequent call to Serve() is required to begin serving files over SFTP.
  67. func NewServer(rwc io.ReadWriteCloser, options ...ServerOption) (*Server, error) {
  68. svrConn := &serverConn{
  69. conn: conn{
  70. Reader: rwc,
  71. WriteCloser: rwc,
  72. },
  73. }
  74. s := &Server{
  75. serverConn: svrConn,
  76. debugStream: ioutil.Discard,
  77. pktMgr: newPktMgr(svrConn),
  78. openFiles: make(map[string]*os.File),
  79. }
  80. for _, o := range options {
  81. if err := o(s); err != nil {
  82. return nil, err
  83. }
  84. }
  85. return s, nil
  86. }
  87. // A ServerOption is a function which applies configuration to a Server.
  88. type ServerOption func(*Server) error
  89. // WithDebug enables Server debugging output to the supplied io.Writer.
  90. func WithDebug(w io.Writer) ServerOption {
  91. return func(s *Server) error {
  92. s.debugStream = w
  93. return nil
  94. }
  95. }
  96. // ReadOnly configures a Server to serve files in read-only mode.
  97. func ReadOnly() ServerOption {
  98. return func(s *Server) error {
  99. s.readOnly = true
  100. return nil
  101. }
  102. }
  103. // WithAllocator enable the allocator.
  104. // After processing a packet we keep in memory the allocated slices
  105. // and we reuse them for new packets.
  106. // The allocator is experimental
  107. func WithAllocator() ServerOption {
  108. return func(s *Server) error {
  109. alloc := newAllocator()
  110. s.pktMgr.alloc = alloc
  111. s.conn.alloc = alloc
  112. return nil
  113. }
  114. }
  115. // WithServerWorkingDirectory sets a working directory to use as base
  116. // for relative paths.
  117. // If unset the default is current working directory (os.Getwd).
  118. func WithServerWorkingDirectory(workDir string) ServerOption {
  119. return func(s *Server) error {
  120. s.workDir = cleanPath(workDir)
  121. return nil
  122. }
  123. }
  124. type rxPacket struct {
  125. pktType fxp
  126. pktBytes []byte
  127. }
  128. // Up to N parallel servers
  129. func (svr *Server) sftpServerWorker(pktChan chan orderedRequest) error {
  130. for pkt := range pktChan {
  131. // readonly checks
  132. readonly := true
  133. switch pkt := pkt.requestPacket.(type) {
  134. case notReadOnly:
  135. readonly = false
  136. case *sshFxpOpenPacket:
  137. readonly = pkt.readonly()
  138. case *sshFxpExtendedPacket:
  139. readonly = pkt.readonly()
  140. }
  141. // If server is operating read-only and a write operation is requested,
  142. // return permission denied
  143. if !readonly && svr.readOnly {
  144. svr.pktMgr.readyPacket(
  145. svr.pktMgr.newOrderedResponse(statusFromError(pkt.id(), syscall.EPERM), pkt.orderID()),
  146. )
  147. continue
  148. }
  149. if err := handlePacket(svr, pkt); err != nil {
  150. return err
  151. }
  152. }
  153. return nil
  154. }
  155. func handlePacket(s *Server, p orderedRequest) error {
  156. var rpkt responsePacket
  157. orderID := p.orderID()
  158. switch p := p.requestPacket.(type) {
  159. case *sshFxInitPacket:
  160. rpkt = &sshFxVersionPacket{
  161. Version: sftpProtocolVersion,
  162. Extensions: sftpExtensions,
  163. }
  164. case *sshFxpStatPacket:
  165. // stat the requested file
  166. info, err := os.Stat(s.toLocalPath(p.Path))
  167. rpkt = &sshFxpStatResponse{
  168. ID: p.ID,
  169. info: info,
  170. }
  171. if err != nil {
  172. rpkt = statusFromError(p.ID, err)
  173. }
  174. case *sshFxpLstatPacket:
  175. // stat the requested file
  176. info, err := os.Lstat(s.toLocalPath(p.Path))
  177. rpkt = &sshFxpStatResponse{
  178. ID: p.ID,
  179. info: info,
  180. }
  181. if err != nil {
  182. rpkt = statusFromError(p.ID, err)
  183. }
  184. case *sshFxpFstatPacket:
  185. f, ok := s.getHandle(p.Handle)
  186. var err error = EBADF
  187. var info os.FileInfo
  188. if ok {
  189. info, err = f.Stat()
  190. rpkt = &sshFxpStatResponse{
  191. ID: p.ID,
  192. info: info,
  193. }
  194. }
  195. if err != nil {
  196. rpkt = statusFromError(p.ID, err)
  197. }
  198. case *sshFxpMkdirPacket:
  199. // TODO FIXME: ignore flags field
  200. err := os.Mkdir(s.toLocalPath(p.Path), 0o755)
  201. rpkt = statusFromError(p.ID, err)
  202. case *sshFxpRmdirPacket:
  203. err := os.Remove(s.toLocalPath(p.Path))
  204. rpkt = statusFromError(p.ID, err)
  205. case *sshFxpRemovePacket:
  206. err := os.Remove(s.toLocalPath(p.Filename))
  207. rpkt = statusFromError(p.ID, err)
  208. case *sshFxpRenamePacket:
  209. err := os.Rename(s.toLocalPath(p.Oldpath), s.toLocalPath(p.Newpath))
  210. rpkt = statusFromError(p.ID, err)
  211. case *sshFxpSymlinkPacket:
  212. err := os.Symlink(s.toLocalPath(p.Targetpath), s.toLocalPath(p.Linkpath))
  213. rpkt = statusFromError(p.ID, err)
  214. case *sshFxpClosePacket:
  215. rpkt = statusFromError(p.ID, s.closeHandle(p.Handle))
  216. case *sshFxpReadlinkPacket:
  217. f, err := os.Readlink(s.toLocalPath(p.Path))
  218. rpkt = &sshFxpNamePacket{
  219. ID: p.ID,
  220. NameAttrs: []*sshFxpNameAttr{
  221. {
  222. Name: f,
  223. LongName: f,
  224. Attrs: emptyFileStat,
  225. },
  226. },
  227. }
  228. if err != nil {
  229. rpkt = statusFromError(p.ID, err)
  230. }
  231. case *sshFxpRealpathPacket:
  232. f, err := filepath.Abs(s.toLocalPath(p.Path))
  233. f = cleanPath(f)
  234. rpkt = &sshFxpNamePacket{
  235. ID: p.ID,
  236. NameAttrs: []*sshFxpNameAttr{
  237. {
  238. Name: f,
  239. LongName: f,
  240. Attrs: emptyFileStat,
  241. },
  242. },
  243. }
  244. if err != nil {
  245. rpkt = statusFromError(p.ID, err)
  246. }
  247. case *sshFxpOpendirPacket:
  248. lp := s.toLocalPath(p.Path)
  249. if stat, err := os.Stat(lp); err != nil {
  250. rpkt = statusFromError(p.ID, err)
  251. } else if !stat.IsDir() {
  252. rpkt = statusFromError(p.ID, &os.PathError{
  253. Path: lp, Err: syscall.ENOTDIR,
  254. })
  255. } else {
  256. rpkt = (&sshFxpOpenPacket{
  257. ID: p.ID,
  258. Path: p.Path,
  259. Pflags: sshFxfRead,
  260. }).respond(s)
  261. }
  262. case *sshFxpReadPacket:
  263. var err error = EBADF
  264. f, ok := s.getHandle(p.Handle)
  265. if ok {
  266. err = nil
  267. data := p.getDataSlice(s.pktMgr.alloc, orderID)
  268. n, _err := f.ReadAt(data, int64(p.Offset))
  269. if _err != nil && (_err != io.EOF || n == 0) {
  270. err = _err
  271. }
  272. rpkt = &sshFxpDataPacket{
  273. ID: p.ID,
  274. Length: uint32(n),
  275. Data: data[:n],
  276. // do not use data[:n:n] here to clamp the capacity, we allocated extra capacity above to avoid reallocations
  277. }
  278. }
  279. if err != nil {
  280. rpkt = statusFromError(p.ID, err)
  281. }
  282. case *sshFxpWritePacket:
  283. f, ok := s.getHandle(p.Handle)
  284. var err error = EBADF
  285. if ok {
  286. _, err = f.WriteAt(p.Data, int64(p.Offset))
  287. }
  288. rpkt = statusFromError(p.ID, err)
  289. case *sshFxpExtendedPacket:
  290. if p.SpecificPacket == nil {
  291. rpkt = statusFromError(p.ID, ErrSSHFxOpUnsupported)
  292. } else {
  293. rpkt = p.respond(s)
  294. }
  295. case serverRespondablePacket:
  296. rpkt = p.respond(s)
  297. default:
  298. return fmt.Errorf("unexpected packet type %T", p)
  299. }
  300. s.pktMgr.readyPacket(s.pktMgr.newOrderedResponse(rpkt, orderID))
  301. return nil
  302. }
  303. // Serve serves SFTP connections until the streams stop or the SFTP subsystem
  304. // is stopped. It returns nil if the server exits cleanly.
  305. func (svr *Server) Serve() error {
  306. defer func() {
  307. if svr.pktMgr.alloc != nil {
  308. svr.pktMgr.alloc.Free()
  309. }
  310. }()
  311. var wg sync.WaitGroup
  312. runWorker := func(ch chan orderedRequest) {
  313. wg.Add(1)
  314. go func() {
  315. defer wg.Done()
  316. if err := svr.sftpServerWorker(ch); err != nil {
  317. svr.conn.Close() // shuts down recvPacket
  318. }
  319. }()
  320. }
  321. pktChan := svr.pktMgr.workerChan(runWorker)
  322. var err error
  323. var pkt requestPacket
  324. var pktType uint8
  325. var pktBytes []byte
  326. for {
  327. pktType, pktBytes, err = svr.serverConn.recvPacket(svr.pktMgr.getNextOrderID())
  328. if err != nil {
  329. // Check whether the connection terminated cleanly in-between packets.
  330. if err == io.EOF {
  331. err = nil
  332. }
  333. // we don't care about releasing allocated pages here, the server will quit and the allocator freed
  334. break
  335. }
  336. pkt, err = makePacket(rxPacket{fxp(pktType), pktBytes})
  337. if err != nil {
  338. switch {
  339. case errors.Is(err, errUnknownExtendedPacket):
  340. //if err := svr.serverConn.sendError(pkt, ErrSshFxOpUnsupported); err != nil {
  341. // debug("failed to send err packet: %v", err)
  342. // svr.conn.Close() // shuts down recvPacket
  343. // break
  344. //}
  345. default:
  346. debug("makePacket err: %v", err)
  347. svr.conn.Close() // shuts down recvPacket
  348. break
  349. }
  350. }
  351. pktChan <- svr.pktMgr.newOrderedRequest(pkt)
  352. }
  353. close(pktChan) // shuts down sftpServerWorkers
  354. wg.Wait() // wait for all workers to exit
  355. // close any still-open files
  356. for handle, file := range svr.openFiles {
  357. fmt.Fprintf(svr.debugStream, "sftp server file with handle %q left open: %v\n", handle, file.Name())
  358. file.Close()
  359. }
  360. return err // error from recvPacket
  361. }
  362. type ider interface {
  363. id() uint32
  364. }
  365. // The init packet has no ID, so we just return a zero-value ID
  366. func (p *sshFxInitPacket) id() uint32 { return 0 }
  367. type sshFxpStatResponse struct {
  368. ID uint32
  369. info os.FileInfo
  370. }
  371. func (p *sshFxpStatResponse) marshalPacket() ([]byte, []byte, error) {
  372. l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(id)
  373. b := make([]byte, 4, l)
  374. b = append(b, sshFxpAttrs)
  375. b = marshalUint32(b, p.ID)
  376. var payload []byte
  377. payload = marshalFileInfo(payload, p.info)
  378. return b, payload, nil
  379. }
  380. func (p *sshFxpStatResponse) MarshalBinary() ([]byte, error) {
  381. header, payload, err := p.marshalPacket()
  382. return append(header, payload...), err
  383. }
  384. var emptyFileStat = []interface{}{uint32(0)}
  385. func (p *sshFxpOpenPacket) readonly() bool {
  386. return !p.hasPflags(sshFxfWrite)
  387. }
  388. func (p *sshFxpOpenPacket) hasPflags(flags ...uint32) bool {
  389. for _, f := range flags {
  390. if p.Pflags&f == 0 {
  391. return false
  392. }
  393. }
  394. return true
  395. }
  396. func (p *sshFxpOpenPacket) respond(svr *Server) responsePacket {
  397. var osFlags int
  398. if p.hasPflags(sshFxfRead, sshFxfWrite) {
  399. osFlags |= os.O_RDWR
  400. } else if p.hasPflags(sshFxfWrite) {
  401. osFlags |= os.O_WRONLY
  402. } else if p.hasPflags(sshFxfRead) {
  403. osFlags |= os.O_RDONLY
  404. } else {
  405. // how are they opening?
  406. return statusFromError(p.ID, syscall.EINVAL)
  407. }
  408. // Don't use O_APPEND flag as it conflicts with WriteAt.
  409. // The sshFxfAppend flag is a no-op here as the client sends the offsets.
  410. if p.hasPflags(sshFxfCreat) {
  411. osFlags |= os.O_CREATE
  412. }
  413. if p.hasPflags(sshFxfTrunc) {
  414. osFlags |= os.O_TRUNC
  415. }
  416. if p.hasPflags(sshFxfExcl) {
  417. osFlags |= os.O_EXCL
  418. }
  419. f, err := os.OpenFile(svr.toLocalPath(p.Path), osFlags, 0o644)
  420. if err != nil {
  421. return statusFromError(p.ID, err)
  422. }
  423. handle := svr.nextHandle(f)
  424. return &sshFxpHandlePacket{ID: p.ID, Handle: handle}
  425. }
  426. func (p *sshFxpReaddirPacket) respond(svr *Server) responsePacket {
  427. f, ok := svr.getHandle(p.Handle)
  428. if !ok {
  429. return statusFromError(p.ID, EBADF)
  430. }
  431. dirents, err := f.Readdir(128)
  432. if err != nil {
  433. return statusFromError(p.ID, err)
  434. }
  435. idLookup := osIDLookup{}
  436. ret := &sshFxpNamePacket{ID: p.ID}
  437. for _, dirent := range dirents {
  438. ret.NameAttrs = append(ret.NameAttrs, &sshFxpNameAttr{
  439. Name: dirent.Name(),
  440. LongName: runLs(idLookup, dirent),
  441. Attrs: []interface{}{dirent},
  442. })
  443. }
  444. return ret
  445. }
  446. func (p *sshFxpSetstatPacket) respond(svr *Server) responsePacket {
  447. // additional unmarshalling is required for each possibility here
  448. b := p.Attrs.([]byte)
  449. var err error
  450. p.Path = svr.toLocalPath(p.Path)
  451. debug("setstat name \"%s\"", p.Path)
  452. if (p.Flags & sshFileXferAttrSize) != 0 {
  453. var size uint64
  454. if size, b, err = unmarshalUint64Safe(b); err == nil {
  455. err = os.Truncate(p.Path, int64(size))
  456. }
  457. }
  458. if (p.Flags & sshFileXferAttrPermissions) != 0 {
  459. var mode uint32
  460. if mode, b, err = unmarshalUint32Safe(b); err == nil {
  461. err = os.Chmod(p.Path, os.FileMode(mode))
  462. }
  463. }
  464. if (p.Flags & sshFileXferAttrACmodTime) != 0 {
  465. var atime uint32
  466. var mtime uint32
  467. if atime, b, err = unmarshalUint32Safe(b); err != nil {
  468. } else if mtime, b, err = unmarshalUint32Safe(b); err != nil {
  469. } else {
  470. atimeT := time.Unix(int64(atime), 0)
  471. mtimeT := time.Unix(int64(mtime), 0)
  472. err = os.Chtimes(p.Path, atimeT, mtimeT)
  473. }
  474. }
  475. if (p.Flags & sshFileXferAttrUIDGID) != 0 {
  476. var uid uint32
  477. var gid uint32
  478. if uid, b, err = unmarshalUint32Safe(b); err != nil {
  479. } else if gid, _, err = unmarshalUint32Safe(b); err != nil {
  480. } else {
  481. err = os.Chown(p.Path, int(uid), int(gid))
  482. }
  483. }
  484. return statusFromError(p.ID, err)
  485. }
  486. func (p *sshFxpFsetstatPacket) respond(svr *Server) responsePacket {
  487. f, ok := svr.getHandle(p.Handle)
  488. if !ok {
  489. return statusFromError(p.ID, EBADF)
  490. }
  491. // additional unmarshalling is required for each possibility here
  492. b := p.Attrs.([]byte)
  493. var err error
  494. debug("fsetstat name \"%s\"", f.Name())
  495. if (p.Flags & sshFileXferAttrSize) != 0 {
  496. var size uint64
  497. if size, b, err = unmarshalUint64Safe(b); err == nil {
  498. err = f.Truncate(int64(size))
  499. }
  500. }
  501. if (p.Flags & sshFileXferAttrPermissions) != 0 {
  502. var mode uint32
  503. if mode, b, err = unmarshalUint32Safe(b); err == nil {
  504. err = f.Chmod(os.FileMode(mode))
  505. }
  506. }
  507. if (p.Flags & sshFileXferAttrACmodTime) != 0 {
  508. var atime uint32
  509. var mtime uint32
  510. if atime, b, err = unmarshalUint32Safe(b); err != nil {
  511. } else if mtime, b, err = unmarshalUint32Safe(b); err != nil {
  512. } else {
  513. atimeT := time.Unix(int64(atime), 0)
  514. mtimeT := time.Unix(int64(mtime), 0)
  515. err = os.Chtimes(f.Name(), atimeT, mtimeT)
  516. }
  517. }
  518. if (p.Flags & sshFileXferAttrUIDGID) != 0 {
  519. var uid uint32
  520. var gid uint32
  521. if uid, b, err = unmarshalUint32Safe(b); err != nil {
  522. } else if gid, _, err = unmarshalUint32Safe(b); err != nil {
  523. } else {
  524. err = f.Chown(int(uid), int(gid))
  525. }
  526. }
  527. return statusFromError(p.ID, err)
  528. }
  529. func statusFromError(id uint32, err error) *sshFxpStatusPacket {
  530. ret := &sshFxpStatusPacket{
  531. ID: id,
  532. StatusError: StatusError{
  533. // sshFXOk = 0
  534. // sshFXEOF = 1
  535. // sshFXNoSuchFile = 2 ENOENT
  536. // sshFXPermissionDenied = 3
  537. // sshFXFailure = 4
  538. // sshFXBadMessage = 5
  539. // sshFXNoConnection = 6
  540. // sshFXConnectionLost = 7
  541. // sshFXOPUnsupported = 8
  542. Code: sshFxOk,
  543. },
  544. }
  545. if err == nil {
  546. return ret
  547. }
  548. debug("statusFromError: error is %T %#v", err, err)
  549. ret.StatusError.Code = sshFxFailure
  550. ret.StatusError.msg = err.Error()
  551. if os.IsNotExist(err) {
  552. ret.StatusError.Code = sshFxNoSuchFile
  553. return ret
  554. }
  555. if code, ok := translateSyscallError(err); ok {
  556. ret.StatusError.Code = code
  557. return ret
  558. }
  559. if errors.Is(err, io.EOF) {
  560. ret.StatusError.Code = sshFxEOF
  561. return ret
  562. }
  563. var e fxerr
  564. if errors.As(err, &e) {
  565. ret.StatusError.Code = uint32(e)
  566. return ret
  567. }
  568. return ret
  569. }