server.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package ssh
  5. import (
  6. "bytes"
  7. "crypto/rand"
  8. "encoding/binary"
  9. "errors"
  10. "fmt"
  11. "io"
  12. "net"
  13. "sync"
  14. _ "crypto/sha1"
  15. )
  16. type ServerConfig struct {
  17. hostKeys []Signer
  18. // Rand provides the source of entropy for key exchange. If Rand is
  19. // nil, the cryptographic random reader in package crypto/rand will
  20. // be used.
  21. Rand io.Reader
  22. // NoClientAuth is true if clients are allowed to connect without
  23. // authenticating.
  24. NoClientAuth bool
  25. // PasswordCallback, if non-nil, is called when a user attempts to
  26. // authenticate using a password. It may be called concurrently from
  27. // several goroutines.
  28. PasswordCallback func(conn *ServerConn, user, password string) bool
  29. // PublicKeyCallback, if non-nil, is called when a client attempts public
  30. // key authentication. It must return true if the given public key is
  31. // valid for the given user.
  32. PublicKeyCallback func(conn *ServerConn, user, algo string, pubkey []byte) bool
  33. // KeyboardInteractiveCallback, if non-nil, is called when
  34. // keyboard-interactive authentication is selected (RFC
  35. // 4256). The client object's Challenge function should be
  36. // used to query the user. The callback may offer multiple
  37. // Challenge rounds. To avoid information leaks, the client
  38. // should be presented a challenge even if the user is
  39. // unknown.
  40. KeyboardInteractiveCallback func(conn *ServerConn, user string, client ClientKeyboardInteractive) bool
  41. // Cryptographic-related configuration.
  42. Crypto CryptoConfig
  43. }
  44. func (c *ServerConfig) rand() io.Reader {
  45. if c.Rand == nil {
  46. return rand.Reader
  47. }
  48. return c.Rand
  49. }
  50. // AddHostKey adds a private key as a host key. If an existing host
  51. // key exists with the same algorithm, it is overwritten.
  52. func (s *ServerConfig) AddHostKey(key Signer) {
  53. for i, k := range s.hostKeys {
  54. if k.PublicKey().PublicKeyAlgo() == key.PublicKey().PublicKeyAlgo() {
  55. s.hostKeys[i] = key
  56. return
  57. }
  58. }
  59. s.hostKeys = append(s.hostKeys, key)
  60. }
  61. // SetRSAPrivateKey sets the private key for a Server. A Server must have a
  62. // private key configured in order to accept connections. The private key must
  63. // be in the form of a PEM encoded, PKCS#1, RSA private key. The file "id_rsa"
  64. // typically contains such a key.
  65. func (s *ServerConfig) SetRSAPrivateKey(pemBytes []byte) error {
  66. priv, err := ParsePrivateKey(pemBytes)
  67. if err != nil {
  68. return err
  69. }
  70. s.AddHostKey(priv)
  71. return nil
  72. }
  73. // cachedPubKey contains the results of querying whether a public key is
  74. // acceptable for a user. The cache only applies to a single ServerConn.
  75. type cachedPubKey struct {
  76. user, algo string
  77. pubKey []byte
  78. result bool
  79. }
  80. const maxCachedPubKeys = 16
  81. // A ServerConn represents an incoming connection.
  82. type ServerConn struct {
  83. transport *transport
  84. config *ServerConfig
  85. channels map[uint32]*serverChan
  86. nextChanId uint32
  87. // lock protects err and channels.
  88. lock sync.Mutex
  89. err error
  90. // cachedPubKeys contains the cache results of tests for public keys.
  91. // Since SSH clients will query whether a public key is acceptable
  92. // before attempting to authenticate with it, we end up with duplicate
  93. // queries for public key validity.
  94. cachedPubKeys []cachedPubKey
  95. // User holds the successfully authenticated user name.
  96. // It is empty if no authentication is used. It is populated before
  97. // any authentication callback is called and not assigned to after that.
  98. User string
  99. // ClientVersion is the client's version, populated after
  100. // Handshake is called. It should not be modified.
  101. ClientVersion []byte
  102. // Our version.
  103. serverVersion []byte
  104. }
  105. // Server returns a new SSH server connection
  106. // using c as the underlying transport.
  107. func Server(c net.Conn, config *ServerConfig) *ServerConn {
  108. return &ServerConn{
  109. transport: newTransport(c, config.rand(), false /* not client */),
  110. channels: make(map[uint32]*serverChan),
  111. config: config,
  112. }
  113. }
  114. // signAndMarshal signs the data with the appropriate algorithm,
  115. // and serializes the result in SSH wire format.
  116. func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) {
  117. sig, err := k.Sign(rand, data)
  118. if err != nil {
  119. return nil, err
  120. }
  121. return serializeSignature(k.PublicKey().PrivateKeyAlgo(), sig), nil
  122. }
  123. // Close closes the connection.
  124. func (s *ServerConn) Close() error { return s.transport.Close() }
  125. // LocalAddr returns the local network address.
  126. func (c *ServerConn) LocalAddr() net.Addr { return c.transport.LocalAddr() }
  127. // RemoteAddr returns the remote network address.
  128. func (c *ServerConn) RemoteAddr() net.Addr { return c.transport.RemoteAddr() }
  129. // Handshake performs an SSH transport and client authentication on the given ServerConn.
  130. func (s *ServerConn) Handshake() error {
  131. var err error
  132. s.serverVersion = []byte(packageVersion)
  133. s.ClientVersion, err = exchangeVersions(s.transport.Conn, s.serverVersion)
  134. if err != nil {
  135. return err
  136. }
  137. if err := s.clientInitHandshake(nil, nil); err != nil {
  138. return err
  139. }
  140. var packet []byte
  141. if packet, err = s.transport.readPacket(); err != nil {
  142. return err
  143. }
  144. var serviceRequest serviceRequestMsg
  145. if err := unmarshal(&serviceRequest, packet, msgServiceRequest); err != nil {
  146. return err
  147. }
  148. if serviceRequest.Service != serviceUserAuth {
  149. return errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
  150. }
  151. serviceAccept := serviceAcceptMsg{
  152. Service: serviceUserAuth,
  153. }
  154. if err := s.transport.writePacket(marshal(msgServiceAccept, serviceAccept)); err != nil {
  155. return err
  156. }
  157. if err := s.authenticate(); err != nil {
  158. return err
  159. }
  160. return err
  161. }
  162. func (s *ServerConn) clientInitHandshake(clientKexInit *kexInitMsg, clientKexInitPacket []byte) (err error) {
  163. serverKexInit := kexInitMsg{
  164. KexAlgos: s.config.Crypto.kexes(),
  165. CiphersClientServer: s.config.Crypto.ciphers(),
  166. CiphersServerClient: s.config.Crypto.ciphers(),
  167. MACsClientServer: s.config.Crypto.macs(),
  168. MACsServerClient: s.config.Crypto.macs(),
  169. CompressionClientServer: supportedCompressions,
  170. CompressionServerClient: supportedCompressions,
  171. }
  172. for _, k := range s.config.hostKeys {
  173. serverKexInit.ServerHostKeyAlgos = append(
  174. serverKexInit.ServerHostKeyAlgos, k.PublicKey().PublicKeyAlgo())
  175. }
  176. serverKexInitPacket := marshal(msgKexInit, serverKexInit)
  177. if err = s.transport.writePacket(serverKexInitPacket); err != nil {
  178. return
  179. }
  180. if clientKexInitPacket == nil {
  181. clientKexInit = new(kexInitMsg)
  182. if clientKexInitPacket, err = s.transport.readPacket(); err != nil {
  183. return
  184. }
  185. if err = unmarshal(clientKexInit, clientKexInitPacket, msgKexInit); err != nil {
  186. return
  187. }
  188. }
  189. algs := findAgreedAlgorithms(clientKexInit, &serverKexInit)
  190. if algs == nil {
  191. return errors.New("ssh: no common algorithms")
  192. }
  193. if clientKexInit.FirstKexFollows && algs.kex != clientKexInit.KexAlgos[0] {
  194. // The client sent a Kex message for the wrong algorithm,
  195. // which we have to ignore.
  196. if _, err = s.transport.readPacket(); err != nil {
  197. return
  198. }
  199. }
  200. var hostKey Signer
  201. for _, k := range s.config.hostKeys {
  202. if algs.hostKey == k.PublicKey().PublicKeyAlgo() {
  203. hostKey = k
  204. }
  205. }
  206. kex, ok := kexAlgoMap[algs.kex]
  207. if !ok {
  208. return fmt.Errorf("ssh: unexpected key exchange algorithm %v", algs.kex)
  209. }
  210. magics := handshakeMagics{
  211. serverVersion: s.serverVersion,
  212. clientVersion: s.ClientVersion,
  213. serverKexInit: marshal(msgKexInit, serverKexInit),
  214. clientKexInit: clientKexInitPacket,
  215. }
  216. result, err := kex.Server(s.transport, s.config.rand(), &magics, hostKey)
  217. if err != nil {
  218. return err
  219. }
  220. if err = s.transport.prepareKeyChange(algs, result); err != nil {
  221. return err
  222. }
  223. if err = s.transport.writePacket([]byte{msgNewKeys}); err != nil {
  224. return
  225. }
  226. if packet, err := s.transport.readPacket(); err != nil {
  227. return err
  228. } else if packet[0] != msgNewKeys {
  229. return UnexpectedMessageError{msgNewKeys, packet[0]}
  230. }
  231. return
  232. }
  233. func isAcceptableAlgo(algo string) bool {
  234. switch algo {
  235. case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
  236. CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01:
  237. return true
  238. }
  239. return false
  240. }
  241. // testPubKey returns true if the given public key is acceptable for the user.
  242. func (s *ServerConn) testPubKey(user, algo string, pubKey []byte) bool {
  243. if s.config.PublicKeyCallback == nil || !isAcceptableAlgo(algo) {
  244. return false
  245. }
  246. for _, c := range s.cachedPubKeys {
  247. if c.user == user && c.algo == algo && bytes.Equal(c.pubKey, pubKey) {
  248. return c.result
  249. }
  250. }
  251. result := s.config.PublicKeyCallback(s, user, algo, pubKey)
  252. if len(s.cachedPubKeys) < maxCachedPubKeys {
  253. c := cachedPubKey{
  254. user: user,
  255. algo: algo,
  256. pubKey: make([]byte, len(pubKey)),
  257. result: result,
  258. }
  259. copy(c.pubKey, pubKey)
  260. s.cachedPubKeys = append(s.cachedPubKeys, c)
  261. }
  262. return result
  263. }
  264. func (s *ServerConn) authenticate() error {
  265. var userAuthReq userAuthRequestMsg
  266. var err error
  267. var packet []byte
  268. userAuthLoop:
  269. for {
  270. if packet, err = s.transport.readPacket(); err != nil {
  271. return err
  272. }
  273. if err = unmarshal(&userAuthReq, packet, msgUserAuthRequest); err != nil {
  274. return err
  275. }
  276. if userAuthReq.Service != serviceSSH {
  277. return errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
  278. }
  279. switch userAuthReq.Method {
  280. case "none":
  281. if s.config.NoClientAuth {
  282. break userAuthLoop
  283. }
  284. case "password":
  285. if s.config.PasswordCallback == nil {
  286. break
  287. }
  288. payload := userAuthReq.Payload
  289. if len(payload) < 1 || payload[0] != 0 {
  290. return ParseError{msgUserAuthRequest}
  291. }
  292. payload = payload[1:]
  293. password, payload, ok := parseString(payload)
  294. if !ok || len(payload) > 0 {
  295. return ParseError{msgUserAuthRequest}
  296. }
  297. s.User = userAuthReq.User
  298. if s.config.PasswordCallback(s, userAuthReq.User, string(password)) {
  299. break userAuthLoop
  300. }
  301. case "keyboard-interactive":
  302. if s.config.KeyboardInteractiveCallback == nil {
  303. break
  304. }
  305. s.User = userAuthReq.User
  306. if s.config.KeyboardInteractiveCallback(s, s.User, &sshClientKeyboardInteractive{s}) {
  307. break userAuthLoop
  308. }
  309. case "publickey":
  310. if s.config.PublicKeyCallback == nil {
  311. break
  312. }
  313. payload := userAuthReq.Payload
  314. if len(payload) < 1 {
  315. return ParseError{msgUserAuthRequest}
  316. }
  317. isQuery := payload[0] == 0
  318. payload = payload[1:]
  319. algoBytes, payload, ok := parseString(payload)
  320. if !ok {
  321. return ParseError{msgUserAuthRequest}
  322. }
  323. algo := string(algoBytes)
  324. pubKey, payload, ok := parseString(payload)
  325. if !ok {
  326. return ParseError{msgUserAuthRequest}
  327. }
  328. if isQuery {
  329. // The client can query if the given public key
  330. // would be okay.
  331. if len(payload) > 0 {
  332. return ParseError{msgUserAuthRequest}
  333. }
  334. if s.testPubKey(userAuthReq.User, algo, pubKey) {
  335. okMsg := userAuthPubKeyOkMsg{
  336. Algo: algo,
  337. PubKey: string(pubKey),
  338. }
  339. if err = s.transport.writePacket(marshal(msgUserAuthPubKeyOk, okMsg)); err != nil {
  340. return err
  341. }
  342. continue userAuthLoop
  343. }
  344. } else {
  345. sig, payload, ok := parseSignature(payload)
  346. if !ok || len(payload) > 0 {
  347. return ParseError{msgUserAuthRequest}
  348. }
  349. // Ensure the public key algo and signature algo
  350. // are supported. Compare the private key
  351. // algorithm name that corresponds to algo with
  352. // sig.Format. This is usually the same, but
  353. // for certs, the names differ.
  354. if !isAcceptableAlgo(algo) || !isAcceptableAlgo(sig.Format) || pubAlgoToPrivAlgo(algo) != sig.Format {
  355. break
  356. }
  357. signedData := buildDataSignedForAuth(s.transport.sessionID, userAuthReq, algoBytes, pubKey)
  358. key, _, ok := ParsePublicKey(pubKey)
  359. if !ok {
  360. return ParseError{msgUserAuthRequest}
  361. }
  362. if !key.Verify(signedData, sig.Blob) {
  363. return ParseError{msgUserAuthRequest}
  364. }
  365. // TODO(jmpittman): Implement full validation for certificates.
  366. s.User = userAuthReq.User
  367. if s.testPubKey(userAuthReq.User, algo, pubKey) {
  368. break userAuthLoop
  369. }
  370. }
  371. }
  372. var failureMsg userAuthFailureMsg
  373. if s.config.PasswordCallback != nil {
  374. failureMsg.Methods = append(failureMsg.Methods, "password")
  375. }
  376. if s.config.PublicKeyCallback != nil {
  377. failureMsg.Methods = append(failureMsg.Methods, "publickey")
  378. }
  379. if s.config.KeyboardInteractiveCallback != nil {
  380. failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
  381. }
  382. if len(failureMsg.Methods) == 0 {
  383. return errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
  384. }
  385. if err = s.transport.writePacket(marshal(msgUserAuthFailure, failureMsg)); err != nil {
  386. return err
  387. }
  388. }
  389. packet = []byte{msgUserAuthSuccess}
  390. if err = s.transport.writePacket(packet); err != nil {
  391. return err
  392. }
  393. return nil
  394. }
  395. // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by
  396. // asking the client on the other side of a ServerConn.
  397. type sshClientKeyboardInteractive struct {
  398. *ServerConn
  399. }
  400. func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
  401. if len(questions) != len(echos) {
  402. return nil, errors.New("ssh: echos and questions must have equal length")
  403. }
  404. var prompts []byte
  405. for i := range questions {
  406. prompts = appendString(prompts, questions[i])
  407. prompts = appendBool(prompts, echos[i])
  408. }
  409. if err := c.transport.writePacket(marshal(msgUserAuthInfoRequest, userAuthInfoRequestMsg{
  410. Instruction: instruction,
  411. NumPrompts: uint32(len(questions)),
  412. Prompts: prompts,
  413. })); err != nil {
  414. return nil, err
  415. }
  416. packet, err := c.transport.readPacket()
  417. if err != nil {
  418. return nil, err
  419. }
  420. if packet[0] != msgUserAuthInfoResponse {
  421. return nil, UnexpectedMessageError{msgUserAuthInfoResponse, packet[0]}
  422. }
  423. packet = packet[1:]
  424. n, packet, ok := parseUint32(packet)
  425. if !ok || int(n) != len(questions) {
  426. return nil, &ParseError{msgUserAuthInfoResponse}
  427. }
  428. for i := uint32(0); i < n; i++ {
  429. ans, rest, ok := parseString(packet)
  430. if !ok {
  431. return nil, &ParseError{msgUserAuthInfoResponse}
  432. }
  433. answers = append(answers, string(ans))
  434. packet = rest
  435. }
  436. if len(packet) != 0 {
  437. return nil, errors.New("ssh: junk at end of message")
  438. }
  439. return answers, nil
  440. }
  441. const defaultWindowSize = 32768
  442. // Accept reads and processes messages on a ServerConn. It must be called
  443. // in order to demultiplex messages to any resulting Channels.
  444. func (s *ServerConn) Accept() (Channel, error) {
  445. // TODO(dfc) s.lock is not held here so visibility of s.err is not guaranteed.
  446. if s.err != nil {
  447. return nil, s.err
  448. }
  449. for {
  450. packet, err := s.transport.readPacket()
  451. if err != nil {
  452. s.lock.Lock()
  453. s.err = err
  454. s.lock.Unlock()
  455. // TODO(dfc) s.lock protects s.channels but isn't being held here.
  456. for _, c := range s.channels {
  457. c.setDead()
  458. c.handleData(nil)
  459. }
  460. return nil, err
  461. }
  462. switch packet[0] {
  463. case msgChannelData:
  464. if len(packet) < 9 {
  465. // malformed data packet
  466. return nil, ParseError{msgChannelData}
  467. }
  468. remoteId := binary.BigEndian.Uint32(packet[1:5])
  469. s.lock.Lock()
  470. c, ok := s.channels[remoteId]
  471. if !ok {
  472. s.lock.Unlock()
  473. continue
  474. }
  475. if length := binary.BigEndian.Uint32(packet[5:9]); length > 0 {
  476. packet = packet[9:]
  477. c.handleData(packet[:length])
  478. }
  479. s.lock.Unlock()
  480. default:
  481. decoded, err := decode(packet)
  482. if err != nil {
  483. return nil, err
  484. }
  485. switch msg := decoded.(type) {
  486. case *channelOpenMsg:
  487. if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
  488. return nil, errors.New("ssh: invalid MaxPacketSize from peer")
  489. }
  490. c := &serverChan{
  491. channel: channel{
  492. packetConn: s.transport,
  493. remoteId: msg.PeersId,
  494. remoteWin: window{Cond: newCond()},
  495. maxPacket: msg.MaxPacketSize,
  496. },
  497. chanType: msg.ChanType,
  498. extraData: msg.TypeSpecificData,
  499. myWindow: defaultWindowSize,
  500. serverConn: s,
  501. cond: newCond(),
  502. pendingData: make([]byte, defaultWindowSize),
  503. }
  504. c.remoteWin.add(msg.PeersWindow)
  505. s.lock.Lock()
  506. c.localId = s.nextChanId
  507. s.nextChanId++
  508. s.channels[c.localId] = c
  509. s.lock.Unlock()
  510. return c, nil
  511. case *channelRequestMsg:
  512. s.lock.Lock()
  513. c, ok := s.channels[msg.PeersId]
  514. if !ok {
  515. s.lock.Unlock()
  516. continue
  517. }
  518. c.handlePacket(msg)
  519. s.lock.Unlock()
  520. case *windowAdjustMsg:
  521. s.lock.Lock()
  522. c, ok := s.channels[msg.PeersId]
  523. if !ok {
  524. s.lock.Unlock()
  525. continue
  526. }
  527. c.handlePacket(msg)
  528. s.lock.Unlock()
  529. case *channelEOFMsg:
  530. s.lock.Lock()
  531. c, ok := s.channels[msg.PeersId]
  532. if !ok {
  533. s.lock.Unlock()
  534. continue
  535. }
  536. c.handlePacket(msg)
  537. s.lock.Unlock()
  538. case *channelCloseMsg:
  539. s.lock.Lock()
  540. c, ok := s.channels[msg.PeersId]
  541. if !ok {
  542. s.lock.Unlock()
  543. continue
  544. }
  545. c.handlePacket(msg)
  546. s.lock.Unlock()
  547. case *globalRequestMsg:
  548. if msg.WantReply {
  549. if err := s.transport.writePacket([]byte{msgRequestFailure}); err != nil {
  550. return nil, err
  551. }
  552. }
  553. case *kexInitMsg:
  554. s.lock.Lock()
  555. if err := s.clientInitHandshake(msg, packet); err != nil {
  556. s.lock.Unlock()
  557. return nil, err
  558. }
  559. s.lock.Unlock()
  560. case *disconnectMsg:
  561. return nil, io.EOF
  562. default:
  563. // Unknown message. Ignore.
  564. }
  565. }
  566. }
  567. panic("unreachable")
  568. }
  569. // A Listener implements a network listener (net.Listener) for SSH connections.
  570. type Listener struct {
  571. listener net.Listener
  572. config *ServerConfig
  573. }
  574. // Addr returns the listener's network address.
  575. func (l *Listener) Addr() net.Addr {
  576. return l.listener.Addr()
  577. }
  578. // Close closes the listener.
  579. func (l *Listener) Close() error {
  580. return l.listener.Close()
  581. }
  582. // Accept waits for and returns the next incoming SSH connection.
  583. // The receiver should call Handshake() in another goroutine
  584. // to avoid blocking the accepter.
  585. func (l *Listener) Accept() (*ServerConn, error) {
  586. c, err := l.listener.Accept()
  587. if err != nil {
  588. return nil, err
  589. }
  590. return Server(c, l.config), nil
  591. }
  592. // Listen creates an SSH listener accepting connections on
  593. // the given network address using net.Listen.
  594. func Listen(network, addr string, config *ServerConfig) (*Listener, error) {
  595. l, err := net.Listen(network, addr)
  596. if err != nil {
  597. return nil, err
  598. }
  599. return &Listener{
  600. l,
  601. config,
  602. }, nil
  603. }