Left: | ||
Right: |
OLD | NEW |
---|---|
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 "bufio" | 8 "bufio" |
9 "bytes" | |
9 "crypto/cipher" | 10 "crypto/cipher" |
10 "crypto/subtle" | 11 "crypto/subtle" |
11 "encoding/binary" | 12 "encoding/binary" |
12 "errors" | 13 "errors" |
14 "fmt" | |
13 "hash" | 15 "hash" |
14 "io" | 16 "io" |
15 "net" | 17 "net" |
16 "sync" | 18 "sync" |
17 ) | 19 ) |
18 | 20 |
19 const ( | 21 const ( |
20 packetSizeMultiple = 16 // TODO(huin) this should be determined by the c ipher. | 22 packetSizeMultiple = 16 // TODO(huin) this should be determined by the c ipher. |
21 | 23 |
22 // RFC 4253 section 6.1 defines a minimum packet size of 32768 that impl ementations | 24 // RFC 4253 section 6.1 defines a minimum packet size of 32768 that impl ementations |
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
351 | 353 |
352 digest := h.Sum(nil) | 354 digest := h.Sum(nil) |
353 n := copy(out, digest) | 355 n := copy(out, digest) |
354 out = out[n:] | 356 out = out[n:] |
355 if len(out) > 0 { | 357 if len(out) > 0 { |
356 digestsSoFar = append(digestsSoFar, digest...) | 358 digestsSoFar = append(digestsSoFar, digest...) |
357 } | 359 } |
358 } | 360 } |
359 } | 361 } |
360 | 362 |
361 // maxVersionStringBytes is the maximum number of bytes that we'll accept as a | 363 var packageVersion = []byte("SSH-2.0-Go") |
dfc
2013/10/14 00:32:28
I think I want packageVersion to be a string const
hanwen-google
2013/10/14 06:41:44
Done.
| |
362 // version string. In the event that the client is talking a different protocol | 364 |
363 // we need to set a limit otherwise we will keep using more and more memory | 365 // Sends a version string. If myVersion is not given, "Go" is used. |
364 // while searching for the end of the version handshake. | 366 func exchangeVersions(rw io.ReadWriter, myVersion string) (us []byte, them []byt e, err error) { |
365 const maxVersionStringBytes = 1024 | 367 » // We start with exchanging version strings. The read and write are |
368 » // not serialized. | |
369 » if len(myVersion) == 0 { | |
370 » » us = packageVersion | |
371 » } else { | |
372 » » for _, c := range []byte(myVersion) { | |
373 » » » // The spec disallows non US-ASCII chars, and | |
374 » » » // specifically forbids null chars. | |
375 » » » if c < 32 { | |
376 » » » » return nil, nil, errors.New("ssh: junk character in version string.") | |
377 » » » } | |
378 » » } | |
379 | |
380 » » us = append([]byte("SSH-2.0-"), myVersion...) | |
381 » } | |
382 » if _, err = rw.Write(append(us, '\r', '\n')); err != nil { | |
383 » » return | |
384 » } | |
385 | |
386 » them, err = readVersion(rw) | |
387 » if !bytes.HasPrefix(them, []byte("SSH-2.0-")) { | |
388 » » return nil, nil, fmt.Errorf("protocol version not supported: %q" , them) | |
389 » } | |
390 » return us, them, err | |
391 } | |
392 | |
393 // maxVersionStringBytes is the maximum number of bytes that we'll | |
394 // accept as a version string. RFC 4253 section 4.2 limits this at 255 | |
395 // chars | |
396 const maxVersionStringBytes = 255 | |
366 | 397 |
367 // Read version string as specified by RFC 4253, section 4.2. | 398 // Read version string as specified by RFC 4253, section 4.2. |
368 func readVersion(r io.Reader) ([]byte, error) { | 399 func readVersion(r io.Reader) ([]byte, error) { |
369 versionString := make([]byte, 0, 64) | 400 versionString := make([]byte, 0, 64) |
370 var ok bool | 401 var ok bool |
371 var buf [1]byte | 402 var buf [1]byte |
372 forEachByte: | 403 |
373 for len(versionString) < maxVersionStringBytes { | 404 for len(versionString) < maxVersionStringBytes { |
374 _, err := io.ReadFull(r, buf[:]) | 405 _, err := io.ReadFull(r, buf[:]) |
375 if err != nil { | 406 if err != nil { |
376 return nil, err | 407 return nil, err |
377 } | 408 } |
378 // The RFC says that the version should be terminated with \r\n | 409 // The RFC says that the version should be terminated with \r\n |
379 // but several SSH servers actually only send a \n. | 410 // but several SSH servers actually only send a \n. |
380 if buf[0] == '\n' { | 411 if buf[0] == '\n' { |
381 » » » ok = true | 412 » » » // Before the version string (format |
382 » » » break forEachByte | 413 » » » // SSH-<protocol-version>-<software-version>) |
414 » » » // there may be other lines that we ignore. | |
415 » » » if bytes.HasPrefix(versionString, []byte("SSH-")) { | |
416 » » » » ok = true | |
417 » » » » break | |
418 » » » } | |
419 » » » versionString = versionString[:0] | |
420 » » » continue | |
383 } | 421 } |
422 | |
423 // non ASCII chars are disallowed, but we are lenient, | |
424 // since Go doesn't use null-terminated strings. | |
425 | |
426 // The RFC allows a comment after a space, however, | |
427 // all of it (version and comments) go into the | |
428 // session hash. | |
384 versionString = append(versionString, buf[0]) | 429 versionString = append(versionString, buf[0]) |
385 } | 430 } |
386 | 431 |
387 if !ok { | 432 if !ok { |
388 » » return nil, errors.New("ssh: failed to read version string") | 433 » » return nil, errors.New("ssh: overflow reading version string") |
389 } | 434 } |
390 | 435 |
391 // There might be a '\r' on the end which we should remove. | 436 // There might be a '\r' on the end which we should remove. |
392 if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' { | 437 if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' { |
393 versionString = versionString[:len(versionString)-1] | 438 versionString = versionString[:len(versionString)-1] |
394 } | 439 } |
395 return versionString, nil | 440 return versionString, nil |
396 } | 441 } |
OLD | NEW |