github.com/vmware/govmomi@v0.51.0/toolbox/command.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package toolbox
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/base64"
    10  	"encoding/binary"
    11  	"encoding/hex"
    12  	"fmt"
    13  	"log"
    14  	"os"
    15  	"path/filepath"
    16  	"runtime"
    17  	"strings"
    18  	"time"
    19  
    20  	"github.com/vmware/govmomi/toolbox/hgfs"
    21  	"github.com/vmware/govmomi/toolbox/process"
    22  	"github.com/vmware/govmomi/toolbox/vix"
    23  )
    24  
    25  type CommandHandler func(vix.CommandRequestHeader, []byte) ([]byte, error)
    26  
    27  type CommandServer struct {
    28  	Out *ChannelOut
    29  
    30  	ProcessManager *process.Manager
    31  
    32  	Authenticate func(vix.CommandRequestHeader, []byte) error
    33  
    34  	ProcessStartCommand func(*process.Manager, *vix.StartProgramRequest) (int64, error)
    35  
    36  	handlers map[uint32]CommandHandler
    37  
    38  	FileServer *hgfs.Server
    39  }
    40  
    41  func registerCommandServer(service *Service) *CommandServer {
    42  	server := &CommandServer{
    43  		Out:            service.out,
    44  		ProcessManager: process.NewManager(),
    45  	}
    46  
    47  	server.handlers = map[uint32]CommandHandler{
    48  		vix.CommandGetToolsState:                 server.GetToolsState,
    49  		vix.CommandStartProgram:                  server.StartCommand,
    50  		vix.CommandTerminateProcess:              server.KillProcess,
    51  		vix.CommandListProcessesEx:               server.ListProcesses,
    52  		vix.CommandReadEnvVariables:              server.ReadEnvironmentVariables,
    53  		vix.CommandCreateTemporaryFileEx:         server.CreateTemporaryFile,
    54  		vix.CommandCreateTemporaryDirectory:      server.CreateTemporaryDirectory,
    55  		vix.CommandDeleteGuestFileEx:             server.DeleteFile,
    56  		vix.CommandCreateDirectoryEx:             server.CreateDirectory,
    57  		vix.CommandDeleteGuestDirectoryEx:        server.DeleteDirectory,
    58  		vix.CommandMoveGuestFileEx:               server.MoveFile,
    59  		vix.CommandMoveGuestDirectory:            server.MoveDirectory,
    60  		vix.CommandListFiles:                     server.ListFiles,
    61  		vix.CommandSetGuestFileAttributes:        server.SetGuestFileAttributes,
    62  		vix.CommandInitiateFileTransferFromGuest: server.InitiateFileTransferFromGuest,
    63  		vix.CommandInitiateFileTransferToGuest:   server.InitiateFileTransferToGuest,
    64  		vix.HgfsSendPacketCommand:                server.ProcessHgfsPacket,
    65  	}
    66  
    67  	server.ProcessStartCommand = DefaultStartCommand
    68  
    69  	service.RegisterHandler("Vix_1_Relayed_Command", server.Dispatch)
    70  
    71  	return server
    72  }
    73  
    74  func commandResult(header vix.CommandRequestHeader, rc int, err error, response []byte) []byte {
    75  	// All Foundry tools commands return results that start with a foundry error
    76  	// and a guest-OS-specific error (e.g. errno)
    77  	errno := 0
    78  
    79  	if err != nil {
    80  		// TODO: inspect err for system error, setting errno
    81  
    82  		response = []byte(err.Error())
    83  
    84  		log.Printf("[vix] op=%d error: %s", header.OpCode, err)
    85  	}
    86  
    87  	buf := bytes.NewBufferString(fmt.Sprintf("%d %d ", rc, errno))
    88  
    89  	if header.CommonFlags&vix.CommandGuestReturnsBinary != 0 {
    90  		// '#' delimits end of ascii and the start of the binary data (see ToolsDaemonTcloReceiveVixCommand)
    91  		_ = buf.WriteByte('#')
    92  	}
    93  
    94  	_, _ = buf.Write(response)
    95  
    96  	if header.CommonFlags&vix.CommandGuestReturnsBinary == 0 {
    97  		// this is not binary data, so it should be a NULL terminated string (see ToolsDaemonTcloReceiveVixCommand)
    98  		_ = buf.WriteByte(0)
    99  	}
   100  
   101  	return buf.Bytes()
   102  }
   103  
   104  func (c *CommandServer) Dispatch(data []byte) ([]byte, error) {
   105  	// See ToolsDaemonTcloGetQuotedString
   106  	if data[0] == '"' {
   107  		data = data[1:]
   108  	}
   109  
   110  	var name string
   111  
   112  	ix := bytes.IndexByte(data, '"')
   113  	if ix > 0 {
   114  		name = string(data[:ix])
   115  		data = data[ix+1:]
   116  	}
   117  	// skip the NULL
   118  	if data[0] == 0 {
   119  		data = data[1:]
   120  	}
   121  
   122  	if Trace {
   123  		fmt.Fprintf(os.Stderr, "vix dispatch %q...\n%s\n", name, hex.Dump(data))
   124  	}
   125  
   126  	var header vix.CommandRequestHeader
   127  	buf := bytes.NewBuffer(data)
   128  	err := binary.Read(buf, binary.LittleEndian, &header)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	if header.Magic != vix.CommandMagicWord {
   134  		return commandResult(header, vix.InvalidMessageHeader, nil, nil), nil
   135  	}
   136  
   137  	handler, ok := c.handlers[header.OpCode]
   138  	if !ok {
   139  		return commandResult(header, vix.UnrecognizedCommandInGuest, nil, nil), nil
   140  	}
   141  
   142  	if header.OpCode != vix.CommandGetToolsState {
   143  		// Every command expect GetToolsState requires authentication
   144  		creds := buf.Bytes()[header.BodyLength:]
   145  
   146  		err = c.authenticate(header, creds[:header.CredentialLength])
   147  		if err != nil {
   148  			return commandResult(header, vix.AuthenticationFail, err, nil), nil
   149  		}
   150  	}
   151  
   152  	rc := vix.OK
   153  
   154  	response, err := handler(header, buf.Bytes())
   155  	if err != nil {
   156  		rc = vix.ErrorCode(err)
   157  	}
   158  
   159  	return commandResult(header, rc, err, response), nil
   160  }
   161  
   162  func (c *CommandServer) RegisterHandler(op uint32, handler CommandHandler) {
   163  	c.handlers[op] = handler
   164  }
   165  
   166  func (c *CommandServer) GetToolsState(_ vix.CommandRequestHeader, _ []byte) ([]byte, error) {
   167  	hostname, _ := os.Hostname()
   168  	osname := fmt.Sprintf("%s-%s", runtime.GOOS, runtime.GOARCH)
   169  
   170  	// Note that vmtoolsd sends back 40 or so of these properties, sticking with the minimal set for now.
   171  	props := vix.PropertyList{
   172  		vix.NewStringProperty(vix.PropertyGuestOsVersion, osname),
   173  		vix.NewStringProperty(vix.PropertyGuestOsVersionShort, osname),
   174  		vix.NewStringProperty(vix.PropertyGuestToolsProductNam, "VMware Tools (Go)"),
   175  		vix.NewStringProperty(vix.PropertyGuestToolsVersion, "10.0.5 build-3227872 (Compatible)"),
   176  		vix.NewStringProperty(vix.PropertyGuestName, hostname),
   177  		vix.NewInt32Property(vix.PropertyGuestToolsAPIOptions, 0x0001), // TODO: const VIX_TOOLSFEATURE_SUPPORT_GET_HANDLE_STATE
   178  		vix.NewInt32Property(vix.PropertyGuestOsFamily, 1),             // TODO: const GUEST_OS_FAMILY_*
   179  		vix.NewBoolProperty(vix.PropertyGuestStartProgramEnabled, true),
   180  		vix.NewBoolProperty(vix.PropertyGuestTerminateProcessEnabled, true),
   181  		vix.NewBoolProperty(vix.PropertyGuestListProcessesEnabled, true),
   182  		vix.NewBoolProperty(vix.PropertyGuestReadEnvironmentVariableEnabled, true),
   183  		vix.NewBoolProperty(vix.PropertyGuestMakeDirectoryEnabled, true),
   184  		vix.NewBoolProperty(vix.PropertyGuestDeleteFileEnabled, true),
   185  		vix.NewBoolProperty(vix.PropertyGuestDeleteDirectoryEnabled, true),
   186  		vix.NewBoolProperty(vix.PropertyGuestMoveDirectoryEnabled, true),
   187  		vix.NewBoolProperty(vix.PropertyGuestMoveFileEnabled, true),
   188  		vix.NewBoolProperty(vix.PropertyGuestCreateTempFileEnabled, true),
   189  		vix.NewBoolProperty(vix.PropertyGuestCreateTempDirectoryEnabled, true),
   190  		vix.NewBoolProperty(vix.PropertyGuestListFilesEnabled, true),
   191  		vix.NewBoolProperty(vix.PropertyGuestChangeFileAttributesEnabled, true),
   192  		vix.NewBoolProperty(vix.PropertyGuestInitiateFileTransferFromGuestEnabled, true),
   193  		vix.NewBoolProperty(vix.PropertyGuestInitiateFileTransferToGuestEnabled, true),
   194  	}
   195  
   196  	src, _ := props.MarshalBinary()
   197  	enc := base64.StdEncoding
   198  	buf := make([]byte, enc.EncodedLen(len(src)))
   199  	enc.Encode(buf, src)
   200  
   201  	return buf, nil
   202  }
   203  
   204  func (c *CommandServer) StartCommand(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   205  	r := &vix.StartProgramRequest{
   206  		CommandRequestHeader: header,
   207  	}
   208  
   209  	err := r.UnmarshalBinary(data)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	pid, err := c.ProcessStartCommand(c.ProcessManager, r)
   215  	if err != nil {
   216  		return nil, err
   217  	}
   218  
   219  	return append([]byte(fmt.Sprintf("%d", pid)), 0), nil
   220  }
   221  
   222  func DefaultStartCommand(m *process.Manager, r *vix.StartProgramRequest) (int64, error) {
   223  	p := process.New()
   224  
   225  	switch r.ProgramPath {
   226  	case "http.RoundTrip":
   227  		p = process.NewRoundTrip()
   228  	default:
   229  		// Standard vmware-tools requires an absolute path,
   230  		// we'll enable IO redirection by default without an absolute path.
   231  		if !strings.Contains(r.ProgramPath, "/") {
   232  			p = p.WithIO()
   233  		}
   234  	}
   235  
   236  	return m.Start(r, p)
   237  }
   238  
   239  func (c *CommandServer) KillProcess(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   240  	r := &vix.KillProcessRequest{
   241  		CommandRequestHeader: header,
   242  	}
   243  
   244  	err := r.UnmarshalBinary(data)
   245  	if err != nil {
   246  		return nil, err
   247  	}
   248  
   249  	if c.ProcessManager.Kill(r.Body.Pid) {
   250  		return nil, err
   251  	}
   252  
   253  	// TODO: could kill process started outside of toolbox
   254  
   255  	return nil, vix.Error(vix.NoSuchProcess)
   256  }
   257  
   258  func (c *CommandServer) ListProcesses(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   259  	r := &vix.ListProcessesRequest{
   260  		CommandRequestHeader: header,
   261  	}
   262  
   263  	err := r.UnmarshalBinary(data)
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  
   268  	state := c.ProcessManager.ListProcesses(r.Pids)
   269  
   270  	return state, nil
   271  }
   272  
   273  func (c *CommandServer) ReadEnvironmentVariables(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   274  	r := &vix.ReadEnvironmentVariablesRequest{
   275  		CommandRequestHeader: header,
   276  	}
   277  
   278  	err := r.UnmarshalBinary(data)
   279  	if err != nil {
   280  		return nil, err
   281  	}
   282  
   283  	buf := new(bytes.Buffer)
   284  
   285  	if len(r.Names) == 0 {
   286  		for _, e := range os.Environ() {
   287  			_, _ = buf.WriteString(fmt.Sprintf("<ev>%s</ev>", process.EscapeXML.Replace(e)))
   288  		}
   289  	} else {
   290  		for _, key := range r.Names {
   291  			val := os.Getenv(key)
   292  			if val == "" {
   293  				continue
   294  			}
   295  			_, _ = buf.WriteString(fmt.Sprintf("<ev>%s=%s</ev>", process.EscapeXML.Replace(key), process.EscapeXML.Replace(val)))
   296  		}
   297  	}
   298  
   299  	return buf.Bytes(), nil
   300  }
   301  
   302  func (c *CommandServer) CreateTemporaryFile(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   303  	r := &vix.CreateTempFileRequest{
   304  		CommandRequestHeader: header,
   305  	}
   306  
   307  	err := r.UnmarshalBinary(data)
   308  	if err != nil {
   309  		return nil, err
   310  	}
   311  
   312  	f, err := os.CreateTemp(r.DirectoryPath, r.FilePrefix+"vmware")
   313  	if err != nil {
   314  		return nil, err
   315  	}
   316  
   317  	_ = f.Close()
   318  
   319  	return []byte(f.Name()), nil
   320  }
   321  
   322  func (c *CommandServer) CreateTemporaryDirectory(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   323  	r := &vix.CreateTempFileRequest{
   324  		CommandRequestHeader: header,
   325  	}
   326  
   327  	err := r.UnmarshalBinary(data)
   328  	if err != nil {
   329  		return nil, err
   330  	}
   331  
   332  	name, err := os.MkdirTemp(r.DirectoryPath, r.FilePrefix+"vmware")
   333  	if err != nil {
   334  		return nil, err
   335  	}
   336  
   337  	return []byte(name), nil
   338  }
   339  
   340  func (c *CommandServer) DeleteFile(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   341  	r := &vix.FileRequest{
   342  		CommandRequestHeader: header,
   343  	}
   344  
   345  	err := r.UnmarshalBinary(data)
   346  	if err != nil {
   347  		return nil, err
   348  	}
   349  
   350  	info, err := os.Stat(r.GuestPathName)
   351  	if err != nil {
   352  		return nil, err
   353  	}
   354  
   355  	if info.IsDir() {
   356  		return nil, vix.Error(vix.NotAFile)
   357  	}
   358  
   359  	err = os.Remove(r.GuestPathName)
   360  
   361  	return nil, err
   362  }
   363  
   364  func (c *CommandServer) DeleteDirectory(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   365  	r := &vix.DirRequest{
   366  		CommandRequestHeader: header,
   367  	}
   368  
   369  	err := r.UnmarshalBinary(data)
   370  	if err != nil {
   371  		return nil, err
   372  	}
   373  
   374  	info, err := os.Stat(r.GuestPathName)
   375  	if err != nil {
   376  		return nil, err
   377  	}
   378  
   379  	if !info.IsDir() {
   380  		return nil, vix.Error(vix.NotADirectory)
   381  	}
   382  
   383  	if r.Body.Recursive {
   384  		err = os.RemoveAll(r.GuestPathName)
   385  	} else {
   386  		err = os.Remove(r.GuestPathName)
   387  	}
   388  
   389  	return nil, err
   390  }
   391  
   392  func (c *CommandServer) CreateDirectory(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   393  	r := &vix.DirRequest{
   394  		CommandRequestHeader: header,
   395  	}
   396  
   397  	err := r.UnmarshalBinary(data)
   398  	if err != nil {
   399  		return nil, err
   400  	}
   401  
   402  	mkdir := os.Mkdir
   403  
   404  	if r.Body.Recursive {
   405  		mkdir = os.MkdirAll
   406  	}
   407  
   408  	err = mkdir(r.GuestPathName, 0700)
   409  
   410  	return nil, err
   411  }
   412  
   413  func (c *CommandServer) MoveDirectory(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   414  	r := &vix.RenameFileRequest{
   415  		CommandRequestHeader: header,
   416  	}
   417  
   418  	err := r.UnmarshalBinary(data)
   419  	if err != nil {
   420  		return nil, err
   421  	}
   422  
   423  	info, err := os.Stat(r.OldPathName)
   424  	if err != nil {
   425  		return nil, err
   426  	}
   427  
   428  	if !info.IsDir() {
   429  		return nil, vix.Error(vix.NotADirectory)
   430  	}
   431  
   432  	if !r.Body.Overwrite {
   433  		_, err = os.Stat(r.NewPathName)
   434  		if err == nil {
   435  			return nil, vix.Error(vix.FileAlreadyExists)
   436  		}
   437  	}
   438  
   439  	return nil, os.Rename(r.OldPathName, r.NewPathName)
   440  }
   441  
   442  func (c *CommandServer) MoveFile(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   443  	r := &vix.RenameFileRequest{
   444  		CommandRequestHeader: header,
   445  	}
   446  
   447  	err := r.UnmarshalBinary(data)
   448  	if err != nil {
   449  		return nil, err
   450  	}
   451  
   452  	info, err := os.Stat(r.OldPathName)
   453  	if err != nil {
   454  		return nil, err
   455  	}
   456  
   457  	if info.IsDir() {
   458  		return nil, vix.Error(vix.NotAFile)
   459  	}
   460  
   461  	if !r.Body.Overwrite {
   462  		_, err = os.Stat(r.NewPathName)
   463  		if err == nil {
   464  			return nil, vix.Error(vix.FileAlreadyExists)
   465  		}
   466  	}
   467  
   468  	return nil, os.Rename(r.OldPathName, r.NewPathName)
   469  }
   470  
   471  func (c *CommandServer) ListFiles(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   472  	r := &vix.ListFilesRequest{
   473  		CommandRequestHeader: header,
   474  	}
   475  
   476  	err := r.UnmarshalBinary(data)
   477  	if err != nil {
   478  		return nil, err
   479  	}
   480  
   481  	info, err := os.Lstat(r.GuestPathName)
   482  	if err != nil {
   483  		return nil, err
   484  	}
   485  
   486  	var dir string
   487  	var files []os.FileInfo
   488  
   489  	if info.IsDir() {
   490  		dir = r.GuestPathName
   491  		entries, err := os.ReadDir(r.GuestPathName)
   492  		if err != nil {
   493  			return nil, err
   494  		}
   495  		for _, entry := range entries {
   496  			file, _ := entry.Info()
   497  			files = append(files, file)
   498  		}
   499  	} else {
   500  		dir = filepath.Dir(r.GuestPathName)
   501  		files = append(files, info)
   502  	}
   503  
   504  	offset := r.Body.Offset + uint64(r.Body.Index)
   505  	total := uint64(len(files)) - offset
   506  	if int(offset) < len(files) {
   507  		files = files[offset:]
   508  	} else {
   509  		total = 0 // offset is not valid (open-vm-tools behaves the same in this case)
   510  	}
   511  
   512  	var remaining uint64
   513  
   514  	if r.Body.MaxResults > 0 && total > uint64(r.Body.MaxResults) {
   515  		remaining = total - uint64(r.Body.MaxResults)
   516  		files = files[:r.Body.MaxResults]
   517  	}
   518  
   519  	buf := new(bytes.Buffer)
   520  	buf.WriteString(fmt.Sprintf("<rem>%d</rem>", remaining))
   521  
   522  	for _, info = range files {
   523  		buf.WriteString(fileExtendedInfoFormat(dir, info))
   524  	}
   525  
   526  	return buf.Bytes(), nil
   527  }
   528  
   529  func chtimes(r *vix.SetGuestFileAttributesRequest) error {
   530  	var mtime, atime *time.Time
   531  
   532  	if r.IsSet(vix.FileAttributeSetModifyDate) {
   533  		t := time.Unix(r.Body.ModificationTime, 0)
   534  		mtime = &t
   535  	}
   536  
   537  	if r.IsSet(vix.FileAttributeSetAccessDate) {
   538  		t := time.Unix(r.Body.AccessTime, 0)
   539  		atime = &t
   540  	}
   541  
   542  	if mtime == nil && atime == nil {
   543  		return nil
   544  	}
   545  
   546  	info, err := os.Stat(r.GuestPathName)
   547  	if err != nil {
   548  		return err
   549  	}
   550  
   551  	if mtime == nil {
   552  		t := info.ModTime()
   553  		mtime = &t
   554  	}
   555  
   556  	if atime == nil {
   557  		t := info.ModTime()
   558  		atime = &t
   559  	}
   560  
   561  	return os.Chtimes(r.GuestPathName, *atime, *mtime)
   562  }
   563  
   564  func chown(r *vix.SetGuestFileAttributesRequest) error {
   565  	uid := -1
   566  	gid := -1
   567  
   568  	if r.IsSet(vix.FileAttributeSetUnixOwnerid) {
   569  		uid = int(r.Body.OwnerID)
   570  	}
   571  
   572  	if r.IsSet(vix.FileAttributeSetUnixGroupid) {
   573  		gid = int(r.Body.GroupID)
   574  	}
   575  
   576  	if uid == -1 && gid == -1 {
   577  		return nil
   578  	}
   579  
   580  	return os.Chown(r.GuestPathName, uid, gid)
   581  }
   582  
   583  func chmod(r *vix.SetGuestFileAttributesRequest) error {
   584  	if r.IsSet(vix.FileAttributeSetUnixPermissions) {
   585  		return os.Chmod(r.GuestPathName, os.FileMode(r.Body.Permissions).Perm())
   586  	}
   587  
   588  	return nil
   589  }
   590  
   591  func (c *CommandServer) SetGuestFileAttributes(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   592  	r := &vix.SetGuestFileAttributesRequest{
   593  		CommandRequestHeader: header,
   594  	}
   595  
   596  	err := r.UnmarshalBinary(data)
   597  	if err != nil {
   598  		return nil, err
   599  	}
   600  
   601  	for _, set := range []func(*vix.SetGuestFileAttributesRequest) error{chtimes, chown, chmod} {
   602  		err = set(r)
   603  		if err != nil {
   604  			return nil, err
   605  		}
   606  	}
   607  
   608  	return nil, nil
   609  }
   610  
   611  func (c *CommandServer) InitiateFileTransferFromGuest(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   612  	r := &vix.ListFilesRequest{
   613  		CommandRequestHeader: header,
   614  	}
   615  
   616  	err := r.UnmarshalBinary(data)
   617  	if err != nil {
   618  		return nil, err
   619  	}
   620  
   621  	info, err := c.FileServer.Stat(r.GuestPathName)
   622  	if err != nil {
   623  		return nil, err
   624  	}
   625  
   626  	if info.Mode()&os.ModeSymlink == os.ModeSymlink {
   627  		return nil, vix.Error(vix.InvalidArg)
   628  	}
   629  
   630  	if info.IsDir() {
   631  		return nil, vix.Error(vix.NotAFile)
   632  	}
   633  
   634  	return []byte(fileExtendedInfoFormat("", info)), nil
   635  }
   636  
   637  func (c *CommandServer) InitiateFileTransferToGuest(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   638  	r := &vix.InitiateFileTransferToGuestRequest{
   639  		CommandRequestHeader: header,
   640  	}
   641  
   642  	err := r.UnmarshalBinary(data)
   643  	if err != nil {
   644  		return nil, err
   645  	}
   646  
   647  	info, err := c.FileServer.Stat(r.GuestPathName)
   648  	if err == nil {
   649  		if info.Mode()&os.ModeSymlink == os.ModeSymlink {
   650  			return nil, vix.Error(vix.InvalidArg)
   651  		}
   652  
   653  		if info.IsDir() {
   654  			return nil, vix.Error(vix.NotAFile)
   655  		}
   656  
   657  		if !r.Body.Overwrite {
   658  			return nil, vix.Error(vix.FileAlreadyExists)
   659  		}
   660  	} else if !os.IsNotExist(err) {
   661  		return nil, err
   662  	}
   663  
   664  	return nil, nil
   665  }
   666  
   667  func (c *CommandServer) ProcessHgfsPacket(header vix.CommandRequestHeader, data []byte) ([]byte, error) {
   668  	r := &vix.CommandHgfsSendPacket{
   669  		CommandRequestHeader: header,
   670  	}
   671  
   672  	err := r.UnmarshalBinary(data)
   673  	if err != nil {
   674  		return nil, err
   675  	}
   676  
   677  	return c.FileServer.Dispatch(r.Packet)
   678  }
   679  
   680  func (c *CommandServer) authenticate(r vix.CommandRequestHeader, data []byte) error {
   681  	if c.Authenticate != nil {
   682  		return c.Authenticate(r, data)
   683  	}
   684  
   685  	switch r.UserCredentialType {
   686  	case vix.UserCredentialTypeNamePassword:
   687  		var c vix.UserCredentialNamePassword
   688  
   689  		if err := c.UnmarshalBinary(data); err != nil {
   690  			return err
   691  		}
   692  
   693  		if Trace {
   694  			fmt.Fprintf(traceLog, "ignoring credentials: %q:%q\n", c.Name, c.Password)
   695  		}
   696  
   697  		return nil
   698  	default:
   699  		return fmt.Errorf("unsupported UserCredentialType=%d", r.UserCredentialType)
   700  	}
   701  }