Skip to content

Commit 9fa1c04

Browse files
committed
Don't allow local certificates over the loopback interface, drop support for writing to plain files.
1 parent 169d216 commit 9fa1c04

11 files changed

Lines changed: 178 additions & 70 deletions

File tree

cups/auth.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// Authentication functions for CUPS.
33
//
4-
// Copyright © 2020-2025 by OpenPrinting.
4+
// Copyright © 2020-2026 by OpenPrinting.
55
// Copyright © 2007-2019 by Apple Inc.
66
// Copyright © 1997-2007 by Easy Software Products.
77
//
@@ -707,7 +707,7 @@ cups_auth_scheme(const char *www_authenticate, // I - Pointer into WWW-Authentic
707707
static bool // O - `true` if authorized, `false` otherwise
708708
cups_do_local_auth(http_t *http) // I - HTTP connection to server
709709
{
710-
#if !_WIN32 && !__EMX__
710+
#if !_WIN32 && !__EMX__ && defined(AF_LOCAL)
711711
int pid; // Current process ID
712712
FILE *fp; // Certificate file
713713
char trc[16], // Try Root Certificate parameter
@@ -729,7 +729,7 @@ cups_do_local_auth(http_t *http) // I - HTTP connection to server
729729
DEBUG_printf("7cups_local_auth(http=%p) hostaddr=%s, hostname=\"%s\"", (void *)http, httpAddrString(http->hostaddr, filename, sizeof(filename)), http->hostname);
730730

731731
// See if we are accessing localhost...
732-
if (!httpAddrIsLocalhost(httpGetAddress(http)))
732+
if (httpAddrGetFamily(httpGetAddress(http)) != AF_LOCAL)
733733
{
734734
DEBUG_puts("8cups_local_auth: Not a local connection, returning false.");
735735
return (false);
@@ -794,12 +794,11 @@ cups_do_local_auth(http_t *http) // I - HTTP connection to server
794794
}
795795
# endif // HAVE_AUTHORIZATION_H
796796

797-
# if defined(SO_PEERCRED) && defined(AF_LOCAL)
797+
# if defined(SO_PEERCRED)
798798
// See if we can authenticate using the peer credentials provided over a
799799
// domain socket; if so, specify "PeerCred username" as the authentication
800800
// information...
801-
if (http->hostaddr->addr.sa_family == AF_LOCAL &&
802-
!getenv("GATEWAY_INTERFACE") && // Not via CGI programs...
801+
if (!getenv("GATEWAY_INTERFACE") && // Not via CGI programs...
803802
cups_auth_find(www_auth, "PeerCred"))
804803
{
805804
// Verify that the current cupsGetUser() matches the current UID...
@@ -863,7 +862,7 @@ cups_do_local_auth(http_t *http) // I - HTTP connection to server
863862
return (true);
864863
}
865864
}
866-
#endif // !_WIN32 && !__EMX__
865+
#endif // !_WIN32 && !__EMX__ && defined(AF_LOCAL)
867866

868867
DEBUG_puts("8cups_do_local_auth: Returning false.");
869868

doc/help/man-cups-files.conf.html

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,15 @@ <h3 id="cups-files.conf-5.description.deprecated-directives">Deprecated Directiv
240240
<p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>FileDevice Yes</strong><br>
241241
</p>
242242
<p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>FileDevice No</strong><br>
243+
</p>
244+
<p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>FileDevice ^</strong><em>PATH-REGEX</em><br>
243245
Specifies whether the file pseudo-device can be used for new printer queues.
244246
The URI &quot;file:///dev/null&quot; is always allowed.
245247
File devices cannot be used with &quot;raw&quot; print queues - a PPD file is required.
246-
The specified file is overwritten for every print job.
247-
Writing to directories is not supported.
248+
The specified file must already exist and is opened for writing in exclusive mode.
249+
Creating new files or writing to directories is not supported.
250+
Specifying a value of &quot;Yes&quot; allows access to TTY devices of the form &quot;/dev/ttySOMETHING&quot;.
251+
Specifying a regular expression allows access to TTY devices whose paths match the specified regular expression.
248252
</p>
249253
<p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>Printcap </strong><em>filename</em><br>
250254
Specifies a file that is filled with a list of local print queues.

man/cups-files.conf.5

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
.\"
22
.\" cups-files.conf man page for CUPS.
33
.\"
4-
.\" Copyright © 2020-2025 by OpenPrinting.
4+
.\" Copyright © 2020-2026 by OpenPrinting.
55
.\" Copyright © 2007-2019 by Apple Inc.
66
.\" Copyright © 1997-2006 by Easy Software Products.
77
.\"
88
.\" Licensed under Apache License v2.0. See the file "LICENSE" for more
99
.\" information.
1010
.\"
11-
.TH cups-files.conf 5 "CUPS" "2025-10-08" "OpenPrinting"
11+
.TH cups-files.conf 5 "CUPS" "2026-03-19" "OpenPrinting"
1212
.SH NAME
1313
cups\-files.conf \- file and directory configuration file for cups
1414
.SH DESCRIPTION
@@ -266,11 +266,15 @@ The following directives are deprecated and will be removed from a future versio
266266
\fBFileDevice Yes\fR
267267
.TP 5
268268
\fBFileDevice No\fR
269+
.TP 5
270+
\fBFileDevice ^\fIPATH-REGEX\fR
269271
Specifies whether the file pseudo-device can be used for new printer queues.
270272
The URI "file:///dev/null" is always allowed.
271273
File devices cannot be used with "raw" print queues - a PPD file is required.
272-
The specified file is overwritten for every print job.
273-
Writing to directories is not supported.
274+
The specified file must already exist and is opened for writing in exclusive mode.
275+
Creating new files or writing to directories is not supported.
276+
Specifying a value of "Yes" allows access to TTY devices of the form "/dev/ttySOMETHING".
277+
Specifying a regular expression allows access to TTY devices whose paths match the specified regular expression.
274278
.\"#Printcap
275279
.TP 5
276280
\fBPrintcap \fIfilename\fR

scheduler/auth.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
382382
}
383383
#ifdef HAVE_AUTHORIZATION_H
384384
else if (!strncmp(authorization, "AuthRef ", 8) &&
385-
httpAddrLocalhost(httpGetAddress(con->http)))
385+
httpAddrGetFamily(httpGetAddress(con->http)) == AF_LOCAL)
386386
{
387387
OSStatus status; /* Status */
388388
char authdata[HTTP_MAX_VALUE];
@@ -463,7 +463,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
463463
#endif /* HAVE_AUTHORIZATION_H */
464464
#if defined(SO_PEERCRED) && defined(AF_LOCAL)
465465
else if (PeerCred != CUPSD_PEERCRED_OFF && !strncmp(authorization, "PeerCred ", 9) &&
466-
con->http->hostaddr->addr.sa_family == AF_LOCAL && con->best)
466+
httpAddrGetFamily(httpGetAddress(con->http)) == AF_LOCAL && con->best)
467467
{
468468
/*
469469
* Use peer credentials from domain socket connection...
@@ -553,7 +553,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
553553
}
554554
#endif /* SO_PEERCRED && AF_LOCAL */
555555
else if (!strncmp(authorization, "Local", 5) &&
556-
httpAddrLocalhost(httpGetAddress(con->http)))
556+
httpAddrGetFamily(httpGetAddress(con->http)) == AF_LOCAL)
557557
{
558558
/*
559559
* Get Local certificate authentication data...

scheduler/client.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2194,7 +2194,7 @@ cupsdSendHeader(
21942194
cupsCopyString(auth_str, "Negotiate", sizeof(auth_str));
21952195
}
21962196

2197-
if (con->best && !con->is_browser && !_cups_strcasecmp(httpGetHostname(con->http, NULL, 0), "localhost"))
2197+
if (con->best && !con->is_browser && httpAddrGetFamily(httpGetAddress(con->http)) == AF_LOCAL)
21982198
{
21992199
/*
22002200
* Add a "trc" (try root certification) parameter for local
@@ -2214,7 +2214,7 @@ cupsdSendHeader(
22142214
auth_size = sizeof(auth_str) - (size_t)(auth_key - auth_str);
22152215

22162216
#if defined(SO_PEERCRED) && defined(AF_LOCAL)
2217-
if (PeerCred != CUPSD_PEERCRED_OFF && httpAddrGetFamily(httpGetAddress(con->http)) == AF_LOCAL)
2217+
if (PeerCred != CUPSD_PEERCRED_OFF)
22182218
{
22192219
cupsCopyString(auth_key, ", PeerCred", auth_size);
22202220
auth_key += 10;

scheduler/conf.c

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ static const cupsd_var_t cupsfiles_vars[] =
134134
{ "DataDir", &DataDir, CUPSD_VARTYPE_STRING },
135135
{ "DocumentRoot", &DocumentRoot, CUPSD_VARTYPE_STRING },
136136
{ "ErrorLog", &ErrorLog, CUPSD_VARTYPE_STRING },
137-
{ "FileDevice", &FileDevice, CUPSD_VARTYPE_BOOLEAN },
138137
{ "LogFilePerm", &LogFilePerm, CUPSD_VARTYPE_PERM },
139138
{ "OAuthScopes", &OAuthScopes, CUPSD_VARTYPE_STRING },
140139
{ "OAuthServer", &OAuthServer, CUPSD_VARTYPE_STRING },
@@ -574,6 +573,21 @@ cupsdReadConfiguration(void)
574573
old_remote_port = RemotePort;
575574
RemotePort = 0;
576575

576+
/*
577+
* FileDevice...
578+
*/
579+
580+
if (FileDevice)
581+
{
582+
/*
583+
* Free file: device path matching regular expression...
584+
*/
585+
586+
regfree(FileDevice);
587+
free(FileDevice);
588+
FileDevice = NULL;
589+
}
590+
577591
/*
578592
* String options...
579593
*/
@@ -741,7 +755,6 @@ cupsdReadConfiguration(void)
741755
JobKillDelay = DEFAULT_TIMEOUT;
742756
JobRetryLimit = 5;
743757
JobRetryInterval = 300;
744-
FileDevice = FALSE;
745758
FilterLevel = 0;
746759
FilterLimit = 0;
747760
FilterNice = 0;
@@ -3629,6 +3642,73 @@ read_cups_files_conf(cups_file_t *fp) /* I - File to read from */
36293642
{
36303643
FatalErrors = parse_fatal_errors(value);
36313644
}
3645+
else if (!_cups_strcasecmp(line, "FileDevice") && value)
3646+
{
3647+
/*
3648+
* FileDevice BOOLEAN
3649+
* FileDevice ^PATH-REGEX
3650+
*/
3651+
3652+
int r; /* Regular expression status */
3653+
char rerror[1024]; /* Regular expression error */
3654+
3655+
if (FileDevice)
3656+
{
3657+
/*
3658+
* Free existing regular expression...
3659+
*/
3660+
3661+
regfree(FileDevice);
3662+
free(FileDevice);
3663+
FileDevice = NULL;
3664+
}
3665+
3666+
if (!_cups_strcasecmp(value, "false") || !_cups_strcasecmp(value, "no") || !_cups_strcasecmp(value, "off"))
3667+
{
3668+
/*
3669+
* Do nothing more, no file: device support beyond /dev/null...
3670+
*/
3671+
3672+
continue;
3673+
}
3674+
else if (!_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "true") || !_cups_strcasecmp(value, "yes"))
3675+
{
3676+
/*
3677+
* Enable file: device support for /dev/ttySOMETHING...
3678+
*/
3679+
3680+
value = "^/dev/tty[A-Za-z0-9._]+$";
3681+
}
3682+
else if (*value != '^')
3683+
{
3684+
cupsdLogMessage(CUPSD_LOG_ERROR, "Unsupported FileDevice \"%s\" on line %d of %s.", value, linenum, CupsFilesFile);
3685+
if (FatalErrors & CUPSD_FATAL_CONFIG)
3686+
return (0);
3687+
}
3688+
3689+
/*
3690+
* Try compiling the regular expression in "value"...
3691+
*/
3692+
3693+
if ((FileDevice = calloc(1, sizeof(regex_t))) == NULL)
3694+
{
3695+
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create FileDevice regular expression \"%s\" on line %d of %s.", value, linenum, CupsFilesFile);
3696+
if (FatalErrors & CUPSD_FATAL_CONFIG)
3697+
return (0);
3698+
}
3699+
3700+
if ((r = regcomp(FileDevice, value, REG_EXTENDED | REG_NOSUB)) != 0)
3701+
{
3702+
regerror(r, FileDevice, rerror, sizeof(rerror));
3703+
free(FileDevice);
3704+
FileDevice = NULL;
3705+
3706+
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to compile FileDevice regular expression \"%s\" on line %d of %s: %s", value, linenum, CupsFilesFile, rerror);
3707+
3708+
if (FatalErrors & CUPSD_FATAL_CONFIG)
3709+
return (0);
3710+
}
3711+
}
36323712
else if (!_cups_strcasecmp(line, "Group") && value)
36333713
{
36343714
/*

scheduler/conf.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* Configuration file definitions for the CUPS scheduler.
33
*
4-
* Copyright © 2020-2025 by OpenPrinting.
4+
* Copyright © 2020-2026 by OpenPrinting.
55
* Copyright © 2007-2018 by Apple Inc.
66
* Copyright © 1997-2007 by Easy Software Products, all rights reserved.
77
*
@@ -203,11 +203,11 @@ VAR int MaxClients VALUE(100),
203203
/* Do we do reverse lookups? */
204204
Timeout VALUE(DEFAULT_TIMEOUT),
205205
/* Timeout during requests */
206-
KeepAlive VALUE(TRUE),
206+
KeepAlive VALUE(TRUE);
207207
/* Support the Keep-Alive option? */
208-
FileDevice VALUE(FALSE),
208+
VAR regex_t *FileDevice VALUE(NULL);
209209
/* Allow file: devices? */
210-
FilterLimit VALUE(0),
210+
VAR int FilterLimit VALUE(0),
211211
/* Max filter cost at any time */
212212
FilterLevel VALUE(0),
213213
/* Current filter level */

scheduler/ipp.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2291,21 +2291,32 @@ add_printer(cupsd_client_t *con, /* I - Client connection */
22912291
* See if the administrator has enabled file devices...
22922292
*/
22932293

2294-
if (!FileDevice && strcmp(resource, "/dev/null"))
2294+
if (strcmp(resource, "/dev/null"))
22952295
{
2296-
/*
2297-
* File devices are disabled and the URL is not file:/dev/null...
2298-
*/
2296+
if (FileDevice && regexec(FileDevice, resource, /*nmatch*/0, /*pmatch*/NULL, /*eflags*/0))
2297+
{
2298+
/*
2299+
* File devices are enabled but the path is not allowed...
2300+
*/
22992301

2300-
send_ipp_status(con, IPP_STATUS_ERROR_NOT_POSSIBLE,
2301-
_("File device URIs have been disabled. "
2302-
"To enable, see the FileDevice directive in "
2303-
"\"%s/cups-files.conf\"."),
2304-
ServerRoot);
2305-
if (!modify)
2306-
cupsdDeletePrinter(printer, 0);
2302+
send_ipp_status(con, IPP_STATUS_ERROR_NOT_POSSIBLE, _("File device URI \"%s\" is not allowed."), ippGetString(attr, 0, NULL));
2303+
if (!modify)
2304+
cupsdDeletePrinter(printer, 0);
23072305

2308-
return;
2306+
return;
2307+
}
2308+
else if (!FileDevice)
2309+
{
2310+
/*
2311+
* File devices are disabled and the URL is not file:///dev/null...
2312+
*/
2313+
2314+
send_ipp_status(con, IPP_STATUS_ERROR_NOT_POSSIBLE, _("File device URIs have been disabled. To enable, see the FileDevice directive in \"%s/cups-files.conf\"."), ServerRoot);
2315+
if (!modify)
2316+
cupsdDeletePrinter(printer, 0);
2317+
2318+
return;
2319+
}
23092320
}
23102321
}
23112322
else
@@ -5483,7 +5494,7 @@ create_local_printer(
54835494
* Require local access to create a local printer...
54845495
*/
54855496

5486-
if (!httpAddrLocalhost(httpGetAddress(con->http)))
5497+
if (httpAddrGetFamily(httpGetAddress(con->http)) != AF_LOCAL)
54875498
{
54885499
send_ipp_status(con, IPP_STATUS_ERROR_FORBIDDEN, _("Only local users can create a local printer."));
54895500
return;
@@ -5543,9 +5554,9 @@ create_local_printer(
55435554

55445555
ptr = ippGetString(device_uri, 0, NULL);
55455556

5546-
if (!ptr || !ptr[0])
5557+
if (!ptr || !ptr[0] || (strncmp(ptr, "ipp://", 6) && strncmp(ptr, "ipps://", 7)))
55475558
{
5548-
send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" has empty value."), "device-uri");
5559+
send_ipp_status(con, IPP_STATUS_ERROR_NOT_POSSIBLE, _("Bad device-uri \"%s\"."), ptr);
55495560

55505561
return;
55515562
}

0 commit comments

Comments
 (0)