Skip to content

Commit 07c17a0

Browse files
committed
Updated cupsFileGetConf and cupsFilePutConf to escape more characters.
1 parent 02f0e27 commit 07c17a0

2 files changed

Lines changed: 134 additions & 45 deletions

File tree

cups/file.c

Lines changed: 78 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// our own file functions allows us to provide transparent support of
77
// different line endings, gzip'd print files, PPD files, etc.
88
//
9-
// Copyright © 2020-2025 by OpenPrinting.
9+
// Copyright © 2020-2026 by OpenPrinting.
1010
// Copyright © 2007-2019 by Apple Inc.
1111
// Copyright © 1997-2007 by Easy Software Products, all rights reserved.
1212
//
@@ -622,8 +622,7 @@ cupsFileGetConf(cups_file_t *fp, // I - CUPS file
622622
// Range check input...
623623
DEBUG_printf("2cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT ", value=%p, linenum=%p)", (void *)fp, (void *)buf, CUPS_LLCAST buflen, (void *)value, (void *)linenum);
624624

625-
if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
626-
!buf || buflen < 2 || !value)
625+
if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2 || !value)
627626
{
628627
if (value)
629628
*value = NULL;
@@ -638,31 +637,33 @@ cupsFileGetConf(cups_file_t *fp, // I - CUPS file
638637
{
639638
(*linenum) ++;
640639

641-
// Strip any comments...
642-
if ((ptr = strchr(buf, '#')) != NULL)
640+
// Handle escaped characters and strip any comments...
641+
for (ptr = buf; *ptr; ptr ++)
643642
{
644-
if (ptr > buf && ptr[-1] == '\\')
643+
if (*ptr == '#')
645644
{
646-
// Unquote the #...
647-
_cups_strcpy(ptr - 1, ptr);
645+
// Strip comment text...
646+
*ptr = '\0';
647+
break;
648648
}
649-
else
649+
else if (*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '#' || ptr[1] == 'n' || ptr[1] == 'r'))
650650
{
651-
// Strip the comment and any trailing whitespace...
652-
while (ptr > buf)
653-
{
654-
if (!_cups_isspace(ptr[-1]))
655-
break;
651+
// \\, \#, \n, or \r, remove backslash and update the escaped char as needed...
652+
_cups_strcpy(ptr, ptr + 1);
656653

657-
ptr --;
658-
}
659-
660-
*ptr = '\0';
654+
if (*ptr == 'n')
655+
*ptr = '\n';
656+
else if (*ptr == 'r')
657+
*ptr = '\r';
661658
}
662659
}
663660

664661
// Strip leading whitespace...
665-
for (ptr = buf; _cups_isspace(*ptr); ptr ++);
662+
for (ptr = buf; *ptr; ptr ++)
663+
{
664+
if (!_cups_isspace(*ptr))
665+
break;
666+
}
666667

667668
if (ptr > buf)
668669
_cups_strcpy(buf, ptr);
@@ -672,8 +673,10 @@ cupsFileGetConf(cups_file_t *fp, // I - CUPS file
672673
{
673674
// Yes, grab any value and return...
674675
for (ptr = buf; *ptr; ptr ++)
676+
{
675677
if (_cups_isspace(*ptr))
676678
break;
679+
}
677680

678681
if (*ptr)
679682
{
@@ -688,7 +691,9 @@ cupsFileGetConf(cups_file_t *fp, // I - CUPS file
688691
ptr += strlen(ptr) - 1;
689692

690693
if (buf[0] == '<' && *ptr == '>')
694+
{
691695
*ptr-- = '\0';
696+
}
692697
else if (buf[0] == '<' && *ptr != '>')
693698
{
694699
// Syntax error...
@@ -1295,7 +1300,7 @@ cupsFilePutChar(cups_file_t *fp, // I - CUPS file
12951300
//
12961301
// 'cupsFilePutConf()' - Write a configuration line.
12971302
//
1298-
// This function handles any comment escaping of the value.
1303+
// This function handles any escaping of the value.
12991304
//
13001305
// @since CUPS 1.4@
13011306
//
@@ -1307,7 +1312,6 @@ cupsFilePutConf(cups_file_t *fp, // I - CUPS file
13071312
{
13081313
ssize_t bytes, // Number of bytes written
13091314
temp; // Temporary byte count
1310-
const char *ptr; // Pointer into value
13111315

13121316

13131317
if (!fp || !directive || !*directive)
@@ -1316,31 +1320,66 @@ cupsFilePutConf(cups_file_t *fp, // I - CUPS file
13161320
if ((bytes = cupsFilePuts(fp, directive)) < 0)
13171321
return (-1);
13181322

1319-
if (cupsFilePutChar(fp, ' ') < 0)
1320-
return (-1);
1321-
bytes ++;
1322-
13231323
if (value && *value)
13241324
{
1325-
if ((ptr = strchr(value, '#')) != NULL)
1325+
const char *start, // Start of current fragment
1326+
*ptr; // Pointer into value
1327+
1328+
if (cupsFilePutChar(fp, ' ') < 0)
1329+
return (-1);
1330+
bytes ++;
1331+
1332+
for (start = ptr = value; *ptr; ptr ++)
13261333
{
1327-
// Need to quote the first # in the info string...
1328-
if ((temp = cupsFileWrite(fp, value, (size_t)(ptr - value))) < 0)
1329-
return (-1);
1330-
bytes += temp;
1334+
if (strchr("#\\\n\r", *ptr) != NULL)
1335+
{
1336+
// Character that needs to be escaped...
1337+
if (ptr > start)
1338+
{
1339+
// Write unescaped portion...
1340+
if ((temp = cupsFileWrite(fp, start, (size_t)(ptr - start))) < 0)
1341+
return (-1);
13311342

1332-
if (cupsFilePutChar(fp, '\\') < 0)
1333-
return (-1);
1334-
bytes ++;
1343+
bytes += temp;
1344+
}
13351345

1336-
if ((temp = cupsFilePuts(fp, ptr)) < 0)
1337-
return (-1);
1338-
bytes += temp;
1346+
start = ptr + 1;
1347+
1348+
if (*ptr == '\\')
1349+
{
1350+
// "\" (for escaping)
1351+
if (cupsFilePuts(fp, "\\\\") < 0)
1352+
return (-1);
1353+
}
1354+
else if (*ptr == '#')
1355+
{
1356+
// "#" (for comment)
1357+
if (cupsFilePuts(fp, "\\#") < 0)
1358+
return (-1);
1359+
}
1360+
else if (*ptr == '\n')
1361+
{
1362+
// LF
1363+
if (cupsFilePuts(fp, "\\n") < 0)
1364+
return (-1);
1365+
}
1366+
else if (cupsFilePuts(fp, "\\r") < 0)
1367+
{
1368+
return (-1);
1369+
}
1370+
1371+
bytes += 2;
1372+
}
13391373
}
1340-
else if ((temp = cupsFilePuts(fp, value)) < 0)
1341-
return (-1);
1342-
else
1374+
1375+
if (ptr > start)
1376+
{
1377+
// Write remaining unescaped portion...
1378+
if ((temp = cupsFileWrite(fp, start, (size_t)(ptr - start))) < 0)
1379+
return (-1);
1380+
13431381
bytes += temp;
1382+
}
13441383
}
13451384

13461385
if (cupsFilePutChar(fp, '\n') < 0)

cups/testfile.c

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// File/directory test program for CUPS.
33
//
4-
// Copyright © 2020-2024 by OpenPrinting.
4+
// Copyright © 2020-2026 by OpenPrinting.
55
// Copyright © 2007-2018 by Apple Inc.
66
// Copyright © 1997-2007 by Easy Software Products.
77
//
@@ -491,6 +491,17 @@ read_write_tests(bool compression) // I - Use compression?
491491
off_t length; // Length of file
492492
static const char *partial_line = "partial line";
493493
// Partial line
494+
static const char * const values[] = // cupsFileGet/PutConf values
495+
{
496+
"simple",
497+
"'single-quoted value'",
498+
"\"double-quoted value\"",
499+
"value with # comment",
500+
"value with \n newline",
501+
"value with \r carriage return",
502+
"value with \\ backslash",
503+
"pathological\r\nvalue\\#with comment"
504+
};
494505

495506

496507
// No errors so far...
@@ -553,6 +564,24 @@ read_write_tests(bool compression) // I - Use compression?
553564
status ++;
554565
}
555566

567+
// cupsFilePutConf()
568+
testBegin("cupsFilePutConf()");
569+
for (i = 0; i < (int)(sizeof(values) / sizeof(values[0])); i ++)
570+
{
571+
if (cupsFilePutConf(fp, "TestConf", values[i]) < 0)
572+
break;
573+
}
574+
575+
if (i >= (int)(sizeof(values) / sizeof(values[0])))
576+
{
577+
testEnd(true);
578+
}
579+
else
580+
{
581+
testEndMessage(false, "%s", strerror(errno));
582+
status ++;
583+
}
584+
556585
// cupsFilePutChar()
557586
testBegin("cupsFilePutChar()");
558587

@@ -607,13 +636,13 @@ read_write_tests(bool compression) // I - Use compression?
607636
// cupsFileTell()
608637
testBegin("cupsFileTell()");
609638

610-
if ((length = cupsFileTell(fp)) == 81933283)
639+
if ((length = cupsFileTell(fp)) == 81933542)
611640
{
612641
testEnd(true);
613642
}
614643
else
615644
{
616-
testEndMessage(false, "" CUPS_LLFMT " instead of 81933283", CUPS_LLCAST length);
645+
testEndMessage(false, "" CUPS_LLFMT " instead of 81933542", CUPS_LLCAST length);
617646
status ++;
618647
}
619648

@@ -682,7 +711,7 @@ read_write_tests(bool compression) // I - Use compression?
682711
// cupsFileGetConf()
683712
linenum = 1;
684713

685-
testBegin("cupsFileGetConf()");
714+
testBegin("cupsFileGetConf(TestLine)");
686715

687716
for (i = 0, value = NULL; i < 1000; i ++)
688717
{
@@ -709,6 +738,27 @@ read_write_tests(bool compression) // I - Use compression?
709738
status ++;
710739
}
711740

741+
testBegin("cupsFileGetConf(TestConf)");
742+
743+
for (i = 0; i < (int)(sizeof(values) / sizeof(values[0])); i ++)
744+
{
745+
if (!cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
746+
{
747+
testEndMessage(false, "%s", strerror(errno));
748+
status ++;
749+
break;
750+
}
751+
else if (_cups_strcasecmp(line, "TestConf") || !value || strcmp(value, values[i]))
752+
{
753+
testEndMessage(false, "Expected 'TestConf %s', got '%s %s'", values[i], line, value);
754+
status ++;
755+
break;
756+
}
757+
}
758+
759+
if (i >= (int)(sizeof(values) / sizeof(values[0])))
760+
testEnd(true);
761+
712762
// cupsFileGetChar()
713763
testBegin("cupsFileGetChar()");
714764

@@ -788,13 +838,13 @@ read_write_tests(bool compression) // I - Use compression?
788838
// cupsFileTell()
789839
testBegin("cupsFileTell()");
790840

791-
if ((length = cupsFileTell(fp)) == 81933283)
841+
if ((length = cupsFileTell(fp)) == 81933542)
792842
{
793843
testEnd(true);
794844
}
795845
else
796846
{
797-
testEndMessage(false, "" CUPS_LLFMT " instead of 81933283", CUPS_LLCAST length);
847+
testEndMessage(false, "" CUPS_LLFMT " instead of 81933542", CUPS_LLCAST length);
798848
status ++;
799849
}
800850

0 commit comments

Comments
 (0)