LEFT | RIGHT |
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 // Session tests. | 7 // Session tests. |
8 | 8 |
9 import ( | 9 import ( |
10 "bytes" | 10 "bytes" |
11 crypto_rand "crypto/rand" | 11 crypto_rand "crypto/rand" |
12 "io" | 12 "io" |
13 "io/ioutil" | 13 "io/ioutil" |
14 "log" | |
15 "math/rand" | 14 "math/rand" |
16 "net" | 15 "net" |
17 "testing" | 16 "testing" |
18 | 17 |
19 "code.google.com/p/go.crypto/ssh/terminal" | 18 "code.google.com/p/go.crypto/ssh/terminal" |
20 ) | 19 ) |
21 | 20 |
22 var _ = log.Println | 21 type serverType func(*channel, *testing.T) |
23 | |
24 type serverType func(Channel, *testing.T) | |
25 | 22 |
26 // dial constructs a new test server and returns a *ClientConn. | 23 // dial constructs a new test server and returns a *ClientConn. |
27 func dial(handler serverType, t *testing.T) *ClientConn { | 24 func dial(handler serverType, t *testing.T) *ClientConn { |
28 l, err := Listen("tcp", "127.0.0.1:0", serverConfig) | 25 l, err := Listen("tcp", "127.0.0.1:0", serverConfig) |
29 if err != nil { | 26 if err != nil { |
30 t.Fatalf("unable to listen: %v", err) | 27 t.Fatalf("unable to listen: %v", err) |
31 } | 28 } |
32 go func() { | 29 go func() { |
33 defer l.Close() | 30 defer l.Close() |
34 conn, err := l.Accept() | 31 conn, err := l.Accept() |
(...skipping 18 matching lines...) Expand all Loading... |
53 } | 50 } |
54 if err != nil { | 51 if err != nil { |
55 t.Errorf("Unable to accept incoming channel requ
est: %v", err) | 52 t.Errorf("Unable to accept incoming channel requ
est: %v", err) |
56 return | 53 return |
57 } | 54 } |
58 if ch.ChannelType() != "session" { | 55 if ch.ChannelType() != "session" { |
59 ch.Reject(UnknownChannelType, "unknown channel t
ype") | 56 ch.Reject(UnknownChannelType, "unknown channel t
ype") |
60 continue | 57 continue |
61 } | 58 } |
62 | 59 |
63 » » » ch.Accept() | 60 » » » if err = ch.Accept(); err != nil { |
| 61 » » » » t.Errorf("Accept: %v", err) |
| 62 » » » } |
64 go func() { | 63 go func() { |
65 defer close(done) | 64 defer close(done) |
66 » » » » handler(ch, t) | 65 » » » » handler(ch.(*compatChannel).channel, t) |
67 }() | 66 }() |
68 } | 67 } |
69 <-done | 68 <-done |
70 }() | 69 }() |
71 | 70 |
72 config := &ClientConfig{ | 71 config := &ClientConfig{ |
73 User: "testuser", | 72 User: "testuser", |
74 Auth: []ClientAuth{ | 73 Auth: []ClientAuth{ |
75 ClientAuthPassword(clientPassword), | 74 ClientAuthPassword(clientPassword), |
76 }, | 75 }, |
77 } | 76 } |
78 | 77 |
79 c, err := Dial("tcp", l.Addr().String(), config) | 78 c, err := Dial("tcp", l.Addr().String(), config) |
80 if err != nil { | 79 if err != nil { |
81 t.Fatalf("unable to dial remote side: %v", err) | 80 t.Fatalf("unable to dial remote side: %v", err) |
82 } | 81 } |
83 return c | 82 return c |
84 } | 83 } |
85 | 84 |
86 // TEST a simple string is returned to session.Stdout. | 85 // Test a simple string is returned to session.Stdout. |
87 func TestSessionShell(t *testing.T) { | 86 func TestSessionShell(t *testing.T) { |
88 conn := dial(shellHandler, t) | 87 conn := dial(shellHandler, t) |
89 defer conn.Close() | 88 defer conn.Close() |
90 session, err := conn.NewSession() | 89 session, err := conn.NewSession() |
91 if err != nil { | 90 if err != nil { |
92 t.Fatalf("Unable to request new session: %v", err) | 91 t.Fatalf("Unable to request new session: %v", err) |
93 } | 92 } |
94 defer session.Close() | 93 defer session.Close() |
95 stdout := new(bytes.Buffer) | 94 stdout := new(bytes.Buffer) |
96 session.Stdout = stdout | 95 session.Stdout = stdout |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
327 t.Fatalf("expected command to fail but it didn't") | 326 t.Fatalf("expected command to fail but it didn't") |
328 } | 327 } |
329 _, ok := err.(*ExitError) | 328 _, ok := err.(*ExitError) |
330 if ok { | 329 if ok { |
331 // you can't actually test for errors.errorString | 330 // you can't actually test for errors.errorString |
332 // because it's not exported. | 331 // because it's not exported. |
333 t.Fatalf("expected *errorString but got %T", err) | 332 t.Fatalf("expected *errorString but got %T", err) |
334 } | 333 } |
335 } | 334 } |
336 | 335 |
337 // Verify that the client never accepts a packet larger than maxpacket. | |
338 func TestServerStdoutRespectsMaxPacketSize(t *testing.T) { | |
339 conn := dial(largeSendHandler, t) | |
340 defer conn.Close() | |
341 session, err := conn.NewSession() | |
342 if err != nil { | |
343 t.Fatalf("Unable to request new session: %v", err) | |
344 } | |
345 defer session.Close() | |
346 out, err := session.StdoutPipe() | |
347 if err != nil { | |
348 t.Fatalf("Unable to connect to Stdout: %v", err) | |
349 } | |
350 if err := session.Shell(); err != nil { | |
351 t.Fatalf("Unable to execute command: %v", err) | |
352 } | |
353 if _, err := ioutil.ReadAll(out); err != nil { | |
354 t.Fatalf("failed to read: %v", err) | |
355 } | |
356 } | |
357 | |
358 // TODO(hanwen): this test should be at the transport level. | 336 // TODO(hanwen): this test should be at the transport level. |
359 func TestClientCannotSendHugePacket(t *testing.T) { | 337 func TestClientCannotSendHugePacket(t *testing.T) { |
360 // client and server use the same transport write code so this | 338 // client and server use the same transport write code so this |
361 // test suffices for both. | 339 // test suffices for both. |
362 conn := dial(shellHandler, t) | 340 conn := dial(shellHandler, t) |
363 defer conn.Close() | 341 defer conn.Close() |
364 if err := conn.transport.writePacket(make([]byte, maxPacket*2)); err ==
nil { | 342 if err := conn.transport.writePacket(make([]byte, maxPacket*2)); err ==
nil { |
365 t.Fatalf("huge packet write should fail") | 343 t.Fatalf("huge packet write should fail") |
366 } | 344 } |
367 } | 345 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 } | 377 } |
400 result <- echoedBuf.Bytes() | 378 result <- echoedBuf.Bytes() |
401 }() | 379 }() |
402 | 380 |
403 serverStdin, err := session.StdinPipe() | 381 serverStdin, err := session.StdinPipe() |
404 if err != nil { | 382 if err != nil { |
405 t.Fatalf("StdinPipe failed: %v", err) | 383 t.Fatalf("StdinPipe failed: %v", err) |
406 } | 384 } |
407 written, err := copyNRandomly("stdin", serverStdin, origBuf, windowTestB
ytes) | 385 written, err := copyNRandomly("stdin", serverStdin, origBuf, windowTestB
ytes) |
408 if err != nil { | 386 if err != nil { |
409 » » t.Fatalf("falied to copy origBuf to serverStdin: %v", err) | 387 » » t.Fatalf("failed to copy origBuf to serverStdin: %v", err) |
410 } | 388 } |
411 if written != windowTestBytes { | 389 if written != windowTestBytes { |
412 t.Fatalf("Wrote only %d of %d bytes to server", written, windowT
estBytes) | 390 t.Fatalf("Wrote only %d of %d bytes to server", written, windowT
estBytes) |
413 } | 391 } |
414 | 392 |
415 echoedBytes := <-result | 393 echoedBytes := <-result |
416 | 394 |
417 if !bytes.Equal(origBytes, echoedBytes) { | 395 if !bytes.Equal(origBytes, echoedBytes) { |
418 t.Fatalf("Echoed buffer differed from original, orig %d, echoed
%d", len(origBytes), len(echoedBytes)) | 396 t.Fatalf("Echoed buffer differed from original, orig %d, echoed
%d", len(origBytes), len(echoedBytes)) |
419 } | 397 } |
(...skipping 21 matching lines...) Expand all Loading... |
441 Status uint32 | 419 Status uint32 |
442 } | 420 } |
443 | 421 |
444 type exitSignalMsg struct { | 422 type exitSignalMsg struct { |
445 Signal string | 423 Signal string |
446 CoreDumped bool | 424 CoreDumped bool |
447 Errmsg string | 425 Errmsg string |
448 Lang string | 426 Lang string |
449 } | 427 } |
450 | 428 |
451 func newServerShell(ch Channel, prompt string) *ServerTerminal { | 429 func newServerShell(ch *channel, prompt string) *ServerTerminal { |
452 term := terminal.NewTerminal(ch, prompt) | 430 term := terminal.NewTerminal(ch, prompt) |
453 s := &ServerTerminal{ | 431 s := &ServerTerminal{ |
454 Term: term, | 432 Term: term, |
455 » » Channel: ch, | 433 » » Channel: newCompatChannel(ch), |
456 » } | 434 » } |
457 » go s.HandleRequests() | |
458 return s | 435 return s |
459 } | 436 } |
460 | 437 |
461 func exitStatusZeroHandler(ch Channel, t *testing.T) { | 438 func exitStatusZeroHandler(ch *channel, t *testing.T) { |
462 defer ch.Close() | 439 defer ch.Close() |
463 // this string is returned to stdout | 440 // this string is returned to stdout |
464 shell := newServerShell(ch, "> ") | 441 shell := newServerShell(ch, "> ") |
465 readLine(shell, t) | 442 readLine(shell, t) |
466 sendStatus(0, ch, t) | 443 sendStatus(0, ch, t) |
467 } | 444 } |
468 | 445 |
469 func exitStatusNonZeroHandler(ch Channel, t *testing.T) { | 446 func exitStatusNonZeroHandler(ch *channel, t *testing.T) { |
470 defer ch.Close() | 447 defer ch.Close() |
471 shell := newServerShell(ch, "> ") | 448 shell := newServerShell(ch, "> ") |
472 readLine(shell, t) | 449 readLine(shell, t) |
473 sendStatus(15, ch, t) | 450 sendStatus(15, ch, t) |
474 } | 451 } |
475 | 452 |
476 func exitSignalAndStatusHandler(ch Channel, t *testing.T) { | 453 func exitSignalAndStatusHandler(ch *channel, t *testing.T) { |
477 defer ch.Close() | 454 defer ch.Close() |
478 shell := newServerShell(ch, "> ") | 455 shell := newServerShell(ch, "> ") |
479 readLine(shell, t) | 456 readLine(shell, t) |
480 sendStatus(15, ch, t) | 457 sendStatus(15, ch, t) |
481 sendSignal("TERM", ch, t) | 458 sendSignal("TERM", ch, t) |
482 } | 459 } |
483 | 460 |
484 func exitSignalHandler(ch Channel, t *testing.T) { | 461 func exitSignalHandler(ch *channel, t *testing.T) { |
485 defer ch.Close() | 462 defer ch.Close() |
486 shell := newServerShell(ch, "> ") | 463 shell := newServerShell(ch, "> ") |
487 readLine(shell, t) | 464 readLine(shell, t) |
488 sendSignal("TERM", ch, t) | 465 sendSignal("TERM", ch, t) |
489 } | 466 } |
490 | 467 |
491 func exitSignalUnknownHandler(ch Channel, t *testing.T) { | 468 func exitSignalUnknownHandler(ch *channel, t *testing.T) { |
492 defer ch.Close() | 469 defer ch.Close() |
493 shell := newServerShell(ch, "> ") | 470 shell := newServerShell(ch, "> ") |
494 readLine(shell, t) | 471 readLine(shell, t) |
495 sendSignal("SYS", ch, t) | 472 sendSignal("SYS", ch, t) |
496 } | 473 } |
497 | 474 |
498 func exitWithoutSignalOrStatus(ch Channel, t *testing.T) { | 475 func exitWithoutSignalOrStatus(ch *channel, t *testing.T) { |
499 defer ch.Close() | 476 defer ch.Close() |
500 shell := newServerShell(ch, "> ") | 477 shell := newServerShell(ch, "> ") |
501 readLine(shell, t) | 478 readLine(shell, t) |
502 } | 479 } |
503 | 480 |
504 func shellHandler(ch Channel, t *testing.T) { | 481 func shellHandler(ch *channel, t *testing.T) { |
505 defer ch.Close() | 482 defer ch.Close() |
506 // this string is returned to stdout | 483 // this string is returned to stdout |
507 shell := newServerShell(ch, "golang") | 484 shell := newServerShell(ch, "golang") |
508 readLine(shell, t) | 485 readLine(shell, t) |
509 sendStatus(0, ch, t) | 486 sendStatus(0, ch, t) |
510 } | 487 } |
511 | 488 |
512 // Ignores the command, writes fixed strings to stderr and stdout. | 489 // Ignores the command, writes fixed strings to stderr and stdout. |
513 // Strings are "this-is-stdout." and "this-is-stderr.". | 490 // Strings are "this-is-stdout." and "this-is-stderr.". |
514 func fixedOutputHandler(ch Channel, t *testing.T) { | 491 func fixedOutputHandler(ch *channel, t *testing.T) { |
515 » defer ch.Close() | 492 » defer ch.Close() |
516 | 493 » _, err := ch.Read(make([]byte, 0)) |
517 » _ = <-ch.ReceivedRequests() | 494 » if _, ok := err.(ChannelRequest); !ok { |
| 495 » » t.Fatalf("error: expected channel request, got: %#v", err) |
| 496 » » return |
| 497 » } |
| 498 |
518 // ignore request, always send some text | 499 // ignore request, always send some text |
519 ch.AckRequest(true) | 500 ch.AckRequest(true) |
520 | 501 |
521 » _, err := io.WriteString(ch, "this-is-stdout.") | 502 » _, err = io.WriteString(ch, "this-is-stdout.") |
522 if err != nil { | 503 if err != nil { |
523 t.Fatalf("error writing on server: %v", err) | 504 t.Fatalf("error writing on server: %v", err) |
524 } | 505 } |
525 » _, err = io.WriteString(ch.Stderr(), "this-is-stderr.") | 506 » _, err = io.WriteString(ch.Extended(1), "this-is-stderr.") |
526 if err != nil { | 507 if err != nil { |
527 t.Fatalf("error writing on server: %v", err) | 508 t.Fatalf("error writing on server: %v", err) |
528 } | 509 } |
529 sendStatus(0, ch, t) | 510 sendStatus(0, ch, t) |
530 } | 511 } |
531 | 512 |
532 func readLine(shell *ServerTerminal, t *testing.T) { | 513 func readLine(shell *ServerTerminal, t *testing.T) { |
533 if _, err := shell.ReadLine(); err != nil && err != io.EOF { | 514 if _, err := shell.ReadLine(); err != nil && err != io.EOF { |
534 t.Errorf("unable to read line: %v", err) | 515 t.Errorf("unable to read line: %v", err) |
535 } | 516 } |
536 } | 517 } |
537 | 518 |
538 func sendStatus(status uint32, ch Channel, t *testing.T) { | 519 func sendStatus(status uint32, ch *channel, t *testing.T) { |
539 msg := exitStatusMsg{ | 520 msg := exitStatusMsg{ |
540 Status: status, | 521 Status: status, |
541 } | 522 } |
542 if _, err := ch.SendRequest("exit-status", false, marshal(0, msg)); err
!= nil { | 523 if _, err := ch.SendRequest("exit-status", false, marshal(0, msg)); err
!= nil { |
543 t.Errorf("unable to send status: %v", err) | 524 t.Errorf("unable to send status: %v", err) |
544 } | 525 } |
545 } | 526 } |
546 | 527 |
547 func sendSignal(signal string, ch Channel, t *testing.T) { | 528 func sendSignal(signal string, ch *channel, t *testing.T) { |
548 sig := exitSignalMsg{ | 529 sig := exitSignalMsg{ |
549 Signal: signal, | 530 Signal: signal, |
550 CoreDumped: false, | 531 CoreDumped: false, |
551 Errmsg: "Process terminated", | 532 Errmsg: "Process terminated", |
552 Lang: "en-GB-oed", | 533 Lang: "en-GB-oed", |
553 } | 534 } |
554 if _, err := ch.SendRequest("exit-signal", false, marshal(0, sig)); err
!= nil { | 535 if _, err := ch.SendRequest("exit-signal", false, marshal(0, sig)); err
!= nil { |
555 t.Errorf("unable to send signal: %v", err) | 536 t.Errorf("unable to send signal: %v", err) |
556 } | 537 } |
557 } | 538 } |
558 | 539 |
559 func discardHandler(ch Channel, t *testing.T) { | 540 func discardHandler(ch *channel, t *testing.T) { |
560 defer ch.Close() | 541 defer ch.Close() |
561 // grow the window to avoid being fooled by | 542 // grow the window to avoid being fooled by |
562 // the initial 1 << 14 window. | 543 // the initial 1 << 14 window. |
563 » ch.(*channel).adjustWindow(1024 * 1024) | 544 » ch.adjustWindow(1024 * 1024) |
564 | 545 |
565 io.Copy(ioutil.Discard, ch) | 546 io.Copy(ioutil.Discard, ch) |
566 } | 547 } |
567 | 548 |
568 func largeSendHandler(ch Channel, t *testing.T) { | 549 func echoHandler(ch *channel, t *testing.T) { |
569 » defer ch.Close() | |
570 » // grow the window to avoid being fooled by | |
571 » // the initial 1 << 14 window. | |
572 » pCh := ch.(*channel) | |
573 » pCh.adjustWindow(1024 * 1024) | |
574 » shell := newServerShell(ch, "> ") | |
575 » readLine(shell, t) | |
576 » // try to send more than the 32k window | |
577 » // will allow | |
578 » if err := pCh.writePacket(make([]byte, 128*1024)); err == nil { | |
579 » » t.Errorf("wrote packet larger than 32k") | |
580 » } | |
581 } | |
582 | |
583 func echoHandler(ch Channel, t *testing.T) { | |
584 defer ch.Close() | 550 defer ch.Close() |
585 if n, err := copyNRandomly("echohandler", ch, ch, windowTestBytes); err
!= nil { | 551 if n, err := copyNRandomly("echohandler", ch, ch, windowTestBytes); err
!= nil { |
586 t.Errorf("short write, wrote %d, expected %d: %v ", n, windowTes
tBytes, err) | 552 t.Errorf("short write, wrote %d, expected %d: %v ", n, windowTes
tBytes, err) |
587 } | 553 } |
588 } | 554 } |
589 | 555 |
590 // copyNRandomly copies n bytes from src to dst. It uses a variable, and random, | 556 // copyNRandomly copies n bytes from src to dst. It uses a variable, and random, |
591 // buffer size to exercise more code paths. | 557 // buffer size to exercise more code paths. |
592 func copyNRandomly(title string, dst io.Writer, src io.Reader, n int) (int, erro
r) { | 558 func copyNRandomly(title string, dst io.Writer, src io.Reader, n int) (int, erro
r) { |
593 var ( | 559 var ( |
(...skipping 16 matching lines...) Expand all Loading... |
610 if nr != nw { | 576 if nr != nw { |
611 return written, io.ErrShortWrite | 577 return written, io.ErrShortWrite |
612 } | 578 } |
613 if er != nil && er != io.EOF { | 579 if er != nil && er != io.EOF { |
614 return written, er | 580 return written, er |
615 } | 581 } |
616 } | 582 } |
617 return written, nil | 583 return written, nil |
618 } | 584 } |
619 | 585 |
620 func channelKeepaliveSender(ch Channel, t *testing.T) { | 586 func channelKeepaliveSender(ch *channel, t *testing.T) { |
621 defer ch.Close() | 587 defer ch.Close() |
622 shell := newServerShell(ch, "> ") | 588 shell := newServerShell(ch, "> ") |
623 readLine(shell, t) | 589 readLine(shell, t) |
624 if _, err := ch.SendRequest("keepalive@openssh.com", true, nil); err !=
nil { | 590 if _, err := ch.SendRequest("keepalive@openssh.com", true, nil); err !=
nil { |
625 t.Errorf("unable to send channel keepalive request: %v", err) | 591 t.Errorf("unable to send channel keepalive request: %v", err) |
626 } | 592 } |
627 sendStatus(0, ch, t) | 593 sendStatus(0, ch, t) |
628 } | 594 } |
| 595 |
| 596 func TestClientWriteEOF(t *testing.T) { |
| 597 conn := dial(simpleEchoHandler, t) |
| 598 defer conn.Close() |
| 599 |
| 600 session, err := conn.NewSession() |
| 601 if err != nil { |
| 602 t.Fatal(err) |
| 603 } |
| 604 defer session.Close() |
| 605 stdin, err := session.StdinPipe() |
| 606 if err != nil { |
| 607 t.Fatalf("StdinPipe failed: %v", err) |
| 608 } |
| 609 stdout, err := session.StdoutPipe() |
| 610 if err != nil { |
| 611 t.Fatalf("StdoutPipe failed: %v", err) |
| 612 } |
| 613 |
| 614 data := []byte(`0000`) |
| 615 _, err = stdin.Write(data) |
| 616 if err != nil { |
| 617 t.Fatalf("Write failed: %v", err) |
| 618 } |
| 619 stdin.Close() |
| 620 |
| 621 res, err := ioutil.ReadAll(stdout) |
| 622 if err != nil { |
| 623 t.Fatalf("Read failed: %v", err) |
| 624 } |
| 625 |
| 626 if !bytes.Equal(data, res) { |
| 627 t.Fatalf("Read differed from write, wrote: %v, read: %v", data,
res) |
| 628 } |
| 629 } |
| 630 |
| 631 func simpleEchoHandler(ch *channel, t *testing.T) { |
| 632 defer ch.Close() |
| 633 data, err := ioutil.ReadAll(ch) |
| 634 if err != nil { |
| 635 t.Errorf("handler read error: %v", err) |
| 636 } |
| 637 _, err = ch.Write(data) |
| 638 if err != nil { |
| 639 t.Errorf("handler write error: %v", err) |
| 640 } |
| 641 } |
LEFT | RIGHT |