github.com/pkg/sftp@v1.13.6/packet.go (about) 1 package sftp 2 3 import ( 4 "bytes" 5 "encoding" 6 "encoding/binary" 7 "errors" 8 "fmt" 9 "io" 10 "os" 11 "reflect" 12 ) 13 14 var ( 15 errLongPacket = errors.New("packet too long") 16 errShortPacket = errors.New("packet too short") 17 errUnknownExtendedPacket = errors.New("unknown extended packet") 18 ) 19 20 const ( 21 maxMsgLength = 256 * 1024 22 debugDumpTxPacket = false 23 debugDumpRxPacket = false 24 debugDumpTxPacketBytes = false 25 debugDumpRxPacketBytes = false 26 ) 27 28 func marshalUint32(b []byte, v uint32) []byte { 29 return append(b, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 30 } 31 32 func marshalUint64(b []byte, v uint64) []byte { 33 return marshalUint32(marshalUint32(b, uint32(v>>32)), uint32(v)) 34 } 35 36 func marshalString(b []byte, v string) []byte { 37 return append(marshalUint32(b, uint32(len(v))), v...) 38 } 39 40 func marshalFileInfo(b []byte, fi os.FileInfo) []byte { 41 // attributes variable struct, and also variable per protocol version 42 // spec version 3 attributes: 43 // uint32 flags 44 // uint64 size present only if flag SSH_FILEXFER_ATTR_SIZE 45 // uint32 uid present only if flag SSH_FILEXFER_ATTR_UIDGID 46 // uint32 gid present only if flag SSH_FILEXFER_ATTR_UIDGID 47 // uint32 permissions present only if flag SSH_FILEXFER_ATTR_PERMISSIONS 48 // uint32 atime present only if flag SSH_FILEXFER_ACMODTIME 49 // uint32 mtime present only if flag SSH_FILEXFER_ACMODTIME 50 // uint32 extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED 51 // string extended_type 52 // string extended_data 53 // ... more extended data (extended_type - extended_data pairs), 54 // so that number of pairs equals extended_count 55 56 flags, fileStat := fileStatFromInfo(fi) 57 58 b = marshalUint32(b, flags) 59 if flags&sshFileXferAttrSize != 0 { 60 b = marshalUint64(b, fileStat.Size) 61 } 62 if flags&sshFileXferAttrUIDGID != 0 { 63 b = marshalUint32(b, fileStat.UID) 64 b = marshalUint32(b, fileStat.GID) 65 } 66 if flags&sshFileXferAttrPermissions != 0 { 67 b = marshalUint32(b, fileStat.Mode) 68 } 69 if flags&sshFileXferAttrACmodTime != 0 { 70 b = marshalUint32(b, fileStat.Atime) 71 b = marshalUint32(b, fileStat.Mtime) 72 } 73 74 if flags&sshFileXferAttrExtended != 0 { 75 b = marshalUint32(b, uint32(len(fileStat.Extended))) 76 77 for _, attr := range fileStat.Extended { 78 b = marshalString(b, attr.ExtType) 79 b = marshalString(b, attr.ExtData) 80 } 81 } 82 83 return b 84 } 85 86 func marshalStatus(b []byte, err StatusError) []byte { 87 b = marshalUint32(b, err.Code) 88 b = marshalString(b, err.msg) 89 b = marshalString(b, err.lang) 90 return b 91 } 92 93 func marshal(b []byte, v interface{}) []byte { 94 if v == nil { 95 return b 96 } 97 switch v := v.(type) { 98 case uint8: 99 return append(b, v) 100 case uint32: 101 return marshalUint32(b, v) 102 case uint64: 103 return marshalUint64(b, v) 104 case string: 105 return marshalString(b, v) 106 case os.FileInfo: 107 return marshalFileInfo(b, v) 108 default: 109 switch d := reflect.ValueOf(v); d.Kind() { 110 case reflect.Struct: 111 for i, n := 0, d.NumField(); i < n; i++ { 112 b = marshal(b, d.Field(i).Interface()) 113 } 114 return b 115 case reflect.Slice: 116 for i, n := 0, d.Len(); i < n; i++ { 117 b = marshal(b, d.Index(i).Interface()) 118 } 119 return b 120 default: 121 panic(fmt.Sprintf("marshal(%#v): cannot handle type %T", v, v)) 122 } 123 } 124 } 125 126 func unmarshalUint32(b []byte) (uint32, []byte) { 127 v := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 128 return v, b[4:] 129 } 130 131 func unmarshalUint32Safe(b []byte) (uint32, []byte, error) { 132 var v uint32 133 if len(b) < 4 { 134 return 0, nil, errShortPacket 135 } 136 v, b = unmarshalUint32(b) 137 return v, b, nil 138 } 139 140 func unmarshalUint64(b []byte) (uint64, []byte) { 141 h, b := unmarshalUint32(b) 142 l, b := unmarshalUint32(b) 143 return uint64(h)<<32 | uint64(l), b 144 } 145 146 func unmarshalUint64Safe(b []byte) (uint64, []byte, error) { 147 var v uint64 148 if len(b) < 8 { 149 return 0, nil, errShortPacket 150 } 151 v, b = unmarshalUint64(b) 152 return v, b, nil 153 } 154 155 func unmarshalString(b []byte) (string, []byte) { 156 n, b := unmarshalUint32(b) 157 return string(b[:n]), b[n:] 158 } 159 160 func unmarshalStringSafe(b []byte) (string, []byte, error) { 161 n, b, err := unmarshalUint32Safe(b) 162 if err != nil { 163 return "", nil, err 164 } 165 if int64(n) > int64(len(b)) { 166 return "", nil, errShortPacket 167 } 168 return string(b[:n]), b[n:], nil 169 } 170 171 func unmarshalAttrs(b []byte) (*FileStat, []byte) { 172 flags, b := unmarshalUint32(b) 173 return unmarshalFileStat(flags, b) 174 } 175 176 func unmarshalFileStat(flags uint32, b []byte) (*FileStat, []byte) { 177 var fs FileStat 178 if flags&sshFileXferAttrSize == sshFileXferAttrSize { 179 fs.Size, b, _ = unmarshalUint64Safe(b) 180 } 181 if flags&sshFileXferAttrUIDGID == sshFileXferAttrUIDGID { 182 fs.UID, b, _ = unmarshalUint32Safe(b) 183 } 184 if flags&sshFileXferAttrUIDGID == sshFileXferAttrUIDGID { 185 fs.GID, b, _ = unmarshalUint32Safe(b) 186 } 187 if flags&sshFileXferAttrPermissions == sshFileXferAttrPermissions { 188 fs.Mode, b, _ = unmarshalUint32Safe(b) 189 } 190 if flags&sshFileXferAttrACmodTime == sshFileXferAttrACmodTime { 191 fs.Atime, b, _ = unmarshalUint32Safe(b) 192 fs.Mtime, b, _ = unmarshalUint32Safe(b) 193 } 194 if flags&sshFileXferAttrExtended == sshFileXferAttrExtended { 195 var count uint32 196 count, b, _ = unmarshalUint32Safe(b) 197 ext := make([]StatExtended, count) 198 for i := uint32(0); i < count; i++ { 199 var typ string 200 var data string 201 typ, b, _ = unmarshalStringSafe(b) 202 data, b, _ = unmarshalStringSafe(b) 203 ext[i] = StatExtended{ 204 ExtType: typ, 205 ExtData: data, 206 } 207 } 208 fs.Extended = ext 209 } 210 return &fs, b 211 } 212 213 func unmarshalStatus(id uint32, data []byte) error { 214 sid, data := unmarshalUint32(data) 215 if sid != id { 216 return &unexpectedIDErr{id, sid} 217 } 218 code, data := unmarshalUint32(data) 219 msg, data, _ := unmarshalStringSafe(data) 220 lang, _, _ := unmarshalStringSafe(data) 221 return &StatusError{ 222 Code: code, 223 msg: msg, 224 lang: lang, 225 } 226 } 227 228 type packetMarshaler interface { 229 marshalPacket() (header, payload []byte, err error) 230 } 231 232 func marshalPacket(m encoding.BinaryMarshaler) (header, payload []byte, err error) { 233 if m, ok := m.(packetMarshaler); ok { 234 return m.marshalPacket() 235 } 236 237 header, err = m.MarshalBinary() 238 return 239 } 240 241 // sendPacket marshals p according to RFC 4234. 242 func sendPacket(w io.Writer, m encoding.BinaryMarshaler) error { 243 header, payload, err := marshalPacket(m) 244 if err != nil { 245 return fmt.Errorf("binary marshaller failed: %w", err) 246 } 247 248 length := len(header) + len(payload) - 4 // subtract the uint32(length) from the start 249 if debugDumpTxPacketBytes { 250 debug("send packet: %s %d bytes %x%x", fxp(header[4]), length, header[5:], payload) 251 } else if debugDumpTxPacket { 252 debug("send packet: %s %d bytes", fxp(header[4]), length) 253 } 254 255 binary.BigEndian.PutUint32(header[:4], uint32(length)) 256 257 if _, err := w.Write(header); err != nil { 258 return fmt.Errorf("failed to send packet: %w", err) 259 } 260 261 if len(payload) > 0 { 262 if _, err := w.Write(payload); err != nil { 263 return fmt.Errorf("failed to send packet payload: %w", err) 264 } 265 } 266 267 return nil 268 } 269 270 func recvPacket(r io.Reader, alloc *allocator, orderID uint32) (uint8, []byte, error) { 271 var b []byte 272 if alloc != nil { 273 b = alloc.GetPage(orderID) 274 } else { 275 b = make([]byte, 4) 276 } 277 if _, err := io.ReadFull(r, b[:4]); err != nil { 278 return 0, nil, err 279 } 280 length, _ := unmarshalUint32(b) 281 if length > maxMsgLength { 282 debug("recv packet %d bytes too long", length) 283 return 0, nil, errLongPacket 284 } 285 if length == 0 { 286 debug("recv packet of 0 bytes too short") 287 return 0, nil, errShortPacket 288 } 289 if alloc == nil { 290 b = make([]byte, length) 291 } 292 if _, err := io.ReadFull(r, b[:length]); err != nil { 293 // ReadFull only returns EOF if it has read no bytes. 294 // In this case, that means a partial packet, and thus unexpected. 295 if err == io.EOF { 296 err = io.ErrUnexpectedEOF 297 } 298 debug("recv packet %d bytes: err %v", length, err) 299 return 0, nil, err 300 } 301 if debugDumpRxPacketBytes { 302 debug("recv packet: %s %d bytes %x", fxp(b[0]), length, b[1:length]) 303 } else if debugDumpRxPacket { 304 debug("recv packet: %s %d bytes", fxp(b[0]), length) 305 } 306 return b[0], b[1:length], nil 307 } 308 309 type extensionPair struct { 310 Name string 311 Data string 312 } 313 314 func unmarshalExtensionPair(b []byte) (extensionPair, []byte, error) { 315 var ep extensionPair 316 var err error 317 ep.Name, b, err = unmarshalStringSafe(b) 318 if err != nil { 319 return ep, b, err 320 } 321 ep.Data, b, err = unmarshalStringSafe(b) 322 return ep, b, err 323 } 324 325 // Here starts the definition of packets along with their MarshalBinary 326 // implementations. 327 // Manually writing the marshalling logic wins us a lot of time and 328 // allocation. 329 330 type sshFxInitPacket struct { 331 Version uint32 332 Extensions []extensionPair 333 } 334 335 func (p *sshFxInitPacket) MarshalBinary() ([]byte, error) { 336 l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(version) 337 for _, e := range p.Extensions { 338 l += 4 + len(e.Name) + 4 + len(e.Data) 339 } 340 341 b := make([]byte, 4, l) 342 b = append(b, sshFxpInit) 343 b = marshalUint32(b, p.Version) 344 345 for _, e := range p.Extensions { 346 b = marshalString(b, e.Name) 347 b = marshalString(b, e.Data) 348 } 349 350 return b, nil 351 } 352 353 func (p *sshFxInitPacket) UnmarshalBinary(b []byte) error { 354 var err error 355 if p.Version, b, err = unmarshalUint32Safe(b); err != nil { 356 return err 357 } 358 for len(b) > 0 { 359 var ep extensionPair 360 ep, b, err = unmarshalExtensionPair(b) 361 if err != nil { 362 return err 363 } 364 p.Extensions = append(p.Extensions, ep) 365 } 366 return nil 367 } 368 369 type sshFxVersionPacket struct { 370 Version uint32 371 Extensions []sshExtensionPair 372 } 373 374 type sshExtensionPair struct { 375 Name, Data string 376 } 377 378 func (p *sshFxVersionPacket) MarshalBinary() ([]byte, error) { 379 l := 4 + 1 + 4 // uint32(length) + byte(type) + uint32(version) 380 for _, e := range p.Extensions { 381 l += 4 + len(e.Name) + 4 + len(e.Data) 382 } 383 384 b := make([]byte, 4, l) 385 b = append(b, sshFxpVersion) 386 b = marshalUint32(b, p.Version) 387 388 for _, e := range p.Extensions { 389 b = marshalString(b, e.Name) 390 b = marshalString(b, e.Data) 391 } 392 393 return b, nil 394 } 395 396 func marshalIDStringPacket(packetType byte, id uint32, str string) ([]byte, error) { 397 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 398 4 + len(str) 399 400 b := make([]byte, 4, l) 401 b = append(b, packetType) 402 b = marshalUint32(b, id) 403 b = marshalString(b, str) 404 405 return b, nil 406 } 407 408 func unmarshalIDString(b []byte, id *uint32, str *string) error { 409 var err error 410 *id, b, err = unmarshalUint32Safe(b) 411 if err != nil { 412 return err 413 } 414 *str, _, err = unmarshalStringSafe(b) 415 return err 416 } 417 418 type sshFxpReaddirPacket struct { 419 ID uint32 420 Handle string 421 } 422 423 func (p *sshFxpReaddirPacket) id() uint32 { return p.ID } 424 425 func (p *sshFxpReaddirPacket) MarshalBinary() ([]byte, error) { 426 return marshalIDStringPacket(sshFxpReaddir, p.ID, p.Handle) 427 } 428 429 func (p *sshFxpReaddirPacket) UnmarshalBinary(b []byte) error { 430 return unmarshalIDString(b, &p.ID, &p.Handle) 431 } 432 433 type sshFxpOpendirPacket struct { 434 ID uint32 435 Path string 436 } 437 438 func (p *sshFxpOpendirPacket) id() uint32 { return p.ID } 439 440 func (p *sshFxpOpendirPacket) MarshalBinary() ([]byte, error) { 441 return marshalIDStringPacket(sshFxpOpendir, p.ID, p.Path) 442 } 443 444 func (p *sshFxpOpendirPacket) UnmarshalBinary(b []byte) error { 445 return unmarshalIDString(b, &p.ID, &p.Path) 446 } 447 448 type sshFxpLstatPacket struct { 449 ID uint32 450 Path string 451 } 452 453 func (p *sshFxpLstatPacket) id() uint32 { return p.ID } 454 455 func (p *sshFxpLstatPacket) MarshalBinary() ([]byte, error) { 456 return marshalIDStringPacket(sshFxpLstat, p.ID, p.Path) 457 } 458 459 func (p *sshFxpLstatPacket) UnmarshalBinary(b []byte) error { 460 return unmarshalIDString(b, &p.ID, &p.Path) 461 } 462 463 type sshFxpStatPacket struct { 464 ID uint32 465 Path string 466 } 467 468 func (p *sshFxpStatPacket) id() uint32 { return p.ID } 469 470 func (p *sshFxpStatPacket) MarshalBinary() ([]byte, error) { 471 return marshalIDStringPacket(sshFxpStat, p.ID, p.Path) 472 } 473 474 func (p *sshFxpStatPacket) UnmarshalBinary(b []byte) error { 475 return unmarshalIDString(b, &p.ID, &p.Path) 476 } 477 478 type sshFxpFstatPacket struct { 479 ID uint32 480 Handle string 481 } 482 483 func (p *sshFxpFstatPacket) id() uint32 { return p.ID } 484 485 func (p *sshFxpFstatPacket) MarshalBinary() ([]byte, error) { 486 return marshalIDStringPacket(sshFxpFstat, p.ID, p.Handle) 487 } 488 489 func (p *sshFxpFstatPacket) UnmarshalBinary(b []byte) error { 490 return unmarshalIDString(b, &p.ID, &p.Handle) 491 } 492 493 type sshFxpClosePacket struct { 494 ID uint32 495 Handle string 496 } 497 498 func (p *sshFxpClosePacket) id() uint32 { return p.ID } 499 500 func (p *sshFxpClosePacket) MarshalBinary() ([]byte, error) { 501 return marshalIDStringPacket(sshFxpClose, p.ID, p.Handle) 502 } 503 504 func (p *sshFxpClosePacket) UnmarshalBinary(b []byte) error { 505 return unmarshalIDString(b, &p.ID, &p.Handle) 506 } 507 508 type sshFxpRemovePacket struct { 509 ID uint32 510 Filename string 511 } 512 513 func (p *sshFxpRemovePacket) id() uint32 { return p.ID } 514 515 func (p *sshFxpRemovePacket) MarshalBinary() ([]byte, error) { 516 return marshalIDStringPacket(sshFxpRemove, p.ID, p.Filename) 517 } 518 519 func (p *sshFxpRemovePacket) UnmarshalBinary(b []byte) error { 520 return unmarshalIDString(b, &p.ID, &p.Filename) 521 } 522 523 type sshFxpRmdirPacket struct { 524 ID uint32 525 Path string 526 } 527 528 func (p *sshFxpRmdirPacket) id() uint32 { return p.ID } 529 530 func (p *sshFxpRmdirPacket) MarshalBinary() ([]byte, error) { 531 return marshalIDStringPacket(sshFxpRmdir, p.ID, p.Path) 532 } 533 534 func (p *sshFxpRmdirPacket) UnmarshalBinary(b []byte) error { 535 return unmarshalIDString(b, &p.ID, &p.Path) 536 } 537 538 type sshFxpSymlinkPacket struct { 539 ID uint32 540 541 // The order of the arguments to the SSH_FXP_SYMLINK method was inadvertently reversed. 542 // Unfortunately, the reversal was not noticed until the server was widely deployed. 543 // Covered in Section 4.1 of https://github.com/openssh/openssh-portable/blob/master/PROTOCOL 544 545 Targetpath string 546 Linkpath string 547 } 548 549 func (p *sshFxpSymlinkPacket) id() uint32 { return p.ID } 550 551 func (p *sshFxpSymlinkPacket) MarshalBinary() ([]byte, error) { 552 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 553 4 + len(p.Targetpath) + 554 4 + len(p.Linkpath) 555 556 b := make([]byte, 4, l) 557 b = append(b, sshFxpSymlink) 558 b = marshalUint32(b, p.ID) 559 b = marshalString(b, p.Targetpath) 560 b = marshalString(b, p.Linkpath) 561 562 return b, nil 563 } 564 565 func (p *sshFxpSymlinkPacket) UnmarshalBinary(b []byte) error { 566 var err error 567 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 568 return err 569 } else if p.Targetpath, b, err = unmarshalStringSafe(b); err != nil { 570 return err 571 } else if p.Linkpath, _, err = unmarshalStringSafe(b); err != nil { 572 return err 573 } 574 return nil 575 } 576 577 type sshFxpHardlinkPacket struct { 578 ID uint32 579 Oldpath string 580 Newpath string 581 } 582 583 func (p *sshFxpHardlinkPacket) id() uint32 { return p.ID } 584 585 func (p *sshFxpHardlinkPacket) MarshalBinary() ([]byte, error) { 586 const ext = "hardlink@openssh.com" 587 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 588 4 + len(ext) + 589 4 + len(p.Oldpath) + 590 4 + len(p.Newpath) 591 592 b := make([]byte, 4, l) 593 b = append(b, sshFxpExtended) 594 b = marshalUint32(b, p.ID) 595 b = marshalString(b, ext) 596 b = marshalString(b, p.Oldpath) 597 b = marshalString(b, p.Newpath) 598 599 return b, nil 600 } 601 602 type sshFxpReadlinkPacket struct { 603 ID uint32 604 Path string 605 } 606 607 func (p *sshFxpReadlinkPacket) id() uint32 { return p.ID } 608 609 func (p *sshFxpReadlinkPacket) MarshalBinary() ([]byte, error) { 610 return marshalIDStringPacket(sshFxpReadlink, p.ID, p.Path) 611 } 612 613 func (p *sshFxpReadlinkPacket) UnmarshalBinary(b []byte) error { 614 return unmarshalIDString(b, &p.ID, &p.Path) 615 } 616 617 type sshFxpRealpathPacket struct { 618 ID uint32 619 Path string 620 } 621 622 func (p *sshFxpRealpathPacket) id() uint32 { return p.ID } 623 624 func (p *sshFxpRealpathPacket) MarshalBinary() ([]byte, error) { 625 return marshalIDStringPacket(sshFxpRealpath, p.ID, p.Path) 626 } 627 628 func (p *sshFxpRealpathPacket) UnmarshalBinary(b []byte) error { 629 return unmarshalIDString(b, &p.ID, &p.Path) 630 } 631 632 type sshFxpNameAttr struct { 633 Name string 634 LongName string 635 Attrs []interface{} 636 } 637 638 func (p *sshFxpNameAttr) MarshalBinary() ([]byte, error) { 639 var b []byte 640 b = marshalString(b, p.Name) 641 b = marshalString(b, p.LongName) 642 for _, attr := range p.Attrs { 643 b = marshal(b, attr) 644 } 645 return b, nil 646 } 647 648 type sshFxpNamePacket struct { 649 ID uint32 650 NameAttrs []*sshFxpNameAttr 651 } 652 653 func (p *sshFxpNamePacket) marshalPacket() ([]byte, []byte, error) { 654 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 655 4 656 657 b := make([]byte, 4, l) 658 b = append(b, sshFxpName) 659 b = marshalUint32(b, p.ID) 660 b = marshalUint32(b, uint32(len(p.NameAttrs))) 661 662 var payload []byte 663 for _, na := range p.NameAttrs { 664 ab, err := na.MarshalBinary() 665 if err != nil { 666 return nil, nil, err 667 } 668 669 payload = append(payload, ab...) 670 } 671 672 return b, payload, nil 673 } 674 675 func (p *sshFxpNamePacket) MarshalBinary() ([]byte, error) { 676 header, payload, err := p.marshalPacket() 677 return append(header, payload...), err 678 } 679 680 type sshFxpOpenPacket struct { 681 ID uint32 682 Path string 683 Pflags uint32 684 Flags uint32 // ignored 685 } 686 687 func (p *sshFxpOpenPacket) id() uint32 { return p.ID } 688 689 func (p *sshFxpOpenPacket) MarshalBinary() ([]byte, error) { 690 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 691 4 + len(p.Path) + 692 4 + 4 693 694 b := make([]byte, 4, l) 695 b = append(b, sshFxpOpen) 696 b = marshalUint32(b, p.ID) 697 b = marshalString(b, p.Path) 698 b = marshalUint32(b, p.Pflags) 699 b = marshalUint32(b, p.Flags) 700 701 return b, nil 702 } 703 704 func (p *sshFxpOpenPacket) UnmarshalBinary(b []byte) error { 705 var err error 706 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 707 return err 708 } else if p.Path, b, err = unmarshalStringSafe(b); err != nil { 709 return err 710 } else if p.Pflags, b, err = unmarshalUint32Safe(b); err != nil { 711 return err 712 } else if p.Flags, _, err = unmarshalUint32Safe(b); err != nil { 713 return err 714 } 715 return nil 716 } 717 718 type sshFxpReadPacket struct { 719 ID uint32 720 Len uint32 721 Offset uint64 722 Handle string 723 } 724 725 func (p *sshFxpReadPacket) id() uint32 { return p.ID } 726 727 func (p *sshFxpReadPacket) MarshalBinary() ([]byte, error) { 728 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 729 4 + len(p.Handle) + 730 8 + 4 // uint64 + uint32 731 732 b := make([]byte, 4, l) 733 b = append(b, sshFxpRead) 734 b = marshalUint32(b, p.ID) 735 b = marshalString(b, p.Handle) 736 b = marshalUint64(b, p.Offset) 737 b = marshalUint32(b, p.Len) 738 739 return b, nil 740 } 741 742 func (p *sshFxpReadPacket) UnmarshalBinary(b []byte) error { 743 var err error 744 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 745 return err 746 } else if p.Handle, b, err = unmarshalStringSafe(b); err != nil { 747 return err 748 } else if p.Offset, b, err = unmarshalUint64Safe(b); err != nil { 749 return err 750 } else if p.Len, _, err = unmarshalUint32Safe(b); err != nil { 751 return err 752 } 753 return nil 754 } 755 756 // We need allocate bigger slices with extra capacity to avoid a re-allocation in sshFxpDataPacket.MarshalBinary 757 // So, we need: uint32(length) + byte(type) + uint32(id) + uint32(data_length) 758 const dataHeaderLen = 4 + 1 + 4 + 4 759 760 func (p *sshFxpReadPacket) getDataSlice(alloc *allocator, orderID uint32) []byte { 761 dataLen := p.Len 762 if dataLen > maxTxPacket { 763 dataLen = maxTxPacket 764 } 765 766 if alloc != nil { 767 // GetPage returns a slice with capacity = maxMsgLength this is enough to avoid new allocations in 768 // sshFxpDataPacket.MarshalBinary 769 return alloc.GetPage(orderID)[:dataLen] 770 } 771 772 // allocate with extra space for the header 773 return make([]byte, dataLen, dataLen+dataHeaderLen) 774 } 775 776 type sshFxpRenamePacket struct { 777 ID uint32 778 Oldpath string 779 Newpath string 780 } 781 782 func (p *sshFxpRenamePacket) id() uint32 { return p.ID } 783 784 func (p *sshFxpRenamePacket) MarshalBinary() ([]byte, error) { 785 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 786 4 + len(p.Oldpath) + 787 4 + len(p.Newpath) 788 789 b := make([]byte, 4, l) 790 b = append(b, sshFxpRename) 791 b = marshalUint32(b, p.ID) 792 b = marshalString(b, p.Oldpath) 793 b = marshalString(b, p.Newpath) 794 795 return b, nil 796 } 797 798 func (p *sshFxpRenamePacket) UnmarshalBinary(b []byte) error { 799 var err error 800 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 801 return err 802 } else if p.Oldpath, b, err = unmarshalStringSafe(b); err != nil { 803 return err 804 } else if p.Newpath, _, err = unmarshalStringSafe(b); err != nil { 805 return err 806 } 807 return nil 808 } 809 810 type sshFxpPosixRenamePacket struct { 811 ID uint32 812 Oldpath string 813 Newpath string 814 } 815 816 func (p *sshFxpPosixRenamePacket) id() uint32 { return p.ID } 817 818 func (p *sshFxpPosixRenamePacket) MarshalBinary() ([]byte, error) { 819 const ext = "posix-rename@openssh.com" 820 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 821 4 + len(ext) + 822 4 + len(p.Oldpath) + 823 4 + len(p.Newpath) 824 825 b := make([]byte, 4, l) 826 b = append(b, sshFxpExtended) 827 b = marshalUint32(b, p.ID) 828 b = marshalString(b, ext) 829 b = marshalString(b, p.Oldpath) 830 b = marshalString(b, p.Newpath) 831 832 return b, nil 833 } 834 835 type sshFxpWritePacket struct { 836 ID uint32 837 Length uint32 838 Offset uint64 839 Handle string 840 Data []byte 841 } 842 843 func (p *sshFxpWritePacket) id() uint32 { return p.ID } 844 845 func (p *sshFxpWritePacket) marshalPacket() ([]byte, []byte, error) { 846 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 847 4 + len(p.Handle) + 848 8 + // uint64 849 4 850 851 b := make([]byte, 4, l) 852 b = append(b, sshFxpWrite) 853 b = marshalUint32(b, p.ID) 854 b = marshalString(b, p.Handle) 855 b = marshalUint64(b, p.Offset) 856 b = marshalUint32(b, p.Length) 857 858 return b, p.Data, nil 859 } 860 861 func (p *sshFxpWritePacket) MarshalBinary() ([]byte, error) { 862 header, payload, err := p.marshalPacket() 863 return append(header, payload...), err 864 } 865 866 func (p *sshFxpWritePacket) UnmarshalBinary(b []byte) error { 867 var err error 868 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 869 return err 870 } else if p.Handle, b, err = unmarshalStringSafe(b); err != nil { 871 return err 872 } else if p.Offset, b, err = unmarshalUint64Safe(b); err != nil { 873 return err 874 } else if p.Length, b, err = unmarshalUint32Safe(b); err != nil { 875 return err 876 } else if uint32(len(b)) < p.Length { 877 return errShortPacket 878 } 879 880 p.Data = b[:p.Length] 881 return nil 882 } 883 884 type sshFxpMkdirPacket struct { 885 ID uint32 886 Flags uint32 // ignored 887 Path string 888 } 889 890 func (p *sshFxpMkdirPacket) id() uint32 { return p.ID } 891 892 func (p *sshFxpMkdirPacket) MarshalBinary() ([]byte, error) { 893 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 894 4 + len(p.Path) + 895 4 // uint32 896 897 b := make([]byte, 4, l) 898 b = append(b, sshFxpMkdir) 899 b = marshalUint32(b, p.ID) 900 b = marshalString(b, p.Path) 901 b = marshalUint32(b, p.Flags) 902 903 return b, nil 904 } 905 906 func (p *sshFxpMkdirPacket) UnmarshalBinary(b []byte) error { 907 var err error 908 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 909 return err 910 } else if p.Path, b, err = unmarshalStringSafe(b); err != nil { 911 return err 912 } else if p.Flags, _, err = unmarshalUint32Safe(b); err != nil { 913 return err 914 } 915 return nil 916 } 917 918 type sshFxpSetstatPacket struct { 919 ID uint32 920 Flags uint32 921 Path string 922 Attrs interface{} 923 } 924 925 type sshFxpFsetstatPacket struct { 926 ID uint32 927 Flags uint32 928 Handle string 929 Attrs interface{} 930 } 931 932 func (p *sshFxpSetstatPacket) id() uint32 { return p.ID } 933 func (p *sshFxpFsetstatPacket) id() uint32 { return p.ID } 934 935 func (p *sshFxpSetstatPacket) marshalPacket() ([]byte, []byte, error) { 936 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 937 4 + len(p.Path) + 938 4 // uint32 939 940 b := make([]byte, 4, l) 941 b = append(b, sshFxpSetstat) 942 b = marshalUint32(b, p.ID) 943 b = marshalString(b, p.Path) 944 b = marshalUint32(b, p.Flags) 945 946 payload := marshal(nil, p.Attrs) 947 948 return b, payload, nil 949 } 950 951 func (p *sshFxpSetstatPacket) MarshalBinary() ([]byte, error) { 952 header, payload, err := p.marshalPacket() 953 return append(header, payload...), err 954 } 955 956 func (p *sshFxpFsetstatPacket) marshalPacket() ([]byte, []byte, error) { 957 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 958 4 + len(p.Handle) + 959 4 // uint32 960 961 b := make([]byte, 4, l) 962 b = append(b, sshFxpFsetstat) 963 b = marshalUint32(b, p.ID) 964 b = marshalString(b, p.Handle) 965 b = marshalUint32(b, p.Flags) 966 967 payload := marshal(nil, p.Attrs) 968 969 return b, payload, nil 970 } 971 972 func (p *sshFxpFsetstatPacket) MarshalBinary() ([]byte, error) { 973 header, payload, err := p.marshalPacket() 974 return append(header, payload...), err 975 } 976 977 func (p *sshFxpSetstatPacket) UnmarshalBinary(b []byte) error { 978 var err error 979 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 980 return err 981 } else if p.Path, b, err = unmarshalStringSafe(b); err != nil { 982 return err 983 } else if p.Flags, b, err = unmarshalUint32Safe(b); err != nil { 984 return err 985 } 986 p.Attrs = b 987 return nil 988 } 989 990 func (p *sshFxpFsetstatPacket) UnmarshalBinary(b []byte) error { 991 var err error 992 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 993 return err 994 } else if p.Handle, b, err = unmarshalStringSafe(b); err != nil { 995 return err 996 } else if p.Flags, b, err = unmarshalUint32Safe(b); err != nil { 997 return err 998 } 999 p.Attrs = b 1000 return nil 1001 } 1002 1003 type sshFxpHandlePacket struct { 1004 ID uint32 1005 Handle string 1006 } 1007 1008 func (p *sshFxpHandlePacket) MarshalBinary() ([]byte, error) { 1009 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 1010 4 + len(p.Handle) 1011 1012 b := make([]byte, 4, l) 1013 b = append(b, sshFxpHandle) 1014 b = marshalUint32(b, p.ID) 1015 b = marshalString(b, p.Handle) 1016 1017 return b, nil 1018 } 1019 1020 type sshFxpStatusPacket struct { 1021 ID uint32 1022 StatusError 1023 } 1024 1025 func (p *sshFxpStatusPacket) MarshalBinary() ([]byte, error) { 1026 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 1027 4 + 1028 4 + len(p.StatusError.msg) + 1029 4 + len(p.StatusError.lang) 1030 1031 b := make([]byte, 4, l) 1032 b = append(b, sshFxpStatus) 1033 b = marshalUint32(b, p.ID) 1034 b = marshalStatus(b, p.StatusError) 1035 1036 return b, nil 1037 } 1038 1039 type sshFxpDataPacket struct { 1040 ID uint32 1041 Length uint32 1042 Data []byte 1043 } 1044 1045 func (p *sshFxpDataPacket) marshalPacket() ([]byte, []byte, error) { 1046 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 1047 4 1048 1049 b := make([]byte, 4, l) 1050 b = append(b, sshFxpData) 1051 b = marshalUint32(b, p.ID) 1052 b = marshalUint32(b, p.Length) 1053 1054 return b, p.Data, nil 1055 } 1056 1057 // MarshalBinary encodes the receiver into a binary form and returns the result. 1058 // To avoid a new allocation the Data slice must have a capacity >= Length + 9 1059 // 1060 // This is hand-coded rather than just append(header, payload...), 1061 // in order to try and reuse the r.Data backing store in the packet. 1062 func (p *sshFxpDataPacket) MarshalBinary() ([]byte, error) { 1063 b := append(p.Data, make([]byte, dataHeaderLen)...) 1064 copy(b[dataHeaderLen:], p.Data[:p.Length]) 1065 // b[0:4] will be overwritten with the length in sendPacket 1066 b[4] = sshFxpData 1067 binary.BigEndian.PutUint32(b[5:9], p.ID) 1068 binary.BigEndian.PutUint32(b[9:13], p.Length) 1069 return b, nil 1070 } 1071 1072 func (p *sshFxpDataPacket) UnmarshalBinary(b []byte) error { 1073 var err error 1074 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 1075 return err 1076 } else if p.Length, b, err = unmarshalUint32Safe(b); err != nil { 1077 return err 1078 } else if uint32(len(b)) < p.Length { 1079 return errShortPacket 1080 } 1081 1082 p.Data = b[:p.Length] 1083 return nil 1084 } 1085 1086 type sshFxpStatvfsPacket struct { 1087 ID uint32 1088 Path string 1089 } 1090 1091 func (p *sshFxpStatvfsPacket) id() uint32 { return p.ID } 1092 1093 func (p *sshFxpStatvfsPacket) MarshalBinary() ([]byte, error) { 1094 const ext = "statvfs@openssh.com" 1095 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 1096 4 + len(ext) + 1097 4 + len(p.Path) 1098 1099 b := make([]byte, 4, l) 1100 b = append(b, sshFxpExtended) 1101 b = marshalUint32(b, p.ID) 1102 b = marshalString(b, ext) 1103 b = marshalString(b, p.Path) 1104 1105 return b, nil 1106 } 1107 1108 // A StatVFS contains statistics about a filesystem. 1109 type StatVFS struct { 1110 ID uint32 1111 Bsize uint64 /* file system block size */ 1112 Frsize uint64 /* fundamental fs block size */ 1113 Blocks uint64 /* number of blocks (unit f_frsize) */ 1114 Bfree uint64 /* free blocks in file system */ 1115 Bavail uint64 /* free blocks for non-root */ 1116 Files uint64 /* total file inodes */ 1117 Ffree uint64 /* free file inodes */ 1118 Favail uint64 /* free file inodes for to non-root */ 1119 Fsid uint64 /* file system id */ 1120 Flag uint64 /* bit mask of f_flag values */ 1121 Namemax uint64 /* maximum filename length */ 1122 } 1123 1124 // TotalSpace calculates the amount of total space in a filesystem. 1125 func (p *StatVFS) TotalSpace() uint64 { 1126 return p.Frsize * p.Blocks 1127 } 1128 1129 // FreeSpace calculates the amount of free space in a filesystem. 1130 func (p *StatVFS) FreeSpace() uint64 { 1131 return p.Frsize * p.Bfree 1132 } 1133 1134 // marshalPacket converts to ssh_FXP_EXTENDED_REPLY packet binary format 1135 func (p *StatVFS) marshalPacket() ([]byte, []byte, error) { 1136 header := []byte{0, 0, 0, 0, sshFxpExtendedReply} 1137 1138 var buf bytes.Buffer 1139 err := binary.Write(&buf, binary.BigEndian, p) 1140 1141 return header, buf.Bytes(), err 1142 } 1143 1144 // MarshalBinary encodes the StatVFS as an SSH_FXP_EXTENDED_REPLY packet. 1145 func (p *StatVFS) MarshalBinary() ([]byte, error) { 1146 header, payload, err := p.marshalPacket() 1147 return append(header, payload...), err 1148 } 1149 1150 type sshFxpFsyncPacket struct { 1151 ID uint32 1152 Handle string 1153 } 1154 1155 func (p *sshFxpFsyncPacket) id() uint32 { return p.ID } 1156 1157 func (p *sshFxpFsyncPacket) MarshalBinary() ([]byte, error) { 1158 const ext = "fsync@openssh.com" 1159 l := 4 + 1 + 4 + // uint32(length) + byte(type) + uint32(id) 1160 4 + len(ext) + 1161 4 + len(p.Handle) 1162 1163 b := make([]byte, 4, l) 1164 b = append(b, sshFxpExtended) 1165 b = marshalUint32(b, p.ID) 1166 b = marshalString(b, ext) 1167 b = marshalString(b, p.Handle) 1168 1169 return b, nil 1170 } 1171 1172 type sshFxpExtendedPacket struct { 1173 ID uint32 1174 ExtendedRequest string 1175 SpecificPacket interface { 1176 serverRespondablePacket 1177 readonly() bool 1178 } 1179 } 1180 1181 func (p *sshFxpExtendedPacket) id() uint32 { return p.ID } 1182 func (p *sshFxpExtendedPacket) readonly() bool { 1183 if p.SpecificPacket == nil { 1184 return true 1185 } 1186 return p.SpecificPacket.readonly() 1187 } 1188 1189 func (p *sshFxpExtendedPacket) respond(svr *Server) responsePacket { 1190 if p.SpecificPacket == nil { 1191 return statusFromError(p.ID, nil) 1192 } 1193 return p.SpecificPacket.respond(svr) 1194 } 1195 1196 func (p *sshFxpExtendedPacket) UnmarshalBinary(b []byte) error { 1197 var err error 1198 bOrig := b 1199 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 1200 return err 1201 } else if p.ExtendedRequest, _, err = unmarshalStringSafe(b); err != nil { 1202 return err 1203 } 1204 1205 // specific unmarshalling 1206 switch p.ExtendedRequest { 1207 case "statvfs@openssh.com": 1208 p.SpecificPacket = &sshFxpExtendedPacketStatVFS{} 1209 case "posix-rename@openssh.com": 1210 p.SpecificPacket = &sshFxpExtendedPacketPosixRename{} 1211 case "hardlink@openssh.com": 1212 p.SpecificPacket = &sshFxpExtendedPacketHardlink{} 1213 default: 1214 return fmt.Errorf("packet type %v: %w", p.SpecificPacket, errUnknownExtendedPacket) 1215 } 1216 1217 return p.SpecificPacket.UnmarshalBinary(bOrig) 1218 } 1219 1220 type sshFxpExtendedPacketStatVFS struct { 1221 ID uint32 1222 ExtendedRequest string 1223 Path string 1224 } 1225 1226 func (p *sshFxpExtendedPacketStatVFS) id() uint32 { return p.ID } 1227 func (p *sshFxpExtendedPacketStatVFS) readonly() bool { return true } 1228 func (p *sshFxpExtendedPacketStatVFS) UnmarshalBinary(b []byte) error { 1229 var err error 1230 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 1231 return err 1232 } else if p.ExtendedRequest, b, err = unmarshalStringSafe(b); err != nil { 1233 return err 1234 } else if p.Path, _, err = unmarshalStringSafe(b); err != nil { 1235 return err 1236 } 1237 return nil 1238 } 1239 1240 type sshFxpExtendedPacketPosixRename struct { 1241 ID uint32 1242 ExtendedRequest string 1243 Oldpath string 1244 Newpath string 1245 } 1246 1247 func (p *sshFxpExtendedPacketPosixRename) id() uint32 { return p.ID } 1248 func (p *sshFxpExtendedPacketPosixRename) readonly() bool { return false } 1249 func (p *sshFxpExtendedPacketPosixRename) UnmarshalBinary(b []byte) error { 1250 var err error 1251 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 1252 return err 1253 } else if p.ExtendedRequest, b, err = unmarshalStringSafe(b); err != nil { 1254 return err 1255 } else if p.Oldpath, b, err = unmarshalStringSafe(b); err != nil { 1256 return err 1257 } else if p.Newpath, _, err = unmarshalStringSafe(b); err != nil { 1258 return err 1259 } 1260 return nil 1261 } 1262 1263 func (p *sshFxpExtendedPacketPosixRename) respond(s *Server) responsePacket { 1264 err := os.Rename(s.toLocalPath(p.Oldpath), s.toLocalPath(p.Newpath)) 1265 return statusFromError(p.ID, err) 1266 } 1267 1268 type sshFxpExtendedPacketHardlink struct { 1269 ID uint32 1270 ExtendedRequest string 1271 Oldpath string 1272 Newpath string 1273 } 1274 1275 // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL 1276 func (p *sshFxpExtendedPacketHardlink) id() uint32 { return p.ID } 1277 func (p *sshFxpExtendedPacketHardlink) readonly() bool { return true } 1278 func (p *sshFxpExtendedPacketHardlink) UnmarshalBinary(b []byte) error { 1279 var err error 1280 if p.ID, b, err = unmarshalUint32Safe(b); err != nil { 1281 return err 1282 } else if p.ExtendedRequest, b, err = unmarshalStringSafe(b); err != nil { 1283 return err 1284 } else if p.Oldpath, b, err = unmarshalStringSafe(b); err != nil { 1285 return err 1286 } else if p.Newpath, _, err = unmarshalStringSafe(b); err != nil { 1287 return err 1288 } 1289 return nil 1290 } 1291 1292 func (p *sshFxpExtendedPacketHardlink) respond(s *Server) responsePacket { 1293 err := os.Link(s.toLocalPath(p.Oldpath), s.toLocalPath(p.Newpath)) 1294 return statusFromError(p.ID, err) 1295 }