From 1d75c07bb1b999adf087aebb267269bd2b739eab Mon Sep 17 00:00:00 2001
From: CentOS Sources
Date: Aug 02 2019 08:05:32 +0000
Subject: import cups-2.2.6-27.el8
---
diff --git a/.cups.metadata b/.cups.metadata
new file mode 100644
index 0000000..8869656
--- /dev/null
+++ b/.cups.metadata
@@ -0,0 +1,2 @@
+b5e3389fb9450bfed377c95c0230c029c053acc4 SOURCES/cups-2.2.6-source.tar.gz
+79ee155bed4c18088be472a6e364f37ad6e410a6 SOURCES/cupsprinter.png
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c5e2c0a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+SOURCES/cups-2.2.6-source.tar.gz
+SOURCES/cupsprinter.png
diff --git a/SOURCES/0001-Add-support-for-MinTLS-and-MaxTLS-options-Issue-5119.patch b/SOURCES/0001-Add-support-for-MinTLS-and-MaxTLS-options-Issue-5119.patch
new file mode 100644
index 0000000..810b9ca
--- /dev/null
+++ b/SOURCES/0001-Add-support-for-MinTLS-and-MaxTLS-options-Issue-5119.patch
@@ -0,0 +1,497 @@
+diff -up cups-2.2.6/cups/http-private.h.remove-weak-ciphers cups-2.2.6/cups/http-private.h
+--- cups-2.2.6/cups/http-private.h.remove-weak-ciphers 2017-11-01 15:57:53.000000000 +0100
++++ cups-2.2.6/cups/http-private.h 2018-08-07 11:53:54.985633959 +0200
+@@ -180,13 +180,17 @@ extern "C" {
+
+ # define _HTTP_TLS_NONE 0 /* No TLS options */
+ # define _HTTP_TLS_ALLOW_RC4 1 /* Allow RC4 cipher suites */
+-# define _HTTP_TLS_ALLOW_SSL3 2 /* Allow SSL 3.0 */
+-# define _HTTP_TLS_ALLOW_DH 4 /* Allow DH/DHE key negotiation */
+-# define _HTTP_TLS_DENY_TLS10 16 /* Deny TLS 1.0 */
+-# define _HTTP_TLS_DENY_CBC 32 /* Deny CBC cipher suites */
+-# define _HTTP_TLS_ONLY_TLS10 64 /* Only use TLS 1.0 */
++# define _HTTP_TLS_ALLOW_DH 2 /* Allow DH/DHE key negotiation */
++# define _HTTP_TLS_DENY_CBC 4 /* Deny CBC cipher suites */
+ # define _HTTP_TLS_SET_DEFAULT 128 /* Setting the default TLS options */
+
++# define _HTTP_TLS_SSL3 0 /* Min/max version is SSL/3.0 */
++# define _HTTP_TLS_1_0 1 /* Min/max version is TLS/1.0 */
++# define _HTTP_TLS_1_1 2 /* Min/max version is TLS/1.1 */
++# define _HTTP_TLS_1_2 3 /* Min/max version is TLS/1.2 */
++# define _HTTP_TLS_1_3 4 /* Min/max version is TLS/1.3 */
++# define _HTTP_TLS_MAX 5 /* Highest known TLS version */
++
+
+ /*
+ * Types and functions for SSL support...
+@@ -442,7 +446,7 @@ extern void _httpTLSInitialize(void);
+ extern size_t _httpTLSPending(http_t *http);
+ extern int _httpTLSRead(http_t *http, char *buf, int len);
+ extern int _httpTLSSetCredentials(http_t *http);
+-extern void _httpTLSSetOptions(int options);
++extern void _httpTLSSetOptions(int options, int min_version, int max_version);
+ extern int _httpTLSStart(http_t *http);
+ extern void _httpTLSStop(http_t *http);
+ extern int _httpTLSWrite(http_t *http, const char *buf, int len);
+diff -up cups-2.2.6/cups/tlscheck.c.remove-weak-ciphers cups-2.2.6/cups/tlscheck.c
+--- cups-2.2.6/cups/tlscheck.c.remove-weak-ciphers 2017-11-01 15:57:53.000000000 +0100
++++ cups-2.2.6/cups/tlscheck.c 2018-08-07 11:53:54.987633942 +0200
+@@ -54,6 +54,8 @@ main(int argc, /* I - Number of comm
+ int af = AF_UNSPEC, /* Address family */
+ tls_options = _HTTP_TLS_NONE,
+ /* TLS options */
++ tls_min_version = _HTTP_TLS_1_0,
++ tls_max_version = _HTTP_TLS_MAX,
+ verbose = 0; /* Verbosity */
+ ipp_t *request, /* IPP Get-Printer-Attributes request */
+ *response; /* IPP Get-Printer-Attributes response */
+@@ -88,11 +90,12 @@ main(int argc, /* I - Number of comm
+ }
+ else if (!strcmp(argv[i], "--no-tls10"))
+ {
+- tls_options |= _HTTP_TLS_DENY_TLS10;
++ tls_min_version = _HTTP_TLS_1_1;
+ }
+ else if (!strcmp(argv[i], "--tls10"))
+ {
+- tls_options |= _HTTP_TLS_ONLY_TLS10;
++ tls_min_version = _HTTP_TLS_1_0;
++ tls_max_version = _HTTP_TLS_1_0;
+ }
+ else if (!strcmp(argv[i], "--rc4"))
+ {
+@@ -148,7 +151,7 @@ main(int argc, /* I - Number of comm
+ if (!port)
+ port = 631;
+
+- _httpTLSSetOptions(tls_options);
++ _httpTLSSetOptions(tls_options, tls_min_version, tls_max_version);
+
+ http = httpConnect2(server, port, NULL, af, HTTP_ENCRYPTION_ALWAYS, 1, 30000, NULL);
+ if (!http)
+diff -up cups-2.2.6/cups/tls-darwin.c.remove-weak-ciphers cups-2.2.6/cups/tls-darwin.c
+--- cups-2.2.6/cups/tls-darwin.c.remove-weak-ciphers 2017-11-01 15:57:53.000000000 +0100
++++ cups-2.2.6/cups/tls-darwin.c 2018-08-07 11:53:54.986633951 +0200
+@@ -53,7 +53,9 @@ static char *tls_keypath = NULL;
+ /* Server cert keychain path */
+ static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER;
+ /* Mutex for keychain/certs */
+-static int tls_options = -1;/* Options for TLS connections */
++static int tls_options = -1,/* Options for TLS connections */
++ tls_min_version = _HTTP_TLS_1_0,
++ tls_max_version = _HTTP_TLS_MAX;
+
+
+ /*
+@@ -1139,10 +1141,16 @@ _httpTLSRead(http_t *http, /* I - HTTP
+ */
+
+ void
+-_httpTLSSetOptions(int options) /* I - Options */
++_httpTLSSetOptions(int options, /* I - Options */
++ int min_version, /* I - Minimum TLS version */
++ int max_version) /* I - Maximum TLS version */
+ {
+ if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
+- tls_options = options;
++ {
++ tls_options = options;
++ tls_min_version = min_version;
++ tls_max_version = max_version;
++ }
+ }
+
+
+@@ -1174,7 +1182,7 @@ _httpTLSStart(http_t *http) /* I - HTTP
+ {
+ DEBUG_puts("4_httpTLSStart: Setting defaults.");
+ _cupsSetDefaults();
+- DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options));
++ DEBUG_printf(("4_httpTLSStart: tls_options=%x, tls_min_version=%d, tls_max_version=%d", tls_options, tls_min_version, tls_max_version));
+ }
+
+ #ifdef HAVE_SECKEYCHAINOPEN
+@@ -1217,22 +1225,23 @@ _httpTLSStart(http_t *http) /* I - HTTP
+
+ if (!error)
+ {
+- SSLProtocol minProtocol;
+-
+- if (tls_options & _HTTP_TLS_DENY_TLS10)
+- minProtocol = kTLSProtocol11;
+- else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
+- minProtocol = kSSLProtocol3;
+- else
+- minProtocol = kTLSProtocol1;
++ static const SSLProtocol protocols[] = /* Min/max protocol versions */
++ {
++ kSSLProtocol3,
++ kTLSProtocol1,
++ kTLSProtocol11,
++ kTLSProtocol12,
++ kTLSProtocol13,
++ kTLSProtocolMaxSupported
++ };
+
+- error = SSLSetProtocolVersionMin(http->tls, minProtocol);
+- DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", minProtocol, (int)error));
++ error = SSLSetProtocolVersionMin(http->tls, protocols[tls_min_version]);
++ DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", protocols[tls_min_version], (int)error));
+
+- if (!error && (tls_options & _HTTP_TLS_ONLY_TLS10))
++ if (!error)
+ {
+- error = SSLSetProtocolVersionMax(http->tls, kTLSProtocol1);
+- DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMax(kTLSProtocol1), error=%d", (int)error));
++ error = SSLSetProtocolVersionMax(http->tls, protocols[tls_max_version]);
++ DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMax(%d), error=%d", protocols[tls_max_version], (int)error));
+ }
+ }
+
+diff -up cups-2.2.6/cups/tls-gnutls.c.remove-weak-ciphers cups-2.2.6/cups/tls-gnutls.c
+--- cups-2.2.6/cups/tls-gnutls.c.remove-weak-ciphers 2017-11-01 15:57:53.000000000 +0100
++++ cups-2.2.6/cups/tls-gnutls.c 2018-08-07 11:58:45.164114342 +0200
+@@ -35,7 +35,9 @@ static char *tls_keypath = NULL;
+ /* Server cert keychain path */
+ static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER;
+ /* Mutex for keychain/certs */
+-static int tls_options = -1;/* Options for TLS connections */
++static int tls_options = -1,/* Options for TLS connections */
++ tls_min_version = _HTTP_TLS_1_0,
++ tls_max_version = _HTTP_TLS_MAX;
+
+
+ /*
+@@ -1224,10 +1226,16 @@ _httpTLSSetCredentials(http_t *http) /*
+ */
+
+ void
+-_httpTLSSetOptions(int options) /* I - Options */
++_httpTLSSetOptions(int options, /* I - Options */
++ int min_version, /* I - Minimum TLS version */
++ int max_version) /* I - Maximum TLS version */
+ {
+ if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
+- tls_options = options;
++ {
++ tls_options = options;
++ tls_min_version = min_version;
++ tls_max_version = max_version;
++ }
+ }
+
+
+@@ -1245,6 +1253,16 @@ _httpTLSStart(http_t *http) /* I - Conn
+ /* TLS credentials */
+ char priority_string[2048];
+ /* Priority string */
++ int version; /* Current version */
++ static const char * const versions[] =/* SSL/TLS versions */
++ {
++ "VERS-SSL3.0",
++ "VERS-TLS1.0",
++ "VERS-TLS1.1",
++ "VERS-TLS1.2",
++ "VERS-TLS1.3",
++ "VERS-TLS-ALL"
++ };
+
+
+ DEBUG_printf(("3_httpTLSStart(http=%p)", http));
+@@ -1506,14 +1524,40 @@ _httpTLSStart(http_t *http) /* I - Conn
+
+ strlcpy(priority_string, "NORMAL", sizeof(priority_string));
+
+- if (tls_options & _HTTP_TLS_DENY_TLS10)
+- strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-TLS1.0:-VERS-SSL3.0", sizeof(priority_string));
+- else if (tls_options & _HTTP_TLS_ALLOW_SSL3)
++ if (tls_max_version < _HTTP_TLS_MAX)
++ {
++ /*
++ * Require specific TLS versions...
++ */
++
++ strlcat(priority_string, ":-VERS-TLS-ALL", sizeof(priority_string));
++ for (version = tls_min_version; version <= tls_max_version; version ++)
++ {
++ strlcat(priority_string, ":+", sizeof(priority_string));
++ strlcat(priority_string, versions[version], sizeof(priority_string));
++ }
++ }
++ else if (tls_min_version == _HTTP_TLS_SSL3)
++ {
++ /*
++ * Allow all versions of TLS and SSL/3.0...
++ */
++
+ strlcat(priority_string, ":+VERS-TLS-ALL:+VERS-SSL3.0", sizeof(priority_string));
+- else if (tls_options & _HTTP_TLS_ONLY_TLS10)
+- strlcat(priority_string, ":-VERS-TLS-ALL:-VERS-SSL3.0:+VERS-TLS1.0", sizeof(priority_string));
++ }
+ else
+- strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-SSL3.0", sizeof(priority_string));
++ {
++ /*
++ * Require a minimum version...
++ */
++
++ strlcat(priority_string, ":+VERS-TLS-ALL", sizeof(priority_string));
++ for (version = 0; version < tls_min_version; version ++)
++ {
++ strlcat(priority_string, ":-", sizeof(priority_string));
++ strlcat(priority_string, versions[version], sizeof(priority_string));
++ }
++ }
+
+ if (tls_options & _HTTP_TLS_ALLOW_RC4)
+ strlcat(priority_string, ":+ARCFOUR-128", sizeof(priority_string));
+diff -up cups-2.2.6/cups/tls-sspi.c.remove-weak-ciphers cups-2.2.6/cups/tls-sspi.c
+--- cups-2.2.6/cups/tls-sspi.c.remove-weak-ciphers 2017-11-01 15:57:53.000000000 +0100
++++ cups-2.2.6/cups/tls-sspi.c 2018-08-07 11:53:54.986633951 +0200
+@@ -52,7 +52,9 @@
+ * Local globals...
+ */
+
+-static int tls_options = -1;/* Options for TLS connections */
++static int tls_options = -1,/* Options for TLS connections */
++ tls_min_version = _HTTP_TLS_1_0,
++ tls_max_version = _HTTP_TLS_MAX;
+
+
+ /*
+@@ -914,7 +916,11 @@ void
+ _httpTLSSetOptions(int options) /* I - Options */
+ {
+ if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0)
+- tls_options = options;
++ {
++ tls_options = options;
++ tls_min_version = min_version;
++ tls_max_version = max_version;
++ }
+ }
+
+
+@@ -1782,14 +1788,14 @@ http_sspi_find_credentials(
+ #else
+ if (http->mode == _HTTP_MODE_SERVER)
+ {
+- if (tls_options & _HTTP_TLS_ALLOW_SSL3)
++ if (tls_min_version == _HTTP_TLS_SSL3)
+ SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER;
+ else
+ SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER;
+ }
+ else
+ {
+- if (tls_options & _HTTP_TLS_ALLOW_SSL3)
++ if (tls_min_version == _HTTP_TLS_SSL3)
+ SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT;
+ else
+ SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
+diff -up cups-2.2.6/cups/usersys.c.remove-weak-ciphers cups-2.2.6/cups/usersys.c
+--- cups-2.2.6/cups/usersys.c.remove-weak-ciphers 2018-08-07 11:53:54.945634283 +0200
++++ cups-2.2.6/cups/usersys.c 2018-08-07 11:53:54.987633942 +0200
+@@ -54,7 +54,9 @@
+ typedef struct _cups_client_conf_s /**** client.conf config data ****/
+ {
+ #ifdef HAVE_SSL
+- int ssl_options; /* SSLOptions values */
++ int ssl_options, /* SSLOptions values */
++ ssl_min_version,/* Minimum SSL/TLS version */
++ ssl_max_version;/* Maximum SSL/TLS version */
+ #endif /* HAVE_SSL */
+ int trust_first, /* Trust on first use? */
+ any_root, /* Allow any (e.g., self-signed) root */
+@@ -957,7 +959,7 @@ _cupsSetDefaults(void)
+ cg->validate_certs = cc.validate_certs;
+
+ #ifdef HAVE_SSL
+- _httpTLSSetOptions(cc.ssl_options | _HTTP_TLS_SET_DEFAULT);
++ _httpTLSSetOptions(cc.ssl_options | _HTTP_TLS_SET_DEFAULT, cc.ssl_min_version, cc.ssl_max_version);
+ #endif /* HAVE_SSL */
+ }
+
+@@ -1336,7 +1338,9 @@ cups_set_ssl_options(
+ * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None]
+ */
+
+- int options = _HTTP_TLS_NONE; /* SSL/TLS options */
++ int options = _HTTP_TLS_NONE, /* SSL/TLS options */
++ min_version = _HTTP_TLS_1_0, /* Minimum SSL/TLS version */
++ max_version = _HTTP_TLS_MAX; /* Maximum SSL/TLS version */
+ char temp[256], /* Copy of value */
+ *start, /* Start of option */
+ *end; /* End of option */
+@@ -1364,20 +1368,38 @@ cups_set_ssl_options(
+ if (!_cups_strcasecmp(start, "AllowRC4"))
+ options |= _HTTP_TLS_ALLOW_RC4;
+ else if (!_cups_strcasecmp(start, "AllowSSL3"))
+- options |= _HTTP_TLS_ALLOW_SSL3;
++ min_version = _HTTP_TLS_SSL3;
+ else if (!_cups_strcasecmp(start, "AllowDH"))
+ options |= _HTTP_TLS_ALLOW_DH;
+ else if (!_cups_strcasecmp(start, "DenyCBC"))
+ options |= _HTTP_TLS_DENY_CBC;
+ else if (!_cups_strcasecmp(start, "DenyTLS1.0"))
+- options |= _HTTP_TLS_DENY_TLS10;
++ min_version = _HTTP_TLS_1_1;
++ else if (!_cups_strcasecmp(start, "MaxTLS1.0"))
++ max_version = _HTTP_TLS_1_0;
++ else if (!_cups_strcasecmp(start, "MaxTLS1.1"))
++ max_version = _HTTP_TLS_1_1;
++ else if (!_cups_strcasecmp(start, "MaxTLS1.2"))
++ max_version = _HTTP_TLS_1_2;
++ else if (!_cups_strcasecmp(start, "MaxTLS1.3"))
++ max_version = _HTTP_TLS_1_3;
++ else if (!_cups_strcasecmp(start, "MinTLS1.0"))
++ min_version = _HTTP_TLS_1_0;
++ else if (!_cups_strcasecmp(start, "MinTLS1.1"))
++ min_version = _HTTP_TLS_1_1;
++ else if (!_cups_strcasecmp(start, "MinTLS1.2"))
++ min_version = _HTTP_TLS_1_2;
++ else if (!_cups_strcasecmp(start, "MinTLS1.3"))
++ min_version = _HTTP_TLS_1_3;
+ else if (!_cups_strcasecmp(start, "None"))
+ options = _HTTP_TLS_NONE;
+ }
+
+- cc->ssl_options = options;
++ cc->ssl_options = options;
++ cc->ssl_max_version = max_version;
++ cc->ssl_min_version = min_version;
+
+- DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x", (void *)cc, value, options));
++ DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x, min_version=%d, max_version=%d", (void *)cc, value, options, min_version, max_version));
+ }
+ #endif /* HAVE_SSL */
+
+diff -up cups-2.2.6/man/client.conf.man.in.remove-weak-ciphers cups-2.2.6/man/client.conf.man.in
+--- cups-2.2.6/man/client.conf.man.in.remove-weak-ciphers 2017-11-01 15:57:53.000000000 +0100
++++ cups-2.2.6/man/client.conf.man.in 2018-08-07 11:53:54.987633942 +0200
+@@ -10,7 +10,7 @@
+ .\" which should have been included with this file. If this file is
+ .\" file is missing or damaged, see the license at "http://www.cups.org/".
+ .\"
+-.TH client.conf 5 "CUPS" "19 October 2017" "Apple Inc."
++.TH client.conf 5 "CUPS" "3 November 2017" "Apple Inc."
+ .SH NAME
+ client.conf \- client configuration file for cups
+ .SH DESCRIPTION
+@@ -56,7 +56,7 @@ Specifies the address and optionally the
+ \fBServerName \fIhostname-or-ip-address\fR[\fI:port\fR]\fB/version=1.1\fR
+ Specifies the address and optionally the port to use when connecting to a server running CUPS 1.3.12 and earlier.
+ .TP 5
+-\fBSSLOptions \fR[\fIAllowDH\fR] [\fIAllowRC4\fR] [\fIAllowSSL3\fR] [\fIDenyCBC\fR] [\fIDenyTLS1.0\fR]
++\fBSSLOptions \fR[\fIAllowDH\fR] [\fIAllowRC4\fR] [\fIAllowSSL3\fR] [\fIDenyCBC\fR] [\fIDenyTLS1.0\fR] [\fIMaxTLS1.0\fR] [\fIMaxTLS1.1\fR] [\fIMaxTLS1.2\fR] [\fIMaxTLS1.3\fR] [\fIMinTLS1.0\fR] [\fIMinTLS1.1\fR] [\fIMinTLS1.2\fR] [\fIMinTLS1.3\fR]
+ .TP 5
+ \fBSSLOptions None\fR
+ Sets encryption options (only in /etc/cups/client.conf).
+@@ -68,6 +68,9 @@ The \fIAllowRC4\fR option enables the 12
+ The \fIAllowSSL3\fR option enables SSL v3.0, which is required for some older clients that do not support TLS v1.0.
+ The \fIDenyCBC\fR option disables all CBC cipher suites.
+ The \fIDenyTLS1.0\fR option disables TLS v1.0 support - this sets the minimum protocol version to TLS v1.1.
++The \fMinTLS\fR options set the minimum TLS version to support.
++The \fMaxTLS\fR options set the maximum TLS version to support.
++Not all operating systems support TLS 1.3 at this time.
+ .TP 5
+ \fBTrustOnFirstUse Yes\fR
+ .TP 5
+diff -up cups-2.2.6/man/cupsd.conf.man.in.remove-weak-ciphers cups-2.2.6/man/cupsd.conf.man.in
+--- cups-2.2.6/man/cupsd.conf.man.in.remove-weak-ciphers 2018-08-07 11:53:54.981633991 +0200
++++ cups-2.2.6/man/cupsd.conf.man.in 2018-08-07 11:53:54.987633942 +0200
+@@ -432,10 +432,11 @@ The default is "Minimal".
+ Listens on the specified address and port for encrypted connections.
+ .\"#SSLOptions
+ .TP 5
+-\fBSSLOptions \fR[\fIAllowDH\fR] [\fIAllowRC4\fR] [\fIAllowSSL3\fR] [\fIDenyCBC\fR] [\fIDenyTLS1.0\fR]
++.TP 5
++\fBSSLOptions \fR[\fIAllowDH\fR] [\fIAllowRC4\fR] [\fIAllowSSL3\fR] [\fIDenyCBC\fR] [\fIDenyTLS1.0\fR] [\fIMaxTLS1.0\fR] [\fIMaxTLS1.1\fR] [\fIMaxTLS1.2\fR] [\fIMaxTLS1.3\fR] [\fIMinTLS1.0\fR] [\fIMinTLS1.1\fR] [\fIMinTLS1.2\fR] [\fIMinTLS1.3\fR]
+ .TP 5
+ \fBSSLOptions None\fR
+-Sets encryption options.
++Sets encryption options (only in /etc/cups/client.conf).
+ By default, CUPS only supports encryption using TLS v1.0 or higher using known secure cipher suites.
+ Security is reduced when \fIAllow\fR options are used.
+ Security is enhanced when \fIDeny\fR options are used.
+@@ -444,6 +445,9 @@ The \fIAllowRC4\fR option enables the 12
+ The \fIAllowSSL3\fR option enables SSL v3.0, which is required for some older clients that do not support TLS v1.0.
+ The \fIDenyCBC\fR option disables all CBC cipher suites.
+ The \fIDenyTLS1.0\fR option disables TLS v1.0 support - this sets the minimum protocol version to TLS v1.1.
++The \fMinTLS\fR options set the minimum TLS version to support.
++The \fMaxTLS\fR options set the maximum TLS version to support.
++Not all operating systems support TLS 1.3 at this time.
+ .\"#SSLPort
+ .TP 5
+ \fBSSLPort \fIport\fR
+diff -up cups-2.2.6/scheduler/conf.c.remove-weak-ciphers cups-2.2.6/scheduler/conf.c
+--- cups-2.2.6/scheduler/conf.c.remove-weak-ciphers 2018-08-07 11:53:54.981633991 +0200
++++ cups-2.2.6/scheduler/conf.c 2018-08-07 11:53:54.988633934 +0200
+@@ -630,7 +630,7 @@ cupsdReadConfiguration(void)
+ cupsdSetString(&ServerKeychain, "/Library/Keychains/System.keychain");
+ # endif /* HAVE_GNUTLS */
+
+- _httpTLSSetOptions(0);
++ _httpTLSSetOptions(_HTTP_TLS_NONE, _HTTP_TLS_1_0, _HTTP_TLS_MAX);
+ #endif /* HAVE_SSL */
+
+ language = cupsLangDefault();
+@@ -3024,7 +3024,9 @@ read_cupsd_conf(cups_file_t *fp) /* I -
+ * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyCBC] [DenyTLS1.0] [None]
+ */
+
+- int options = 0; /* SSL/TLS options */
++ int options = _HTTP_TLS_NONE,/* SSL/TLS options */
++ min_version = _HTTP_TLS_1_0,
++ max_version = _HTTP_TLS_MAX;
+
+ if (value)
+ {
+@@ -3048,24 +3050,40 @@ read_cupsd_conf(cups_file_t *fp) /* I -
+ * Compare...
+ */
+
+- if (!_cups_strcasecmp(start, "AllowRC4"))
++ if (!_cups_strcasecmp(start, "AllowRC4"))
+ options |= _HTTP_TLS_ALLOW_RC4;
+- else if (!_cups_strcasecmp(start, "AllowSSL3"))
+- options |= _HTTP_TLS_ALLOW_SSL3;
++ else if (!_cups_strcasecmp(start, "AllowSSL3"))
++ min_version = _HTTP_TLS_SSL3;
+ else if (!_cups_strcasecmp(start, "AllowDH"))
+ options |= _HTTP_TLS_ALLOW_DH;
+ else if (!_cups_strcasecmp(start, "DenyCBC"))
+ options |= _HTTP_TLS_DENY_CBC;
+ else if (!_cups_strcasecmp(start, "DenyTLS1.0"))
+- options |= _HTTP_TLS_DENY_TLS10;
+- else if (!_cups_strcasecmp(start, "None"))
+- options = 0;
++ min_version = _HTTP_TLS_1_1;
++ else if (!_cups_strcasecmp(start, "MaxTLS1.0"))
++ max_version = _HTTP_TLS_1_0;
++ else if (!_cups_strcasecmp(start, "MaxTLS1.1"))
++ max_version = _HTTP_TLS_1_1;
++ else if (!_cups_strcasecmp(start, "MaxTLS1.2"))
++ max_version = _HTTP_TLS_1_2;
++ else if (!_cups_strcasecmp(start, "MaxTLS1.3"))
++ max_version = _HTTP_TLS_1_3;
++ else if (!_cups_strcasecmp(start, "MinTLS1.0"))
++ min_version = _HTTP_TLS_1_0;
++ else if (!_cups_strcasecmp(start, "MinTLS1.1"))
++ min_version = _HTTP_TLS_1_1;
++ else if (!_cups_strcasecmp(start, "MinTLS1.2"))
++ min_version = _HTTP_TLS_1_2;
++ else if (!_cups_strcasecmp(start, "MinTLS1.3"))
++ min_version = _HTTP_TLS_1_3;
++ else if (!_cups_strcasecmp(start, "None"))
++ options = _HTTP_TLS_NONE;
+ else if (_cups_strcasecmp(start, "NoEmptyFragments"))
+ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown SSL option %s at line %d.", start, linenum);
+ }
+ }
+
+- _httpTLSSetOptions(options);
++ _httpTLSSetOptions(options, min_version, max_version);
+ }
+ #endif /* HAVE_SSL */
+ else if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")
diff --git a/SOURCES/0001-CVE-2018-4700-Linux-session-cookies-used-a-predictab.patch b/SOURCES/0001-CVE-2018-4700-Linux-session-cookies-used-a-predictab.patch
new file mode 100644
index 0000000..2745b5d
--- /dev/null
+++ b/SOURCES/0001-CVE-2018-4700-Linux-session-cookies-used-a-predictab.patch
@@ -0,0 +1,22 @@
+diff --git a/cgi-bin/var.c b/cgi-bin/var.c
+index 316b67f05..12f3c8344 100644
+--- a/cgi-bin/var.c
++++ b/cgi-bin/var.c
+@@ -1186,6 +1186,7 @@ cgi_set_sid(void)
+ const char *remote_addr, /* REMOTE_ADDR */
+ *server_name, /* SERVER_NAME */
+ *server_port; /* SERVER_PORT */
++ struct timeval curtime; /* Current time */
+
+
+ if ((remote_addr = getenv("REMOTE_ADDR")) == NULL)
+@@ -1195,7 +1196,8 @@ cgi_set_sid(void)
+ if ((server_port = getenv("SERVER_PORT")) == NULL)
+ server_port = "SERVER_PORT";
+
+- CUPS_SRAND(time(NULL));
++ gettimeofday(&curtime, NULL);
++ CUPS_SRAND(curtime.tv_sec + curtime.tv_usec);
+ snprintf(buffer, sizeof(buffer), "%s:%s:%s:%02X%02X%02X%02X%02X%02X%02X%02X",
+ remote_addr, server_name, server_port,
+ (unsigned)CUPS_RAND() & 255, (unsigned)CUPS_RAND() & 255,
diff --git a/SOURCES/0001-Fix-default-TLS-versions.patch b/SOURCES/0001-Fix-default-TLS-versions.patch
new file mode 100644
index 0000000..b3821d6
--- /dev/null
+++ b/SOURCES/0001-Fix-default-TLS-versions.patch
@@ -0,0 +1,24 @@
+diff -up cups-2.2.6/cups/usersys.c.defaulttls cups-2.2.6/cups/usersys.c
+--- cups-2.2.6/cups/usersys.c.defaulttls 2018-09-03 12:10:36.111230611 +0200
++++ cups-2.2.6/cups/usersys.c 2018-09-03 12:12:41.307074414 +0200
+@@ -1166,11 +1166,15 @@ cups_init_client_conf(
+
+ memset(cc, 0, sizeof(_cups_client_conf_t));
+
+- cc->encryption = (http_encryption_t)-1;
+- cc->trust_first = -1;
+- cc->any_root = -1;
+- cc->expired_certs = -1;
+- cc->validate_certs = -1;
++#ifdef HAVE_SSL
++ cc->ssl_min_version = _HTTP_TLS_1_0;
++ cc->ssl_max_version = _HTTP_TLS_MAX;
++#endif /* HAVE_SSL */
++ cc->encryption = (http_encryption_t)-1;
++ cc->trust_first = -1;
++ cc->any_root = -1;
++ cc->expired_certs = -1;
++ cc->validate_certs = -1;
+
+ /*
+ * Load settings from the org.cups.PrintingPrefs plist (which trump
diff --git a/SOURCES/0001-Fix-local-privilege-escalation-to-root-and-sandbox-b.patch b/SOURCES/0001-Fix-local-privilege-escalation-to-root-and-sandbox-b.patch
new file mode 100644
index 0000000..dfb74a1
--- /dev/null
+++ b/SOURCES/0001-Fix-local-privilege-escalation-to-root-and-sandbox-b.patch
@@ -0,0 +1,481 @@
+From d47f6aec436e0e9df6554436e391471097686ecc Mon Sep 17 00:00:00 2001
+From: Michael R Sweet
+Date: Tue, 8 May 2018 15:24:21 -0700
+Subject: [PATCH] Fix local privilege escalation to root and sandbox bypasses
+ in scheduler (rdar://37836779, rdar://37836995, rdar://37837252,
+ rdar://37837581)
+
+---
+ man/cups-files.conf.man.in | 10 ++
+ man/cupsd.conf.man.in | 8 --
+ scheduler/conf.c | 201 +++++++++++++++++++++++--------------
+ scheduler/job.c | 12 +++
+ scheduler/process.c | 16 +--
+ scheduler/server.c | 20 +++-
+ test/run-stp-tests.sh | 11 +-
+ 7 files changed, 179 insertions(+), 99 deletions(-)
+
+diff --git a/man/cups-files.conf.man.in b/man/cups-files.conf.man.in
+index 7b96d687d..baf3cb6af 100644
+--- a/man/cups-files.conf.man.in
++++ b/man/cups-files.conf.man.in
+@@ -153,6 +153,11 @@ The server name may be included in filenames using the string "%s", for example:
+
+ .fi
+ The default is "/var/log/cups/page_log".
++.\"#PassEnv
++.TP 5
++\fBPassEnv \fIvariable \fR[ ... \fIvariable \fR]
++Passes the specified environment variable(s) to child processes.
++Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive.
+ .\"#RemoteRoot
+ .TP 5
+ \fBRemoteRoot \fIusername\fR
+@@ -187,6 +192,11 @@ macOS uses its keychain database to store certificates and keys while other plat
+ \fBServerRoot \fIdirectory\fR
+ Specifies the directory containing the server configuration files.
+ The default is "/etc/cups".
++.\"#SetEnv
++.TP 5
++\fBSetEnv \fIvariable value\fR
++Set the specified environment variable to be passed to child processes.
++Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive.
+ .\"#StateDir
+ .TP 5
+ \fBStateDir \fIdirectory\fR
+diff --git a/man/cupsd.conf.man.in b/man/cupsd.conf.man.in
+index 3ffc80e42..36c849398 100644
+--- a/man/cupsd.conf.man.in
++++ b/man/cupsd.conf.man.in
+@@ -349,10 +349,6 @@ The default is "1048576" (1MB).
+ \fBMultipleOperationTimeout \fIseconds\fR
+ Specifies the maximum amount of time to allow between files in a multiple file print job.
+ The default is "300" (5 minutes).
+-.\"#PassEnv
+-.TP 5
+-\fBPassEnv \fIvariable \fR[ ... \fIvariable \fR]
+-Passes the specified environment variable(s) to child processes.
+ .\"#Policy
+ .TP 5
+ \fB \fR... \fB\fR
+@@ -433,10 +429,6 @@ Specifies what information is included in the Server header of HTTP responses.
+ command.
+ "Full" reports "CUPS 2.0.0 (UNAME) IPP/2.0".
+ The default is "Minimal".
+-.\"#SetEnv
+-.TP 5
+-\fBSetEnv \fIvariable value\fR
+-Set the specified environment variable to be passed to child processes.
+ .\"#SSLListen
+ .TP 5
+ \fBSSLListen \fIipv4-address\fB:\fIport\fR
+diff --git a/scheduler/conf.c b/scheduler/conf.c
+index 67a91e7a6..b51c6060c 100644
+--- a/scheduler/conf.c
++++ b/scheduler/conf.c
+@@ -2929,13 +2929,10 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
+ /* Line from file */
+ temp[HTTP_MAX_BUFFER],
+ /* Temporary buffer for value */
+- *value, /* Pointer to value */
+- *valueptr; /* Pointer into value */
++ *value; /* Pointer to value */
+ int valuelen; /* Length of value */
+ http_addrlist_t *addrlist, /* Address list */
+ *addr; /* Current address */
+- cups_file_t *incfile; /* Include file */
+- char incname[1024]; /* Include filename */
+
+
+ /*
+@@ -2950,28 +2947,7 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
+ * Decode the directive...
+ */
+
+- if (!_cups_strcasecmp(line, "Include") && value)
+- {
+- /*
+- * Include filename
+- */
+-
+- if (value[0] == '/')
+- strlcpy(incname, value, sizeof(incname));
+- else
+- snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value);
+-
+- if ((incfile = cupsFileOpen(incname, "rb")) == NULL)
+- cupsdLogMessage(CUPSD_LOG_ERROR,
+- "Unable to include config file \"%s\" - %s",
+- incname, strerror(errno));
+- else
+- {
+- read_cupsd_conf(incfile);
+- cupsFileClose(incfile);
+- }
+- }
+- else if (!_cups_strcasecmp(line, "
+@@ -3367,31 +3343,6 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
+ cupsdLogMessage(CUPSD_LOG_WARN, "Unknown ServerTokens %s on line %d of %s.",
+ value, linenum, ConfigurationFile);
+ }
+- else if (!_cups_strcasecmp(line, "PassEnv") && value)
+- {
+- /*
+- * PassEnv variable [... variable]
+- */
+-
+- for (; *value;)
+- {
+- for (valuelen = 0; value[valuelen]; valuelen ++)
+- if (_cups_isspace(value[valuelen]) || value[valuelen] == ',')
+- break;
+-
+- if (value[valuelen])
+- {
+- value[valuelen] = '\0';
+- valuelen ++;
+- }
+-
+- cupsdSetEnv(value, NULL);
+-
+- for (value += valuelen; *value; value ++)
+- if (!_cups_isspace(*value) || *value != ',')
+- break;
+- }
+- }
+ else if (!_cups_strcasecmp(line, "ServerAlias") && value)
+ {
+ /*
+@@ -3420,30 +3371,6 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
+ break;
+ }
+ }
+- else if (!_cups_strcasecmp(line, "SetEnv") && value)
+- {
+- /*
+- * SetEnv variable value
+- */
+-
+- for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
+-
+- if (*valueptr)
+- {
+- /*
+- * Found a value...
+- */
+-
+- while (isspace(*valueptr & 255))
+- *valueptr++ = '\0';
+-
+- cupsdSetEnv(value, valueptr);
+- }
+- else
+- cupsdLogMessage(CUPSD_LOG_ERROR,
+- "Missing value for SetEnv directive on line %d of %s.",
+- linenum, ConfigurationFile);
+- }
+ else if (!_cups_strcasecmp(line, "AccessLog") ||
+ !_cups_strcasecmp(line, "CacheDir") ||
+ !_cups_strcasecmp(line, "ConfigFilePerm") ||
+@@ -3457,6 +3384,7 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
+ !_cups_strcasecmp(line, "LogFilePerm") ||
+ !_cups_strcasecmp(line, "LPDConfigFile") ||
+ !_cups_strcasecmp(line, "PageLog") ||
++ !_cups_strcasecmp(line, "PassEnv") ||
+ !_cups_strcasecmp(line, "Printcap") ||
+ !_cups_strcasecmp(line, "PrintcapFormat") ||
+ !_cups_strcasecmp(line, "RemoteRoot") ||
+@@ -3466,6 +3394,7 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
+ !_cups_strcasecmp(line, "ServerKey") ||
+ !_cups_strcasecmp(line, "ServerKeychain") ||
+ !_cups_strcasecmp(line, "ServerRoot") ||
++ !_cups_strcasecmp(line, "SetEnv") ||
+ !_cups_strcasecmp(line, "SMBConfigFile") ||
+ !_cups_strcasecmp(line, "StateDir") ||
+ !_cups_strcasecmp(line, "SystemGroup") ||
+@@ -3495,10 +3424,49 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
+ static int /* O - 1 on success, 0 on failure */
+ read_cups_files_conf(cups_file_t *fp) /* I - File to read from */
+ {
+- int linenum; /* Current line number */
++ int i, /* Looping var */
++ linenum; /* Current line number */
+ char line[HTTP_MAX_BUFFER], /* Line from file */
+ *value; /* Value from line */
+ struct group *group; /* Group */
++ static const char * const prohibited_env[] =
++ { /* Prohibited environment variables */
++ "APPLE_LANGUAGE",
++ "AUTH_DOMAIN",
++ "AUTH_INFO_REQUIRED",
++ "AUTH_NEGOTIATE",
++ "AUTH_PASSWORD",
++ "AUTH_UID",
++ "AUTH_USERNAME",
++ "CHARSET",
++ "CLASS",
++ "CLASSIFICATION",
++ "CONTENT_TYPE",
++ "CUPS_CACHEDIR",
++ "CUPS_DATADIR",
++ "CUPS_DOCROOT",
++ "CUPS_FILETYPE",
++ "CUPS_FONTPATH",
++ "CUPS_MAX_MESSAGE",
++ "CUPS_REQUESTROOT",
++ "CUPS_SERVERBIN",
++ "CUPS_SERVERROOT",
++ "CUPS_STATEDIR",
++ "DEVICE_URI",
++ "FINAL_CONTENT_TYPE",
++ "HOME",
++ "LANG",
++ "PPD",
++ "PRINTER",
++ "PRINTER_INFO",
++ "PRINTER_LOCATION",
++ "PRINTER_STATE_REASONS",
++ "RIP_CACHE",
++ "SERVER_ADMIN",
++ "SOFTWARE",
++ "TMPDIR",
++ "USER"
++ };
+
+
+ /*
+@@ -3536,6 +3504,47 @@ read_cups_files_conf(cups_file_t *fp) /* I - File to read from */
+ }
+ }
+ }
++ else if (!_cups_strcasecmp(line, "PassEnv") && value)
++ {
++ /*
++ * PassEnv variable [... variable]
++ */
++
++ int valuelen; /* Length of variable name */
++
++ for (; *value;)
++ {
++ for (valuelen = 0; value[valuelen]; valuelen ++)
++ if (_cups_isspace(value[valuelen]) || value[valuelen] == ',')
++ break;
++
++ if (value[valuelen])
++ {
++ value[valuelen] = '\0';
++ valuelen ++;
++ }
++
++ for (i = 0; i < (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])); i ++)
++ {
++ if (!strcmp(value, prohibited_env[i]))
++ {
++ cupsdLogMessage(CUPSD_LOG_ERROR, "Environment variable \"%s\" cannot be passed through on line %d of %s.", value, linenum, CupsFilesFile);
++
++ if (FatalErrors & CUPSD_FATAL_CONFIG)
++ return (0);
++ else
++ break;
++ }
++ }
++
++ if (i >= (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])))
++ cupsdSetEnv(value, NULL);
++
++ for (value += valuelen; *value; value ++)
++ if (!_cups_isspace(*value) || *value != ',')
++ break;
++ }
++ }
+ else if (!_cups_strcasecmp(line, "PrintcapFormat") && value)
+ {
+ /*
+@@ -3581,6 +3590,46 @@ read_cups_files_conf(cups_file_t *fp) /* I - File to read from */
+ return (0);
+ }
+ }
++ else if (!_cups_strcasecmp(line, "SetEnv") && value)
++ {
++ /*
++ * SetEnv variable value
++ */
++
++ char *valueptr; /* Pointer to environment variable value */
++
++ for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
++
++ if (*valueptr)
++ {
++ /*
++ * Found a value...
++ */
++
++ while (isspace(*valueptr & 255))
++ *valueptr++ = '\0';
++
++ for (i = 0; i < (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])); i ++)
++ {
++ if (!strcmp(value, prohibited_env[i]))
++ {
++ cupsdLogMessage(CUPSD_LOG_ERROR, "Environment variable \"%s\" cannot be set on line %d of %s.", value, linenum, CupsFilesFile);
++
++ if (FatalErrors & CUPSD_FATAL_CONFIG)
++ return (0);
++ else
++ break;
++ }
++ }
++
++ if (i >= (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])))
++ cupsdSetEnv(value, valueptr);
++ }
++ else
++ cupsdLogMessage(CUPSD_LOG_ERROR,
++ "Missing value for SetEnv directive on line %d of %s.",
++ linenum, ConfigurationFile);
++ }
+ else if (!_cups_strcasecmp(line, "SystemGroup") && value)
+ {
+ /*
+diff --git a/scheduler/job.c b/scheduler/job.c
+index 61cda44e2..5ced0b9d1 100644
+--- a/scheduler/job.c
++++ b/scheduler/job.c
+@@ -4779,6 +4779,18 @@ start_job(cupsd_job_t *job, /* I - Job ID */
+ job->profile = cupsdCreateProfile(job->id, 0);
+ job->bprofile = cupsdCreateProfile(job->id, 1);
+
++#ifdef HAVE_SANDBOX_H
++ if ((!job->profile || !job->bprofile) && UseSandboxing && Sandboxing != CUPSD_SANDBOXING_OFF)
++ {
++ /*
++ * Failure to create the sandbox profile means something really bad has
++ * happened and we need to shutdown immediately.
++ */
++
++ return;
++ }
++#endif /* HAVE_SANDBOX_H */
++
+ /*
+ * Create the status pipes and buffer...
+ */
+diff --git a/scheduler/process.c b/scheduler/process.c
+index b8d49d8f0..3c1c6ba4f 100644
+--- a/scheduler/process.c
++++ b/scheduler/process.c
+@@ -98,9 +98,13 @@ cupsdCreateProfile(int job_id, /* I - Job ID or 0 for none */
+
+ if ((fp = cupsTempFile2(profile, sizeof(profile))) == NULL)
+ {
++ /*
++ * This should never happen, and is fatal when sandboxing is enabled.
++ */
++
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d, allow_networking=%d) = NULL", job_id, allow_networking);
+- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create security profile: %s",
+- strerror(errno));
++ cupsdLogMessage(CUPSD_LOG_EMERG, "Unable to create security profile: %s", strerror(errno));
++ kill(getpid(), SIGTERM);
+ return (NULL);
+ }
+
+@@ -197,10 +201,8 @@ cupsdCreateProfile(int job_id, /* I - Job ID or 0 for none */
+ " #\"^%s/\"" /* TempDir/... */
+ " #\"^%s$\"" /* CacheDir */
+ " #\"^%s/\"" /* CacheDir/... */
+- " #\"^%s$\"" /* StateDir */
+- " #\"^%s/\"" /* StateDir/... */
+ "))\n",
+- temp, temp, cache, cache, state, state);
++ temp, temp, cache, cache);
+ /* Read common folders */
+ cupsFilePrintf(fp,
+ "(allow file-read-data file-read-metadata\n"
+@@ -242,8 +244,10 @@ cupsdCreateProfile(int job_id, /* I - Job ID or 0 for none */
+ " #\"^%s/\"" /* ServerBin/... */
+ " #\"^%s$\"" /* ServerRoot */
+ " #\"^%s/\"" /* ServerRoot/... */
++ " #\"^%s$\"" /* StateDir */
++ " #\"^%s/\"" /* StateDir/... */
+ "))\n",
+- request, request, bin, bin, root, root);
++ request, request, bin, bin, root, root, state, state);
+ if (Sandboxing == CUPSD_SANDBOXING_RELAXED)
+ {
+ /* Limited write access to /Library/Printers/... */
+diff --git a/scheduler/server.c b/scheduler/server.c
+index cecbabe67..a4033791b 100644
+--- a/scheduler/server.c
++++ b/scheduler/server.c
+@@ -34,16 +34,28 @@ void
+ cupsdStartServer(void)
+ {
+ /*
+- * Start color management (as needed)...
++ * Create the default security profile...
+ */
+
+- cupsdStartColor();
++ DefaultProfile = cupsdCreateProfile(0, 1);
++
++#ifdef HAVE_SANDBOX_H
++ if (!DefaultProfile && UseSandboxing && Sandboxing != CUPSD_SANDBOXING_OFF)
++ {
++ /*
++ * Failure to create the sandbox profile means something really bad has
++ * happened and we need to shutdown immediately.
++ */
++
++ return;
++ }
++#endif /* HAVE_SANDBOX_H */
+
+ /*
+- * Create the default security profile...
++ * Start color management (as needed)...
+ */
+
+- DefaultProfile = cupsdCreateProfile(0, 1);
++ cupsdStartColor();
+
+ /*
+ * Startup all the networking stuff...
+diff --git a/test/run-stp-tests.sh b/test/run-stp-tests.sh
+index 7eb269a67..f83bd5d91 100755
+--- a/test/run-stp-tests.sh
++++ b/test/run-stp-tests.sh
+@@ -489,11 +489,6 @@ StrictConformance Yes
+ Browsing Off
+ Listen localhost:$port
+ Listen $BASE/sock
+-PassEnv DYLD_LIBRARY_PATH
+-PassEnv LD_LIBRARY_PATH
+-PassEnv LD_PRELOAD
+-PassEnv LOCALEDIR
+-PassEnv SHLIB_PATH
+ MaxSubscriptions 3
+ MaxLogSize 0
+ AccessLogLevel actions
+@@ -529,6 +524,12 @@ TempDir $BASE/spool/temp
+ AccessLog $BASE/log/access_log
+ ErrorLog $BASE/log/error_log
+ PageLog $BASE/log/page_log
++
++PassEnv DYLD_LIBRARY_PATH
++PassEnv LD_LIBRARY_PATH
++PassEnv LD_PRELOAD
++PassEnv LOCALEDIR
++PassEnv SHLIB_PATH
+ EOF
+
+ if test $ssltype != 0 -a `uname` = Darwin; then
+--
+2.17.1
+
diff --git a/SOURCES/0001-Fix-memory-leaks-found-by-Coverity-Issue-5375.patch b/SOURCES/0001-Fix-memory-leaks-found-by-Coverity-Issue-5375.patch
new file mode 100644
index 0000000..ec224c3
--- /dev/null
+++ b/SOURCES/0001-Fix-memory-leaks-found-by-Coverity-Issue-5375.patch
@@ -0,0 +1,206 @@
+diff --git a/backend/ipp.c b/backend/ipp.c
+index 32eb3aaa4..2a880bd75 100644
+--- a/backend/ipp.c
++++ b/backend/ipp.c
+@@ -3612,6 +3612,8 @@ update_reasons(ipp_attribute_t *attr, /* I - printer-state-reasons or NULL */
+ }
+ }
+
++ cupsArrayDelete(new_reasons);
++
+ _cupsMutexUnlock(&report_mutex);
+
+ /*
+diff --git a/cgi-bin/search.c b/cgi-bin/search.c
+index 3956afc33..ad1f5ed0e 100644
+--- a/cgi-bin/search.c
++++ b/cgi-bin/search.c
+@@ -361,4 +362,5 @@ void
+ cgiFreeSearch(void *search) /* I - Search context */
+ {
+ regfree((regex_t *)search);
++ free(search);
+ }
+diff --git a/cups/http-addrlist.c b/cups/http-addrlist.c
+index 5d510140b..688901a7d 100644
+--- a/cups/http-addrlist.c
++++ b/cups/http-addrlist.c
+@@ -612,6 +613,7 @@ httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for p
+ if (!temp)
+ {
+ httpAddrFreeList(first);
++ freeaddrinfo(results);
+ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
+ return (NULL);
+ }
+diff --git a/cups/http.c b/cups/http.c
+index a9235b087..d9332cc83 100644
+--- a/cups/http.c
++++ b/cups/http.c
+@@ -3915,7 +3915,7 @@ http_create(
+ if ((http = calloc(sizeof(http_t), 1)) == NULL)
+ {
+ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
+- httpAddrFreeList(addrlist);
++ httpAddrFreeList(myaddrlist);
+ return (NULL);
+ }
+
+diff --git a/ppdc/ppdc-source.cxx b/ppdc/ppdc-source.cxx
+index be24cebae..4e8cba7bb 100644
+--- a/ppdc/ppdc-source.cxx
++++ b/ppdc/ppdc-source.cxx
+@@ -2665,6 +2666,7 @@ ppdcSource::scan_file(ppdcFile *fp, // I - File to read
+ // Add it to the current option...
+ if (!o)
+ {
++ c->release();
+ _cupsLangPrintf(stderr,
+ _("ppdc: Choice found on line %d of %s with no "
+ "Option."), fp->line, fp->filename);
+diff --git a/scheduler/cups-driverd.cxx b/scheduler/cups-driverd.cxx
+index 657eee0a0..b518a9325 100644
+--- a/scheduler/cups-driverd.cxx
++++ b/scheduler/cups-driverd.cxx
+@@ -153,7 +153,7 @@ static ppd_info_t *add_ppd(const char *filename, const char *name,
+ size_t size, int model_number, int type,
+ const char *scheme);
+ static int cat_drv(const char *name, int request_id);
+-static int cat_ppd(const char *name, int request_id);
++static void cat_ppd(const char *name, int request_id);
+ static int cat_static(const char *name, int request_id);
+ static int cat_tar(const char *name, int request_id);
+ static int compare_inodes(struct stat *a, struct stat *b);
+@@ -163,12 +163,12 @@ static int compare_names(const ppd_info_t *p0,
+ const ppd_info_t *p1);
+ static int compare_ppds(const ppd_info_t *p0,
+ const ppd_info_t *p1);
+-static int dump_ppds_dat(const char *filename);
++static void dump_ppds_dat(const char *filename);
+ static void free_array(cups_array_t *a);
+ static cups_file_t *get_file(const char *name, int request_id,
+ const char *subdir, char *buffer,
+ size_t bufsize, char **subfile);
+-static int list_ppds(int request_id, int limit, const char *opt);
++static void list_ppds(int request_id, int limit, const char *opt);
+ static int load_drivers(cups_array_t *include,
+ cups_array_t *exclude);
+ static int load_drv(const char *filename, const char *name,
+@@ -204,13 +204,13 @@ main(int argc, /* I - Number of command-line args */
+ */
+
+ if (argc == 3 && !strcmp(argv[1], "cat"))
+- return (cat_ppd(argv[2], 0));
++ cat_ppd(argv[2], 0);
+ else if ((argc == 2 || argc == 3) && !strcmp(argv[1], "dump"))
+- return (dump_ppds_dat(argv[2]));
++ dump_ppds_dat(argv[2]);
+ else if (argc == 4 && !strcmp(argv[1], "get"))
+- return (cat_ppd(argv[3], atoi(argv[2])));
++ cat_ppd(argv[3], atoi(argv[2]));
+ else if (argc == 5 && !strcmp(argv[1], "list"))
+- return (list_ppds(atoi(argv[2]), atoi(argv[3]), argv[4]));
++ list_ppds(atoi(argv[2]), atoi(argv[3]), argv[4]);
+ else
+ {
+ fputs("Usage: cups-driverd cat ppd-name\n", stderr);
+@@ -428,7 +428,7 @@ cat_drv(const char *name, /* I - PPD name */
+ * 'cat_ppd()' - Copy a PPD file to stdout.
+ */
+
+-static int /* O - Exit code */
++static void
+ cat_ppd(const char *name, /* I - PPD name */
+ int request_id) /* I - Request ID for response? */
+ {
+@@ -445,7 +445,7 @@ cat_ppd(const char *name, /* I - PPD name */
+ if (strstr(name, "../"))
+ {
+ fputs("ERROR: Invalid PPD name.\n", stderr);
+- return (1);
++ exit(1);
+ }
+
+ strlcpy(scheme, name, sizeof(scheme));
+@@ -475,11 +475,11 @@ cat_ppd(const char *name, /* I - PPD name */
+ puts("Content-Type: application/ipp\n");
+
+ if (!scheme[0])
+- return (cat_static(name, request_id));
++ exit(cat_static(name, request_id));
+ else if (!strcmp(scheme, "drv"))
+- return (cat_drv(name, request_id));
++ exit(cat_drv(name, request_id));
+ else if (!strcmp(scheme, "file"))
+- return (cat_tar(name, request_id));
++ exit(cat_tar(name, request_id));
+ else
+ {
+ /*
+@@ -517,7 +517,7 @@ cat_ppd(const char *name, /* I - PPD name */
+ cupsdSendIPPTrailer();
+ }
+
+- return (1);
++ exit(1);
+ }
+
+ /*
+@@ -547,15 +547,15 @@ cat_ppd(const char *name, /* I - PPD name */
+
+ fprintf(stderr, "ERROR: [cups-driverd] Unable to execute \"%s\" - %s\n",
+ line, strerror(errno));
+- return (1);
++ exit(1);
+ }
+ }
+
+ /*
+- * Return with no errors...
++ * Exit with no errors...
+ */
+
+- return (0);
++ exit(0);
+ }
+
+
+@@ -778,7 +778,7 @@ compare_ppds(const ppd_info_t *p0, /* I - First PPD file */
+ * 'dump_ppds_dat()' - Dump the contents of the ppds.dat file.
+ */
+
+-static int /* O - Exit status */
++static void
+ dump_ppds_dat(const char *filename) /* I - Filename */
+ {
+ char temp[1024]; /* ppds.dat filename */
+@@ -810,7 +810,7 @@ dump_ppds_dat(const char *filename) /* I - Filename */
+ ppd->record.make_and_model, ppd->record.device_id,
+ ppd->record.scheme);
+
+- return (0);
++ exit(0);
+ }
+
+
+@@ -1004,7 +1004,7 @@ get_file(const char *name, /* I - Name */
+ * 'list_ppds()' - List PPD files.
+ */
+
+-static int /* O - Exit code */
++static void
+ list_ppds(int request_id, /* I - Request ID */
+ int limit, /* I - Limit */
+ const char *opt) /* I - Option argument */
+@@ -1566,7 +1566,7 @@ list_ppds(int request_id, /* I - Request ID */
+ if (request_id)
+ cupsdSendIPPTrailer();
+
+- return (0);
++ exit(0);
+ }
+
+
+--
+2.17.1
+
diff --git a/SOURCES/0001-Fix-stuck-multi-file-jobs-Issue-5359-Issue-5413.patch b/SOURCES/0001-Fix-stuck-multi-file-jobs-Issue-5359-Issue-5413.patch
new file mode 100644
index 0000000..2d7ca02
--- /dev/null
+++ b/SOURCES/0001-Fix-stuck-multi-file-jobs-Issue-5359-Issue-5413.patch
@@ -0,0 +1,56 @@
+diff --git a/backend/socket.c b/backend/socket.c
+index 675061dd9..68379e95b 100644
+--- a/backend/socket.c
++++ b/backend/socket.c
+@@ -397,8 +397,10 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
+ lseek(print_fd, 0, SEEK_SET);
+ }
+
+- tbytes = backendRunLoop(print_fd, device_fd, snmp_fd, &(addrlist->addr), 1,
+- 0, backendNetworkSideCB);
++ if ((bytes = backendRunLoop(print_fd, device_fd, snmp_fd, &(addrlist->addr), 1, 0, backendNetworkSideCB)) < 0)
++ tbytes = -1;
++ else
++ tbytes = bytes;
+
+ if (print_fd != 0 && tbytes >= 0)
+ _cupsLangPrintFilter(stderr, "INFO", _("Print file sent."));
+@@ -406,7 +408,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
+
+ fputs("STATE: +cups-waiting-for-job-completed\n", stderr);
+
+- if (waiteof)
++ if (waiteof && tbytes >= 0)
+ {
+ /*
+ * Shutdown the socket and wait for the other end to finish...
+@@ -443,7 +445,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
+ if (print_fd != 0)
+ close(print_fd);
+
+- return (CUPS_BACKEND_OK);
++ return (tbytes >= 0 ? CUPS_BACKEND_OK : CUPS_BACKEND_FAILED);
+ }
+
+
+diff --git a/scheduler/main.c b/scheduler/main.c
+index 4b3914ade..472b9946d 100644
+--- a/scheduler/main.c
++++ b/scheduler/main.c
+@@ -1472,9 +1472,16 @@ process_children(void)
+ (!job->filters[i] && WIFEXITED(old_status)))
+ { /* Backend and filter didn't crash */
+ if (job->filters[i])
++ {
+ job->status = status; /* Filter failed */
++ }
+ else
++ {
+ job->status = -status; /* Backend failed */
++
++ if (job->current_file < job->num_files)
++ cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_FORCE, "Canceling multi-file job due to backend failure.");
++ }
+ }
+
+ if (job->state_value == IPP_JOB_PROCESSING &&
diff --git a/SOURCES/0001-Printing-to-old-CUPS-servers-has-been-fixed-Issue-52.patch b/SOURCES/0001-Printing-to-old-CUPS-servers-has-been-fixed-Issue-52.patch
new file mode 100644
index 0000000..de7ef28
--- /dev/null
+++ b/SOURCES/0001-Printing-to-old-CUPS-servers-has-been-fixed-Issue-52.patch
@@ -0,0 +1,562 @@
+diff --git a/cups/cups-private.h b/cups/cups-private.h
+index 6fd66a9..1f66fd7 100644
+--- a/cups/cups-private.h
++++ b/cups/cups-private.h
+@@ -237,13 +237,9 @@ extern void _cupsBufferRelease(char *b);
+
+ extern http_t *_cupsConnect(void);
+ extern char *_cupsCreateDest(const char *name, const char *info, const char *device_id, const char *device_uri, char *uri, size_t urisize);
+-extern int _cupsGet1284Values(const char *device_id,
+- cups_option_t **values);
+-extern const char *_cupsGetDestResource(cups_dest_t *dest, char *resource,
+- size_t resourcesize);
+-extern int _cupsGetDests(http_t *http, ipp_op_t op,
+- const char *name, cups_dest_t **dests,
+- cups_ptype_t type, cups_ptype_t mask);
++extern int _cupsGet1284Values(const char *device_id, cups_option_t **values);
++extern const char *_cupsGetDestResource(cups_dest_t *dest, unsigned flags, char *resource, size_t resourcesize);
++extern int _cupsGetDests(http_t *http, ipp_op_t op, const char *name, cups_dest_t **dests, cups_ptype_t type, cups_ptype_t mask);
+ extern const char *_cupsGetPassword(const char *prompt);
+ extern void _cupsGlobalLock(void);
+ extern _cups_globals_t *_cupsGlobals(void);
+@@ -253,13 +249,10 @@ extern const char *_cupsGSSServiceName(void);
+ # endif /* HAVE_GSSAPI */
+ extern int _cupsNextDelay(int current, int *previous);
+ extern void _cupsSetDefaults(void);
+-extern void _cupsSetError(ipp_status_t status, const char *message,
+- int localize);
++extern void _cupsSetError(ipp_status_t status, const char *message, int localize);
+ extern void _cupsSetHTTPError(http_status_t status);
+ # ifdef HAVE_GSSAPI
+-extern int _cupsSetNegotiateAuthString(http_t *http,
+- const char *method,
+- const char *resource);
++extern int _cupsSetNegotiateAuthString(http_t *http, const char *method, const char *resource);
+ # endif /* HAVE_GSSAPI */
+ extern char *_cupsUserDefault(char *name, size_t namesize);
+
+diff --git a/cups/dest-options.c b/cups/dest-options.c
+index 51705a5..cfa28ce 100644
+--- a/cups/dest-options.c
++++ b/cups/dest-options.c
+@@ -572,6 +572,7 @@ cupsCopyDestInfo(
+ cups_dest_t *dest) /* I - Destination */
+ {
+ cups_dinfo_t *dinfo; /* Destination information */
++ unsigned dflags; /* Destination flags */
+ ipp_t *request, /* Get-Printer-Attributes request */
+ *response; /* Supported attributes */
+ int tries, /* Number of tries so far */
+@@ -581,6 +582,7 @@ cupsCopyDestInfo(
+ char resource[1024]; /* Resource path */
+ int version; /* IPP version */
+ ipp_status_t status; /* Status of request */
++ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+ static const char * const requested_attrs[] =
+ { /* Requested attributes */
+ "job-template",
+@@ -589,14 +591,25 @@ cupsCopyDestInfo(
+ };
+
+
+- DEBUG_printf(("cupsCopyDestSupported(http=%p, dest=%p(%s))", (void *)http, (void *)dest, dest ? dest->name : ""));
++ DEBUG_printf(("cupsCopyDestInfo(http=%p, dest=%p(%s))", (void *)http, (void *)dest, dest ? dest->name : ""));
+
+ /*
+ * Get the default connection as needed...
+ */
+
+ if (!http)
+- http = _cupsConnect();
++ {
++ http = _cupsConnect();
++ dflags = CUPS_DEST_FLAGS_NONE;
++ }
++#ifdef AF_LOCAL
++ else if (strcmp(http->hostname, cg->server) || (httpAddrFamily(http->hostaddr) != AF_LOCAL && cg->ipp_port != httpAddrPort(http->hostaddr)))
++#else
++ else if (strcmp(http->hostname, cg->server) || cg->ipp_port != httpAddrPort(http->hostaddr))
++#endif /* AF_LOCAL */
++ dflags = CUPS_DEST_FLAGS_DEVICE;
++ else
++ dflags = CUPS_DEST_FLAGS_NONE;
+
+ /*
+ * Range check input...
+@@ -609,8 +622,11 @@ cupsCopyDestInfo(
+ * Get the printer URI and resource path...
+ */
+
+- if ((uri = _cupsGetDestResource(dest, resource, sizeof(resource))) == NULL)
++ if ((uri = _cupsGetDestResource(dest, dflags, resource, sizeof(resource))) == NULL)
++ {
++ DEBUG_puts("1cupsCopyDestInfo: Unable to get resource.");
+ return (NULL);
++ }
+
+ /*
+ * Get the supported attributes...
+@@ -628,28 +644,25 @@ cupsCopyDestInfo(
+ */
+
+ request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
+- ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
+- uri);
+- ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+- "requesting-user-name", NULL, cupsUser());
+- ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+- "requested-attributes",
+- (int)(sizeof(requested_attrs) / sizeof(requested_attrs[0])),
+- NULL, requested_attrs);
++
++ ippSetVersion(request, version / 10, version % 10);
++ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
++ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
++ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(requested_attrs) / sizeof(requested_attrs[0])), NULL, requested_attrs);
+ response = cupsDoRequest(http, request, resource);
+ status = cupsLastError();
+
+ if (status > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED)
+ {
+- DEBUG_printf(("cupsCopyDestSupported: Get-Printer-Attributes for '%s' "
+- "returned %s (%s)", dest->name, ippErrorString(status),
+- cupsLastErrorString()));
++ DEBUG_printf(("1cupsCopyDestInfo: Get-Printer-Attributes for '%s' returned %s (%s)", dest->name, ippErrorString(status), cupsLastErrorString()));
+
+ ippDelete(response);
+ response = NULL;
+
+- if (status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED && version > 11)
++ if ((status == IPP_STATUS_ERROR_BAD_REQUEST || status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) && version > 11)
++ {
+ version = 11;
++ }
+ else if (status == IPP_STATUS_ERROR_BUSY)
+ {
+ sleep((unsigned)delay);
+@@ -665,7 +678,10 @@ cupsCopyDestInfo(
+ while (!response && tries < 10);
+
+ if (!response)
++ {
++ DEBUG_puts("1cupsCopyDestInfo: Unable to get printer attributes.");
+ return (NULL);
++ }
+
+ /*
+ * Allocate a cups_dinfo_t structure and return it...
+@@ -678,6 +694,8 @@ cupsCopyDestInfo(
+ return (NULL);
+ }
+
++ DEBUG_printf(("1cupsCopyDestInfo: version=%d, uri=\"%s\", resource=\"%s\".", version, uri, resource));
++
+ dinfo->version = version;
+ dinfo->uri = uri;
+ dinfo->resource = _cupsStrAlloc(resource);
+diff --git a/cups/dest.c b/cups/dest.c
+index 57a8dc9..3537572 100644
+--- a/cups/dest.c
++++ b/cups/dest.c
+@@ -1103,13 +1103,16 @@ cupsGetDest(const char *name, /* I - Destination name or @code NULL@ for the d
+ * '_cupsGetDestResource()' - Get the resource path and URI for a destination.
+ */
+
+-const char * /* O - Printer URI */
++const char * /* O - URI */
+ _cupsGetDestResource(
+ cups_dest_t *dest, /* I - Destination */
++ unsigned flags, /* I - Destination flags */
+ char *resource, /* I - Resource buffer */
+ size_t resourcesize) /* I - Size of resource buffer */
+ {
+- const char *uri; /* Printer URI */
++ const char *uri, /* URI */
++ *device_uri, /* Device URI */
++ *printer_uri; /* Printer URI */
+ char scheme[32], /* URI scheme */
+ userpass[256], /* Username and password (unused) */
+ hostname[256]; /* Hostname */
+@@ -1132,25 +1135,46 @@ _cupsGetDestResource(
+ }
+
+ /*
+- * Grab the printer URI...
++ * Grab the printer and device URIs...
+ */
+
+- if ((uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options)) == NULL)
++ device_uri = cupsGetOption("device-uri", dest->num_options, dest->options);
++ printer_uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options);
++
++ DEBUG_printf(("1_cupsGetDestResource: device-uri=\"%s\", printer-uri-supported=\"%s\".", device_uri, printer_uri));
++
++#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
++ if (((flags & CUPS_DEST_FLAGS_DEVICE) || !printer_uri) && strstr(device_uri, "._tcp"))
+ {
+- if ((uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL)
++ if ((device_uri = cups_dnssd_resolve(dest, device_uri, 5000, NULL, NULL, NULL)) != NULL)
+ {
+-#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+- if (strstr(uri, "._tcp"))
+- uri = cups_dnssd_resolve(dest, uri, 5000, NULL, NULL, NULL);
+-#endif /* HAVE_DNSSD || HAVE_AVAHI */
++ DEBUG_printf(("1_cupsGetDestResource: Resolved device-uri=\"%s\".", device_uri));
+ }
+-
+- if (uri)
++ else
+ {
+- DEBUG_printf(("1_cupsGetDestResource: Resolved printer-uri-supported=\"%s\"", uri));
++ DEBUG_puts("1_cupsGetDestResource: Unable to resolve device.");
+
+- uri = _cupsCreateDest(dest->name, cupsGetOption("printer-info", dest->num_options, dest->options), NULL, uri, resource, resourcesize);
++ if (resource)
++ *resource = '\0';
++
++ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
++
++ return (NULL);
+ }
++ }
++#endif /* HAVE_DNSSD || HAVE_AVAHI */
++
++ if (flags & CUPS_DEST_FLAGS_DEVICE)
++ {
++ uri = device_uri;
++ }
++ else if (printer_uri)
++ {
++ uri = printer_uri;
++ }
++ else
++ {
++ uri = _cupsCreateDest(dest->name, cupsGetOption("printer-info", dest->num_options, dest->options), NULL, device_uri, resource, resourcesize);
+
+ if (uri)
+ {
+@@ -1160,30 +1184,24 @@ _cupsGetDestResource(
+
+ uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options);
+ }
+- else
+- {
+- DEBUG_puts("1_cupsGetDestResource: No printer-uri-supported found.");
++ }
+
+- if (resource)
+- *resource = '\0';
++ if (!uri)
++ {
++ DEBUG_puts("1_cupsGetDestResource: No printer-uri-supported or device-uri found.");
+
+- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
++ if (resource)
++ *resource = '\0';
+
+- return (NULL);
+- }
++ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
++
++ return (NULL);
+ }
+- else
++ else if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, (int)resourcesize) < HTTP_URI_STATUS_OK)
+ {
+- DEBUG_printf(("1_cupsGetDestResource: printer-uri-supported=\"%s\"", uri));
++ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad URI."), 1);
+
+- if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
+- userpass, sizeof(userpass), hostname, sizeof(hostname),
+- &port, resource, (int)resourcesize) < HTTP_URI_STATUS_OK)
+- {
+- _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad printer-uri."), 1);
+-
+- return (NULL);
+- }
++ return (NULL);
+ }
+
+ DEBUG_printf(("1_cupsGetDestResource: resource=\"%s\"", resource));
+diff --git a/cups/testdest.c b/cups/testdest.c
+index c5c2052..27060f6 100644
+--- a/cups/testdest.c
++++ b/cups/testdest.c
+@@ -43,9 +43,12 @@ int /* O - Exit status */
+ main(int argc, /* I - Number of command-line arguments */
+ char *argv[]) /* I - Command-line arguments */
+ {
++ int i; /* Looping var */
+ http_t *http; /* Connection to destination */
+ cups_dest_t *dest = NULL; /* Destination */
+ cups_dinfo_t *dinfo; /* Destination info */
++ unsigned dflags = CUPS_DEST_FLAGS_NONE;
++ /* Destination flags */
+
+
+ if (argc < 2)
+@@ -103,9 +106,17 @@ main(int argc, /* I - Number of command-line arguments */
+
+ return (0);
+ }
+- else if (!strncmp(argv[1], "ipp://", 6) || !strncmp(argv[1], "ipps://", 7))
+- dest = cupsGetDestWithURI(NULL, argv[1]);
+- else if (!strcmp(argv[1], "default"))
++
++ i = 1;
++ if (!strcmp(argv[i], "--device"))
++ {
++ dflags = CUPS_DEST_FLAGS_DEVICE;
++ i ++;
++ }
++
++ if (!strncmp(argv[i], "ipp://", 6) || !strncmp(argv[i], "ipps://", 7))
++ dest = cupsGetDestWithURI(NULL, argv[i]);
++ else if (!strcmp(argv[i], "default"))
+ {
+ dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, NULL, NULL);
+ if (dest && dest->instance)
+@@ -114,67 +125,70 @@ main(int argc, /* I - Number of command-line arguments */
+ printf("default is \"%s\".\n", dest->name);
+ }
+ else
+- dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, argv[1], NULL);
++ dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, argv[i], NULL);
+
+ if (!dest)
+ {
+- printf("testdest: Unable to get destination \"%s\": %s\n", argv[1], cupsLastErrorString());
++ printf("testdest: Unable to get destination \"%s\": %s\n", argv[i], cupsLastErrorString());
+ return (1);
+ }
+
+- if ((http = cupsConnectDest(dest, CUPS_DEST_FLAGS_NONE, 30000, NULL, NULL, 0, NULL, NULL)) == NULL)
++ i ++;
++
++ if ((http = cupsConnectDest(dest, dflags, 30000, NULL, NULL, 0, NULL, NULL)) == NULL)
+ {
+- printf("testdest: Unable to connect to destination \"%s\": %s\n", argv[1], cupsLastErrorString());
++ printf("testdest: Unable to connect to destination \"%s\": %s\n", dest->name, cupsLastErrorString());
+ return (1);
+ }
+
+ if ((dinfo = cupsCopyDestInfo(http, dest)) == NULL)
+ {
+- printf("testdest: Unable to get information for destination \"%s\": %s\n", argv[1], cupsLastErrorString());
++ printf("testdest: Unable to get information for destination \"%s\": %s\n", dest->name, cupsLastErrorString());
+ return (1);
+ }
+
+- if (argc == 2 || (!strcmp(argv[2], "supported") && argc < 6))
++ if (i == argc || !strcmp(argv[i], "supported"))
+ {
+- if (argc > 3)
+- show_supported(http, dest, dinfo, argv[3], argv[4]);
++ i ++;
++
++ if ((i + 1) < argc)
++ show_supported(http, dest, dinfo, argv[i], argv[i + 1]);
+ else if (argc > 2)
+- show_supported(http, dest, dinfo, argv[3], NULL);
++ show_supported(http, dest, dinfo, argv[i], NULL);
+ else
+ show_supported(http, dest, dinfo, NULL, NULL);
+ }
+- else if (!strcmp(argv[2], "conflicts") && argc > 3)
++ else if (!strcmp(argv[i], "conflicts") && (i + 1) < argc)
+ {
+- int i, /* Looping var */
+- num_options = 0;/* Number of options */
++ int num_options = 0;/* Number of options */
+ cups_option_t *options = NULL;/* Options */
+
+- for (i = 3; i < argc; i ++)
++ for (i ++; i < argc; i ++)
+ num_options = cupsParseOptions(argv[i], num_options, &options);
+
+ show_conflicts(http, dest, dinfo, num_options, options);
+ }
+- else if (!strcmp(argv[2], "default") && argc == 4)
++ else if (!strcmp(argv[i], "default") && (i + 1) < argc)
+ {
+- show_default(http, dest, dinfo, argv[3]);
++ show_default(http, dest, dinfo, argv[i + 1]);
+ }
+- else if (!strcmp(argv[2], "localize") && argc < 6)
++ else if (!strcmp(argv[i], "localize"))
+ {
+- if (argc > 3)
+- localize(http, dest, dinfo, argv[3], argv[4]);
++ i ++;
++ if ((i + 1) < argc)
++ localize(http, dest, dinfo, argv[i], argv[i + 1]);
+ else if (argc > 2)
+- localize(http, dest, dinfo, argv[3], NULL);
++ localize(http, dest, dinfo, argv[i], NULL);
+ else
+ localize(http, dest, dinfo, NULL, NULL);
+ }
+- else if (!strcmp(argv[2], "media"))
++ else if (!strcmp(argv[i], "media"))
+ {
+- int i; /* Looping var */
+ const char *name = NULL; /* Media name, if any */
+ unsigned flags = CUPS_MEDIA_FLAGS_DEFAULT;
+ /* Media selection flags */
+
+- for (i = 3; i < argc; i ++)
++ for (i ++; i < argc; i ++)
+ {
+ if (!strcmp(argv[i], "borderless"))
+ flags = CUPS_MEDIA_FLAGS_BORDERLESS;
+@@ -192,19 +206,19 @@ main(int argc, /* I - Number of command-line arguments */
+
+ show_media(http, dest, dinfo, flags, name);
+ }
+- else if (!strcmp(argv[2], "print") && argc > 3)
++ else if (!strcmp(argv[i], "print") && (i + 1) < argc)
+ {
+- int i, /* Looping var */
+- num_options = 0;/* Number of options */
++ int num_options = 0;/* Number of options */
+ cups_option_t *options = NULL;/* Options */
++ const char *filename = argv[i + 1];
+
+- for (i = 4; i < argc; i ++)
++ for (i += 2; i < argc; i ++)
+ num_options = cupsParseOptions(argv[i], num_options, &options);
+
+- print_file(http, dest, dinfo, argv[3], num_options, options);
++ print_file(http, dest, dinfo, filename, num_options, options);
+ }
+ else
+- usage(argv[2]);
++ usage(argv[i]);
+
+ return (0);
+ }
+@@ -740,9 +754,9 @@ usage(const char *arg) /* I - Argument for usage message */
+ printf("testdest: Unknown option \"%s\".\n", arg);
+
+ puts("Usage:");
+- puts(" ./testdest name [operation ...]");
+- puts(" ./testdest ipp://... [operation ...]");
+- puts(" ./testdest ipps://... [operation ...]");
++ puts(" ./testdest [--device] name [operation ...]");
++ puts(" ./testdest [--device] ipp://... [operation ...]");
++ puts(" ./testdest [--device] ipps://... [operation ...]");
+ puts(" ./testdest --enum [grayscale] [color] [duplex] [staple] [small]\n"
+ " [medium] [large]");
+ puts("");
+diff --git a/test/ippserver.c b/test/ippserver.c
+index 38b304f..c593d3a 100644
+--- a/test/ippserver.c
++++ b/test/ippserver.c
+@@ -461,6 +461,7 @@ static AvahiClient *DNSSDClient = NULL;
+ #endif /* HAVE_DNSSD */
+
+ static int KeepFiles = 0,
++ MaxVersion = 20,
+ Verbosity = 0;
+
+
+@@ -533,6 +534,23 @@ main(int argc, /* I - Number of command-line args */
+ pin = 1;
+ break;
+
++ case 'V' : /* -V max-version */
++ i ++;
++ if (i >= argc)
++ usage(1);
++
++ if (!strcmp(argv[i], "2.2"))
++ MaxVersion = 22;
++ else if (!strcmp(argv[i], "2.1"))
++ MaxVersion = 21;
++ else if (!strcmp(argv[i], "2.0"))
++ MaxVersion = 20;
++ else if (!strcmp(argv[i], "1.1"))
++ MaxVersion = 11;
++ else
++ usage(1);
++ break;
++
+ case 'a' : /* -a attributes-file */
+ i ++;
+ if (i >= argc)
+@@ -1324,9 +1342,10 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default)
+ };
+ static const char * const versions[] =/* ipp-versions-supported values */
+ {
+- "1.0",
+ "1.1",
+- "2.0"
++ "2.0",
++ "2.1",
++ "2.2"
+ };
+ static const char * const features[] =/* ipp-features-supported values */
+ {
+@@ -1738,7 +1757,12 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default)
+
+ /* ipp-versions-supported */
+ if (!ippFindAttribute(printer->attrs, "ipp-versions-supported", IPP_TAG_ZERO))
+- ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]), NULL, versions);
++ {
++ int num_versions = MaxVersion == 11 ? 1 : MaxVersion == 20 ? 2 : MaxVersion == 21 ? 3 : 4;
++ /* Number of supported versions */
++
++ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-versions-supported", num_versions, NULL, versions);
++ }
+
+ /* job-account-id-default */
+ if (!ippFindAttribute(printer->attrs, "job-account-id-default", IPP_TAG_ZERO))
+@@ -5800,15 +5824,24 @@ process_ipp(_ipp_client_t *client) /* I - Client */
+ * Return an error, since we only support IPP 1.x and 2.x.
+ */
+
+- respond_ipp(client, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED,
+- "Bad request version number %d.%d.", major, minor);
++ respond_ipp(client, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, "Bad request version number %d.%d.", major, minor);
++ }
++ else if ((major * 10 + minor) > MaxVersion)
++ {
++ if (httpGetState(client->http) != HTTP_STATE_POST_SEND)
++ httpFlush(client->http); /* Flush trailing (junk) data */
++
++ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
++ return (0);
+ }
+ else if (ippGetRequestId(client->request) <= 0)
+- respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad request-id %d.",
+- ippGetRequestId(client->request));
++ {
++ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad request-id %d.", ippGetRequestId(client->request));
++ }
+ else if (!ippFirstAttribute(client->request))
+- respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST,
+- "No attributes in request.");
++ {
++ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "No attributes in request.");
++ }
+ else
+ {
+ /*
+@@ -6877,8 +6910,7 @@ usage(int status) /* O - Exit status */
+ {
+ if (!status)
+ {
+- puts(CUPS_SVERSION " - Copyright 2010-2015 by Apple Inc. All rights "
+- "reserved.");
++ puts(CUPS_SVERSION " - Copyright (c) 2010-2018 by Apple Inc. All rights reserved.");
+ puts("");
+ }
+
+@@ -6888,6 +6920,7 @@ usage(int status) /* O - Exit status */
+ puts("-2 Supports 2-sided printing (default=1-sided)");
+ puts("-M manufacturer Manufacturer name (default=Test)");
+ puts("-P PIN printing mode");
++ puts("-V max-version Set maximum supported IPP version");
+ puts("-a attributes-file Load printer attributes from file");
+ puts("-c command Run command for every print job");
+ printf("-d spool-directory Spool directory "
diff --git a/SOURCES/0001-Remove-web-log-buttons.patch b/SOURCES/0001-Remove-web-log-buttons.patch
new file mode 100644
index 0000000..a19d806
--- /dev/null
+++ b/SOURCES/0001-Remove-web-log-buttons.patch
@@ -0,0 +1,98 @@
+diff --git a/templates/admin.tmpl b/templates/admin.tmpl
+index 101f960..5ebd813 100644
+--- a/templates/admin.tmpl
++++ b/templates/admin.tmpl
+@@ -27,9 +27,6 @@
+
+
+
+-
+-
+-
+
+
+ {SETTINGS_ERROR?{SETTINGS_MESSAGE}
+diff --git a/templates/de/admin.tmpl b/templates/de/admin.tmpl
+index fb2851a..f8ddeff 100644
+--- a/templates/de/admin.tmpl
++++ b/templates/de/admin.tmpl
+@@ -27,9 +27,6 @@
+
+
+
+-
+-
+-
+
+
+ {SETTINGS_ERROR?{SETTINGS_MESSAGE}
+diff --git a/templates/es/admin.tmpl b/templates/es/admin.tmpl
+index 097c65c..b83b1a0 100644
+--- a/templates/es/admin.tmpl
++++ b/templates/es/admin.tmpl
+@@ -27,9 +27,6 @@
+
+
+
+-
+-
+-
+
+
+ {SETTINGS_ERROR?{SETTINGS_MESSAGE}
+diff --git a/templates/fr/admin.tmpl b/templates/fr/admin.tmpl
+index 2fcd9c5..e365ff3 100644
+--- a/templates/fr/admin.tmpl
++++ b/templates/fr/admin.tmpl
+@@ -27,9 +27,6 @@
+
+
+
+-
+-
+-
+
+
+ {SETTINGS_ERROR?{SETTINGS_MESSAGE}
+diff --git a/templates/ja/admin.tmpl b/templates/ja/admin.tmpl
+index 13d6f13..f5fa750 100644
+--- a/templates/ja/admin.tmpl
++++ b/templates/ja/admin.tmpl
+@@ -27,9 +27,6 @@
+
+
+
+-
+-
+-
+
+
+ {SETTINGS_ERROR?{SETTINGS_MESSAGE}
+diff --git a/templates/pt_BR/admin.tmpl b/templates/pt_BR/admin.tmpl
+index b847bef..e11d889 100644
+--- a/templates/pt_BR/admin.tmpl
++++ b/templates/pt_BR/admin.tmpl
+@@ -27,9 +27,6 @@
+
+
+
+-
+-
+-
+
+
+ {SETTINGS_ERROR?{SETTINGS_MESSAGE}
+diff --git a/templates/ru/admin.tmpl b/templates/ru/admin.tmpl
+index 49a168c..44b1493 100644
+--- a/templates/ru/admin.tmpl
++++ b/templates/ru/admin.tmpl
+@@ -26,9 +26,6 @@
+
+
+
+-
+-
+-
+
+
+ {SETTINGS_ERROR?{SETTINGS_MESSAGE}
diff --git a/SOURCES/0001-The-scheduler-could-crash-while-adding-an-IPP-Everyw.patch b/SOURCES/0001-The-scheduler-could-crash-while-adding-an-IPP-Everyw.patch
new file mode 100644
index 0000000..e5b9e9e
--- /dev/null
+++ b/SOURCES/0001-The-scheduler-could-crash-while-adding-an-IPP-Everyw.patch
@@ -0,0 +1,22 @@
+diff --git a/scheduler/ipp.c b/scheduler/ipp.c
+index 649995bb5..2396c9b58 100644
+--- a/scheduler/ipp.c
++++ b/scheduler/ipp.c
+@@ -4873,6 +4873,8 @@ copy_printer_attrs(
+ * and document-format attributes that may be provided by the client.
+ */
+
++ _cupsRWLockRead(&printer->lock);
++
+ curtime = time(NULL);
+
+ if (!ra || cupsArrayFind(ra, "marker-change-time"))
+@@ -5034,6 +5036,8 @@ copy_printer_attrs(
+ if (printer->ppd_attrs)
+ copy_attrs(con->response, printer->ppd_attrs, ra, IPP_TAG_ZERO, 0, NULL);
+ copy_attrs(con->response, CommonData, ra, IPP_TAG_ZERO, IPP_TAG_COPY, NULL);
++
++ _cupsRWUnlock(&printer->lock);
+ }
+
+
diff --git a/SOURCES/cups-avahi-address.patch b/SOURCES/cups-avahi-address.patch
new file mode 100644
index 0000000..b8090ea
--- /dev/null
+++ b/SOURCES/cups-avahi-address.patch
@@ -0,0 +1,95 @@
+diff -up cups-2.2b2/cups/http-support.c.avahi-address cups-2.2b2/cups/http-support.c
+--- cups-2.2b2/cups/http-support.c.avahi-address 2016-06-24 17:43:35.000000000 +0200
++++ cups-2.2b2/cups/http-support.c 2016-06-27 15:31:34.201361844 +0200
+@@ -2340,7 +2340,7 @@ http_resolve_cb(
+ const char *type, /* I - Registration type */
+ const char *domain, /* I - Domain (unused) */
+ const char *hostTarget, /* I - Hostname */
+- const AvahiAddress *address, /* I - Address (unused) */
++ const AvahiAddress *address, /* I - Address */
+ uint16_t port, /* I - Port number */
+ AvahiStringList *txt, /* I - TXT record */
+ AvahiLookupResultFlags flags, /* I - Lookup flags (unused) */
+@@ -2493,39 +2493,62 @@ http_resolve_cb(
+ * getting the IP address of the .local name and then do reverse-lookups...
+ */
+
+- http_addrlist_t *addrlist, /* List of addresses */
+- *addr; /* Current address */
++ http_addr_t addr;
++ size_t addrlen;
++ int error;
+
+ DEBUG_printf(("5http_resolve_cb: Looking up \"%s\".", hostTarget));
+
+- snprintf(fqdn, sizeof(fqdn), "%d", ntohs(port));
+- if ((addrlist = httpAddrGetList(hostTarget, AF_UNSPEC, fqdn)) != NULL)
++ switch (address->proto)
+ {
+- for (addr = addrlist; addr; addr = addr->next)
++ case AVAHI_PROTO_INET:
++ addr.ipv4.sin_family = AF_INET;
++ addrlen = sizeof (addr.ipv4.sin_addr);
++ memcpy (&addr.ipv4.sin_addr, &address->data, addrlen);
++ break;
++ case AVAHI_PROTO_INET6:
++ addr.ipv6.sin6_family = AF_INET6;
++ addrlen = sizeof (addr.ipv6.sin6_addr);
++ memcpy (&addr.ipv6.sin6_addr, &address->data, addrlen);
++ break;
++ default:
++ DEBUG_printf(("8http_resolve_cb: unknown address family %d",
++ address->proto));
++ addrlen = 0;
++ }
++
++ if (addrlen > 0) {
++ error = getnameinfo(&addr.addr, httpAddrLength (&addr),
++ fqdn, sizeof(fqdn), NULL, 0, NI_NAMEREQD);
++
++ if (!error)
+ {
+- int error = getnameinfo(&(addr->addr.addr), (socklen_t)httpAddrLength(&(addr->addr)), fqdn, sizeof(fqdn), NULL, 0, NI_NAMEREQD);
++ DEBUG_printf(("8http_resolve_cb: Found \"%s\".", fqdn));
+
+- if (!error)
+- {
+- DEBUG_printf(("5http_resolve_cb: Found \"%s\".", fqdn));
++ if ((hostptr = fqdn + strlen(fqdn) - 6) <= fqdn ||
++ _cups_strcasecmp(hostptr, ".local"))
+
+- if ((hostptr = fqdn + strlen(fqdn) - 6) <= fqdn ||
+- _cups_strcasecmp(hostptr, ".local"))
+- {
+- hostTarget = fqdn;
+- break;
+- }
++ {
++ hostTarget = fqdn;
+ }
++ } else {
++ avahi_address_snprint (fqdn, sizeof (fqdn), address);
++ hostTarget = fqdn;
++
+ #ifdef DEBUG
+- else
+- DEBUG_printf(("5http_resolve_cb: \"%s\" did not resolve: %d",
+- httpAddrString(&(addr->addr), fqdn, sizeof(fqdn)),
+- error));
++ DEBUG_printf(("8http_resolve_cb: \"%s\" did not resolve: %d",
++ fqdn, error));
+ #endif /* DEBUG */
+ }
+
+- httpAddrFreeList(addrlist);
+ }
++ } else {
++ /*
++ * Use the IP address that responded...
++ */
++
++ avahi_address_snprint (fqdn, sizeof (fqdn), address);
++ hostTarget = fqdn;
+ }
+
+ /*
diff --git a/SOURCES/cups-avahi-no-threaded.patch b/SOURCES/cups-avahi-no-threaded.patch
new file mode 100644
index 0000000..942bbf5
--- /dev/null
+++ b/SOURCES/cups-avahi-no-threaded.patch
@@ -0,0 +1,1025 @@
+diff -up cups-2.2.5/scheduler/avahi.c.avahi-no-threaded cups-2.2.5/scheduler/avahi.c
+--- cups-2.2.5/scheduler/avahi.c.avahi-no-threaded 2017-10-17 19:03:00.760881016 +0200
++++ cups-2.2.5/scheduler/avahi.c 2017-10-17 19:03:00.760881016 +0200
+@@ -0,0 +1,441 @@
++/*
++ * "$Id$"
++ *
++ * Avahi poll implementation for the CUPS scheduler.
++ *
++ * Copyright (C) 2010, 2011 Red Hat, Inc.
++ * Authors:
++ * Tim Waugh
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ *
++ * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
++ * OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Contents:
++ *
++ * watch_read_cb - Read callback for file descriptor
++ * watch_write_cb - Write callback for file descriptor
++ * watched_fd_add_select() - Call cupsdAddSelect() as needed
++ * watch_new() - Create a new file descriptor watch
++ * watch_free() - Free a file descriptor watch
++ * watch_update() - Update watched events for a file descriptor
++ * watch_get_events() - Get events that happened for a file descriptor
++ * timeout_cb() - Run a timed Avahi callback
++ * timeout_new() - Set a wakeup time
++ * timeout_update() - Update the expiration time for a timeout
++ * timeout_free() - Free a timeout
++ * compare_watched_fds() - Compare watched file descriptors for array sorting
++ * avahi_cups_poll_new() - Create a new Avahi main loop object for CUPS
++ * avahi_cups_poll_free() - Free an Avahi main loop object for CUPS
++ * avahi_cups_poll_get() - Get the abstract poll API structure
++ */
++
++#include
++
++#ifdef HAVE_AVAHI /* Applies to entire file... */
++
++/*
++ * Include necessary headers...
++ */
++
++#include "cupsd.h"
++
++#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
++# include
++#endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
++
++#ifdef HAVE_AVAHI
++# include
++#endif /* HAVE_AVAHI */
++
++
++typedef struct
++{
++ AvahiCupsPoll *cups_poll;
++
++ int fd;
++ AvahiWatchEvent occurred;
++ cups_array_t *watches;
++} cupsd_watched_fd_t;
++
++struct AvahiWatch
++{
++ cupsd_watched_fd_t *watched_fd;
++
++ AvahiWatchEvent events;
++ AvahiWatchCallback callback;
++ void *userdata;
++};
++
++struct AvahiTimeout
++{
++ AvahiCupsPoll *cups_poll;
++ AvahiTimeoutCallback callback;
++ void *userdata;
++ cupsd_timeout_t *cupsd_timeout;
++};
++
++/*
++ * Local functions...
++ */
++
++static AvahiWatch * watch_new(const AvahiPoll *api,
++ int fd,
++ AvahiWatchEvent events,
++ AvahiWatchCallback callback,
++ void *userdata);
++static void watch_free(AvahiWatch *watch);
++static void watch_update(AvahiWatch *watch,
++ AvahiWatchEvent events);
++static AvahiWatchEvent watch_get_events(AvahiWatch *watch);
++
++
++/*
++ * 'watch_read_cb' - Read callback for file descriptor
++ */
++
++static void
++watch_read_cb (void *userdata)
++{
++ AvahiWatch *watch;
++ cupsd_watched_fd_t *watched_fd = userdata;
++ watched_fd->occurred |= AVAHI_WATCH_IN;
++ for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
++ watch;
++ watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches))
++ {
++ if (watch->events & watched_fd->occurred)
++ {
++ (watch->callback) (watch, watched_fd->fd,
++ AVAHI_WATCH_IN, watch->userdata);
++ watched_fd->occurred &= ~AVAHI_WATCH_IN;
++ break;
++ }
++ }
++}
++
++
++/*
++ * 'watch_write_cb' - Write callback for file descriptor
++ */
++
++static void
++watch_write_cb (void *userdata)
++{
++ AvahiWatch *watch;
++ cupsd_watched_fd_t *watched_fd = userdata;
++ watched_fd->occurred |= AVAHI_WATCH_OUT;
++ for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
++ watch;
++ watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches))
++ {
++ if (watch->events & watched_fd->occurred)
++ {
++ (watch->callback) (watch, watched_fd->fd,
++ AVAHI_WATCH_OUT, watch->userdata);
++ watched_fd->occurred &= ~AVAHI_WATCH_OUT;
++ break;
++ }
++ }
++}
++
++
++/*
++ * 'watched_fd_add_select' - Call cupsdAddSelect() as needed
++ */
++
++static int /* O - Watches? */
++watched_fd_add_select (cupsd_watched_fd_t *watched_fd)
++{
++ AvahiWatch *watch;
++ cupsd_selfunc_t read_cb = NULL, write_cb = NULL;
++ int any_watches = 0;
++
++ for (watch = (AvahiWatch *)cupsArrayFirst(watched_fd->watches);
++ watch;
++ watch = (AvahiWatch *)cupsArrayNext(watched_fd->watches))
++ {
++ any_watches = 1;
++ if (watch->events & (AVAHI_WATCH_IN |
++ AVAHI_WATCH_ERR |
++ AVAHI_WATCH_HUP))
++ {
++ read_cb = (cupsd_selfunc_t)watch_read_cb;
++ if (write_cb != NULL)
++ break;
++ }
++
++ if (watch->events & AVAHI_WATCH_OUT)
++ {
++ write_cb = (cupsd_selfunc_t)watch_write_cb;
++ if (read_cb != NULL)
++ break;
++ }
++ }
++
++ if (read_cb || write_cb)
++ cupsdAddSelect (watched_fd->fd, read_cb, write_cb, watched_fd);
++ else
++ cupsdRemoveSelect (watched_fd->fd);
++
++ return (any_watches);
++}
++
++/*
++ * 'watch_new' - Create a new file descriptor watch
++ */
++
++static AvahiWatch *
++watch_new (const AvahiPoll *api,
++ int fd,
++ AvahiWatchEvent events,
++ AvahiWatchCallback callback,
++ void *userdata)
++{
++ cupsd_watched_fd_t key, *watched_fd;
++ AvahiCupsPoll *cups_poll = api->userdata;
++ AvahiWatch *watch = malloc(sizeof(AvahiWatch));
++ if (watch == NULL)
++ return (NULL);
++
++ watch->events = events;
++ watch->callback = callback;
++ watch->userdata = userdata;
++
++ key.fd = fd;
++ watched_fd = cupsArrayFind (cups_poll->watched_fds, &key);
++ if (watched_fd == NULL)
++ {
++ watched_fd = malloc(sizeof(cupsd_watched_fd_t));
++ if (watched_fd == NULL)
++ {
++ free (watch);
++ return (NULL);
++ }
++
++ watched_fd->fd = fd;
++ watched_fd->occurred = 0;
++ watched_fd->cups_poll = cups_poll;
++ watched_fd->watches = cupsArrayNew (NULL, NULL);
++ cupsArrayAdd (cups_poll->watched_fds, watched_fd);
++ }
++
++ watch->watched_fd = watched_fd;
++ cupsArrayAdd(watched_fd->watches, watch);
++ watched_fd_add_select (watched_fd);
++ return (watch);
++}
++
++
++/*
++ * 'watch_free' - Free a file descriptor watch
++ */
++
++static void
++watch_free (AvahiWatch *watch)
++{
++ cupsd_watched_fd_t *watched_fd = watch->watched_fd;
++ AvahiCupsPoll *cups_poll = watched_fd->cups_poll;
++
++ cupsArrayRemove (watched_fd->watches, watch);
++ free (watch);
++
++ if (!watched_fd_add_select (watched_fd))
++ {
++ /* No more watches */
++ cupsArrayRemove (cups_poll->watched_fds, watched_fd);
++ free (watched_fd);
++ }
++}
++
++
++/*
++ * 'watch_update' - Update watched events for a file descriptor
++ */
++
++static void
++watch_update (AvahiWatch *watch,
++ AvahiWatchEvent events)
++{
++ watch->events = events;
++ watched_fd_add_select (watch->watched_fd);
++}
++
++
++/*
++ * 'watch_get_events' - Get events that happened for a file descriptor
++ */
++
++static AvahiWatchEvent
++watch_get_events (AvahiWatch *watch)
++{
++ return (watch->watched_fd->occurred);
++}
++
++
++/*
++ * 'timeout_cb()' - Run a timed Avahi callback
++ */
++
++static void
++timeout_cb (cupsd_timeout_t *cupsd_timeout, void *userdata)
++{
++ AvahiTimeout *timeout = userdata;
++ (timeout->callback) (timeout, timeout->userdata);
++}
++
++
++/*
++ * 'timeout_new' - Set a wakeup time
++ */
++
++static AvahiTimeout *
++timeout_new (const AvahiPoll *api,
++ const struct timeval *tv,
++ AvahiTimeoutCallback callback,
++ void *userdata)
++{
++ AvahiTimeout *timeout;
++ AvahiCupsPoll *cups_poll = api->userdata;
++
++ timeout = malloc(sizeof(AvahiTimeout));
++ if (timeout == NULL)
++ return (NULL);
++
++ timeout->cups_poll = cups_poll;
++ timeout->callback = callback;
++ timeout->userdata = userdata;
++ timeout->cupsd_timeout = cupsdAddTimeout (tv,
++ (cupsd_timeoutfunc_t)timeout_cb,
++ timeout);
++ cupsArrayAdd (cups_poll->timeouts, timeout);
++ return (timeout);
++}
++
++
++/*
++ * 'timeout_update' - Update the expiration time for a timeout
++ */
++
++static void
++timeout_update (AvahiTimeout *timeout,
++ const struct timeval *tv)
++{
++ cupsdUpdateTimeout (timeout->cupsd_timeout, tv);
++}
++
++
++/*
++ * ' timeout_free' - Free a timeout
++ */
++
++static void
++timeout_free (AvahiTimeout *timeout)
++{
++ cupsArrayRemove (timeout->cups_poll->timeouts, timeout);
++ cupsdRemoveTimeout (timeout->cupsd_timeout);
++ free (timeout);
++}
++
++
++/*
++ * 'compare_watched_fds' - Compare watched file descriptors for array sorting
++ */
++static int
++compare_watched_fds(cupsd_watched_fd_t *p0,
++ cupsd_watched_fd_t *p1)
++{
++ /*
++ * Compare by fd (no two elements have the same fd)
++ */
++
++ if (p0->fd == p1->fd)
++ return 0;
++
++ return (p0->fd < p1->fd ? -1 : 1);
++}
++
++
++/*
++ * 'avahi_cups_poll_new' - Create a new Avahi main loop object for CUPS
++ */
++
++AvahiCupsPoll *
++avahi_cups_poll_new (void)
++{
++ AvahiCupsPoll *cups_poll = malloc(sizeof(AvahiCupsPoll));
++ if (cups_poll == NULL)
++ return (NULL);
++
++ cups_poll->watched_fds = cupsArrayNew ((cups_array_func_t)compare_watched_fds,
++ NULL);
++ cups_poll->timeouts = cupsArrayNew (NULL, NULL);
++
++ cups_poll->api.userdata = cups_poll;
++ cups_poll->api.watch_new = watch_new;
++ cups_poll->api.watch_free = watch_free;
++ cups_poll->api.watch_update = watch_update;
++ cups_poll->api.watch_get_events = watch_get_events;
++
++ cups_poll->api.timeout_new = timeout_new;
++ cups_poll->api.timeout_update = timeout_update;
++ cups_poll->api.timeout_free = timeout_free;
++
++ return (cups_poll);
++}
++
++
++/*
++ * 'avahi_cups_poll_free' - Free an Avahi main loop object for CUPS
++ */
++void
++avahi_cups_poll_free (AvahiCupsPoll *cups_poll)
++{
++ cupsd_watched_fd_t *watched_fd;
++
++ for (watched_fd = (cupsd_watched_fd_t*)cupsArrayFirst(cups_poll->watched_fds);
++ watched_fd;
++ watched_fd = (cupsd_watched_fd_t*)cupsArrayNext(cups_poll->watched_fds))
++ cupsArrayClear (watched_fd->watches);
++
++ cupsArrayClear (cups_poll->watched_fds);
++ cupsArrayClear (cups_poll->timeouts);
++}
++
++
++/*
++ * 'avahi_cups_poll_get' - Get the abstract poll API structure
++ */
++
++const AvahiPoll *
++avahi_cups_poll_get (AvahiCupsPoll *cups_poll)
++{
++ return (&cups_poll->api);
++}
++
++
++#endif /* HAVE_AVAHI ... from top of file */
++
++/*
++ * End of "$Id$".
++ */
+diff -up cups-2.2.5/scheduler/avahi.h.avahi-no-threaded cups-2.2.5/scheduler/avahi.h
+--- cups-2.2.5/scheduler/avahi.h.avahi-no-threaded 2017-10-17 19:03:00.760881016 +0200
++++ cups-2.2.5/scheduler/avahi.h 2017-10-17 19:03:00.760881016 +0200
+@@ -0,0 +1,69 @@
++/*
++ * "$Id$"
++ *
++ * Avahi poll implementation for the CUPS scheduler.
++ *
++ * Copyright (C) 2010, 2011 Red Hat, Inc.
++ * Authors:
++ * Tim Waugh
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ *
++ * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
++ * OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include
++
++#ifdef HAVE_AVAHI
++# include
++# include
++#endif /* HAVE_AVAHI */
++
++#ifdef HAVE_AUTHORIZATION_H
++# include
++#endif /* HAVE_AUTHORIZATION_H */
++
++
++#ifdef HAVE_AVAHI
++typedef struct
++{
++ AvahiPoll api;
++ cups_array_t *watched_fds;
++ cups_array_t *timeouts;
++} AvahiCupsPoll;
++#endif /* HAVE_AVAHI */
++
++/*
++ * Prototypes...
++ */
++
++#ifdef HAVE_AVAHI
++extern AvahiCupsPoll * avahi_cups_poll_new(void);
++extern void avahi_cups_poll_free(AvahiCupsPoll *cups_poll);
++extern const AvahiPoll *avahi_cups_poll_get(AvahiCupsPoll *cups_poll);
++#endif /* HAVE_AVAHI */
++
++
++/*
++ * End of "$Id$".
++ */
+diff -up cups-2.2.5/scheduler/cupsd.h.avahi-no-threaded cups-2.2.5/scheduler/cupsd.h
+--- cups-2.2.5/scheduler/cupsd.h.avahi-no-threaded 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/scheduler/cupsd.h 2017-10-17 19:03:00.760881016 +0200
+@@ -118,6 +118,7 @@ extern const char *cups_hstrerror(int);
+ #include "colorman.h"
+ #include "conf.h"
+ #include "banners.h"
++#include "avahi.h"
+ #include "dirsvc.h"
+ #include "network.h"
+ #include "subscriptions.h"
+@@ -138,6 +139,15 @@ extern const char *cups_hstrerror(int);
+
+ typedef void (*cupsd_selfunc_t)(void *data);
+
++#ifdef HAVE_AVAHI
++/*
++ * Timeout callback function type...
++ */
++
++typedef struct _cupsd_timeout_s cupsd_timeout_t;
++typedef void (*cupsd_timeoutfunc_t)(cupsd_timeout_t *timeout, void *data);
++#endif /* HAVE_AVAHI */
++
+
+ /*
+ * Globals...
+@@ -162,6 +172,9 @@ VAR int OnDemand VALUE(0);
+ /* Launched on demand */
+ #endif /* HAVE_ONDEMAND */
+
++#ifdef HAVE_AVAHI
++VAR cups_array_t *Timeouts; /* Timed callbacks for main loop */
++#endif /* HAVE_AVAHI */
+
+ /*
+ * Prototypes...
+@@ -224,3 +237,15 @@ extern void cupsdStopSelect(void);
+ /* server.c */
+ extern void cupsdStartServer(void);
+ extern void cupsdStopServer(void);
++
++#ifdef HAVE_AVAHI
++extern void cupsdInitTimeouts(void);
++extern cupsd_timeout_t *cupsdAddTimeout (const struct timeval *tv,
++ cupsd_timeoutfunc_t cb,
++ void *data);
++extern cupsd_timeout_t *cupsdNextTimeout (long *delay);
++extern void cupsdRunTimeout (cupsd_timeout_t *timeout);
++extern void cupsdUpdateTimeout (cupsd_timeout_t *timeout,
++ const struct timeval *tv);
++extern void cupsdRemoveTimeout (cupsd_timeout_t *timeout);
++#endif /* HAVE_AVAHI */
+\ No newline at end of file
+diff -up cups-2.2.5/scheduler/dirsvc.c.avahi-no-threaded cups-2.2.5/scheduler/dirsvc.c
+--- cups-2.2.5/scheduler/dirsvc.c.avahi-no-threaded 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/scheduler/dirsvc.c 2017-10-17 19:05:35.938592292 +0200
+@@ -193,7 +193,7 @@ cupsdStartBrowsing(void)
+ cupsdUpdateDNSSDName();
+
+ # else /* HAVE_AVAHI */
+- if ((DNSSDMaster = avahi_threaded_poll_new()) == NULL)
++ if ((DNSSDMaster = avahi_cups_poll_new()) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create DNS-SD thread.");
+
+@@ -204,7 +204,7 @@ cupsdStartBrowsing(void)
+ {
+ int error; /* Error code, if any */
+
+- DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssdClientCallback, NULL, &error);
++ DNSSDClient = avahi_client_new(avahi_cups_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssdClientCallback, NULL, &error);
+
+ if (DNSSDClient == NULL)
+ {
+@@ -215,11 +215,9 @@ cupsdStartBrowsing(void)
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+
+- avahi_threaded_poll_free(DNSSDMaster);
++ avahi_cups_poll_free(DNSSDMaster);
+ DNSSDMaster = NULL;
+ }
+- else
+- avahi_threaded_poll_start(DNSSDMaster);
+ }
+ # endif /* HAVE_DNSSD */
+ }
+@@ -635,7 +633,7 @@ dnssdClientCallback(
+ * Renew Avahi client...
+ */
+
+- DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssdClientCallback, NULL, &error);
++ DNSSDClient = avahi_client_new(avahi_cups_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssdClientCallback, NULL, &error);
+
+ if (!DNSSDClient)
+ {
+@@ -701,13 +699,7 @@ dnssdDeregisterInstance(
+ # else /* HAVE_AVAHI */
+ if (*srv)
+ {
+- if (!from_callback)
+- avahi_threaded_poll_lock(DNSSDMaster);
+-
+ avahi_entry_group_free(*srv);
+-
+- if (!from_callback)
+- avahi_threaded_poll_unlock(DNSSDMaster);
+ }
+ # endif /* HAVE_DNSSD */
+
+@@ -1029,16 +1021,10 @@ dnssdRegisterInstance(
+ (void)commit;
+
+ # else /* HAVE_AVAHI */
+- if (!from_callback)
+- avahi_threaded_poll_lock(DNSSDMaster);
+-
+ if (!*srv)
+ *srv = avahi_entry_group_new(DNSSDClient, dnssdRegisterCallback, NULL);
+ if (!*srv)
+ {
+- if (!from_callback)
+- avahi_threaded_poll_unlock(DNSSDMaster);
+-
+ cupsdLogMessage(CUPSD_LOG_WARN, "DNS-SD registration of \"%s\" failed: %s",
+ name, dnssdErrorString(avahi_client_errno(DNSSDClient)));
+ return (0);
+@@ -1153,9 +1139,6 @@ dnssdRegisterInstance(
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD commit of \"%s\" failed.",
+ name);
+ }
+-
+- if (!from_callback)
+- avahi_threaded_poll_unlock(DNSSDMaster);
+ # endif /* HAVE_DNSSD */
+
+ if (error)
+@@ -1326,9 +1309,6 @@ dnssdStop(void)
+ DNSSDMaster = NULL;
+
+ # else /* HAVE_AVAHI */
+- if (DNSSDMaster)
+- avahi_threaded_poll_stop(DNSSDMaster);
+-
+ if (DNSSDClient)
+ {
+ avahi_client_free(DNSSDClient);
+@@ -1337,7 +1317,7 @@ dnssdStop(void)
+
+ if (DNSSDMaster)
+ {
+- avahi_threaded_poll_free(DNSSDMaster);
++ avahi_cups_poll_free(DNSSDMaster);
+ DNSSDMaster = NULL;
+ }
+ # endif /* HAVE_DNSSD */
+diff -up cups-2.2.5/scheduler/dirsvc.h.avahi-no-threaded cups-2.2.5/scheduler/dirsvc.h
+--- cups-2.2.5/scheduler/dirsvc.h.avahi-no-threaded 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/scheduler/dirsvc.h 2017-10-17 19:03:00.761881007 +0200
+@@ -49,7 +49,7 @@ VAR cups_array_t *DNSSDPrinters VALUE(NU
+ VAR DNSServiceRef DNSSDMaster VALUE(NULL);
+ /* Master DNS-SD service reference */
+ # else /* HAVE_AVAHI */
+-VAR AvahiThreadedPoll *DNSSDMaster VALUE(NULL);
++VAR AvahiCupsPoll *DNSSDMaster VALUE(NULL);
+ /* Master polling interface for Avahi */
+ VAR AvahiClient *DNSSDClient VALUE(NULL);
+ /* Client information */
+diff -up cups-2.2.5/scheduler/main.c.avahi-no-threaded cups-2.2.5/scheduler/main.c
+--- cups-2.2.5/scheduler/main.c.avahi-no-threaded 2017-10-17 19:03:00.753881074 +0200
++++ cups-2.2.5/scheduler/main.c 2017-10-17 19:03:00.761881007 +0200
+@@ -131,7 +131,10 @@ main(int argc, /* I - Number of comm
+ int service_idle_exit;
+ /* Idle exit on select timeout? */
+ #endif /* HAVE_ONDEMAND */
+-
++#ifdef HAVE_AVAHI
++ cupsd_timeout_t *tmo; /* Next scheduled timed callback */
++ long tmo_delay; /* Time before it must be called */
++#endif /* HAVE_AVAHI */
+
+ #ifdef HAVE_GETEUID
+ /*
+@@ -610,6 +613,14 @@ main(int argc, /* I - Number of comm
+
+ httpInitialize();
+
++#ifdef HAVE_AVAHI
++ /*
++ * Initialize timed callback structures.
++ */
++
++ cupsdInitTimeouts();
++#endif /* HAVE_AVAHI */
++
+ cupsdStartServer();
+
+ /*
+@@ -928,6 +939,16 @@ main(int argc, /* I - Number of comm
+ }
+ #endif /* __APPLE__ */
+
++#ifdef HAVE_AVAHI
++ /*
++ * If a timed callback is due, run it.
++ */
++
++ tmo = cupsdNextTimeout (&tmo_delay);
++ if (tmo && tmo_delay == 0)
++ cupsdRunTimeout (tmo);
++#endif /* HAVE_AVAHI */
++
+ #ifndef __APPLE__
+ /*
+ * Update the network interfaces once a minute...
+@@ -1632,6 +1653,10 @@ select_timeout(int fds) /* I - Number
+ cupsd_job_t *job; /* Job information */
+ cupsd_printer_t *printer; /* Printer information */
+ const char *why; /* Debugging aid */
++#ifdef HAVE_AVAHI
++ cupsd_timeout_t *tmo; /* Timed callback */
++ long tmo_delay; /* Seconds before calling it */
++#endif /* HAVE_AVAHI */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout: JobHistoryUpdate=%ld",
+@@ -1677,6 +1702,19 @@ select_timeout(int fds) /* I - Number
+ }
+ #endif /* __APPLE__ */
+
++#ifdef HAVE_AVAHI
++ /*
++ * See if there are any scheduled timed callbacks to run.
++ */
++
++ if ((tmo = cupsdNextTimeout(&tmo_delay)) != NULL &&
++ (now + tmo_delay) < timeout)
++ {
++ timeout = tmo_delay;
++ why = "run a timed callback";
++ }
++#endif /* HAVE_AVAHI */
++
+ /*
+ * Check whether we are accepting new connections...
+ */
+diff -up cups-2.2.5/scheduler/Makefile.avahi-no-threaded cups-2.2.5/scheduler/Makefile
+--- cups-2.2.5/scheduler/Makefile.avahi-no-threaded 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/scheduler/Makefile 2017-10-17 19:03:00.762880999 +0200
+@@ -15,6 +15,7 @@ include ../Makedefs
+
+ CUPSDOBJS = \
+ auth.o \
++ avahi.o \
+ banners.o \
+ cert.o \
+ classes.o \
+@@ -38,7 +39,8 @@ CUPSDOBJS = \
+ server.o \
+ statbuf.o \
+ subscriptions.o \
+- sysman.o
++ sysman.o \
++ timeout.o
+ LIBOBJS = \
+ filter.o \
+ mime.o \
+diff -up cups-2.2.5/scheduler/timeout.c.avahi-no-threaded cups-2.2.5/scheduler/timeout.c
+--- cups-2.2.5/scheduler/timeout.c.avahi-no-threaded 2017-10-17 19:03:00.762880999 +0200
++++ cups-2.2.5/scheduler/timeout.c 2017-10-17 19:03:00.762880999 +0200
+@@ -0,0 +1,235 @@
++/*
++ * "$Id$"
++ *
++ * Timeout functions for the Common UNIX Printing System (CUPS).
++ *
++ * Copyright (C) 2010, 2011 Red Hat, Inc.
++ * Authors:
++ * Tim Waugh
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ *
++ * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in the
++ * documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
++ * OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * Contents:
++ *
++ * cupsdInitTimeouts() - Initialise timeout structure.
++ * cupsdAddTimeout() - Add a timed callback.
++ * cupsdNextTimeout() - Find the next enabled timed callback.
++ * cupsdUpdateTimeout() - Adjust the time of a timed callback or disable it.
++ * cupsdRemoveTimeout() - Discard a timed callback.
++ * compare_timeouts() - Compare timed callbacks for array sorting.
++ */
++
++#include
++
++#ifdef HAVE_AVAHI /* Applies to entire file... */
++
++/*
++ * Include necessary headers...
++ */
++
++#include "cupsd.h"
++
++#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
++# include
++#endif /* HAVE_MALLOC_H && HAVE_MALLINFO */
++
++#ifdef HAVE_AVAHI
++# include
++#endif /* HAVE_AVAHI */
++
++
++struct _cupsd_timeout_s
++{
++ struct timeval when;
++ int enabled;
++ cupsd_timeoutfunc_t callback;
++ void *data;
++};
++
++/*
++ * Local functions...
++ */
++
++/*
++ * 'compare_timeouts()' - Compare timed callbacks for array sorting.
++ */
++
++static int
++compare_addrs (void *p0, void *p1)
++{
++ if (p0 == p1)
++ return (0);
++ if (p0 < p1)
++ return (-1);
++ return (1);
++}
++
++static int
++compare_timeouts (cupsd_timeout_t *p0, cupsd_timeout_t *p1)
++{
++ int addrsdiff = compare_addrs (p0, p1);
++ int tvdiff;
++
++ if (addrsdiff == 0)
++ return (0);
++
++ if (!p0->enabled || !p1->enabled)
++ {
++ if (!p0->enabled && !p1->enabled)
++ return (addrsdiff);
++
++ return (p0->enabled ? -1 : 1);
++ }
++
++ tvdiff = avahi_timeval_compare (&p0->when, &p1->when);
++ if (tvdiff != 0)
++ return (tvdiff);
++
++ return (addrsdiff);
++}
++
++
++/*
++ * 'cupsdInitTimeouts()' - Initialise timeout structures.
++ */
++
++void
++cupsdInitTimeouts(void)
++{
++ Timeouts = cupsArrayNew ((cups_array_func_t)compare_timeouts, NULL);
++}
++
++
++/*
++ * 'cupsdAddTimeout()' - Add a timed callback.
++ */
++
++cupsd_timeout_t * /* O - Timeout handle */
++cupsdAddTimeout(const struct timeval *tv, /* I - Absolute time */
++ cupsd_timeoutfunc_t cb, /* I - Callback function */
++ void *data) /* I - User data */
++{
++ cupsd_timeout_t *timeout;
++
++ timeout = malloc (sizeof(cupsd_timeout_t));
++ if (timeout != NULL)
++ {
++ timeout->enabled = (tv != NULL);
++ if (tv)
++ {
++ timeout->when.tv_sec = tv->tv_sec;
++ timeout->when.tv_usec = tv->tv_usec;
++ }
++
++ timeout->callback = cb;
++ timeout->data = data;
++ cupsArrayAdd (Timeouts, timeout);
++ }
++
++ return timeout;
++}
++
++
++/*
++ * 'cupsdNextTimeout()' - Find the next enabled timed callback.
++ */
++
++cupsd_timeout_t * /* O - Next enabled timeout or NULL */
++cupsdNextTimeout(long *delay) /* O - Seconds before scheduled */
++{
++ cupsd_timeout_t *first = cupsArrayFirst (Timeouts);
++ struct timeval curtime;
++
++ if (first && !first->enabled)
++ first = NULL;
++
++ if (first && delay)
++ {
++ gettimeofday (&curtime, NULL);
++ if (avahi_timeval_compare (&curtime, &first->when) > 0)
++ {
++ *delay = 0;
++ } else {
++ *delay = 1 + first->when.tv_sec - curtime.tv_sec;
++ if (first->when.tv_usec < curtime.tv_usec)
++ (*delay)--;
++ }
++ }
++
++ return (first);
++}
++
++
++/*
++ * 'cupsdRunTimeout()' - Run a timed callback.
++ */
++
++void
++cupsdRunTimeout(cupsd_timeout_t *timeout) /* I - Timeout */
++{
++ if (!timeout)
++ return;
++ timeout->enabled = 0;
++ if (!timeout->callback)
++ return;
++ timeout->callback (timeout, timeout->data);
++}
++
++/*
++ * 'cupsdUpdateTimeout()' - Adjust the time of a timed callback or disable it.
++ */
++
++void
++cupsdUpdateTimeout(cupsd_timeout_t *timeout, /* I - Timeout */
++ const struct timeval *tv) /* I - Absolute time or NULL */
++{
++ cupsArrayRemove (Timeouts, timeout);
++ timeout->enabled = (tv != NULL);
++ if (tv)
++ {
++ timeout->when.tv_sec = tv->tv_sec;
++ timeout->when.tv_usec = tv->tv_usec;
++ }
++ cupsArrayAdd (Timeouts, timeout);
++}
++
++
++/*
++ * 'cupsdRemoveTimeout()' - Discard a timed callback.
++ */
++
++void
++cupsdRemoveTimeout(cupsd_timeout_t *timeout) /* I - Timeout */
++{
++ cupsArrayRemove (Timeouts, timeout);
++ free (timeout);
++}
++
++
++#endif /* HAVE_AVAHI ... from top of file */
++
++/*
++ * End of "$Id$".
++ */
diff --git a/SOURCES/cups-banners.patch b/SOURCES/cups-banners.patch
new file mode 100644
index 0000000..aa19282
--- /dev/null
+++ b/SOURCES/cups-banners.patch
@@ -0,0 +1,12 @@
+diff -up cups-1.5b1/scheduler/banners.c.banners cups-1.5b1/scheduler/banners.c
+--- cups-1.5b1/scheduler/banners.c.banners 2011-05-20 05:49:49.000000000 +0200
++++ cups-1.5b1/scheduler/banners.c 2011-05-23 17:35:30.000000000 +0200
+@@ -110,6 +110,8 @@ cupsdLoadBanners(const char *d) /* I -
+ if ((ext = strrchr(dent->filename, '.')) != NULL)
+ if (!strcmp(ext, ".bck") ||
+ !strcmp(ext, ".bak") ||
++ !strcmp(ext, ".rpmnew") ||
++ !strcmp(ext, ".rpmsave") ||
+ !strcmp(ext, ".sav"))
+ continue;
+
diff --git a/SOURCES/cups-direct-usb.patch b/SOURCES/cups-direct-usb.patch
new file mode 100644
index 0000000..4e25ce7
--- /dev/null
+++ b/SOURCES/cups-direct-usb.patch
@@ -0,0 +1,27 @@
+diff -up cups-1.5b1/backend/usb-unix.c.direct-usb cups-1.5b1/backend/usb-unix.c
+--- cups-1.5b1/backend/usb-unix.c.direct-usb 2011-05-20 05:49:49.000000000 +0200
++++ cups-1.5b1/backend/usb-unix.c 2011-05-23 17:52:14.000000000 +0200
+@@ -102,6 +102,9 @@ print_device(const char *uri, /* I - De
+ _cups_strncasecmp(hostname, "Minolta", 7);
+ #endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__ */
+
++ if (use_bc && !strncmp(uri, "usb:/dev/", 9))
++ use_bc = 0;
++
+ if ((device_fd = open_device(uri, &use_bc)) == -1)
+ {
+ if (getenv("CLASS") != NULL)
+@@ -331,12 +334,7 @@ open_device(const char *uri, /* I - Dev
+ if (!strncmp(uri, "usb:/dev/", 9))
+ #ifdef __linux
+ {
+- /*
+- * Do not allow direct devices anymore...
+- */
+-
+- errno = ENODEV;
+- return (-1);
++ return (open(uri + 4, O_RDWR | O_EXCL));
+ }
+ else if (!strncmp(uri, "usb://", 6))
+ {
diff --git a/SOURCES/cups-dnssd-deviceid.patch b/SOURCES/cups-dnssd-deviceid.patch
new file mode 100644
index 0000000..7bd2463
--- /dev/null
+++ b/SOURCES/cups-dnssd-deviceid.patch
@@ -0,0 +1,38 @@
+diff -up cups-2.1.4/backend/dnssd.c.dnssd-deviceid cups-2.1.4/backend/dnssd.c
+--- cups-2.1.4/backend/dnssd.c.dnssd-deviceid 2016-06-15 14:36:19.922353606 +0200
++++ cups-2.1.4/backend/dnssd.c 2016-06-15 14:45:45.794966648 +0200
+@@ -1188,15 +1188,22 @@ query_callback(
+ if (device->device_id)
+ free(device->device_id);
+
++if (device_id[0])
++{
++ /* Mark this as the real device ID. */
++ ptr = device_id + strlen(device_id);
++ snprintf(ptr, sizeof(device_id) - (ptr - device_id), "FZY:0;");
++}
++
+ if (!device_id[0] && strcmp(model, "Unknown"))
+ {
+ if (make_and_model[0])
+- snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;",
++ snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;FZY:1;",
+ make_and_model, model);
+ else if (!_cups_strncasecmp(model, "designjet ", 10))
+- snprintf(device_id, sizeof(device_id), "MFG:HP;MDL:%s;", model + 10);
++ snprintf(device_id, sizeof(device_id), "MFG:HP;MDL:%s;FZY:1;", model + 10);
+ else if (!_cups_strncasecmp(model, "stylus ", 7))
+- snprintf(device_id, sizeof(device_id), "MFG:EPSON;MDL:%s;", model + 7);
++ snprintf(device_id, sizeof(device_id), "MFG:EPSON;MDL:%s;FZY:1;", model + 7);
+ else if ((ptr = strchr(model, ' ')) != NULL)
+ {
+ /*
+@@ -1206,7 +1213,7 @@ query_callback(
+ memcpy(make_and_model, model, (size_t)(ptr - model));
+ make_and_model[ptr - model] = '\0';
+
+- snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;",
++ snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;FZY:1;",
+ make_and_model, ptr + 1);
+ }
+ }
diff --git a/SOURCES/cups-driverd-timeout.patch b/SOURCES/cups-driverd-timeout.patch
new file mode 100644
index 0000000..b7240a3
--- /dev/null
+++ b/SOURCES/cups-driverd-timeout.patch
@@ -0,0 +1,21 @@
+diff -up cups-1.7b1/scheduler/ipp.c.driverd-timeout cups-1.7b1/scheduler/ipp.c
+--- cups-1.7b1/scheduler/ipp.c.driverd-timeout 2013-04-19 12:24:43.003841810 +0200
++++ cups-1.7b1/scheduler/ipp.c 2013-04-19 12:24:43.204839107 +0200
+@@ -4556,7 +4556,7 @@ copy_model(cupsd_client_t *con, /* I -
+ close(temppipe[1]);
+
+ /*
+- * Wait up to 30 seconds for the PPD file to be copied...
++ * Wait up to 70 seconds for the PPD file to be copied...
+ */
+
+ total = 0;
+@@ -4576,7 +4576,7 @@ copy_model(cupsd_client_t *con, /* I -
+ FD_SET(temppipe[0], &input);
+ FD_SET(CGIPipes[0], &input);
+
+- timeout.tv_sec = 30;
++ timeout.tv_sec = 70;
+ timeout.tv_usec = 0;
+
+ if ((i = select(maxfd, &input, NULL, NULL, &timeout)) < 0)
diff --git a/SOURCES/cups-dymo-deviceid.patch b/SOURCES/cups-dymo-deviceid.patch
new file mode 100644
index 0000000..cc2995d
--- /dev/null
+++ b/SOURCES/cups-dymo-deviceid.patch
@@ -0,0 +1,11 @@
+diff -up cups-1.6.2/ppdc/sample.drv.dymo-deviceid cups-1.6.2/ppdc/sample.drv
+--- cups-1.6.2/ppdc/sample.drv.dymo-deviceid 2013-06-18 16:57:02.110662953 +0100
++++ cups-1.6.2/ppdc/sample.drv 2013-06-18 16:58:56.513989117 +0100
+@@ -125,6 +125,7 @@ Version "1.5"
+ {
+ Manufacturer "Dymo"
+ ModelName "Label Printer"
++ Attribute "1284DeviceID" "" "MFG:DYMO;MDL:LabelWriter 400;"
+ Attribute NickName "" "Dymo Label Printer"
+ PCFileName "dymo.ppd"
+ DriverType label
diff --git a/SOURCES/cups-eggcups.patch b/SOURCES/cups-eggcups.patch
new file mode 100644
index 0000000..b1eb218
--- /dev/null
+++ b/SOURCES/cups-eggcups.patch
@@ -0,0 +1,130 @@
+diff -up cups-2.2.5/backend/ipp.c.eggcups cups-2.2.5/backend/ipp.c
+--- cups-2.2.5/backend/ipp.c.eggcups 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/backend/ipp.c 2017-10-17 18:56:42.409024451 +0200
+@@ -149,6 +149,70 @@ static char tmpfilename[1024] = "";
+ static char mandatory_attrs[1024] = "";
+ /* cupsMandatory value */
+
++#if HAVE_DBUS
++#include
++
++static DBusConnection *dbus_connection = NULL;
++
++static int
++init_dbus (void)
++{
++ DBusConnection *connection;
++ DBusError error;
++
++ if (dbus_connection &&
++ !dbus_connection_get_is_connected (dbus_connection)) {
++ dbus_connection_unref (dbus_connection);
++ dbus_connection = NULL;
++ }
++
++ dbus_error_init (&error);
++ connection = dbus_bus_get (getuid () ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error);
++ if (connection == NULL) {
++ dbus_error_free (&error);
++ return -1;
++ }
++
++ dbus_connection = connection;
++ return 0;
++}
++
++int
++dbus_broadcast_queued_remote (const char *printer_uri,
++ ipp_status_t status,
++ unsigned int local_job_id,
++ unsigned int remote_job_id,
++ const char *username,
++ const char *printer_name)
++{
++ DBusMessage *message;
++ DBusMessageIter iter;
++ const char *errstr;
++
++ if (!dbus_connection || !dbus_connection_get_is_connected (dbus_connection)) {
++ if (init_dbus () || !dbus_connection)
++ return -1;
++ }
++
++ errstr = ippErrorString (status);
++ message = dbus_message_new_signal ("/com/redhat/PrinterSpooler",
++ "com.redhat.PrinterSpooler",
++ "JobQueuedRemote");
++ dbus_message_iter_init_append (message, &iter);
++ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &printer_uri);
++ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &errstr);
++ dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &local_job_id);
++ dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &remote_job_id);
++ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &username);
++ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &printer_name);
++
++ dbus_connection_send (dbus_connection, message, NULL);
++ dbus_connection_flush (dbus_connection);
++ dbus_message_unref (message);
++
++ return 0;
++}
++#endif /* HAVE_DBUS */
+
+ /*
+ * Local functions...
+@@ -1743,6 +1807,15 @@ main(int argc, /* I - Number of comm
+ fprintf(stderr, "DEBUG: Print job accepted - job ID %d.\n", job_id);
+ }
+
++#if HAVE_DBUS
++ dbus_broadcast_queued_remote (argv[0],
++ ipp_status,
++ atoi (argv[1]),
++ job_id,
++ argv[2],
++ getenv ("PRINTER"));
++#endif /* HAVE_DBUS */
++
+ ippDelete(response);
+
+ if (job_canceled)
+diff -up cups-2.2.5/backend/Makefile.eggcups cups-2.2.5/backend/Makefile
+--- cups-2.2.5/backend/Makefile.eggcups 2017-10-17 18:56:42.409024451 +0200
++++ cups-2.2.5/backend/Makefile 2017-10-17 18:59:11.696781116 +0200
+@@ -262,7 +262,7 @@ dnssd: dnssd.o ../cups/$(LIBCUPS) libbac
+
+ ipp: ipp.o ../cups/$(LIBCUPS) libbackend.a
+ echo Linking $@...
+- $(LD_CC) $(LDFLAGS) -o ipp ipp.o libbackend.a $(LIBS)
++ $(LD_CC) $(LDFLAGS) -o ipp ipp.o libbackend.a $(LIBS) $(SERVERLIBS)
+ $(RM) http
+ $(LN) ipp http
+
+diff -up cups-2.2.5/scheduler/subscriptions.c.eggcups cups-2.2.5/scheduler/subscriptions.c
+--- cups-2.2.5/scheduler/subscriptions.c.eggcups 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/scheduler/subscriptions.c 2017-10-17 18:56:42.409024451 +0200
+@@ -1291,13 +1291,13 @@ cupsd_send_dbus(cupsd_eventmask_t event,
+ what = "PrinterAdded";
+ else if (event & CUPSD_EVENT_PRINTER_DELETED)
+ what = "PrinterRemoved";
+- else if (event & CUPSD_EVENT_PRINTER_CHANGED)
+- what = "QueueChanged";
+ else if (event & CUPSD_EVENT_JOB_CREATED)
+ what = "JobQueuedLocal";
+ else if ((event & CUPSD_EVENT_JOB_STATE) && job &&
+ job->state_value == IPP_JOB_PROCESSING)
+ what = "JobStartedLocal";
++ else if (event & (CUPSD_EVENT_PRINTER_CHANGED|CUPSD_EVENT_JOB_STATE_CHANGED|CUPSD_EVENT_PRINTER_STATE_CHANGED))
++ what = "QueueChanged";
+ else
+ return;
+
+@@ -1333,7 +1333,7 @@ cupsd_send_dbus(cupsd_eventmask_t event,
+ dbus_message_append_iter_init(message, &iter);
+ if (dest)
+ dbus_message_iter_append_string(&iter, dest->name);
+- if (job)
++ if (job && strcmp (what, "QueueChanged") != 0)
+ {
+ dbus_message_iter_append_uint32(&iter, job->id);
+ dbus_message_iter_append_string(&iter, job->username);
diff --git a/SOURCES/cups-filter-debug.patch b/SOURCES/cups-filter-debug.patch
new file mode 100644
index 0000000..96c82da
--- /dev/null
+++ b/SOURCES/cups-filter-debug.patch
@@ -0,0 +1,32 @@
+diff -up cups-1.6b1/scheduler/job.c.filter-debug cups-1.6b1/scheduler/job.c
+--- cups-1.6b1/scheduler/job.c.filter-debug 2012-05-25 16:06:01.000000000 +0200
++++ cups-1.6b1/scheduler/job.c 2012-05-25 16:07:46.309259511 +0200
+@@ -625,10 +625,28 @@ cupsdContinueJob(cupsd_job_t *job) /* I
+
+ if (!filters)
+ {
++ mime_filter_t *current;
++
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to convert file %d to printable format.",
+ job->current_file);
+
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Required: %s/%s -> %s/%s",
++ job->filetypes[job->current_file]->super,
++ job->filetypes[job->current_file]->type,
++ job->printer->filetype->super,
++ job->printer->filetype->type);
++
++ for (current = (mime_filter_t *)cupsArrayFirst(MimeDatabase->srcs);
++ current;
++ current = (mime_filter_t *)cupsArrayNext(MimeDatabase->srcs))
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Available: %s/%s -> %s/%s (%s)",
++ current->src->super, current->src->type,
++ current->dst->super, current->dst->type,
++ current->filter);
++
+ abort_message = "Aborting job because it cannot be printed.";
+ abort_state = IPP_JOB_ABORTED;
+
diff --git a/SOURCES/cups-freebind.patch b/SOURCES/cups-freebind.patch
new file mode 100644
index 0000000..6d9ba43
--- /dev/null
+++ b/SOURCES/cups-freebind.patch
@@ -0,0 +1,15 @@
+diff -up cups-2.0.2/cups/http-addr.c.freebind cups-2.0.2/cups/http-addr.c
+--- cups-2.0.2/cups/http-addr.c.freebind 2015-02-10 14:46:33.000000000 +0100
++++ cups-2.0.2/cups/http-addr.c 2015-02-10 14:50:35.074759141 +0100
+@@ -186,6 +186,10 @@ httpAddrListen(http_addr_t *addr, /* I -
+ val = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, CUPS_SOCAST &val, sizeof(val));
+
++#ifdef __linux
++ setsockopt(fd, IPPROTO_IP, IP_FREEBIND, CUPS_SOCAST &val, sizeof(val));
++#endif /* __linux */
++
+ #ifdef IPV6_V6ONLY
+ if (addr->addr.sa_family == AF_INET6)
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, CUPS_SOCAST &val, sizeof(val));
+diff -up cups-2.0.2/scheduler/listen.c.freebind cups-2.0.2/scheduler/listen.c
diff --git a/SOURCES/cups-hp-deviceid-oid.patch b/SOURCES/cups-hp-deviceid-oid.patch
new file mode 100644
index 0000000..da5136a
--- /dev/null
+++ b/SOURCES/cups-hp-deviceid-oid.patch
@@ -0,0 +1,21 @@
+diff -up cups-1.5b1/backend/snmp.c.hp-deviceid-oid cups-1.5b1/backend/snmp.c
+--- cups-1.5b1/backend/snmp.c.hp-deviceid-oid 2011-05-20 05:49:49.000000000 +0200
++++ cups-1.5b1/backend/snmp.c 2011-05-24 17:24:48.000000000 +0200
+@@ -187,6 +187,7 @@ static const int UriOID[] = { CUPS_OID_p
+ static const int LexmarkProductOID[] = { 1,3,6,1,4,1,641,2,1,2,1,2,1,-1 };
+ static const int LexmarkProductOID2[] = { 1,3,6,1,4,1,674,10898,100,2,1,2,1,2,1,-1 };
+ static const int LexmarkDeviceIdOID[] = { 1,3,6,1,4,1,641,2,1,2,1,3,1,-1 };
++static const int HPDeviceIdOID[] = { 1,3,6,1,4,1,11,2,3,9,1,1,7,0,-1 };
+ static const int XeroxProductOID[] = { 1,3,6,1,4,1,128,2,1,3,1,2,0,-1 };
+ static cups_array_t *DeviceURIs = NULL;
+ static int HostNameLookups = 0;
+@@ -1006,6 +1007,9 @@ read_snmp_response(int fd) /* I - SNMP
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, XeroxProductOID);
++ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
++ packet.community, CUPS_ASN1_GET_REQUEST,
++ DEVICE_ID, HPDeviceIdOID);
+ break;
+
+ case DEVICE_DESCRIPTION :
diff --git a/SOURCES/cups-ipp-multifile.patch b/SOURCES/cups-ipp-multifile.patch
new file mode 100644
index 0000000..beac7fa
--- /dev/null
+++ b/SOURCES/cups-ipp-multifile.patch
@@ -0,0 +1,15 @@
+diff -up cups-1.7.0/backend/ipp.c.ipp-multifile cups-1.7.0/backend/ipp.c
+--- cups-1.7.0/backend/ipp.c.ipp-multifile 2013-10-24 15:52:00.745814354 +0100
++++ cups-1.7.0/backend/ipp.c 2013-10-24 15:53:46.463266724 +0100
+@@ -1758,7 +1758,10 @@ main(int argc, /* I - Number of comm
+ ippAddBoolean(request, IPP_TAG_OPERATION, "last-document",
+ (i + 1) >= num_files);
+
+- if (document_format)
++ if (num_files > 1)
++ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
++ "document-format", NULL, "application/octet-stream");
++ else if (document_format)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
+ "document-format", NULL, document_format);
+
diff --git a/SOURCES/cups-logrotate.patch b/SOURCES/cups-logrotate.patch
new file mode 100644
index 0000000..6b8eb8c
--- /dev/null
+++ b/SOURCES/cups-logrotate.patch
@@ -0,0 +1,63 @@
+diff -up cups-2.1b1/scheduler/log.c.logrotate cups-2.1b1/scheduler/log.c
+--- cups-2.1b1/scheduler/log.c.logrotate 2015-06-04 20:00:31.000000000 +0200
++++ cups-2.1b1/scheduler/log.c 2015-06-29 13:25:09.623350218 +0200
+@@ -26,6 +26,9 @@
+ # include
+ #endif /* HAVE_ASL_H */
+ #include
++#include
++#include
++#include
+
+
+ /*
+@@ -135,12 +138,10 @@ cupsdCheckLogFile(cups_file_t **lf, /* I
+ }
+
+ /*
+- * Format the filename as needed...
++ * Format the filename...
+ */
+
+- if (!*lf ||
+- (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
+- MaxLogSize > 0))
++ if (strncmp(logname, "/dev/", 5))
+ {
+ /*
+ * Handle format strings...
+@@ -254,6 +255,34 @@ cupsdCheckLogFile(cups_file_t **lf, /* I
+ /*
+ * Change ownership and permissions of non-device logs...
+ */
++
++ fchown(cupsFileNumber(*lf), RunUser, Group);
++ fchmod(cupsFileNumber(*lf), LogFilePerm);
++ }
++ }
++
++ /*
++ * Has someone else (i.e. logrotate) already rotated the log for us?
++ */
++ else if (strncmp(filename, "/dev/", 5))
++ {
++ struct stat st;
++ if (stat(filename, &st) || st.st_size == 0)
++ {
++ /* File is either missing or has zero size. */
++
++ cupsFileClose(*lf);
++ if ((*lf = cupsFileOpen(filename, "a")) == NULL)
++ {
++ syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
++ strerror(errno));
++
++ return (0);
++ }
++
++ /*
++ * Change ownership and permissions of non-device logs...
++ */
+
+ fchown(cupsFileNumber(*lf), RunUser, Group);
+ fchmod(cupsFileNumber(*lf), LogFilePerm);
diff --git a/SOURCES/cups-lpr-help.patch b/SOURCES/cups-lpr-help.patch
new file mode 100644
index 0000000..f025698
--- /dev/null
+++ b/SOURCES/cups-lpr-help.patch
@@ -0,0 +1,48 @@
+diff -up cups-2.2b2/berkeley/lpr.c.lpr-help cups-2.2b2/berkeley/lpr.c
+--- cups-2.2b2/berkeley/lpr.c.lpr-help 2016-06-24 17:43:35.000000000 +0200
++++ cups-2.2b2/berkeley/lpr.c 2016-06-27 15:11:30.646348752 +0200
+@@ -18,6 +18,31 @@
+ #include
+
+
++static void
++usage (const char *name)
++{
++ _cupsLangPrintf(stdout,
++"Usage: %s [OPTION] [ file(s) ]\n"
++"Print files.\n\n"
++" -E force encryption\n"
++" -H server[:port] specify alternate server\n"
++" -C title, -J title, -T title\n"
++" set the job name\n\n"
++" -P destination/instance print to named printer\n"
++" -U username specify alternate username\n"
++" -# num-copies set number of copies\n"
++" -h disable banner printing\n"
++" -l print without filtering\n"
++" -m send email on completion\n"
++" -o option[=value] set a job option\n"
++" -p format text file with header\n"
++" -q hold job for printing\n"
++" -r delete files after printing\n"
++"\nWith no file given, read standard input.\n"
++, name);
++}
++
++
+ /*
+ * 'main()' - Parse options and send files for printing.
+ */
+@@ -281,6 +306,12 @@ main(int argc, /* I - Number of comm
+ break;
+
+ default :
++ if (!strcmp (argv[i], "--help"))
++ {
++ usage (argv[0]);
++ return (0);
++ }
++
+ _cupsLangPrintf(stderr, _("%s: Error - unknown option \"%c\"."), argv[0], *opt);
+ return (1);
+ }
diff --git a/SOURCES/cups-lspp.patch b/SOURCES/cups-lspp.patch
new file mode 100644
index 0000000..13cfb16
--- /dev/null
+++ b/SOURCES/cups-lspp.patch
@@ -0,0 +1,1997 @@
+diff -up cups-2.2.5/config.h.in.lspp cups-2.2.5/config.h.in
+--- cups-2.2.5/config.h.in.lspp 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/config.h.in 2017-10-17 19:06:19.640228964 +0200
+@@ -730,4 +730,11 @@ static __inline int _cups_abs(int i) { r
+ # endif /* __GNUC__ || __STDC_VERSION__ */
+ #endif /* !HAVE_ABS && !abs */
+
++/*
++ * Are we trying to meet LSPP requirements?
++ */
++
++#undef WITH_LSPP
++
++
+ #endif /* !_CUPS_CONFIG_H_ */
+diff -up cups-2.2.5/config-scripts/cups-lspp.m4.lspp cups-2.2.5/config-scripts/cups-lspp.m4
+--- cups-2.2.5/config-scripts/cups-lspp.m4.lspp 2017-10-17 19:06:19.640228964 +0200
++++ cups-2.2.5/config-scripts/cups-lspp.m4 2017-10-17 19:06:19.640228964 +0200
+@@ -0,0 +1,36 @@
++dnl
++dnl LSPP code for the Common UNIX Printing System (CUPS).
++dnl
++dnl Copyright 2005-2006 by Hewlett-Packard Development Company, L.P.
++dnl
++dnl This program is free software; you can redistribute it and/or modify
++dnl it under the terms of the GNU General Public License as published by
++dnl the Free Software Foundation; version 2.
++dnl
++dnl This program is distributed in the hope that it will be useful, but
++dnl WITHOUT ANY WARRANTY; without even the implied warranty of
++dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++dnl General Public License for more details.
++dnl
++dnl You should have received a copy of the GNU General Public License
++dnl along with this program; if not, write to the Free Software Foundation,
++dnl Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301 USA
++dnl
++
++dnl Are we trying to meet LSPP requirements
++AC_ARG_ENABLE(lspp, [ --enable-lspp turn on auditing and label support, default=no])
++
++if test x"$enable_lspp" != xno; then
++ case "$uname" in
++ Linux)
++ AC_CHECK_LIB(audit,audit_log_user_message, [LIBAUDIT="-laudit" AC_SUBST(LIBAUDIT)])
++ AC_CHECK_HEADER(libaudit.h)
++ AC_CHECK_LIB(selinux,getpeercon, [LIBSELINUX="-lselinux" AC_SUBST(LIBSELINUX)])
++ AC_CHECK_HEADER(selinux/selinux.h)
++ AC_DEFINE(WITH_LSPP)
++ ;;
++ *)
++ # All others
++ ;;
++ esac
++fi
+diff -up cups-2.2.5/configure.ac.lspp cups-2.2.5/configure.ac
+--- cups-2.2.5/configure.ac.lspp 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/configure.ac 2017-10-17 19:06:19.640228964 +0200
+@@ -38,6 +38,8 @@ sinclude(config-scripts/cups-startup.m4)
+ sinclude(config-scripts/cups-defaults.m4)
+ sinclude(config-scripts/cups-scripting.m4)
+
++sinclude(config-scripts/cups-lspp.m4)
++
+ INSTALL_LANGUAGES=""
+ UNINSTALL_LANGUAGES=""
+ LANGFILES=""
+diff -up cups-2.2.5/filter/common.c.lspp cups-2.2.5/filter/common.c
+--- cups-2.2.5/filter/common.c.lspp 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/filter/common.c 2017-10-17 19:06:19.640228964 +0200
+@@ -17,6 +17,12 @@
+ * Include necessary headers...
+ */
+
++#include "config.h"
++#ifdef WITH_LSPP
++#define _GNU_SOURCE
++#include
++#endif /* WITH_LSPP */
++
+ #include "common.h"
+ #include
+
+@@ -299,6 +305,18 @@ WriteLabelProlog(const char *label, /* I
+ {
+ const char *classification; /* CLASSIFICATION environment variable */
+ const char *ptr; /* Temporary string pointer */
++#ifdef WITH_LSPP
++ int i, /* counter */
++ n, /* counter */
++ lines, /* number of lines needed */
++ line_len, /* index into tmp_label */
++ label_len, /* length of the label in characters */
++ label_index, /* index into the label */
++ longest, /* length of the longest line */
++ longest_line, /* index to the longest line */
++ max_width; /* maximum width in characters */
++ char **wrapped_label; /* label with line breaks */
++#endif /* WITH_LSPP */
+
+
+ /*
+@@ -321,6 +339,124 @@ WriteLabelProlog(const char *label, /* I
+ return;
+ }
+
++#ifdef WITH_LSPP
++ if (strncmp(classification, "LSPP:", 5) == 0 && label == NULL)
++ {
++ /*
++ * Based on the 12pt fixed width font below determine the max_width
++ */
++ max_width = width / 8;
++ longest_line = 0;
++ longest = 0;
++ classification += 5; // Skip the "LSPP:"
++ label_len = strlen(classification);
++
++ if (label_len > max_width)
++ {
++ lines = 1 + (int)(label_len / max_width);
++ line_len = (int)(label_len / lines);
++ wrapped_label = malloc(sizeof(*wrapped_label) * lines);
++ label_index = i = n = 0;
++ while (classification[label_index])
++ {
++ if ((label_index + line_len) > label_len)
++ break;
++ switch (classification[label_index + line_len + i])
++ {
++ case ':':
++ case ',':
++ case '-':
++ i++;
++ wrapped_label[n++] = strndup(&classification[label_index], (line_len + i));
++ label_index += line_len + i;
++ i = 0;
++ break;
++ default:
++ i++;
++ break;
++ }
++ if ((i + line_len) == max_width)
++ {
++ wrapped_label[n++] = strndup(&(classification[label_index]), (line_len + i));
++ label_index = label_index + line_len + i;
++ i = 0;
++ }
++ }
++ wrapped_label[n] = strndup(&classification[label_index], label_len - label_index);
++ }
++ else
++ {
++ lines = 1;
++ wrapped_label = malloc(sizeof(*wrapped_label));
++ wrapped_label[0] = (char*)classification;
++ }
++
++ for (n = 0; n < lines; n++ )
++ {
++ printf("userdict/ESPp%c(", ('a' + n));
++ for (ptr = wrapped_label[n], i = 0; *ptr; ptr ++, i++)
++ if (*ptr < 32 || *ptr > 126)
++ printf("\\%03o", *ptr);
++ else
++ {
++ if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
++ putchar('\\');
++
++ printf("%c", *ptr);
++ }
++ if (i > longest)
++ {
++ longest = i;
++ longest_line = n;
++ }
++ printf(")put\n");
++ }
++
++ /*
++ * For LSPP use a fixed width font so that line wrapping can be calculated
++ */
++
++ puts("userdict/ESPlf /Nimbus-Mono findfont 12 scalefont put");
++
++ /*
++ * Finally, the procedure to write the labels on the page...
++ */
++
++ printf("userdict/ESPwl{\n"
++ " ESPlf setfont\n");
++ printf(" ESPp%c stringwidth pop dup 12 add exch -0.5 mul %.0f add\n ",
++ 'a' + longest_line, width * 0.5f);
++ for (n = 1; n < lines; n++)
++ printf(" dup");
++ printf("\n 1 setgray\n");
++ printf(" dup 6 sub %.0f %d index %.0f ESPrf\n",
++ (bottom - 2.0), (2 + lines), 6.0 + (16.0 * lines));
++ printf(" dup 6 sub %.0f %d index %.0f ESPrf\n",
++ (top - 6.0 - (16.0 * lines)), (2 + lines), 4.0 + (16.0 * lines));
++ printf(" 0 setgray\n");
++ printf(" dup 6 sub %.0f %d index %.0f ESPrs\n",
++ (bottom - 2.0), (2 + lines), 6.0 + (16.0 * lines));
++ printf(" dup 6 sub %.0f %d index %.0f ESPrs\n",
++ (top - 6.0 - (16.0 * lines)), (2 + lines), 4.0 + (16.0 * lines));
++ for (n = 0; n < lines; n ++)
++ {
++ printf(" dup %.0f moveto ESPp%c show\n",
++ bottom + 6.0 + ((lines - (n+1)) * 16.0), 'a' + n);
++ printf(" %.0f moveto ESPp%c show\n", top + 2.0 - ((n + 1) * 16.0), 'a' + n);
++ }
++ printf(" pop\n"
++ "}bind put\n");
++
++ /*
++ * Do some clean up at the end of the LSPP special case
++ */
++ free(wrapped_label);
++
++ }
++ else
++ {
++#endif /* !WITH_LSPP */
++
+ /*
+ * Set the classification + page label string...
+ */
+@@ -401,7 +537,10 @@ WriteLabelProlog(const char *label, /* I
+ printf(" %.0f moveto ESPpl show\n", top - 14.0);
+ puts("pop");
+ puts("}bind put");
++ }
++#ifdef WITH_LSPP
+ }
++#endif /* WITH_LSPP */
+
+
+ /*
+diff -up cups-2.2.5/filter/pstops.c.lspp cups-2.2.5/filter/pstops.c
+--- cups-2.2.5/filter/pstops.c.lspp 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/filter/pstops.c 2017-10-17 19:06:19.641228955 +0200
+@@ -3176,6 +3176,18 @@ write_label_prolog(pstops_doc_t *doc, /*
+ {
+ const char *classification; /* CLASSIFICATION environment variable */
+ const char *ptr; /* Temporary string pointer */
++#ifdef WITH_LSPP
++ int i, /* counter */
++ n, /* counter */
++ lines, /* number of lines needed */
++ line_len, /* index into tmp_label */
++ label_len, /* length of the label in characters */
++ label_index, /* index into the label */
++ longest, /* length of the longest line */
++ longest_line, /* index to the longest line */
++ max_width; /* maximum width in characters */
++ char **wrapped_label; /* label with line breaks */
++#endif /* WITH_LSPP */
+
+
+ /*
+@@ -3198,6 +3210,124 @@ write_label_prolog(pstops_doc_t *doc, /*
+ return;
+ }
+
++#ifdef WITH_LSPP
++ if (strncmp(classification, "LSPP:", 5) == 0 && label == NULL)
++ {
++ /*
++ * Based on the 12pt fixed width font below determine the max_width
++ */
++ max_width = width / 8;
++ longest_line = 0;
++ longest = 0;
++ classification += 5; // Skip the "LSPP:"
++ label_len = strlen(classification);
++
++ if (label_len > max_width)
++ {
++ lines = 1 + (int)(label_len / max_width);
++ line_len = (int)(label_len / lines);
++ wrapped_label = malloc(sizeof(*wrapped_label) * lines);
++ label_index = i = n = 0;
++ while (classification[label_index])
++ {
++ if ((label_index + line_len) > label_len)
++ break;
++ switch (classification[label_index + line_len + i])
++ {
++ case ':':
++ case ',':
++ case '-':
++ i++;
++ wrapped_label[n++] = strndup(&classification[label_index], (line_len + i));
++ label_index += line_len + i;
++ i = 0;
++ break;
++ default:
++ i++;
++ break;
++ }
++ if ((i + line_len) == max_width)
++ {
++ wrapped_label[n++] = strndup(&(classification[label_index]), (line_len + i));
++ label_index = label_index + line_len + i;
++ i = 0;
++ }
++ }
++ wrapped_label[n] = strndup(&classification[label_index], label_len - label_index);
++ }
++ else
++ {
++ lines = 1;
++ wrapped_label = malloc(sizeof(*wrapped_label));
++ wrapped_label[0] = (char*)classification;
++ }
++
++ for (n = 0; n < lines; n++ )
++ {
++ printf("userdict/ESPp%c(", ('a' + n));
++ for (ptr = wrapped_label[n], i = 0; *ptr; ptr ++, i++)
++ if (*ptr < 32 || *ptr > 126)
++ printf("\\%03o", *ptr);
++ else
++ {
++ if (*ptr == '(' || *ptr == ')' || *ptr == '\\')
++ putchar('\\');
++
++ printf("%c", *ptr);
++ }
++ if (i > longest)
++ {
++ longest = i;
++ longest_line = n;
++ }
++ printf(")put\n");
++ }
++
++ /*
++ * For LSPP use a fixed width font so that line wrapping can be calculated
++ */
++
++ puts("userdict/ESPlf /Nimbus-Mono findfont 12 scalefont put");
++
++ /*
++ * Finally, the procedure to write the labels on the page...
++ */
++
++ printf("userdict/ESPwl{\n"
++ " ESPlf setfont\n");
++ printf(" ESPp%c stringwidth pop dup 12 add exch -0.5 mul %.0f add\n ",
++ 'a' + longest_line, width * 0.5f);
++ for (n = 1; n < lines; n++)
++ printf(" dup");
++ printf("\n 1 setgray\n");
++ printf(" dup 6 sub %.0f %d index %.0f ESPrf\n",
++ (bottom - 2.0), (2 + lines), 6.0 + (16.0 * lines));
++ printf(" dup 6 sub %.0f %d index %.0f ESPrf\n",
++ (top - 6.0 - (16.0 * lines)), (2 + lines), 4.0 + (16.0 * lines));
++ printf(" 0 setgray\n");
++ printf(" dup 6 sub %.0f %d index %.0f ESPrs\n",
++ (bottom - 2.0), (2 + lines), 6.0 + (16.0 * lines));
++ printf(" dup 6 sub %.0f %d index %.0f ESPrs\n",
++ (top - 6.0 - (16.0 * lines)), (2 + lines), 4.0 + (16.0 * lines));
++ for (n = 0; n < lines; n ++)
++ {
++ printf(" dup %.0f moveto ESPp%c show\n",
++ bottom + 6.0 + ((lines - (n+1)) * 16.0), 'a' + n);
++ printf(" %.0f moveto ESPp%c show\n", top + 2.0 - ((n + 1) * 16.0), 'a' + n);
++ }
++ printf(" pop\n"
++ "}bind put\n");
++
++ /*
++ * Do some clean up at the end of the LSPP special case
++ */
++ free(wrapped_label);
++
++ }
++ else
++ {
++#endif /* !WITH_LSPP */
++
+ /*
+ * Set the classification + page label string...
+ */
+@@ -3276,7 +3406,10 @@ write_label_prolog(pstops_doc_t *doc, /*
+ doc_printf(doc, " %.0f moveto ESPpl show\n", top - 14.0);
+ doc_puts(doc, "pop\n");
+ doc_puts(doc, "}bind put\n");
++ }
++#ifdef WITH_LSPP
+ }
++#endif /* WITH_LSPP */
+
+
+ /*
+diff -up cups-2.2.5/Makedefs.in.lspp cups-2.2.5/Makedefs.in
+--- cups-2.2.5/Makedefs.in.lspp 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/Makedefs.in 2017-10-17 19:06:19.641228955 +0200
+@@ -161,7 +161,7 @@ LDFLAGS = -L../cgi-bin -L../cups -L../f
+ @LDFLAGS@ @RELROFLAGS@ @PIEFLAGS@ $(OPTIM)
+ LINKCUPS = @LINKCUPS@ $(LIBGSSAPI) $(DNSSDLIBS) $(SSLLIBS) $(LIBZ)
+ LINKCUPSIMAGE = @LINKCUPSIMAGE@
+-LIBS = $(LINKCUPS) $(COMMONLIBS)
++LIBS = $(LINKCUPS) $(COMMONLIBS) @LIBAUDIT@ @LIBSELINUX@
+ ONDEMANDFLAGS = @ONDEMANDFLAGS@
+ ONDEMANDLIBS = @ONDEMANDLIBS@
+ OPTIM = @OPTIM@
+diff -up cups-2.2.5/scheduler/client.c.lspp cups-2.2.5/scheduler/client.c
+--- cups-2.2.5/scheduler/client.c.lspp 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/scheduler/client.c 2017-10-17 19:06:19.689228556 +0200
+@@ -22,12 +22,20 @@
+ #define _HTTP_NO_PRIVATE
+ #include "cupsd.h"
+
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE
++#endif /* !defined(_GNU_SOURCE) */
+ #ifdef __APPLE__
+ # include
+ #endif /* __APPLE__ */
+ #ifdef HAVE_TCPD_H
+ # include
+ #endif /* HAVE_TCPD_H */
++#ifdef WITH_LSPP
++# include
++# include
++# include
++#endif /* WITH_LSPP */
+
+
+ /*
+@@ -268,6 +276,59 @@ cupsdAcceptClient(cupsd_listener_t *lis)
+ }
+ #endif /* HAVE_TCPD_H */
+
++#ifdef WITH_LSPP
++ if (is_lspp_config())
++ {
++ struct ucred cr;
++ unsigned int cl=sizeof(cr);
++
++ if (getsockopt(httpGetFd(con->http), SOL_SOCKET, SO_PEERCRED, &cr, &cl) == 0)
++ {
++ /*
++ * client_pid_to_auid() can be racey
++ * In this case the pid is based on a socket connected to the client
++ */
++ if ((con->auid = client_pid_to_auid(cr.pid)) == -1)
++ {
++ httpClose(con->http);
++ cupsdLogClient(con, CUPSD_LOG_ERROR,
++ "Unable to determine client auid for client pid=%d",
++ cr.pid);
++ free(con);
++ return;
++ }
++ cupsdLogClient(con, CUPSD_LOG_INFO,
++ "peer's pid=%d, uid=%d, gid=%d, auid=%d",
++ cr.pid, cr.uid, cr.gid, con->auid);
++ }
++ else
++ {
++ httpClose(con->http);
++ cupsdLogClient(con, CUPSD_LOG_ERROR, "getsockopt() failed");
++ free(con);
++ return;
++ }
++
++ /*
++ * get the context of the peer connection
++ */
++ if (getpeercon(httpGetFd(con->http), &con->scon))
++ {
++ httpClose(con->http);
++ cupsdLogClient(con, CUPSD_LOG_ERROR, "getpeercon() failed");
++ free(con);
++ return;
++ }
++
++ cupsdLogClient(con, CUPSD_LOG_INFO, "client context=%s", con->scon);
++ }
++ else
++ {
++ cupsdLogClient(con, CUPSD_LOG_DEBUG, "skipping getpeercon()");
++ cupsdSetString(&con->scon, UNKNOWN_SL);
++ }
++#endif /* WITH_LSPP */
++
+ #ifdef AF_LOCAL
+ if (httpAddrFamily(httpGetAddress(con->http)) == AF_LOCAL)
+ {
+@@ -562,6 +623,13 @@ cupsdReadClient(cupsd_client_t *con) /*
+ mime_type_t *type; /* MIME type of file */
+ cupsd_printer_t *p; /* Printer */
+ static unsigned request_id = 0; /* Request ID for temp files */
++#ifdef WITH_LSPP
++ security_context_t spoolcon; /* context of the job file */
++ context_t clicon; /* contex_t container for con->scon */
++ context_t tmpcon; /* temp context to swap the level */
++ char *clirange; /* SELinux sensitivity range */
++ char *cliclearance; /* SELinux low end clearance */
++#endif /* WITH_LSPP */
+
+
+ status = HTTP_STATUS_CONTINUE;
+@@ -1926,6 +1994,73 @@ cupsdReadClient(cupsd_client_t *con) /*
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+ }
+
++#ifdef WITH_LSPP
++ if (strncmp(con->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
++ {
++ if (getfilecon(con->filename, &spoolcon) == -1)
++ {
++ cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
++ cupsdCloseClient(con);
++ return;
++ }
++ clicon = context_new(con->scon);
++ tmpcon = context_new(spoolcon);
++ freecon(spoolcon);
++ if (!clicon || !tmpcon)
++ {
++ cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
++ if (clicon)
++ context_free(clicon);
++ if (tmpcon)
++ context_free(tmpcon);
++ cupsdCloseClient(con);
++ return;
++ }
++ clirange = (char *) context_range_get(clicon);
++ if (clirange)
++ {
++ clirange = strdup(clirange);
++ if ((cliclearance = strtok(clirange, "-")) != NULL)
++ {
++ if (context_range_set(tmpcon, cliclearance) == -1)
++ {
++ cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
++ free(clirange);
++ context_free(tmpcon);
++ context_free(clicon);
++ cupsdCloseClient(con);
++ return;
++ }
++ }
++ else
++ {
++ if (context_range_set(tmpcon, (context_range_get(clicon))) == -1)
++ {
++ cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
++ free(clirange);
++ context_free(tmpcon);
++ context_free(clicon);
++ cupsdCloseClient(con);
++ return;
++ }
++ }
++ free(clirange);
++ }
++ if (setfilecon(con->filename, context_str(tmpcon)) == -1)
++ {
++ cupsdSendError(con, HTTP_STATUS_SERVER_ERROR, CUPSD_AUTH_NONE);
++ context_free(tmpcon);
++ context_free(clicon);
++ cupsdCloseClient(con);
++ return;
++ }
++ cupsdLogClient(con, CUPSD_LOG_DEBUG2, "%s set to %s",
++ con->filename, context_str(tmpcon));
++ context_free(tmpcon);
++ context_free(clicon);
++ }
++#endif /* WITH_LSPP */
++
+ if (httpGetState(con->http) != HTTP_STATE_POST_SEND)
+ {
+ if (!httpWait(con->http, 0))
+@@ -3456,6 +3591,49 @@ is_path_absolute(const char *path) /* I
+ return (1);
+ }
+
++#ifdef WITH_LSPP
++/*
++ * 'client_pid_to_auid()' - Using the client's pid, read /proc and determine the loginuid.
++ */
++
++uid_t client_pid_to_auid(pid_t clipid)
++{
++ uid_t uid;
++ int len, in;
++ char buf[16] = {0};
++ char fname[32] = {0};
++
++
++ /*
++ * Hopefully this pid is still the one we are interested in.
++ */
++ snprintf(fname, 32, "/proc/%d/loginuid", clipid);
++ in = open(fname, O_NOFOLLOW|O_RDONLY);
++
++ if (in < 0)
++ return (uid_t) -1;
++
++ errno = 0;
++
++ do {
++ len = read(in, buf, sizeof(buf));
++ } while (len < 0 && errno == EINTR);
++
++ close(in);
++
++ if (len < 0 || len >= sizeof(buf))
++ return (uid_t) -1;
++
++ errno = 0;
++ buf[len] = 0;
++ uid = strtol(buf, 0, 10);
++
++ if (errno != 0)
++ return (uid_t) -1;
++ else
++ return uid;
++}
++#endif /* WITH_LSPP */
+
+ /*
+ * 'pipe_command()' - Pipe the output of a command to the remote client.
+diff -up cups-2.2.5/scheduler/client.h.lspp cups-2.2.5/scheduler/client.h
+--- cups-2.2.5/scheduler/client.h.lspp 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/scheduler/client.h 2017-10-17 19:06:19.690228548 +0200
+@@ -16,6 +16,13 @@
+ #endif /* HAVE_AUTHORIZATION_H */
+
+
++/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
++/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
++
++#ifdef WITH_LSPP
++#include
++#endif /* WITH_LSPP */
++
+ /*
+ * HTTP client structure...
+ */
+@@ -65,6 +72,10 @@ struct cupsd_client_s
+ #ifdef HAVE_AUTHORIZATION_H
+ AuthorizationRef authref; /* Authorization ref */
+ #endif /* HAVE_AUTHORIZATION_H */
++#ifdef WITH_LSPP
++ security_context_t scon; /* Security context of connection */
++ uid_t auid; /* Audit loginuid of the client */
++#endif /* WITH_LSPP */
+ };
+
+ #define HTTP(con) ((con)->http)
+@@ -138,6 +149,9 @@ extern void cupsdStartListening(void);
+ extern void cupsdStopListening(void);
+ extern void cupsdUpdateCGI(void);
+ extern void cupsdWriteClient(cupsd_client_t *con);
++#ifdef WITH_LSPP
++extern uid_t client_pid_to_auid(pid_t clipid);
++#endif /* WITH_LSPP */
+
+ #ifdef HAVE_SSL
+ extern int cupsdEndTLS(cupsd_client_t *con);
+diff -up cups-2.2.5/scheduler/conf.c.lspp cups-2.2.5/scheduler/conf.c
+--- cups-2.2.5/scheduler/conf.c.lspp 2017-10-17 19:06:19.637228989 +0200
++++ cups-2.2.5/scheduler/conf.c 2017-10-17 19:06:19.691228540 +0200
+@@ -40,6 +40,9 @@
+ # define INADDR_NONE 0xffffffff
+ #endif /* !INADDR_NONE */
+
++#ifdef WITH_LSPP
++# include
++#endif /* WITH_LSPP */
+
+ /*
+ * Configuration variable structure...
+@@ -131,6 +134,10 @@ static const cupsd_var_t cupsd_vars[] =
+ { "ServerName", &ServerName, CUPSD_VARTYPE_STRING },
+ { "StrictConformance", &StrictConformance, CUPSD_VARTYPE_BOOLEAN },
+ { "Timeout", &Timeout, CUPSD_VARTYPE_TIME },
++#ifdef WITH_LSPP
++ { "AuditLog", &AuditLog, CUPSD_VARTYPE_INTEGER },
++ { "PerPageLabels", &PerPageLabels, CUPSD_VARTYPE_BOOLEAN },
++#endif /* WITH_LSPP */
+ { "WebInterface", &WebInterface, CUPSD_VARTYPE_BOOLEAN }
+ };
+ static const cupsd_var_t cupsfiles_vars[] =
+@@ -544,6 +551,9 @@ cupsdReadConfiguration(void)
+ const char *tmpdir; /* TMPDIR environment variable */
+ struct stat tmpinfo; /* Temporary directory info */
+ cupsd_policy_t *p; /* Policy */
++#ifdef WITH_LSPP
++ char *audit_message; /* Audit message string */
++#endif /* WITH_LSPP */
+
+
+ /*
+@@ -866,6 +876,25 @@ cupsdReadConfiguration(void)
+
+ RunUser = getuid();
+
++#ifdef WITH_LSPP
++ if (AuditLog != -1)
++ {
++ /*
++ * ClassifyOverride is set during read_configuration, if its ON, report it now
++ */
++ if (ClassifyOverride)
++ audit_log_user_message(AuditLog, AUDIT_USYS_CONFIG,
++ "[Config] ClassifyOverride=enabled Users can override print banners",
++ ServerName, NULL, NULL, 1);
++ /*
++ * PerPageLabel is set during read_configuration, if its OFF, report it now
++ */
++ if (!PerPageLabels)
++ audit_log_user_message(AuditLog, AUDIT_USYS_CONFIG,
++ "[Config] PerPageLabels=disabled", ServerName, NULL, NULL, 1);
++ }
++#endif /* WITH_LSPP */
++
+ cupsdLogMessage(CUPSD_LOG_INFO, "Remote access is %s.",
+ RemotePort ? "enabled" : "disabled");
+
+@@ -1286,7 +1315,19 @@ cupsdReadConfiguration(void)
+ cupsdClearString(&Classification);
+
+ if (Classification)
++ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Security set to \"%s\"", Classification);
++#ifdef WITH_LSPP
++ if (AuditLog != -1)
++ {
++ audit_message = NULL;
++ cupsdSetStringf(&audit_message, "[Config] Classification=%s", Classification);
++ audit_log_user_message(AuditLog, AUDIT_LABEL_LEVEL_CHANGE, audit_message,
++ ServerName, NULL, NULL, 1);
++ cupsdClearString(&audit_message);
++ }
++#endif /* WITH_LSPP */
++ }
+
+ /*
+ * Check the MaxClients setting, and then allocate memory for it...
+@@ -3770,6 +3811,18 @@ read_location(cups_file_t *fp, /* I - C
+ return ((FatalErrors & CUPSD_FATAL_CONFIG) ? 0 : linenum);
+ }
+
++#ifdef WITH_LSPP
++int is_lspp_config()
++{
++ if (Classification != NULL)
++ return ((_cups_strcasecmp(Classification, MLS_CONFIG) == 0)
++ || (_cups_strcasecmp(Classification, TE_CONFIG) == 0)
++ || (_cups_strcasecmp(Classification, SELINUX_CONFIG) == 0));
++ else
++ return 0;
++}
++#endif /* WITH_LSPP */
++
+
+ /*
+ * 'read_policy()' - Read a definition.
+diff -up cups-2.2.5/scheduler/conf.h.lspp cups-2.2.5/scheduler/conf.h
+--- cups-2.2.5/scheduler/conf.h.lspp 2017-10-17 19:06:19.585229421 +0200
++++ cups-2.2.5/scheduler/conf.h 2017-10-17 19:06:19.691228540 +0200
+@@ -250,6 +250,13 @@ VAR char *ServerKeychain VALUE(NULL);
+ /* Keychain holding cert + key */
+ #endif /* HAVE_SSL */
+
++#ifdef WITH_LSPP
++VAR int AuditLog VALUE(-1),
++ /* File descriptor for audit */
++ PerPageLabels VALUE(TRUE);
++ /* Put the label on each page */
++#endif /* WITH_LSPP */
++
+ #ifdef HAVE_ONDEMAND
+ VAR int IdleExitTimeout VALUE(60);
+ /* Time after which an idle cupsd will exit */
+@@ -268,6 +275,9 @@ VAR int HaveServerCreds VALUE(0);
+ VAR gss_cred_id_t ServerCreds; /* Server's GSS credentials */
+ #endif /* HAVE_GSSAPI */
+
++#ifdef WITH_LSPP
++extern int is_lspp_config(void);
++#endif /* WITH_LSPP */
+
+ /*
+ * Prototypes...
+diff -up cups-2.2.5/scheduler/cupsd.h.lspp cups-2.2.5/scheduler/cupsd.h
+--- cups-2.2.5/scheduler/cupsd.h.lspp 2017-10-17 19:06:19.626229080 +0200
++++ cups-2.2.5/scheduler/cupsd.h 2017-10-17 19:06:19.691228540 +0200
+@@ -11,6 +11,8 @@
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
++/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
++/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
+
+ /*
+ * Include necessary headers.
+@@ -36,13 +38,20 @@
+ # include
+ #endif /* WIN32 */
+
++#include "config.h"
++#ifdef WITH_LSPP
++# define MLS_CONFIG "mls"
++# define TE_CONFIG "te"
++# define SELINUX_CONFIG "SELinux"
++# define UNKNOWN_SL "UNKNOWN SL"
++#endif /* WITH_LSPP */
++
+ #include "mime.h"
+
+ #if defined(HAVE_CDSASSL)
+ # include
+ #endif /* HAVE_CDSASSL */
+
+-
+ /*
+ * Some OS's don't have hstrerror(), most notably Solaris...
+ */
+diff -up cups-2.2.5/scheduler/ipp.c.lspp cups-2.2.5/scheduler/ipp.c
+--- cups-2.2.5/scheduler/ipp.c.lspp 2017-10-17 19:06:19.599229305 +0200
++++ cups-2.2.5/scheduler/ipp.c 2017-10-17 19:06:19.695228506 +0200
+@@ -14,6 +14,9 @@
+ * missing or damaged, see the license at "http://www.cups.org/".
+ */
+
++/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
++/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
++
+ /*
+ * Include necessary headers...
+ */
+@@ -37,6 +40,14 @@ extern int mbr_check_membership_by_id(uu
+ # endif /* HAVE_MEMBERSHIPPRIV_H */
+ #endif /* __APPLE__ */
+
++#ifdef WITH_LSPP
++#include
++#include
++#include
++#include
++#include
++#include
++#endif /* WITH_LSPP */
+
+ /*
+ * Local functions...
+@@ -61,6 +72,9 @@ static void cancel_all_jobs(cupsd_client
+ static void cancel_job(cupsd_client_t *con, ipp_attribute_t *uri);
+ static void cancel_subscription(cupsd_client_t *con, int id);
+ static int check_rss_recipient(const char *recipient);
++#ifdef WITH_LSPP
++static int check_context(cupsd_client_t *con, cupsd_job_t *job);
++#endif /* WITH_LSPP */
+ static int check_quotas(cupsd_client_t *con, cupsd_printer_t *p);
+ static void close_job(cupsd_client_t *con, ipp_attribute_t *uri);
+ static void copy_attrs(ipp_t *to, ipp_t *from, cups_array_t *ra,
+@@ -1286,6 +1300,21 @@ add_job(cupsd_client_t *con, /* I - Cl
+ "time-at-creation",
+ "time-at-processing"
+ };
++#ifdef WITH_LSPP
++ char *audit_message; /* Audit message string */
++ char *printerfile; /* device file pointed to by the printer */
++ char *userheader = NULL; /* User supplied job-sheets[0] */
++ char *userfooter = NULL; /* User supplied job-sheets[1] */
++ int override = 0; /* Was a banner overrode on a job */
++ security_id_t clisid; /* SELinux SID for the client */
++ security_id_t psid; /* SELinux SID for the printer */
++ context_t printercon; /* Printer's context string */
++ struct stat printerstat; /* Printer's stat buffer */
++ security_context_t devcon; /* Printer's SELinux context */
++ struct avc_entry_ref avcref; /* Pointer to the access vector cache */
++ security_class_t tclass; /* Object class for the SELinux check */
++ access_vector_t avr; /* Access method being requested */
++#endif /* WITH_LSPP */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))",
+@@ -1597,6 +1626,106 @@ add_job(cupsd_client_t *con, /* I - Cl
+ return (NULL);
+ }
+
++#ifdef WITH_LSPP
++ if (is_lspp_config())
++ {
++ if (!con->scon || strncmp(con->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0)
++ {
++ cupsdLogMessage(CUPSD_LOG_ERROR, "add_job: missing classification for connection \'%s\'!", printer->name);
++ send_ipp_status(con, IPP_INTERNAL_ERROR, _("Missing required security attributes."));
++ return (NULL);
++ }
++
++ /*
++ * Perform an access check so that if the user gets feedback at enqueue time
++ */
++
++ printerfile = strstr(printer->device_uri, "/dev/");
++ if (printerfile == NULL && (strncmp(printer->device_uri, "file:/", 6) == 0))
++ printerfile = printer->device_uri + strlen("file:");
++
++ if (printerfile != NULL)
++ {
++ cupsdLogMessage(CUPSD_LOG_DEBUG, "add_job: Attempting an access check on printer device %s",
++ printerfile);
++
++ if (lstat(printerfile, &printerstat) < 0)
++ {
++ if (errno != ENOENT)
++ {
++ send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to stat the printer"));
++ return (NULL);
++ }
++ /*
++ * The printer does not exist, so for now assume it's a FileDevice
++ */
++ tclass = SECCLASS_FILE;
++ avr = FILE__WRITE;
++ }
++ else if (S_ISCHR(printerstat.st_mode))
++ {
++ tclass = SECCLASS_CHR_FILE;
++ avr = CHR_FILE__WRITE;
++ }
++ else if (S_ISREG(printerstat.st_mode))
++ {
++ tclass = SECCLASS_FILE;
++ avr = FILE__WRITE;
++ }
++ else
++ {
++ send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Printer is not a character device or regular file"));
++ return (NULL);
++ }
++ static int avc_initialized = 0;
++ if (!avc_initialized++)
++ avc_init("cupsd_enqueue_", NULL, NULL, NULL, NULL);
++ avc_entry_ref_init(&avcref);
++ if (avc_context_to_sid(con->scon, &clisid) != 0)
++ {
++ send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to get the SELinux sid of the client"));
++ return (NULL);
++ }
++ if (getfilecon(printerfile, &devcon) == -1)
++ {
++ send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to get the SELinux context of the printer"));
++ return (NULL);
++ }
++ printercon = context_new(devcon);
++ cupsdLogMessage(CUPSD_LOG_DEBUG, "add_job: printer context %s client context %s",
++ context_str(printercon), con->scon);
++ context_free(printercon);
++
++ if (avc_context_to_sid(devcon, &psid) != 0)
++ {
++ send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Unable to get the SELinux sid of the printer"));
++ freecon(devcon);
++ return (NULL);
++ }
++ freecon(devcon);
++ if (avc_has_perm(clisid, psid, tclass, avr, &avcref, NULL) != 0)
++ {
++ /*
++ * The access check failed, so cancel the job and send an audit message
++ */
++ if (AuditLog != -1)
++ {
++ audit_message = NULL;
++ cupsdSetStringf(&audit_message, "job=? auid=%u acct=%s obj=%s refused"
++ " unable to access printer=%s", con->auid,
++ con->username, con->scon, printer->name);
++ audit_log_user_message(AuditLog, AUDIT_USER_LABELED_EXPORT, audit_message,
++ ServerName, NULL, NULL, 0);
++ cupsdClearString(&audit_message);
++ }
++
++ send_ipp_status(con, IPP_NOT_AUTHORIZED, _("SELinux prohibits access to the printer"));
++ return (NULL);
++ }
++ }
++ }
++#endif /* WITH_LSPP */
++
+ if ((job = cupsdAddJob(priority, printer->name)) == NULL)
+ {
+ send_ipp_status(con, IPP_INTERNAL_ERROR,
+@@ -1605,6 +1734,32 @@ add_job(cupsd_client_t *con, /* I - Cl
+ return (NULL);
+ }
+
++#ifdef WITH_LSPP
++ if (is_lspp_config())
++ {
++ /*
++ * duplicate the security context and auid of the connection into the job structure
++ */
++ job->scon = strdup(con->scon);
++ job->auid = con->auid;
++
++ /*
++ * add the security context to the request so that on a restart the security
++ * attributes will be able to be restored
++ */
++ ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "security-context",
++ NULL, job->scon);
++ }
++ else
++ {
++ /*
++ * Fill in the security context of the job as unlabeled
++ */
++ cupsdLogMessage(CUPSD_LOG_DEBUG, "add_job: setting context of job to %s", UNKNOWN_SL);
++ cupsdSetString(&job->scon, UNKNOWN_SL);
++ }
++#endif /* WITH_LSPP */
++
+ job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
+ job->attrs = con->request;
+ job->dirty = 1;
+@@ -1794,6 +1949,29 @@ add_job(cupsd_client_t *con, /* I - Cl
+ ippSetString(job->attrs, &attr, 0, printer->job_sheets[0]);
+ ippSetString(job->attrs, &attr, 1, printer->job_sheets[1]);
+ }
++#ifdef WITH_LSPP
++ else
++ {
++ /*
++ * The option was present, so capture the user supplied strings
++ */
++ userheader = strdup(attr->values[0].string.text);
++
++ if (attr->num_values > 1)
++ userfooter = strdup(attr->values[1].string.text);
++
++ if (Classification != NULL && (strcmp(userheader, Classification) == 0)
++ && userfooter &&(strcmp(userfooter, Classification) == 0))
++ {
++ /*
++ * Since both values are Classification, the user is not trying to Override
++ */
++ free(userheader);
++ if (userfooter) free(userfooter);
++ userheader = userfooter = NULL;
++ }
++ }
++#endif /* WITH_LSPP */
+
+ job->job_sheets = attr;
+
+@@ -1824,6 +2002,9 @@ add_job(cupsd_client_t *con, /* I - Cl
+ "job-sheets=\"%s,none\", "
+ "job-originating-user-name=\"%s\"",
+ Classification, job->username);
++#ifdef WITH_LSPP
++ override = 1;
++#endif /* WITH_LSPP */
+ }
+ else if (attr->num_values == 2 &&
+ strcmp(attr->values[0].string.text,
+@@ -1842,6 +2023,9 @@ add_job(cupsd_client_t *con, /* I - Cl
+ "job-originating-user-name=\"%s\"",
+ attr->values[0].string.text,
+ attr->values[1].string.text, job->username);
++#ifdef WITH_LSPP
++ override = 1;
++#endif /* WITH_LSPP */
+ }
+ else if (strcmp(attr->values[0].string.text, Classification) &&
+ strcmp(attr->values[0].string.text, "none") &&
+@@ -1862,6 +2046,9 @@ add_job(cupsd_client_t *con, /* I - Cl
+ "job-originating-user-name=\"%s\"",
+ attr->values[0].string.text,
+ attr->values[1].string.text, job->username);
++#ifdef WITH_LSPP
++ override = 1;
++#endif /* WITH_LSPP */
+ }
+ }
+ else if (strcmp(attr->values[0].string.text, Classification) &&
+@@ -1902,8 +2089,52 @@ add_job(cupsd_client_t *con, /* I - Cl
+ "job-sheets=\"%s\", "
+ "job-originating-user-name=\"%s\"",
+ Classification, job->username);
++#ifdef WITH_LSPP
++ override = 1;
++#endif /* WITH_LSPP */
+ }
++#ifdef WITH_LSPP
++ if (is_lspp_config() && AuditLog != -1)
++ {
++ audit_message = NULL;
++
++ if (userheader || userfooter)
++ {
++ if (!override)
++ {
++ /*
++ * The user overrode the banner, so audit it
++ */
++ cupsdSetStringf(&audit_message, "job=%d user supplied job-sheets=%s,%s"
++ " using banners=%s,%s", job->id, userheader,
++ userfooter, attr->values[0].string.text,
++ (attr->num_values > 1) ? attr->values[1].string.text : "(null)");
++ audit_log_user_message(AuditLog, AUDIT_LABEL_OVERRIDE, audit_message,
++ ServerName, NULL, NULL, 1);
++ }
++ else
++ {
++ /*
++ * The user tried to override the banner, audit the failure
++ */
++ cupsdSetStringf(&audit_message, "job=%d user supplied job-sheets=%s,%s"
++ " ignored banners=%s,%s", job->id, userheader,
++ userfooter, attr->values[0].string.text,
++ (attr->num_values > 1) ? attr->values[1].string.text : "(null)");
++ audit_log_user_message(AuditLog, AUDIT_LABEL_OVERRIDE, audit_message,
++ ServerName, NULL, NULL, 0);
++ }
++ cupsdClearString(&audit_message);
++ }
++ }
++
++ if (userheader)
++ free(userheader);
++ if (userfooter)
++ free(userfooter);
++#endif /* WITH_LSPP */
+ }
++
+
+ /*
+ * See if we need to add the starting sheet...
+@@ -3686,6 +3917,128 @@ check_rss_recipient(
+ }
+
+
++#ifdef WITH_LSPP
++/*
++ * 'check_context()' - Check SELinux security context of a user and job
++ */
++
++static int /* O - 1 if OK, 0 if not, -1 on error */
++check_context(cupsd_client_t *con, /* I - Client connection */
++ cupsd_job_t *job) /* I - Job */
++{
++ int enforcing; /* is SELinux in enforcing mode */
++ char filename[1024]; /* Filename of the spool file */
++ security_id_t clisid; /* SELinux SID of the client */
++ security_id_t jobsid; /* SELinux SID of the job */
++ security_id_t filesid; /* SELinux SID of the spool file */
++ struct avc_entry_ref avcref; /* AVC entry cache pointer */
++ security_class_t tclass; /* SELinux security class */
++ access_vector_t avr; /* SELinux access being queried */
++ security_context_t spoolfilecon; /* SELinux context of the spool file */
++
++
++ /*
++ * Validate the input to be sure there are contexts to work with...
++ */
++
++ if (con->scon == NULL || job->scon == NULL
++ || strncmp(con->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0
++ || strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0)
++ return -1;
++
++ if ((enforcing = security_getenforce()) == -1)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Error while determining SELinux enforcement");
++ return -1;
++ }
++ cupsdLogJob(job, CUPSD_LOG_DEBUG,
++ "check_context: client context %s job context %s",
++ con->scon, job->scon);
++
++
++ /*
++ * Initialize the avc engine...
++ */
++
++ static int avc_initialized = 0;
++ if (! avc_initialized++)
++ {
++ if (avc_init("cupsd", NULL, NULL, NULL, NULL) < 0)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR, "check_context: unable avc_init");
++ return -1;
++ }
++ }
++ if (avc_context_to_sid(con->scon, &clisid) != 0)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "check_context: unable to convert %s to SELinux sid",
++ con->scon);
++ return -1;
++ }
++ if (avc_context_to_sid(job->scon, &jobsid) != 0)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "check_context: unable to convert %s to SELinux sid",
++ job->scon);
++ return -1;
++ }
++ avc_entry_ref_init(&avcref);
++ tclass = SECCLASS_FILE;
++ avr = FILE__READ;
++
++ /*
++ * Perform the check with the client as the subject, first with the job as the object
++ * if that fails then with the spool file as the object...
++ */
++
++ if (avc_has_perm_noaudit(clisid, jobsid, tclass, avr, &avcref, NULL) != 0)
++ {
++ cupsdLogJob(job, CUPSD_LOG_INFO,
++ "check_context: SELinux denied access "
++ "based on the client context");
++
++ snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, job->id);
++ if (getfilecon(filename, &spoolfilecon) == -1)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "check_context: Unable to get spoolfile context");
++ return -1;
++ }
++ if (avc_context_to_sid(spoolfilecon, &filesid) != 0)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "check_context: Unable to determine the "
++ "SELinux sid for the spool file");
++ freecon(spoolfilecon);
++ return -1;
++ }
++ freecon(spoolfilecon);
++ if (avc_has_perm_noaudit(clisid, filesid, tclass, avr, &avcref, NULL) != 0)
++ {
++ cupsdLogJob(job, CUPSD_LOG_INFO,
++ "check_context: SELinux denied access to the spool file");
++ return 0;
++ }
++ cupsdLogJob(job, CUPSD_LOG_INFO,
++ "check_context: SELinux allowed access to the spool file");
++ return 1;
++ }
++ else
++ if (enforcing == 0)
++ cupsdLogJob(job, CUPSD_LOG_INFO,
++ "check_context: allowing operation due to permissive mode");
++ else
++ cupsdLogJob(job, CUPSD_LOG_INFO,
++ "check_context: SELinux allowed access based on the "
++ "client context");
++
++ return 1;
++}
++#endif /* WITH_LSPP */
++
++
+ /*
+ * 'check_quotas()' - Check quotas for a printer and user.
+ */
+@@ -4142,6 +4495,15 @@ copy_banner(cupsd_client_t *con, /* I -
+ char attrname[255], /* Name of attribute */
+ *s; /* Pointer into name */
+ ipp_attribute_t *attr; /* Attribute */
++#ifdef WITH_LSPP
++ const char *mls_label; /* SL of print job */
++ char *jobrange; /* SELinux sensitivity range */
++ char *jobclearance; /* SELinux low end clearance */
++ context_t jobcon; /* SELinux context of the job */
++ context_t tmpcon; /* Temp context to set the level */
++ security_context_t spoolcon; /* Context of the file in the spool */
++#endif /* WITH_LSPP */
++
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+@@ -4177,6 +4539,85 @@ copy_banner(cupsd_client_t *con, /* I -
+
+ fchmod(cupsFileNumber(out), 0640);
+ fchown(cupsFileNumber(out), RunUser, Group);
++#ifdef WITH_LSPP
++ if (job->scon != NULL &&
++ strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
++ {
++ if (getfilecon(filename, &spoolcon) == -1)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Unable to get the context of the banner file %s - %s",
++ filename, strerror(errno));
++ job->num_files --;
++ return (0);
++ }
++ tmpcon = context_new(spoolcon);
++ jobcon = context_new(job->scon);
++ freecon(spoolcon);
++ if (!tmpcon || !jobcon)
++ {
++ if (tmpcon)
++ context_free(tmpcon);
++ if (jobcon)
++ context_free(jobcon);
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "copy_banner: Unable to get the SELinux contexts");
++ job->num_files --;
++ return (0);
++ }
++ jobrange = (char *) context_range_get(jobcon);
++ if (jobrange)
++ {
++ jobrange = strdup(jobrange);
++ if ((jobclearance = strtok(jobrange, "-")) != NULL)
++ {
++ if (context_range_set(tmpcon, jobclearance) == -1)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "copy_banner: Unable to set the "
++ "level of the context for file %s - %s",
++ filename, strerror(errno));
++ free(jobrange);
++ context_free(jobcon);
++ context_free(tmpcon);
++ job->num_files --;
++ return (0);
++ }
++ }
++ else
++ {
++ if (context_range_set(tmpcon, (context_range_get(jobcon))) == -1)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "copy_banner: Unable to set the "
++ "level of the context for file %s - %s",
++ filename, strerror(errno));
++ free(jobrange);
++ context_free(jobcon);
++ context_free(tmpcon);
++ job->num_files --;
++ return (0);
++ }
++ }
++ free(jobrange);
++ }
++ if (setfilecon(filename, context_str(tmpcon)) == -1)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "copy_banner: Unable to set the "
++ "context of the banner file %s - %s",
++ filename, strerror(errno));
++ context_free(jobcon);
++ context_free(tmpcon);
++ job->num_files --;
++ return (0);
++ }
++ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "copy_banner: %s set to %s",
++ filename, context_str(tmpcon));
++ context_free(jobcon);
++ context_free(tmpcon);
++ }
++#endif /* WITH_LSPP */
+
+ /*
+ * Try the localized banner file under the subdirectory...
+@@ -4271,6 +4712,24 @@ copy_banner(cupsd_client_t *con, /* I -
+ else
+ s = attrname;
+
++#ifdef WITH_LSPP
++ if (strcmp(s, "mls-label") == 0)
++ {
++ if (job->scon != NULL && strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
++ {
++ jobcon = context_new(job->scon);
++ if (_cups_strcasecmp(name, MLS_CONFIG) == 0)
++ mls_label = context_range_get(jobcon);
++ else if (_cups_strcasecmp(name, TE_CONFIG) == 0)
++ mls_label = context_type_get(jobcon);
++ else // default to using the whole context string
++ mls_label = context_str(jobcon);
++ cupsFilePuts(out, mls_label);
++ context_free(jobcon);
++ }
++ continue;
++ }
++#endif /* WITH_LSPP */
+ if (!strcmp(s, "printer-name"))
+ {
+ cupsFilePuts(out, job->dest);
+@@ -6459,6 +6918,22 @@ get_job_attrs(cupsd_client_t *con, /* I
+
+ exclude = cupsdGetPrivateAttrs(policy, con, printer, job->username);
+
++
++#ifdef WITH_LSPP
++ /*
++ * Check SELinux...
++ */
++ if (is_lspp_config() && check_context(con, job) != 1)
++ {
++ /*
++ * Unfortunately we have to lie to the user...
++ */
++ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
++ return;
++ }
++#endif /* WITH_LSPP */
++
++
+ /*
+ * Copy attributes...
+ */
+@@ -6856,6 +7331,11 @@ get_jobs(cupsd_client_t *con, /* I - C
+ if (username[0] && _cups_strcasecmp(username, job->username))
+ continue;
+
++#ifdef WITH_LSPP
++ if (is_lspp_config() && check_context(con, job) != 1)
++ continue;
++#endif /* WITH_LSPP */
++
+ if (count > 0)
+ ippAddSeparator(con->response);
+
+@@ -11487,6 +11967,11 @@ validate_user(cupsd_job_t *job, /* I
+
+ strlcpy(username, get_username(con), userlen);
+
++#ifdef WITH_LSPP
++ if (is_lspp_config() && check_context(con, job) != 1)
++ return 0;
++#endif /* WITH_LSPP */
++
+ /*
+ * Check the username against the owner...
+ */
+diff -up cups-2.2.5/scheduler/job.c.lspp cups-2.2.5/scheduler/job.c
+--- cups-2.2.5/scheduler/job.c.lspp 2017-10-17 19:06:19.607229238 +0200
++++ cups-2.2.5/scheduler/job.c 2017-10-17 19:06:19.696228498 +0200
+@@ -11,6 +11,9 @@
+ * missing or damaged, see the license at "http://www.cups.org/".
+ */
+
++/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
++/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
++
+ /*
+ * Include necessary headers...
+ */
+@@ -26,6 +29,14 @@
+ # endif /* HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H */
+ #endif /* __APPLE__ */
+
++#ifdef WITH_LSPP
++#include
++#include
++#include
++#include
++#include
++#include
++#endif /* WITH_LSPP */
+
+ /*
+ * Design Notes for Job Management
+@@ -547,6 +558,14 @@ cupsdContinueJob(cupsd_job_t *job) /* I
+ /* PRINTER_STATE_REASONS env var */
+ rip_max_cache[255];
+ /* RIP_MAX_CACHE env variable */
++#ifdef WITH_LSPP
++ char *audit_message = NULL; /* Audit message string */
++ context_t jobcon; /* SELinux context of the job */
++ char *label_template = NULL; /* SL to put in classification
++ env var */
++ const char *mls_label = NULL; /* SL to put in classification
++ env var */
++#endif /* WITH_LSPP */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+@@ -1083,6 +1102,67 @@ cupsdContinueJob(cupsd_job_t *job) /* I
+ if (final_content_type[0])
+ envp[envc ++] = final_content_type;
+
++#ifdef WITH_LSPP
++ if (is_lspp_config())
++ {
++ if (!job->scon || strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) == 0)
++ {
++ if (AuditLog != -1)
++ {
++ audit_message = NULL;
++ cupsdSetStringf(&audit_message, "job=%d auid=%u acct=%s printer=%s title=%s",
++ job->id, job->auid, job->username, job->printer->name, title);
++ audit_log_user_message(AuditLog, AUDIT_USER_UNLABELED_EXPORT, audit_message,
++ ServerName, NULL, NULL, 1);
++ cupsdClearString(&audit_message);
++ }
++ }
++ else
++ {
++ jobcon = context_new(job->scon);
++
++ if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME)) == NULL)
++ label_template = strdup(Classification);
++ else if (attr->num_values > 1 &&
++ strcmp(attr->values[1].string.text, "none") != 0)
++ label_template = strdup(attr->values[1].string.text);
++ else
++ label_template = strdup(attr->values[0].string.text);
++
++ if (_cups_strcasecmp(label_template, MLS_CONFIG) == 0)
++ mls_label = context_range_get(jobcon);
++ else if (_cups_strcasecmp(label_template, TE_CONFIG) == 0)
++ mls_label = context_type_get(jobcon);
++ else if (_cups_strcasecmp(label_template, SELINUX_CONFIG) == 0)
++ mls_label = context_str(jobcon);
++ else
++ mls_label = label_template;
++
++ if (mls_label && (PerPageLabels || banner_page))
++ {
++ snprintf(classification, sizeof(classification), "CLASSIFICATION=LSPP:%s", mls_label);
++ envp[envc ++] = classification;
++ }
++
++ if ((AuditLog != -1) && !banner_page)
++ {
++ audit_message = NULL;
++ cupsdSetStringf(&audit_message, "job=%d auid=%u acct=%s printer=%s title=%s"
++ " obj=%s label=%s", job->id, job->auid, job->username,
++ job->printer->name, title, job->scon, mls_label?mls_label:"none");
++ audit_log_user_message(AuditLog, AUDIT_USER_LABELED_EXPORT, audit_message,
++ ServerName, NULL, NULL, 1);
++ cupsdClearString(&audit_message);
++ }
++ context_free(jobcon);
++ free(label_template);
++ }
++ }
++ else
++ /*
++ * Fall through to the non-LSPP behavior
++ */
++#endif /* WITH_LSPP */
+ if (Classification && !banner_page)
+ {
+ if ((attr = ippFindAttribute(job->attrs, "job-sheets",
+@@ -1908,6 +1988,22 @@ cupsdLoadJob(cupsd_job_t *job) /* I - J
+ ippSetString(job->attrs, &job->reasons, 0, "none");
+ }
+
++#ifdef WITH_LSPP
++ if ((attr = ippFindAttribute(job->attrs, "security-context", IPP_TAG_NAME)) != NULL)
++ cupsdSetString(&job->scon, attr->values[0].string.text);
++ else if (is_lspp_config())
++ {
++ /*
++ * There was no security context so delete the job
++ */
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Missing or bad security-context attribute "
++ "in control file \"%s\"!",
++ jobfile);
++ goto error;
++ }
++#endif /* WITH_LSPP */
++
+ job->impressions = ippFindAttribute(job->attrs, "job-impressions-completed", IPP_TAG_INTEGER);
+ job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed", IPP_TAG_INTEGER);
+ job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
+@@ -2321,6 +2417,14 @@ cupsdSaveJob(cupsd_job_t *job) /* I - J
+ {
+ char filename[1024]; /* Job control filename */
+ cups_file_t *fp; /* Job file */
++#ifdef WITH_LSPP
++ security_context_t spoolcon; /* context of the job control file */
++ context_t jobcon; /* contex_t container for job->scon */
++ context_t tmpcon; /* Temp context to swap the level */
++ char *jobclearance; /* SELinux low end clearance */
++ const char *jobrange; /* SELinux sensitivity range */
++ char *jobrange_copy; /* SELinux sensitivity range */
++#endif /* WITH_LSPP */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSaveJob(job=%p(%d)): job->attrs=%p",
+@@ -2343,6 +2447,78 @@ cupsdSaveJob(cupsd_job_t *job) /* I - J
+
+ fchown(cupsFileNumber(fp), RunUser, Group);
+
++#ifdef WITH_LSPP
++ if (job->scon && strncmp(job->scon, UNKNOWN_SL, strlen(UNKNOWN_SL)) != 0)
++ {
++ if (getfilecon(filename, &spoolcon) == -1)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Unable to get context of job control file \"%s\" - %s.",
++ filename, strerror(errno));
++ return;
++ }
++ jobcon = context_new(job->scon);
++ tmpcon = context_new(spoolcon);
++ freecon(spoolcon);
++ if (!jobcon || !tmpcon)
++ {
++ if (jobcon)
++ context_free(jobcon);
++ if (tmpcon)
++ context_free(tmpcon);
++ cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to get SELinux contexts");
++ return;
++ }
++ jobrange = context_range_get(jobcon);
++ if (jobrange)
++ {
++ jobrange_copy = strdup(jobrange);
++ if ((jobclearance = strtok(jobrange_copy, "-")) != NULL)
++ {
++ if (context_range_set(tmpcon, jobclearance) == -1)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Unable to set the range for "
++ "job control file \"%s\" - %s.",
++ filename, strerror(errno));
++ free(jobrange_copy);
++ context_free(tmpcon);
++ context_free(jobcon);
++ return;
++ }
++ }
++ else
++ {
++ if (context_range_set(tmpcon, (context_range_get(jobcon))) == -1)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Unable to set the range for "
++ "job control file \"%s\" - %s.",
++ filename, strerror(errno));
++ free(jobrange_copy);
++ context_free(tmpcon);
++ context_free(jobcon);
++ return;
++ }
++ }
++ free(jobrange_copy);
++ }
++ if (setfilecon(filename, context_str(tmpcon)) == -1)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Unable to set context of job control file \"%s\" - %s.",
++ filename, strerror(errno));
++ context_free(tmpcon);
++ context_free(jobcon);
++ return;
++ }
++ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "New spool file context=%s",
++ context_str(tmpcon));
++ context_free(tmpcon);
++ context_free(jobcon);
++ }
++#endif /* WITH_LSPP */
++
+ job->attrs->state = IPP_IDLE;
+
+ if (ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL,
+@@ -3989,6 +4165,19 @@ get_options(cupsd_job_t *job, /* I - Jo
+ banner_page)
+ continue;
+
++#ifdef WITH_LSPP
++ /*
++ * In LSPP mode refuse to honor the page-label
++ */
++ if (is_lspp_config() &&
++ !strcmp(attr->name, "page-label"))
++ {
++ cupsdLogJob(job, CUPSD_LOG_DEBUG,
++ "Ignoring page-label option due to LSPP mode");
++ continue;
++ }
++#endif /* WITH_LSPP */
++
+ /*
+ * Otherwise add them to the list...
+ */
+@@ -4750,6 +4939,18 @@ start_job(cupsd_job_t *job, /* I -
+ cupsd_printer_t *printer) /* I - Printer to print job */
+ {
+ const char *filename; /* Support filename */
++#ifdef WITH_LSPP
++ char *audit_message = NULL; /* Audit message string */
++ char *printerfile = NULL; /* Device file pointed to by the printer */
++ security_id_t clisid; /* SELinux SID for the client */
++ security_id_t psid; /* SELinux SID for the printer */
++ context_t printercon; /* Printer's context string */
++ struct stat printerstat; /* Printer's stat buffer */
++ security_context_t devcon; /* Printer's SELinux context */
++ struct avc_entry_ref avcref; /* Pointer to the access vector cache */
++ security_class_t tclass; /* Object class for the SELinux check */
++ access_vector_t avr; /* Access method being requested */
++#endif /* WITH_LSPP */
+ ipp_attribute_t *cancel_after = ippFindAttribute(job->attrs,
+ "job-cancel-after",
+ IPP_TAG_INTEGER);
+@@ -4926,6 +5127,113 @@ start_job(cupsd_job_t *job, /* I -
+ fcntl(job->side_pipes[1], F_SETFD,
+ fcntl(job->side_pipes[1], F_GETFD) | FD_CLOEXEC);
+
++#ifdef WITH_LSPP
++ if (is_lspp_config())
++ {
++ /*
++ * Perform an access check before printing, but only if the printer starts with /dev/
++ */
++ printerfile = strstr(printer->device_uri, "/dev/");
++ if (printerfile == NULL && (strncmp(printer->device_uri, "file:/", 6) == 0))
++ printerfile = printer->device_uri + strlen("file:");
++
++ if (printerfile != NULL)
++ {
++ cupsdLogJob(job, CUPSD_LOG_DEBUG,
++ "Attempting to check access on printer device %s",
++ printerfile);
++ if (lstat(printerfile, &printerstat) < 0)
++ {
++ if (errno != ENOENT)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Unable to stat the printer");
++ cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
++ return ;
++ }
++ /*
++ * The printer does not exist, so for now assume it's a FileDevice
++ */
++ tclass = SECCLASS_FILE;
++ avr = FILE__WRITE;
++ }
++ else if (S_ISCHR(printerstat.st_mode))
++ {
++ tclass = SECCLASS_CHR_FILE;
++ avr = CHR_FILE__WRITE;
++ }
++ else if (S_ISREG(printerstat.st_mode))
++ {
++ tclass = SECCLASS_FILE;
++ avr = FILE__WRITE;
++ }
++ else
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "StartJob: Printer is not a character device or "
++ "regular file");
++ cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
++ return ;
++ }
++ static int avc_initialized = 0;
++ if (!avc_initialized++)
++ avc_init("cupsd_dequeue_", NULL, NULL, NULL, NULL);
++ avc_entry_ref_init(&avcref);
++ if (avc_context_to_sid(job->scon, &clisid) != 0)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Unable to determine the SELinux sid for the job");
++ cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
++ return ;
++ }
++ if (getfilecon(printerfile, &devcon) == -1)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Unable to get the SELinux context of %s",
++ printerfile);
++ cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
++ return ;
++ }
++ printercon = context_new(devcon);
++ cupsdLogJob(job, CUPSD_LOG_DEBUG,
++ "Printer context %s client context %s",
++ context_str(printercon), job->scon);
++ context_free(printercon);
++
++ if (avc_context_to_sid(devcon, &psid) != 0)
++ {
++ cupsdLogJob(job, CUPSD_LOG_ERROR,
++ "Unable to determine the SELinux sid for the printer");
++ freecon(devcon);
++ cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
++ return ;
++ }
++ freecon(devcon);
++
++ if (avc_has_perm(clisid, psid, tclass, avr, &avcref, NULL) != 0)
++ {
++ /*
++ * The access check failed, so cancel the job and send an audit message
++ */
++ if (AuditLog != -1)
++ {
++ audit_message = NULL;
++ cupsdSetStringf(&audit_message, "job=%d auid=%u acct=%s obj=%s canceled"
++ " unable to access printer=%s", job->id,
++ job->auid, (job->username)?job->username:"?", job->scon, printer->name);
++ audit_log_user_message(AuditLog, AUDIT_USER_LABELED_EXPORT, audit_message,
++ ServerName, NULL, NULL, 0);
++ cupsdClearString(&audit_message);
++ }
++
++ cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT, NULL);
++
++ return ;
++ }
++ }
++ }
++#endif /* WITH_LSPP */
++
+ /*
+ * Now start the first file in the job...
+ */
+diff -up cups-2.2.5/scheduler/job.h.lspp cups-2.2.5/scheduler/job.h
+--- cups-2.2.5/scheduler/job.h.lspp 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/scheduler/job.h 2017-10-17 19:06:19.696228498 +0200
+@@ -11,6 +11,13 @@
+ * missing or damaged, see the license at "http://www.cups.org/".
+ */
+
++/* Copyright (C) 2005 Trusted Computer Solutions, Inc. */
++/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
++
++#ifdef WITH_LSPP
++#include
++#endif /* WITH_LSPP */
++
+ /*
+ * Constants...
+ */
+@@ -88,6 +95,10 @@ struct cupsd_job_s /**** Job request *
+ int progress; /* Printing progress */
+ int num_keywords; /* Number of PPD keywords */
+ cups_option_t *keywords; /* PPD keywords */
++#ifdef WITH_LSPP
++ security_context_t scon; /* Security context of job */
++ uid_t auid; /* Audit loginuid for this job */
++#endif /* WITH_LSPP */
+ };
+
+ typedef struct cupsd_joblog_s /**** Job log message ****/
+diff -up cups-2.2.5/scheduler/main.c.lspp cups-2.2.5/scheduler/main.c
+--- cups-2.2.5/scheduler/main.c.lspp 2017-10-17 19:06:19.637228989 +0200
++++ cups-2.2.5/scheduler/main.c 2017-10-17 19:08:26.642173026 +0200
+@@ -56,6 +56,9 @@
+ # include
+ #endif /* HAVE_SYS_PARAM_H */
+
++#ifdef WITH_LSPP
++# include
++#endif /* WITH_LSPP */
+
+ /*
+ * Local functions...
+@@ -122,6 +125,9 @@ main(int argc, /* I - Number of comm
+ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+ struct sigaction action; /* Actions for POSIX signals */
+ #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
++#if WITH_LSPP
++ auditfail_t failmode; /* Action for audit_open failure */
++#endif /* WITH_LSPP */
+ #ifdef __APPLE__
+ int use_sysman = 1; /* Use system management functions? */
+ #else
+@@ -516,6 +522,25 @@ main(int argc, /* I - Number of comm
+ exit(errno);
+ }
+
++#ifdef WITH_LSPP
++ if ((AuditLog = audit_open()) < 0 )
++ {
++ if (get_auditfail_action(&failmode) == 0)
++ {
++ if (failmode == FAIL_LOG)
++ {
++ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to connect to audit subsystem.");
++ AuditLog = -1;
++ }
++ else if (failmode == FAIL_TERMINATE)
++ {
++ fprintf(stderr, "cupsd: unable to start auditing, terminating");
++ return -1;
++ }
++ }
++ }
++#endif /* WITH_LSPP */
++
+ /*
+ * Let the system know we are busy while we bring up cupsd...
+ */
+@@ -1227,6 +1252,11 @@ main(int argc, /* I - Number of comm
+
+ cupsdStopSelect();
+
++#ifdef WITH_LSPP
++ if (AuditLog != -1)
++ audit_close(AuditLog);
++#endif /* WITH_LSPP */
++
+ return (!stop_scheduler);
+ }
+
+diff -up cups-2.2.5/scheduler/printers.c.lspp cups-2.2.5/scheduler/printers.c
+--- cups-2.2.5/scheduler/printers.c.lspp 2017-10-17 19:06:19.587229404 +0200
++++ cups-2.2.5/scheduler/printers.c 2017-10-17 19:06:19.697228490 +0200
+@@ -11,6 +11,8 @@
+ * missing or damaged, see the license at "http://www.cups.org/".
+ */
+
++/* (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P. */
++
+ /*
+ * Include necessary headers...
+ */
+@@ -35,6 +37,10 @@
+ # include
+ #endif /* __APPLE__ */
+
++#ifdef WITH_LSPP
++# include
++# include
++#endif /* WITH_LSPP */
+
+ /*
+ * Local functions...
+@@ -2212,6 +2218,13 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)
+ ipp_attribute_t *attr; /* Attribute data */
+ char *name, /* Current user/group name */
+ *filter; /* Current filter */
++#ifdef WITH_LSPP
++ char *audit_message; /* Audit message string */
++ char *printerfile; /* Path to a local printer dev */
++ char *rangestr; /* Printer's range if its available */
++ security_context_t devcon; /* Printer SELinux context */
++ context_t printercon; /* context_t for the printer */
++#endif /* WITH_LSPP */
+
+
+ DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
+@@ -2339,6 +2352,45 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)
+ attr->values[1].string.text = _cupsStrAlloc(Classification ?
+ Classification : p->job_sheets[1]);
+ }
++#ifdef WITH_LSPP
++ if (AuditLog != -1)
++ {
++ audit_message = NULL;
++ rangestr = NULL;
++ printercon = 0;
++ printerfile = strstr(p->device_uri, "/dev/");
++ if (printerfile == NULL && (strncmp(p->device_uri, "file:/", 6) == 0))
++ printerfile = p->device_uri + strlen("file:");
++
++ if (printerfile != NULL)
++ {
++ if (getfilecon(printerfile, &devcon) == -1)
++ {
++ if(is_selinux_enabled())
++ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetPrinterAttrs: Unable to get printer context");
++ }
++ else
++ {
++ printercon = context_new(devcon);
++ freecon(devcon);
++ }
++ }
++
++ if (printercon && context_range_get(printercon))
++ rangestr = strdup(context_range_get(printercon));
++ else
++ rangestr = strdup("unknown");
++
++ cupsdSetStringf(&audit_message, "printer=%s uri=%s banners=%s,%s range=%s",
++ p->name, p->sanitized_device_uri, p->job_sheets[0], p->job_sheets[1], rangestr);
++ audit_log_user_message(AuditLog, AUDIT_LABEL_LEVEL_CHANGE, audit_message,
++ ServerName, NULL, NULL, 1);
++ if (printercon)
++ context_free(printercon);
++ free(rangestr);
++ cupsdClearString(&audit_message);
++ }
++#endif /* WITH_LSPP */
+ }
+
+ p->raw = 0;
diff --git a/SOURCES/cups-multilib.patch b/SOURCES/cups-multilib.patch
new file mode 100644
index 0000000..3c6bc39
--- /dev/null
+++ b/SOURCES/cups-multilib.patch
@@ -0,0 +1,16 @@
+diff -up cups-1.5b1/cups-config.in.multilib cups-1.5b1/cups-config.in
+--- cups-1.5b1/cups-config.in.multilib 2010-06-16 02:48:25.000000000 +0200
++++ cups-1.5b1/cups-config.in 2011-05-23 17:33:31.000000000 +0200
+@@ -22,8 +22,10 @@ prefix=@prefix@
+ exec_prefix=@exec_prefix@
+ bindir=@bindir@
+ includedir=@includedir@
+-libdir=@libdir@
+-imagelibdir=@libdir@
++# Fetch libdir from gnutls's pkg-config script. This is a bit
++# of a cheat, but the cups-devel package requires gnutls-devel anyway.
++libdir=`pkg-config --variable=libdir gnutls`
++imagelibdir=`pkg-config --variable=libdir gnutls`
+ datarootdir=@datadir@
+ datadir=@datadir@
+ sysconfdir=@sysconfdir@
diff --git a/SOURCES/cups-no-export-ssllibs.patch b/SOURCES/cups-no-export-ssllibs.patch
new file mode 100644
index 0000000..14b4426
--- /dev/null
+++ b/SOURCES/cups-no-export-ssllibs.patch
@@ -0,0 +1,10 @@
+diff -up cups-2.2b2/config-scripts/cups-ssl.m4.no-export-ssllibs cups-2.2b2/config-scripts/cups-ssl.m4
+--- cups-2.2b2/config-scripts/cups-ssl.m4.no-export-ssllibs 2016-06-27 15:06:22.299980753 +0200
++++ cups-2.2b2/config-scripts/cups-ssl.m4 2016-06-27 15:08:00.953154042 +0200
+@@ -102,5 +102,5 @@ AC_SUBST(IPPALIASES)
+ AC_SUBST(SSLFLAGS)
+ AC_SUBST(SSLLIBS)
+
+-EXPORT_SSLLIBS="$SSLLIBS"
++EXPORT_SSLLIBS=""
+ AC_SUBST(EXPORT_SSLLIBS)
diff --git a/SOURCES/cups-no-gzip-man.patch b/SOURCES/cups-no-gzip-man.patch
new file mode 100644
index 0000000..c476b7b
--- /dev/null
+++ b/SOURCES/cups-no-gzip-man.patch
@@ -0,0 +1,18 @@
+diff -up cups-2.2.4/config-scripts/cups-manpages.m4.no-gzip-man cups-2.2.4/config-scripts/cups-manpages.m4
+--- cups-2.2.4/config-scripts/cups-manpages.m4.no-gzip-man 2017-06-30 20:37:09.470034273 +0200
++++ cups-2.2.4/config-scripts/cups-manpages.m4 2017-06-30 20:39:15.982884832 +0200
+@@ -53,10 +53,10 @@ case "$host_os_name" in
+ ;;
+ linux* | gnu* | darwin*)
+ # Linux, GNU Hurd, and macOS
+- MAN1EXT=1.gz
+- MAN5EXT=5.gz
+- MAN7EXT=7.gz
+- MAN8EXT=8.gz
++ MAN1EXT=1
++ MAN5EXT=5
++ MAN7EXT=7
++ MAN8EXT=8
+ MAN8DIR=8
+ ;;
+ *)
diff --git a/SOURCES/cups-peercred.patch b/SOURCES/cups-peercred.patch
new file mode 100644
index 0000000..a106abb
--- /dev/null
+++ b/SOURCES/cups-peercred.patch
@@ -0,0 +1,11 @@
+diff -up cups-1.5b1/scheduler/auth.c.peercred cups-1.5b1/scheduler/auth.c
+--- cups-1.5b1/scheduler/auth.c.peercred 2011-05-20 05:49:49.000000000 +0200
++++ cups-1.5b1/scheduler/auth.c 2011-05-23 18:00:18.000000000 +0200
+@@ -52,6 +52,7 @@
+ * Include necessary headers...
+ */
+
++#define _GNU_SOURCE
+ #include "cupsd.h"
+ #include
+ #ifdef HAVE_SHADOW_H
diff --git a/SOURCES/cups-pid.patch b/SOURCES/cups-pid.patch
new file mode 100644
index 0000000..23ffd47
--- /dev/null
+++ b/SOURCES/cups-pid.patch
@@ -0,0 +1,37 @@
+diff -up cups-1.5b1/scheduler/main.c.pid cups-1.5b1/scheduler/main.c
+--- cups-1.5b1/scheduler/main.c.pid 2011-05-18 22:44:16.000000000 +0200
++++ cups-1.5b1/scheduler/main.c 2011-05-23 18:01:20.000000000 +0200
+@@ -311,6 +311,8 @@ main(int argc, /* I - Number of comm
+ * Setup signal handlers for the parent...
+ */
+
++ pid_t pid;
++
+ #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
+ sigset(SIGUSR1, parent_handler);
+ sigset(SIGCHLD, parent_handler);
+@@ -334,7 +336,7 @@ main(int argc, /* I - Number of comm
+ signal(SIGHUP, SIG_IGN);
+ #endif /* HAVE_SIGSET */
+
+- if (fork() > 0)
++ if ((pid = fork()) > 0)
+ {
+ /*
+ * OK, wait for the child to startup and send us SIGUSR1 or to crash
+@@ -346,7 +348,15 @@ main(int argc, /* I - Number of comm
+ sleep(1);
+
+ if (parent_signal == SIGUSR1)
++ {
++ FILE *f = fopen ("/var/run/cupsd.pid", "w");
++ if (f)
++ {
++ fprintf (f, "%d\n", pid);
++ fclose (f);
++ }
+ return (0);
++ }
+
+ if (wait(&i) < 0)
+ {
diff --git a/SOURCES/cups-res_init.patch b/SOURCES/cups-res_init.patch
new file mode 100644
index 0000000..3866521
--- /dev/null
+++ b/SOURCES/cups-res_init.patch
@@ -0,0 +1,26 @@
+diff -up cups-1.7b1/cups/http-addr.c.res_init cups-1.7b1/cups/http-addr.c
+--- cups-1.7b1/cups/http-addr.c.res_init 2013-03-20 19:14:10.000000000 +0100
++++ cups-1.7b1/cups/http-addr.c 2013-04-19 12:01:36.927512159 +0200
+@@ -319,7 +319,8 @@ httpAddrLookup(
+
+ if (error)
+ {
+- if (error == EAI_FAIL)
++ if (error == EAI_FAIL || error == EAI_AGAIN || error == EAI_NODATA ||
++ error == EAI_NONAME)
+ cg->need_res_init = 1;
+
+ return (httpAddrString(addr, name, namelen));
+diff -up cups-1.7b1/cups/http-addrlist.c.res_init cups-1.7b1/cups/http-addrlist.c
+--- cups-1.7b1/cups/http-addrlist.c.res_init 2013-04-19 12:01:36.930512119 +0200
++++ cups-1.7b1/cups/http-addrlist.c 2013-04-19 12:03:13.769229554 +0200
+@@ -581,7 +581,8 @@ httpAddrGetList(const char *hostname, /*
+ }
+ else
+ {
+- if (error == EAI_FAIL)
++ if (error == EAI_FAIL || error == EAI_AGAIN || error == EAI_NODATA ||
++ error == EAI_NONAME)
+ cg->need_res_init = 1;
+
+ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, gai_strerror(error), 0);
diff --git a/SOURCES/cups-ricoh-deviceid-oid.patch b/SOURCES/cups-ricoh-deviceid-oid.patch
new file mode 100644
index 0000000..c148f95
--- /dev/null
+++ b/SOURCES/cups-ricoh-deviceid-oid.patch
@@ -0,0 +1,21 @@
+diff -up cups-1.5b1/backend/snmp.c.ricoh-deviceid-oid cups-1.5b1/backend/snmp.c
+--- cups-1.5b1/backend/snmp.c.ricoh-deviceid-oid 2011-05-24 17:29:48.000000000 +0200
++++ cups-1.5b1/backend/snmp.c 2011-05-24 17:29:48.000000000 +0200
+@@ -188,6 +188,7 @@ static const int LexmarkProductOID[] = {
+ static const int LexmarkProductOID2[] = { 1,3,6,1,4,1,674,10898,100,2,1,2,1,2,1,-1 };
+ static const int LexmarkDeviceIdOID[] = { 1,3,6,1,4,1,641,2,1,2,1,3,1,-1 };
+ static const int HPDeviceIdOID[] = { 1,3,6,1,4,1,11,2,3,9,1,1,7,0,-1 };
++static const int RicohDeviceIdOID[] = { 1,3,6,1,4,1,367,3,2,1,1,1,11,0,-1 };
+ static const int XeroxProductOID[] = { 1,3,6,1,4,1,128,2,1,3,1,2,0,-1 };
+ static cups_array_t *DeviceURIs = NULL;
+ static int HostNameLookups = 0;
+@@ -1005,6 +1006,9 @@ read_snmp_response(int fd) /* I - SNMP
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_ID, LexmarkDeviceIdOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
++ packet.community, CUPS_ASN1_GET_REQUEST,
++ DEVICE_ID, RicohDeviceIdOID);
++ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, XeroxProductOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
diff --git a/SOURCES/cups-serverbin-compat.patch b/SOURCES/cups-serverbin-compat.patch
new file mode 100644
index 0000000..5f51e23
--- /dev/null
+++ b/SOURCES/cups-serverbin-compat.patch
@@ -0,0 +1,193 @@
+diff -up cups-2.2rc1/scheduler/conf.c.serverbin-compat cups-2.2rc1/scheduler/conf.c
+--- cups-2.2rc1/scheduler/conf.c.serverbin-compat 2016-08-08 20:06:00.000000000 +0200
++++ cups-2.2rc1/scheduler/conf.c 2016-08-09 09:58:21.324033645 +0200
+@@ -609,6 +609,9 @@ cupsdReadConfiguration(void)
+ cupsdClearString(&ServerName);
+ cupsdClearString(&ServerAdmin);
+ cupsdSetString(&ServerBin, CUPS_SERVERBIN);
++#ifdef __x86_64__
++ cupsdSetString(&ServerBin_compat, "/usr/lib64/cups");
++#endif /* __x86_64__ */
+ cupsdSetString(&RequestRoot, CUPS_REQUESTS);
+ cupsdSetString(&CacheDir, CUPS_CACHEDIR);
+ cupsdSetString(&DataDir, CUPS_DATADIR);
+@@ -1604,7 +1607,12 @@ cupsdReadConfiguration(void)
+ * Read the MIME type and conversion database...
+ */
+
++#ifdef __x86_64__
++ snprintf(temp, sizeof(temp), "%s/filter:%s/filter", ServerBin,
++ ServerBin_compat);
++#else
+ snprintf(temp, sizeof(temp), "%s/filter", ServerBin);
++#endif
+ snprintf(mimedir, sizeof(mimedir), "%s/mime", DataDir);
+
+ MimeDatabase = mimeNew();
+diff -up cups-2.2rc1/scheduler/conf.h.serverbin-compat cups-2.2rc1/scheduler/conf.h
+--- cups-2.2rc1/scheduler/conf.h.serverbin-compat 2016-08-08 20:06:00.000000000 +0200
++++ cups-2.2rc1/scheduler/conf.h 2016-08-09 09:58:21.325033636 +0200
+@@ -106,6 +106,10 @@ VAR char *ConfigurationFile VALUE(NULL)
+ /* Root directory for scheduler */
+ *ServerBin VALUE(NULL),
+ /* Root directory for binaries */
++#ifdef __x86_64__
++ *ServerBin_compat VALUE(NULL),
++ /* Compat directory for binaries */
++#endif /* __x86_64__ */
+ *StateDir VALUE(NULL),
+ /* Root directory for state data */
+ *RequestRoot VALUE(NULL),
+diff -up cups-2.2rc1/scheduler/env.c.serverbin-compat cups-2.2rc1/scheduler/env.c
+--- cups-2.2rc1/scheduler/env.c.serverbin-compat 2016-08-08 20:06:00.000000000 +0200
++++ cups-2.2rc1/scheduler/env.c 2016-08-09 09:58:21.325033636 +0200
+@@ -212,8 +212,13 @@ cupsdUpdateEnv(void)
+ set_if_undefined("LD_PRELOAD", NULL);
+ set_if_undefined("NLSPATH", NULL);
+ if (find_env("PATH") < 0)
++#ifdef __x86_64__
++ cupsdSetEnvf("PATH", "%s/filter:%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR
++ ":/bin:/usr/bin", ServerBin, ServerBin_compat);
++#else /* ! defined(__x86_64__) */
+ cupsdSetEnvf("PATH", "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR
+ ":/bin:/usr/bin", ServerBin);
++#endif
+ set_if_undefined("SERVER_ADMIN", ServerAdmin);
+ set_if_undefined("SHLIB_PATH", NULL);
+ set_if_undefined("SOFTWARE", CUPS_MINIMAL);
+diff -up cups-2.2rc1/scheduler/ipp.c.serverbin-compat cups-2.2rc1/scheduler/ipp.c
+--- cups-2.2rc1/scheduler/ipp.c.serverbin-compat 2016-08-09 09:58:21.326033626 +0200
++++ cups-2.2rc1/scheduler/ipp.c 2016-08-09 10:10:16.266127629 +0200
+@@ -2419,12 +2419,21 @@ add_printer(cupsd_client_t *con, /* I -
+ * Could not find device in list!
+ */
+
++#ifdef __x86_64__
++ snprintf(srcfile, sizeof(srcfile), "%s/backend/%s", ServerBin_compat,
++ scheme);
++ if (access(srcfile, X_OK))
++ {
++#endif /* __x86_64__ */
+ send_ipp_status(con, IPP_NOT_POSSIBLE,
+ _("Bad device-uri scheme \"%s\"."), scheme);
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
+ return;
++#ifdef __x86_64__
++ }
++#endif /* __x86_64__ */
+ }
+ }
+
+diff -up cups-2.2rc1/scheduler/job.c.serverbin-compat cups-2.2rc1/scheduler/job.c
+--- cups-2.2rc1/scheduler/job.c.serverbin-compat 2016-08-08 20:06:00.000000000 +0200
++++ cups-2.2rc1/scheduler/job.c 2016-08-09 09:58:21.327033616 +0200
+@@ -1126,8 +1126,32 @@ cupsdContinueJob(cupsd_job_t *job) /* I
+ i ++, filter = (mime_filter_t *)cupsArrayNext(filters))
+ {
+ if (filter->filter[0] != '/')
+- snprintf(command, sizeof(command), "%s/filter/%s", ServerBin,
+- filter->filter);
++ {
++ snprintf(command, sizeof(command), "%s/filter/%s", ServerBin,
++ filter->filter);
++#ifdef __x86_64__
++ if (access(command, F_OK))
++ {
++ snprintf(command, sizeof(command), "%s/filter/%s",
++ ServerBin_compat, filter->filter);
++ if (!access(command, F_OK))
++ {
++ /* Not in the correct directory, but found it in the compat
++ * directory. Issue a warning. */
++ cupsdLogMessage(CUPSD_LOG_INFO,
++ "Filter '%s' not in %s/filter!",
++ filter->filter, ServerBin);
++ }
++ else
++ {
++ /* Not in the compat directory either; make any error
++ * messages use the correct directory name then. */
++ snprintf(command, sizeof(command), "%s/filter/%s", ServerBin,
++ filter->filter);
++ }
++ }
++#endif /* __x86_64__ */
++ }
+ else
+ strlcpy(command, filter->filter, sizeof(command));
+
+@@ -1283,6 +1307,28 @@ cupsdContinueJob(cupsd_job_t *job) /* I
+ {
+ cupsdClosePipe(job->back_pipes);
+ cupsdClosePipe(job->side_pipes);
++#ifdef __x86_64__
++ if (access(command, F_OK))
++ {
++ snprintf(command, sizeof(command), "%s/backend/%s", ServerBin_compat,
++ scheme);
++ if (!access(command, F_OK))
++ {
++ /* Not in the correct directory, but we found it in the compat
++ * directory. Issue a warning. */
++ cupsdLogMessage(CUPSD_LOG_INFO,
++ "Backend '%s' not in %s/backend!", scheme,
++ ServerBin);
++ }
++ else
++ {
++ /* Not in the compat directory either; make any error
++ messages use the correct directory name then. */
++ snprintf(command, sizeof(command), "%s/backend/%s", ServerBin,
++ scheme);
++ }
++ }
++#endif /* __x86_64__ */
+
+ close(job->status_pipes[1]);
+ job->status_pipes[1] = -1;
+diff -up cups-2.2rc1/scheduler/printers.c.serverbin-compat cups-2.2rc1/scheduler/printers.c
+--- cups-2.2rc1/scheduler/printers.c.serverbin-compat 2016-08-08 20:06:00.000000000 +0200
++++ cups-2.2rc1/scheduler/printers.c 2016-08-09 09:58:21.327033616 +0200
+@@ -967,9 +967,19 @@ cupsdLoadAllPrinters(void)
+ * Backend does not exist, stop printer...
+ */
+
++#ifdef __x86_64__
++ snprintf(line, sizeof(line), "%s/backend/%s", ServerBin_compat,
++ p->device_uri);
++ if (access(line, 0))
++ {
++#endif /* __x86_64__ */
++
+ p->state = IPP_PRINTER_STOPPED;
+ snprintf(p->state_message, sizeof(p->state_message),
+ "Backend %s does not exist!", line);
++#ifdef __x86_64__
++ }
++#endif /* __x86_64__ */
+ }
+ }
+
+@@ -3481,8 +3491,20 @@ add_printer_filter(
+ else
+ snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
+
++#ifdef __x86_64__
++ if (_cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !RunUser,
++ cupsdLogFCMessage, p) == _CUPS_FILE_CHECK_MISSING) {
++ snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin_compat,
++ program);
++ if (_cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !RunUser,
++ cupsdLogFCMessage, p) == _CUPS_FILE_CHECK_MISSING)
++ snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin,
++ program);
++ }
++#else /* ! defined(__x86_64__) */
+ _cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !RunUser,
+ cupsdLogFCMessage, p);
++#endif
+ }
+
+ /*
diff --git a/SOURCES/cups-str3382.patch b/SOURCES/cups-str3382.patch
new file mode 100644
index 0000000..b31bf37
--- /dev/null
+++ b/SOURCES/cups-str3382.patch
@@ -0,0 +1,62 @@
+diff -up cups-2.0rc1/cups/tempfile.c.str3382 cups-2.0rc1/cups/tempfile.c
+--- cups-2.0rc1/cups/tempfile.c.str3382 2014-07-31 02:58:00.000000000 +0200
++++ cups-2.0rc1/cups/tempfile.c 2014-09-12 14:06:42.560887827 +0200
+@@ -27,6 +27,7 @@
+ # include
+ #else
+ # include
++# include
+ #endif /* WIN32 || __EMX__ */
+
+
+@@ -48,7 +49,7 @@ cupsTempFd(char *filename, /* I - Point
+ char tmppath[1024]; /* Windows temporary directory */
+ DWORD curtime; /* Current time */
+ #else
+- struct timeval curtime; /* Current time */
++ mode_t old_umask; /* Old umask before using mkstemp() */
+ #endif /* WIN32 */
+
+
+@@ -98,32 +99,24 @@ cupsTempFd(char *filename, /* I - Point
+ */
+
+ snprintf(filename, (size_t)len - 1, "%s/%05lx%08lx", tmpdir, GetCurrentProcessId(), curtime);
+-#else
+- /*
+- * Get the current time of day...
+- */
+-
+- gettimeofday(&curtime, NULL);
+-
+- /*
+- * Format a string using the hex time values...
+- */
+-
+- snprintf(filename, (size_t)len - 1, "%s/%05x%08x", tmpdir, (unsigned)getpid(), (unsigned)(curtime.tv_sec + curtime.tv_usec + tries));
+-#endif /* WIN32 */
+
+ /*
+ * Open the file in "exclusive" mode, making sure that we don't
+ * stomp on an existing file or someone's symlink crack...
+ */
+
+-#ifdef WIN32
+ fd = open(filename, _O_CREAT | _O_RDWR | _O_TRUNC | _O_BINARY,
+ _S_IREAD | _S_IWRITE);
+-#elif defined(O_NOFOLLOW)
+- fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
+ #else
+- fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
++ /*
++ * Use the standard mkstemp() call to make a temporary filename
++ * securely. -- andrew.wood@jdplc.com
++ */
++ snprintf(filename, len - 1, "%s/cupsXXXXXX", tmpdir);
++
++ old_umask = umask(0077);
++ fd = mkstemp(filename);
++ umask(old_umask);
+ #endif /* WIN32 */
+
+ if (fd < 0 && errno != EEXIST)
diff --git a/SOURCES/cups-strict-ppd-line-length.patch b/SOURCES/cups-strict-ppd-line-length.patch
new file mode 100644
index 0000000..4ba1dd2
--- /dev/null
+++ b/SOURCES/cups-strict-ppd-line-length.patch
@@ -0,0 +1,30 @@
+diff -up cups-2.0rc1/cups/ppd.c.strict-ppd-line-length cups-2.0rc1/cups/ppd.c
+--- cups-2.0rc1/cups/ppd.c.strict-ppd-line-length 2014-02-06 19:33:34.000000000 +0100
++++ cups-2.0rc1/cups/ppd.c 2014-09-12 18:07:44.227773710 +0200
+@@ -2872,7 +2872,7 @@ ppd_read(cups_file_t *fp, /* I - Fil
+ *lineptr++ = (char)ch;
+ col ++;
+
+- if (col > (PPD_MAX_LINE - 1))
++ if (col > (PPD_MAX_LINE - 1) && pg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ /*
+ * Line is too long...
+@@ -2933,7 +2933,7 @@ ppd_read(cups_file_t *fp, /* I - Fil
+ {
+ col ++;
+
+- if (col > (PPD_MAX_LINE - 1))
++ if (col > (PPD_MAX_LINE - 1) && pg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ /*
+ * Line is too long...
+@@ -2992,7 +2992,7 @@ ppd_read(cups_file_t *fp, /* I - Fil
+ {
+ col ++;
+
+- if (col > (PPD_MAX_LINE - 1))
++ if (col > (PPD_MAX_LINE - 1) && pg->ppd_conform == PPD_CONFORM_STRICT)
+ {
+ /*
+ * Line is too long...
diff --git a/SOURCES/cups-substitute-bad-attrs.patch b/SOURCES/cups-substitute-bad-attrs.patch
new file mode 100644
index 0000000..37e65a1
--- /dev/null
+++ b/SOURCES/cups-substitute-bad-attrs.patch
@@ -0,0 +1,141 @@
+diff -up cups-2.2.7/scheduler/ipp.c.substitute-bad-attrs cups-2.2.7/scheduler/ipp.c
+--- cups-2.2.7/scheduler/ipp.c.substitute-bad-attrs 2018-04-03 15:55:45.974344993 +0200
++++ cups-2.2.7/scheduler/ipp.c 2018-04-03 16:15:06.723859881 +0200
+@@ -164,6 +164,7 @@ cupsdProcessIPPRequest(
+ ipp_attribute_t *uri = NULL; /* Printer or job URI attribute */
+ ipp_attribute_t *username; /* requesting-user-name attr */
+ int sub_id; /* Subscription ID */
++ int valid = 1; /* Valid request? */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest(%p[%d]): operation_id=%04x(%s)", con, con->number, con->request->request.op.operation_id, ippOpString(con->request->request.op.operation_id));
+@@ -423,20 +424,55 @@ cupsdProcessIPPRequest(
+ else
+ {
+ /*
+- * OK, all the checks pass so far; make sure requesting-user-name is
+- * not "root" from a remote host...
++ * OK, all the checks pass so far; validate "requesting-user-name"
++ * attribute value...
+ */
+
+- if ((username = ippFindAttribute(con->request, "requesting-user-name",
+- IPP_TAG_NAME)) != NULL)
+- {
+- /*
+- * Check for root user...
+- */
+-
+- if (!strcmp(username->values[0].string.text, "root") &&
+- _cups_strcasecmp(con->http->hostname, "localhost") &&
+- strcmp(con->username, "root"))
++ if ((username = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_ZERO)) != NULL)
++ {
++ /*
++ * Validate "requesting-user-name"...
++ */
++
++ if (username->group_tag != IPP_TAG_OPERATION && StrictConformance)
++ {
++ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute in wrong group.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname);
++ send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("\"requesting-user-name\" attribute in wrong group."));
++ valid = 0;
++ }
++ else if (username->value_tag != IPP_TAG_NAME && username->value_tag != IPP_TAG_NAMELANG)
++ {
++ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute with wrong syntax.", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, con->http->hostname);
++ send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("\"requesting-user-name\" attribute with wrong syntax."));
++ if ((attr = ippCopyAttribute(con->response, username, 0)) != NULL)
++ attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
++ valid = 0;
++ }
++ else if (!ippValidateAttribute(username))
++ {
++ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute with bad value.", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, con->http->hostname);
++
++ if (StrictConformance)
++ {
++ /*
++ * Throw an error...
++ */
++
++ send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("\"requesting-user-name\" attribute with wrong syntax."));
++ if ((attr = ippCopyAttribute(con->response, username, 0)) != NULL)
++ attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
++ valid = 0;
++ }
++ else
++ {
++ /*
++ * Map bad "requesting-user-name" to 'anonymous'...
++ */
++
++ ippSetString(con->request, &username, 0, "anonymous");
++ }
++ }
++ else if (!strcmp(username->values[0].string.text, "root") && _cups_strcasecmp(con->http->hostname, "localhost") && strcmp(con->username, "root"))
+ {
+ /*
+ * Remote unauthenticated user masquerading as local root...
+@@ -452,6 +488,8 @@ cupsdProcessIPPRequest(
+ else
+ sub_id = 0;
+
++ if (valid)
++ {
+ /*
+ * Then try processing the operation...
+ */
+@@ -655,6 +693,7 @@ cupsdProcessIPPRequest(
+ ippOpString(
+ con->request->request.op.operation_id));
+ break;
++ }
+ }
+ }
+ }
+@@ -1615,27 +1654,34 @@ add_job(cupsd_client_t *con, /* I - Cl
+ _("Bad job-name value: Wrong type or count."));
+ if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL)
+ attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
+- return (NULL);
++
++ if (StrictConformance)
++ return (NULL);
++
++ /* Don't use invalid attribute */
++ ippDeleteAttribute(con->request, attr);
++
++ ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled");
+ }
+ else if (!ippValidateAttribute(attr))
+ {
+ send_ipp_status(con, IPP_ATTRIBUTES, _("Bad job-name value: %s"),
+ cupsLastErrorString());
++
+ if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL)
+ attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
+- return (NULL);
+- }
+
+- attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
++ if (StrictConformance)
++ return (NULL);
+
+- if (attr && !ippValidateAttribute(attr))
+- {
+- send_ipp_status(con, IPP_ATTRIBUTES, _("Bad requesting-user-name value: %s"), cupsLastErrorString());
+- if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL)
+- attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
+- return (NULL);
++ /* Don't use invalid attribute */
++ ippDeleteAttribute(con->request, attr);
++
++ ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled");
+ }
+
++ attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
++
+ #ifdef WITH_LSPP
+ if (is_lspp_config())
+ {
diff --git a/SOURCES/cups-synconclose.patch b/SOURCES/cups-synconclose.patch
new file mode 100644
index 0000000..8aee02b
--- /dev/null
+++ b/SOURCES/cups-synconclose.patch
@@ -0,0 +1,48 @@
+diff -up cups-2.0.2/conf/cups-files.conf.in.LGOyhq cups-2.0.2/conf/cups-files.conf.in
+--- cups-2.0.2/conf/cups-files.conf.in.LGOyhq 2015-02-10 13:51:24.912193296 +0100
++++ cups-2.0.2/conf/cups-files.conf.in 2015-02-10 13:52:49.400997262 +0100
+@@ -7,7 +7,7 @@
+ #FatalErrors @CUPS_FATAL_ERRORS@
+
+ # Do we call fsync() after writing configuration or status files?
+-#SyncOnClose No
++#SyncOnClose Yes
+
+ # Default user and group for filters/backends/helper programs; this cannot be
+ # any user or group that resolves to ID 0 for security reasons...
+diff -up cups-2.0.2/doc/help/man-cups-files.conf.html.LGOyhq cups-2.0.2/doc/help/man-cups-files.conf.html
+--- cups-2.0.2/doc/help/man-cups-files.conf.html.LGOyhq 2015-02-10 13:52:49.400997262 +0100
++++ cups-2.0.2/doc/help/man-cups-files.conf.html 2015-02-10 13:53:07.057747311 +0100
+@@ -136,7 +136,7 @@ The default is "/etc/cups".
+ Specifies whether the scheduler calls
+ fsync(2)
+ after writing configuration or state files.
+-The default is "No".
++The default is "Yes".
+ SystemGroup group-name [ ... group-name ]
+ Specifies the group(s) to use for @SYSTEM group authentication.
+ The default contains "admin", "lpadmin", "root", "sys", and/or "system".
+diff -up cups-2.0.2/man/cups-files.conf.man.in.LGOyhq cups-2.0.2/man/cups-files.conf.man.in
+--- cups-2.0.2/man/cups-files.conf.man.in.LGOyhq 2015-02-10 13:52:49.400997262 +0100
++++ cups-2.0.2/man/cups-files.conf.man.in 2015-02-10 13:53:23.753510964 +0100
+@@ -201,7 +201,7 @@ The default is "/etc/cups".
+ Specifies whether the scheduler calls
+ .BR fsync (2)
+ after writing configuration or state files.
+-The default is "No".
++The default is "Yes".
+ .\"#SystemGroup
+ .TP 5
+ \fBSystemGroup \fIgroup-name \fR[ ... \fIgroup-name\fR ]
+diff -up cups-2.0.2/scheduler/conf.c.LGOyhq cups-2.0.2/scheduler/conf.c
+--- cups-2.0.2/scheduler/conf.c.LGOyhq 2015-02-10 13:51:24.991192177 +0100
++++ cups-2.0.2/scheduler/conf.c 2015-02-10 13:52:49.401997248 +0100
+@@ -717,7 +717,7 @@ cupsdReadConfiguration(void)
+ RootCertDuration = 300;
+ Sandboxing = CUPSD_SANDBOXING_STRICT;
+ StrictConformance = FALSE;
+- SyncOnClose = FALSE;
++ SyncOnClose = TRUE;
+ Timeout = DEFAULT_TIMEOUT;
+ WebInterface = CUPS_DEFAULT_WEBIF;
+
diff --git a/SOURCES/cups-system-auth.patch b/SOURCES/cups-system-auth.patch
new file mode 100644
index 0000000..60117a9
--- /dev/null
+++ b/SOURCES/cups-system-auth.patch
@@ -0,0 +1,38 @@
+diff -up cups-1.5b1/conf/cups.password-auth.system-auth cups-1.5b1/conf/cups.password-auth
+--- cups-1.5b1/conf/cups.password-auth.system-auth 2011-05-23 17:27:27.000000000 +0200
++++ cups-1.5b1/conf/cups.password-auth 2011-05-23 17:27:27.000000000 +0200
+@@ -0,0 +1,4 @@
++#%PAM-1.0
++# Use password-auth common PAM configuration for the daemon
++auth include password-auth
++account include password-auth
+diff -up cups-1.5b1/conf/cups.system-auth.system-auth cups-1.5b1/conf/cups.system-auth
+--- cups-1.5b1/conf/cups.system-auth.system-auth 2011-05-23 17:27:27.000000000 +0200
++++ cups-1.5b1/conf/cups.system-auth 2011-05-23 17:27:27.000000000 +0200
+@@ -0,0 +1,3 @@
++#%PAM-1.0
++auth include system-auth
++account include system-auth
+diff -up cups-1.5b1/conf/Makefile.system-auth cups-1.5b1/conf/Makefile
+--- cups-1.5b1/conf/Makefile.system-auth 2011-05-12 07:21:56.000000000 +0200
++++ cups-1.5b1/conf/Makefile 2011-05-23 17:27:27.000000000 +0200
+@@ -90,10 +90,16 @@ install-data:
+ done
+ -if test x$(PAMDIR) != x; then \
+ $(INSTALL_DIR) -m 755 $(BUILDROOT)$(PAMDIR); \
+- if test -r $(BUILDROOT)$(PAMDIR)/cups ; then \
+- $(INSTALL_DATA) $(PAMFILE) $(BUILDROOT)$(PAMDIR)/cups.N ; \
++ if test -f /etc/pam.d/password-auth; then \
++ $(INSTALL_DATA) cups.password-auth $(BUILDROOT)$(PAMDIR)/cups; \
++ elif test -f /etc/pam.d/system-auth; then \
++ $(INSTALL_DATA) cups.system-auth $(BUILDROOT)$(PAMDIR)/cups; \
+ else \
+- $(INSTALL_DATA) $(PAMFILE) $(BUILDROOT)$(PAMDIR)/cups ; \
++ if test -r $(BUILDROOT)$(PAMDIR)/cups ; then \
++ $(INSTALL_DATA) $(PAMFILE) $(BUILDROOT)$(PAMDIR)/cups.N ; \
++ else \
++ $(INSTALL_DATA) $(PAMFILE) $(BUILDROOT)$(PAMDIR)/cups ; \
++ fi ; \
+ fi ; \
+ fi
+
diff --git a/SOURCES/cups-systemd-socket.patch b/SOURCES/cups-systemd-socket.patch
new file mode 100644
index 0000000..37ccec9
--- /dev/null
+++ b/SOURCES/cups-systemd-socket.patch
@@ -0,0 +1,73 @@
+diff -up cups-2.2.5/scheduler/main.c.systemd-socket cups-2.2.5/scheduler/main.c
+--- cups-2.2.5/scheduler/main.c.systemd-socket 2017-10-17 18:59:53.732431498 +0200
++++ cups-2.2.5/scheduler/main.c 2017-10-17 19:02:13.132275861 +0200
+@@ -691,8 +691,16 @@ main(int argc, /* I - Number of comm
+
+ #ifdef HAVE_ONDEMAND
+ if (OnDemand)
++ {
+ cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL, "Scheduler started on demand.");
+- else
++# ifdef HAVE_SYSTEMD
++ sd_notifyf(0, "READY=1\n"
++ "STATUS=Scheduler is running...\n"
++ "MAINPID=%lu",
++ (unsigned long) getpid());
++# endif /* HAVE_SYSTEMD */
++ } else
++
+ #endif /* HAVE_ONDEMAND */
+ if (fg)
+ cupsdAddEvent(CUPSD_EVENT_SERVER_STARTED, NULL, NULL, "Scheduler started in foreground.");
+diff -up cups-2.2.5/scheduler/org.cups.cupsd.path.in.systemd-socket cups-2.2.5/scheduler/org.cups.cupsd.path.in
+--- cups-2.2.5/scheduler/org.cups.cupsd.path.in.systemd-socket 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/scheduler/org.cups.cupsd.path.in 2017-10-17 18:59:53.732431498 +0200
+@@ -1,6 +1,6 @@
+ [Unit]
+ Description=CUPS Scheduler
+-PartOf=org.cups.cupsd.service
++PartOf=cups.service
+
+ [Path]
+ PathExists=@CUPS_CACHEDIR@/org.cups.cupsd
+diff -up cups-2.2.5/scheduler/org.cups.cupsd.service.in.systemd-socket cups-2.2.5/scheduler/org.cups.cupsd.service.in
+--- cups-2.2.5/scheduler/org.cups.cupsd.service.in.systemd-socket 2017-10-13 20:22:26.000000000 +0200
++++ cups-2.2.5/scheduler/org.cups.cupsd.service.in 2017-10-17 18:59:53.732431498 +0200
+@@ -1,11 +1,13 @@
+ [Unit]
+ Description=CUPS Scheduler
+ Documentation=man:cupsd(8)
++After=network.target
+
+ [Service]
+ ExecStart=@sbindir@/cupsd -l
+-Type=simple
++Type=notify
++Restart=on-failure
+
+ [Install]
+-Also=org.cups.cupsd.socket org.cups.cupsd.path
++Also=cups.socket cups.path
+ WantedBy=printer.target
+diff -up cups-2.2.6/scheduler/org.cups.cupsd.socket.in.systemd-socket cups-2.2.6/scheduler/org.cups.cupsd.socket.in
+--- cups-2.2.6/scheduler/org.cups.cupsd.socket.in.systemd-socket 2017-11-01 15:57:53.000000000 +0100
++++ cups-2.2.6/scheduler/org.cups.cupsd.socket.in 2018-09-19 12:38:00.630843246 +0200
+@@ -1,6 +1,6 @@
+ [Unit]
+ Description=CUPS Scheduler
+-PartOf=org.cups.cupsd.service
++PartOf=cups.service
+
+ [Socket]
+ ListenStream=@CUPS_DEFAULT_DOMAINSOCKET@
+diff -up cups-2.2.6/scheduler/org.cups.cups-lpd.socket.systemd-socket cups-2.2.6/scheduler/org.cups.cups-lpd.socket
+--- cups-2.2.6/scheduler/org.cups.cups-lpd.socket.systemd-socket 2017-11-01 15:57:53.000000000 +0100
++++ cups-2.2.6/scheduler/org.cups.cups-lpd.socket 2018-09-19 12:38:00.630843246 +0200
+@@ -1,6 +1,6 @@
+ [Unit]
+ Description=CUPS LPD Server Socket
+-PartOf=org.cups.cups-lpd.service
++PartOf=cups-lpd.service
+
+ [Socket]
+ ListenStream=515
diff --git a/SOURCES/cups-uri-compat.patch b/SOURCES/cups-uri-compat.patch
new file mode 100644
index 0000000..2520a5b
--- /dev/null
+++ b/SOURCES/cups-uri-compat.patch
@@ -0,0 +1,51 @@
+diff -up cups-1.5b1/backend/usb-unix.c.uri-compat cups-1.5b1/backend/usb-unix.c
+--- cups-1.5b1/backend/usb-unix.c.uri-compat 2011-05-24 15:59:05.000000000 +0200
++++ cups-1.5b1/backend/usb-unix.c 2011-05-24 16:02:03.000000000 +0200
+@@ -63,11 +63,34 @@ print_device(const char *uri, /* I - De
+ int device_fd; /* USB device */
+ ssize_t tbytes; /* Total number of bytes written */
+ struct termios opts; /* Parallel port options */
++ char *fixed_uri = strdup (uri);
++ char *p;
+
+
+ (void)argc;
+ (void)argv;
+
++ p = strchr (fixed_uri, ':');
++ if (p++ != NULL)
++ {
++ char *e;
++ p += strspn (p, "/");
++ e = strchr (p, '/');
++ if (e > p)
++ {
++ size_t mfrlen = e - p;
++ e++;
++ if (!strncasecmp (e, p, mfrlen))
++ {
++ char *x = e + mfrlen;
++ if (!strncmp (x, "%20", 3))
++ /* Take mfr name out of mdl name for compatibility with
++ * Fedora 11 before bug #507244 was fixed. */
++ strcpy (e, x + 3); puts(fixed_uri);
++ }
++ }
++ }
++
+ /*
+ * Open the USB port device...
+ */
+@@ -107,10 +130,10 @@ print_device(const char *uri, /* I - De
+ _cups_strncasecmp(hostname, "Minolta", 7);
+ #endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__ */
+
+- if (use_bc && !strncmp(uri, "usb:/dev/", 9))
++ if (use_bc && !strncmp(fixed_uri, "usb:/dev/", 9))
+ use_bc = 0;
+
+- if ((device_fd = open_device(uri, &use_bc)) == -1)
++ if ((device_fd = open_device(fixed_uri, &use_bc)) == -1)
+ {
+ if (getenv("CLASS") != NULL)
+ {
diff --git a/SOURCES/cups-usb-paperout.patch b/SOURCES/cups-usb-paperout.patch
new file mode 100644
index 0000000..f1f73f0
--- /dev/null
+++ b/SOURCES/cups-usb-paperout.patch
@@ -0,0 +1,52 @@
+diff -up cups-1.5b1/backend/usb-unix.c.usb-paperout cups-1.5b1/backend/usb-unix.c
+--- cups-1.5b1/backend/usb-unix.c.usb-paperout 2011-05-24 15:51:39.000000000 +0200
++++ cups-1.5b1/backend/usb-unix.c 2011-05-24 15:51:39.000000000 +0200
+@@ -30,6 +30,11 @@
+
+ #include
+
++#ifdef __linux
++#include
++#include
++#endif /* __linux */
++
+
+ /*
+ * Local functions...
+@@ -334,7 +339,19 @@ open_device(const char *uri, /* I - Dev
+ if (!strncmp(uri, "usb:/dev/", 9))
+ #ifdef __linux
+ {
+- return (open(uri + 4, O_RDWR | O_EXCL));
++ fd = open(uri + 4, O_RDWR | O_EXCL);
++
++ if (fd != -1)
++ {
++ /*
++ * Tell the driver to return from write() with errno==ENOSPACE
++ * on paper-out.
++ */
++ unsigned int t = 1;
++ ioctl (fd, LPABORT, &t);
++ }
++
++ return fd;
+ }
+ else if (!strncmp(uri, "usb://", 6))
+ {
+@@ -400,7 +417,14 @@ open_device(const char *uri, /* I - Dev
+ if (!strcmp(uri, device_uri))
+ {
+ /*
+- * Yes, return this file descriptor...
++ * Yes, tell the driver to return from write() with
++ * errno==ENOSPACE on paper-out.
++ */
++ unsigned int t = 1;
++ ioctl (fd, LPABORT, &t);
++
++ /*
++ * Return this file descriptor...
+ */
+
+ fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n",
diff --git a/SOURCES/cups-use-ipp1.1.patch b/SOURCES/cups-use-ipp1.1.patch
new file mode 100644
index 0000000..41855fc
--- /dev/null
+++ b/SOURCES/cups-use-ipp1.1.patch
@@ -0,0 +1,12 @@
+diff -up cups-1.6.3/cups/usersys.c.use-ipp1.1 cups-1.6.3/cups/usersys.c
+--- cups-1.6.3/cups/usersys.c.use-ipp1.1 2013-07-12 11:41:45.368837618 +0200
++++ cups-1.6.3/cups/usersys.c 2013-07-12 11:41:45.391837299 +0200
+@@ -366,7 +366,7 @@ cupsSetServer(const char *server) /* I -
+ cg->server_version = 22;
+ }
+ else
+- cg->server_version = 20;
++ cg->server_version = 11;
+
+ if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL &&
+ !strchr(port, ']') && isdigit(port[1] & 255))
diff --git a/SOURCES/cups-web-devices-timeout.patch b/SOURCES/cups-web-devices-timeout.patch
new file mode 100644
index 0000000..fa3a320
--- /dev/null
+++ b/SOURCES/cups-web-devices-timeout.patch
@@ -0,0 +1,19 @@
+diff -up cups-1.7rc1/cgi-bin/admin.c.web-devices-timeout cups-1.7rc1/cgi-bin/admin.c
+--- cups-1.7rc1/cgi-bin/admin.c.web-devices-timeout 2013-05-29 12:51:34.000000000 +0100
++++ cups-1.7rc1/cgi-bin/admin.c 2013-08-16 16:01:17.308264287 +0100
+@@ -1019,13 +1019,13 @@ do_am_printer(http_t *http, /* I - HTTP
+ }
+
+ /*
+- * Scan for devices for up to 30 seconds...
++ * Scan for devices for up to 10 seconds...
+ */
+
+ fputs("DEBUG: Getting list of devices...\n", stderr);
+
+ current_device = 0;
+- if (cupsGetDevices(http, 5, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE,
++ if (cupsGetDevices(http, 10, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE,
+ (cups_device_cb_t)choose_device_cb,
+ (void *)title) == IPP_OK)
+ {
diff --git a/SOURCES/cups-ypbind.patch b/SOURCES/cups-ypbind.patch
new file mode 100644
index 0000000..f942708
--- /dev/null
+++ b/SOURCES/cups-ypbind.patch
@@ -0,0 +1,12 @@
+diff -up cups-2.2.0/scheduler/org.cups.cupsd.service.in.ypbind cups-2.2.0/scheduler/org.cups.cupsd.service.in
+--- cups-2.2.0/scheduler/org.cups.cupsd.service.in.ypbind 2017-09-22 16:51:39.053585694 +0200
++++ cups-2.2.0/scheduler/org.cups.cupsd.service.in 2017-09-22 16:52:02.588403584 +0200
+@@ -1,7 +1,7 @@
+ [Unit]
+ Description=CUPS Scheduler
+ Documentation=man:cupsd(8)
+-After=network.target
++After=network.target ypbind.service
+
+ [Service]
+ ExecStart=@sbindir@/cupsd -l
diff --git a/SOURCES/cups.logrotate b/SOURCES/cups.logrotate
new file mode 100644
index 0000000..773c70f
--- /dev/null
+++ b/SOURCES/cups.logrotate
@@ -0,0 +1,5 @@
+/var/log/cups/*_log {
+ missingok
+ notifempty
+ sharedscripts
+}
diff --git a/SOURCES/macros.cups b/SOURCES/macros.cups
new file mode 100644
index 0000000..5b560d9
--- /dev/null
+++ b/SOURCES/macros.cups
@@ -0,0 +1 @@
+%_cups_serverbin %(/usr/bin/cups-config --serverbin)
diff --git a/SOURCES/ncp.backend b/SOURCES/ncp.backend
new file mode 100755
index 0000000..d57ada1
--- /dev/null
+++ b/SOURCES/ncp.backend
@@ -0,0 +1,51 @@
+#!/bin/sh
+# This is a modified version of 'ncpprint'. It can now be used as a CUPS
+# backend.
+# Modifications:
+# Copyright (C) 2002 Red Hat, inc
+# Copyright (C) 2002 Tim Waugh
+# Before modification: shipped as /usr/share/printconf/util/ncpprint
+
+if [ -z "$*" ]
+then
+ # This is where we would enumerate all the URIs we support.
+ # Patches welcome.
+ exit 0
+fi
+
+FILE=$6
+if [ -z "$FILE" ]
+then
+ FILE=-
+fi
+
+# $DEVICE_URI is 'ncp://[user:password@]server/queue'
+URI=${DEVICE_URI#*://}
+queue=${URI#*/}
+URI=${URI%/$queue}
+server=${URI#*@}
+URI=${URI%$server}
+URI=${URI%@}
+if [ -n "$URI" ]
+then
+ user=${URI%:*}
+ URI=${URI#$user}
+ password=${URI#:}
+fi
+
+#echo user: ${user-(none)}
+#echo password: ${password-(none)}
+#echo server: $server
+#echo queue: $queue
+
+if [ -n "$user" ]
+then
+ if [ -n "$password" ]
+ then
+ /usr/bin/nprint -S "$server" -q "$queue" -U "$user" -P "$password" -N "$FILE" 2>/dev/null
+ else
+ /usr/bin/nprint -S "$server" -q "$queue" -U "$user" -n -N "$FILE" 2>/dev/null
+ fi
+else
+ /usr/bin/nprint -S "$server" -q "$queue" -N "$FILE" 2>/dev/null
+fi
diff --git a/SPECS/cups.spec b/SPECS/cups.spec
new file mode 100644
index 0000000..1c3e7c8
--- /dev/null
+++ b/SPECS/cups.spec
@@ -0,0 +1,3684 @@
+%global use_alternatives 1
+%global lspp 1
+
+# {_exec_prefix}/lib/cups is correct, even on x86_64.
+# It is not used for shared objects but for executables.
+# It's more of a libexec-style ({_libexecdir}) usage,
+# but we use lib for compatibility with 3rd party drivers (at upstream request).
+%global cups_serverbin %{_exec_prefix}/lib/cups
+
+#%%global prever rc1
+#%%global VERSION %%{version}%%{prever}
+%global VERSION %{version}
+
+Summary: CUPS printing system
+Name: cups
+Epoch: 1
+Version: 2.2.6
+Release: 27%{?dist}
+License: GPLv2+ and LGPLv2 with exceptions and AML
+Url: http://www.cups.org/
+Source0: https://github.com/apple/cups/releases/download/v%{VERSION}/cups-%{VERSION}-source.tar.gz
+# Pixmap for desktop file
+Source2: cupsprinter.png
+# Logrotate configuration
+Source6: cups.logrotate
+# Backend for NCP protocol
+Source7: ncp.backend
+Source8: macros.cups
+
+Patch1: cups-no-gzip-man.patch
+Patch2: cups-system-auth.patch
+Patch3: cups-multilib.patch
+Patch5: cups-banners.patch
+Patch6: cups-serverbin-compat.patch
+Patch7: cups-no-export-ssllibs.patch
+Patch8: cups-direct-usb.patch
+Patch9: cups-lpr-help.patch
+Patch10: cups-peercred.patch
+Patch11: cups-pid.patch
+Patch12: cups-eggcups.patch
+Patch13: cups-driverd-timeout.patch
+Patch14: cups-strict-ppd-line-length.patch
+Patch15: cups-logrotate.patch
+Patch16: cups-usb-paperout.patch
+Patch17: cups-res_init.patch
+Patch18: cups-filter-debug.patch
+Patch19: cups-uri-compat.patch
+Patch20: cups-str3382.patch
+#Patch21: cups-0755.patch
+Patch22: cups-hp-deviceid-oid.patch
+Patch23: cups-dnssd-deviceid.patch
+Patch24: cups-ricoh-deviceid-oid.patch
+Patch25: cups-systemd-socket.patch
+Patch27: cups-avahi-address.patch
+Patch29: cups-dymo-deviceid.patch
+Patch30: cups-freebind.patch
+#Patch31: cups-no-gcry.patch
+Patch33: cups-use-ipp1.1.patch
+Patch34: cups-avahi-no-threaded.patch
+Patch35: cups-ipp-multifile.patch
+Patch36: cups-web-devices-timeout.patch
+Patch37: cups-synconclose.patch
+Patch38: cups-ypbind.patch
+Patch39: cups-substitute-bad-attrs.patch
+# 1607295 - CVE-2018-4180 CVE-2018-4181 CVE-2018-4182 CVE-2018-4183 cups: various flaws [rhel-8.0]
+Patch40: 0001-Fix-local-privilege-escalation-to-root-and-sandbox-b.patch
+# 1613173 - Remove weak SSL/TLS ciphers from CUPS
+Patch41: 0001-Add-support-for-MinTLS-and-MaxTLS-options-Issue-5119.patch
+# 1602469 - fixed covscan issues, backported from upstream
+Patch42: 0001-Fix-memory-leaks-found-by-Coverity-Issue-5375.patch
+# 1625899 - cups 2.2.6 lpr command fails against old cups 1.3.9 server
+Patch43: 0001-Printing-to-old-CUPS-servers-has-been-fixed-Issue-52.patch
+# 1625913 - ssl options aren't initialized when no SSLOptions directive is set in /etc/cups/client.conf
+Patch44: 0001-Fix-default-TLS-versions.patch
+# 1622431 - Jobs with multiple files don't complete when backend fails
+Patch45: 0001-Fix-stuck-multi-file-jobs-Issue-5359-Issue-5413.patch
+# CVE-2018-4700 cups: Predictable session cookie breaks CSRF protection [rhel-8]
+Patch46: 0001-CVE-2018-4700-Linux-session-cookies-used-a-predictab.patch
+# 1659486 - cupsd crash on startup in ippCopyAttribute
+Patch47: 0001-The-scheduler-could-crash-while-adding-an-IPP-Everyw.patch
+# 1677577 - Remove 'View X log' buttons from web ui
+Patch48: 0001-Remove-web-log-buttons.patch
+
+Patch100: cups-lspp.patch
+
+Requires: %{name}-filesystem = %{epoch}:%{version}-%{release}
+Requires: %{name}-libs%{?_isa} = %{epoch}:%{version}-%{release}
+Requires: %{name}-client%{?_isa} = %{epoch}:%{version}-%{release}
+
+Provides: cupsddk cupsddk-drivers
+
+BuildRequires: pam-devel pkgconf-pkg-config
+BuildRequires: pkgconfig(gnutls)
+BuildRequires: libacl-devel
+BuildRequires: openldap-devel
+BuildRequires: pkgconfig(libusb-1.0)
+BuildRequires: krb5-devel
+BuildRequires: pkgconfig(avahi-client)
+BuildRequires: systemd
+BuildRequires: pkgconfig(libsystemd)
+BuildRequires: pkgconfig(dbus-1)
+BuildRequires: automake
+# for decompressing functions when reading from a gzipped file
+BuildRequires: zlib-devel
+
+# gcc and gcc-c++ is no longer in buildroot by default
+# gcc for most of files
+BuildRequires: gcc
+# gcc-c++ for ppdc and cups-driverd
+Buildrequires: gcc-c++
+
+# Make sure we get postscriptdriver tags.
+BuildRequires: python3-cups
+
+%if %{lspp}
+BuildRequires: libselinux-devel
+BuildRequires: audit-libs-devel
+%endif
+
+Requires: dbus
+
+# Requires working PrivateTmp (bug #807672)
+Requires(pre): systemd
+Requires(post): systemd
+Requires(post): grep, sed
+Requires(preun): systemd
+Requires(postun): systemd
+
+# We ship udev rules which use setfacl.
+Requires: systemd
+Requires: acl
+
+# Make sure we have some filters for converting to raster format.
+Requires: cups-filters
+
+%package client
+Summary: CUPS printing system - client programs
+License: GPLv2
+Requires: %{name}-libs%{?_isa} = %{epoch}:%{version}-%{release}
+%if %{use_alternatives}
+Provides: /usr/bin/lpq /usr/bin/lpr /usr/bin/lp /usr/bin/cancel /usr/bin/lprm /usr/bin/lpstat
+Requires: /usr/sbin/alternatives
+%endif
+Provides: lpr
+
+%package devel
+Summary: CUPS printing system - development environment
+License: LGPLv2
+Requires: %{name}-libs%{?_isa} = %{epoch}:%{version}-%{release}
+Requires: gnutls-devel
+Requires: krb5-devel
+Requires: zlib-devel
+Provides: cupsddk-devel
+
+%package libs
+Summary: CUPS printing system - libraries
+License: LGPLv2 and zlib
+
+%package filesystem
+Summary: CUPS printing system - directory layout
+BuildArch: noarch
+
+%package lpd
+Summary: CUPS printing system - lpd emulation
+Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release}
+Requires: %{name}-libs%{?_isa} = %{epoch}:%{version}-%{release}
+Provides: lpd
+
+%package ipptool
+Summary: CUPS printing system - tool for performing IPP requests
+Requires: %{name}-libs%{?_isa} = %{epoch}:%{version}-%{release}
+
+%description
+CUPS printing system provides a portable printing layer for
+UNIX® operating systems. It has been developed by Apple Inc.
+to promote a standard printing solution for all UNIX vendors and users.
+CUPS provides the System V and Berkeley command-line interfaces.
+
+%description client
+CUPS printing system provides a portable printing layer for
+UNIX® operating systems. This package contains command-line client
+programs.
+
+%description devel
+CUPS printing system provides a portable printing layer for
+UNIX® operating systems. This is the development package for creating
+additional printer drivers, and other CUPS services.
+
+%description libs
+CUPS printing system provides a portable printing layer for
+UNIX® operating systems. It has been developed by Apple Inc.
+to promote a standard printing solution for all UNIX vendors and users.
+CUPS provides the System V and Berkeley command-line interfaces.
+The cups-libs package provides libraries used by applications to use CUPS
+natively, without needing the lp/lpr commands.
+
+%description filesystem
+CUPS printing system provides a portable printing layer for
+UNIX® operating systems. This package provides some directories which are
+required by other packages that add CUPS drivers (i.e. filters, backends etc.).
+
+%description lpd
+CUPS printing system provides a portable printing layer for
+UNIX® operating systems. This is the package that provides standard
+lpd emulation.
+
+%description ipptool
+Sends IPP requests to the specified URI and tests and/or displays the results.
+
+%prep
+%setup -q -n cups-%{VERSION}
+# Don't gzip man pages in the Makefile, let rpmbuild do it.
+%patch1 -p1 -b .no-gzip-man
+# Use the system pam configuration.
+%patch2 -p1 -b .system-auth
+# Prevent multilib conflict in cups-config script.
+%patch3 -p1 -b .multilib
+# Ignore rpm save/new files in the banners directory.
+%patch5 -p1 -b .banners
+# Use compatibility fallback path for ServerBin.
+%patch6 -p1 -b .serverbin-compat
+# Don't export SSLLIBS to cups-config.
+%patch7 -p1 -b .no-export-ssllibs
+# Allow file-based usb device URIs.
+%patch8 -p1 -b .direct-usb
+# Add --help option to lpr.
+%patch9 -p1 -b .lpr-help
+# Fix compilation of peer credentials support.
+%patch10 -p1 -b .peercred
+# Maintain a cupsd.pid file.
+%patch11 -p1 -b .pid
+# Fix implementation of com.redhat.PrinterSpooler D-Bus object.
+%patch12 -p1 -b .eggcups
+# Increase driverd timeout to 70s to accommodate foomatic (bug #744715).
+%patch13 -p1 -b .driverd-timeout
+# Only enforce maximum PPD line length when in strict mode.
+%patch14 -p1 -b .strict-ppd-line-length
+# Re-open the log if it has been logrotated under us.
+%patch15 -p1 -b .logrotate
+# Support for errno==ENOSPACE-based USB paper-out reporting.
+%patch16 -p1 -b .usb-paperout
+# Re-initialise the resolver on failure in httpAddrGetList() (bug #567353).
+%patch17 -p1 -b .res_init
+# Log extra debugging information if no filters are available.
+%patch18 -p1 -b .filter-debug
+# Allow the usb backend to understand old-style URI formats.
+%patch19 -p1 -b .uri-compat
+# Fix temporary filename creation.
+%patch20 -p1 -b .str3382
+# Use mode 0755 for binaries and libraries where appropriate.
+#%%patch21 -p1 -b .0755
+# Add an SNMP query for HP's device ID OID (STR #3552).
+%patch22 -p1 -b .hp-deviceid-oid
+# Mark DNS-SD Device IDs that have been guessed at with "FZY:1;".
+%patch23 -p1 -b .dnssd-deviceid
+# Add an SNMP query for Ricoh's device ID OID (STR #3552).
+%patch24 -p1 -b .ricoh-deviceid-oid
+# Make cups.service Type=notify (bug #1088918).
+%patch25 -p1 -b .systemd-socket
+# Use IP address when resolving DNSSD URIs (bug #948288).
+%patch27 -p1 -b .avahi-address
+# Added IEEE 1284 Device ID for a Dymo device (bug #747866).
+%patch29 -p1 -b .dymo-deviceid
+# Use IP_FREEBIND socket option when binding listening sockets (bug #970809).
+%patch30 -p1 -b .freebind
+# Don't link against libgcrypt needlessly.
+#%%patch31 -p1 -b .no-gcry
+# Default to IPP/1.1 for now (bug #977813).
+%patch33 -p1 -b .use-ipp1.1
+# Don't use D-Bus from two threads (bug #979748).
+%patch34 -p1 -b .avahi-no-threaded
+# Fixes for jobs with multiple files and multiple formats.
+%patch35 -p1 -b .ipp-multifile
+# Increase web interface get-devices timeout to 10s (bug #996664).
+%patch36 -p1 -b .web-devices-timeout
+# Set the default for SyncOnClose to Yes.
+%patch37 -p1 -b .synconclose
+# CUPS may fail to start if NIS groups are used (bug #1494558)
+%patch38 -p1 -b .ypbind
+
+%if %{lspp}
+# LSPP support.
+%patch100 -p1 -b .lspp
+%endif
+
+# substitute default values for invalid job attributes (upstream #5186 and #5229)
+%patch39 -p1 -b .substitute-bad-attrs
+# 1607295 - CVE-2018-4180 CVE-2018-4181 CVE-2018-4182 CVE-2018-4183 cups: various flaws [rhel-8.0]
+%patch40 -p1 -b .privilege-escalation
+# 1613173 - Remove weak SSL/TLS ciphers from CUPS
+%patch41 -p1 -b .remove-weak-ciphers
+# 1602469 - fixed covscan issues, backported from upstream
+%patch42 -p1 -b .covscan
+# 1625899 - cups 2.2.6 lpr command fails against old cups 1.3.9 server
+%patch43 -p1 -b .oldcupsservers
+# 1625913 - ssl options aren't initialized when no SSLOptions directive is set in /etc/cups/client.conf
+%patch44 -p1 -b .defaulttls
+# 1622431 - Jobs with multiple files don't complete when backend fails
+%patch45 -p1 -b .multifile-stuck
+# CVE-2018-4700 cups: Predictable session cookie breaks CSRF protection [rhel-8]
+%patch46 -p1 -b .predictable-cookie
+# 1659486 - cupsd crash on startup in ippCopyAttribute
+%patch47 -p1 -b .ippeve-crash
+# 1677577 - Remove 'View X log' buttons from web ui
+%patch48 -p1 -b .rm-webui-buttons
+
+sed -i -e '1iMaxLogSize 0' conf/cupsd.conf.in
+
+# Log to the system journal by default (bug #1078781, bug #1519331).
+sed -i -e 's,^ErrorLog .*$,ErrorLog syslog,' conf/cups-files.conf.in
+sed -i -e 's,^AccessLog .*$,AccessLog syslog,' conf/cups-files.conf.in
+sed -i -e 's,^PageLog .*$,PageLog syslog,' conf/cups-files.conf.in
+
+# Add comment text mentioning syslog is systemd journal (bug #1358589)
+sed -i -e 's,\"syslog\",\"syslog\" \(syslog means systemd journal by default\),' conf/cups-files.conf.in
+
+# Add group wheel to SystemGroups (bug #1405669)
+sed -i -e 's,^SystemGroup .*$, SystemGroup sys root wheel,' conf/cups-files.conf.in
+
+# Let's look at the compilation command lines.
+perl -pi -e "s,^.SILENT:,," Makedefs.in
+
+f=CREDITS.md
+mv "$f" "$f"~
+iconv -f MACINTOSH -t UTF-8 "$f"~ > "$f"
+rm -f "$f"~
+
+aclocal -I config-scripts
+autoconf -I config-scripts
+
+%build
+# add Fedora specific flags to DSOFLAGS
+export DSOFLAGS="$DSOFLAGS -L../cgi-bin -L../filter -L../ppdc -L../scheduler -Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-z,relro,-z,now -fPIE -pie"
+export CFLAGS="$RPM_OPT_FLAGS -fstack-protector-all -DLDAP_DEPRECATED=1"
+export CC=gcc
+export CXX=g++
+# --enable-debug to avoid stripping binaries
+%configure --with-docdir=%{_datadir}/%{name}/www --enable-debug \
+%if %{lspp}
+ --enable-lspp \
+%endif
+ --with-exe-file-perm=0755 \
+ --with-cupsd-file-perm=0755 \
+ --with-log-file-perm=0600 \
+ --enable-relro \
+ --with-dbusdir=%{_sysconfdir}/dbus-1 \
+ --with-php=/usr/bin/php-cgi \
+ --enable-avahi \
+ --enable-threads \
+ --enable-gnutls \
+ --enable-webif \
+ --with-xinetd=no \
+ --with-access-log-level=actions \
+ --enable-page-logging \
+ localedir=%{_datadir}/locale
+
+# If we got this far, all prerequisite libraries must be here.
+make %{?_smp_mflags}
+
+%install
+make BUILDROOT=%{buildroot} install
+
+rm -rf %{buildroot}%{_initddir} \
+ %{buildroot}%{_sysconfdir}/init.d \
+ %{buildroot}%{_sysconfdir}/rc?.d
+mkdir -p %{buildroot}%{_unitdir}
+
+find %{buildroot}%{_datadir}/cups/model -name "*.ppd" |xargs gzip -n9f
+
+%if %{use_alternatives}
+pushd %{buildroot}%{_bindir}
+for i in cancel lp lpq lpr lprm lpstat; do
+ mv $i $i.cups
+done
+cd %{buildroot}%{_sbindir}
+mv lpc lpc.cups
+cd %{buildroot}%{_mandir}/man1
+for i in cancel lp lpq lpr lprm lpstat; do
+ mv $i.1 $i-cups.1
+done
+cd %{buildroot}%{_mandir}/man8
+mv lpc.8 lpc-cups.8
+popd
+%endif
+
+mv %{buildroot}%{_unitdir}/org.cups.cupsd.path %{buildroot}%{_unitdir}/cups.path
+mv %{buildroot}%{_unitdir}/org.cups.cupsd.service %{buildroot}%{_unitdir}/cups.service
+mv %{buildroot}%{_unitdir}/org.cups.cupsd.socket %{buildroot}%{_unitdir}/cups.socket
+mv %{buildroot}%{_unitdir}/org.cups.cups-lpd.socket %{buildroot}%{_unitdir}/cups-lpd.socket
+mv %{buildroot}%{_unitdir}/org.cups.cups-lpd@.service %{buildroot}%{_unitdir}/cups-lpd@.service
+/bin/sed -i -e "s,org.cups.cupsd,cups,g" %{buildroot}%{_unitdir}/cups.service
+
+mkdir -p %{buildroot}%{_datadir}/pixmaps %{buildroot}%{_sysconfdir}/X11/sysconfig %{buildroot}%{_sysconfdir}/X11/applnk/System %{buildroot}%{_sysconfdir}/logrotate.d
+install -p -m 644 %{SOURCE2} %{buildroot}%{_datadir}/pixmaps
+install -p -m 644 %{SOURCE6} %{buildroot}%{_sysconfdir}/logrotate.d/cups
+install -p -m 755 %{SOURCE7} %{buildroot}%{cups_serverbin}/backend/ncp
+
+# Ship an rpm macro for where to put driver executables.
+mkdir -p %{buildroot}%{_rpmconfigdir}/macros.d
+install -m 0644 %{SOURCE8} %{buildroot}%{_rpmconfigdir}/macros.d
+
+# Ship a printers.conf file, and a client.conf file. That way, they get
+# their SELinux file contexts set correctly.
+touch %{buildroot}%{_sysconfdir}/cups/printers.conf
+touch %{buildroot}%{_sysconfdir}/cups/classes.conf
+touch %{buildroot}%{_sysconfdir}/cups/client.conf
+touch %{buildroot}%{_sysconfdir}/cups/subscriptions.conf
+touch %{buildroot}%{_sysconfdir}/cups/lpoptions
+
+# LSB 3.2 printer driver directory
+mkdir -p %{buildroot}%{_datadir}/ppd
+
+# Remove unshipped files.
+rm -rf %{buildroot}%{_mandir}/cat? %{buildroot}%{_mandir}/*/cat?
+rm -f %{buildroot}%{_datadir}/applications/cups.desktop
+rm -rf %{buildroot}%{_datadir}/icons
+# there are pdf-banners shipped with cups-filters (#919489)
+rm -rf %{buildroot}%{_datadir}/cups/banners
+rm -f %{buildroot}%{_datadir}/cups/data/testprint
+
+# install /usr/lib/tmpfiles.d/cups.conf (bug #656566, bug #893834)
+mkdir -p ${RPM_BUILD_ROOT}%{_tmpfilesdir}
+cat > ${RPM_BUILD_ROOT}%{_tmpfilesdir}/cups.conf < ${RPM_BUILD_ROOT}%{_tmpfilesdir}/cups-lp.conf < %{name}.lang
+
+%post
+%systemd_post %{name}.path %{name}.socket %{name}.service
+
+# Remove old-style certs directory; new-style is /var/run
+# (see bug #194581 for why this is necessary).
+rm -rf %{_sysconfdir}/cups/certs
+rm -f %{_localstatedir}/cache/cups/*.ipp %{_localstatedir}/cache/cups/*.cache
+
+# Previous migration script unnecessarily put PageLogFormat into cups-files.conf
+# (see bug #1148995)
+FILE=%{_sysconfdir}/cups/cups-files.conf
+for keyword in PageLogFormat; do
+ /bin/sed -i -e "s,^$keyword,#$keyword,i" "$FILE" || :
+done
+
+# Because of moving logs to journal, we need to create placeholder files
+# at /var/log/cups for users, whose are going to install CUPS on new OS
+# machine with info message
+%if 0%{?rhel} > 7 || 0%{?fedora} > 27
+confignames=( "ErrorLog" "AccessLog" "PageLog" )
+lognames=( "error_log" "access_log" "page_log" )
+message="This CUPS log has been moved into journal by default unless changes have been made in /etc/cups/cups-files.conf. Log messages can be got by \"$ journalctl -u cups -e\""
+for ((i=0;i<${#confignames[@]};i++));
+do
+ found=`%{_bindir}/grep -i "${confignames[i]} syslog" /etc/cups/cups-files.conf`
+ if [ ! -z "$found" ]
+ then
+ if [ ! -f %{_localstatedir}/log/cups/${lognames[i]} ]
+ then
+ %{_bindir}/touch %{_localstatedir}/log/cups/${lognames[i]} || :
+ fi
+ perms=`%{_bindir}/ls -lah %{_localstatedir}/log/cups/${lognames[i]} | %{_bindir}/grep -v -e "\-rw-------" -e "root lp"`
+ if [ ! -z "$perms" ]
+ then
+ # we need to set correct permissions and ownership because of possible
+ # security issues
+ # we need to have here, because previous CUPS releases had the bug.
+ # Checking permissions and ownership here fixes it.
+ %{_bindir}/chown root:lp %{_localstatedir}/log/cups/${lognames[i]} || :
+ %{_bindir}/chmod 600 %{_localstatedir}/log/cups/${lognames[i]} || :
+ fi
+ lastmessage=`%{_bindir}/tail -n 1 %{_localstatedir}/log/cups/${lognames[i]} | %{_bindir}/grep "$message"`
+ if [ -z "$lastmessage" ]
+ then
+ %{_bindir}/echo $message >> %{_localstatedir}/log/cups/${lognames[i]} || :
+ fi
+ fi
+done
+%endif
+
+exit 0
+
+%post client
+%if %{use_alternatives}
+/usr/sbin/alternatives --install %{_bindir}/lpr print %{_bindir}/lpr.cups 40 \
+ --slave %{_bindir}/lp print-lp %{_bindir}/lp.cups \
+ --slave %{_bindir}/lpq print-lpq %{_bindir}/lpq.cups \
+ --slave %{_bindir}/lprm print-lprm %{_bindir}/lprm.cups \
+ --slave %{_bindir}/lpstat print-lpstat %{_bindir}/lpstat.cups \
+ --slave %{_bindir}/cancel print-cancel %{_bindir}/cancel.cups \
+ --slave %{_sbindir}/lpc print-lpc %{_sbindir}/lpc.cups \
+ --slave %{_mandir}/man1/cancel.1.gz print-cancelman %{_mandir}/man1/cancel-cups.1.gz \
+ --slave %{_mandir}/man1/lp.1.gz print-lpman %{_mandir}/man1/lp-cups.1.gz \
+ --slave %{_mandir}/man8/lpc.8.gz print-lpcman %{_mandir}/man8/lpc-cups.8.gz \
+ --slave %{_mandir}/man1/lpq.1.gz print-lpqman %{_mandir}/man1/lpq-cups.1.gz \
+ --slave %{_mandir}/man1/lpr.1.gz print-lprman %{_mandir}/man1/lpr-cups.1.gz \
+ --slave %{_mandir}/man1/lprm.1.gz print-lprmman %{_mandir}/man1/lprm-cups.1.gz \
+ --slave %{_mandir}/man1/lpstat.1.gz print-lpstatman %{_mandir}/man1/lpstat-cups.1.gz
+%endif
+exit 0
+
+%post lpd
+%systemd_post cups-lpd.socket
+exit 0
+
+%ldconfig_scriptlets libs
+
+%preun
+%systemd_preun %{name}.path %{name}.socket %{name}.service
+exit 0
+
+%preun client
+%if %{use_alternatives}
+if [ $1 -eq 0 ] ; then
+ /usr/sbin/alternatives --remove print %{_bindir}/lpr.cups
+fi
+%endif
+exit 0
+
+%preun lpd
+%systemd_preun cups-lpd.socket
+exit 0
+
+%postun
+%systemd_postun_with_restart %{name}.path %{name}.socket %{name}.service
+exit 0
+
+%postun lpd
+%systemd_postun_with_restart cups-lpd.socket
+exit 0
+
+%triggerin -- samba-client
+ln -sf %{_libexecdir}/samba/cups_backend_smb %{cups_serverbin}/backend/smb || :
+exit 0
+
+%triggerun -- samba-client
+[ $2 = 0 ] || exit 0
+rm -f %{cups_serverbin}/backend/smb
+
+%files -f %{name}.lang
+%doc README.md CREDITS.md CHANGES.md
+%dir %attr(0755,root,lp) %{_sysconfdir}/cups
+%dir %attr(0755,root,lp) %{_localstatedir}/run/cups
+%dir %attr(0511,lp,sys) %{_localstatedir}/run/cups/certs
+%{_tmpfilesdir}/cups.conf
+%{_tmpfilesdir}/cups-lp.conf
+%verify(not md5 size mtime) %config(noreplace) %attr(0640,root,lp) %{_sysconfdir}/cups/cupsd.conf
+%attr(0640,root,lp) %{_sysconfdir}/cups/cupsd.conf.default
+%verify(not md5 size mtime) %config(noreplace) %attr(0640,root,lp) %{_sysconfdir}/cups/cups-files.conf
+%attr(0640,root,lp) %{_sysconfdir}/cups/cups-files.conf.default
+%verify(not md5 size mtime) %config(noreplace) %attr(0644,root,lp) %{_sysconfdir}/cups/client.conf
+%verify(not md5 size mtime) %config(noreplace) %attr(0600,root,lp) %{_sysconfdir}/cups/classes.conf
+%verify(not md5 size mtime) %config(noreplace) %attr(0600,root,lp) %{_sysconfdir}/cups/printers.conf
+%verify(not md5 size mtime) %config(noreplace) %attr(0644,root,lp) %{_sysconfdir}/cups/snmp.conf
+%attr(0640,root,lp) %{_sysconfdir}/cups/snmp.conf.default
+%verify(not md5 size mtime) %config(noreplace) %attr(0640,root,lp) %{_sysconfdir}/cups/subscriptions.conf
+#%%{_sysconfdir}/cups/interfaces
+%verify(not md5 size mtime) %config(noreplace) %attr(0644,root,lp) %{_sysconfdir}/cups/lpoptions
+%dir %attr(0755,root,lp) %{_sysconfdir}/cups/ppd
+%dir %attr(0700,root,lp) %{_sysconfdir}/cups/ssl
+%config(noreplace) %{_sysconfdir}/pam.d/cups
+%config(noreplace) %{_sysconfdir}/logrotate.d/cups
+%dir %{_datadir}/%{name}/www
+%dir %{_datadir}/%{name}/www/de
+%dir %{_datadir}/%{name}/www/es
+%dir %{_datadir}/%{name}/www/ja
+%dir %{_datadir}/%{name}/www/ru
+%{_datadir}/%{name}/www/images
+%{_datadir}/%{name}/www/*.css
+%doc %{_datadir}/%{name}/www/index.html
+%doc %{_datadir}/%{name}/www/help
+%doc %{_datadir}/%{name}/www/robots.txt
+%doc %{_datadir}/%{name}/www/de/index.html
+%doc %{_datadir}/%{name}/www/es/index.html
+%doc %{_datadir}/%{name}/www/ja/index.html
+%doc %{_datadir}/%{name}/www/ru/index.html
+%doc %{_datadir}/%{name}/www/pt_BR/index.html
+%doc %{_datadir}/%{name}/www/apple-touch-icon.png
+%dir %{_datadir}/%{name}/usb
+%{_datadir}/%{name}/usb/org.cups.usb-quirks
+%{_unitdir}/%{name}.service
+%{_unitdir}/%{name}.socket
+%{_unitdir}/%{name}.path
+%{_bindir}/cupstestppd
+%{_bindir}/cupstestdsc
+%{_bindir}/ppd*
+%{cups_serverbin}/backend/*
+%{cups_serverbin}/cgi-bin
+%dir %{cups_serverbin}/daemon
+%{cups_serverbin}/daemon/cups-deviced
+%{cups_serverbin}/daemon/cups-driverd
+%{cups_serverbin}/daemon/cups-exec
+%{cups_serverbin}/notifier
+%{cups_serverbin}/filter/*
+%{cups_serverbin}/monitor
+%{_mandir}/man[1578]/*
+# client subpackage
+%exclude %{_mandir}/man1/lp*.1.gz
+%exclude %{_mandir}/man1/cancel-cups.1.gz
+%exclude %{_mandir}/man8/lpc-cups.8.gz
+# devel subpackage
+%exclude %{_mandir}/man1/cups-config.1.gz
+# ipptool subpackage
+%exclude %{_mandir}/man1/ipptool.1.gz
+%exclude %{_mandir}/man5/ipptoolfile.5.gz
+# lpd subpackage
+%exclude %{_mandir}/man8/cups-lpd.8.gz
+%{_sbindir}/*
+# client subpackage
+%exclude %{_sbindir}/lpc.cups
+%dir %{_datadir}/cups/templates
+%dir %{_datadir}/cups/templates/de
+%dir %{_datadir}/cups/templates/es
+%dir %{_datadir}/cups/templates/ja
+%dir %{_datadir}/cups/templates/ru
+%dir %{_datadir}/cups/templates/pt_BR
+%{_datadir}/cups/templates/*.tmpl
+%{_datadir}/cups/templates/de/*.tmpl
+%{_datadir}/cups/templates/fr/*.tmpl
+%{_datadir}/cups/templates/es/*.tmpl
+%{_datadir}/cups/templates/ja/*.tmpl
+%{_datadir}/cups/templates/ru/*.tmpl
+%{_datadir}/cups/templates/pt_BR/*.tmpl
+%dir %attr(1770,root,lp) %{_localstatedir}/spool/cups/tmp
+%dir %attr(0710,root,lp) %{_localstatedir}/spool/cups
+%dir %attr(0755,lp,sys) %{_localstatedir}/log/cups
+%{_datadir}/pixmaps/cupsprinter.png
+%config(noreplace) %{_sysconfdir}/dbus-1/system.d/cups.conf
+%{_datadir}/cups/drv/sample.drv
+%{_datadir}/cups/examples
+%{_datadir}/cups/mime/mime.types
+%{_datadir}/cups/mime/mime.convs
+%{_datadir}/cups/ppdc/*.defs
+%{_datadir}/cups/ppdc/*.h
+
+%files client
+%{_sbindir}/lpc.cups
+%{_bindir}/cancel*
+%{_bindir}/lp*
+%{_mandir}/man1/lp*.1.gz
+%{_mandir}/man1/cancel-cups.1.gz
+%{_mandir}/man8/lpc-cups.8.gz
+
+%files libs
+%{license} LICENSE.txt
+%{_libdir}/libcups.so.2
+%{_libdir}/libcupscgi.so.1
+%{_libdir}/libcupsimage.so.2
+%{_libdir}/libcupsmime.so.1
+%{_libdir}/libcupsppdc.so.1
+
+%files filesystem
+%dir %{cups_serverbin}
+%dir %{cups_serverbin}/backend
+%dir %{cups_serverbin}/driver
+%dir %{cups_serverbin}/filter
+%dir %{_datadir}/cups
+#%%dir %%{_datadir}/cups/banners
+#%%dir %%{_datadir}/cups/charsets
+%dir %{_datadir}/cups/data
+%dir %{_datadir}/cups/drv
+%dir %{_datadir}/cups/mime
+%dir %{_datadir}/cups/model
+%dir %{_datadir}/cups/ppdc
+%dir %{_datadir}/ppd
+
+%files devel
+%{_bindir}/cups-config
+%{_libdir}/*.so
+%{_includedir}/cups
+%{_mandir}/man1/cups-config.1.gz
+%{_rpmconfigdir}/macros.d/macros.cups
+
+%files lpd
+%{_unitdir}/cups-lpd.socket
+%{_unitdir}/cups-lpd@.service
+%{cups_serverbin}/daemon/cups-lpd
+%{_mandir}/man8/cups-lpd.8.gz
+
+%files ipptool
+%{_bindir}/ipptool
+%{_bindir}/ippfind
+%dir %{_datadir}/cups/ipptool
+%{_datadir}/cups/ipptool/*
+%{_mandir}/man1/ipptool.1.gz
+%{_mandir}/man5/ipptoolfile.5.gz
+
+%changelog
+* Mon Jun 10 2019 Tomas Korbar - 1:2.2.6-27
+- 1677577 - Remove 'View X log' buttons from web ui
+
+* Fri Jun 07 2019 Tomas Korbar - 1:2.2.6-26
+- 1659998 - cups fails to build if clang is installed
+
+* Fri Dec 14 2018 Zdenek Dohnal - 1:2.2.6-25
+- 1659486 - cupsd crash on startup in ippCopyAttribute
+
+* Fri Dec 14 2018 Zdenek Dohnal - 1:2.2.6-24
+- related to 1659111 - fix for previous releases
+
+* Thu Dec 13 2018 Zdenek Dohnal - 1:2.2.6-23
+- 1659111 - Logs needs to have '-rw------' [regression]
+
+* Wed Dec 12 2018 Zdenek Dohnal - 1:2.2.6-22
+- 1622431 - Jobs with multiple files don't complete when backend fails
+- CVE-2018-4700 cups: Predictable session cookie breaks CSRF protection [rhel-8]
+
+* Fri Sep 21 2018 Zdenek Dohnal - 1:2.2.6-21
+- 1602469 - fixed covscan issues
+- 1625899 - cups 2.2.6 lpr command fails against old cups 1.3.9 server
+- 1625913 - ssl options aren't initialized when no SSLOptions directive is set in /etc/cups/client.conf
+- 1618009 - Enabling cups.path causes high load when jobs are submitted to CUPS
+- 1630805 - Make cups systemd unit files more upstream-like
+
+* Tue Aug 07 2018 Zdenek Dohnal - 1:2.2.6-20
+- 1613173 - Remove weak SSL/TLS ciphers from CUPS
+
+* Mon Aug 06 2018 Zdenek Dohnal - 1:2.2.6-19
+- 1612933 - cups doesn't restart after cupsctl command
+
+* Tue Jul 24 2018 Zdenek Dohnal - 1:2.2.6-18
+- correct license
+
+* Mon Jul 23 2018 Zdenek Dohnal - 1:2.2.6-17
+- 1607295 - CVE-2018-4180 CVE-2018-4181 CVE-2018-4182 CVE-2018-4183 cups: various flaws [rhel-8.0]
+
+* Wed Jun 13 2018 Zdenek Dohnal - 1:2.2.6-16
+- 1590122 - cups-driverd doesn't recognize static gzipped ppds
+
+* Tue May 29 2018 Zdenek Dohnal - 1:2.2.6-15
+- missing $ in sed
+
+* Tue Apr 03 2018 Zdenek Dohnal - 1:2.2.6-14
+- substitute default values for invalid job attributes (upstream #5186 and #5229)
+
+* Thu Mar 29 2018 Pavel Zhukov - 1:2.2.6-13
+- Use dbus fix instead of general attr delete (upstream)
+
+* Wed Mar 28 2018 Pavel Zhukov - 1:2.2.6-12
+- Fix for CVE-2017-18248
+
+* Wed Feb 28 2018 Zdenek Dohnal - 1:2.2.6-11
+- remake of 1499261
+
+* Wed Feb 28 2018 Zdenek Dohnal - 1:2.2.6-10
+- mention library names explicitly to warn about soname change
+
+* Tue Feb 27 2018 Zdenek Dohnal - 1:2.2.6-9
+- 1548120 - cups: Partial injection of Fedora build flags
+
+* Mon Feb 26 2018 Zdenek Dohnal - 1:2.2.6-8
+- pkgconfig is now shipped in pkgconf-pkg-config package
+
+* Tue Feb 20 2018 Zdenek Dohnal - 1:2.2.6-7
+- 1499261 - Move log files into journal
+
+* Mon Feb 19 2018 Zdenek Dohnal - 1:2.2.6-6
+- gcc and gcc-c++ is not in buildroot by default now
+
+* Wed Feb 07 2018 Fedora Release Engineering - 1:2.2.6-5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
+
+* Fri Feb 02 2018 Igor Gnatenko - 1:2.2.6-4
+- Switch to %%ldconfig_scriptlets
+
+* Sat Jan 20 2018 Björn Esser - 1:2.2.6-3
+- Rebuilt for switch to libxcrypt
+
+* Fri Jan 12 2018 Zdenek Dohnal - 1:2.2.6-2
+- 1437345 - Remove cups-resolv_reload.patch
+
+* Fri Nov 03 2017 Zdenek Dohnal - 1:2.2.6-1
+- rebase to 2.2.6
+
+* Tue Oct 17 2017 Zdenek Dohnal - 1:2.2.5-1
+- rebase to 2.2.5
+
+* Mon Oct 09 2017 Zdenek Dohnal - 1:2.2.4-7
+- removing ghostscript-cups dependency - cups-filters ships it
+
+* Wed Oct 04 2017 Zdenek Dohnal - 1:2.2.4-6
+- 1498091 - Cannot browse CUPS servers in GNOME Control Panel Printers
+
+* Mon Oct 02 2017 Zdenek Dohnal - 1:2.2.4-5
+- 1484916 - Can not get destinations from CUPS server
+
+* Fri Sep 22 2017 Zdenek Dohnal - 1:2.2.4-4
+- 1494558 - CUPS may fail to start if NIS groups are used
+
+* Wed Aug 02 2017 Fedora Release Engineering - 1:2.2.4-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
+
+* Wed Jul 26 2017 Fedora Release Engineering - 1:2.2.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
+
+* Fri Jun 30 2017 Zdenek Dohnal - 1:2.2.4-1
+- rebase to 2.2.4
+
+* Thu Jun 29 2017 Zdenek Dohnal - 1:2.2.3-6
+- update python dependencies accordingly Fedora Guideline for Python (python-cups -> python3-cups)
+
+* Thu Apr 27 2017 Zdenek Dohnal - 1:2.2.3-5
+- copying cups-resolv_reload.patch from RHEL
+
+* Wed Apr 05 2017 Zdenek Dohnal - 1:2.2.3-4
+- fixing issue with #1437065 - makes res_init() call to local resolver and keeps error message, but no hard exit for cupsd
+
+* Tue Apr 04 2017 Zdenek Dohnal - 1:2.2.3-3
+- disable patch for #1437065 for now until issue with stat is solved
+
+* Thu Mar 30 2017 Zdenek Dohnal - 1:2.2.3-2
+- 1437065 - CUPS does not recognize changes to /etc/resolv.conf until CUPS restart
+
+* Wed Mar 29 2017 Zdenek Dohnal - 1:2.2.3-1
+- rebase to 2.2.3
+
+* Fri Feb 10 2017 Fedora Release Engineering - 1:2.2.2-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
+
+* Thu Jan 19 2017 Zdenek Dohnal - 1:2.2.2-1
+- rebase to 2.2.2
+
+* Wed Jan 11 2017 Zdenek Dohnal - 1:2.2.1-4
+- bug 1405669 - adding group wheel to SystemGroup
+
+* Fri Nov 11 2016 Zdenek Dohnal - 1:2.2.1-3
+- Unable to print from Windows (7) on a Cups-Server(2.2.1-1) with german umlauts in the filename (bug #1386751)
+
+* Mon Nov 07 2016 Zdenek Dohnal - 1:2.2.1-2
+- #873123 - (cups-usb-quirks) usb printer doesn't print (usblp0: USB Bidirectional printer dev)
+
+* Tue Oct 04 2016 Zdenek Dohnal - 1:2.2.1-1
+- rebase to 2.2.1
+
+* Thu Sep 22 2016 Zdenek Dohnal - 1:2.2.0-2
+- fixing looping in partial failing service (bug #1366775)
+
+* Thu Sep 15 2016 Jiri Popelka - 1:2.2.0-1
+- 2.2.0
+
+* Fri Aug 12 2016 Zdenek Dohnal - 1:2.2-0.4rc1
+- fixing release number
+
+* Tue Aug 09 2016 Zdenek Dohnal - 1:2.2-0.2rc1
+- rebase to cups-2.2rc1
+
+* Wed Aug 03 2016 Zdenek Dohnal - 1:2.2-0.2b2
+- bug 1358589 - added information about syslog means systemd journal by default
+
+* Mon Jun 27 2016 Zdenek Dohnal - 1:2.2-0.1b2
+- Rebase to 2.2b2, editing patches and spec (no need for /etc/cups/interfaces)
+
+* Mon Jun 27 2016 Zdenek Dohnal - 1:2.1.4-1
+- substitution BuildRequires: pkgconfig(libsystemd-*) for BuildRequires: pkgconfig(libsystemd)
+
+* Wed Jun 15 2016 Zdenek Dohnal - 1:2.1.4-1
+- 2.1.4, 1346668 - Change symlink for smb backend to /usr/libexec/samba/cups_backend_smb
+
+* Mon Feb 08 2016 Jiri Popelka - 1:2.1.3-1
+- 2.1.3
+
+* Wed Feb 03 2016 Fedora Release Engineering - 1:2.1.2-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
+
+* Wed Dec 02 2015 Jiri Popelka - 1:2.1.2-1
+- 2.1.2 - interface scripts support is back (until 2.2)
+
+* Tue Dec 01 2015 Jiri Popelka - 1:2.1.1-1
+- 2.1.1 - interface scripts no longer supported.
+
+* Mon Nov 02 2015 Jiri Popelka - 1:2.1.0-2
+- Change mode of subscriptions.conf from 644 to 640 (bug #1259770).
+
+* Tue Sep 01 2015 Jiri Popelka - 1:2.1.0-1
+- 2.1.0
+
+* Thu Aug 13 2015 Jiri Popelka - 1:2.1-0.3rc1
+- fix crash in scheduler (#1253135)
+
+* Mon Aug 10 2015 Jiri Popelka - 1:2.1-0.2rc1
+- better fix for STR#4687
+
+* Mon Aug 10 2015 Jiri Popelka - 1:2.1-0.1rc1
+- 2.1rc1
+
+* Mon Aug 10 2015 Jiri Popelka - 1:2.0.4-1
+- 2.0.4
+
+* Tue Jul 28 2015 Jiri Popelka - 1:2.0.3-5
+- BuildRequires: gnutls-devel -> pkgconfig(gnutls)
+
+* Tue Jul 07 2015 Jiri Popelka - 1:2.0.3-4
+- RPM_BUILD_ROOT -> %%{buildroot}, put braces around lspp and use_alternatives
+
+* Thu Jun 25 2015 Tim Waugh - 1:2.0.3-3
+- Fix slow resume of jobs after restart (STR #4646).
+- Fix redirection from CGI scripts (bug #1232030, STR #4538).
+
+* Wed Jun 17 2015 Fedora Release Engineering - 1:2.0.3-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
+* Tue Jun 09 2015 Jiri Popelka - 1:2.0.3-1
+- 2.0.3
+
+* Sat May 02 2015 Kalev Lember - 1:2.0.2-6
+- Rebuilt for GCC 5 C++11 ABI change
+
+* Mon Mar 16 2015 Tim Waugh - 1:2.0.2-5
+- Avoid busy loop in cupsd when connection is closed after request
+ sent (bug #1179596).
+
+* Mon Feb 16 2015 Jiri Popelka - 1:2.0.2-2
+- Fixed multilib.patch to check for gnutls instead of openssl.
+
+* Tue Feb 10 2015 Jiri Popelka - 1:2.0.2-1
+- 2.0.2
+
+* Tue Jan 27 2015 Tim Waugh - 1:2.0.1-2
+- Fixed systemd notify support (bug #1184453).
+
+* Sat Nov 15 2014 Jiri Popelka - 1:2.0.1-1
+- 2.0.1
+
+* Fri Nov 7 2014 Tim Waugh - 1:2.0.0-12
+- Re-introduce SSLOptions configuration directive, disable SSL3 by
+ default (STR #4476).
+- Enable SSL again via GnuTLS (bug #1161235).
+
+* Thu Nov 6 2014 Tim Waugh - 1:2.0.0-11
+- Removed openssl requirements from spec file as it is no longer
+ supported upstream (see bug #1161235).
+
+* Thu Nov 6 2014 Tim Waugh - 1:2.0.0-10
+- cups-lspp.patch: use cupsdLogJob() when appropriate.
+- Fixed some warnings in cups-lspp.patch.
+- New systemd journal fields CUPS_DEST and CUPS_PRINTER, as well as
+ accurate code location fields.
+
+* Wed Oct 22 2014 Tim Waugh - 1:2.0.0-9
+- Upstream fix for cupsd crash on restart when colord not available
+- (STR #4496).
+
+* Sat Oct 18 2014 Tim Waugh - 1:2.0.0-7
+- Fix for last fix (bug #1153660, bug #1154284).
+
+* Thu Oct 16 2014 Tim Waugh - 1:2.0.0-6
+- Start cupsd systemd service after network.target (bug #1153660).
+
+* Wed Oct 15 2014 Tim Waugh - 1:2.0.0-5
+- Fix cupsGetPPD3() so it doesn't give the caller an unreadable file
+ (bug #1150917, STR #4500).
+
+* Wed Oct 15 2014 Tim Waugh - 1:2.0.0-4
+- Can no longer reproduce bug #1010580 so removing final-content-type
+ patch as it causes issues for some backends (bug #1149244).
+
+* Fri Oct 03 2014 Jiri Popelka - 1:2.0.0-3
+- comment out unnecessary PageLogFormat from cups-files.conf (#1148995)
+
+* Fri Oct 03 2014 Jiri Popelka - 1:2.0.0-2
+- s/org.cups.cupsd/cups/ cups.service
+
+* Wed Oct 01 2014 Jiri Popelka - 1:2.0.0-1
+- 2.0.0
+
+* Fri Sep 12 2014 Jiri Popelka - 1:2.0-0.1.rc1
+- 2.0rc1
+
+* Mon Sep 1 2014 Tim Waugh - 1:1.7.5-7
+- Fix icon display in web interface during server restart (STR #4475).
+
+* Mon Sep 1 2014 Tim Waugh - 1:1.7.5-6
+- More STR #4461 fixes from upstream.
+
+* Tue Aug 26 2014 Tim Waugh - 1:1.7.5-5
+- Use upstream patch for STR #4461.
+
+* Wed Aug 20 2014 Tim Waugh - 1:1.7.5-4
+- Removed old one-off trigger now it's no longer needed.
+- Run systemd postun script for path and socket unit files as well as
+ the main service unit file.
+- Upstream patch for STR #4396, pre-requisite for STR #2913 patch.
+- Upstream patch for STR #2913 to limit Get-Jobs replies to 500 jobs
+ (bug #421671).
+
+* Sat Aug 16 2014 Fedora Release Engineering - 1:1.7.5-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
+
+* Mon Aug 11 2014 Tim Waugh - 1:1.7.5-2
+- Fix conf/log file reading for authenticated users (STR #4461).
+
+* Fri Aug 01 2014 Jiri Popelka - 1:1.7.5-1
+- 1.7.5
+
+* Wed Jul 23 2014 Jiri Popelka - 1:1.7.4-3
+- CVE-2014-5029, CVE-2014-5030, CVE-2014-5031 (#1122601)
+
+* Wed Jul 23 2014 Tim Waugh - 1:1.7.4-2
+- Fix CGI handling (STR #4454).
+
+* Mon Jul 14 2014 Jiri Popelka - 1:1.7.4-1
+- 1.7.4: CVE-2014-3537
+
+* Sat Jun 07 2014 Fedora Release Engineering - 1:1.7.3-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Wed May 28 2014 Jiri Popelka - 1:1.7.3-1
+- 1.7.3
+- str4386.patch merged upstream in STR #4403
+
+* Fri May 9 2014 Tim Waugh - 1:1.7.2-3
+- Another attempt at avoiding race condition when sending IPP requests
+ (STR #4386, bug #1072952).
+
+* Thu Apr 17 2014 Jiri Popelka - 1:1.7.2-2
+- Make cups.service Type=notify (bug #1088918).
+
+* Mon Apr 14 2014 Jiri Popelka - 1:1.7.2-1
+- 1.7.2
+
+* Fri Apr 4 2014 Tim Waugh - 1:1.7.1-11
+- Log to the system journal by default (bug #1078781).
+
+* Thu Apr 3 2014 Tim Waugh - 1:1.7.1-10
+- libcups: avoid race condition when sending IPP requests (STR #4386,
+ bug #1072952).
+
+* Wed Apr 02 2014 Jiri Popelka - 1:1.7.1-9
+- New client subpackage containing command line client tools (bug #1002342).
+- Removed unneeded Group tags.
+- Removed 'Requires: /sbin/chkconfig'.
+- Moved 'Provides: lpd' to lpd subpackage.
+
+* Tue Mar 18 2014 Tim Waugh - 1:1.7.1-8
+- Removed patch for STR #4386 as it does not work and causes problems
+ instead (bug #1077239).
+
+* Mon Mar 10 2014 Jiri Popelka - 1:1.7.1-7
+- BuildRequires: pkgconfig(foo) instead of foo-devel
+
+* Thu Mar 6 2014 Tim Waugh - 1:1.7.1-6
+- Track local default in cupsEnumDests() (STR #4332).
+- libcups: avoid race condition when sending IPP requests (STR #4386).
+- Prevent feedback loop when fetching error_log over HTTP (STR #4366).
+
+* Wed Mar 5 2014 Tim Waugh - 1:1.7.1-5
+- Fix for cupsEnumDest() 'removed' callbacks (bug #1054312, STR #4380).
+
+* Mon Feb 17 2014 Tim Waugh - 1:1.7.1-4
+- Document 'journal' logging target.
+
+* Tue Feb 11 2014 Tim Waugh - 1:1.7.1-3
+- Prevent dnssd backend exiting too early (bug #1026940, STR #4365).
+
+* Mon Feb 03 2014 Jiri Popelka - 1:1.7.1-2
+- move macros.cups from /etc/rpm/ to /usr/lib/rpm/macros.d
+
+* Wed Jan 08 2014 Jiri Popelka - 1:1.7.1-1
+- 1.7.1
+
+* Wed Jan 8 2014 Tim Waugh - 1:1.7.0-11
+- Apply upstream patch to improve cupsUser() (STR #4327).
+
+* Tue Jan 7 2014 Tim Waugh - 1:1.7.0-10
+- Removed cups-dbus-utf8.patch as no longer needed (see STR #4314).
+- Return jobs in rank order when handling IPP-Get-Jobs (STR #4326).
+
+* Thu Jan 2 2014 Tim Waugh - 1:1.7.0-9
+- dbus notifier: call _exit when handling SIGTERM (STR #4314).
+- Use '-f' when using rm in %%setup section.
+- Fixed avahi-no-threaded patch so it removes a call to
+ avahi_threaded_poll_stop() (bug #1044602).
+
+* Fri Dec 13 2013 Tim Waugh - 1:1.7.0-8
+- Use string literal for format string in sd_journal_print call.
+
+* Thu Nov 28 2013 Tim Waugh - 1:1.7.0-7
+- Prevent USB timeouts causing incorrect print output (bug #1026914).
+
+* Thu Nov 14 2013 Tim Waugh - 1:1.7.0-6
+- Avoid stale lockfile in dbus notifier (bug #1026949).
+
+* Thu Nov 7 2013 Tim Waugh - 1:1.7.0-5
+- Use upstream patch for stringpool corruption issue (bug #974048).
+
+* Mon Nov 4 2013 Tim Waugh - 1:1.7.0-4
+- Adjusted commented out default for SyncOnClose in cups-files.conf.
+
+* Thu Oct 31 2013 Tim Waugh - 1:1.7.0-3
+- Set the default for SyncOnClose to Yes.
+
+* Mon Oct 28 2013 Tim Waugh - 1:1.7.0-2
+- Use upstream patch to fix job history.
+
+* Thu Oct 24 2013 Tim Waugh - 1:1.7.0-1
+- 1.7.0.
+
+* Thu Oct 24 2013 Tim Waugh
+- Fix job history logging.
+
+* Mon Oct 21 2013 Tim Waugh - 1:1.7-0.27.rc1
+- Allow "journal" log type for log output to system journal.
+
+* Fri Sep 27 2013 Tim Waugh - 1:1.7-0.26.rc1
+- Reverted upstream change to FINAL_CONTENT_TYPE in order to fix
+ printing to remote CUPS servers (bug #1010580).
+
+* Wed Aug 21 2013 Jaromír Končický
+- Add SyncOnClose option (bug #984883).
+
+* Fri Aug 16 2013 Tim Waugh - 1:1.7-0.25.rc1
+- Increase web interface get-devices timeout to 10s (bug #996664).
+
+* Thu Aug 15 2013 Tim Waugh - 1:1.7-0.24.rc1
+- Build with full read-only relocations (bug #996740).
+
+* Tue Aug 6 2013 Tim Waugh - 1:1.7-0.23.rc1
+- Fixes for jobs with multiple files and multiple formats.
+
+* Sat Aug 03 2013 Fedora Release Engineering - 1:1.7-0.22.rc1
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
+
+* Wed Jul 24 2013 Tim Waugh - 1:1.7-0.21.rc1
+- Fixed cups-config, broken by last change (bug #987660).
+
+* Mon Jul 22 2013 Tim Waugh - 1:1.7-0.20.rc1
+- Removed stale comment in spec file.
+- Link against OpenSSL instead of GnuTLS.
+
+* Mon Jul 22 2013 Tim Waugh - 1:1.7-0.19.rc1
+- Fixed avahi-no-threaded patch (was missing part of cupsd.h). Thanks
+ to Joseph Wang for spotting it.
+
+* Thu Jul 18 2013 Tim Waugh - 1:1.7-0.18.rc1
+- Fixed downoad URL to point to the actual source, not a download
+ page.
+
+* Fri Jul 12 2013 Jiri Popelka - 1:1.7-0.17.rc1
+- 1.7rc1
+
+* Thu Jul 11 2013 Tim Waugh 1:1.7-0.16.b1
+- Avoid sign-extending CRCs for gz decompression (bug #983486).
+
+* Wed Jul 10 2013 Tim Waugh 1:1.7-0.15.b1
+- Fixed download URL.
+
+* Wed Jul 10 2013 Jiri Popelka - 1:1.7-0.14.b1
+- Remove pstops cost factor tweak from conf/mime.convs.in
+
+* Mon Jul 1 2013 Tim Waugh 1:1.7-0.13.b1
+- Don't use D-Bus from two threads (bug #979748).
+
+* Fri Jun 28 2013 Tim Waugh 1:1.7-0.12.b1
+- Fix for DNSSD name resolution.
+
+* Wed Jun 26 2013 Tim Waugh 1:1.7-0.11.b1
+- Default to IPP/1.1 for now (bug #977813).
+
+* Tue Jun 25 2013 Tim Waugh 1:1.7-0.10.b1
+- Added libusb quirk for Canon PIXMA MP540 (bug #967873).
+
+* Mon Jun 24 2013 Tim Waugh 1:1.7-0.9.b1
+- Don't link against libgcrypt needlessly.
+
+* Thu Jun 20 2013 Jiri Popelka - 1:1.7-0.8.b1
+- Remove scriptlet for migrating to a systemd unit from a SysV initscript
+
+* Thu Jun 20 2013 Tim Waugh 1:1.7-0.7.b1
+- Use IP_FREEBIND socket option when binding listening sockets (bug #970809).
+
+* Tue Jun 18 2013 Tim Waugh 1:1.7-0.6.b1
+- Added IEEE 1284 Device ID for a Dymo device (bug #747866).
+
+* Thu Jun 13 2013 Tim Waugh 1:1.7-0.5.b1
+- Prevent stringpool damage leading to memory leaks (bug #974048).
+
+* Tue Jun 4 2013 Tim Waugh - 1:1.7-0.4.b1
+- Return from cupsEnumDests() once all records have been returned.
+
+* Thu May 23 2013 Jiri Popelka
+- don't ship Russian web templates because they're broken (#960571, STR #4310)
+
+* Wed May 15 2013 Jiri Popelka - 1:1.7-0.3.b1
+- move cups/ppdc/ to filesystem subpackage
+
+* Mon Apr 29 2013 Jiri Popelka - 1:1.7-0.2.b1
+- Do not apply unary exclamation mark to va_list (bug #957737).
+
+* Fri Apr 19 2013 Jiri Popelka - 1:1.7-0.1.b1
+- 1.7b1
+- use _tmpfilesdir macro
+
+* Wed Apr 10 2013 Tim Waugh
+- cups-dbus-utf.patch: now that the scheduler only accepts valid UTF-8
+ strings for job-name, there's no need to validate it as UTF-8 in the
+ dbus notifier.
+
+* Thu Apr 4 2013 Tim Waugh 1:1.6.2-4
+- Use IP address when resolving DNSSD URIs (bug #948288).
+
+* Thu Mar 28 2013 Tim Waugh 1:1.6.2-3
+- Check for cupsd.conf existence prior to grepping it (bug #928816).
+
+* Tue Mar 19 2013 Jiri Popelka - 1:1.6.2-2
+- revert previous bug #919489 fix (i.e we don't ship banners now)
+
+* Mon Mar 18 2013 Jiri Popelka - 1:1.6.2-1
+- 1.6.2
+
+* Wed Mar 13 2013 Jiri Popelka - 1:1.6.1-26
+- ship banners again (#919489)
+
+* Tue Mar 5 2013 Tim Waugh 1:1.6.1-25
+- Talk about systemd in cups-lpd manpage (part of bug #884641).
+
+* Tue Mar 5 2013 Tim Waugh 1:1.6.1-24
+- Documentation fixes from STR #4223 (bug #915981).
+
+* Wed Feb 27 2013 Jiri Popelka - 1:1.6.1-23
+- Removed obsolete browsing directives from cupsd.conf (bug #880826, STR #4157).
+- Updated summary and descriptions (#882982).
+- Fixed bogus dates in changelog.
+
+* Fri Feb 15 2013 Tim Waugh 1:1.6.1-22
+- Applied colorman fix from STR #4232 and STR #4276.
+
+* Wed Feb 13 2013 Fedora Release Engineering - 1:1.6.1-21
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
+
+* Fri Jan 18 2013 Jiri Popelka 1:1.6.1-20
+- Add quirk rule for Canon MP210 (#847923).
+
+* Mon Jan 14 2013 Jiri Popelka 1:1.6.1-19
+- Fix unowned directories (#894531).
+
+* Thu Jan 10 2013 Jiri Popelka 1:1.6.1-18
+- Clean /var/spool/cups/tmp with tmpfiles.d instead of tmpwatch&cron (#893834).
+
+* Wed Dec 19 2012 Jiri Popelka 1:1.6.1-17
+- Migrate cups-lpd from xinetd to systemd socket activatable service (#884641).
+- Clean up old Requires/Conflicts/Obsoletes/Provides.
+
+* Thu Dec 6 2012 Tim Waugh 1:1.6.1-16
+- Additional fix relating to CVE-2012-5519 to avoid misleading error
+ message about actions to take to enable file device URIs.
+
+* Tue Dec 4 2012 Tim Waugh 1:1.6.1-15
+- Small error handling improvements in the configuration migration
+ script.
+
+* Mon Dec 3 2012 Jiri Popelka 1:1.6.1-14
+- move ipptoolfile(5) to ipptool subpackage
+
+* Mon Dec 3 2012 Tim Waugh 1:1.6.1-13
+- Applied additional upstream patch for CVE-2012-5519 so that the
+ RemoteRoot keyword is recognised in the correct configuration file.
+
+* Wed Nov 28 2012 Tim Waugh 1:1.6.1-12
+- Fixed paths in config migration %%post script.
+- Set default cups-files.conf filename.
+
+* Mon Nov 26 2012 Tim Waugh 1:1.6.1-11
+- Apply upstream fix for CVE-2012-5519 (STR #4223, bug #875898).
+ Migrate configuration keywords as needed.
+
+* Mon Nov 19 2012 Tim Waugh 1:1.6.1-10
+- Re-enable the web interface as it is required for adjusting server
+ settings (bug #878090).
+
+* Tue Nov 6 2012 Tim Waugh 1:1.6.1-9
+- Disable the web interface by default (bug #864522).
+
+* Tue Oct 30 2012 Tim Waugh 1:1.6.1-8
+- Ensure attributes are valid UTF-8 in dbus notifier (bug #863387).
+
+* Mon Oct 29 2012 Tim Waugh 1:1.6.1-7
+- Removed broken cups-get-classes patch (bug #870612).
+
+* Mon Oct 22 2012 Jiri Popelka 1:1.6.1-6
+- Add quirk rule for Xerox Phaser 3124 (#867392)
+- backport more quirk rules (STR #4191)
+
+* Thu Sep 20 2012 Tim Waugh 1:1.6.1-5
+- The cups-libs subpackage contains code distributed under the zlib
+ license (md5.c).
+
+* Thu Aug 23 2012 Jiri Popelka 1:1.6.1-4
+- quirk handler for port reset done by new USB backend (bug #847923, STR #4155)
+
+* Mon Aug 13 2012 Jiri Popelka 1:1.6.1-3
+- fixed usage of parametrized systemd macros (#847405)
+
+* Wed Aug 08 2012 Jiri Popelka 1:1.6.1-2
+- Requires: cups-filters
+
+* Wed Aug 08 2012 Jiri Popelka 1:1.6.1-1
+- 1.6.1
+ - simplified systemd.patch due to removed CUPS Browsing protocol (STR #3922)
+ - removed:
+ textonly filter - moved to cups-filters
+ pstopdf filter - cups-filters also has pstopdf (different)
+ PHP module - moved to cups-filters (STR #3932)
+ serial.patch - moved to cups-filters
+ getpass.patch - r10140 removed the getpass() use
+ snmp-quirks.patch - fixed upstream (r10493)
+ avahi patches - merged upstream (STR #3066)
+ icc.patch - merged upstream (STR #3808)
+ - TODO:
+ - do we need cups-build.patch ?
+- added filesystem sub-package (#624695)
+- use macroized systemd scriptlets
+
+* Thu Jul 26 2012 Jiri Popelka 1:1.5.4-1
+- 1.5.4
+
+* Tue Jul 24 2012 Tim Waugh 1:1.5.3-5
+- Don't enable IP-based systemd socket activation by default (bug #842365).
+
+* Wed Jul 18 2012 Fedora Release Engineering - 1:1.5.3-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Tue Jun 05 2012 Jiri Popelka 1:1.5.3-3
+- Require systemd instead of udev.
+
+* Mon May 28 2012 Jiri Popelka 1:1.5.3-2
+- Buildrequire libusb1 (STR #3477)
+
+* Tue May 15 2012 Jiri Popelka 1:1.5.3-1
+- 1.5.3
+
+* Wed May 09 2012 Jiri Popelka 1:1.5.2-13
+- Add triggers for samba4-client. (#817110)
+- No need to define BuildRoot and clean it in clean and install section anymore.
+- %%defattr no longer needed in %%files sections.
+
+* Tue Apr 17 2012 Jiri Popelka