From 8f42dbda00c349172b8fc3bdb4bba2aeacfc5034 Mon Sep 17 00:00:00 2001 From: wangkx Date: Fri, 4 Aug 2023 11:50:18 -0400 Subject: [PATCH] HPCC-30037 Check legacy DZ physical permission in ESP services 1. In the getDZPathScopePermissions(), add code to check legacy physical permission. 2. Pass the permission requirement to getDZPathScopePermissions(). Check legacy physical permission when Plane Scope permission does not meet the requirement. 3. Pass the host to getDZPathScopePermissions() in order to check legacy physical permission. 4. When DZ name is not found, the getDZPathScopePermissions() is called to check legacy physical permission. Signed-off-by: wangkx --- esp/services/ws_fs/ws_fsBinding.cpp | 4 +-- esp/services/ws_fs/ws_fsService.cpp | 52 ++++++++++++--------------- esp/smc/SMCLib/TpCommon.cpp | 56 +++++++++++++++++++++++++---- esp/smc/SMCLib/TpWrapper.hpp | 4 +-- 4 files changed, 76 insertions(+), 40 deletions(-) diff --git a/esp/services/ws_fs/ws_fsBinding.cpp b/esp/services/ws_fs/ws_fsBinding.cpp index 353c591f245..daf99c0090b 100644 --- a/esp/services/ws_fs/ws_fsBinding.cpp +++ b/esp/services/ws_fs/ws_fsBinding.cpp @@ -414,7 +414,7 @@ int CFileSpraySoapBindingEx::downloadFile(IEspContext &context, CHttpRequest* re if (!validateDropZoneHostAndPath(dropZoneName, netAddressStr, pathStr)) //The pathStr should be the absolute path for the dropzone. throw makeStringException(ECLWATCH_INVALID_INPUT, "Invalid DropZoneName, NetAddress or Path."); - SecAccessFlags permission = getDZPathScopePermissions(context, dropZoneName, pathStr, netAddressStr); + SecAccessFlags permission = getDZPathScopePermissions(context, dropZoneName, pathStr, netAddressStr, SecAccess_Read); if (permission < SecAccess_Read) throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s %s not allowed for user %s (permission:%s). Read Access Required.", dropZoneName.str(), netAddressStr.str(), pathStr.str(), context.queryUserId(), getSecAccessFlagName(permission)); @@ -465,7 +465,7 @@ int CFileSpraySoapBindingEx::onStartUpload(IEspContext& ctx, CHttpRequest* reque request->getParameter("DropZoneName", dropZoneName); if (!validateDropZoneHostAndPath(dropZoneName, netAddress, path)) //The path should be the absolute path for the dropzone. throw makeStringException(ECLWATCH_INVALID_INPUT, "Invalid DropZoneName, NetAddress or Path."); - SecAccessFlags permission = getDZPathScopePermissions(ctx, dropZoneName, path, netAddress); + SecAccessFlags permission = getDZPathScopePermissions(ctx, dropZoneName, path, netAddress, SecAccess_Full); if (permission < SecAccess_Full) throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s %s not allowed for user %s (permission:%s). Full Access Required.", dropZoneName.str(), netAddress.str(), path.str(), ctx.queryUserId(), getSecAccessFlagName(permission)); diff --git a/esp/services/ws_fs/ws_fsService.cpp b/esp/services/ws_fs/ws_fsService.cpp index b4ffedc9bfa..845036c3960 100644 --- a/esp/services/ws_fs/ws_fsService.cpp +++ b/esp/services/ws_fs/ws_fsService.cpp @@ -2013,15 +2013,12 @@ void CFileSprayEx::readAndCheckSpraySourceReq(IEspContext& context, MemoryBuffer } } - if (dropZone) - { - //Based on the tests, the dfuserver only supports the wildcard inside the file name, like '/path/f*'. - //The dfuserver throws an error if the wildcard is inside the path, like /p*ath/file. - SecAccessFlags permission = getDZFileScopePermissions(context, sourcePlaneReq, path, nullptr); - if (permission < SecAccess_Read) - throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s not allowed for user %s (permission:%s). Read Access Required.", - sourcePlaneReq.str(), path, context.queryUserId(), getSecAccessFlagName(permission)); - } + //Based on the tests, the dfuserver only supports the wildcard inside the file name, like '/path/f*'. + //The dfuserver throws an error if the wildcard is inside the path, like /p*ath/file. + SecAccessFlags permission = getDZFileScopePermissions(context, sourcePlaneReq, path, sourceIPReq, SecAccess_Read); + if (permission < SecAccess_Read) + throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s not allowed for user %s (permission:%s). Read Access Required.", + sourcePlaneReq.str(), path, context.queryUserId(), getSecAccessFlagName(permission)); if (!sourcePathReq.isEmpty()) sourcePathReq.append(","); @@ -2566,7 +2563,7 @@ bool CFileSprayEx::onDespray(IEspContext &context, IEspDespray &req, IEspDespray if (!isEmptyString(destPlane)) // must be true, unless bare-metal and isDropZoneRestrictionEnabled()==false getDropZoneInfoByDestPlane(version, destPlane, destfile, destfileWithPath, umask, destip); - SecAccessFlags permission = getDZFileScopePermissions(context, destPlane, destfileWithPath, destip); + SecAccessFlags permission = getDZFileScopePermissions(context, destPlane, destfileWithPath, destip, SecAccess_Write); if (permission < SecAccess_Write) throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s not allowed for user %s (permission:%s). Write Access Required.", isEmptyString(destPlane) ? destip : destPlane, destfileWithPath.str(), context.queryUserId(), getSecAccessFlagName(permission)); @@ -3010,13 +3007,11 @@ bool CFileSprayEx::onFileList(IEspContext &context, IEspFileListRequest &req, IE StringBuffer dzName; if (isEmptyString(dropZoneName)) dropZoneName = findDropZonePlaneName(netaddr, sPath, dzName); - if (!isEmptyString(dropZoneName)) - { - SecAccessFlags permission = getDZPathScopePermissions(context, dropZoneName, sPath, nullptr); - if (permission < SecAccess_Read) - throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s not allowed for user %s (permission:%s). Read Access Required.", - dropZoneName, sPath.str(), context.queryUserId(), getSecAccessFlagName(permission)); - } + + SecAccessFlags permission = getDZPathScopePermissions(context, dropZoneName, sPath, netaddr, SecAccess_Read); + if (permission < SecAccess_Read) + throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s not allowed for user %s (permission:%s). Read Access Required.", + dropZoneName, sPath.str(), context.queryUserId(), getSecAccessFlagName(permission)); StringArray hosts; if (isEmptyString(netaddr)) @@ -3123,7 +3118,7 @@ void CFileSprayEx::addPhysicalFile(IEspContext& context, IDirectoryIterator* di, bool CFileSprayEx::searchDropZoneFiles(IEspContext& context, const char* dropZoneName, const char* server, const char* dir, const char* relDir, const char* nameFilter, IArrayOf& files, unsigned& filesFound) { - if (getDZPathScopePermissions(context, dropZoneName, dir, server) < SecAccess_Read) + if (getDZPathScopePermissions(context, dropZoneName, dir, server, SecAccess_Read) < SecAccess_Read) return false; RemoteFilename rfn; @@ -3341,10 +3336,10 @@ void CFileSprayEx::getPhysicalFiles(IEspContext &context, const char *dropZoneNa if (!di->isDir() && (directoryOnly || (!isEmptyString(fileNameMask) && !WildMatch(fileName.str(), fileNameMask, true)))) continue; - if (dropZoneName && di->isDir()) + if (di->isDir()) { VStringBuffer fullPath("%s%s", path, fileName.str()); - if (getDZPathScopePermissions(context, dropZoneName, fullPath, nullptr) < SecAccess_Read) + if (getDZPathScopePermissions(context, dropZoneName, fullPath, host, SecAccess_Read) < SecAccess_Read) continue; } @@ -3455,7 +3450,7 @@ bool CFileSprayEx::onDropZoneFiles(IEspContext &context, IEspDropZoneFilesReques StringBuffer planeName; if (isEmptyString(dzName)) dzName = findDropZonePlaneName(netAddress, directoryStr, planeName); - if (!isEmptyString(dzName) && getDZPathScopePermissions(context, dzName, directoryStr, nullptr) < SecAccess_Read) + if (getDZPathScopePermissions(context, dzName, directoryStr, netAddress, SecAccess_Read) < SecAccess_Read) return false; bool directoryOnly = req.getDirectoryOnly(); @@ -3604,13 +3599,11 @@ void CFileSprayEx::checkDropZoneFileScopeAccess(IEspContext &context, const char StringBuffer dzName; if (isEmptyString(dropZoneName)) dropZoneName = findDropZonePlaneName(netAddress, dropZonePath, dzName); - if (!isEmptyString(dropZoneName)) - { - SecAccessFlags permission = getDZPathScopePermissions(context, dropZoneName, dropZonePath, nullptr); - if (permission < accessReq) - throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s not allowed for user %s (permission:%s). %s Permission Required.", - dropZoneName, dropZonePath, context.queryUserId(), getSecAccessFlagName(permission), accessReqName); - } + + SecAccessFlags permission = getDZPathScopePermissions(context, dropZoneName, dropZonePath, netAddress, accessReq); + if (permission < accessReq) + throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s not allowed for user %s (permission:%s). %s Permission Required.", + dropZoneName, dropZonePath, context.queryUserId(), getSecAccessFlagName(permission), accessReqName); RemoteFilename rfn; SocketEndpoint ep(netAddress); @@ -3651,8 +3644,7 @@ void CFileSprayEx::checkDropZoneFileScopeAccess(IEspContext &context, const char StringBuffer fullPath(dropZonePath); addPathSepChar(fullPath).append(pathToCheck); - //If the dropzone name is not found, the DZPathScopePermissions cannot be validated. - SecAccessFlags permission = isEmptyString(dropZoneName) ? accessReq : getDZPathScopePermissions(context, dropZoneName, fullPath, nullptr); + SecAccessFlags permission = getDZPathScopePermissions(context, dropZoneName, fullPath, netAddress, accessReq); if (permission < accessReq) { uniquePath.setValue(pathToCheck.str(), false); //add a path denied diff --git a/esp/smc/SMCLib/TpCommon.cpp b/esp/smc/SMCLib/TpCommon.cpp index 195c2f6e909..f8b0e3eed07 100644 --- a/esp/smc/SMCLib/TpCommon.cpp +++ b/esp/smc/SMCLib/TpCommon.cpp @@ -196,8 +196,37 @@ static SecAccessFlags getDropZoneScopePermissions(IEspContext& context, const IP return queryDistributedFileDirectory().getDropZoneScopePermissions(dropZone->queryProp("@name"), dropZonePath, userDesc); } -extern TPWRAPPER_API SecAccessFlags getDZPathScopePermissions(IEspContext& context, const char* dropZoneName, const char* dropZonePath, const char* dropZoneHost) +static SecAccessFlags verifyLegacyPhysicalPerms(IEspContext& context, const char* dropZoneName, const char* dropZoneHost, const char* dropZoneScope) { + Owned userDesc = createUserDescriptor(); + userDesc->set(context.queryUserId(), context.queryPassword(), context.querySignature()); + + StringBuffer host; + if (isEmptyString(dropZoneHost)) + { + Owned plane = getDropZonePlane(dropZoneName); + if (getPlaneHost(host, plane, 0)) + dropZoneHost = host.str(); + else + dropZoneHost = "localhost"; + } + + //The setExternal() requests the path with a file name. The file name is not used by the getDLFNPermissions(). + //So, the dropZoneScope + a faked file name is passed to the setExternal(). + StringBuffer pathWithFakedFileName(dropZoneScope); + addPathSepChar(pathWithFakedFileName).append("any"); + + CDfsLogicalFileName dlfn; + SocketEndpoint ep(dropZoneHost); + dlfn.setExternal(ep, pathWithFakedFileName); + return queryDistributedFileDirectory().getDLFNPermissions(dlfn, userDesc); +} + +extern TPWRAPPER_API SecAccessFlags getDZPathScopePermissions(IEspContext& context, const char* dropZoneName, const char* dropZonePath, + const char* dropZoneHost, SecAccessFlags permissionReq) +{ + if (isEmptyString(dropZoneName) && isEmptyString(dropZoneHost)) + throw makeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "getDZPathScopePermissions(): DropZone name or host must be specified."); if (isEmptyString(dropZonePath)) throw makeStringException(ECLWATCH_INVALID_CLUSTER_NAME, "getDZPathScopePermissions(): DropZone path must be specified."); @@ -208,7 +237,9 @@ extern TPWRAPPER_API SecAccessFlags getDZPathScopePermissions(IEspContext& conte if (!dropZone) { throwOrLogDropZoneLookUpError(ECLWATCH_INVALID_INPUT, "getDZPathScopePermissions(): DropZone %s not found.", dropZoneName); - return SecAccess_Full; + if (!getGlobalConfigSP()->getPropBool("expert/@failOverToLegacyPhysicalPerms", !isContainerized())) + return SecAccess_Full; + return verifyLegacyPhysicalPerms(context, dropZoneName, dropZoneHost, dropZonePath); } } else @@ -218,16 +249,29 @@ extern TPWRAPPER_API SecAccessFlags getDZPathScopePermissions(IEspContext& conte throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "getDZPathScopePermissions(): DropZone %s not found.", dropZoneName); } - return getDropZoneScopePermissions(context, dropZone, dropZonePath); + SecAccessFlags permission = getDropZoneScopePermissions(context, dropZone, dropZonePath); + if ((permission < permissionReq) && getGlobalConfigSP()->getPropBool("expert/@failOverToLegacyPhysicalPerms", !isContainerized())) + { + StringBuffer fileNameWithAbsPath; + if (!isAbsolutePath(dropZonePath)) + { //Only happens when this is called by the validateDropZoneAccess(). In the validateDropZoneAccess(), + //the dropZone is always available. Now, convert the dropZonePath to absolute path. + addPathSepChar(fileNameWithAbsPath.set(dropZone->queryProp("@prefix"))).append(dropZonePath); + dropZonePath = fileNameWithAbsPath.str(); + } + permission = verifyLegacyPhysicalPerms(context, dropZoneName, dropZoneHost, dropZonePath); + } + + return permission; } extern TPWRAPPER_API SecAccessFlags getDZFileScopePermissions(IEspContext& context, const char* dropZoneName, const char* dropZonePath, - const char* dropZoneHost) + const char* dropZoneHost, SecAccessFlags permissionReq) { StringBuffer dir, fileName; splitFilename(dropZonePath, &dir, &dir, nullptr, nullptr); dropZonePath = dir.str(); - return getDZPathScopePermissions(context, dropZoneName, dropZonePath, dropZoneHost); + return getDZPathScopePermissions(context, dropZoneName, dropZonePath, dropZoneHost, permissionReq); } extern TPWRAPPER_API void validateDropZoneAccess(IEspContext& context, const char* targetDZNameOrHost, const char* hostReq, SecAccessFlags permissionReq, @@ -245,7 +289,7 @@ extern TPWRAPPER_API void validateDropZoneAccess(IEspContext& context, const cha throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Host %s is not valid DropZone plane %s", hostReq, targetDZNameOrHost); } const char *dropZoneName = dropZone->queryProp("@name"); - SecAccessFlags permission = getDZFileScopePermissions(context, dropZoneName, fileNameWithRelPath, hostReq); + SecAccessFlags permission = getDZFileScopePermissions(context, dropZoneName, fileNameWithRelPath, hostReq, permissionReq); if (permission < permissionReq) throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone Scope %s %s not allowed for user %s (permission:%s). %s Access Required.", dropZoneName, fileNameWithRelPath, context.queryUserId(), getSecAccessFlagName(permission), getSecAccessFlagName(permissionReq)); diff --git a/esp/smc/SMCLib/TpWrapper.hpp b/esp/smc/SMCLib/TpWrapper.hpp index bbc89ee91b0..589fcb41c17 100644 --- a/esp/smc/SMCLib/TpWrapper.hpp +++ b/esp/smc/SMCLib/TpWrapper.hpp @@ -241,8 +241,8 @@ extern TPWRAPPER_API bool matchNetAddressRequest(const char* netAddressReg, bool extern TPWRAPPER_API StringBuffer &findDropZonePlaneName(const char* host, const char* path, StringBuffer& planeName); extern TPWRAPPER_API bool validateDropZoneHostAndPath(const char* dropZoneName, const char* hostToCheck, const char* pathToCheck); -extern TPWRAPPER_API SecAccessFlags getDZPathScopePermissions(IEspContext& context, const char* dropZoneName, const char* dropZonePath, const char* dropZoneHost); -extern TPWRAPPER_API SecAccessFlags getDZFileScopePermissions(IEspContext& context, const char* dropZoneName, const char* dropZonePath, const char* dropZoneHost); +extern TPWRAPPER_API SecAccessFlags getDZPathScopePermissions(IEspContext& context, const char* dropZoneName, const char* dropZonePath, const char* dropZoneHost, SecAccessFlags permissionReq); +extern TPWRAPPER_API SecAccessFlags getDZFileScopePermissions(IEspContext& context, const char* dropZoneName, const char* dropZonePath, const char* dropZoneHost, SecAccessFlags permissionReq); extern TPWRAPPER_API void validateDropZoneAccess(IEspContext& context, const char* targetDZNameOrHost, const char* hostReq, SecAccessFlags permissionReq, const char* fileNameWithRelPath, CDfsLogicalFileName& dlfn);