campaignd: Blacklist standard reserved DOS Device Names

Windows XP and later define DOS device names for several system devices
that will be handled as if they had directory entries everywhere. Their
names may not be used on the left side of a file name if a dot is
present, otherwise the read or write operation in progress (if
applicable) is redirected to the device in question, with unexpected
results (e.g. writing to CON writes to a console that may or may not be
attached, writing to COM1 will send data through the first enumerated
serial port, and so on).

Thus, we really don't want add-on authors to either intentionally or
accidentally use them on non-Windows platforms and cause Windows-based
clients to do unexpected things.

Emitting special messages for the UI in this case seems unnecessary and
it'll be a waste of space most of the time since these names should crop
up extremely rarely. Better just tell people what's up on a case-by-case
basis if they decide to post in the forums about it.
This commit is contained in:
Ignacio R. Morelle 2017-10-24 01:41:43 -03:00
parent bc8eb4900a
commit c32eded71e

View file

@ -30,6 +30,16 @@ namespace {
"other", ""
};
// Reserved DOS device names on Windows XP and later.
const std::set<std::string> dos_device_names = {
"NUL", "CON", "AUX", "PRN",
// Console API devices
"CONIN$", "CONOUT$",
// Configuration-dependent devices
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
};
struct addon_name_char_illegal
{
/**
@ -94,6 +104,20 @@ bool addon_filename_legal(const std::string& name)
name.size() > 255) {
return false;
} else {
// NOTE: We can't use filesystem::base_name() here, since it returns
// the filename up to the *last* dot. "CON.foo.bar" in
// "CON.foo.bar.baz" is still redirected to "CON" on Windows;
// the base_name() approach would cause the name to not match
// any entries on our blacklist.
// Do also note that we're relying on the next check after this
// to flag the name as illegal if it contains a ':' -- a
// trailing colon is a valid way to refer to DOS device names,
// meaning that e.g. "CON:" is equivalent to "CON".
const std::string stem = boost::algorithm::to_upper_copy(name.substr(0, name.find('.')), std::locale::classic());
if(dos_device_names.find(stem) != dos_device_names.end()) {
return false;
}
const ucs4::string name_ucs4 = unicode_cast<ucs4::string>(name);
const std::string name_utf8 = unicode_cast<utf8::string>(name_ucs4);
if(name != name_utf8){ // name is invalid UTF-8