From c25abc7556a7225140d63e1908368626affcd70f Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Jul 28 2020 07:45:29 +0000 Subject: import cups-2.2.6-38.el8 --- diff --git a/SOURCES/cups-autostart-when-enabled.patch b/SOURCES/cups-autostart-when-enabled.patch new file mode 100644 index 0000000..1cdefb6 --- /dev/null +++ b/SOURCES/cups-autostart-when-enabled.patch @@ -0,0 +1,10 @@ +diff --git a/scheduler/org.cups.cupsd.service.in b/scheduler/org.cups.cupsd.service.in +index 307d69b..add238b 100644 +--- a/scheduler/org.cups.cupsd.service.in ++++ b/scheduler/org.cups.cupsd.service.in +@@ -10,4 +10,4 @@ Restart=on-failure + + [Install] + Also=cups.socket cups.path +-WantedBy=printer.target ++WantedBy=printer.target multi-user.target diff --git a/SOURCES/cups-dirtyclean.patch b/SOURCES/cups-dirtyclean.patch new file mode 100644 index 0000000..390ed19 --- /dev/null +++ b/SOURCES/cups-dirtyclean.patch @@ -0,0 +1,13 @@ +diff --git a/scheduler/main.c b/scheduler/main.c +index 592531a..a6e2c3a 100644 +--- a/scheduler/main.c ++++ b/scheduler/main.c +@@ -947,7 +947,7 @@ main(int argc, /* I - Number of command-line args */ + * Write dirty config/state files... + */ + +- if (DirtyCleanTime && current_time >= DirtyCleanTime && cupsArrayCount(Clients) == 0) ++ if (DirtyCleanTime && current_time >= DirtyCleanTime) + cupsdCleanDirty(); + + #ifdef __APPLE__ diff --git a/SOURCES/cups-etimedout.patch b/SOURCES/cups-etimedout.patch new file mode 100644 index 0000000..31defda --- /dev/null +++ b/SOURCES/cups-etimedout.patch @@ -0,0 +1,25 @@ +diff --git a/cups/http-addrlist.c b/cups/http-addrlist.c +index e4ffc3d..a989055 100644 +--- a/cups/http-addrlist.c ++++ b/cups/http-addrlist.c +@@ -240,7 +240,10 @@ httpAddrConnect2( + } + + if (!addrlist && nfds == 0) ++ { ++ errno = EHOSTDOWN; + break; ++ } + + /* + * See if we can connect to any of the addresses so far... +@@ -371,6 +374,9 @@ httpAddrConnect2( + remaining -= 250; + } + ++ if (remaining <= 0) ++ errno = ETIMEDOUT; ++ + while (nfds > 0) + { + nfds --; diff --git a/SOURCES/cups-failover-backend.patch b/SOURCES/cups-failover-backend.patch new file mode 100644 index 0000000..a92dad8 --- /dev/null +++ b/SOURCES/cups-failover-backend.patch @@ -0,0 +1,877 @@ +diff --git a/backend/Makefile b/backend/Makefile +index 3038682..6642016 100644 +--- a/backend/Makefile ++++ b/backend/Makefile +@@ -28,6 +28,7 @@ include ../Makedefs + RBACKENDS = \ + ipp \ + lpd \ ++ failover \ + $(DNSSD_BACKEND) + UBACKENDS = \ + snmp \ +@@ -51,6 +52,7 @@ LIBOBJS = \ + OBJS = \ + ipp.o \ + lpd.o \ ++ failover.o \ + dnssd.o \ + snmp.o \ + socket.o \ +@@ -275,6 +277,13 @@ lpd: lpd.o ../cups/$(LIBCUPS) libbackend.a + echo Linking $@... + $(LD_CC) $(LDFLAGS) -o lpd lpd.o libbackend.a $(LIBS) + ++# ++# failover ++# ++ ++failover: failover.o ../cups/$(LIBCUPS) libbackend.a ++ echo Linking $@... ++ $(LD_CC) $(LDFLAGS) -o failover failover.o libbackend.a $(LIBS) + + # + # snmp +diff --git a/backend/failover.c b/backend/failover.c +new file mode 100644 +index 0000000..9affd8f +--- /dev/null ++++ b/backend/failover.c +@@ -0,0 +1,837 @@ ++/* ++ * Failover Backend for the Common UNIX Printing System (CUPS). ++ * ++ * Copyright (c) 2014, Red Hat, Inc. ++ * All rights reserved. ++ * ++ * 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. ++ * * Neither the name of Red Hat, Inc. nor the names of its contributors ++ * may be used to endorse or promote products derived from this software ++ * without specific prior written permission. ++ * ++ * 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 RED HAT, ++ * INC. 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. ++ * ++ * Original version by Clark Hale, Red Hat, Inc. ++ * ++ * This backend presents a fake printer that will choose the first ++ * available printer from a list of IPP URIs. ++ * ++ * Option failover contains a comma separated list of IPP URIs. The ++ * URIs are attempted in-order. ++ * ++ * Option failover-retries contains an integer that indicates how many ++ * times to iterate through the failover list before completely ++ * failing. ++ * ++ * Contents: ++ * main() - Checks each printer in a failover list, and ++ * sends job data to the first available printer ++ * move_job() - Sends and IPP Move-Job request ++ * check_printer() - Checks a printer's attributes to see ++ * if it's enabled and accepting jobs ++ * read_config() - Read the backends configuration from ++ * options ++ * get_printer_attributes() - Sends an IPP Get-Attributes request to ++ * a URI ++ * sigterm_handler() - Handle SIGTERM that cancels the job ++ * password_cb() - Password call back used to disable password ++ * prompt ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "backend-private.h" ++ ++/* ++ * Return Values ++ */ ++typedef enum fo_state_e ++{ ++ FO_PRINTER_GOOD = 0, ++ FO_PRINTER_BAD, ++ FO_PRINTER_BUSY, ++ FO_AUTH_REQUIRED ++} fo_state_t; ++ ++/* ++ * Constants ++ */ ++#define FAILOVER_DEFAULT_RETRIES (3) ++#define FAILOVER_PASSWORD_RETRIES_MAX (3) ++ ++/* ++ * Local Functions ++ */ ++static int check_printer(const char *device_uri); ++static int read_config(cups_array_t *printer_array, int *retries, ++ const char *options); ++static int get_printer_attributes(const char *device_uri, ++ ipp_t **attributes); ++static int move_job(int jobid, const char *dest); ++static void sigterm_handler(int sig); ++static const char *password_cb(const char *); ++ ++/* ++ * Global Variables ++ */ ++static int job_canceled = 0; /* Job canceled */ ++static char *password = NULL; /* password for device */ ++static int password_retries = 0; ++static const char *auth_info_required = "none"; ++ ++/* ++ * 'main()' - Checks each printer in a failover list, and ++ * sends job data to the first available printer ++ * Usage: ++ * printer-uri job-id user title copies options [file] ++ * ++ * The printer-uri option is not used, but it still required to fit ++ * to the backend(7) standards. ++ */ ++int ++main(int argc, char *argv[]) ++{ ++ const char *selected_uri = NULL; /* URI of selected printer */ ++ const char *tmp_device_uri; /* Device URI to check */ ++ cups_array_t *printer_array; /* Array of available printers */ ++ int printer_count = 0; /* current printer array index */ ++ int retry_max = 1; /* maximum retries before exit */ ++ int retry_count = 0; /* current retry number */ ++ int auth_failed_count = 0; /* auth failures per loop */ ++ int rc = CUPS_BACKEND_OK; ++#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) ++ struct sigaction action; /* Actions for POSIX signals */ ++#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ ++ ++ /* ++ * Check args ++ */ ++ if (argc == 1) ++ { ++ /* ++ * print out discovery data ++ */ ++ char *backendName; ++ ++ if ((backendName = strrchr(argv[0], '/')) != NULL) ++ backendName++; ++ else ++ backendName = argv[0]; ++ ++ _cupsLangPrintf(stderr,"network %s \"Unknown\" \"%s (%s)\"\n", ++ backendName, ++ _cupsLangString(cupsLangDefault(), _("Failover Printer")), ++ backendName); ++ ++ return (CUPS_BACKEND_OK); ++ } ++ else if (argc < 6) ++ { ++ _cupsLangPrintf(stderr, ++ _("Usage: %s job-id user title copies options [file]"), ++ argv[0]); ++ return (CUPS_BACKEND_STOP); ++ } ++ ++ fprintf(stderr, "DEBUG: Failover backend starting up.\n"); ++ ++ /* ++ * Don't buffer status messages ++ */ ++ setbuf(stderr, NULL); ++ ++ /* ++ * Ignore SIGPIPE and catch SIGTERM signals... ++ */ ++#ifdef HAVE_SIGSET ++ sigset(SIGPIPE, SIG_IGN); ++ sigset(SIGTERM, sigterm_handler); ++#elif defined(HAVE_SIGACTION) ++ memset(&action, 0, sizeof(action)); ++ action.sa_handler = SIG_IGN; ++ sigaction(SIGPIPE, &action, NULL); ++ ++ sigemptyset(&action.sa_mask); ++ sigaddset(&action.sa_mask, SIGTERM); ++ action.sa_handler = sigterm_handler; ++ sigaction(SIGTERM, &action, NULL); ++#else ++ signal(SIGPIPE, SIG_IGN); ++ signal(SIGTERM, sigterm_handler); ++#endif /* HAVE_SIGSET */ ++ ++ printer_array = cupsArrayNew(NULL, NULL); ++ ++ /* ++ * Read Configuration ++ */ ++ if ((rc = read_config(printer_array, &retry_max, ++ argv[5])) != CUPS_BACKEND_OK) ++ { ++ fprintf(stderr, "ERROR: Failed to read configuration options!\n"); ++ goto cleanup; ++ } ++ ++ /* ++ * Main Retry Loop ++ */ ++ for (retry_count = 0; retry_count < retry_max; retry_count++) ++ { ++ fprintf(stderr, "DEBUG: Retry loop #%d\n", retry_count + 1); ++ ++ /* ++ * Reset Counters ++ */ ++ printer_count = 0; ++ auth_failed_count = 0; ++ ++ tmp_device_uri = (char *)cupsArrayFirst(printer_array); ++ ++ do ++ { ++ if (job_canceled) ++ { ++ fprintf(stderr, "DEBUG: Job Canceled\n"); ++ goto cleanup; ++ } ++ ++ fprintf(stderr,"DEBUG: Checking printer #%d: %s\n", ++ printer_count+1, tmp_device_uri); ++ ++ rc = check_printer(tmp_device_uri); ++ ++ // Printer is available and not busy. ++ if ( rc == FO_PRINTER_GOOD ) ++ { ++ selected_uri = tmp_device_uri; ++ break; ++ } ++ // Printer is busy ++ else if (rc == FO_PRINTER_BUSY) ++ { ++ fprintf(stderr, "DEBUG: Waiting for job to complete.\n"); ++ sleep(2); ++ continue; ++ } ++ // Authorization is required to access the printer. ++ else if (rc == FO_AUTH_REQUIRED) ++ { ++ auth_failed_count++; ++ fprintf(stderr, "DEBUG: auth_failed_count = %d\n", auth_failed_count); ++ } ++ // Printer is stopped or not accepting jobs ++ else ++ { ++ if (!printer_count) ++ fprintf(stderr, "INFO: Primary Printer, %s, not available. " ++ "Attempting Failovers...\n", ++ tmp_device_uri); ++ else ++ fprintf(stderr, "INFO: Failover Printer, %s, not available. " ++ "Attempting Failovers..\n", ++ tmp_device_uri); ++ printer_count++; ++ tmp_device_uri = (char *)cupsArrayNext(printer_array); ++ } ++ } while (tmp_device_uri != NULL); ++ ++ if (selected_uri && !printer_count) ++ fprintf(stderr, "STATE: -primary-printer-failed\n"); ++ else ++ fprintf(stderr, "STATE: +primary-printer-failed\n"); ++ ++ if (job_canceled) ++ { ++ fprintf(stderr, "DEBUG: Job Canceled\n"); ++ goto cleanup; ++ } ++ ++ if (!selected_uri && auth_failed_count == printer_count) ++ { ++ fprintf(stderr, "ERROR: All failover printers failed with " ++ "authorization issues.\n"); ++ rc = CUPS_BACKEND_AUTH_REQUIRED; ++ fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required); ++ goto cleanup; ++ } ++ else if (!selected_uri && retry_count + 1 < retry_max) ++ { ++ fprintf(stderr, "INFO: No suitable printer found...retrying...\n"); ++ sleep(2); ++ continue; ++ } ++ else if (selected_uri) ++ { ++ fprintf(stderr, "DEBUG: Using printer, %s.\n", selected_uri); ++ break; ++ } ++ } ++ ++ if (!selected_uri) ++ { ++ fprintf(stderr, "ERROR: No suitable printer found. Aborting print\n"); ++ rc = CUPS_BACKEND_FAILED; ++ goto cleanup; ++ } ++ ++ rc = move_job(atoi(argv[1]), selected_uri); ++ ++ if (job_canceled) ++ rc = CUPS_BACKEND_OK; ++ ++cleanup : ++ if (job_canceled) ++ rc = CUPS_BACKEND_OK; ++ ++ tmp_device_uri = (char *)cupsArrayFirst(printer_array); ++ do ++ { ++ free((void *)tmp_device_uri); ++ } while ((tmp_device_uri = (char *)cupsArrayNext(printer_array)) != NULL); ++ ++ cupsArrayDelete(printer_array); ++ sleep(2); ++ return (rc); ++} ++ ++/* ++ * 'check_printer()' - Checks the status of a remote printer and returns ++ * back a good/bad/busy status. ++ */ ++int ++check_printer(const char *device_uri) ++{ ++ ipp_t *attributes = NULL; /* attributes for device_uri */ ++ ipp_attribute_t *tmp_attribute; /* for examining attribs */ ++ int rc = FO_PRINTER_GOOD; /* return code */ ++ char *reason; /* printer state reason */ ++ int i; ++ ++ fprintf(stderr, "DEBUG: Checking printer %s\n",device_uri); ++ ++ rc = get_printer_attributes(device_uri, &attributes); ++ if ( rc != CUPS_BACKEND_OK ) ++ { ++ fprintf(stderr, "DEBUG: Failed to get attributes from printer: %s\n", ++ device_uri); ++ if ( rc == CUPS_BACKEND_AUTH_REQUIRED ) ++ return (FO_AUTH_REQUIRED); ++ else ++ return (FO_PRINTER_BAD); ++ } ++ ++ /* ++ * Check if printer is accepting jobs ++ */ ++ if ((tmp_attribute = ippFindAttribute(attributes, ++ "printer-is-accepting-jobs", ++ IPP_TAG_BOOLEAN)) != NULL && ++ !tmp_attribute->values[0].boolean) ++ { ++ fprintf(stderr, ++ "DEBUG: Printer, %s, is not accepting jobs.\n", ++ device_uri); ++ ++ rc = FO_PRINTER_BAD; ++ } ++ ++ /* ++ * Check if printer is stopped or busy processing ++ */ ++ if ((tmp_attribute = ippFindAttribute(attributes, ++ "printer-state", ++ IPP_TAG_ENUM)) != NULL) ++ { ++ // Printer Stopped ++ if ( tmp_attribute->values[0].integer == IPP_PRINTER_STOPPED ) ++ { ++ fprintf(stderr, "DEBUG: Printer, %s, stopped.\n", device_uri); ++ rc = FO_PRINTER_BAD; ++ } ++ // Printer Busy ++ else if ( tmp_attribute->values[0].integer == IPP_PRINTER_PROCESSING ) ++ { ++ fprintf(stderr, "DEBUG: Printer %s is busy.\n", device_uri); ++ rc = FO_PRINTER_BUSY; ++ } ++ } ++ ++ /* ++ * Parse through the printer-state-reasons ++ */ ++ if ((tmp_attribute = ippFindAttribute(attributes, "printer-state-reasons", ++ IPP_TAG_KEYWORD)) != NULL) ++ { ++ for (i = 0; i < tmp_attribute->num_values; i++) ++ { ++ reason = tmp_attribute->values[i].string.text; ++ int len = strlen(reason); ++ ++ if (len > 8 && !strcmp(reason + len - 8, "-warning")) ++ { ++ fprintf(stderr, "DEBUG: Printer Supply Warning, %s\n", reason); ++ rc = FO_PRINTER_BAD; ++ } ++ else if (len > 6 && !strcmp(reason + len - 6, "-error")) ++ { ++ fprintf(stderr, "DEBUG: Printer Supply Error, %s\n", reason); ++ rc = FO_PRINTER_BAD; ++ } ++ } ++ } ++ ++ return (rc); ++} ++ ++/* ++ * 'read_config()' - Parses the failover and failover-retries options ++ * ++ */ ++static int ++read_config(cups_array_t *printer_array, int *retries, const char *options) ++{ ++ ++ const char *tmp; /* temporary ptr */ ++ char *tok_tmp; /* temporary ptr for option parsing */ ++ int jobopts_count = 0; /* number of options */ ++ cups_option_t *jobopts = NULL; /* job options */ ++ ++ ++ fprintf(stderr, "DEBUG: Reading Configuration.\n"); ++ jobopts_count = cupsParseOptions(options, 0, &jobopts); ++ ++ if (!jobopts_count) ++ { ++ fprintf(stderr, ++ "ERROR: No job options! Cannot find failover options!\n"); ++ return (CUPS_BACKEND_STOP); ++ } ++ ++ /* ++ * Get attributes from the primary printer ++ */ ++ fprintf(stderr, "DEBUG: Searching for failover option.\n"); ++ ++ if ((tmp = cupsGetOption("failover", jobopts_count, jobopts)) != NULL) ++ { ++ fprintf(stderr, "DEBUG: Failover option contents: %s.\n", tmp); ++ ++ tok_tmp = strdup(tmp); ++ ++ tmp = strtok(tok_tmp, ","); ++ do ++ { ++ cupsArrayAdd(printer_array, strdup(tmp)); ++ } while ((tmp = strtok(NULL,",")) != NULL); ++ ++ free(tok_tmp); ++ } ++ else ++ { ++ /* ++ * The queue is misconfigured, so return back CUPS_BACKEND_STOP ++ */ ++ fprintf(stderr, "ERROR: failover option not specified!\n"); ++ return (CUPS_BACKEND_STOP); ++ } ++ ++ /* ++ * Get the failover-retries value, if it exists. ++ */ ++ fprintf(stderr, "DEBUG: Searching for failover-retries option.\n"); ++ ++ if ((tmp = cupsGetOption("failover-retries", ++ jobopts_count, jobopts)) != NULL) ++ { ++ fprintf(stderr, "DEBUG: failover-retries option contents: %s.\n", tmp); ++ *retries = atoi(tmp); ++ } ++ else ++ { ++ *retries = FAILOVER_DEFAULT_RETRIES; ++ fprintf(stderr, "DEBUG: Failed to get failover-retries option\n"); ++ fprintf(stderr, "DEBUG: Defaulted to %d retries\n", *retries); ++ } ++ ++ return (CUPS_BACKEND_OK); ++} ++ ++/* ++ * 'get_printer_attributes()' - Sends an IPP Get-Attributes request to ++ * a URI ++ */ ++int ++get_printer_attributes(const char *device_uri, ipp_t **attributes) ++{ ++ char uri[HTTP_MAX_URI]; /* Updated URI without login */ ++ int version; /* IPP version */ ++ char scheme[256]; /* Scheme in URI */ ++ ipp_status_t ipp_status; /* Status of IPP request */ ++ char hostname[1024]; /* Hostname */ ++ char resource[1024]; /* Resource infoo */ ++ char addrname[256]; /* Address name */ ++ int port; /* IPP Port number */ ++ char portname[255]; /* Port as string */ ++ http_t *http; /* HTTP connection */ ++ ipp_t *request; /* IPP request */ ++ int rc = CUPS_BACKEND_OK; /* Return Code */ ++ char username[256]; /* Username for device URI */ ++ char *option_ptr; /* for parsing resource opts */ ++ const char * const pattrs[] = /* Printer attributes wanted */ ++ { ++ "printer-is-accepting-jobs", ++ "printer-state", ++ "printer-state-reasons" ++ }; ++ ++ if (job_canceled) ++ return (CUPS_BACKEND_OK); ++ ++ fprintf(stderr, "DEBUG: Getting Printer Attributes.\n"); ++ fprintf(stderr, "DEBUG: Device URL %s.\n", device_uri); ++ ++ /* ++ * Parse device_uri ++ */ ++ if (httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme), ++ username, sizeof(username), hostname, sizeof(hostname), ++ &port, resource, sizeof(resource)) != HTTP_URI_OK) ++ { ++ fprintf(stderr, "ERROR: Problem parsing device_uri, %s\n", device_uri); ++ return (CUPS_BACKEND_STOP); ++ } ++ ++ if (!port) ++ port = IPP_PORT; ++ ++ sprintf(portname, "%d", port); ++ ++ fprintf(stderr, "DEBUG: Getting Printer Attributes.\n"); ++ ++ /* ++ * Configure password ++ */ ++ cupsSetPasswordCB(password_cb); ++ ++ /* ++ * reset, in case a previous attempt for ++ * another printer left residue ++ */ ++ cupsSetUser(NULL); ++ password = NULL; ++ password_retries = 0; ++ ++ if (*username) ++ { ++ if ((password = strchr(username, ':')) != NULL) ++ { ++ *password = '\0'; ++ password++; ++ } ++ ++ cupsSetUser(username); ++ } ++ else if (!getuid()) ++ { ++ const char *username_env; ++ ++ if ((username_env = getenv("AUTH_USERNAME")) != NULL) ++ { ++ cupsSetUser(username_env); ++ password = getenv("AUTH_PASSWORD"); ++ } ++ } ++ ++ /* ++ * Try connecting to the remote server... ++ */ ++ fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port); ++ _cupsLangPuts(stderr, _("INFO: Connecting to printer...\n")); ++ ++ http = httpConnectEncrypt(hostname, port, cupsEncryption()); ++ ++ /* ++ * Deal the socket not being open. ++ */ ++ if (!http) ++ { ++ int error = errno; /* Connection error */ ++ ++ switch (error) ++ { ++ case EHOSTDOWN : ++ _cupsLangPuts(stderr, _("WARNING: " ++ "The printer may not exist or " ++ "is unavailable at this time.\n")); ++ break; ++ case EHOSTUNREACH : ++ _cupsLangPuts(stderr, _("WARNING: " ++ "The printer is unreachable at this " ++ "time.\n")); ++ break; ++ case ECONNREFUSED : ++ _cupsLangPuts(stderr, _("WARNING: " ++ "Connection Refused.\n")); ++ break; ++ default : ++ fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno)); ++ break; ++ } ++ ++ rc = CUPS_BACKEND_FAILED; ++ sleep(5); ++ goto prt_available_cleanup; ++ } ++ ++ ++#ifdef AF_INET6 ++ if (http->hostaddr->addr.sa_family == AF_INET6) ++ fprintf(stderr, "DEBUG: Connected to [%s]:%d (IPv6)...\n", ++ httpAddrString(http->hostaddr, addrname, sizeof(addrname)), ++ ntohs(http->hostaddr->ipv6.sin6_port)); ++ else ++#endif /* AF_INET6 */ ++ if (http->hostaddr->addr.sa_family == AF_INET) ++ fprintf(stderr, "DEBUG: Connected to %s:%d (IPv4)...\n", ++ httpAddrString(http->hostaddr, addrname, sizeof(addrname)), ++ ntohs(http->hostaddr->ipv4.sin_port)); ++ ++ /* ++ * Search the resource string for options. ++ * We only care about version, for the moment. ++ */ ++ version = 11; ++ ++ if ((option_ptr = strchr(resource, '?')) != NULL) ++ { ++ *option_ptr++ = '\0'; ++ ++ if ((option_ptr = strstr(option_ptr, "version="))!=NULL) ++ { ++ int minor; /* minor version from URI */ ++ int major; /* major version from URI */ ++ char *version_str; /* ipp version */ ++ ++ option_ptr += 8; ++ version_str = option_ptr; ++ ++ while (*option_ptr && *option_ptr != '&' && *option_ptr != '+') ++ option_ptr++; ++ ++ if (*option_ptr) ++ *option_ptr = '\0'; ++ ++ sscanf(version_str, "%d.%d", &major, &minor); ++ ++ version = (major * 10) + minor; ++ ++ switch(version) ++ { ++ case 10 : ++ case 11 : ++ case 20 : ++ case 21 : ++ fprintf(stderr, ++ "DEBUG: Set version to %d from URI\n", ++ version); ++ break; ++ default : ++ _cupsLangPrintf(stderr, ++ _("DEBUG: Invalid version, %d, from URI. " ++ "Using default of 1.1 \n"), ++ version); ++ version = 11; ++ } ++ } ++ } ++ ++ ++ /* ++ * Build a URI for the printer. We can't use the URI in argv[0] ++ * because it might contain username:password information... ++ */ ++ if (httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, NULL, ++ hostname, port, resource) != HTTP_URI_OK) ++ { ++ fprintf(stderr, "ERROR: Problem assembling printer URI from host %s, " ++ "port %d, resource %s\n", hostname, port, resource); ++ return (CUPS_BACKEND_STOP); ++ } ++ ++ /* ++ * Build the IPP request... ++ */ ++ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); ++ request->request.op.version[0] = version / 10; ++ request->request.op.version[1] = version % 10; ++ ++ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", ++ NULL, uri); ++ ++ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, ++ "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), ++ NULL, pattrs); ++ ++ /* ++ * Do the request... ++ */ ++ fputs("DEBUG: Getting supported attributes...\n", stderr); ++ ++ fprintf(stderr, "DEBUG: IPP Request Structure Built.\n"); ++ ++ *attributes = cupsDoRequest(http, request, resource); ++ ipp_status = cupsLastError(); ++ ++ fprintf(stderr, "DEBUG: Get-Printer-Attributes: %s (%s)\n", ++ ippErrorString(ipp_status), cupsLastErrorString()); ++ ++ if (ipp_status > IPP_OK_CONFLICT) ++ { ++ fprintf(stderr, "DEBUG: Get-Printer-Attributes returned %s.\n", ++ ippErrorString(ipp_status)); ++ switch(ipp_status) ++ { ++ case IPP_FORBIDDEN : ++ case IPP_NOT_AUTHORIZED : ++ _cupsLangPuts(stderr, _("ERROR: Not Authorized.\n")); ++ rc = CUPS_BACKEND_AUTH_REQUIRED; ++ break; ++ case IPP_PRINTER_BUSY : ++ case IPP_SERVICE_UNAVAILABLE : ++ _cupsLangPuts(stderr, _("ERROR: " ++ "The printer is not responding.\n")); ++ rc = CUPS_BACKEND_FAILED; ++ break; ++ case IPP_BAD_REQUEST : ++ case IPP_VERSION_NOT_SUPPORTED : ++ fprintf(stderr, "ERROR: Destination does not support IPP version %d\n", ++ version); ++ case IPP_NOT_FOUND : ++ _cupsLangPuts(stderr, _("ERROR: " ++ "The printer configuration is incorrect or the " ++ "printer no longer exists.\n")); ++ rc = CUPS_BACKEND_STOP; ++ break; ++ default : ++ rc = CUPS_BACKEND_FAILED; ++ } ++ goto prt_available_cleanup; ++ } ++ ++prt_available_cleanup : ++ httpClose(http); ++ return (rc); ++} ++ ++static int ++move_job(int jobid, /* Job ID */ ++ const char *dest) /* Destination ipp address */ ++{ ++ ipp_t *request; /* IPP Request */ ++ char job_uri[HTTP_MAX_URI]; /* job-uri */ ++ ++ http_t* http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); ++ ++ if (!http) ++ { ++ _cupsLangPrintf(stderr, ++ _("failover: Unable to connect to server: %s\n"), ++ strerror(errno)); ++ return (CUPS_BACKEND_FAILED); ++ } ++ ++ /* ++ * Build a CUPS_MOVE_JOB request, which requires the following ++ * attributes: ++ * ++ * job-uri/printer-uri ++ * job-printer-uri ++ * requesting-user-name ++ */ ++ ++ request = ippNewRequest(CUPS_MOVE_JOB); ++ ++ snprintf(job_uri, sizeof(job_uri), "ipp://localhost/jobs/%d", jobid); ++ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, ++ job_uri); ++ ++ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, ++ "requesting-user-name", ++ NULL, cupsUser()); ++ ++ ippAddString(request, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", ++ NULL, dest); ++ ++ /* ++ * Do the request and get back a response... ++ */ ++ ++ ippDelete(cupsDoRequest(http, request, "/jobs")); ++ ++ httpClose(http); ++ ++ if (cupsLastError() > IPP_OK_CONFLICT) ++ { ++ _cupsLangPrintf(stderr, "failover: %s\n", cupsLastErrorString()); ++ return (CUPS_BACKEND_FAILED); ++ } ++ else ++ return (CUPS_BACKEND_OK); ++} ++ ++/* ++ * 'sigterm_handler()' - handles a sigterm, i.e. job canceled ++ */ ++static void ++sigterm_handler(int sig) ++{ ++ if (!job_canceled) ++ { ++ write(2, "DEBUG: Got SIGTERM.\n", 20); ++ job_canceled = 1; ++ } ++ else ++ { ++ /* ++ * Job has already been canceled, so just exit ++ */ ++ exit(1); ++ } ++} ++ ++/* ++ * 'password_cb()' - Disable the password prompt for cupsDoFileRequest(). ++ */ ++static const char * /* O - Password */ ++password_cb(const char *prompt) /* I - Prompt (not used) */ ++{ ++ auth_info_required = "username,password"; ++ password_retries++; ++ ++ if(password_retries < FAILOVER_PASSWORD_RETRIES_MAX) ++ return (password); ++ else ++ return (NULL); ++} diff --git a/SOURCES/cups-memory-consumption.patch b/SOURCES/cups-memory-consumption.patch new file mode 100644 index 0000000..5ccfbba --- /dev/null +++ b/SOURCES/cups-memory-consumption.patch @@ -0,0 +1,1220 @@ +diff --git a/cups/ppd-cache.c b/cups/ppd-cache.c +index 925ab80..e5f89ee 100644 +--- a/cups/ppd-cache.c ++++ b/cups/ppd-cache.c +@@ -508,24 +508,20 @@ _ppdCacheCreateWithFile( + else if (!_cups_strcasecmp(line, "Filter")) + { + if (!pc->filters) +- pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0, +- (cups_acopy_func_t)_cupsStrAlloc, +- (cups_afree_func_t)_cupsStrFree); ++ pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); + + cupsArrayAdd(pc->filters, value); + } + else if (!_cups_strcasecmp(line, "PreFilter")) + { + if (!pc->prefilters) +- pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0, +- (cups_acopy_func_t)_cupsStrAlloc, +- (cups_afree_func_t)_cupsStrFree); ++ pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); + + cupsArrayAdd(pc->prefilters, value); + } + else if (!_cups_strcasecmp(line, "Product")) + { +- pc->product = _cupsStrAlloc(value); ++ pc->product = strdup(value); + } + else if (!_cups_strcasecmp(line, "SingleFile")) + { +@@ -625,8 +621,8 @@ _ppdCacheCreateWithFile( + } + + map = pc->bins + pc->num_bins; +- map->pwg = _cupsStrAlloc(pwg_keyword); +- map->ppd = _cupsStrAlloc(ppd_keyword); ++ map->pwg = strdup(pwg_keyword); ++ map->ppd = strdup(ppd_keyword); + + pc->num_bins ++; + } +@@ -680,8 +676,8 @@ _ppdCacheCreateWithFile( + goto create_error; + } + +- size->map.pwg = _cupsStrAlloc(pwg_keyword); +- size->map.ppd = _cupsStrAlloc(ppd_keyword); ++ size->map.pwg = strdup(pwg_keyword); ++ size->map.ppd = strdup(ppd_keyword); + + pc->num_sizes ++; + } +@@ -709,15 +705,15 @@ _ppdCacheCreateWithFile( + + pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "max", + pc->custom_max_width, pc->custom_max_length, NULL); +- pc->custom_max_keyword = _cupsStrAlloc(pwg_keyword); ++ pc->custom_max_keyword = strdup(pwg_keyword); + + pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "min", + pc->custom_min_width, pc->custom_min_length, NULL); +- pc->custom_min_keyword = _cupsStrAlloc(pwg_keyword); ++ pc->custom_min_keyword = strdup(pwg_keyword); + } + else if (!_cups_strcasecmp(line, "SourceOption")) + { +- pc->source_option = _cupsStrAlloc(value); ++ pc->source_option = strdup(value); + } + else if (!_cups_strcasecmp(line, "NumSources")) + { +@@ -764,8 +760,8 @@ _ppdCacheCreateWithFile( + } + + map = pc->sources + pc->num_sources; +- map->pwg = _cupsStrAlloc(pwg_keyword); +- map->ppd = _cupsStrAlloc(ppd_keyword); ++ map->pwg = strdup(pwg_keyword); ++ map->ppd = strdup(ppd_keyword); + + pc->num_sources ++; + } +@@ -813,8 +809,8 @@ _ppdCacheCreateWithFile( + } + + map = pc->types + pc->num_types; +- map->pwg = _cupsStrAlloc(pwg_keyword); +- map->ppd = _cupsStrAlloc(ppd_keyword); ++ map->pwg = strdup(pwg_keyword); ++ map->ppd = strdup(ppd_keyword); + + pc->num_types ++; + } +@@ -844,13 +840,13 @@ _ppdCacheCreateWithFile( + pc->presets[print_color_mode] + print_quality); + } + else if (!_cups_strcasecmp(line, "SidesOption")) +- pc->sides_option = _cupsStrAlloc(value); ++ pc->sides_option = strdup(value); + else if (!_cups_strcasecmp(line, "Sides1Sided")) +- pc->sides_1sided = _cupsStrAlloc(value); ++ pc->sides_1sided = strdup(value); + else if (!_cups_strcasecmp(line, "Sides2SidedLong")) +- pc->sides_2sided_long = _cupsStrAlloc(value); ++ pc->sides_2sided_long = strdup(value); + else if (!_cups_strcasecmp(line, "Sides2SidedShort")) +- pc->sides_2sided_short = _cupsStrAlloc(value); ++ pc->sides_2sided_short = strdup(value); + else if (!_cups_strcasecmp(line, "Finishings")) + { + if (!pc->finishings) +@@ -871,13 +867,13 @@ _ppdCacheCreateWithFile( + else if (!_cups_strcasecmp(line, "MaxCopies")) + pc->max_copies = atoi(value); + else if (!_cups_strcasecmp(line, "ChargeInfoURI")) +- pc->charge_info_uri = _cupsStrAlloc(value); ++ pc->charge_info_uri = strdup(value); + else if (!_cups_strcasecmp(line, "JobAccountId")) + pc->account_id = !_cups_strcasecmp(value, "true"); + else if (!_cups_strcasecmp(line, "JobAccountingUserId")) + pc->accounting_user_id = !_cups_strcasecmp(value, "true"); + else if (!_cups_strcasecmp(line, "JobPassword")) +- pc->password = _cupsStrAlloc(value); ++ pc->password = strdup(value); + else if (!_cups_strcasecmp(line, "Mandatory")) + { + if (pc->mandatory) +@@ -888,9 +884,7 @@ _ppdCacheCreateWithFile( + else if (!_cups_strcasecmp(line, "SupportFile")) + { + if (!pc->support_files) +- pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0, +- (cups_acopy_func_t)_cupsStrAlloc, +- (cups_afree_func_t)_cupsStrFree); ++ pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); + + cupsArrayAdd(pc->support_files, value); + } +@@ -1130,8 +1124,8 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + */ + + new_size = old_size; +- _cupsStrFree(old_size->map.ppd); +- _cupsStrFree(old_size->map.pwg); ++ free(old_size->map.ppd); ++ free(old_size->map.pwg); + } + } + +@@ -1152,8 +1146,8 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + * Save this size... + */ + +- new_size->map.ppd = _cupsStrAlloc(ppd_size->name); +- new_size->map.pwg = _cupsStrAlloc(pwg_name); ++ new_size->map.ppd = strdup(ppd_size->name); ++ new_size->map.pwg = strdup(pwg_name); + new_size->width = new_width; + new_size->length = new_length; + new_size->left = new_left; +@@ -1173,14 +1167,14 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "max", + PWG_FROM_POINTS(ppd->custom_max[0]), + PWG_FROM_POINTS(ppd->custom_max[1]), NULL); +- pc->custom_max_keyword = _cupsStrAlloc(pwg_keyword); ++ pc->custom_max_keyword = strdup(pwg_keyword); + pc->custom_max_width = PWG_FROM_POINTS(ppd->custom_max[0]); + pc->custom_max_length = PWG_FROM_POINTS(ppd->custom_max[1]); + + pwgFormatSizeName(pwg_keyword, sizeof(pwg_keyword), "custom", "min", + PWG_FROM_POINTS(ppd->custom_min[0]), + PWG_FROM_POINTS(ppd->custom_min[1]), NULL); +- pc->custom_min_keyword = _cupsStrAlloc(pwg_keyword); ++ pc->custom_min_keyword = strdup(pwg_keyword); + pc->custom_min_width = PWG_FROM_POINTS(ppd->custom_min[0]); + pc->custom_min_length = PWG_FROM_POINTS(ppd->custom_min[1]); + +@@ -1199,7 +1193,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + + if (input_slot) + { +- pc->source_option = _cupsStrAlloc(input_slot->keyword); ++ pc->source_option = strdup(input_slot->keyword); + + if ((pc->sources = calloc((size_t)input_slot->num_choices, sizeof(pwg_map_t))) == NULL) + { +@@ -1251,8 +1245,8 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + "_"); + } + +- map->pwg = _cupsStrAlloc(pwg_name); +- map->ppd = _cupsStrAlloc(choice->choice); ++ map->pwg = strdup(pwg_name); ++ map->ppd = strdup(choice->choice); + } + } + +@@ -1315,8 +1309,8 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + "_"); + } + +- map->pwg = _cupsStrAlloc(pwg_name); +- map->ppd = _cupsStrAlloc(choice->choice); ++ map->pwg = strdup(pwg_name); ++ map->ppd = strdup(choice->choice); + } + } + +@@ -1342,8 +1336,8 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + { + pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword), "_"); + +- map->pwg = _cupsStrAlloc(pwg_keyword); +- map->ppd = _cupsStrAlloc(choice->choice); ++ map->pwg = strdup(pwg_keyword); ++ map->ppd = strdup(choice->choice); + } + } + +@@ -1558,7 +1552,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + + if (duplex) + { +- pc->sides_option = _cupsStrAlloc(duplex->keyword); ++ pc->sides_option = strdup(duplex->keyword); + + for (i = duplex->num_choices, choice = duplex->choices; + i > 0; +@@ -1566,16 +1560,16 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + { + if ((!_cups_strcasecmp(choice->choice, "None") || + !_cups_strcasecmp(choice->choice, "False")) && !pc->sides_1sided) +- pc->sides_1sided = _cupsStrAlloc(choice->choice); ++ pc->sides_1sided = strdup(choice->choice); + else if ((!_cups_strcasecmp(choice->choice, "DuplexNoTumble") || + !_cups_strcasecmp(choice->choice, "LongEdge") || + !_cups_strcasecmp(choice->choice, "Top")) && !pc->sides_2sided_long) +- pc->sides_2sided_long = _cupsStrAlloc(choice->choice); ++ pc->sides_2sided_long = strdup(choice->choice); + else if ((!_cups_strcasecmp(choice->choice, "DuplexTumble") || + !_cups_strcasecmp(choice->choice, "ShortEdge") || + !_cups_strcasecmp(choice->choice, "Bottom")) && + !pc->sides_2sided_short) +- pc->sides_2sided_short = _cupsStrAlloc(choice->choice); ++ pc->sides_2sided_short = strdup(choice->choice); + } + } + +@@ -1583,9 +1577,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + * Copy filters and pre-filters... + */ + +- pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0, +- (cups_acopy_func_t)_cupsStrAlloc, +- (cups_afree_func_t)_cupsStrFree); ++ pc->filters = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); + + cupsArrayAdd(pc->filters, + "application/vnd.cups-raw application/octet-stream 0 -"); +@@ -1642,9 +1634,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + + if ((ppd_attr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL) + { +- pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0, +- (cups_acopy_func_t)_cupsStrAlloc, +- (cups_afree_func_t)_cupsStrFree); ++ pc->prefilters = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); + + do + { +@@ -1661,7 +1651,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + */ + + if (ppd->product) +- pc->product = _cupsStrAlloc(ppd->product); ++ pc->product = strdup(ppd->product); + + /* + * Copy finishings mapping data... +@@ -1818,7 +1808,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + */ + + if ((ppd_attr = ppdFindAttr(ppd, "cupsChargeInfoURI", NULL)) != NULL) +- pc->charge_info_uri = _cupsStrAlloc(ppd_attr->value); ++ pc->charge_info_uri = strdup(ppd_attr->value); + + if ((ppd_attr = ppdFindAttr(ppd, "cupsJobAccountId", NULL)) != NULL) + pc->account_id = !_cups_strcasecmp(ppd_attr->value, "true"); +@@ -1827,7 +1817,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + pc->accounting_user_id = !_cups_strcasecmp(ppd_attr->value, "true"); + + if ((ppd_attr = ppdFindAttr(ppd, "cupsJobPassword", NULL)) != NULL) +- pc->password = _cupsStrAlloc(ppd_attr->value); ++ pc->password = strdup(ppd_attr->value); + + if ((ppd_attr = ppdFindAttr(ppd, "cupsMandatory", NULL)) != NULL) + pc->mandatory = _cupsArrayNewStrings(ppd_attr->value, ' '); +@@ -1836,9 +1826,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ + * Support files... + */ + +- pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0, +- (cups_acopy_func_t)_cupsStrAlloc, +- (cups_afree_func_t)_cupsStrFree); ++ pc->support_files = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free); + + for (ppd_attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); + ppd_attr; +@@ -1894,8 +1882,8 @@ _ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */ + { + for (i = pc->num_bins, map = pc->bins; i > 0; i --, map ++) + { +- _cupsStrFree(map->pwg); +- _cupsStrFree(map->ppd); ++ free(map->pwg); ++ free(map->ppd); + } + + free(pc->bins); +@@ -1905,15 +1893,14 @@ _ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */ + { + for (i = pc->num_sizes, size = pc->sizes; i > 0; i --, size ++) + { +- _cupsStrFree(size->map.pwg); +- _cupsStrFree(size->map.ppd); ++ free(size->map.pwg); ++ free(size->map.ppd); + } + + free(pc->sizes); + } + +- if (pc->source_option) +- _cupsStrFree(pc->source_option); ++ free(pc->source_option); + + if (pc->sources) + { +@@ -1930,26 +1917,23 @@ _ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */ + { + for (i = pc->num_types, map = pc->types; i > 0; i --, map ++) + { +- _cupsStrFree(map->pwg); +- _cupsStrFree(map->ppd); ++ free(map->pwg); ++ free(map->ppd); + } + + free(pc->types); + } + +- if (pc->custom_max_keyword) +- _cupsStrFree(pc->custom_max_keyword); +- +- if (pc->custom_min_keyword) +- _cupsStrFree(pc->custom_min_keyword); ++ free(pc->custom_max_keyword); ++ free(pc->custom_min_keyword); + +- _cupsStrFree(pc->product); ++ free(pc->product); + cupsArrayDelete(pc->filters); + cupsArrayDelete(pc->prefilters); + cupsArrayDelete(pc->finishings); + +- _cupsStrFree(pc->charge_info_uri); +- _cupsStrFree(pc->password); ++ free(pc->charge_info_uri); ++ free(pc->password); + + cupsArrayDelete(pc->mandatory); + +diff --git a/cups/ppd-mark.c b/cups/ppd-mark.c +index 464c09a..cb67468 100644 +--- a/cups/ppd-mark.c ++++ b/cups/ppd-mark.c +@@ -890,9 +890,9 @@ ppd_mark_option(ppd_file_t *ppd, /* I - PPD file */ + case PPD_CUSTOM_PASSWORD : + case PPD_CUSTOM_STRING : + if (cparam->current.custom_string) +- _cupsStrFree(cparam->current.custom_string); ++ free(cparam->current.custom_string); + +- cparam->current.custom_string = _cupsStrAlloc(choice + 7); ++ cparam->current.custom_string = strdup(choice + 7); + break; + } + } +@@ -967,9 +967,9 @@ ppd_mark_option(ppd_file_t *ppd, /* I - PPD file */ + case PPD_CUSTOM_PASSWORD : + case PPD_CUSTOM_STRING : + if (cparam->current.custom_string) +- _cupsStrFree(cparam->current.custom_string); ++ free(cparam->current.custom_string); + +- cparam->current.custom_string = _cupsStrRetain(val->value); ++ cparam->current.custom_string = strdup(val->value); + break; + } + } +diff --git a/cups/ppd.c b/cups/ppd.c +index 8276988..6782a85 100644 +--- a/cups/ppd.c ++++ b/cups/ppd.c +@@ -34,8 +34,6 @@ + * Definitions... + */ + +-#define ppd_free(p) if (p) free(p) /* Safe free macro */ +- + #define PPD_KEYWORD 1 /* Line contained a keyword */ + #define PPD_OPTION 2 /* Line contained an option name */ + #define PPD_TEXT 4 /* Line contained human-readable text */ +@@ -117,7 +115,6 @@ void + ppdClose(ppd_file_t *ppd) /* I - PPD file record */ + { + int i; /* Looping var */ +- ppd_emul_t *emul; /* Current emulation */ + ppd_group_t *group; /* Current group */ + char **font; /* Current font */ + ppd_attr_t **attr; /* Current attribute */ +@@ -136,28 +133,12 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ + * Free all strings at the top level... + */ + +- _cupsStrFree(ppd->lang_encoding); +- _cupsStrFree(ppd->nickname); +- if (ppd->patches) +- free(ppd->patches); +- _cupsStrFree(ppd->jcl_begin); +- _cupsStrFree(ppd->jcl_end); +- _cupsStrFree(ppd->jcl_ps); +- +- /* +- * Free any emulations... +- */ +- +- if (ppd->num_emulations > 0) +- { +- for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++) +- { +- _cupsStrFree(emul->start); +- _cupsStrFree(emul->stop); +- } +- +- ppd_free(ppd->emulations); +- } ++ free(ppd->lang_encoding); ++ free(ppd->nickname); ++ free(ppd->patches); ++ free(ppd->jcl_begin); ++ free(ppd->jcl_end); ++ free(ppd->jcl_ps); + + /* + * Free any UI groups, subgroups, and options... +@@ -168,7 +149,7 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ + for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) + ppd_free_group(group); + +- ppd_free(ppd->groups); ++ free(ppd->groups); + } + + cupsArrayDelete(ppd->options); +@@ -179,14 +160,14 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ + */ + + if (ppd->num_sizes > 0) +- ppd_free(ppd->sizes); ++ free(ppd->sizes); + + /* + * Free any constraints... + */ + + if (ppd->num_consts > 0) +- ppd_free(ppd->consts); ++ free(ppd->consts); + + /* + * Free any filters... +@@ -201,9 +182,9 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ + if (ppd->num_fonts > 0) + { + for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++) +- _cupsStrFree(*font); ++ free(*font); + +- ppd_free(ppd->fonts); ++ free(ppd->fonts); + } + + /* +@@ -211,7 +192,7 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ + */ + + if (ppd->num_profiles > 0) +- ppd_free(ppd->profiles); ++ free(ppd->profiles); + + /* + * Free any attributes... +@@ -221,11 +202,11 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ + { + for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++) + { +- _cupsStrFree((*attr)->value); +- ppd_free(*attr); ++ free((*attr)->value); ++ free(*attr); + } + +- ppd_free(ppd->attrs); ++ free(ppd->attrs); + } + + cupsArrayDelete(ppd->sorted_attrs); +@@ -247,7 +228,7 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ + case PPD_CUSTOM_PASSCODE : + case PPD_CUSTOM_PASSWORD : + case PPD_CUSTOM_STRING : +- _cupsStrFree(cparam->current.custom_string); ++ free(cparam->current.custom_string); + break; + + default : +@@ -295,7 +276,7 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ + * Free the whole record... + */ + +- ppd_free(ppd); ++ free(ppd); + } + + +@@ -441,7 +422,6 @@ _ppdOpen( + _ppd_localization_t localization) /* I - Localization to load */ + { + int i, j, k; /* Looping vars */ +- int count; /* Temporary count */ + _ppd_line_t line; /* Line buffer */ + ppd_file_t *ppd; /* PPD file record */ + ppd_group_t *group, /* Current group */ +@@ -459,7 +439,6 @@ _ppdOpen( + /* Human-readable text from file */ + *string, /* Code/text from file */ + *sptr, /* Pointer into string */ +- *nameptr, /* Pointer into name */ + *temp, /* Temporary string pointer */ + **tempfonts; /* Temporary fonts pointer */ + float order; /* Order dependency number */ +@@ -633,16 +612,14 @@ _ppdOpen( + if (pg->ppd_status == PPD_OK) + pg->ppd_status = PPD_MISSING_PPDADOBE4; + +- _cupsStrFree(string); +- ppd_free(line.buffer); ++ free(string); ++ free(line.buffer); + + return (NULL); + } + + DEBUG_printf(("2_ppdOpen: keyword=%s, string=%p", keyword, string)); + +- _cupsStrFree(string); +- + /* + * Allocate memory for the PPD file record... + */ +@@ -651,12 +628,15 @@ _ppdOpen( + { + pg->ppd_status = PPD_ALLOC_ERROR; + +- _cupsStrFree(string); +- ppd_free(line.buffer); ++ free(string); ++ free(line.buffer); + + return (NULL); + } + ++ free(string); ++ string = NULL; ++ + ppd->language_level = 2; + ppd->color_device = 0; + ppd->colorspace = PPD_CS_N; +@@ -735,6 +715,8 @@ _ppdOpen( + strncmp(ll, keyword, ll_len))) + { + DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword)); ++ free(string); ++ string = NULL; + continue; + } + else if (localization == _PPD_LOCALIZATION_ICC_PROFILES) +@@ -754,6 +736,8 @@ _ppdOpen( + if (i >= (int)(sizeof(color_keywords) / sizeof(color_keywords[0]))) + { + DEBUG_printf(("2_ppdOpen: Ignoring localization: \"%s\"\n", keyword)); ++ free(string); ++ string = NULL; + continue; + } + } +@@ -849,7 +833,7 @@ _ppdOpen( + * Say all PPD files are UTF-8, since we convert to UTF-8... + */ + +- ppd->lang_encoding = _cupsStrAlloc("UTF-8"); ++ ppd->lang_encoding = strdup("UTF-8"); + encoding = _ppdGetEncoding(string); + } + else if (!strcmp(keyword, "LanguageVersion")) +@@ -870,10 +854,10 @@ _ppdOpen( + + + cupsCharsetToUTF8(utf8, string, sizeof(utf8), encoding); +- ppd->nickname = _cupsStrAlloc((char *)utf8); ++ ppd->nickname = strdup((char *)utf8); + } + else +- ppd->nickname = _cupsStrAlloc(string); ++ ppd->nickname = strdup(string); + } + else if (!strcmp(keyword, "Product")) + ppd->product = string; +@@ -883,17 +867,17 @@ _ppdOpen( + ppd->ttrasterizer = string; + else if (!strcmp(keyword, "JCLBegin")) + { +- ppd->jcl_begin = _cupsStrAlloc(string); ++ ppd->jcl_begin = strdup(string); + ppd_decode(ppd->jcl_begin); /* Decode quoted string */ + } + else if (!strcmp(keyword, "JCLEnd")) + { +- ppd->jcl_end = _cupsStrAlloc(string); ++ ppd->jcl_end = strdup(string); + ppd_decode(ppd->jcl_end); /* Decode quoted string */ + } + else if (!strcmp(keyword, "JCLToPSInterpreter")) + { +- ppd->jcl_ps = _cupsStrAlloc(string); ++ ppd->jcl_ps = strdup(string); + ppd_decode(ppd->jcl_ps); /* Decode quoted string */ + } + else if (!strcmp(keyword, "AccurateScreensSupport")) +@@ -961,10 +945,10 @@ _ppdOpen( + ppd->num_filters ++; + + /* +- * Retain a copy of the filter string... ++ * Make a copy of the filter string... + */ + +- *filter = _cupsStrRetain(string); ++ *filter = strdup(string); + } + else if (!strcmp(keyword, "Throughput")) + ppd->throughput = atoi(string); +@@ -987,7 +971,7 @@ _ppdOpen( + } + + ppd->fonts = tempfonts; +- ppd->fonts[ppd->num_fonts] = _cupsStrAlloc(name); ++ ppd->fonts[ppd->num_fonts] = strdup(name); + ppd->num_fonts ++; + } + else if (!strncmp(keyword, "ParamCustom", 11)) +@@ -1152,7 +1136,7 @@ _ppdOpen( + strlcpy(choice->text, text[0] ? text : _("Custom"), + sizeof(choice->text)); + +- choice->code = _cupsStrAlloc(string); ++ choice->code = strdup(string); + + if (custom_option->section == PPD_ORDER_JCL) + ppd_decode(choice->code); +@@ -1201,59 +1185,23 @@ _ppdOpen( + else if (!strcmp(string, "Plus90")) + ppd->landscape = 90; + } +- else if (!strcmp(keyword, "Emulators") && string) +- { +- for (count = 1, sptr = string; sptr != NULL;) +- if ((sptr = strchr(sptr, ' ')) != NULL) +- { +- count ++; +- while (*sptr == ' ') +- sptr ++; +- } +- +- ppd->num_emulations = count; +- if ((ppd->emulations = calloc((size_t)count, sizeof(ppd_emul_t))) == NULL) +- { +- pg->ppd_status = PPD_ALLOC_ERROR; +- +- goto error; +- } +- +- for (i = 0, sptr = string; i < count; i ++) +- { +- for (nameptr = ppd->emulations[i].name; +- *sptr != '\0' && *sptr != ' '; +- sptr ++) +- if (nameptr < (ppd->emulations[i].name + sizeof(ppd->emulations[i].name) - 1)) +- *nameptr++ = *sptr; +- +- *nameptr = '\0'; +- +- while (*sptr == ' ') +- sptr ++; +- } +- } +- else if (!strncmp(keyword, "StartEmulator_", 14)) ++ else if (!strcmp(keyword, "Emulators") && string && ppd->num_emulations == 0) + { +- ppd_decode(string); ++ /* ++ * Issue #5562: Samsung printer drivers incorrectly use Emulators keyword ++ * to configure themselves ++ * ++ * The Emulators keyword was loaded but never used by anything in CUPS, ++ * and has no valid purpose in CUPS. The old code was removed due to a ++ * memory leak (Issue #5475), so the following (new) code supports a single ++ * name for the Emulators keyword, allowing these drivers to work until we ++ * remove PPD and driver support entirely in a future version of CUPS. ++ */ + +- for (i = 0; i < ppd->num_emulations; i ++) +- if (!strcmp(keyword + 14, ppd->emulations[i].name)) +- { +- ppd->emulations[i].start = string; +- string = NULL; +- } +- } +- else if (!strncmp(keyword, "StopEmulator_", 13)) +- { +- ppd_decode(string); ++ ppd->num_emulations = 1; ++ ppd->emulations = calloc(1, sizeof(ppd_emul_t)); + +- for (i = 0; i < ppd->num_emulations; i ++) +- if (!strcmp(keyword + 13, ppd->emulations[i].name)) +- { +- ppd->emulations[i].stop = string; +- string = NULL; +- } ++ strlcpy(ppd->emulations[0].name, string, sizeof(ppd->emulations[0].name)); + } + else if (!strcmp(keyword, "JobPatchFile")) + { +@@ -1408,7 +1356,7 @@ _ppdOpen( + + option->section = PPD_ORDER_ANY; + +- _cupsStrFree(string); ++ free(string); + string = NULL; + + /* +@@ -1436,7 +1384,7 @@ _ppdOpen( + strlcpy(choice->text, + custom_attr->text[0] ? custom_attr->text : _("Custom"), + sizeof(choice->text)); +- choice->code = _cupsStrRetain(custom_attr->value); ++ choice->code = strdup(custom_attr->value); + } + } + else if (!strcmp(keyword, "JCLOpenUI")) +@@ -1515,7 +1463,7 @@ _ppdOpen( + option->section = PPD_ORDER_JCL; + group = NULL; + +- _cupsStrFree(string); ++ free(string); + string = NULL; + + /* +@@ -1539,14 +1487,14 @@ _ppdOpen( + strlcpy(choice->text, + custom_attr->text[0] ? custom_attr->text : _("Custom"), + sizeof(choice->text)); +- choice->code = _cupsStrRetain(custom_attr->value); ++ choice->code = strdup(custom_attr->value); + } + } + else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI")) + { + option = NULL; + +- _cupsStrFree(string); ++ free(string); + string = NULL; + } + else if (!strcmp(keyword, "OpenGroup")) +@@ -1593,14 +1541,14 @@ _ppdOpen( + if (group == NULL) + goto error; + +- _cupsStrFree(string); ++ free(string); + string = NULL; + } + else if (!strcmp(keyword, "CloseGroup")) + { + group = NULL; + +- _cupsStrFree(string); ++ free(string); + string = NULL; + } + else if (!strcmp(keyword, "OrderDependency")) +@@ -1658,7 +1606,7 @@ _ppdOpen( + option->order = order; + } + +- _cupsStrFree(string); ++ free(string); + string = NULL; + } + else if (!strncmp(keyword, "Default", 7)) +@@ -1901,7 +1849,7 @@ _ppdOpen( + * Don't add this one as an attribute... + */ + +- _cupsStrFree(string); ++ free(string); + string = NULL; + } + else if (!strcmp(keyword, "PaperDimension")) +@@ -1923,7 +1871,7 @@ _ppdOpen( + size->width = (float)_cupsStrScand(string, &sptr, loc); + size->length = (float)_cupsStrScand(sptr, NULL, loc); + +- _cupsStrFree(string); ++ free(string); + string = NULL; + } + else if (!strcmp(keyword, "ImageableArea")) +@@ -1947,7 +1895,7 @@ _ppdOpen( + size->right = (float)_cupsStrScand(sptr, &sptr, loc); + size->top = (float)_cupsStrScand(sptr, NULL, loc); + +- _cupsStrFree(string); ++ free(string); + string = NULL; + } + else if (option != NULL && +@@ -2003,7 +1951,7 @@ _ppdOpen( + (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING)) + ppd_add_attr(ppd, keyword, name, text, string); + else +- _cupsStrFree(string); ++ free(string); + } + + /* +@@ -2016,7 +1964,8 @@ _ppdOpen( + goto error; + } + +- ppd_free(line.buffer); ++ free(string); ++ free(line.buffer); + + /* + * Reset language preferences... +@@ -2098,8 +2047,8 @@ _ppdOpen( + + error: + +- _cupsStrFree(string); +- ppd_free(line.buffer); ++ free(string); ++ free(line.buffer); + + ppdClose(ppd); + +@@ -2537,9 +2486,9 @@ ppd_free_filters(ppd_file_t *ppd) /* I - PPD file */ + if (ppd->num_filters > 0) + { + for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++) +- _cupsStrFree(*filter); ++ free(*filter); + +- ppd_free(ppd->filters); ++ free(ppd->filters); + + ppd->num_filters = 0; + ppd->filters = NULL; +@@ -2566,7 +2515,7 @@ ppd_free_group(ppd_group_t *group) /* I - Group to free */ + i --, option ++) + ppd_free_option(option); + +- ppd_free(group->options); ++ free(group->options); + } + + if (group->num_subgroups > 0) +@@ -2576,7 +2525,7 @@ ppd_free_group(ppd_group_t *group) /* I - Group to free */ + i --, subgroup ++) + ppd_free_group(subgroup); + +- ppd_free(group->subgroups); ++ free(group->subgroups); + } + } + +@@ -2598,10 +2547,10 @@ ppd_free_option(ppd_option_t *option) /* I - Option to free */ + i > 0; + i --, choice ++) + { +- _cupsStrFree(choice->code); ++ free(choice->code); + } + +- ppd_free(option->choices); ++ free(option->choices); + } + } + +@@ -3338,7 +3287,7 @@ ppd_read(cups_file_t *fp, /* I - File to read from */ + lineptr ++; + } + +- *string = _cupsStrAlloc(lineptr); ++ *string = strdup(lineptr); + + mask |= PPD_STRING; + } +@@ -3460,7 +3409,7 @@ ppd_update_filters(ppd_file_t *ppd, /* I - PPD file */ + filter += ppd->num_filters; + ppd->num_filters ++; + +- *filter = _cupsStrAlloc(buffer); ++ *filter = strdup(buffer); + } + while ((attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL); + +diff --git a/cups/ppd.h b/cups/ppd.h +index fb33c08..1c852c7 100644 +--- a/cups/ppd.h ++++ b/cups/ppd.h +@@ -302,8 +302,8 @@ typedef struct ppd_file_s /**** PPD File ****/ + int throughput; /* Pages per minute */ + ppd_cs_t colorspace; /* Default colorspace */ + char *patches; /* Patch commands to be sent to printer */ +- int num_emulations; /* Number of emulations supported */ +- ppd_emul_t *emulations; /* Emulations and the code to invoke them */ ++ int num_emulations; /* Number of emulations supported (no longer supported) @private@ */ ++ ppd_emul_t *emulations; /* Emulations and the code to invoke them (no longer supported) @private@ */ + char *jcl_begin; /* Start JCL commands */ + char *jcl_ps; /* Enter PostScript interpreter */ + char *jcl_end; /* End JCL commands */ +diff --git a/cups/string.c b/cups/string.c +index 0d4ed0f..8f37caf 100644 +--- a/cups/string.c ++++ b/cups/string.c +@@ -316,6 +316,13 @@ _cupsStrFree(const char *s) /* I - String to free */ + + key = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str)); + ++ if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL && ++ item == key) ++ { ++ /* ++ * Found it, dereference... ++ */ ++ + #ifdef DEBUG_GUARDS + if (key->guard != _CUPS_STR_GUARD) + { +@@ -325,13 +332,6 @@ _cupsStrFree(const char *s) /* I - String to free */ + } + #endif /* DEBUG_GUARDS */ + +- if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL && +- item == key) +- { +- /* +- * Found it, dereference... +- */ +- + item->ref_count --; + + if (!item->ref_count) +diff --git a/scheduler/ipp.c b/scheduler/ipp.c +index 298b684..e0dbc4a 100644 +--- a/scheduler/ipp.c ++++ b/scheduler/ipp.c +@@ -2918,8 +2918,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ + if (!strcmp(attr->values[i].string.text, "none")) + continue; + +- printer->reasons[printer->num_reasons] = +- _cupsStrRetain(attr->values[i].string.text); ++ printer->reasons[printer->num_reasons] = _cupsStrAlloc(attr->values[i].string.text); + printer->num_reasons ++; + + if (!strcmp(attr->values[i].string.text, "paused") && +@@ -5437,8 +5436,7 @@ copy_printer_attrs( + + if ((p2_uri = ippFindAttribute(p2->attrs, "printer-uri-supported", + IPP_TAG_URI)) != NULL) +- member_uris->values[i].string.text = +- _cupsStrRetain(p2_uri->values[0].string.text); ++ member_uris->values[i].string.text = _cupsStrAlloc(p2_uri->values[0].string.text); + else + { + httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, +diff --git a/scheduler/printers.c b/scheduler/printers.c +index 3ec16cf..f16552e 100644 +--- a/scheduler/printers.c ++++ b/scheduler/printers.c +@@ -54,8 +54,7 @@ static int compare_printers(void *first, void *second, void *data); + static void delete_printer_filters(cupsd_printer_t *p); + static void dirty_printer(cupsd_printer_t *p); + static void load_ppd(cupsd_printer_t *p); +-static ipp_t *new_media_col(pwg_size_t *size, const char *source, +- const char *type); ++static ipp_t *new_media_col(pwg_size_t *size); + static void write_xml_string(cups_file_t *fp, const char *s); + + +@@ -3873,21 +3872,19 @@ dirty_printer(cupsd_printer_t *p) /* I - Printer */ + static void + load_ppd(cupsd_printer_t *p) /* I - Printer */ + { +- int i, j, k; /* Looping vars */ ++ int i, j; /* Looping vars */ + char cache_name[1024]; /* Cache filename */ + struct stat cache_info; /* Cache file info */ + ppd_file_t *ppd; /* PPD file */ + char ppd_name[1024]; /* PPD filename */ + struct stat ppd_info; /* PPD file info */ +- int num_media; /* Number of media options */ ++ int num_media; /* Number of media values */ + ppd_size_t *size; /* Current PPD size */ + ppd_option_t *duplex, /* Duplex option */ + *output_bin, /* OutputBin option */ + *output_mode, /* OutputMode option */ + *resolution; /* (Set|JCL|)Resolution option */ +- ppd_choice_t *choice, /* Current PPD choice */ +- *input_slot, /* Current input slot */ +- *media_type; /* Current media type */ ++ ppd_choice_t *choice; /* Current PPD choice */ + ppd_attr_t *ppd_attr; /* PPD attribute */ + int xdpi, /* Horizontal resolution */ + ydpi; /* Vertical resolution */ +@@ -4147,18 +4144,7 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ + { + ipp_t *col; /* Collection value */ + +- input_slot = ppdFindMarkedChoice(ppd, "InputSlot"); +- media_type = ppdFindMarkedChoice(ppd, "MediaType"); +- col = new_media_col(pwgsize, +- input_slot ? +- _ppdCacheGetSource(p->pc, +- input_slot->choice) : +- NULL, +- media_type ? +- _ppdCacheGetType(p->pc, +- media_type->choice) : +- NULL); +- ++ col = new_media_col(pwgsize); + ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default", + col); + ippDelete(col); +@@ -4354,89 +4340,19 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ + * media-col-database + */ + +- num_media = p->pc->num_sizes; +- if (p->pc->num_sources) ++ if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-database", p->pc->num_sizes, NULL)) != NULL) + { +- if (p->pc->num_types > 0) +- num_media += p->pc->num_sizes * p->pc->num_sources * +- p->pc->num_types; +- else +- num_media += p->pc->num_sizes * p->pc->num_sources; +- } +- else if (p->pc->num_types) +- num_media += p->pc->num_sizes * p->pc->num_types; ++ /* ++ * Add each page size without source or type... ++ */ + +- if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, +- "media-col-database", num_media, +- NULL)) != NULL) +- { +- for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, val = attr->values; +- i > 0; +- i --, pwgsize ++) ++ for (i = 0, pwgsize = p->pc->sizes; i < p->pc->num_sizes; i ++, pwgsize ++) + { +- /* +- * Start by adding the page size without source or type... +- */ ++ ipp_t *col = new_media_col(pwgsize); + +- ppdMarkOption(ppd, "PageSize", pwgsize->map.ppd); +- +- val->collection = new_media_col(pwgsize, NULL, NULL); +- val ++; +- +- /* +- * Then add the specific, supported combinations of size, source, and +- * type... +- */ +- +- if (p->pc->num_sources > 0) +- { +- for (j = p->pc->num_sources, pwgsource = p->pc->sources; +- j > 0; +- j --, pwgsource ++) +- { +- ppdMarkOption(ppd, "InputSlot", pwgsource->ppd); +- +- if (p->pc->num_types > 0) +- { +- for (k = p->pc->num_types, pwgtype = p->pc->types; +- k > 0; +- k --, pwgtype ++) +- { +- if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd)) +- { +- val->collection = new_media_col(pwgsize, pwgsource->pwg, +- pwgtype->pwg); +- val ++; +- } +- } +- } +- else if (!ppdConflicts(ppd)) +- { +- val->collection = new_media_col(pwgsize, pwgsource->pwg, NULL); +- val ++; +- } +- } +- } +- else if (p->pc->num_types > 0) +- { +- for (j = p->pc->num_types, pwgtype = p->pc->types; +- j > 0; +- j --, pwgtype ++) +- { +- if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd)) +- { +- val->collection = new_media_col(pwgsize, NULL, pwgtype->pwg); +- val ++; +- } +- } +- } ++ ippSetCollection(p->ppd_attrs, &attr, i, col); ++ ippDelete(col); + } +- +- /* +- * Update the number of media-col-database values... +- */ +- +- attr->num_values = val - attr->values; + } + } + +@@ -5134,9 +5050,7 @@ load_ppd(cupsd_printer_t *p) /* I - Printer */ + */ + + static ipp_t * /* O - Collection value */ +-new_media_col(pwg_size_t *size, /* I - media-size/margin values */ +- const char *source, /* I - media-source value */ +- const char *type) /* I - media-type value */ ++new_media_col(pwg_size_t *size) /* I - media-size/margin values */ + { + ipp_t *media_col, /* Collection value */ + *media_size; /* media-size value */ +@@ -5145,29 +5059,15 @@ new_media_col(pwg_size_t *size, /* I - media-size/margin values */ + media_col = ippNew(); + + media_size = ippNew(); +- ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, +- "x-dimension", size->width); +- ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, +- "y-dimension", size->length); ++ ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "x-dimension", size->width); ++ ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "y-dimension", size->length); + ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size); + ippDelete(media_size); + +- ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, +- "media-bottom-margin", size->bottom); +- ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, +- "media-left-margin", size->left); +- ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, +- "media-right-margin", size->right); +- ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, +- "media-top-margin", size->top); +- +- if (source) +- ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source", +- NULL, source); +- +- if (type) +- ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type", +- NULL, type); ++ ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin", size->bottom); ++ ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin", size->left); ++ ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin", size->right); ++ ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin", size->top); + + return (media_col); + } diff --git a/SOURCES/cups-ppdopen-heap-overflow.patch b/SOURCES/cups-ppdopen-heap-overflow.patch new file mode 100644 index 0000000..4b725e1 --- /dev/null +++ b/SOURCES/cups-ppdopen-heap-overflow.patch @@ -0,0 +1,42 @@ +diff --git a/cups/ppd.c b/cups/ppd.c +index ff52df2e..199cf034 100644 +--- a/cups/ppd.c ++++ b/cups/ppd.c +@@ -1719,8 +1719,7 @@ _ppdOpen( + constraint->choice1, constraint->option2, + constraint->choice2)) + { +- case 0 : /* Error */ +- case 1 : /* Error */ ++ default : /* Error */ + pg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + goto error; + +diff --git a/ppdc/ppdc-source.cxx b/ppdc/ppdc-source.cxx +index c25d4966..236c00db 100644 +--- a/ppdc/ppdc-source.cxx ++++ b/ppdc/ppdc-source.cxx +@@ -1743,15 +1743,17 @@ ppdcSource::get_resolution(ppdcFile *fp)// I - File to read + + switch (sscanf(name, "%dx%d", &xdpi, &ydpi)) + { +- case 0 : +- _cupsLangPrintf(stderr, +- _("ppdc: Bad resolution name \"%s\" on line %d of " +- "%s."), name, fp->line, fp->filename); +- break; + case 1 : + ydpi = xdpi; + break; +- } ++ case 2 : ++ break; ++ default : ++ _cupsLangPrintf(stderr, ++ _("ppdc: Bad resolution name \"%s\" on line %d of " ++ "%s."), name, fp->line, fp->filename); ++ break; ++} + + // Create the necessary PS commands... + snprintf(command, sizeof(command), diff --git a/SOURCES/cups-rastertoepson-crash.patch b/SOURCES/cups-rastertoepson-crash.patch new file mode 100644 index 0000000..11f6673 --- /dev/null +++ b/SOURCES/cups-rastertoepson-crash.patch @@ -0,0 +1,13 @@ +diff --git a/filter/rastertoepson.c b/filter/rastertoepson.c +index 4efe669..e8fe0c6 100644 +--- a/filter/rastertoepson.c ++++ b/filter/rastertoepson.c +@@ -307,7 +307,7 @@ StartPage( + + if (DotBytes) + { +- if ((LineBuffers[0] = calloc((size_t)DotBytes, header->cupsWidth * (size_t)(Shingling + 1))) == NULL) ++ if ((LineBuffers[0] = calloc((size_t)DotBytes, (header->cupsWidth + 7) * (size_t)(Shingling + 1))) == NULL) + { + fputs("ERROR: Unable to allocate memory\n", stderr); + exit(1); diff --git a/SPECS/cups.spec b/SPECS/cups.spec index bb99862..5110061 100644 --- a/SPECS/cups.spec +++ b/SPECS/cups.spec @@ -15,7 +15,7 @@ Summary: CUPS printing system Name: cups Epoch: 1 Version: 2.2.6 -Release: 30%{?dist} +Release: 38%{?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 @@ -87,6 +87,20 @@ Patch50: cups-do-not-advertise-http-methods.patch # 1774462, 1774463 - CVE-2019-8696, CVE-2019-8675 - buffer overflow in SNMP and IPP, # memory disclosure and DoS in scheduler Patch51: 0001-Multiple-security-disclosure-issues.patch +# 1775668 - cupsd eats a lot of memory when lots of queue with extensive PPDs are created +Patch52: cups-memory-consumption.patch +# 1784884 - cups.service doesn't execute automatically on request +Patch53: cups-autostart-when-enabled.patch +# 1825253 - CVE-2020-3898 cups: heap based buffer overflow in libcups's ppdFindOption() in ppd-mark.c +Patch54: cups-ppdopen-heap-overflow.patch +# 1838449 - ipp/socket backends connect to turned off device for eternity (contimeout is not applied) +Patch55: cups-etimedout.patch +# 1689207 - Add failover backend +Patch56: cups-failover-backend.patch +# 1833516 - DirtyCleanInterval ignored if there are open client connections +Patch57: cups-dirtyclean.patch +# 1775590 - rastertoepson filter crashes with paper size A6 +Patch58: cups-rastertoepson-crash.patch Patch100: cups-lspp.patch @@ -317,6 +331,20 @@ Sends IPP requests to the specified URI and tests and/or displays the results. # 1774462, 1774463 - CVE-2019-8696, CVE-2019-8675 - buffer overflow in SNMP and IPP, # memory disclosure and DoS in scheduler %patch51 -p1 -b .cve-in-scheduler +# 1775668 - cupsd eats a lot of memory when lots of queue with extensive PPDs are created +%patch52 -p1 -b .memory-consumption +# 1784884 - cups.service doesn't execute automatically on request +%patch53 -p1 -b .autostart-when-enabled +# 1825253 - CVE-2020-3898 cups: heap based buffer overflow in libcups's ppdFindOption() in ppd-mark.c +%patch54 -p1 -b .ppdopen-heap-overflow +# 1838449 - ipp/socket backends connect to turned off device for eternity (contimeout is not applied) +%patch55 -p1 -b .etimedout +# 1689207 - Add failover backend +%patch56 -p1 -b .failover +# 1833516 - DirtyCleanInterval ignored if there are open client connections +%patch57 -p1 -b .dirtyclean +# 1775590 - rastertoepson filter crashes with paper size A6 +%patch58 -p1 -b .rastertoepson-crash sed -i -e '1iMaxLogSize 0' conf/cupsd.conf.in @@ -512,6 +540,13 @@ do done %endif +%{_bindir}/rm /var/cache/cups/*.data > /dev/null 2>&1 + +if [ -e /etc/systemd/system/printer.target.wants/cups.service ] +then + %{_bindir}/systemctl enable cups.service > /dev/null 2>&1 +fi + exit 0 %post client @@ -720,6 +755,38 @@ rm -f %{cups_serverbin}/backend/smb %{_mandir}/man5/ipptoolfile.5.gz %changelog +* Tue May 26 2020 Zdenek Dohnal - 1:2.2.6-38 +- 1775590 - rastertoepson filter crashes with paper size A6 + +* Mon May 25 2020 Zdenek Dohnal - 1:2.2.6-37 +- forgot to enable optimization - 1833516 + +* Fri May 22 2020 Zdenek Dohnal - 1:2.2.6-36 +- 1838449 - ipp/socket backends connect to turned off device for eternity (contimeout is not applied) +- 1689207 - Add failover backend +- 1833516 - DirtyCleanInterval ignored if there are open client connections + +* Tue Apr 21 2020 Zdenek Dohnal - 1:2.2.6-35 +- 1825254 - CVE-2020-3898 cups: heap based buffer overflow in libcups's ppdFindOption() in ppd-mark.c + +* Mon Apr 20 2020 Zdenek Dohnal - 1:2.2.6-34 +- 1809002 - scriptlet issue, /usr/bin/rm: cannot remove '/var/cache/cups/*.data' + +* Thu Apr 09 2020 Zdenek Dohnal - 1:2.2.6-34 +- 1784884 - cups.service doesn't execute automatically on request + +* Wed Apr 08 2020 Zdenek Dohnal - 1:2.2.6-34 +- 1822135 - _ppdOpen() leaks 'string' variable + +* Fri Feb 14 2020 Zdenek Dohnal - 1:2.2.6-33 +- fix more memory leaks found by coverity in 1775668 + +* Fri Feb 14 2020 Zdenek Dohnal - 1:2.2.6-32 +- fix covscan issues raised by 1775668 + +* Thu Feb 06 2020 Zdenek Dohnal - 1:2.2.6-31 +- 1775668 - cupsd eats a lot of memory when lots of queue with extensive PPDs are created + * Tue Nov 26 2019 Zdenek Dohnal - 1:2.2.6-30 - 1774462 - CVE-2019-8675 - buffer overflow in SNMP and IPP, memory disclosure and DoS in scheduler - 1774463 - CVE-2019-8696