Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(895)

Delta Between Two Patch Sets: ssh/server.go

Issue 14225043: code review 14225043: go.crypto/ssh: reimplement SSH connection protocol modu... (Closed)
Left Patch Set: diff -r 2cd6b3b93cdb https://code.google.com/p/go.crypto Created 10 years, 5 months ago
Right Patch Set: diff -r cd1eea1eb828 https://code.google.com/p/go.crypto Created 10 years, 5 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « ssh/mux_test.go ('k') | ssh/server_terminal.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // Copyright 2011 The Go Authors. All rights reserved. 1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package ssh 5 package ssh
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "crypto/rand" 9 "crypto/rand"
10 "errors" 10 "errors"
(...skipping 15 matching lines...) Expand all
26 // NoClientAuth is true if clients are allowed to connect without 26 // NoClientAuth is true if clients are allowed to connect without
27 // authenticating. 27 // authenticating.
28 NoClientAuth bool 28 NoClientAuth bool
29 29
30 // PasswordCallback, if non-nil, is called when a user attempts to 30 // PasswordCallback, if non-nil, is called when a user attempts to
31 // authenticate using a password. It may be called concurrently from 31 // authenticate using a password. It may be called concurrently from
32 // several goroutines. 32 // several goroutines.
33 PasswordCallback func(conn *ServerConn, user, password string) bool 33 PasswordCallback func(conn *ServerConn, user, password string) bool
34 34
35 // PublicKeyCallback, if non-nil, is called when a client attempts publi c 35 // PublicKeyCallback, if non-nil, is called when a client attempts publi c
36 » // key authentication. It must return true iff the given public key is 36 » // key authentication. It must return true if the given public key is
37 // valid for the given user. 37 // valid for the given user.
38 PublicKeyCallback func(conn *ServerConn, user, algo string, pubkey []byt e) bool 38 PublicKeyCallback func(conn *ServerConn, user, algo string, pubkey []byt e) bool
39 39
40 // KeyboardInteractiveCallback, if non-nil, is called when 40 // KeyboardInteractiveCallback, if non-nil, is called when
41 // keyboard-interactive authentication is selected (RFC 41 // keyboard-interactive authentication is selected (RFC
42 // 4256). The client object's Challenge function should be 42 // 4256). The client object's Challenge function should be
43 // used to query the user. The callback may offer multiple 43 // used to query the user. The callback may offer multiple
44 // Challenge rounds. To avoid information leaks, the client 44 // Challenge rounds. To avoid information leaks, the client
45 // should be presented a challenge even if the user is 45 // should be presented a challenge even if the user is
46 // unknown. 46 // unknown.
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 type cachedPubKey struct { 88 type cachedPubKey struct {
89 user, algo string 89 user, algo string
90 pubKey []byte 90 pubKey []byte
91 result bool 91 result bool
92 } 92 }
93 93
94 const maxCachedPubKeys = 16 94 const maxCachedPubKeys = 16
95 95
96 // A ServerConn represents an incoming connection. 96 // A ServerConn represents an incoming connection.
97 type ServerConn struct { 97 type ServerConn struct {
98 » *transport 98 » transport *transport
99 » config *ServerConfig 99 » config *ServerConfig
100 100
101 // cachedPubKeys contains the cache results of tests for public keys. 101 // cachedPubKeys contains the cache results of tests for public keys.
102 // Since SSH clients will query whether a public key is acceptable 102 // Since SSH clients will query whether a public key is acceptable
103 // before attempting to authenticate with it, we end up with duplicate 103 // before attempting to authenticate with it, we end up with duplicate
104 // queries for public key validity. 104 // queries for public key validity.
105 cachedPubKeys []cachedPubKey 105 cachedPubKeys []cachedPubKey
106 106
107 // User holds the successfully authenticated user name. 107 // User holds the successfully authenticated user name.
108 // It is empty if no authentication is used. It is populated before 108 // It is empty if no authentication is used. It is populated before
109 // any authentication callback is called and not assigned to after that. 109 // any authentication callback is called and not assigned to after that.
110 User string 110 User string
111 111
112 // ClientVersion is the client's version, populated after 112 // ClientVersion is the client's version, populated after
113 // Handshake is called. It should not be modified. 113 // Handshake is called. It should not be modified.
114 ClientVersion []byte 114 ClientVersion []byte
115 115
116 // Our version.
117 serverVersion []byte
118
116 // Initial H used for the session ID. Once assigned this must not change 119 // Initial H used for the session ID. Once assigned this must not change
117 // even during subsequent key exchanges. 120 // even during subsequent key exchanges.
118 sessionId []byte 121 sessionId []byte
119 mux *mux 122 mux *mux
120 } 123 }
121 124
122 // Server returns a new SSH server connection 125 // Server returns a new SSH server connection
123 // using c as the underlying transport. 126 // using c as the underlying transport.
124 func Server(c net.Conn, config *ServerConfig) *ServerConn { 127 func Server(c net.Conn, config *ServerConfig) *ServerConn {
125 » tr := newTransport(c, config.rand()) 128 » tr := newTransport(c, config.rand(), false /* not client */)
126 return &ServerConn{ 129 return &ServerConn{
127 transport: tr, 130 transport: tr,
128 config: config, 131 config: config,
129 mux: newMux(tr),
130 } 132 }
131 } 133 }
132 134
133 // signAndMarshal signs the data with the appropriate algorithm, 135 // signAndMarshal signs the data with the appropriate algorithm,
134 // and serializes the result in SSH wire format. 136 // and serializes the result in SSH wire format.
135 func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { 137 func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) {
136 sig, err := k.Sign(rand, data) 138 sig, err := k.Sign(rand, data)
137 if err != nil { 139 if err != nil {
138 return nil, err 140 return nil, err
139 } 141 }
140 142
141 return serializeSignature(k.PublicKey().PrivateKeyAlgo(), sig), nil 143 return serializeSignature(k.PublicKey().PrivateKeyAlgo(), sig), nil
142 } 144 }
143 145
144 // serverVersion is the fixed identification string that Server will use. 146 // Close closes the connection.
145 var serverVersion = []byte("SSH-2.0-Go\r\n") 147 func (s *ServerConn) Close() error { return s.transport.Close() }
148
149 // LocalAddr returns the local network address.
150 func (c *ServerConn) LocalAddr() net.Addr { return c.transport.LocalAddr() }
151
152 // RemoteAddr returns the remote network address.
153 func (c *ServerConn) RemoteAddr() net.Addr { return c.transport.RemoteAddr() }
146 154
147 // Handshake performs an SSH transport and client authentication on the given Se rverConn. 155 // Handshake performs an SSH transport and client authentication on the given Se rverConn.
148 func (s *ServerConn) Handshake() (err error) { 156 func (s *ServerConn) Handshake() error {
149 » if _, err = s.Write(serverVersion); err != nil { 157 » var err error
150 » » return 158 » s.serverVersion = []byte(packageVersion)
151 » } 159 » s.ClientVersion, err = exchangeVersions(s.transport.Conn, s.serverVersio n)
152 » if err := s.Flush(); err != nil { 160 » if err != nil {
153 » » return err 161 » » return err
154 » } 162 » }
155 163 » if err := s.clientInitHandshake(nil, nil); err != nil {
156 » s.ClientVersion, err = readVersion(s) 164 » » return err
157 » if err != nil {
158 » » return
159 » }
160 » if err = s.clientInitHandshake(nil, nil); err != nil {
161 » » return
162 } 165 }
163 166
164 var packet []byte 167 var packet []byte
165 » if packet, err = s.readPacket(); err != nil { 168 » if packet, err = s.transport.readPacket(); err != nil {
166 » » return 169 » » return err
167 } 170 }
168 var serviceRequest serviceRequestMsg 171 var serviceRequest serviceRequestMsg
169 » if err = unmarshal(&serviceRequest, packet, msgServiceRequest); err != n il { 172 » if err := unmarshal(&serviceRequest, packet, msgServiceRequest); err != nil {
170 » » return 173 » » return err
171 } 174 }
172 if serviceRequest.Service != serviceUserAuth { 175 if serviceRequest.Service != serviceUserAuth {
173 return errors.New("ssh: requested service '" + serviceRequest.Se rvice + "' before authenticating") 176 return errors.New("ssh: requested service '" + serviceRequest.Se rvice + "' before authenticating")
174 } 177 }
175 serviceAccept := serviceAcceptMsg{ 178 serviceAccept := serviceAcceptMsg{
176 Service: serviceUserAuth, 179 Service: serviceUserAuth,
177 } 180 }
178 » if err = s.writePacket(marshal(msgServiceAccept, serviceAccept)); err != nil { 181 » if err := s.transport.writePacket(marshal(msgServiceAccept, serviceAccep t)); err != nil {
179 » » return 182 » » return err
180 » } 183 » }
181 184
182 » if err = s.authenticate(s.sessionId); err != nil { 185 » if err := s.authenticate(); err != nil {
183 » » return 186 » » return err
184 » } 187 » }
185 188
189 » s.mux = newMux(s.transport)
190 » go s.handleGlobalRequests()
186 go s.mux.Loop() 191 go s.mux.Loop()
187 » go s.handleGlobalRequests() 192 » return err
188 » return
189 } 193 }
190 194
191 func (s *ServerConn) handleGlobalRequests() { 195 func (s *ServerConn) handleGlobalRequests() {
192 » for r := range s.mux.ReceivedRequests() { 196 » for r := range s.mux.incomingRequests {
193 if r.WantReply { 197 if r.WantReply {
194 s.mux.AckRequest(false, nil) 198 s.mux.AckRequest(false, nil)
195 } 199 }
196 } 200 }
197 } 201 }
198 202
199 func (s *ServerConn) clientInitHandshake(clientKexInit *kexInitMsg, clientKexIni tPacket []byte) (err error) { 203 func (s *ServerConn) clientInitHandshake(clientKexInit *kexInitMsg, clientKexIni tPacket []byte) (err error) {
200 serverKexInit := kexInitMsg{ 204 serverKexInit := kexInitMsg{
201 KexAlgos: s.config.Crypto.kexes(), 205 KexAlgos: s.config.Crypto.kexes(),
202 CiphersClientServer: s.config.Crypto.ciphers(), 206 CiphersClientServer: s.config.Crypto.ciphers(),
203 CiphersServerClient: s.config.Crypto.ciphers(), 207 CiphersServerClient: s.config.Crypto.ciphers(),
204 MACsClientServer: s.config.Crypto.macs(), 208 MACsClientServer: s.config.Crypto.macs(),
205 MACsServerClient: s.config.Crypto.macs(), 209 MACsServerClient: s.config.Crypto.macs(),
206 CompressionClientServer: supportedCompressions, 210 CompressionClientServer: supportedCompressions,
207 CompressionServerClient: supportedCompressions, 211 CompressionServerClient: supportedCompressions,
208 } 212 }
209 for _, k := range s.config.hostKeys { 213 for _, k := range s.config.hostKeys {
210 serverKexInit.ServerHostKeyAlgos = append( 214 serverKexInit.ServerHostKeyAlgos = append(
211 serverKexInit.ServerHostKeyAlgos, k.PublicKey().PublicKe yAlgo()) 215 serverKexInit.ServerHostKeyAlgos, k.PublicKey().PublicKe yAlgo())
212 } 216 }
213 217
214 serverKexInitPacket := marshal(msgKexInit, serverKexInit) 218 serverKexInitPacket := marshal(msgKexInit, serverKexInit)
215 » if err = s.writePacket(serverKexInitPacket); err != nil { 219 » if err = s.transport.writePacket(serverKexInitPacket); err != nil {
216 return 220 return
217 } 221 }
218 222
219 if clientKexInitPacket == nil { 223 if clientKexInitPacket == nil {
220 clientKexInit = new(kexInitMsg) 224 clientKexInit = new(kexInitMsg)
221 » » if clientKexInitPacket, err = s.readPacket(); err != nil { 225 » » if clientKexInitPacket, err = s.transport.readPacket(); err != n il {
222 return 226 return
223 } 227 }
224 if err = unmarshal(clientKexInit, clientKexInitPacket, msgKexIni t); err != nil { 228 if err = unmarshal(clientKexInit, clientKexInitPacket, msgKexIni t); err != nil {
225 return 229 return
226 } 230 }
227 } 231 }
228 232
229 » kexAlgo, hostKeyAlgo, ok := findAgreedAlgorithms(s.transport, clientKexI nit, &serverKexInit) 233 » algs := findAgreedAlgorithms(clientKexInit, &serverKexInit)
230 » if !ok { 234 » if algs == nil {
231 return errors.New("ssh: no common algorithms") 235 return errors.New("ssh: no common algorithms")
232 } 236 }
233 » if clientKexInit.FirstKexFollows && kexAlgo != clientKexInit.KexAlgos[0] { 237
238 » if clientKexInit.FirstKexFollows && algs.kex != clientKexInit.KexAlgos[0 ] {
234 // The client sent a Kex message for the wrong algorithm, 239 // The client sent a Kex message for the wrong algorithm,
235 // which we have to ignore. 240 // which we have to ignore.
236 » » if _, err = s.readPacket(); err != nil { 241 » » if _, err = s.transport.readPacket(); err != nil {
237 return 242 return
238 } 243 }
239 } 244 }
240 245
241 var hostKey Signer 246 var hostKey Signer
242 for _, k := range s.config.hostKeys { 247 for _, k := range s.config.hostKeys {
243 » » if hostKeyAlgo == k.PublicKey().PublicKeyAlgo() { 248 » » if algs.hostKey == k.PublicKey().PublicKeyAlgo() {
244 hostKey = k 249 hostKey = k
245 } 250 }
246 } 251 }
247 252
248 » kex, ok := kexAlgoMap[kexAlgo] 253 » kex, ok := kexAlgoMap[algs.kex]
249 if !ok { 254 if !ok {
250 » » return fmt.Errorf("ssh: unexpected key exchange algorithm %v", k exAlgo) 255 » » return fmt.Errorf("ssh: unexpected key exchange algorithm %v", a lgs.kex)
251 } 256 }
252 257
253 magics := handshakeMagics{ 258 magics := handshakeMagics{
254 » » serverVersion: serverVersion[:len(serverVersion)-2], 259 » » serverVersion: s.serverVersion,
255 clientVersion: s.ClientVersion, 260 clientVersion: s.ClientVersion,
256 serverKexInit: marshal(msgKexInit, serverKexInit), 261 serverKexInit: marshal(msgKexInit, serverKexInit),
257 clientKexInit: clientKexInitPacket, 262 clientKexInit: clientKexInitPacket,
258 } 263 }
259 » result, err := kex.Server(s, s.config.rand(), &magics, hostKey) 264 » result, err := kex.Server(s.transport, s.config.rand(), &magics, hostKey )
260 » if err != nil { 265 » if err != nil {
261 » » return err 266 » » return err
262 » } 267 » }
263 268
264 » // sessionId must only be assigned during initial handshake. 269 » if err = s.transport.prepareKeyChange(algs, result); err != nil {
265 » if s.sessionId == nil { 270 » » return err
266 » » s.sessionId = result.H 271 » }
267 » } 272
268 273 » if err = s.transport.writePacket([]byte{msgNewKeys}); err != nil {
269 » var packet []byte
270
271 » if err = s.writePacket([]byte{msgNewKeys}); err != nil {
272 return 274 return
273 } 275 }
274 » if err = s.transport.writer.setupKeys(serverKeys, result.K, result.H, s. sessionId, kex.Hash()); err != nil { 276 » if packet, err := s.transport.readPacket(); err != nil {
275 » » return 277 » » return err
276 » } 278 » } else if packet[0] != msgNewKeys {
277
278 » if packet, err = s.readPacket(); err != nil {
279 » » return
280 » }
281 » if packet[0] != msgNewKeys {
282 return UnexpectedMessageError{msgNewKeys, packet[0]} 279 return UnexpectedMessageError{msgNewKeys, packet[0]}
283 }
284 if err = s.transport.reader.setupKeys(clientKeys, result.K, result.H, s. sessionId, kex.Hash()); err != nil {
285 return
286 } 280 }
287 281
288 return 282 return
289 } 283 }
290 284
291 func isAcceptableAlgo(algo string) bool { 285 func isAcceptableAlgo(algo string) bool {
292 switch algo { 286 switch algo {
293 case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoEC DSA521, 287 case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoEC DSA521,
294 CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECD SA384v01, CertAlgoECDSA521v01: 288 CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECD SA384v01, CertAlgoECDSA521v01:
295 return true 289 return true
(...skipping 21 matching lines...) Expand all
317 pubKey: make([]byte, len(pubKey)), 311 pubKey: make([]byte, len(pubKey)),
318 result: result, 312 result: result,
319 } 313 }
320 copy(c.pubKey, pubKey) 314 copy(c.pubKey, pubKey)
321 s.cachedPubKeys = append(s.cachedPubKeys, c) 315 s.cachedPubKeys = append(s.cachedPubKeys, c)
322 } 316 }
323 317
324 return result 318 return result
325 } 319 }
326 320
327 func (s *ServerConn) authenticate(H []byte) error { 321 func (s *ServerConn) authenticate() error {
328 var userAuthReq userAuthRequestMsg 322 var userAuthReq userAuthRequestMsg
329 var err error 323 var err error
330 var packet []byte 324 var packet []byte
331 325
332 userAuthLoop: 326 userAuthLoop:
333 for { 327 for {
334 » » if packet, err = s.readPacket(); err != nil { 328 » » if packet, err = s.transport.readPacket(); err != nil {
335 return err 329 return err
336 } 330 }
337 if err = unmarshal(&userAuthReq, packet, msgUserAuthRequest); er r != nil { 331 if err = unmarshal(&userAuthReq, packet, msgUserAuthRequest); er r != nil {
338 return err 332 return err
339 } 333 }
340 334
341 if userAuthReq.Service != serviceSSH { 335 if userAuthReq.Service != serviceSSH {
342 return errors.New("ssh: client attempted to negotiate fo r unknown service: " + userAuthReq.Service) 336 return errors.New("ssh: client attempted to negotiate fo r unknown service: " + userAuthReq.Service)
343 } 337 }
344 338
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
389 return ParseError{msgUserAuthRequest} 383 return ParseError{msgUserAuthRequest}
390 } 384 }
391 algo := string(algoBytes) 385 algo := string(algoBytes)
392 386
393 pubKey, payload, ok := parseString(payload) 387 pubKey, payload, ok := parseString(payload)
394 if !ok { 388 if !ok {
395 return ParseError{msgUserAuthRequest} 389 return ParseError{msgUserAuthRequest}
396 } 390 }
397 if isQuery { 391 if isQuery {
398 // The client can query if the given public key 392 // The client can query if the given public key
399 » » » » // would be ok. 393 » » » » // would be okay.
400 if len(payload) > 0 { 394 if len(payload) > 0 {
401 return ParseError{msgUserAuthRequest} 395 return ParseError{msgUserAuthRequest}
402 } 396 }
403 if s.testPubKey(userAuthReq.User, algo, pubKey) { 397 if s.testPubKey(userAuthReq.User, algo, pubKey) {
404 okMsg := userAuthPubKeyOkMsg{ 398 okMsg := userAuthPubKeyOkMsg{
405 Algo: algo, 399 Algo: algo,
406 PubKey: string(pubKey), 400 PubKey: string(pubKey),
407 } 401 }
408 » » » » » if err = s.writePacket(marshal(msgUserAu thPubKeyOk, okMsg)); err != nil { 402 » » » » » if err = s.transport.writePacket(marshal (msgUserAuthPubKeyOk, okMsg)); err != nil {
409 return err 403 return err
410 } 404 }
411 continue userAuthLoop 405 continue userAuthLoop
412 } 406 }
413 } else { 407 } else {
414 sig, payload, ok := parseSignature(payload) 408 sig, payload, ok := parseSignature(payload)
415 if !ok || len(payload) > 0 { 409 if !ok || len(payload) > 0 {
416 return ParseError{msgUserAuthRequest} 410 return ParseError{msgUserAuthRequest}
417 } 411 }
418 // Ensure the public key algo and signature algo 412 // Ensure the public key algo and signature algo
419 // are supported. Compare the private key 413 // are supported. Compare the private key
420 // algorithm name that corresponds to algo with 414 // algorithm name that corresponds to algo with
421 // sig.Format. This is usually the same, but 415 // sig.Format. This is usually the same, but
422 // for certs, the names differ. 416 // for certs, the names differ.
423 if !isAcceptableAlgo(algo) || !isAcceptableAlgo( sig.Format) || pubAlgoToPrivAlgo(algo) != sig.Format { 417 if !isAcceptableAlgo(algo) || !isAcceptableAlgo( sig.Format) || pubAlgoToPrivAlgo(algo) != sig.Format {
424 break 418 break
425 } 419 }
426 » » » » signedData := buildDataSignedForAuth(H, userAuth Req, algoBytes, pubKey) 420 » » » » signedData := buildDataSignedForAuth(s.transport .sessionID, userAuthReq, algoBytes, pubKey)
427 » » » » key, _, ok := parsePubKey(pubKey) 421 » » » » key, _, ok := ParsePublicKey(pubKey)
428 if !ok { 422 if !ok {
429 return ParseError{msgUserAuthRequest} 423 return ParseError{msgUserAuthRequest}
430 } 424 }
431 425
432 if !key.Verify(signedData, sig.Blob) { 426 if !key.Verify(signedData, sig.Blob) {
433 return ParseError{msgUserAuthRequest} 427 return ParseError{msgUserAuthRequest}
434 } 428 }
435 // TODO(jmpittman): Implement full validation fo r certificates. 429 // TODO(jmpittman): Implement full validation fo r certificates.
436 s.User = userAuthReq.User 430 s.User = userAuthReq.User
437 if s.testPubKey(userAuthReq.User, algo, pubKey) { 431 if s.testPubKey(userAuthReq.User, algo, pubKey) {
(...skipping 10 matching lines...) Expand all
448 failureMsg.Methods = append(failureMsg.Methods, "publick ey") 442 failureMsg.Methods = append(failureMsg.Methods, "publick ey")
449 } 443 }
450 if s.config.KeyboardInteractiveCallback != nil { 444 if s.config.KeyboardInteractiveCallback != nil {
451 failureMsg.Methods = append(failureMsg.Methods, "keyboar d-interactive") 445 failureMsg.Methods = append(failureMsg.Methods, "keyboar d-interactive")
452 } 446 }
453 447
454 if len(failureMsg.Methods) == 0 { 448 if len(failureMsg.Methods) == 0 {
455 return errors.New("ssh: no authentication methods config ured but NoClientAuth is also false") 449 return errors.New("ssh: no authentication methods config ured but NoClientAuth is also false")
456 } 450 }
457 451
458 » » if err = s.writePacket(marshal(msgUserAuthFailure, failureMsg)); err != nil { 452 » » if err = s.transport.writePacket(marshal(msgUserAuthFailure, fai lureMsg)); err != nil {
459 return err 453 return err
460 } 454 }
461 } 455 }
462 456
463 packet = []byte{msgUserAuthSuccess} 457 packet = []byte{msgUserAuthSuccess}
464 » if err = s.writePacket(packet); err != nil { 458 » if err = s.transport.writePacket(packet); err != nil {
465 return err 459 return err
466 } 460 }
467 461
468 return nil 462 return nil
469 } 463 }
470 464
471 // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by 465 // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by
472 // asking the client on the other side of a ServerConn. 466 // asking the client on the other side of a ServerConn.
473 type sshClientKeyboardInteractive struct { 467 type sshClientKeyboardInteractive struct {
474 *ServerConn 468 *ServerConn
475 } 469 }
476 470
477 func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, quest ions []string, echos []bool) (answers []string, err error) { 471 func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, quest ions []string, echos []bool) (answers []string, err error) {
478 if len(questions) != len(echos) { 472 if len(questions) != len(echos) {
479 return nil, errors.New("ssh: echos and questions must have equal length") 473 return nil, errors.New("ssh: echos and questions must have equal length")
480 } 474 }
481 475
482 var prompts []byte 476 var prompts []byte
483 for i := range questions { 477 for i := range questions {
484 prompts = appendString(prompts, questions[i]) 478 prompts = appendString(prompts, questions[i])
485 prompts = appendBool(prompts, echos[i]) 479 prompts = appendBool(prompts, echos[i])
486 } 480 }
487 481
488 » if err := c.writePacket(marshal(msgUserAuthInfoRequest, userAuthInfoRequ estMsg{ 482 » if err := c.transport.writePacket(marshal(msgUserAuthInfoRequest, userAu thInfoRequestMsg{
489 Instruction: instruction, 483 Instruction: instruction,
490 NumPrompts: uint32(len(questions)), 484 NumPrompts: uint32(len(questions)),
491 Prompts: prompts, 485 Prompts: prompts,
492 })); err != nil { 486 })); err != nil {
493 return nil, err 487 return nil, err
494 } 488 }
495 489
496 » packet, err := c.readPacket() 490 » packet, err := c.transport.readPacket()
497 if err != nil { 491 if err != nil {
498 return nil, err 492 return nil, err
499 } 493 }
500 if packet[0] != msgUserAuthInfoResponse { 494 if packet[0] != msgUserAuthInfoResponse {
501 return nil, UnexpectedMessageError{msgUserAuthInfoResponse, pack et[0]} 495 return nil, UnexpectedMessageError{msgUserAuthInfoResponse, pack et[0]}
502 } 496 }
503 packet = packet[1:] 497 packet = packet[1:]
504 498
505 n, packet, ok := parseUint32(packet) 499 n, packet, ok := parseUint32(packet)
506 if !ok || int(n) != len(questions) { 500 if !ok || int(n) != len(questions) {
(...skipping 14 matching lines...) Expand all
521 } 515 }
522 516
523 return answers, nil 517 return answers, nil
524 } 518 }
525 519
526 const defaultWindowSize = 32768 520 const defaultWindowSize = 32768
527 521
528 // Accept reads and processes messages on a ServerConn. It must be called 522 // Accept reads and processes messages on a ServerConn. It must be called
529 // in order to demultiplex messages to any resulting Channels. 523 // in order to demultiplex messages to any resulting Channels.
530 func (s *ServerConn) Accept() (Channel, error) { 524 func (s *ServerConn) Accept() (Channel, error) {
531 » return s.mux.Accept() 525 » in, ok := <-s.mux.incomingChannels
526 » if !ok {
527 » » return nil, io.EOF
528 » }
529 » return newCompatChannel(in), nil
532 } 530 }
533 531
534 // A Listener implements a network listener (net.Listener) for SSH connections. 532 // A Listener implements a network listener (net.Listener) for SSH connections.
535 type Listener struct { 533 type Listener struct {
536 listener net.Listener 534 listener net.Listener
537 config *ServerConfig 535 config *ServerConfig
538 } 536 }
539 537
540 // Addr returns the listener's network address. 538 // Addr returns the listener's network address.
541 func (l *Listener) Addr() net.Addr { 539 func (l *Listener) Addr() net.Addr {
(...skipping 21 matching lines...) Expand all
563 func Listen(network, addr string, config *ServerConfig) (*Listener, error) { 561 func Listen(network, addr string, config *ServerConfig) (*Listener, error) {
564 l, err := net.Listen(network, addr) 562 l, err := net.Listen(network, addr)
565 if err != nil { 563 if err != nil {
566 return nil, err 564 return nil, err
567 } 565 }
568 return &Listener{ 566 return &Listener{
569 l, 567 l,
570 config, 568 config,
571 }, nil 569 }, nil
572 } 570 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b