Skip to content

Commit 8818d5b

Browse files
committed
Updated cupsFileGetConf and cupsFilePutConf to escape more characters.
1 parent b9e520a commit 8818d5b

3 files changed

Lines changed: 125 additions & 44 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ v3.0.1 - YYYY-MM-DD
88
embedded platforms (Issue #141)
99
- Updated `httpAddrLookup` to return a numeric address when the resolver
1010
returns "localhost" for a non-loopback address.
11+
- Updated `cupsFileGetConf` and `cupsFilePutConf` to escape more characters.
1112
- Fixed a bug when the `ippFindXxx` and `ippSetXxx` functions were mixed
1213
(Issue #138)
1314

cups/file.c

Lines changed: 68 additions & 38 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, etc.
88
//
9-
// Copyright © 2021-2025 by OpenPrinting.
9+
// Copyright © 2021-2026 by OpenPrinting.
1010
// Copyright © 2007-2019 by Apple Inc.
1111
// Copyright © 1997-2007 by Easy Software Products, all rights reserved.
1212
//
@@ -325,8 +325,7 @@ cupsFileGetConf(cups_file_t *fp, // I - CUPS file
325325

326326

327327
// Range check input...
328-
if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
329-
!buf || buflen < 2 || !value)
328+
if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2 || !value)
330329
{
331330
if (value)
332331
*value = NULL;
@@ -341,31 +340,33 @@ cupsFileGetConf(cups_file_t *fp, // I - CUPS file
341340
{
342341
(*linenum) ++;
343342

344-
// Strip any comments...
345-
if ((ptr = strchr(buf, '#')) != NULL)
343+
// Handle escaped characters and strip any comments...
344+
for (ptr = buf; *ptr; ptr ++)
346345
{
347-
if (ptr > buf && ptr[-1] == '\\')
346+
if (*ptr == '#')
348347
{
349-
// Unquote the #...
350-
_cups_strcpy(ptr - 1, ptr);
348+
// Strip comment text...
349+
*ptr = '\0';
350+
break;
351351
}
352-
else
352+
else if (*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '#' || ptr[1] == 'n' || ptr[1] == 'r'))
353353
{
354-
// Strip the comment and any trailing whitespace...
355-
while (ptr > buf)
356-
{
357-
if (!_cups_isspace(ptr[-1]))
358-
break;
359-
360-
ptr --;
361-
}
354+
// \\, \#, \n, or \r, remove backslash and update the escaped char as needed...
355+
_cups_strcpy(ptr, ptr + 1);
362356

363-
*ptr = '\0';
357+
if (*ptr == 'n')
358+
*ptr = '\n';
359+
else if (*ptr == 'r')
360+
*ptr = '\r';
364361
}
365362
}
366363

367364
// Strip leading whitespace...
368-
for (ptr = buf; _cups_isspace(*ptr); ptr ++);
365+
for (ptr = buf; *ptr; ptr ++)
366+
{
367+
if (!_cups_isspace(*ptr))
368+
break;
369+
}
369370

370371
if (ptr > buf)
371372
_cups_strcpy(buf, ptr);
@@ -993,43 +994,72 @@ cupsFilePutChar(cups_file_t *fp, // I - CUPS file
993994
//
994995
// 'cupsFilePutConf()' - Write a configuration line.
995996
//
996-
// This function handles any comment escaping of the value.
997+
// This function handles any escaping of the value.
997998
//
998999

9991000
bool // O - `true` on success, `false` on error
10001001
cupsFilePutConf(cups_file_t *fp, // I - CUPS file
1001-
const char *directive, // I - Directive
1002-
const char *value) // I - Value
1002+
const char *directive, // I - Directive
1003+
const char *value) // I - Value
10031004
{
1004-
const char *ptr; // Pointer into value
1005-
1006-
10071005
if (!fp || !directive || !*directive)
10081006
return (false);
10091007

10101008
if (!cupsFilePuts(fp, directive))
10111009
return (false);
10121010

1013-
if (!cupsFilePutChar(fp, ' '))
1014-
return (false);
1015-
10161011
if (value && *value)
10171012
{
1018-
if ((ptr = strchr(value, '#')) != NULL)
1013+
const char *start, // Start of current fragment
1014+
*ptr; // Pointer into value
1015+
1016+
if (!cupsFilePutChar(fp, ' '))
1017+
return (false);
1018+
1019+
for (start = ptr = value; *ptr; ptr ++)
10191020
{
1020-
// Need to quote the first # in the info string...
1021-
if (!cupsFileWrite(fp, value, (size_t)(ptr - value)))
1022-
return (false);
1021+
if (strchr("#\\\n\r", *ptr) != NULL)
1022+
{
1023+
// Character that needs to be escaped...
1024+
if (ptr > start)
1025+
{
1026+
// Write unescaped portion...
1027+
if (!cupsFileWrite(fp, start, (size_t)(ptr - start)))
1028+
return (false);
1029+
}
10231030

1024-
if (!cupsFilePutChar(fp, '\\'))
1025-
return (false);
1031+
start = ptr + 1;
10261032

1027-
if (!cupsFilePuts(fp, ptr))
1028-
return (false);
1033+
if (*ptr == '\\')
1034+
{
1035+
// "\" (for escaping)
1036+
if (!cupsFilePuts(fp, "\\\\"))
1037+
return (false);
1038+
}
1039+
else if (*ptr == '#')
1040+
{
1041+
// "#" (for comment)
1042+
if (!cupsFilePuts(fp, "\\#"))
1043+
return (false);
1044+
}
1045+
else if (*ptr == '\n')
1046+
{
1047+
// LF
1048+
if (!cupsFilePuts(fp, "\\n"))
1049+
return (false);
1050+
}
1051+
else if (!cupsFilePuts(fp, "\\r"))
1052+
{
1053+
return (false);
1054+
}
1055+
}
10291056
}
1030-
else if (!cupsFilePuts(fp, value))
1057+
1058+
if (ptr > start)
10311059
{
1032-
return (false);
1060+
// Write remaining unescaped portion...
1061+
if (!cupsFileWrite(fp, start, (size_t)(ptr - start)))
1062+
return (false);
10331063
}
10341064
}
10351065

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 © 2021-2023 by OpenPrinting.
4+
// Copyright © 2021-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]))
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)