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 }