Skip to content

Commit

Permalink
HPCC-30037 WIP
Browse files Browse the repository at this point in the history
Signed-off-by: wangkx <[email protected]>
  • Loading branch information
wangkx committed Sep 18, 2023
1 parent 76bb0c9 commit f64c34c
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 58 deletions.
7 changes: 7 additions & 0 deletions dali/base/dautils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ bool isHostInPlane(IPropertyTree *plane, const char *host, bool ipMatch)
Owned<IPropertyTree> planeGroup = getPlaneHostGroup(plane);
if (!planeGroup)
return false;
StringBuffer s;
toXML(planeGroup, s);
DBGLOG("####host(%s), planeGroup(%s)", isEmptyString(host) ? "" : host, s.str());

Owned<IPropertyTreeIterator> hostsIter = planeGroup->getElements("hosts");
SocketEndpoint hostEp;
if (ipMatch)
Expand Down Expand Up @@ -123,6 +127,9 @@ bool isPathInPlane(IPropertyTree *plane, const char *path)

bool validateDropZone(IPropertyTree * plane, const char * path, const char * host, bool ipMatch)
{
StringBuffer s;
toXML(plane, s);
DBGLOG("####host(%s), path(%s), plane(%s)", isEmptyString(host) ? "" : host, isEmptyString(path) ? "" : path, s.str());
if (host)
{
if (!isHostInPlane(plane, host, ipMatch))
Expand Down
2 changes: 1 addition & 1 deletion esp/services/ws_fs/ws_fsBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,11 +410,11 @@ int CFileSpraySoapBindingEx::downloadFile(IEspContext &context, CHttpRequest* re
if (!osStr.isEmpty() && (atoi(osStr.str())== OS_WINDOWS))
pathSep = '\\';
pathStr.replace(pathSep=='\\'?'/':'\\', pathSep);
addPathSepChar(pathStr);

validateDropZoneReq(context, dropZoneName, netAddressStr, pathStr, SecAccess_Read);

StringBuffer fullName;
addPathSepChar(pathStr);
fullName.appendf("%s%s", pathStr.str(), nameStr.str());

StringBuffer headerStr("attachment;");
Expand Down
34 changes: 12 additions & 22 deletions esp/services/ws_fs/ws_fsService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2036,7 +2036,7 @@ void CFileSprayEx::readAndCheckSpraySourceReq(IEspContext& context, MemoryBuffer
{
//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.
validateDZFileScopePermissions(context, sourcePlaneReq, path, sourceIPReq, SecAccess_Read);
validateDZFileScopePermsAndLegacyPhysicalPerms(context, sourcePlaneReq, path, sourceIPReq, SecAccess_Read);
}

if (!sourcePathReq.isEmpty())
Expand Down Expand Up @@ -2582,7 +2582,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);
validateDZFileScopePermissions(context, destPlane, destfileWithPath, destip, SecAccess_Write);
validateDZFileScopePermsAndLegacyPhysicalPerms(context, destPlane, destfileWithPath, destip, SecAccess_Write);
}
else
destfileWithPath.append(destfile).trim();
Expand Down Expand Up @@ -3023,23 +3023,17 @@ bool CFileSprayEx::onFileList(IEspContext &context, IEspFileListRequest &req, IE
}
else
{
StringBuffer dzName;
if (isEmptyString(dropZoneName))
dropZoneName = findDropZonePlaneName(netaddr, sPath, dzName);
if (!isEmptyString(dropZoneName))
Owned<IPropertyTree> dropZone = getDropZoneAndValidateHostAndPath(dropZoneName, netaddr, sPath);
if (dropZone)
{
SecAccessFlags permission = getDZPathScopePermsAndLegacyPhysicalPerms(context, dropZoneName, sPath, netaddr, SecAccess_Read);
if (permission < SecAccess_Read)
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone %s %s not allowed for user %s (permission:%s). Read Access Required.",
dropZoneName, sPath.str(), context.queryUserId(), getSecAccessFlagName(permission));
if (isEmptyString(dropZoneName))
dropZoneName= dropZone->queryProp("@name");
validateDZPathScopePermsAndLegacyPhysicalPerms(context, dropZoneName, sPath, netaddr, SecAccess_Read);
}

StringArray hosts;
if (isEmptyString(netaddr))
{
Owned<IPropertyTree> dropZone = getDropZonePlane(dropZoneName);
if (!dropZone)
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Unknown landing zone: %s", dropZoneName);
getPlaneHosts(hosts, dropZone);
if (!hosts.ordinality())
hosts.append("localhost");
Expand All @@ -3049,9 +3043,10 @@ bool CFileSprayEx::onFileList(IEspContext &context, IEspFileListRequest &req, IE

ForEachItemIn(i, hosts)
{
const char* host = hosts.item(i);
if (validateDropZoneHostAndPath(dropZoneName, host, sPath))
getPhysicalFiles(context, dropZoneName, host, sPath, fileNameMask, directoryOnly, files);
///const char* host = hosts.item(i);
///if (validateDropZoneHostAndPath(dropZoneName, host, sPath))
/// getPhysicalFiles(context, dropZoneName, host, sPath, fileNameMask, directoryOnly, files);
getPhysicalFiles(context, dropZoneName, hosts.item(i), sPath, fileNameMask, directoryOnly, files);
}
}

Expand Down Expand Up @@ -3621,12 +3616,7 @@ void CFileSprayEx::checkDropZoneFileScopeAccess(IEspContext &context, const char
if (isEmptyString(dropZoneName))
dropZoneName = findDropZonePlaneName(netAddress, dropZonePath, dzName);
if (!isEmptyString(dropZoneName))
{
SecAccessFlags permission = getDZPathScopePermsAndLegacyPhysicalPerms(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);
}
validateDZPathScopePermsAndLegacyPhysicalPerms(context, dropZoneName, dropZonePath, netAddress, accessReq);

RemoteFilename rfn;
SocketEndpoint ep(netAddress);
Expand Down
114 changes: 81 additions & 33 deletions esp/smc/SMCLib/TpCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,33 +148,33 @@ StringBuffer &findDropZonePlaneName(const char *host, const char *path, StringBu
return planeName;
}

extern TPWRAPPER_API bool validateDropZoneHostAndPath(const char* dropZoneName, const char* hostToCheck, const char* pathToCheck)
extern TPWRAPPER_API IPropertyTree* getDropZoneAndValidateHostAndPath(const char* dropZoneName, const char* host, const char* path)
{
//Both hostToCheck and pathToCheck should not be empty. For backward compatibility, the dropZoneName may be empty.
if (isEmptyString(hostToCheck))
throw makeStringException(ECLWATCH_INVALID_INPUT, "Host not defined.");
if (isEmptyString(pathToCheck))
throw makeStringException(ECLWATCH_INVALID_INPUT, "Path not defined.");
if (isContainerized() && streq("localhost", hostToCheck))
hostToCheck = nullptr; // "localhost" is a placeholder for mounted dropzones that have no hosts.
if (isEmptyString(hostToCheck) && isEmptyString(dropZoneName))
throw makeStringException(ECLWATCH_INVALID_INPUT, "No dropzone or host provided.");
StringBuffer pathToCheck(path);
addPathSepChar(pathToCheck);

if (containsRelPaths(pathToCheck)) //Detect a path like: /home/lexis/runtime/var/lib/HPCCSystems/mydropzone/../../../
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Invalid path %s", pathToCheck);
const char* hostToCheck = nullptr;
if (isContainerized() && streq("localhost", host))
hostToCheck = nullptr; // "localhost" is a placeholder for mounted dropzones that have no hosts.
else
hostToCheck = host;

StringBuffer path(pathToCheck);
addPathSepChar(path);
Owned<IPropertyTree> dropZone;
if (isEmptyString(dropZoneName))
{
Owned<IPropertyTree> plane = findDropZonePlane(path, hostToCheck, isIPAddress(hostToCheck), false);
return nullptr != plane;
dropZone.setown(findDropZonePlane(pathToCheck, hostToCheck, isIPAddress(hostToCheck), false));
if (!dropZone)
throwOrLogDropZoneLookUpError(ECLWATCH_INVALID_INPUT, "DropZone not found for host '%s' path '%s'.", host, path);
}

Owned<IPropertyTree> plane = getDropZonePlane(dropZoneName);
if (nullptr == plane)
return false;
return validateDropZone(plane, path, hostToCheck, isIPAddress(hostToCheck));
else
{
dropZone.setown(getDropZonePlane(dropZoneName));
if (!dropZone)
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "DropZone '%s' not found.", dropZoneName);
if (!validateDropZone(dropZone, pathToCheck, hostToCheck, isIPAddress(hostToCheck)))
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "The host '%s' or path '%s' is not valid for dropzone %s.", host, path, dropZoneName);
}
return dropZone.getClear();
}

static SecAccessFlags getDropZoneScopePermissions(IEspContext& context, const IPropertyTree* dropZone, const char* dropZonePath)
Expand Down Expand Up @@ -207,7 +207,7 @@ static SecAccessFlags getDZPathScopePermissions(IEspContext& context, const char
dropZone.setown(findDropZonePlane(dropZonePath, dropZoneHost, true, false));
if (!dropZone)
{
throwOrLogDropZoneLookUpError(ECLWATCH_INVALID_INPUT, "getDZPathScopePermissions(): DropZone %s not found for host '%s' path '%s'.",
throwOrLogDropZoneLookUpError(ECLWATCH_INVALID_INPUT, "getDZPathScopePermissions(): DropZone not found for host '%s' path '%s'.",
isEmptyString(dropZoneHost) ? "unspecified" : dropZoneHost, isEmptyString(dropZonePath) ? "unspecified" : dropZonePath);
return SecAccess_Full;
}
Expand Down Expand Up @@ -278,22 +278,18 @@ extern TPWRAPPER_API SecAccessFlags getDZPathScopePermsAndLegacyPhysicalPerms(IE
return permission;
}

//Validate dropzone host and file path. Also validate dropzone file path permission. Because the file
//path does not contain a file name, the getDZPathScopePermsAndLegacyPhysicalPerms() is called to
//validate the permission.
extern TPWRAPPER_API void validateDropZoneReq(IEspContext& ctx, const char* dropZoneName, const char* host, const char* filePath, SecAccessFlags permissionReq)
extern TPWRAPPER_API void validateDZPathScopePermsAndLegacyPhysicalPerms(IEspContext &context, const char *dropZoneName, const char *path,
const char *host, SecAccessFlags permissionReq)
{
if (!validateDropZoneHostAndPath(dropZoneName, host, filePath)) //The filePath should be the absolute path for the dropzone.
throw makeStringException(ECLWATCH_INVALID_INPUT, "Invalid DropZoneName, NetAddress or Path.");

SecAccessFlags permission = getDZPathScopePermsAndLegacyPhysicalPerms(ctx, dropZoneName, filePath, host, permissionReq);
SecAccessFlags permission = getDZPathScopePermsAndLegacyPhysicalPerms(context, dropZoneName, path, host, permissionReq);
if (permission < permissionReq)
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone %s %s %s not allowed for user %s (permission:%s). %s permission required.",
dropZoneName, host, filePath, ctx.queryUserId(), getSecAccessFlagName(permission), getSecAccessFlagName(permissionReq));
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Access DropZone %s %s not allowed for user %s (permission:%s). Read Access Required.",
dropZoneName, path, context.queryUserId(), getSecAccessFlagName(permission));
}

//Validate dropzone file permission when the file path contains a file name.
extern TPWRAPPER_API void validateDZFileScopePermissions(IEspContext& context, const char* dropZoneName, const char* path, const char* host, SecAccessFlags permissionReq)
extern TPWRAPPER_API void validateDZFileScopePermsAndLegacyPhysicalPerms(IEspContext& context, const char* dropZoneName, const char* path,
const char* host, SecAccessFlags permissionReq)
{
SecAccessFlags permission = getDZFileScopePermissions(context, dropZoneName, path, host);
if ((permission < permissionReq) && getGlobalConfigSP()->getPropBool("expert/@failOverToLegacyPhysicalPerms", !isContainerized()))
Expand All @@ -303,6 +299,58 @@ extern TPWRAPPER_API void validateDZFileScopePermissions(IEspContext& context, c
dropZoneName, path, context.queryUserId(), getSecAccessFlagName(permission), getSecAccessFlagName(permissionReq));
}

//TODO: it would be worth expanding on the comments for the functions now in TpCommon,
//as they're quite similar and it is not obvious when one would be used over the other sometimes.

//Validate dropzone host and file path. Also validate dropzone file path permission. Because the file
//path does not contain a file name, the getDZPathScopePermsAndLegacyPhysicalPerms() is called to
//validate the permission.
extern TPWRAPPER_API void validateDropZoneReq(IEspContext& ctx, const char* dropZoneName, const char* host, const char* filePath, SecAccessFlags permissionReq)
{
// if (!validateDropZoneHostAndPath(dropZoneName, host, filePath)) //The filePath should be the absolute path for the dropzone.
// throw makeStringException(ECLWATCH_INVALID_INPUT, "Invalid DropZoneName, NetAddress or Path.");

if (isEmptyString(host) || isEmptyString(filePath)) //The host and filePath must be specified for accessing a DropZone file.
throw makeStringException(ECLWATCH_INVALID_INPUT, "Host or file path not defined.");

if (containsRelPaths(filePath)) //Detect a path like: /home/lexis/runtime/var/lib/HPCCSystems/mydropzone/../../../
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Invalid path %s", filePath);

//If the dropZoneName is empty, try to find it using the host and filePath.
//If not, validate the dropZoneName, host, and filePath.
dropZoneName = "";
Owned<IPropertyTree> dropZone = getDropZoneAndValidateHostAndPath(dropZoneName, host, filePath);
if (dropZone)
dropZoneName= dropZone->queryProp("@name");
/*StringBuffer path(filePath);
addPathSepChar(path);
const char* hostToCheck = nullptr;
if (isContainerized() && streq("localhost", path))
hostToCheck = nullptr; // "localhost" is a placeholder for mounted dropzones that have no hosts.
else
hostToCheck = host;
if (isEmptyString(dropZoneName))
{
Owned<IPropertyTree> dropZone = findDropZonePlane(path, hostToCheck, isIPAddress(hostToCheck), false);
if (dropZone)
dropZoneName= dropZone->queryProp("@name");
else
throwOrLogDropZoneLookUpError(ECLWATCH_INVALID_INPUT, "DropZone not found for host '%s' path '%s'.", host, filePath);
}
else
{ //If the dropZoneName is specified, valid it first. And check whether the host and filePath are valid for the DropZone.
Owned<IPropertyTree> dropZone = getDropZonePlane(dropZoneName);
if (!dropZone)
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "DropZone '%s' not found.", dropZoneName);
if (!validateDropZone(dropZone, path, hostToCheck, isIPAddress(hostToCheck)))
throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "The host '%s' or path '%s' is not valid for dropzone %s.", host, filePath, dropZoneName);
}*/

//If the dropZoneName is not empty, validate the permissions.
if (!isEmptyString(dropZoneName))
validateDZPathScopePermsAndLegacyPhysicalPerms(ctx, dropZoneName, filePath, host, permissionReq);
}

//Validate dropzone file path and permission, Also set the dlfn.
extern TPWRAPPER_API void validateDropZoneAccess(IEspContext& context, const char* targetDZNameOrHost, const char* hostReq, SecAccessFlags permissionReq,
const char* fileNameWithRelPath, CDfsLogicalFileName& dlfn)
Expand Down
6 changes: 4 additions & 2 deletions esp/smc/SMCLib/TpWrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,14 @@ extern TPWRAPPER_API bool validateDataPlaneName(const char *remoteDali, const ch
extern TPWRAPPER_API bool matchNetAddressRequest(const char* netAddressReg, bool ipReq, IConstTpMachine& tpMachine);

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 IPropertyTree* getDropZoneAndValidateHostAndPath(const char* dropZoneName, const char* host, const char* path);
extern TPWRAPPER_API void validateDropZoneAccess(IEspContext& context, const char* targetDZNameOrHost, const char* hostReq, SecAccessFlags permissionReq,
const char* fileNameWithRelPath, CDfsLogicalFileName& dlfn);
extern TPWRAPPER_API SecAccessFlags getDZPathScopePermsAndLegacyPhysicalPerms(IEspContext &context, const char *dropZoneName, const char *path,
const char *host, SecAccessFlags permissionReq);
extern TPWRAPPER_API void validateDZPathScopePermsAndLegacyPhysicalPerms(IEspContext &context, const char *dropZoneName, const char *path,
const char *host, SecAccessFlags permissionReq);
extern TPWRAPPER_API void validateDropZoneReq(IEspContext& ctx, const char* dropZoneName, const char* host, const char* path, SecAccessFlags permissionReq);
extern TPWRAPPER_API void validateDZFileScopePermissions(IEspContext& context, const char* dropZoneName, const char* path, const char* host, SecAccessFlags permissionReq);
extern TPWRAPPER_API void validateDZFileScopePermsAndLegacyPhysicalPerms(IEspContext& context, const char* dropZoneName, const char* path, const char* host, SecAccessFlags permissionReq);

#endif //_ESPWIZ_TpWrapper_HPP__

0 comments on commit f64c34c

Please sign in to comment.