Skip to content

Commit 3418887

Browse files
committed
Disallow map section URIs which are subpaths of subsequent map section URIs
1 parent 72ac94d commit 3418887

File tree

3 files changed

+85
-6
lines changed

3 files changed

+85
-6
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
@@ -104,6 +104,31 @@ static void process_config_string(const dictionary *ini, const char *section, co
104104
free(key);
105105
}
106106

107+
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)
108+
{
109+
char *key = name_with_section(section, name);
110+
const char *src = iniparser_getstring(ini, key, notfound);
111+
112+
g_logger(G_LOG_LEVEL_DEBUG, "\tRead %s: '%s'", key, src);
113+
114+
if (src[strnlen(src, maxlen) - 1] != '/') {
115+
char *tempsrc = strndup(src, maxlen);
116+
int len = asprintf(&tempsrc, "%s/", src);
117+
118+
if (len == -1) {
119+
g_logger(G_LOG_LEVEL_CRITICAL, "process_config_string_with_trailing_slash: asprintf error");
120+
exit(7);
121+
}
122+
123+
copy_string(tempsrc, dest, maxlen);
124+
free(tempsrc);
125+
} else {
126+
copy_string(src, dest, maxlen);
127+
}
128+
129+
free(key);
130+
}
131+
107132
void free_map_section(xmlconfigitem map_section)
108133
{
109134
free((void *)map_section.attribution);
@@ -241,8 +266,8 @@ void process_map_sections(dictionary *ini, const char *config_file_name, xmlconf
241266
process_config_string(ini, section, "parameterize_style", &maps_dest[map_section_num].parameterization, "", PATH_MAX);
242267
process_config_string(ini, section, "server_alias", &maps_dest[map_section_num].server_alias, "", PATH_MAX);
243268
process_config_string(ini, section, "tiledir", &maps_dest[map_section_num].tile_dir, default_tile_dir, PATH_MAX);
244-
process_config_string(ini, section, "uri", &maps_dest[map_section_num].xmluri, "", PATH_MAX);
245269
process_config_string(ini, section, "xml", &maps_dest[map_section_num].xmlfile, "", PATH_MAX);
270+
process_config_string_with_trailing_slash(ini, section, "uri", &maps_dest[map_section_num].xmluri, "", PATH_MAX);
246271

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

@@ -277,9 +302,7 @@ void process_map_sections(dictionary *ini, const char *config_file_name, xmlconf
277302
process_config_string(ini, section, "type", &ini_type, "png image/png png256", INILINE_MAX);
278303
ini_type_copy = strndup(ini_type, INILINE_MAX);
279304

280-
for (ini_type_part = strtok_r(ini_type_copy, " ", &ini_type_context);
281-
ini_type_part;
282-
ini_type_part = strtok_r(NULL, " ", &ini_type_context)) {
305+
for (ini_type_part = strtok_r(ini_type_copy, " ", &ini_type_context); ini_type_part; ini_type_part = strtok_r(NULL, " ", &ini_type_context)) {
283306
switch (ini_type_part_num) {
284307
case 0:
285308
copy_string(ini_type_part, &maps_dest[map_section_num].file_extension, ini_type_part_maxlen);
@@ -332,6 +355,17 @@ void process_map_sections(dictionary *ini, const char *config_file_name, xmlconf
332355
g_logger(G_LOG_LEVEL_CRITICAL, "No map config sections were found in file: %s", config_file_name);
333356
exit(1);
334357
}
358+
359+
if (map_section_num > 0) {
360+
for (int x = 0; x < map_section_num; x++) {
361+
for (int y = x + 1; y <= map_section_num; y++) {
362+
if (strncmp(maps_dest[x].xmluri, maps_dest[y].xmluri, strnlen(maps_dest[x].xmluri, PATH_MAX)) == 0) {
363+
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);
364+
exit(7);
365+
}
366+
}
367+
}
368+
}
335369
}
336370

337371
void process_mapnik_section(dictionary *ini, const char *config_file_name, renderd_config *config_dest)

tests/renderd_config_test.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ TEST_CASE("renderd_config config parser", "specific testing")
192192

193193
for (int i = 0; i <= XMLCONFIGS_MAX; i++) {
194194
renderd_conf_file << "[map" + std::to_string(i) + "]\n";
195+
renderd_conf_file << "uri=/" + std::to_string(i) + "\n";
195196
}
196197

197198
renderd_conf_file.close();
@@ -452,8 +453,52 @@ TEST_CASE("renderd_config config parser", "specific testing")
452453
REQUIRE(WEXITSTATUS(status) == 7);
453454
REQUIRE_THAT(err_log_lines, Catch::Matchers::Contains("Duplicate renderd config section names for section 0: renderd0 & renderd"));
454455
}
455-
}
456456

457+
SECTION("renderd.conf with overlapping URIs", "should return 7") {
458+
std::string map0_uri = GENERATE("/", "/map1/", "/map2/");
459+
460+
std::string renderd_conf = std::tmpnam(nullptr);
461+
std::ofstream renderd_conf_file;
462+
renderd_conf_file.open(renderd_conf);
463+
renderd_conf_file << "[mapnik]\n[renderd]\n";
464+
465+
renderd_conf_file << "[map0]\n";
466+
renderd_conf_file << "uri=" + map0_uri + "\n";
467+
renderd_conf_file << "[map1]\n";
468+
renderd_conf_file << "uri=" + map0_uri + "1\n";
469+
470+
renderd_conf_file.close();
471+
472+
std::vector<std::string> argv = {"--config", renderd_conf};
473+
474+
int status = run_command(test_binary, argv);
475+
std::remove(renderd_conf.c_str());
476+
REQUIRE(WEXITSTATUS(status) == 7);
477+
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'"));
478+
}
479+
480+
SECTION("renderd.conf with blank URIs", "should return 7") {
481+
std::string renderd_conf = std::tmpnam(nullptr);
482+
std::ofstream renderd_conf_file;
483+
renderd_conf_file.open(renderd_conf);
484+
renderd_conf_file << "[mapnik]\n[renderd]\n";
485+
486+
renderd_conf_file << "[map0]\n";
487+
renderd_conf_file << "uri=/0\n";
488+
renderd_conf_file << "[map1]\n";
489+
renderd_conf_file << "[map2]\n";
490+
renderd_conf_file << "uri=/2\n";
491+
492+
renderd_conf_file.close();
493+
494+
std::vector<std::string> argv = {"--config", renderd_conf};
495+
496+
int status = run_command(test_binary, argv);
497+
std::remove(renderd_conf.c_str());
498+
REQUIRE(WEXITSTATUS(status) == 7);
499+
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'"));
500+
}
501+
}
457502

458503
TEST_CASE("renderd_config_test_helper", "specific testing")
459504
{

0 commit comments

Comments
 (0)