From: Oliver Kurth Date: Fri, 26 Jan 2018 23:04:35 +0000 (-0800) Subject: Hgfs Server: fix error result for new dir creation in the virtual folder X-Git-Tag: stable-10.3.0~175 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=09b6621863ece170e4fc6b617f0bc1e3d17867f2;p=thirdparty%2Fopen-vm-tools.git Hgfs Server: fix error result for new dir creation in the virtual folder The Hgfs server code detects when a client tries to create a new folder in the virtual folder containing the VMware Shares. This is not allowed as only the host can add new Shares which appears in this folder. The current error code returned to the client in these cases is access denied. This is only correct when the new folder does not collide with an existing share. This stops clients treating the virtual folder as a regular read/write physical folder. However, for the case where the name collides, the access denied error is not correct, as it does not tell the client the folder already exists. This causes some applications to fail as they expect to see this error if the path component exists as that is okay and expected. At this point the application will continue to traverse the path and ensure the next component exists or if not create that. To ensure that applications don't prematurely fail and can test that the share still exists in the path the Hgfs server should return HGFS_ERROR_FILE_EXIST and leave HGFS_ERROR_ACCESS_DENIED for all other cases. --- diff --git a/open-vm-tools/lib/hgfsServer/hgfsServer.c b/open-vm-tools/lib/hgfsServer/hgfsServer.c index b942653e3..ea9d48180 100644 --- a/open-vm-tools/lib/hgfsServer/hgfsServer.c +++ b/open-vm-tools/lib/hgfsServer/hgfsServer.c @@ -7466,63 +7466,78 @@ HgfsServerCreateDir(HgfsInputParam *input) // IN: Input params HGFS_ASSERT_INPUT(input); - if (HgfsUnpackCreateDirRequest(input->payload, input->payloadSize, - input->op, &info)) { - nameStatus = HgfsServerGetLocalNameInfo(info.cpName, info.cpNameSize, info.caseFlags, - &shareInfo, &utf8Name, &utf8NameLen); - if (HGFS_NAME_STATUS_COMPLETE == nameStatus) { - ASSERT(utf8Name); + if (!HgfsUnpackCreateDirRequest(input->payload, input->payloadSize, + input->op, &info)) { + status = HGFS_ERROR_PROTOCOL; + goto exit; + } - LOG(4, ("%s: making dir \"%s\"", __FUNCTION__, utf8Name)); - /* - * For read-only shares we must never attempt to create a directory. - * However the error code must be different depending on the existence - * of the file with the same name. - */ - if (shareInfo.writePermissions) { - status = HgfsPlatformCreateDir(&info, utf8Name); - if (HGFS_ERROR_SUCCESS == status) { - if (!HgfsPackCreateDirReply(input->packet, input->request, info.requestType, - &replyPayloadSize, input->session)) { - status = HGFS_ERROR_PROTOCOL; - } - } - } else { - status = HgfsPlatformFileExists(utf8Name); - if (HGFS_ERROR_SUCCESS == status) { - status = HGFS_ERROR_FILE_EXIST; - } else if (HGFS_ERROR_FILE_NOT_FOUND == status) { - status = HGFS_ERROR_ACCESS_DENIED; + nameStatus = HgfsServerGetLocalNameInfo(info.cpName, info.cpNameSize, info.caseFlags, + &shareInfo, &utf8Name, &utf8NameLen); + if (HGFS_NAME_STATUS_COMPLETE == nameStatus) { + ASSERT(utf8Name); + + /* + * Check if the guest is attempting to create a directory as a new + * share in our virtual root folder. If so, then it exists as we have found + * the share. This should error as a file exists whereas access denied is for + * new folders that do not collide. + * The virtual root folder is read-only for guests and new shares can only be + * created from the host. + */ + if (HgfsServerIsSharedFolderOnly(info.cpName, info.cpNameSize)) { + /* Disallow creating a subfolder matching the share in the virtual folder. */ + LOG(4, ("%s: Collision: cannot create a folder which is a share\n", __FUNCTION__)); + status = HGFS_ERROR_FILE_EXIST; + goto exit; + } + /* + * For read-only shares we must never attempt to create a directory. + * However the error code must be different depending on the existence + * of the file with the same name. + */ + if (shareInfo.writePermissions) { + status = HgfsPlatformCreateDir(&info, utf8Name); + if (HGFS_ERROR_SUCCESS == status) { + if (!HgfsPackCreateDirReply(input->packet, input->request, info.requestType, + &replyPayloadSize, input->session)) { + status = HGFS_ERROR_PROTOCOL; } } } else { - /* - * Check if the name does not exist - the share was not found. - * Then it could one of two things: the share was removed/disabled; - * or we could be in the root share itself and have a new name. - * To return the correct error, if we are in the root share, - * we must check the open mode too - creation of new files/folders - * should fail access denied, for anything else "not found" is acceptable. - */ - if (nameStatus == HGFS_NAME_STATUS_DOES_NOT_EXIST) { - if (HgfsServerIsSharedFolderOnly(info.cpName, - info.cpNameSize)) { - nameStatus = HGFS_NAME_STATUS_ACCESS_DENIED; - LOG(4, ("%s: New file creation in share root not allowed\n", __FUNCTION__)); - } else { - LOG(4, ("%s: Shared folder not found\n", __FUNCTION__)); - } + status = HgfsPlatformFileExists(utf8Name); + if (HGFS_ERROR_SUCCESS == status) { + status = HGFS_ERROR_FILE_EXIST; + } else if (HGFS_ERROR_FILE_NOT_FOUND == status) { + status = HGFS_ERROR_ACCESS_DENIED; + } + } + } else { + /* + * Check if the name does not exist - the share was not found. + * Then it could one of two things: the share was removed/disabled; + * or we could be in the root share itself and have a new name. + * To return the correct error, if we are in the root share, + * we must check the open mode too - creation of new files/folders + * should fail access denied, for anything else "not found" is acceptable. + */ + if (nameStatus == HGFS_NAME_STATUS_DOES_NOT_EXIST) { + if (HgfsServerIsSharedFolderOnly(info.cpName, + info.cpNameSize)) { + nameStatus = HGFS_NAME_STATUS_ACCESS_DENIED; + LOG(4, ("%s: disallow new folder creation in virtual share root.\n", + __FUNCTION__)); } else { - LOG(4, ("%s: Shared folder access error %u\n", __FUNCTION__, nameStatus)); + LOG(4, ("%s: Shared folder not found\n", __FUNCTION__)); } - - status = HgfsPlatformConvertFromNameStatus(nameStatus); + } else { + LOG(4, ("%s: Shared folder access error %u\n", __FUNCTION__, nameStatus)); } - } else { - status = HGFS_ERROR_PROTOCOL; + status = HgfsPlatformConvertFromNameStatus(nameStatus); } +exit: HgfsServerCompleteRequest(status, replyPayloadSize, input); free(utf8Name); }