Commit 7a4af278 authored by Daniel Hosseinian's avatar Daniel Hosseinian Committed by Commit Bot

Remove lpoptions parsing code

A destination's lpoptions are stored by CUPS in the |options| field.
Therefore, the existing manual parsing of the lpoptions files is
unnecessary and dangerous as it exposes a surface through which
untrusted inputs can be read.

Additionally, the existing code assumes that the lpoptions files'
locations are perpetually static, while the CUPS programming manual
makes no guarantees about them.

Bug: 466717
Change-Id: I655716af573ba3e58656eb01e477614384af7e51
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2238955Reviewed-by: default avatarSean Kau <skau@chromium.org>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Commit-Queue: Daniel Hosseinian <dhoss@chromium.org>
Cr-Commit-Position: refs/heads/master@{#779495}
parent ec37ab86
......@@ -4,18 +4,13 @@
#include "printing/backend/cups_helper.h"
#include <cups/ppd.h>
#include <stddef.h>
#include <string>
#include <vector>
#include "base/base_paths.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "base/values.h"
......@@ -88,81 +83,6 @@ constexpr char kXeroxXRXColor[] = "XRXColor";
constexpr char kXeroxAutomatic[] = "Automatic";
constexpr char kXeroxBW[] = "BW";
void ParseLpOptions(const base::FilePath& filepath,
base::StringPiece printer_name,
int* num_options,
cups_option_t** options) {
std::string content;
if (!base::ReadFileToString(filepath, &content))
return;
const char kDest[] = "dest";
const char kDefault[] = "default";
const size_t kDestLen = sizeof(kDest) - 1;
const size_t kDefaultLen = sizeof(kDefault) - 1;
for (base::StringPiece line : base::SplitStringPiece(
content, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
if (base::StartsWith(line, base::StringPiece(kDefault, kDefaultLen),
base::CompareCase::INSENSITIVE_ASCII) &&
isspace(line[kDefaultLen])) {
line = line.substr(kDefaultLen);
} else if (base::StartsWith(line, base::StringPiece(kDest, kDestLen),
base::CompareCase::INSENSITIVE_ASCII) &&
isspace(line[kDestLen])) {
line = line.substr(kDestLen);
} else {
continue;
}
line = base::TrimWhitespaceASCII(line, base::TRIM_ALL);
if (line.empty())
continue;
size_t space_found = line.find(' ');
if (space_found == base::StringPiece::npos)
continue;
base::StringPiece name = line.substr(0, space_found);
if (name.empty())
continue;
if (!EqualsCaseInsensitiveASCII(printer_name, name))
continue; // This is not the required printer.
line = line.substr(space_found + 1);
// Remove extra spaces.
line = base::TrimWhitespaceASCII(line, base::TRIM_ALL);
if (line.empty())
continue;
// Parse the selected printer custom options. Need to pass a
// null-terminated string.
*num_options = cupsParseOptions(line.as_string().c_str(), 0, options);
}
}
void MarkLpOptions(base::StringPiece printer_name, ppd_file_t* ppd) {
static constexpr char kSystemLpOptionPath[] = "/etc/cups/lpoptions";
static constexpr char kUserLpOptionPath[] = ".cups/lpoptions";
std::vector<base::FilePath> file_locations;
file_locations.push_back(base::FilePath(kSystemLpOptionPath));
base::FilePath homedir;
base::PathService::Get(base::DIR_HOME, &homedir);
file_locations.push_back(base::FilePath(homedir.Append(kUserLpOptionPath)));
for (const base::FilePath& location : file_locations) {
int num_options = 0;
cups_option_t* options = nullptr;
ParseLpOptions(location, printer_name, &num_options, &options);
if (num_options > 0 && options) {
cupsMarkOptions(ppd, num_options, options);
cupsFreeOptions(num_options, options);
}
}
}
int32_t GetCopiesMax(ppd_file_t* ppd) {
ppd_attr_t* attr = ppdFindAttr(ppd, kCupsMaxCopies, nullptr);
if (!attr || !attr->value) {
......@@ -594,7 +514,7 @@ http_t* HttpConnectionCUPS::http() {
return http_;
}
bool ParsePpdCapabilities(base::StringPiece printer_name,
bool ParsePpdCapabilities(cups_dest_t* dest,
base::StringPiece locale,
base::StringPiece printer_capabilities,
PrinterSemanticCapsAndDefaults* printer_info) {
......@@ -616,7 +536,8 @@ bool ParsePpdCapabilities(base::StringPiece printer_name,
return false;
}
ppdMarkDefaults(ppd);
MarkLpOptions(printer_name, ppd);
if (dest)
cupsMarkOptions(ppd, dest->num_options, dest->options);
PrinterSemanticCapsAndDefaults caps;
caps.collate_capable = true;
......
......@@ -36,7 +36,7 @@ class PRINTING_EXPORT HttpConnectionCUPS {
// Helper function to parse and convert PPD capabilitites to
// semantic options.
PRINTING_EXPORT bool ParsePpdCapabilities(
base::StringPiece printer_name,
cups_dest_t* dest,
base::StringPiece locale,
base::StringPiece printer_capabilities,
PrinterSemanticCapsAndDefaults* printer_info);
......
......@@ -56,7 +56,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorDuplexShortEdge) {
*CloseGroup: General)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_TRUE(caps.collate_capable);
EXPECT_TRUE(caps.collate_default);
EXPECT_EQ(caps.copies_max, 9999);
......@@ -86,7 +87,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorDuplexSimples) {
*CloseGroup: General)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_TRUE(caps.collate_capable);
EXPECT_TRUE(caps.collate_default);
EXPECT_EQ(caps.copies_max, 9999);
......@@ -113,7 +115,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingNoColorNoDuplex) {
*CloseGroup: General)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_TRUE(caps.collate_capable);
EXPECT_TRUE(caps.collate_default);
EXPECT_EQ(caps.copies_max, 9999);
......@@ -146,7 +149,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingColorTrueDuplexShortEdge) {
*CloseGroup: General)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_TRUE(caps.collate_capable);
EXPECT_TRUE(caps.collate_default);
EXPECT_EQ(caps.copies_max, 9999);
......@@ -188,7 +192,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingColorFalseDuplexLongEdge) {
*CloseGroup: General)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_TRUE(caps.collate_capable);
EXPECT_TRUE(caps.collate_default);
EXPECT_EQ(caps.copies_max, 9999);
......@@ -220,7 +225,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingPageSize) {
*CloseUI: *PageSize)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
ASSERT_EQ(2UL, caps.papers.size());
EXPECT_EQ("Letter", caps.papers[0].vendor_id);
EXPECT_EQ("US Letter", caps.papers[0].display_name);
......@@ -261,7 +267,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingPageSizeNoDefaultSpecified) {
{
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "en-US", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"en-US",
kTestPpdData, &caps));
ASSERT_EQ(4UL, caps.papers.size());
EXPECT_EQ("Letter", caps.papers[3].vendor_id);
EXPECT_EQ("US Letter", caps.papers[3].display_name);
......@@ -271,7 +278,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingPageSizeNoDefaultSpecified) {
}
{
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "en-UK", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"en-UK",
kTestPpdData, &caps));
ASSERT_EQ(4UL, caps.papers.size());
EXPECT_EQ("A4", caps.papers[1].vendor_id);
EXPECT_EQ("ISO A4", caps.papers[1].display_name);
......@@ -294,7 +302,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingBrotherPrinters) {
*CloseUI: *BRPrintQuality)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_TRUE(caps.color_changeable);
EXPECT_TRUE(caps.color_default);
EXPECT_EQ(BROTHER_BRSCRIPT3_COLOR, caps.color_model);
......@@ -313,7 +322,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingBrotherPrinters) {
*CloseUI: *BRMonoColor)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_TRUE(caps.color_changeable);
EXPECT_TRUE(caps.color_default);
EXPECT_EQ(BROTHER_CUPS_COLOR, caps.color_model);
......@@ -332,7 +342,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingBrotherPrinters) {
*CloseUI: *BRDuplex)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_THAT(caps.duplex_modes,
testing::UnorderedElementsAre(mojom::DuplexMode::kSimplex,
mojom::DuplexMode::kLongEdge,
......@@ -354,7 +365,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingHpPrinters) {
*CloseUI: *HPColorMode)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_TRUE(caps.color_changeable);
EXPECT_TRUE(caps.color_default);
EXPECT_EQ(HP_COLOR_COLOR, caps.color_model);
......@@ -377,7 +389,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingEpsonPrinters) {
*CloseUI: *Ink)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_TRUE(caps.color_changeable);
EXPECT_TRUE(caps.color_default);
EXPECT_EQ(EPSON_INK_COLOR, caps.color_model);
......@@ -396,7 +409,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingSamsungPrinters) {
*CloseUI: *ColorMode)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_TRUE(caps.color_changeable);
EXPECT_TRUE(caps.color_default);
EXPECT_EQ(COLORMODE_COLOR, caps.color_model);
......@@ -420,7 +434,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingSharpPrinters) {
*CloseUI: *ARCMode)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_TRUE(caps.color_changeable);
EXPECT_TRUE(caps.color_default);
EXPECT_EQ(SHARP_ARCMODE_CMCOLOR, caps.color_model);
......@@ -442,7 +457,8 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingXeroxPrinters) {
*CloseUI: *XRXColor)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_TRUE(caps.color_changeable);
EXPECT_TRUE(caps.color_default);
EXPECT_EQ(XEROX_XRXCOLOR_AUTOMATIC, caps.color_model);
......@@ -460,8 +476,9 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingCupsMaxCopies) {
*CloseUI: *ColorMode)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_EQ(caps.copies_max, 99);
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_EQ(99, caps.copies_max);
}
{
......@@ -473,9 +490,49 @@ TEST(PrintBackendCupsHelperTest, TestPpdParsingCupsMaxCopies) {
*CloseUI: *ColorMode)";
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities("test", "", kTestPpdData, &caps));
EXPECT_EQ(caps.copies_max, 9999);
EXPECT_TRUE(ParsePpdCapabilities(/*dest=*/nullptr, /*locale=*/"",
kTestPpdData, &caps));
EXPECT_EQ(9999, caps.copies_max);
}
}
TEST(PrintBackendCupsHelperTest, TestPpdSetsDestOptions) {
constexpr char kTestPpdData[] =
R"(*PPD-Adobe: "4.3"
*OpenUI *Duplex/2-Sided Printing: PickOne
*DefaultDuplex: DuplexTumble
*Duplex None/Off: "
<</Duplex false>>setpagedevice"
*Duplex DuplexNoTumble/LongEdge: "
</Duplex true/Tumble false>>setpagedevice"
*Duplex DuplexTumble/ShortEdge: "
<</Duplex true/Tumble true>>setpagedevice"
*CloseUI: *Duplex)";
cups_dest_t* dest;
int num_dests = 0;
num_dests =
cupsAddDest(/*name=*/"test_dest", /*instance=*/nullptr, num_dests, &dest);
ASSERT_EQ(1, num_dests);
// Set long edge duplex mode in the destination options even though the PPD
// sets short edge duplex mode as the default.
cups_option_t* options = nullptr;
int num_options = 0;
num_options =
cupsAddOption("Duplex", "DuplexNoTumble", num_options, &options);
dest->num_options = num_options;
dest->options = options;
PrinterSemanticCapsAndDefaults caps;
EXPECT_TRUE(ParsePpdCapabilities(dest, /*locale=*/"", kTestPpdData, &caps));
EXPECT_THAT(caps.duplex_modes,
testing::UnorderedElementsAre(mojom::DuplexMode::kSimplex,
mojom::DuplexMode::kLongEdge,
mojom::DuplexMode::kShortEdge));
EXPECT_EQ(mojom::DuplexMode::kLongEdge, caps.duplex_default);
cupsFreeDests(num_dests, dest);
}
} // namespace printing
......@@ -164,7 +164,8 @@ bool PrintBackendCUPS::GetPrinterSemanticCapsAndDefaults(
if (!GetPrinterCapsAndDefaults(printer_name, &info))
return false;
return ParsePpdCapabilities(printer_name, locale(), info.printer_capabilities,
ScopedDestination dest = GetNamedDest(printer_name);
return ParsePpdCapabilities(dest.get(), locale(), info.printer_capabilities,
printer_info);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment