github.com/vmware/govmomi@v0.37.2/toolbox/vix/protocol.go (about) 1 /* 2 Copyright (c) 2017 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package vix 18 19 import ( 20 "bytes" 21 "encoding/base64" 22 "encoding/binary" 23 "fmt" 24 "os" 25 "os/exec" 26 "syscall" 27 ) 28 29 const ( 30 CommandMagicWord = 0xd00d0001 31 32 CommandGetToolsState = 62 33 34 CommandStartProgram = 185 35 CommandListProcessesEx = 186 36 CommandReadEnvVariables = 187 37 CommandTerminateProcess = 193 38 39 CommandCreateDirectoryEx = 178 40 CommandMoveGuestFileEx = 179 41 CommandMoveGuestDirectory = 180 42 CommandCreateTemporaryFileEx = 181 43 CommandCreateTemporaryDirectory = 182 44 CommandSetGuestFileAttributes = 183 45 CommandDeleteGuestFileEx = 194 46 CommandDeleteGuestDirectoryEx = 195 47 48 CommandListFiles = 177 49 HgfsSendPacketCommand = 84 50 CommandInitiateFileTransferFromGuest = 188 51 CommandInitiateFileTransferToGuest = 189 52 53 // VIX_USER_CREDENTIAL_NAME_PASSWORD 54 UserCredentialTypeNamePassword = 1 55 56 // VIX_E_* constants from vix.h 57 OK = 0 58 Fail = 1 59 InvalidArg = 3 60 FileNotFound = 4 61 FileAlreadyExists = 12 62 FileAccessError = 13 63 AuthenticationFail = 35 64 65 UnrecognizedCommandInGuest = 3025 66 InvalidMessageHeader = 10000 67 InvalidMessageBody = 10001 68 NotAFile = 20001 69 NotADirectory = 20002 70 NoSuchProcess = 20003 71 DirectoryNotEmpty = 20006 72 73 // VIX_COMMAND_* constants from Commands.h 74 CommandGuestReturnsBinary = 0x80 75 76 // VIX_FILE_ATTRIBUTES_ constants from vix.h 77 FileAttributesDirectory = 0x0001 78 FileAttributesSymlink = 0x0002 79 ) 80 81 // SetGuestFileAttributes flags as defined in vixOpenSource.h 82 const ( 83 FileAttributeSetAccessDate = 0x0001 84 FileAttributeSetModifyDate = 0x0002 85 FileAttributeSetReadonly = 0x0004 86 FileAttributeSetHidden = 0x0008 87 FileAttributeSetUnixOwnerid = 0x0010 88 FileAttributeSetUnixGroupid = 0x0020 89 FileAttributeSetUnixPermissions = 0x0040 90 ) 91 92 type Error int 93 94 func (err Error) Error() string { 95 return fmt.Sprintf("vix error=%d", err) 96 } 97 98 // ErrorCode does its best to map the given error to a VIX error code. 99 // See also: Vix_TranslateErrno 100 func ErrorCode(err error) int { 101 switch t := err.(type) { 102 case Error: 103 return int(t) 104 case *os.PathError: 105 if errno, ok := t.Err.(syscall.Errno); ok { 106 switch errno { 107 case syscall.ENOTEMPTY: 108 return DirectoryNotEmpty 109 } 110 } 111 case *exec.Error: 112 if t.Err == exec.ErrNotFound { 113 return FileNotFound 114 } 115 } 116 117 switch { 118 case os.IsNotExist(err): 119 return FileNotFound 120 case os.IsExist(err): 121 return FileAlreadyExists 122 case os.IsPermission(err): 123 return FileAccessError 124 default: 125 return Fail 126 } 127 } 128 129 type Header struct { 130 Magic uint32 131 MessageVersion uint16 132 133 TotalMessageLength uint32 134 HeaderLength uint32 135 BodyLength uint32 136 CredentialLength uint32 137 138 CommonFlags uint8 139 } 140 141 type CommandRequestHeader struct { 142 Header 143 144 OpCode uint32 145 RequestFlags uint32 146 147 TimeOut uint32 148 149 Cookie uint64 150 ClientHandleID uint32 151 152 UserCredentialType uint32 153 } 154 155 type StartProgramRequest struct { 156 CommandRequestHeader 157 158 Body struct { 159 StartMinimized uint8 160 ProgramPathLength uint32 161 ArgumentsLength uint32 162 WorkingDirLength uint32 163 NumEnvVars uint32 164 EnvVarLength uint32 165 } 166 167 ProgramPath string 168 Arguments string 169 WorkingDir string 170 EnvVars []string 171 } 172 173 // MarshalBinary implements the encoding.BinaryMarshaler interface 174 func (r *StartProgramRequest) MarshalBinary() ([]byte, error) { 175 var env bytes.Buffer 176 177 if n := len(r.EnvVars); n != 0 { 178 for _, e := range r.EnvVars { 179 _, _ = env.Write([]byte(e)) 180 _ = env.WriteByte(0) 181 } 182 r.Body.NumEnvVars = uint32(n) 183 r.Body.EnvVarLength = uint32(env.Len()) 184 } 185 186 var fields []string 187 188 add := func(s string, l *uint32) { 189 if n := len(s); n != 0 { 190 *l = uint32(n) + 1 191 fields = append(fields, s) 192 } 193 } 194 195 add(r.ProgramPath, &r.Body.ProgramPathLength) 196 add(r.Arguments, &r.Body.ArgumentsLength) 197 add(r.WorkingDir, &r.Body.WorkingDirLength) 198 199 buf := new(bytes.Buffer) 200 201 _ = binary.Write(buf, binary.LittleEndian, &r.Body) 202 203 for _, val := range fields { 204 _, _ = buf.Write([]byte(val)) 205 _ = buf.WriteByte(0) 206 } 207 208 if r.Body.EnvVarLength != 0 { 209 _, _ = buf.Write(env.Bytes()) 210 } 211 212 return buf.Bytes(), nil 213 } 214 215 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 216 func (r *StartProgramRequest) UnmarshalBinary(data []byte) error { 217 buf := bytes.NewBuffer(data) 218 219 err := binary.Read(buf, binary.LittleEndian, &r.Body) 220 if err != nil { 221 return err 222 } 223 224 fields := []struct { 225 len uint32 226 val *string 227 }{ 228 {r.Body.ProgramPathLength, &r.ProgramPath}, 229 {r.Body.ArgumentsLength, &r.Arguments}, 230 {r.Body.WorkingDirLength, &r.WorkingDir}, 231 } 232 233 for _, field := range fields { 234 if field.len == 0 { 235 continue 236 } 237 238 x := buf.Next(int(field.len)) 239 *field.val = string(bytes.TrimRight(x, "\x00")) 240 } 241 242 for i := 0; i < int(r.Body.NumEnvVars); i++ { 243 env, rerr := buf.ReadString(0) 244 if rerr != nil { 245 return rerr 246 } 247 248 env = env[:len(env)-1] // discard NULL terminator 249 r.EnvVars = append(r.EnvVars, env) 250 } 251 252 return nil 253 } 254 255 type KillProcessRequest struct { 256 CommandRequestHeader 257 258 Body struct { 259 Pid int64 260 Options uint32 261 } 262 } 263 264 // MarshalBinary implements the encoding.BinaryMarshaler interface 265 func (r *KillProcessRequest) MarshalBinary() ([]byte, error) { 266 buf := new(bytes.Buffer) 267 268 _ = binary.Write(buf, binary.LittleEndian, &r.Body) 269 270 return buf.Bytes(), nil 271 } 272 273 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 274 func (r *KillProcessRequest) UnmarshalBinary(data []byte) error { 275 buf := bytes.NewBuffer(data) 276 277 return binary.Read(buf, binary.LittleEndian, &r.Body) 278 } 279 280 type ListProcessesRequest struct { 281 CommandRequestHeader 282 283 Body struct { 284 Key uint32 285 Offset uint32 286 NumPids uint32 287 } 288 289 Pids []int64 290 } 291 292 // MarshalBinary implements the encoding.BinaryMarshaler interface 293 func (r *ListProcessesRequest) MarshalBinary() ([]byte, error) { 294 r.Body.NumPids = uint32(len(r.Pids)) 295 296 buf := new(bytes.Buffer) 297 298 _ = binary.Write(buf, binary.LittleEndian, &r.Body) 299 300 for _, pid := range r.Pids { 301 _ = binary.Write(buf, binary.LittleEndian, &pid) 302 } 303 304 return buf.Bytes(), nil 305 } 306 307 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 308 func (r *ListProcessesRequest) UnmarshalBinary(data []byte) error { 309 buf := bytes.NewBuffer(data) 310 311 err := binary.Read(buf, binary.LittleEndian, &r.Body) 312 if err != nil { 313 return err 314 } 315 316 r.Pids = make([]int64, r.Body.NumPids) 317 318 for i := uint32(0); i < r.Body.NumPids; i++ { 319 err := binary.Read(buf, binary.LittleEndian, &r.Pids[i]) 320 if err != nil { 321 return err 322 } 323 } 324 325 return nil 326 } 327 328 type ReadEnvironmentVariablesRequest struct { 329 CommandRequestHeader 330 331 Body struct { 332 NumNames uint32 333 NamesLength uint32 334 } 335 336 Names []string 337 } 338 339 // MarshalBinary implements the encoding.BinaryMarshaler interface 340 func (r *ReadEnvironmentVariablesRequest) MarshalBinary() ([]byte, error) { 341 var env bytes.Buffer 342 343 if n := len(r.Names); n != 0 { 344 for _, e := range r.Names { 345 _, _ = env.Write([]byte(e)) 346 _ = env.WriteByte(0) 347 } 348 r.Body.NumNames = uint32(n) 349 r.Body.NamesLength = uint32(env.Len()) 350 } 351 352 buf := new(bytes.Buffer) 353 354 _ = binary.Write(buf, binary.LittleEndian, &r.Body) 355 356 if r.Body.NamesLength != 0 { 357 _, _ = buf.Write(env.Bytes()) 358 } 359 360 return buf.Bytes(), nil 361 } 362 363 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 364 func (r *ReadEnvironmentVariablesRequest) UnmarshalBinary(data []byte) error { 365 buf := bytes.NewBuffer(data) 366 367 err := binary.Read(buf, binary.LittleEndian, &r.Body) 368 if err != nil { 369 return err 370 } 371 372 for i := 0; i < int(r.Body.NumNames); i++ { 373 env, rerr := buf.ReadString(0) 374 if rerr != nil { 375 return rerr 376 } 377 378 env = env[:len(env)-1] // discard NULL terminator 379 r.Names = append(r.Names, env) 380 } 381 382 return nil 383 } 384 385 type CreateTempFileRequest struct { 386 CommandRequestHeader 387 388 Body struct { 389 Options int32 390 FilePrefixLength uint32 391 FileSuffixLength uint32 392 DirectoryPathLength uint32 393 PropertyListLength uint32 394 } 395 396 FilePrefix string 397 FileSuffix string 398 DirectoryPath string 399 } 400 401 // MarshalBinary implements the encoding.BinaryMarshaler interface 402 func (r *CreateTempFileRequest) MarshalBinary() ([]byte, error) { 403 var fields []string 404 405 add := func(s string, l *uint32) { 406 *l = uint32(len(s)) // NOTE: NULL byte is not included in the length fields on the wire 407 fields = append(fields, s) 408 } 409 410 add(r.FilePrefix, &r.Body.FilePrefixLength) 411 add(r.FileSuffix, &r.Body.FileSuffixLength) 412 add(r.DirectoryPath, &r.Body.DirectoryPathLength) 413 414 buf := new(bytes.Buffer) 415 416 _ = binary.Write(buf, binary.LittleEndian, &r.Body) 417 418 for _, val := range fields { 419 _, _ = buf.Write([]byte(val)) 420 _ = buf.WriteByte(0) 421 } 422 423 return buf.Bytes(), nil 424 } 425 426 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 427 func (r *CreateTempFileRequest) UnmarshalBinary(data []byte) error { 428 buf := bytes.NewBuffer(data) 429 430 err := binary.Read(buf, binary.LittleEndian, &r.Body) 431 if err != nil { 432 return err 433 } 434 435 fields := []struct { 436 len uint32 437 val *string 438 }{ 439 {r.Body.FilePrefixLength, &r.FilePrefix}, 440 {r.Body.FileSuffixLength, &r.FileSuffix}, 441 {r.Body.DirectoryPathLength, &r.DirectoryPath}, 442 } 443 444 for _, field := range fields { 445 field.len++ // NOTE: NULL byte is not included in the length fields on the wire 446 447 x := buf.Next(int(field.len)) 448 *field.val = string(bytes.TrimRight(x, "\x00")) 449 } 450 451 return nil 452 } 453 454 type FileRequest struct { 455 CommandRequestHeader 456 457 Body struct { 458 FileOptions int32 459 GuestPathNameLength uint32 460 } 461 462 GuestPathName string 463 } 464 465 // MarshalBinary implements the encoding.BinaryMarshaler interface 466 func (r *FileRequest) MarshalBinary() ([]byte, error) { 467 buf := new(bytes.Buffer) 468 469 r.Body.GuestPathNameLength = uint32(len(r.GuestPathName)) 470 471 _ = binary.Write(buf, binary.LittleEndian, &r.Body) 472 473 _, _ = buf.WriteString(r.GuestPathName) 474 _ = buf.WriteByte(0) 475 476 return buf.Bytes(), nil 477 } 478 479 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 480 func (r *FileRequest) UnmarshalBinary(data []byte) error { 481 buf := bytes.NewBuffer(data) 482 483 err := binary.Read(buf, binary.LittleEndian, &r.Body) 484 if err != nil { 485 return err 486 } 487 488 name := buf.Next(int(r.Body.GuestPathNameLength)) 489 r.GuestPathName = string(bytes.TrimRight(name, "\x00")) 490 491 return nil 492 } 493 494 type DirRequest struct { 495 CommandRequestHeader 496 497 Body struct { 498 FileOptions int32 499 GuestPathNameLength uint32 500 FilePropertiesLength uint32 501 Recursive bool 502 } 503 504 GuestPathName string 505 } 506 507 // MarshalBinary implements the encoding.BinaryMarshaler interface 508 func (r *DirRequest) MarshalBinary() ([]byte, error) { 509 buf := new(bytes.Buffer) 510 511 r.Body.GuestPathNameLength = uint32(len(r.GuestPathName)) 512 513 _ = binary.Write(buf, binary.LittleEndian, &r.Body) 514 515 _, _ = buf.WriteString(r.GuestPathName) 516 _ = buf.WriteByte(0) 517 518 return buf.Bytes(), nil 519 } 520 521 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 522 func (r *DirRequest) UnmarshalBinary(data []byte) error { 523 buf := bytes.NewBuffer(data) 524 525 err := binary.Read(buf, binary.LittleEndian, &r.Body) 526 if err != nil { 527 return err 528 } 529 530 name := buf.Next(int(r.Body.GuestPathNameLength)) 531 r.GuestPathName = string(bytes.TrimRight(name, "\x00")) 532 533 return nil 534 } 535 536 type RenameFileRequest struct { 537 CommandRequestHeader 538 539 Body struct { 540 CopyFileOptions int32 541 OldPathNameLength uint32 542 NewPathNameLength uint32 543 FilePropertiesLength uint32 544 Overwrite bool 545 } 546 547 OldPathName string 548 NewPathName string 549 } 550 551 // MarshalBinary implements the encoding.BinaryMarshaler interface 552 func (r *RenameFileRequest) MarshalBinary() ([]byte, error) { 553 var fields []string 554 555 add := func(s string, l *uint32) { 556 *l = uint32(len(s)) // NOTE: NULL byte is not included in the length fields on the wire 557 fields = append(fields, s) 558 } 559 560 add(r.OldPathName, &r.Body.OldPathNameLength) 561 add(r.NewPathName, &r.Body.NewPathNameLength) 562 563 buf := new(bytes.Buffer) 564 565 _ = binary.Write(buf, binary.LittleEndian, &r.Body) 566 567 for _, val := range fields { 568 _, _ = buf.Write([]byte(val)) 569 _ = buf.WriteByte(0) 570 } 571 572 return buf.Bytes(), nil 573 } 574 575 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 576 func (r *RenameFileRequest) UnmarshalBinary(data []byte) error { 577 buf := bytes.NewBuffer(data) 578 579 err := binary.Read(buf, binary.LittleEndian, &r.Body) 580 if err != nil { 581 return err 582 } 583 584 fields := []struct { 585 len uint32 586 val *string 587 }{ 588 {r.Body.OldPathNameLength, &r.OldPathName}, 589 {r.Body.NewPathNameLength, &r.NewPathName}, 590 } 591 592 for _, field := range fields { 593 field.len++ // NOTE: NULL byte is not included in the length fields on the wire 594 595 x := buf.Next(int(field.len)) 596 *field.val = string(bytes.TrimRight(x, "\x00")) 597 } 598 599 return nil 600 } 601 602 type ListFilesRequest struct { 603 CommandRequestHeader 604 605 Body struct { 606 FileOptions int32 607 GuestPathNameLength uint32 608 PatternLength uint32 609 Index int32 610 MaxResults int32 611 Offset uint64 612 } 613 614 GuestPathName string 615 Pattern string 616 } 617 618 // MarshalBinary implements the encoding.BinaryMarshaler interface 619 func (r *ListFilesRequest) MarshalBinary() ([]byte, error) { 620 var fields []string 621 622 add := func(s string, l *uint32) { 623 if n := len(s); n != 0 { 624 *l = uint32(n) + 1 625 fields = append(fields, s) 626 } 627 } 628 629 add(r.GuestPathName, &r.Body.GuestPathNameLength) 630 add(r.Pattern, &r.Body.PatternLength) 631 632 buf := new(bytes.Buffer) 633 634 _ = binary.Write(buf, binary.LittleEndian, &r.Body) 635 636 for _, val := range fields { 637 _, _ = buf.Write([]byte(val)) 638 _ = buf.WriteByte(0) 639 } 640 641 return buf.Bytes(), nil 642 } 643 644 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 645 func (r *ListFilesRequest) UnmarshalBinary(data []byte) error { 646 buf := bytes.NewBuffer(data) 647 648 err := binary.Read(buf, binary.LittleEndian, &r.Body) 649 if err != nil { 650 return err 651 } 652 653 fields := []struct { 654 len uint32 655 val *string 656 }{ 657 {r.Body.GuestPathNameLength, &r.GuestPathName}, 658 {r.Body.PatternLength, &r.Pattern}, 659 } 660 661 for _, field := range fields { 662 if field.len == 0 { 663 continue 664 } 665 666 x := buf.Next(int(field.len)) 667 *field.val = string(bytes.TrimRight(x, "\x00")) 668 } 669 670 return nil 671 } 672 673 type SetGuestFileAttributesRequest struct { 674 CommandRequestHeader 675 676 Body struct { 677 FileOptions int32 678 AccessTime int64 679 ModificationTime int64 680 OwnerID int32 681 GroupID int32 682 Permissions int32 683 Hidden bool 684 ReadOnly bool 685 GuestPathNameLength uint32 686 } 687 688 GuestPathName string 689 } 690 691 // MarshalBinary implements the encoding.BinaryMarshaler interface 692 func (r *SetGuestFileAttributesRequest) MarshalBinary() ([]byte, error) { 693 buf := new(bytes.Buffer) 694 695 r.Body.GuestPathNameLength = uint32(len(r.GuestPathName)) 696 697 _ = binary.Write(buf, binary.LittleEndian, &r.Body) 698 699 _, _ = buf.WriteString(r.GuestPathName) 700 _ = buf.WriteByte(0) 701 702 return buf.Bytes(), nil 703 } 704 705 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 706 func (r *SetGuestFileAttributesRequest) UnmarshalBinary(data []byte) error { 707 buf := bytes.NewBuffer(data) 708 709 err := binary.Read(buf, binary.LittleEndian, &r.Body) 710 if err != nil { 711 return err 712 } 713 714 name := buf.Next(int(r.Body.GuestPathNameLength)) 715 r.GuestPathName = string(bytes.TrimRight(name, "\x00")) 716 717 return nil 718 } 719 720 func (r *SetGuestFileAttributesRequest) IsSet(opt int32) bool { 721 return r.Body.FileOptions&opt == opt 722 } 723 724 type CommandHgfsSendPacket struct { 725 CommandRequestHeader 726 727 Body struct { 728 PacketSize uint32 729 Timeout int32 730 } 731 732 Packet []byte 733 } 734 735 // MarshalBinary implements the encoding.BinaryMarshaler interface 736 func (r *CommandHgfsSendPacket) MarshalBinary() ([]byte, error) { 737 buf := new(bytes.Buffer) 738 739 _ = binary.Write(buf, binary.LittleEndian, &r.Body) 740 741 _, _ = buf.Write(r.Packet) 742 743 return buf.Bytes(), nil 744 } 745 746 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 747 func (r *CommandHgfsSendPacket) UnmarshalBinary(data []byte) error { 748 buf := bytes.NewBuffer(data) 749 750 err := binary.Read(buf, binary.LittleEndian, &r.Body) 751 if err != nil { 752 return err 753 } 754 755 r.Packet = buf.Next(int(r.Body.PacketSize)) 756 757 return nil 758 } 759 760 type InitiateFileTransferToGuestRequest struct { 761 CommandRequestHeader 762 763 Body struct { 764 Options int32 765 GuestPathNameLength uint32 766 Overwrite bool 767 } 768 769 GuestPathName string 770 } 771 772 // MarshalBinary implements the encoding.BinaryMarshaler interface 773 func (r *InitiateFileTransferToGuestRequest) MarshalBinary() ([]byte, error) { 774 buf := new(bytes.Buffer) 775 776 r.Body.GuestPathNameLength = uint32(len(r.GuestPathName)) 777 778 _ = binary.Write(buf, binary.LittleEndian, &r.Body) 779 780 _, _ = buf.WriteString(r.GuestPathName) 781 _ = buf.WriteByte(0) 782 783 return buf.Bytes(), nil 784 } 785 786 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 787 func (r *InitiateFileTransferToGuestRequest) UnmarshalBinary(data []byte) error { 788 buf := bytes.NewBuffer(data) 789 790 err := binary.Read(buf, binary.LittleEndian, &r.Body) 791 if err != nil { 792 return err 793 } 794 795 name := buf.Next(int(r.Body.GuestPathNameLength)) 796 r.GuestPathName = string(bytes.TrimRight(name, "\x00")) 797 798 return nil 799 } 800 801 type UserCredentialNamePassword struct { 802 Body struct { 803 NameLength uint32 804 PasswordLength uint32 805 } 806 807 Name string 808 Password string 809 } 810 811 func (c *UserCredentialNamePassword) UnmarshalBinary(data []byte) error { 812 buf := bytes.NewBuffer(bytes.TrimRight(data, "\x00")) 813 814 err := binary.Read(buf, binary.LittleEndian, &c.Body) 815 if err != nil { 816 return err 817 } 818 819 str, err := base64.StdEncoding.DecodeString(buf.String()) 820 if err != nil { 821 return err 822 } 823 824 c.Name = string(str[0:c.Body.NameLength]) 825 c.Password = string(str[c.Body.NameLength+1 : len(str)-1]) 826 827 return nil 828 } 829 830 func (c *UserCredentialNamePassword) MarshalBinary() ([]byte, error) { 831 buf := new(bytes.Buffer) 832 833 c.Body.NameLength = uint32(len(c.Name)) 834 c.Body.PasswordLength = uint32(len(c.Password)) 835 836 _ = binary.Write(buf, binary.LittleEndian, &c.Body) 837 838 src := append([]byte(c.Name+"\x00"), []byte(c.Password+"\x00")...) 839 840 enc := base64.StdEncoding 841 pwd := make([]byte, enc.EncodedLen(len(src))) 842 enc.Encode(pwd, src) 843 _, _ = buf.Write(pwd) 844 _ = buf.WriteByte(0) 845 846 return buf.Bytes(), nil 847 }