Skip to content

Commit

Permalink
WMS client (cascaded WMS): restrict the list of GDAL drivers used to …
Browse files Browse the repository at this point in the history
…read the GetMap response; add a 'wms_allowed_gdal_drivers' LAYER.METADATA option that takes a comma separated list of GDAL driver names (#6940)
  • Loading branch information
rouault committed Oct 8, 2023
1 parent 4e7b0df commit f20110e
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 50 deletions.
1 change: 1 addition & 0 deletions msautotest/wxs/wms_client_111.map
Expand Up @@ -55,6 +55,7 @@ MAP
"wms_server_version" "1.1.1"
"wms_format" "image/png"
"wms_enable_request" "*"
"wms_allowed_gdal_drivers" "PNG" # would be set automatically given wms_format=image/png
END
END
END
35 changes: 34 additions & 1 deletion src/mapraster.c
Expand Up @@ -639,10 +639,43 @@ void *msDrawRasterLayerLowOpenDataset(mapObj *map, layerObj *layer,
if (!layer->tileindex) {
char **connectionoptions =
msGetStringListFromHashTable(&(layer->connectionoptions));
char **papszAllowedDrivers = NULL;
// ALLOWED_GDAL_DRIVERS typically set by msDrawWMSLayerLow()
const char *pszAllowedDrivers =
msLayerGetProcessingKey(layer, "ALLOWED_GDAL_DRIVERS");
if (pszAllowedDrivers && !EQUAL(pszAllowedDrivers, "*"))
papszAllowedDrivers = CSLTokenizeString2(pszAllowedDrivers, ",", 0);
GDALDatasetH hDS =
GDALOpenEx(*p_decrypted_path, GDAL_OF_RASTER | GDAL_OF_SHARED, NULL,
GDALOpenEx(*p_decrypted_path, GDAL_OF_RASTER | GDAL_OF_SHARED,
(const char *const *)papszAllowedDrivers,
(const char *const *)connectionoptions, NULL);
CSLDestroy(papszAllowedDrivers);
CSLDestroy(connectionoptions);

// Give a hint about which GDAL driver should be enabled, but only in
// debug mode.
if (layer->debug && hDS == NULL && pszAllowedDrivers &&
!EQUAL(pszAllowedDrivers, "*")) {
GDALDriverH hDrv = GDALIdentifyDriver(*p_decrypted_path, NULL);
if (hDrv) {
const char *pszDrvName = GDALGetDescription(hDrv);
bool bFound = false;
for (int i = 0; papszAllowedDrivers && papszAllowedDrivers[i]; ++i) {
if (EQUAL(papszAllowedDrivers[i], pszDrvName)) {
bFound = true;
break;
}
}
if (!bFound) {
msSetError(MS_IMGERR,
"Failed to draw layer named '%s'. The image returned "
"is recognized by GDAL driver %s, but it is not allowed "
"currently.",
"msDrawRasterLayerLowOpenDataset()", layer->name,
pszDrvName);
}
}
}
return hDS;
} else {
return GDALOpenShared(*p_decrypted_path, GA_ReadOnly);
Expand Down
138 changes: 89 additions & 49 deletions src/mapwmslayer.c
Expand Up @@ -187,6 +187,71 @@ static char *msBuildURLFromWMSParams(wmsParamsObj *wmsparams) {
}

#ifdef USE_WMS_LYR

static bool IsPNGFormat(const char *pszValue) {
return EQUAL(pszValue, "PNG") || EQUAL(pszValue, "image/png");
}

static bool IsJPEGFormat(const char *pszValue) {
return EQUAL(pszValue, "JPEG") || EQUAL(pszValue, "image/jpeg");
}

/**********************************************************************
* msWMSLayerGetFormat()
*
* Returns the value of the "FORMAT" parameter (to be freed with msFree())
* or NULL in case of error
**********************************************************************/
static char *msWMSLayerGetFormat(layerObj *lp) {
const char *pszFormat = msOWSLookupMetadata(&(lp->metadata), "MO", "format");
if (pszFormat)
return msStrdup(pszFormat);

const char *pszFormatList =
msOWSLookupMetadata(&(lp->metadata), "MO", "formatlist");
if (pszFormatList == NULL) {
msSetError(MS_WMSCONNERR,
"At least wms_format or wms_formatlist is required for "
"layer %s. "
"Please either provide a valid CONNECTION URL, or provide "
"those values in the layer's metadata.\n",
"msBuildWMSLayerURLBase()", lp->name);
return NULL;
}

/* Look for the first format in list that matches */
int i, n;
char **papszTok = msStringSplit(pszFormatList, ',', &n);

for (i = 0; pszFormat == NULL && i < n; i++) {
if (0
#if defined USE_PNG
|| IsPNGFormat(papszTok[i])
#endif
#if defined USE_JPEG
|| IsJPEGFormat(papszTok[i])
#endif
) {
pszFormat = papszTok[i];
}
}

if (pszFormat) {
char *pszRet = msStrdup(pszFormat);
msFreeCharArray(papszTok, n);
return pszRet;
} else {
msSetError(MS_WMSCONNERR,
"Could not find a format that matches supported input "
"formats in wms_formatlist metdata in layer %s. "
"Please either provide a valid CONNECTION URL, or "
"provide the required layer metadata.\n",
"msBuildWMSLayerURLBase()", lp->name);
msFreeCharArray(papszTok, n);
return NULL;
}
}

/**********************************************************************
* msBuildWMSLayerURLBase()
*
Expand All @@ -204,8 +269,8 @@ static char *msBuildURLFromWMSParams(wmsParamsObj *wmsparams) {
**********************************************************************/
static int msBuildWMSLayerURLBase(mapObj *map, layerObj *lp,
wmsParamsObj *psWMSParams, int nRequestType) {
const char *pszOnlineResource, *pszVersion, *pszName, *pszFormat;
const char *pszFormatList, *pszStyle, /* *pszStyleList,*/ *pszTime;
const char *pszOnlineResource, *pszVersion, *pszName;
const char *pszStyle, /* *pszStyleList,*/ *pszTime;
const char *pszBgColor, *pszTransparent;
const char *pszSLD = NULL, *pszStyleSLDBody = NULL, *pszVersionKeyword = NULL;
const char *pszSLDBody = NULL, *pszSLDURL = NULL;
Expand All @@ -220,8 +285,6 @@ static int msBuildWMSLayerURLBase(mapObj *map, layerObj *lp,

pszVersion = msOWSLookupMetadata(&(lp->metadata), "MO", "server_version");
pszName = msOWSLookupMetadata(&(lp->metadata), "MO", "name");
pszFormat = msOWSLookupMetadata(&(lp->metadata), "MO", "format");
pszFormatList = msOWSLookupMetadata(&(lp->metadata), "MO", "formatlist");
pszStyle = msOWSLookupMetadata(&(lp->metadata), "MO", "style");
/*pszStyleList = msOWSLookupMetadata(&(lp->metadata), "MO",
* "stylelist");*/
Expand Down Expand Up @@ -258,53 +321,13 @@ static int msBuildWMSLayerURLBase(mapObj *map, layerObj *lp,
msSetWMSParamString(psWMSParams, "SERVICE", "WMS", MS_FALSE, nVersion);
msSetWMSParamString(psWMSParams, "LAYERS", pszName, MS_TRUE, nVersion);

if (pszFormat == NULL && pszFormatList == NULL) {
msSetError(MS_WMSCONNERR,
"At least wms_format or wms_formatlist is required for "
"layer %s. "
"Please either provide a valid CONNECTION URL, or provide "
"those values in the layer's metadata.\n",
"msBuildWMSLayerURLBase()", lp->name);
char *pszFormat = msWMSLayerGetFormat(lp);
if (!pszFormat) {
return MS_FAILURE;
}

if (pszFormat != NULL) {
msSetWMSParamString(psWMSParams, "FORMAT", pszFormat, MS_TRUE, nVersion);
} else {
/* Look for the first format in list that matches */
char **papszTok;
int i, n;
papszTok = msStringSplit(pszFormatList, ',', &n);

for (i = 0; pszFormat == NULL && i < n; i++) {
if (0
#if defined USE_PNG
|| strcasecmp(papszTok[i], "PNG") ||
strcasecmp(papszTok[i], "image/png")
#endif
#if defined USE_JPEG
|| strcasecmp(papszTok[i], "JPEG") ||
strcasecmp(papszTok[i], "image/jpeg")
#endif
) {
pszFormat = papszTok[i];
}
}

if (pszFormat) {
msSetWMSParamString(psWMSParams, "FORMAT", pszFormat, MS_TRUE, nVersion);
msFreeCharArray(papszTok, n);
} else {
msSetError(MS_WMSCONNERR,
"Could not find a format that matches supported input "
"formats in wms_formatlist metdata in layer %s. "
"Please either provide a valid CONNECTION URL, or "
"provide the required layer metadata.\n",
"msBuildWMSLayerURLBase()", lp->name);
msFreeCharArray(papszTok, n);
return MS_FAILURE;
}
}
msSetWMSParamString(psWMSParams, "FORMAT", pszFormat, MS_TRUE, nVersion);
msFree(pszFormat);

if (pszStyle == NULL) {
/* When no style is selected, use "" which is a valid default. */
Expand Down Expand Up @@ -1457,7 +1480,7 @@ int msDrawWMSLayerLow(int nLayerId, httpRequestObj *pasReqInfo, int numRequests,
currenttype = lp->type;
currentconnectiontype = lp->connectiontype;
lp->type = MS_LAYER_RASTER;
lp->connectiontype = MS_SHAPEFILE;
lp->connectiontype = MS_RASTER;

/* set the classes to 0 so that It won't do client side */
/* classification if an sld was set. */
Expand All @@ -1478,6 +1501,23 @@ int msDrawWMSLayerLow(int nLayerId, httpRequestObj *pasReqInfo, int numRequests,
else
lp->data = msStrdup(pasReqInfo[iReq].pszOutputFile);

const char *pszAllowedDrivers =
msOWSLookupMetadata(&(lp->metadata), "MO", "allowed_gdal_drivers");
if (!pszAllowedDrivers) {
char *pszFormat = msWMSLayerGetFormat(lp);
if (IsPNGFormat(pszFormat))
pszAllowedDrivers = "PNG";
else if (IsJPEGFormat(pszFormat))
pszAllowedDrivers = "JPEG";
else
pszAllowedDrivers = "PNG,JPEG";
msFree(pszFormat);
}
// This will be used by msDrawRasterLayerLow()
msLayerSetProcessingKey(lp, "ALLOWED_GDAL_DRIVERS", pszAllowedDrivers);
if (lp->debug)
msDebug("Setting ALLOWED_GDAL_DRIVERS = %s\n", pszAllowedDrivers);

/* #3138 If PROCESSING "RESAMPLE=..." is set we cannot use the simple case */
if (!msProjectionsDiffer(&(map->projection), &(lp->projection)) &&
(msLayerGetProcessingKey(lp, "RESAMPLE") == NULL)) {
Expand Down

0 comments on commit f20110e

Please sign in to comment.