Skip to content

Commit c4a1aa5

Browse files
committed
Disallow map section URIs which are subpaths of subsequent map section URIs
1 parent f0811e8 commit c4a1aa5

File tree

3 files changed

+86
-5
lines changed

3 files changed

+86
-5
lines changed

etc/apache2/renderd-example-map.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,5 +161,5 @@ Listen 8081
161161
# Off = a 404 is returned for that url instead.
162162
# Default: On
163163
#ModTileEnableDirtyURL Off
164-
164+
LogLevel debug
165165
</VirtualHost>

src/renderd_config.c

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,31 @@ static void process_config_string(const dictionary *ini, const char *section, co
106106
free(key);
107107
}
108108

109+
static char *process_config_string_with_trailing_slash(const dictionary *ini, const char *section, const char *name, const char **dest, const char *notfound, size_t maxlen)
110+
{
111+
char *key = name_with_section(section, name);
112+
const char *src = iniparser_getstring(ini, key, notfound);
113+
114+
g_logger(G_LOG_LEVEL_DEBUG, "\tRead %s: '%s'", key, src);
115+
116+
if (src[strnlen(src, maxlen) - 1] != '/') {
117+
char *tempsrc = strndup(src, maxlen);
118+
int len = asprintf(&tempsrc, "%s/", src);
119+
120+
if (len == -1) {
121+
g_logger(G_LOG_LEVEL_CRITICAL, "process_config_string_with_trailing_slash: asprintf error");
122+
exit(7);
123+
}
124+
125+
copy_string(tempsrc, dest, maxlen);
126+
free(tempsrc);
127+
} else {
128+
copy_string(src, dest, maxlen);
129+
}
130+
131+
free(key);
132+
}
133+
109134
void free_map_section(xmlconfigitem map_section)
110135
{
111136
free((void *)map_section.attribution);
@@ -239,8 +264,8 @@ void process_map_sections(const char *config_file_name, xmlconfigitem *maps_dest
239264
process_config_string(ini, section, "parameterize_style", &maps_dest[map_section_num].parameterization, "", PATH_MAX);
240265
process_config_string(ini, section, "server_alias", &maps_dest[map_section_num].server_alias, "", PATH_MAX);
241266
process_config_string(ini, section, "tiledir", &maps_dest[map_section_num].tile_dir, default_tile_dir, PATH_MAX);
242-
process_config_string(ini, section, "uri", &maps_dest[map_section_num].xmluri, "", PATH_MAX);
243267
process_config_string(ini, section, "xml", &maps_dest[map_section_num].xmlfile, "", PATH_MAX);
268+
process_config_string_with_trailing_slash(ini, section, "uri", &maps_dest[map_section_num].xmluri, "", PATH_MAX);
244269

245270
process_config_double(ini, section, "scale", &maps_dest[map_section_num].scale_factor, 1.0);
246271

@@ -275,9 +300,7 @@ void process_map_sections(const char *config_file_name, xmlconfigitem *maps_dest
275300
process_config_string(ini, section, "type", &ini_type, "png image/png png256", INILINE_MAX);
276301
ini_type_copy = strndup(ini_type, INILINE_MAX);
277302

278-
for (ini_type_part = strtok_r(ini_type_copy, " ", &ini_type_context);
279-
ini_type_part;
280-
ini_type_part = strtok_r(NULL, " ", &ini_type_context)) {
303+
for (ini_type_part = strtok_r(ini_type_copy, " ", &ini_type_context); ini_type_part; ini_type_part = strtok_r(NULL, " ", &ini_type_context)) {
281304
switch (ini_type_part_num) {
282305
case 0:
283306
copy_string(ini_type_part, &maps_dest[map_section_num].file_extension, ini_type_part_maxlen);
@@ -329,6 +352,17 @@ void process_map_sections(const char *config_file_name, xmlconfigitem *maps_dest
329352
g_logger(G_LOG_LEVEL_CRITICAL, "No map config sections were found in file: %s", config_file_name);
330353
exit(1);
331354
}
355+
356+
if (map_section_num > 0) {
357+
for (int x = 0; x < map_section_num; x++) {
358+
for (int y = x + 1; y <= map_section_num; y++) {
359+
if (strncmp(maps_dest[x].xmluri, maps_dest[y].xmluri, strnlen(maps_dest[x].xmluri, PATH_MAX)) == 0) {
360+
g_logger(G_LOG_LEVEL_CRITICAL, "Specified URI path ('%s' in map section '%s') must not be the parent of any subsequent map config section's URI path, e.g., '%s' in map section '%s'.", maps_dest[x].xmluri, maps_dest[x].xmlname, maps_dest[y].xmluri, maps_dest[y].xmlname);
361+
exit(7);
362+
}
363+
}
364+
}
365+
}
332366
}
333367

334368
void process_mapnik_section(const char *config_file_name, renderd_config *config_dest)

tests/renderd_config_test.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ TEST_CASE("renderd_config config parser", "specific testing")
187187

188188
for (int i = 0; i <= XMLCONFIGS_MAX; i++) {
189189
renderd_conf_file << "[map" + std::to_string(i) + "]\n";
190+
renderd_conf_file << "uri=/" + std::to_string(i) + "\n";
190191
}
191192

192193
renderd_conf_file.close();
@@ -447,4 +448,50 @@ TEST_CASE("renderd_config config parser", "specific testing")
447448
REQUIRE(WEXITSTATUS(status) == 7);
448449
REQUIRE_THAT(err_log_lines, Catch::Matchers::Contains("Duplicate renderd config section names for section 0: renderd0 & renderd"));
449450
}
451+
452+
SECTION("renderd.conf with overlapping URIs", "should return 7") {
453+
std::string map0_uri = GENERATE("/", "/map1/", "/map2/");
454+
455+
std::string renderd_conf = std::tmpnam(nullptr);
456+
std::ofstream renderd_conf_file;
457+
renderd_conf_file.open(renderd_conf);
458+
renderd_conf_file << "[mapnik]\n[renderd]\n";
459+
460+
renderd_conf_file << "[map0]\n";
461+
renderd_conf_file << "uri=" + map0_uri + "\n";
462+
renderd_conf_file << "[map1]\n";
463+
renderd_conf_file << "uri=" + map0_uri + "1\n";
464+
465+
renderd_conf_file.close();
466+
467+
std::vector<std::string> argv = {"--config", renderd_conf};
468+
469+
int status = run_command(test_binary, argv);
470+
std::remove(renderd_conf.c_str());
471+
REQUIRE(WEXITSTATUS(status) == 7);
472+
REQUIRE_THAT(err_log_lines, Catch::Matchers::Contains("Specified URI path ('" + map0_uri + "' in map section 'map0') must not be the parent of any subsequent map config section's URI path, e.g., '" + map0_uri + "1/' in map section 'map1'"));
473+
}
474+
475+
SECTION("renderd.conf with blank URIs", "should return 7") {
476+
std::string renderd_conf = std::tmpnam(nullptr);
477+
std::ofstream renderd_conf_file;
478+
renderd_conf_file.open(renderd_conf);
479+
renderd_conf_file << "[mapnik]\n[renderd]\n";
480+
481+
renderd_conf_file << "[map0]\n";
482+
renderd_conf_file << "uri=/0\n";
483+
renderd_conf_file << "[map1]\n";
484+
renderd_conf_file << "[map2]\n";
485+
renderd_conf_file << "uri=/2\n";
486+
487+
renderd_conf_file.close();
488+
489+
std::vector<std::string> argv = {"--config", renderd_conf};
490+
491+
int status = run_command(test_binary, argv);
492+
std::remove(renderd_conf.c_str());
493+
REQUIRE(WEXITSTATUS(status) == 7);
494+
REQUIRE_THAT(err_log_lines, Catch::Matchers::Contains("Specified URI path ('/' in map section 'map1') must not be the parent of any subsequent map config section's URI path, e.g., '/2/' in map section 'map2'"));
495+
}
450496
}
497+

0 commit comments

Comments
 (0)