github.com/glycerine/xcryptossh@v7.0.4+incompatible/test/session_test.go (about)

     1  // Copyright 2012 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  
     5  // +build !windows
     6  
     7  package test
     8  
     9  // Session functional tests.
    10  
    11  import (
    12  	"bytes"
    13  	"context"
    14  	"errors"
    15  	"io"
    16  	"strings"
    17  	"testing"
    18  
    19  	"github.com/glycerine/xcryptossh"
    20  )
    21  
    22  func TestRunCommandSuccess(t *testing.T) {
    23  
    24  	ctx, cancelctx := context.WithCancel(context.Background())
    25  	defer cancelctx()
    26  	halt := ssh.NewHalter()
    27  	defer halt.ReqStop.Close()
    28  
    29  	server := newServer(t)
    30  	defer server.Shutdown()
    31  	conn := server.Dial(ctx, clientConfig(halt))
    32  	defer conn.Close()
    33  
    34  	session, err := conn.NewSession(ctx)
    35  	if err != nil {
    36  		t.Fatalf("session failed: %v", err)
    37  	}
    38  	defer session.Close()
    39  	err = session.Run("true")
    40  	if err != nil {
    41  		t.Fatalf("session failed: %v", err)
    42  	}
    43  }
    44  
    45  func TestHostKeyCheck(t *testing.T) {
    46  	ctx, cancelctx := context.WithCancel(context.Background())
    47  	defer cancelctx()
    48  	halt := ssh.NewHalter()
    49  	defer halt.ReqStop.Close()
    50  
    51  	server := newServer(t)
    52  	defer server.Shutdown()
    53  
    54  	conf := clientConfig(halt)
    55  	hostDB := hostKeyDB()
    56  	conf.HostKeyCallback = hostDB.Check
    57  
    58  	// change the keys.
    59  	hostDB.keys[ssh.KeyAlgoRSA][25]++
    60  	hostDB.keys[ssh.KeyAlgoDSA][25]++
    61  	hostDB.keys[ssh.KeyAlgoECDSA256][25]++
    62  
    63  	conn, err := server.TryDial(ctx, conf)
    64  	if err == nil {
    65  		conn.Close()
    66  		t.Fatalf("dial should have failed.")
    67  	} else if !strings.Contains(err.Error(), "host key mismatch") {
    68  		t.Fatalf("'host key mismatch' not found in %v", err)
    69  	}
    70  }
    71  
    72  func TestRunCommandStdin(t *testing.T) {
    73  	ctx, cancelctx := context.WithCancel(context.Background())
    74  	defer cancelctx()
    75  	halt := ssh.NewHalter()
    76  	defer halt.ReqStop.Close()
    77  
    78  	server := newServer(t)
    79  	defer server.Shutdown()
    80  	conn := server.Dial(ctx, clientConfig(halt))
    81  	defer conn.Close()
    82  
    83  	session, err := conn.NewSession(ctx)
    84  	if err != nil {
    85  		t.Fatalf("session failed: %v", err)
    86  	}
    87  	defer session.Close()
    88  
    89  	r, w := io.Pipe()
    90  	defer r.Close()
    91  	defer w.Close()
    92  	session.Stdin = r
    93  
    94  	err = session.Run("true")
    95  	if err != nil {
    96  		t.Fatalf("session failed: %v", err)
    97  	}
    98  }
    99  
   100  func TestRunCommandStdinError(t *testing.T) {
   101  	ctx, cancelctx := context.WithCancel(context.Background())
   102  	defer cancelctx()
   103  	halt := ssh.NewHalter()
   104  	defer halt.ReqStop.Close()
   105  
   106  	server := newServer(t)
   107  	defer server.Shutdown()
   108  	conn := server.Dial(ctx, clientConfig(halt))
   109  	defer conn.Close()
   110  
   111  	session, err := conn.NewSession(ctx)
   112  	if err != nil {
   113  		t.Fatalf("session failed: %v", err)
   114  	}
   115  	defer session.Close()
   116  
   117  	r, w := io.Pipe()
   118  	defer r.Close()
   119  	session.Stdin = r
   120  	pipeErr := errors.New("closing write end of pipe")
   121  	w.CloseWithError(pipeErr)
   122  
   123  	err = session.Run("true")
   124  	if err != pipeErr {
   125  		t.Fatalf("expected %v, found %v", pipeErr, err)
   126  	}
   127  }
   128  
   129  func TestRunCommandFailed(t *testing.T) {
   130  	ctx, cancelctx := context.WithCancel(context.Background())
   131  	defer cancelctx()
   132  	halt := ssh.NewHalter()
   133  	defer halt.ReqStop.Close()
   134  
   135  	server := newServer(t)
   136  	defer server.Shutdown()
   137  	conn := server.Dial(ctx, clientConfig(halt))
   138  	defer conn.Close()
   139  
   140  	session, err := conn.NewSession(ctx)
   141  	if err != nil {
   142  		t.Fatalf("session failed: %v", err)
   143  	}
   144  	defer session.Close()
   145  	err = session.Run(`bash -c "kill -9 $$"`)
   146  	if err == nil {
   147  		t.Fatalf("session succeeded: %v", err)
   148  	}
   149  }
   150  
   151  func TestRunCommandWeClosed(t *testing.T) {
   152  	ctx, cancelctx := context.WithCancel(context.Background())
   153  	defer cancelctx()
   154  	halt := ssh.NewHalter()
   155  	defer halt.ReqStop.Close()
   156  
   157  	server := newServer(t)
   158  	defer server.Shutdown()
   159  	conn := server.Dial(ctx, clientConfig(halt))
   160  	defer conn.Close()
   161  
   162  	session, err := conn.NewSession(ctx)
   163  	if err != nil {
   164  		t.Fatalf("session failed: %v", err)
   165  	}
   166  	err = session.Shell()
   167  	if err != nil {
   168  		t.Fatalf("shell failed: %v", err)
   169  	}
   170  	err = session.Close()
   171  	if err != nil {
   172  		t.Fatalf("shell failed: %v", err)
   173  	}
   174  }
   175  
   176  func TestFuncLargeRead(t *testing.T) {
   177  	ctx, cancelctx := context.WithCancel(context.Background())
   178  	defer cancelctx()
   179  	halt := ssh.NewHalter()
   180  	defer halt.ReqStop.Close()
   181  
   182  	server := newServer(t)
   183  	defer server.Shutdown()
   184  	conn := server.Dial(ctx, clientConfig(halt))
   185  	defer conn.Close()
   186  
   187  	session, err := conn.NewSession(ctx)
   188  	if err != nil {
   189  		t.Fatalf("unable to create new session: %s", err)
   190  	}
   191  
   192  	stdout, err := session.StdoutPipe()
   193  	if err != nil {
   194  		t.Fatalf("unable to acquire stdout pipe: %s", err)
   195  	}
   196  
   197  	err = session.Start("dd if=/dev/urandom bs=2048 count=1024")
   198  	if err != nil {
   199  		t.Fatalf("unable to execute remote command: %s", err)
   200  	}
   201  
   202  	buf := new(bytes.Buffer)
   203  	n, err := io.Copy(buf, stdout)
   204  	if err != nil {
   205  		t.Fatalf("error reading from remote stdout: %s", err)
   206  	}
   207  
   208  	if n != 2048*1024 {
   209  		t.Fatalf("Expected %d bytes but read only %d from remote command", 2048, n)
   210  	}
   211  }
   212  
   213  func TestKeyChange(t *testing.T) {
   214  	ctx, cancelctx := context.WithCancel(context.Background())
   215  	defer cancelctx()
   216  	halt := ssh.NewHalter()
   217  	defer halt.ReqStop.Close()
   218  
   219  	server := newServer(t)
   220  	defer server.Shutdown()
   221  	conf := clientConfig(halt)
   222  	hostDB := hostKeyDB()
   223  	conf.HostKeyCallback = hostDB.Check
   224  	conf.RekeyThreshold = 1024
   225  	conn := server.Dial(ctx, conf)
   226  	defer conn.Close()
   227  
   228  	for i := 0; i < 4; i++ {
   229  		session, err := conn.NewSession(ctx)
   230  		if err != nil {
   231  			t.Fatalf("unable to create new session: %s", err)
   232  		}
   233  
   234  		stdout, err := session.StdoutPipe()
   235  		if err != nil {
   236  			t.Fatalf("unable to acquire stdout pipe: %s", err)
   237  		}
   238  
   239  		err = session.Start("dd if=/dev/urandom bs=1024 count=1")
   240  		if err != nil {
   241  			t.Fatalf("unable to execute remote command: %s", err)
   242  		}
   243  		buf := new(bytes.Buffer)
   244  		n, err := io.Copy(buf, stdout)
   245  		if err != nil {
   246  			t.Fatalf("error reading from remote stdout: %s", err)
   247  		}
   248  
   249  		want := int64(1024)
   250  		if n != want {
   251  			t.Fatalf("Expected %d bytes but read only %d from remote command", want, n)
   252  		}
   253  	}
   254  
   255  	if changes := hostDB.checkCount; changes < 4 {
   256  		t.Errorf("got %d key changes, want 4", changes)
   257  	}
   258  }
   259  
   260  func TestInvalidTerminalMode(t *testing.T) {
   261  	ctx, cancelctx := context.WithCancel(context.Background())
   262  	defer cancelctx()
   263  	halt := ssh.NewHalter()
   264  	defer halt.ReqStop.Close()
   265  
   266  	server := newServer(t)
   267  	defer server.Shutdown()
   268  	conn := server.Dial(ctx, clientConfig(halt))
   269  	defer conn.Close()
   270  
   271  	session, err := conn.NewSession(ctx)
   272  	if err != nil {
   273  		t.Fatalf("session failed: %v", err)
   274  	}
   275  	defer session.Close()
   276  
   277  	if err = session.RequestPty("vt100", 80, 40, ssh.TerminalModes{255: 1984}); err == nil {
   278  		t.Fatalf("req-pty failed: successful request with invalid mode")
   279  	}
   280  }
   281  
   282  func TestValidTerminalMode(t *testing.T) {
   283  	ctx, cancelctx := context.WithCancel(context.Background())
   284  	defer cancelctx()
   285  	halt := ssh.NewHalter()
   286  	defer halt.ReqStop.Close()
   287  
   288  	server := newServer(t)
   289  	defer server.Shutdown()
   290  	conn := server.Dial(ctx, clientConfig(halt))
   291  	defer conn.Close()
   292  
   293  	session, err := conn.NewSession(ctx)
   294  	if err != nil {
   295  		t.Fatalf("session failed: %v", err)
   296  	}
   297  	defer session.Close()
   298  
   299  	stdout, err := session.StdoutPipe()
   300  	if err != nil {
   301  		t.Fatalf("unable to acquire stdout pipe: %s", err)
   302  	}
   303  
   304  	stdin, err := session.StdinPipe()
   305  	if err != nil {
   306  		t.Fatalf("unable to acquire stdin pipe: %s", err)
   307  	}
   308  
   309  	tm := ssh.TerminalModes{ssh.ECHO: 0}
   310  	if err = session.RequestPty("xterm", 80, 40, tm); err != nil {
   311  		t.Fatalf("req-pty failed: %s", err)
   312  	}
   313  
   314  	err = session.Shell()
   315  	if err != nil {
   316  		t.Fatalf("session failed: %s", err)
   317  	}
   318  
   319  	stdin.Write([]byte("stty -a && exit\n"))
   320  
   321  	var buf bytes.Buffer
   322  	if _, err := io.Copy(&buf, stdout); err != nil {
   323  		t.Fatalf("reading failed: %s", err)
   324  	}
   325  
   326  	if sttyOutput := buf.String(); !strings.Contains(sttyOutput, "-echo ") {
   327  		t.Fatalf("terminal mode failure: expected -echo in stty output, got %s", sttyOutput)
   328  	}
   329  }
   330  
   331  func TestWindowChange(t *testing.T) {
   332  	ctx, cancelctx := context.WithCancel(context.Background())
   333  	defer cancelctx()
   334  	halt := ssh.NewHalter()
   335  	defer halt.ReqStop.Close()
   336  
   337  	server := newServer(t)
   338  	defer server.Shutdown()
   339  	conn := server.Dial(ctx, clientConfig(halt))
   340  	defer conn.Close()
   341  
   342  	session, err := conn.NewSession(ctx)
   343  	if err != nil {
   344  		t.Fatalf("session failed: %v", err)
   345  	}
   346  	defer session.Close()
   347  
   348  	stdout, err := session.StdoutPipe()
   349  	if err != nil {
   350  		t.Fatalf("unable to acquire stdout pipe: %s", err)
   351  	}
   352  
   353  	stdin, err := session.StdinPipe()
   354  	if err != nil {
   355  		t.Fatalf("unable to acquire stdin pipe: %s", err)
   356  	}
   357  
   358  	tm := ssh.TerminalModes{ssh.ECHO: 0}
   359  	if err = session.RequestPty("xterm", 80, 40, tm); err != nil {
   360  		t.Fatalf("req-pty failed: %s", err)
   361  	}
   362  
   363  	if err := session.WindowChange(100, 100); err != nil {
   364  		t.Fatalf("window-change failed: %s", err)
   365  	}
   366  
   367  	err = session.Shell()
   368  	if err != nil {
   369  		t.Fatalf("session failed: %s", err)
   370  	}
   371  
   372  	stdin.Write([]byte("stty size && exit\n"))
   373  
   374  	var buf bytes.Buffer
   375  	if _, err := io.Copy(&buf, stdout); err != nil {
   376  		t.Fatalf("reading failed: %s", err)
   377  	}
   378  
   379  	if sttyOutput := buf.String(); !strings.Contains(sttyOutput, "100 100") {
   380  		t.Fatalf("terminal WindowChange failure: expected \"100 100\" stty output, got %s", sttyOutput)
   381  	}
   382  }
   383  
   384  func TestCiphers(t *testing.T) {
   385  	ctx, cancelctx := context.WithCancel(context.Background())
   386  	defer cancelctx()
   387  	halt := ssh.NewHalter()
   388  	defer halt.ReqStop.Close()
   389  
   390  	var config ssh.Config
   391  	config.SetDefaults()
   392  	cipherOrder := config.Ciphers
   393  	// These ciphers will not be tested when commented out in cipher.go it will
   394  	// fallback to the next available as per line 292.
   395  	cipherOrder = append(cipherOrder, "aes128-cbc", "3des-cbc")
   396  
   397  	for _, ciph := range cipherOrder {
   398  		server := newServer(t)
   399  		defer server.Shutdown()
   400  		conf := clientConfig(halt)
   401  		conf.Ciphers = []string{ciph}
   402  		// Don't fail if sshd doesn't have the cipher.
   403  		conf.Ciphers = append(conf.Ciphers, cipherOrder...)
   404  		conn, err := server.TryDial(ctx, conf)
   405  		if err == nil {
   406  			conn.Close()
   407  		} else {
   408  			t.Fatalf("failed for cipher %q", ciph)
   409  		}
   410  	}
   411  }
   412  
   413  func TestMACs(t *testing.T) {
   414  	ctx, cancelctx := context.WithCancel(context.Background())
   415  	defer cancelctx()
   416  	halt := ssh.NewHalter()
   417  	defer halt.ReqStop.Close()
   418  
   419  	var config ssh.Config
   420  	config.SetDefaults()
   421  	macOrder := config.MACs
   422  
   423  	for _, mac := range macOrder {
   424  		server := newServer(t)
   425  		defer server.Shutdown()
   426  		conf := clientConfig(halt)
   427  		conf.MACs = []string{mac}
   428  		// Don't fail if sshd doesn't have the MAC.
   429  		conf.MACs = append(conf.MACs, macOrder...)
   430  		if conn, err := server.TryDial(ctx, conf); err == nil {
   431  			conn.Close()
   432  		} else {
   433  			t.Fatalf("failed for MAC %q", mac)
   434  		}
   435  	}
   436  }
   437  
   438  func TestKeyExchanges(t *testing.T) {
   439  	ctx, cancelctx := context.WithCancel(context.Background())
   440  	defer cancelctx()
   441  	halt := ssh.NewHalter()
   442  	defer halt.ReqStop.Close()
   443  
   444  	var config ssh.Config
   445  	config.SetDefaults()
   446  	kexOrder := config.KeyExchanges
   447  	for _, kex := range kexOrder {
   448  		server := newServer(t)
   449  		defer server.Shutdown()
   450  		conf := clientConfig(halt)
   451  		// Don't fail if sshd doesn't have the kex.
   452  		conf.KeyExchanges = append([]string{kex}, kexOrder...)
   453  		conn, err := server.TryDial(ctx, conf)
   454  		if err == nil {
   455  			conn.Close()
   456  		} else {
   457  			t.Errorf("failed for kex %q", kex)
   458  		}
   459  	}
   460  }
   461  
   462  func TestClientAuthAlgorithms(t *testing.T) {
   463  	ctx, cancelctx := context.WithCancel(context.Background())
   464  	defer cancelctx()
   465  	halt := ssh.NewHalter()
   466  	defer halt.ReqStop.Close()
   467  
   468  	for _, key := range []string{
   469  		"rsa",
   470  		"dsa",
   471  		"ecdsa",
   472  		"ed25519",
   473  	} {
   474  		server := newServer(t)
   475  		conf := clientConfig(halt)
   476  		conf.SetDefaults()
   477  		conf.Auth = []ssh.AuthMethod{
   478  			ssh.PublicKeys(testSigners[key]),
   479  		}
   480  
   481  		conn, err := server.TryDial(ctx, conf)
   482  		if err == nil {
   483  			conn.Close()
   484  		} else {
   485  			t.Errorf("failed for key %q", key)
   486  		}
   487  
   488  		server.Shutdown()
   489  	}
   490  }