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 import ( | 7 import ( |
8 "encoding/binary" | 8 "encoding/binary" |
9 "errors" | 9 "errors" |
10 "fmt" | 10 "fmt" |
11 "io" | 11 "io" |
12 "log" | 12 "log" |
13 "sync" | 13 "sync" |
14 ) | 14 ) |
15 | 15 |
16 // A Channel is an ordered, reliable, duplex stream that is | 16 // A Channel is an ordered, reliable, duplex stream that is |
17 // multiplexed over an SSH connection. | 17 // multiplexed over an SSH connection. |
18 type Channel interface { | 18 type Channel interface { |
19 // Accept accepts the channel creation request. | 19 // Accept accepts the channel creation request. |
20 Accept() error | 20 Accept() error |
21 | 21 |
22 // Reject rejects the channel creation request. After calling | 22 // Reject rejects the channel creation request. After calling |
23 // this, no other methods on the Channel may be called. | 23 // this, no other methods on the Channel may be called. |
24 Reject(reason RejectionReason, message string) error | 24 Reject(reason RejectionReason, message string) error |
25 | 25 |
26 » // NOSUBMIT - should add ReadExtended/WriteExtended here? | 26 » // Read may return a ChannelRequest as an error. |
27 | |
28 Read(data []byte) (int, error) | 27 Read(data []byte) (int, error) |
29 Write(data []byte) (int, error) | 28 Write(data []byte) (int, error) |
30 | |
31 // Sends EOF to the other side. | |
32 CloseWrite() error | |
33 | 29 |
34 // Signals end of channel use. No data may be sent after this | 30 // Signals end of channel use. No data may be sent after this |
35 // call. | 31 // call. |
36 Close() error | 32 Close() error |
37 | 33 |
38 » // Stderr returns an io.ReadWriter that writes to this channel with the | 34 » // Stderr returns an io.Writer that writes to this channel with the |
39 // extended data type set to stderr. | 35 // extended data type set to stderr. |
40 » Stderr() io.ReadWriter | 36 » Stderr() io.Writer |
41 | |
42 » // SendRequest sends a channel request. | |
43 » SendRequest(name string, wantReply bool, payload []byte) (bool, error) | |
44 | |
45 » // ReceivedRequests returns the channel for out-of-band | |
46 » // requests. For all requests received that have WantReply, a | |
47 » // call of AckRequest should follow. | |
48 » ReceivedRequests() chan *ChannelRequest | |
49 | 37 |
50 // AckRequest either sends an ack or nack to the channel | 38 // AckRequest either sends an ack or nack to the channel |
51 // request. It should only be called if the last | 39 // request. It should only be called if the last |
52 // ChannelRequest had a WantReply | 40 // ChannelRequest had a WantReply |
53 AckRequest(ok bool) error | 41 AckRequest(ok bool) error |
54 | 42 |
55 // ChannelType returns the type of the channel, as supplied by the | 43 // ChannelType returns the type of the channel, as supplied by the |
56 // client. | 44 // client. |
57 ChannelType() string | 45 ChannelType() string |
58 | 46 |
59 » // ExtraData returns the arbitary payload for this channel, as supplied | 47 » // ExtraData returns the arbitrary payload for this channel, as supplied |
60 // by the client. This data is specific to the channel type. | 48 // by the client. This data is specific to the channel type. |
61 ExtraData() []byte | 49 ExtraData() []byte |
62 } | 50 } |
63 | 51 |
64 // ChannelRequest represents a request sent, outside of the normal | 52 // ChannelRequest represents a request sent, outside of the normal |
65 // stream of bytes. Requests may either be channel specific, or global | 53 // stream of bytes. |
66 type ChannelRequest struct { | 54 type ChannelRequest struct { |
67 Request string | 55 Request string |
68 WantReply bool | 56 WantReply bool |
69 Payload []byte | 57 Payload []byte |
| 58 } |
| 59 |
| 60 func (c ChannelRequest) Error() string { |
| 61 return "ssh: channel request received" |
70 } | 62 } |
71 | 63 |
72 // RejectionReason is an enumeration used when rejecting channel creation | 64 // RejectionReason is an enumeration used when rejecting channel creation |
73 // requests. See RFC 4254, section 5.1. | 65 // requests. See RFC 4254, section 5.1. |
74 type RejectionReason uint32 | 66 type RejectionReason uint32 |
75 | 67 |
76 const ( | 68 const ( |
77 Prohibited RejectionReason = iota + 1 | 69 Prohibited RejectionReason = iota + 1 |
78 ConnectionFailed | 70 ConnectionFailed |
79 UnknownChannelType | 71 UnknownChannelType |
80 ResourceShortage | 72 ResourceShortage |
81 ) | 73 ) |
82 | 74 |
| 75 // String converts the rejection reason to human readable form. |
83 func (r RejectionReason) String() string { | 76 func (r RejectionReason) String() string { |
84 switch r { | 77 switch r { |
85 case Prohibited: | 78 case Prohibited: |
86 » » return "Prohibited" | 79 » » return "administratively prohibited" |
87 case ConnectionFailed: | 80 case ConnectionFailed: |
88 » » return "ConnectionFailed" | 81 » » return "connect failed" |
89 case UnknownChannelType: | 82 case UnknownChannelType: |
90 » » return "UnknownChannelType" | 83 » » return "unknown channel type" |
91 case ResourceShortage: | 84 case ResourceShortage: |
92 » » return "ResourceShortage" | 85 » » return "resource shortage" |
93 } | 86 } |
94 return fmt.Sprintf("unknown reason %d", int(r)) | 87 return fmt.Sprintf("unknown reason %d", int(r)) |
95 } | 88 } |
96 | 89 |
97 // channel implements the Channel | 90 // channel implements the Channel |
98 type channel struct { | 91 type channel struct { |
99 // R/O after creation | 92 // R/O after creation |
100 chanType string | 93 chanType string |
101 extraData []byte | 94 extraData []byte |
102 localId, remoteId uint32 | 95 localId, remoteId uint32 |
103 maxPacket uint32 | 96 maxPacket uint32 |
104 mux *mux | 97 mux *mux |
105 | 98 |
106 // If set, we have called Accept or Reject on this channel | 99 // If set, we have called Accept or Reject on this channel |
107 decided bool | 100 decided bool |
108 | 101 |
109 // Pending internal channel messages. | 102 // Pending internal channel messages. |
110 msg chan interface{} | 103 msg chan interface{} |
111 | 104 |
112 // Pending user-serviceable messages. | 105 // Pending user-serviceable messages. |
113 » sentRequestMu sync.Mutex | 106 » sentRequestMu sync.Mutex |
114 » pendingRequests chan *ChannelRequest | 107 |
| 108 » incomingRequests chan *ChannelRequest |
115 | 109 |
116 sentEOF bool | 110 sentEOF bool |
117 | 111 |
118 // thread-safe data | 112 // thread-safe data |
119 remoteWin window | 113 remoteWin window |
120 pending *buffer | 114 pending *buffer |
121 extPending *buffer | 115 extPending *buffer |
122 | 116 |
123 // Protects all of the below. | 117 // Protects all of the below. |
124 mu sync.Mutex | 118 mu sync.Mutex |
(...skipping 13 matching lines...) Expand all Loading... |
138 if uint32(len(packet)) > c.maxPacket { | 132 if uint32(len(packet)) > c.maxPacket { |
139 return fmt.Errorf("ssh: cannot write %d bytes, maxPacket is %d b
ytes", len(packet), c.maxPacket) | 133 return fmt.Errorf("ssh: cannot write %d bytes, maxPacket is %d b
ytes", len(packet), c.maxPacket) |
140 } | 134 } |
141 | 135 |
142 c.mu.Lock() | 136 c.mu.Lock() |
143 if c.sentClose { | 137 if c.sentClose { |
144 c.mu.Unlock() | 138 c.mu.Unlock() |
145 return io.EOF | 139 return io.EOF |
146 } | 140 } |
147 c.sentClose = (packet[0] == msgChannelClose) | 141 c.sentClose = (packet[0] == msgChannelClose) |
148 » err := c.mux.writePacket(packet) | 142 » err := c.mux.conn.writePacket(packet) |
149 c.mu.Unlock() | 143 c.mu.Unlock() |
150 return err | 144 return err |
151 } | 145 } |
152 | 146 |
153 func (c *channel) sendMessage(code byte, msg interface{}) error { | 147 func (c *channel) sendMessage(code byte, msg interface{}) error { |
154 if debug { | 148 if debug { |
155 log.Printf("send %d: %#v", c.mux.chanList.offset, msg) | 149 log.Printf("send %d: %#v", c.mux.chanList.offset, msg) |
156 } | 150 } |
157 | 151 |
158 p := marshal(code, msg) | 152 p := marshal(code, msg) |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 return c.sendMessage(msgChannelWindowAdjust, windowAdjustMsg{ | 252 return c.sendMessage(msgChannelWindowAdjust, windowAdjustMsg{ |
259 AdditionalBytes: uint32(n), | 253 AdditionalBytes: uint32(n), |
260 }) | 254 }) |
261 } | 255 } |
262 | 256 |
263 func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error)
{ | 257 func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error)
{ |
264 if extended == 1 { | 258 if extended == 1 { |
265 n, err = c.extPending.Read(data) | 259 n, err = c.extPending.Read(data) |
266 } else if extended == 0 { | 260 } else if extended == 0 { |
267 n, err = c.pending.Read(data) | 261 n, err = c.pending.Read(data) |
| 262 } else { |
| 263 return 0, fmt.Errorf("ssh: extended code %d implemented", extend
ed) |
268 } | 264 } |
269 | 265 |
270 if n > 0 { | 266 if n > 0 { |
271 err = c.adjustWindow(uint32(n)) | 267 err = c.adjustWindow(uint32(n)) |
272 // sendWindowAdjust can return io.EOF if the remote | 268 // sendWindowAdjust can return io.EOF if the remote |
273 // peer has closed the connection, however we want to | 269 // peer has closed the connection, however we want to |
274 // defer forwarding io.EOF to the caller of Read until | 270 // defer forwarding io.EOF to the caller of Read until |
275 // the buffer has been drained. | 271 // the buffer has been drained. |
276 if n > 0 && err == io.EOF { | 272 if n > 0 && err == io.EOF { |
277 err = nil | 273 err = nil |
(...skipping 13 matching lines...) Expand all Loading... |
291 case msgChannelData, msgChannelExtendedData: | 287 case msgChannelData, msgChannelExtendedData: |
292 return c.handleData(packet) | 288 return c.handleData(packet) |
293 case msgChannelClose: | 289 case msgChannelClose: |
294 // Ack the close. | 290 // Ack the close. |
295 c.sendMessage(msgChannelClose, channelCloseMsg{ | 291 c.sendMessage(msgChannelClose, channelCloseMsg{ |
296 PeersId: c.remoteId}) | 292 PeersId: c.remoteId}) |
297 | 293 |
298 c.pending.eof() | 294 c.pending.eof() |
299 c.extPending.eof() | 295 c.extPending.eof() |
300 close(c.msg) | 296 close(c.msg) |
301 » » close(c.pendingRequests) | 297 » » close(c.incomingRequests) |
302 c.mux.chanList.remove(c.localId) | 298 c.mux.chanList.remove(c.localId) |
303 | 299 |
304 return nil | 300 return nil |
305 case msgChannelEOF: | 301 case msgChannelEOF: |
306 c.pending.eof() | |
307 // RFC 4254 is mute on how EOF affects dataExt messages but | 302 // RFC 4254 is mute on how EOF affects dataExt messages but |
308 // it is logical to signal EOF at the same time. | 303 // it is logical to signal EOF at the same time. |
309 c.extPending.eof() | 304 c.extPending.eof() |
| 305 |
| 306 // For ServerConn, ChannelRequests are actually output |
| 307 // as Read error. This means that no requests can be |
| 308 // processed after EOF is sent, which is a bug |
| 309 c.pending.eof() |
310 return nil | 310 return nil |
311 } | 311 } |
312 | 312 |
313 decoded, err := decode(packet) | 313 decoded, err := decode(packet) |
314 if err != nil { | 314 if err != nil { |
315 return err | 315 return err |
316 } | 316 } |
317 | 317 |
318 switch msg := decoded.(type) { | 318 switch msg := decoded.(type) { |
319 case *windowAdjustMsg: | 319 case *windowAdjustMsg: |
320 if !c.remoteWin.add(msg.AdditionalBytes) { | 320 if !c.remoteWin.add(msg.AdditionalBytes) { |
321 return fmt.Errorf("invalid window update %d", msg.Additi
onalBytes) | 321 return fmt.Errorf("invalid window update %d", msg.Additi
onalBytes) |
322 } | 322 } |
323 | 323 |
324 case *channelRequestMsg: | 324 case *channelRequestMsg: |
325 req := ChannelRequest{ | 325 req := ChannelRequest{ |
326 Request: msg.Request, | 326 Request: msg.Request, |
327 WantReply: msg.WantReply, | 327 WantReply: msg.WantReply, |
328 Payload: msg.RequestSpecificData, | 328 Payload: msg.RequestSpecificData, |
329 } | 329 } |
330 | 330 |
331 » » c.pendingRequests <- &req | 331 » » c.incomingRequests <- &req |
332 default: | 332 default: |
333 c.msg <- msg | 333 c.msg <- msg |
334 } | 334 } |
335 return nil | 335 return nil |
336 } | 336 } |
337 | 337 |
338 func newChannel(chanType string, extraData []byte) *channel { | 338 func newChannel(chanType string, extraData []byte) *channel { |
339 return &channel{ | 339 return &channel{ |
340 » » remoteWin: window{Cond: newCond()}, | 340 » » remoteWin: window{Cond: newCond()}, |
341 » » myWindow: defaultWindowSize, | 341 » » myWindow: defaultWindowSize, |
342 » » pending: newBuffer(), | 342 » » pending: newBuffer(), |
343 » » extPending: newBuffer(), | 343 » » extPending: newBuffer(), |
344 » » pendingRequests: make(chan *ChannelRequest, 16), | 344 » » incomingRequests: make(chan *ChannelRequest, 16), |
345 » » msg: make(chan interface{}, 16), | 345 » » msg: make(chan interface{}, 16), |
346 » » chanType: chanType, | 346 » » chanType: chanType, |
347 » » extraData: extraData, | 347 » » extraData: extraData, |
348 } | 348 } |
349 } | 349 } |
350 | 350 |
351 var errUndecided = errors.New("ssh: must Accept or Reject channel") | 351 var errUndecided = errors.New("ssh: must Accept or Reject channel") |
352 var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once") | 352 var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once") |
353 | 353 |
354 type extChannel channel | 354 type extChannel struct { |
| 355 » code uint32 |
| 356 » ch *channel |
| 357 } |
355 | 358 |
356 func (e *extChannel) Write(data []byte) (n int, err error) { | 359 func (e *extChannel) Write(data []byte) (n int, err error) { |
357 » return ((*channel)(e)).WriteExtended(data, 1) | 360 » return e.ch.WriteExtended(data, e.code) |
358 } | 361 } |
359 func (e *extChannel) Read(data []byte) (n int, err error) { | 362 func (e *extChannel) Read(data []byte) (n int, err error) { |
360 » return ((*channel)(e)).ReadExtended(data, 1) | 363 » return e.ch.ReadExtended(data, e.code) |
361 } | 364 } |
362 | 365 |
363 func (c *channel) Accept() error { | 366 func (c *channel) Accept() error { |
364 if c.decided { | 367 if c.decided { |
365 return errDecidedAlready | 368 return errDecidedAlready |
366 } | 369 } |
367 confirm := channelOpenConfirmMsg{ | 370 confirm := channelOpenConfirmMsg{ |
368 PeersId: c.remoteId, | 371 PeersId: c.remoteId, |
369 MyId: c.localId, | 372 MyId: c.localId, |
370 MyWindow: c.myWindow, | 373 MyWindow: c.myWindow, |
371 MaxPacketSize: c.maxPacket, | 374 MaxPacketSize: c.maxPacket, |
372 } | 375 } |
373 c.decided = true | 376 c.decided = true |
374 » return c.sendMessage(msgChannelOpenConfirm, confirm) | 377 » if err := c.sendMessage(msgChannelOpenConfirm, confirm); err != nil { |
| 378 » » return err |
| 379 » } |
| 380 |
| 381 » return nil |
375 } | 382 } |
376 | 383 |
377 func (ch *channel) Reject(reason RejectionReason, message string) error { | 384 func (ch *channel) Reject(reason RejectionReason, message string) error { |
378 if ch.decided { | 385 if ch.decided { |
379 return errDecidedAlready | 386 return errDecidedAlready |
380 } | 387 } |
381 reject := channelOpenFailureMsg{ | 388 reject := channelOpenFailureMsg{ |
382 PeersId: ch.remoteId, | 389 PeersId: ch.remoteId, |
383 Reason: reason, | 390 Reason: reason, |
384 Message: message, | 391 Message: message, |
385 Language: "en", | 392 Language: "en", |
386 } | 393 } |
387 ch.decided = true | 394 ch.decided = true |
388 return ch.sendMessage(msgChannelOpenFailure, reject) | 395 return ch.sendMessage(msgChannelOpenFailure, reject) |
389 } | 396 } |
390 | 397 |
391 func (ch *channel) Read(data []byte) (int, error) { | 398 func (ch *channel) Read(data []byte) (int, error) { |
392 if !ch.decided { | 399 if !ch.decided { |
393 return 0, errUndecided | 400 return 0, errUndecided |
394 } | 401 } |
395 | 402 |
396 return ch.ReadExtended(data, 0) | 403 return ch.ReadExtended(data, 0) |
397 } | 404 } |
398 | 405 |
399 func (ch *channel) ReceivedRequests() chan *ChannelRequest { | |
400 return ch.pendingRequests | |
401 } | |
402 | |
403 func (ch *channel) Write(data []byte) (int, error) { | 406 func (ch *channel) Write(data []byte) (int, error) { |
404 if !ch.decided { | 407 if !ch.decided { |
405 return 0, errUndecided | 408 return 0, errUndecided |
406 } | 409 } |
407 return ch.WriteExtended(data, 0) | 410 return ch.WriteExtended(data, 0) |
408 } | 411 } |
409 | 412 |
410 func (ch *channel) CloseWrite() error { | 413 func (ch *channel) CloseWrite() error { |
411 if !ch.decided { | 414 if !ch.decided { |
412 return errUndecided | 415 return errUndecided |
413 } | 416 } |
414 ch.sentEOF = true | 417 ch.sentEOF = true |
415 return ch.sendMessage(msgChannelEOF, channelEOFMsg{ | 418 return ch.sendMessage(msgChannelEOF, channelEOFMsg{ |
416 PeersId: ch.remoteId}) | 419 PeersId: ch.remoteId}) |
417 } | 420 } |
418 | 421 |
419 func (ch *channel) Close() error { | 422 func (ch *channel) Close() error { |
420 if !ch.decided { | 423 if !ch.decided { |
421 return errUndecided | 424 return errUndecided |
422 } | 425 } |
423 | 426 |
424 return ch.sendMessage(msgChannelClose, channelCloseMsg{ | 427 return ch.sendMessage(msgChannelClose, channelCloseMsg{ |
425 PeersId: ch.remoteId}) | 428 PeersId: ch.remoteId}) |
426 } | 429 } |
427 | 430 |
428 func (ch *channel) Stderr() io.ReadWriter { | 431 func (ch *channel) Extended(code uint32) io.ReadWriter { |
429 if !ch.decided { | 432 if !ch.decided { |
430 return nil | 433 return nil |
431 } | 434 } |
432 » return (*extChannel)(ch) | 435 » return &extChannel{code, ch} |
433 } | 436 } |
434 | 437 |
435 // SendRequest sends a channel request. If wantReply is set, it will | 438 // SendRequest sends a channel request. If wantReply is set, it will |
436 // wait for a reply and return the result as a boolean. | 439 // wait for a reply and return the result as a boolean. |
437 func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (boo
l, error) { | 440 func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (boo
l, error) { |
438 if !ch.decided { | 441 if !ch.decided { |
439 return false, errUndecided | 442 return false, errUndecided |
440 } | 443 } |
441 | 444 |
442 if wantReply { | 445 if wantReply { |
443 ch.sentRequestMu.Lock() | 446 ch.sentRequestMu.Lock() |
444 defer ch.sentRequestMu.Unlock() | 447 defer ch.sentRequestMu.Unlock() |
445 } | 448 } |
446 | 449 |
447 msg := channelRequestMsg{ | 450 msg := channelRequestMsg{ |
448 PeersId: ch.remoteId, | 451 PeersId: ch.remoteId, |
449 Request: name, | 452 Request: name, |
450 WantReply: wantReply, | 453 WantReply: wantReply, |
451 RequestSpecificData: payload, | 454 RequestSpecificData: payload, |
452 } | 455 } |
453 | 456 |
454 if err := ch.sendMessage(msgChannelRequest, msg); err != nil { | 457 if err := ch.sendMessage(msgChannelRequest, msg); err != nil { |
455 return false, err | 458 return false, err |
456 } | 459 } |
457 | 460 |
458 if wantReply { | 461 if wantReply { |
459 » » switch (<-ch.msg).(type) { | 462 » » m, ok := (<-ch.msg) |
| 463 » » if !ok { |
| 464 » » » return false, io.EOF |
| 465 » » } |
| 466 » » switch m.(type) { |
460 case *channelRequestFailureMsg: | 467 case *channelRequestFailureMsg: |
461 return false, nil | 468 return false, nil |
462 case *channelRequestSuccessMsg: | 469 case *channelRequestSuccessMsg: |
463 return true, nil | 470 return true, nil |
| 471 default: |
| 472 return false, fmt.Errorf("unexpected response %#v", m) |
464 } | 473 } |
465 } | 474 } |
466 | 475 |
467 return false, nil | 476 return false, nil |
468 } | 477 } |
469 | 478 |
470 // AckRequest either sends an ack or nack to the channel request. | 479 // AckRequest either sends an ack or nack to the channel request. |
471 func (ch *channel) AckRequest(ok bool) error { | 480 func (ch *channel) AckRequest(ok bool) error { |
472 if !ch.decided { | 481 if !ch.decided { |
473 return errUndecided | 482 return errUndecided |
(...skipping 15 matching lines...) Expand all Loading... |
489 return ch.sendMessage(code, msg) | 498 return ch.sendMessage(code, msg) |
490 } | 499 } |
491 | 500 |
492 func (ch *channel) ChannelType() string { | 501 func (ch *channel) ChannelType() string { |
493 return ch.chanType | 502 return ch.chanType |
494 } | 503 } |
495 | 504 |
496 func (ch *channel) ExtraData() []byte { | 505 func (ch *channel) ExtraData() []byte { |
497 return ch.extraData | 506 return ch.extraData |
498 } | 507 } |
| 508 |
| 509 // compatChannel is a hack to implement Channel's |
| 510 // handing of channel requests. |
| 511 type compatChannel struct { |
| 512 *channel |
| 513 } |
| 514 |
| 515 func newCompatChannel(ch *channel) *compatChannel { |
| 516 c := &compatChannel{ch} |
| 517 go c.loop() |
| 518 return c |
| 519 } |
| 520 |
| 521 func (c *compatChannel) loop() { |
| 522 for r := range c.channel.incomingRequests { |
| 523 c.channel.pending.addRequest(r) |
| 524 } |
| 525 } |
| 526 |
| 527 func (c *compatChannel) Stderr() io.Writer { |
| 528 return c.Extended(1) |
| 529 } |
LEFT | RIGHT |