From: Steve Algernon Date: Fri, 27 Oct 2023 22:47:22 +0000 (-0700) Subject: Update ipp documentation to reflect the behavior of configuring WiFi on IPP USB printers. X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=commitdiff_plain;h=HEAD;hp=918332904921acaa6d9286c24ce61478d422a0fd Update ipp documentation to reflect the behavior of configuring WiFi on IPP USB printers. --- diff --git a/.gitignore b/.gitignore index a5e32e600..3bc3f2efc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ *.a *.bck -*.cgi +/cgi-bin/*.cgi *.o autom4te.cache config.h diff --git a/.lgtm.yml b/.lgtm.yml index 626551724..e7f2e0dff 100644 --- a/.lgtm.yml +++ b/.lgtm.yml @@ -2,3 +2,6 @@ queries: - exclude: cpp/integer-multiplication-cast-to-long - exclude: cpp/missing-header-guard - exclude: cpp/short-global-name + - exclude: cpp/tainted-format-string + - exclude: cpp/toctou-race-condition + - exclude: cpp/constant-comparison diff --git a/CHANGES.md b/CHANGES.md index 6af792b82..9da22c8e7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,113 @@ -CHANGES - 2.3.2 - 2019-12-18 -============================ +Change History +============== + +Changes in CUPS v2.3.6 +---------------------- +- CVE-2022-26691: An incorrect comparison in local admin authentication. + + +Changes in CUPS v2.3.5 +---------------------- + +- The automated test suite can now be activated using `make test` for + consistency with other projects and CI environments - the old `make check` + continues to work as well, and the previous test server behavior can be + accessed by running `make testserver`. +- ippeveprinter now supports multiple icons and strings files. +- ippeveprinter now uses the system's FQDN with Avahi. +- ippeveprinter now supports Get-Printer-Attributes on "/". +- ippeveprinter now uses a deterministic "printer-uuid" value. +- ippeveprinter now uses system sounds on macOS for Identify-Printer. +- Updated ippfind to look for files in "~/Desktop" on Windows. +- Updated ippfind to honor `SKIP-XXX` directives with `PAUSE`. +- Updated IPP Everywhere support to work around printers that only advertise + color raster support but really also support grayscale (OpenPrinting #1) +- ipptool now supports DNS-SD URIs like `ipps://My%20Printer._ipps._tcp.local` + (OpenPrinting #5) +- ipptool now supports monitoring the printer state while submitting a job + with the `MONITOR-PRINTER-STATE` directive (OpenPrinting #153) +- ipptool now supports testing for unique values with the `WITH-DISTINCT-VALUES` + predicate (OpenPrinting #153) +- ipptool now supports retrying requests on a `server-error-busy` status code + (OpenPrinting #153) +- ipptool now supports `value-tag(MAX)` and `value-tag(MIN:MAX)` for the + `OF-TYPE` predicate (OpenPrinting #153) +- The scheduler now allows root backends to have world read permissions but not + world execute permissions (OpenPrinting #21) +- Failures to bind IPv6 listener sockets no longer cause errors if IPv6 is + disabled on the host (OpenPrinting #25) +- The SNMP backend now supports the HP and Ricoh vendor MIBs (OpenPrinting #28) +- The scheduler no longer includes a timestamp in files it writes (OpenPrinting #29) +- IPP Everywhere PPDs could have an "unknown" default InputSlot (OpenPrinting #44) +- The `httpAddrListen` function now uses a listen backlog of 128. +- The PPD functions now treat boolean values as case-insensitive (OpenPrinting #106) +- Temporary queue names no longer end with an underscore (OpenPrinting #110) +- Added USB quirks (Issue #5789, #5766, #5823, #5831, #5838, #5843, #5867) +- Fixed IPP Everywhere v1.1 conformance issues in ippeveprinter. +- Fixed DNS-SD name collision support in ippeveprinter. +- Fixed compiler and code analyzer warnings. +- Fixed TLS support on Windows. +- Fixed ippfind sub-type searches with Avahi. +- Fixed the default hostname used by ippeveprinter on macOS. +- Fixed resolution of local IPP-USB printers with Avahi. +- Fixed coverity issues (OpenPrinting #2) +- Fixed `httpAddrConnect` issues (OpenPrinting #3) +- Fixed web interface device URI issue (OpenPrinting #4) +- Fixed lp/lpr "printer/class not found" error reporting (OpenPrinting #6) +- Fixed a memory leak in the scheduler (OpenPrinting #12) +- Fixed a potential integer overflow in the PPD hashing code (OpenPrinting #13) +- Fixed output-bin and print-quality handling issues (OpenPrinting #18) +- Fixed PPD options getting mapped to odd IPP values like "tray---4" (OpenPrinting #23) +- Fixed remote access to the cupsd.conf and log files (OpenPrinting #24) +- Fixed a logging regression caused by a previous change for Issue #5604 + (OpenPrinting #25) +- Fixed the "uri-security-supported" value from the scheduler (OpenPrinting #42) +- Fixed IPP backend crash bug with "printer-alert" values (OpenPrinting #43) +- Fixed default options that incorrectly use the "custom" prefix (OpenPrinting #48) +- Fixed a memory leak when resolving DNS-SD URIs (OpenPrinting #49) +- Fixed cupsManualCopies values in IPP Everywhere PPDs (Issue #5807) +- Fixed duplicate ColorModel entries for AirPrint printers (Issue 59) +- Fixed crash bug in `ppdOpen` (OpenPrinting #64, OpenPrinting #78) +- Fixed regression in `snprintf` emulation function (OpenPrinting #67) +- Fixed reporting of printer instances when enumerating and when no options are + set for the main instance (OpenPrinting #71) +- Fixed segfault in help.cgi when searching in man pages (OpenPrinting #81) +- Fixed a bug in ipptool that caused the reuse of request IDs when repeating a + test (OpenPrinting #153) +- Root certificates were incorrectly stored in "~/.cups/ssl". +- Fixed a PPD memory leak caused by emulator definitions (OpenPrinting #124) +- Fixed a `DISPLAY` bug in `ipptool` (OpenPrinting #139) +- `httpReconnect2` did not reset the socket file descriptor when the TLS + negotiation failed (Issue #5907) +- `httpUpdate` did not reset the socket file descriptor when the TLS + negotiation failed (Apple #5915) +- The `ippeveprinter` tool now automatically uses an available port. +- The IPP backend now retries Validate-Job requests (OpenPrinting #132) +- Removed support for the (long deprecated and unused) `KeepAliveTimeout` + directive in `cupsd.conf` (Issue #5733) +- Fixed `@IF(name)` handling in `cupsd.conf` (Issue #5918) +- The scheduler now supports the "everywhere" model directly (Issue #5919) +- Fixed documentation and added examples for CUPS' limited CGI support + (Issue #5940) +- Fixed the `lpc` command prompt (Issue #5946) +- Fixed `job-pages-per-set` value for duplex print jobs. + + +Changes in CUPS v2.3.4 +---------------------- + +- CVE-2020-10001: Fixed a buffer (read) overflow in the `ippReadIO` function. + + +Changes in CUPS v2.3.3 +---------------------- + +- CVE-2020-3898: The `ppdOpen` function did not handle invalid UI + constraint. `ppdcSource::get_resolution` function did not handle + invalid resolution strings. +- CVE-2019-8842: The `ippReadIO` function may under-read an extension + field. +- Fixed WARNING_OPTIONS support for GCC 9.x Changes in CUPS v2.3.2 diff --git a/INSTALL.md b/INSTALL.md index f8801347a..f88dfedff 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,4 +1,4 @@ -INSTALL - CUPS v2.3.1 - 2019-12-13 +INSTALL - CUPS v2.3.6 - 2022-05-25 ================================== This file describes how to compile and install CUPS from source code. For more diff --git a/Makefile b/Makefile index 15544627f..294ac5ea4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # # Top-level Makefile for CUPS. # -# Copyright © 2007-2019 by Apple Inc. +# Copyright © 2007-2021 by Apple Inc. # Copyright © 1997-2007 by Easy Software Products, all rights reserved. # # Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -230,16 +230,16 @@ uninstall: # Run the test suite... # -test: all unittests - echo Running CUPS test suite... +testserver: all unittests + echo Running CUPS test server... cd test; ./run-stp-tests.sh $(TESTOPTIONS) -check: all unittests +check test: all unittests echo Running CUPS test suite with defaults... cd test; ./run-stp-tests.sh 1 0 n n -debugcheck: all unittests +debugcheck debugtest: all unittests echo Running CUPS test suite with debug printfs... cd test; ./run-stp-tests.sh 1 0 n y diff --git a/README.md b/README.md index 6e15a93e7..f48de5367 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ -README - CUPS v2.3.1 - 2019-12-13 -================================= +README - Apple CUPS v2.3.6 - 2022-05-25 +======================================= + +> Note: Apple CUPS is the version of CUPS that is shipped with macOS and iOS. +> For the current version of CUPS that is used on other operating systems, see +> for details. + INTRODUCTION ------------ @@ -157,7 +162,7 @@ This will prevent the filters from misinterpreting your print file. LEGAL STUFF ----------- -Copyright © 2007-2019 by Apple Inc. +Copyright © 2007-2021 by Apple Inc. Copyright © 1997-2007 by Easy Software Products. CUPS is provided under the terms of the Apache License, Version 2.0 with diff --git a/backend/backend-private.h b/backend/backend-private.h index 85fb8aef8..d19b06b82 100644 --- a/backend/backend-private.h +++ b/backend/backend-private.h @@ -1,7 +1,8 @@ /* * Backend support definitions for CUPS. * - * Copyright © 2007-2014 by Apple Inc. + * Copyright © 2021 by OpenPrinting + * Copyright © 2007-2021 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -52,6 +53,14 @@ extern "C" { # endif /* __cplusplus */ +/* + * Log messages in backend signal handlers or other places where stdio cannot + * be used... + */ + +# define backendMessage(msg) {const char *s = msg; write(2, s, strlen(s));} + + /* * OID constants... */ @@ -320,7 +329,6 @@ extern int backendSNMPSupplies(int snmp_fd, http_addr_t *addr, extern int backendWaitLoop(int snmp_fd, http_addr_t *addr, int use_bc, _cups_sccb_t side_cb); - # ifdef __cplusplus } # endif /* __cplusplus */ diff --git a/backend/ipp.c b/backend/ipp.c index 3f3e1867d..3779c88fa 100644 --- a/backend/ipp.c +++ b/backend/ipp.c @@ -1,7 +1,8 @@ /* * IPP backend for CUPS. * - * Copyright © 2007-2019 by Apple Inc. + * Copyright © 2021 by OpenPrinting + * Copyright © 2007-2021 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -256,6 +257,7 @@ main(int argc, /* I - Number of command-line args */ get_job_attrs = 0, /* Does printer support Get-Job-Attributes? */ send_document = 0, /* Does printer support Send-Document? */ validate_job = 0, /* Does printer support Validate-Job? */ + validate_retried = 0, /* Was Validate-Job request retried? */ copies, /* Number of copies for job */ copies_remaining; /* Number of copies remaining */ const char *content_type, /* CONTENT_TYPE environment variable */ @@ -1559,7 +1561,17 @@ main(int argc, /* I - Number of command-line args */ ipp_status == IPP_STATUS_ERROR_BAD_REQUEST) break; else if (job_auth == NULL && ipp_status > IPP_STATUS_ERROR_BAD_REQUEST) + { + if (!validate_retried) + { + // Retry Validate-Job operation once, to work around known printer bug... + validate_retried = 1; + sleep(10); + continue; + } + goto cleanup; + } } /* @@ -2240,7 +2252,8 @@ main(int argc, /* I - Number of command-line args */ else if (ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_AUTHORIZATION_FAILED) fputs("JOBSTATE: account-authorization-failed\n", stderr); - if (job_canceled) + // job_canceled can be -1 which should not be treated as CUPS_BACKEND_OK + if (job_canceled > 0) return (CUPS_BACKEND_OK); else if (ipp_status == IPP_STATUS_ERROR_NOT_AUTHORIZED || ipp_status == IPP_STATUS_ERROR_FORBIDDEN || ipp_status == IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED) return (CUPS_BACKEND_AUTH_REQUIRED); @@ -2825,7 +2838,21 @@ new_request( */ _httpDecodeURI(phone, keyword, sizeof(phone)); - for (ptr = phone; *ptr;) + ptr = phone; + + /* + * Weed out "Custom." in the beginning, this allows to put the + * "phone" option as custom string option into the PPD so that + * print dialogs not supporting fax display the option and + * allow entering the phone number. Print dialogs also send "None" + * if no phone number got entered, filter this, too. + */ + if (!_cups_strcasecmp(phone, "None")) + *ptr = '\0'; + if (!_cups_strncasecmp(phone, "Custom.", 7)) + _cups_strcpy(ptr, ptr + 7); + + for (; *ptr;) { if (*ptr == ',') *ptr = 'p'; @@ -2835,20 +2862,36 @@ new_request( ptr ++; } - httpAssembleURI(HTTP_URI_CODING_ALL, tel_uri, sizeof(tel_uri), "tel", NULL, NULL, 0, phone); - ippAddString(destination, IPP_TAG_JOB, IPP_TAG_URI, "destination-uri", NULL, tel_uri); - - if ((keyword = cupsGetOption("faxPrefix", num_options, - options)) != NULL && *keyword) + if (strlen(phone) > 0) { - char predial[1024]; /* Pre-dial string */ + httpAssembleURI(HTTP_URI_CODING_ALL, tel_uri, sizeof(tel_uri), "tel", NULL, NULL, 0, phone); + ippAddString(destination, IPP_TAG_JOB, IPP_TAG_URI, "destination-uri", NULL, tel_uri); + fprintf(stderr, "DEBUG: Faxing to phone %s; destination-uri: %s\n", phone, tel_uri); - _httpDecodeURI(predial, keyword, sizeof(predial)); - ippAddString(destination, IPP_TAG_JOB, IPP_TAG_TEXT, "pre-dial-string", NULL, predial); - } + if ((keyword = cupsGetOption("faxPrefix", num_options, options)) != NULL && *keyword) + { + char predial[1024]; /* Pre-dial string */ + + _httpDecodeURI(predial, keyword, sizeof(predial)); + ptr = predial; + if (!_cups_strcasecmp(ptr, "None")) + *ptr = '\0'; + if (!_cups_strncasecmp(ptr, "Custom.", 7)) + ptr += 7; + if (strlen(ptr) > 0) + { + ippAddString(destination, IPP_TAG_JOB, IPP_TAG_TEXT, "pre-dial-string", NULL, ptr); + fprintf(stderr, "DEBUG: Pre-dialing %s; pre-dial-string: %s\n", ptr, ptr); + } + else + fprintf(stderr, "WARNING: Pre-dial number for fax not valid! Sending fax without pre-dial number.\n"); + } - ippAddCollection(request, IPP_TAG_JOB, "destination-uris", destination); - ippDelete(destination); + ippAddCollection(request, IPP_TAG_JOB, "destination-uris", destination); + ippDelete(destination); + } + else + fprintf(stderr, "ERROR: Phone number for fax not valid! Fax cannot be sent.\n"); } } else @@ -3075,7 +3118,7 @@ report_printer_state(ipp_t *ipp) /* I - IPP response */ * Report alerts and messages... */ - if ((pa = ippFindAttribute(ipp, "printer-alert", IPP_TAG_TEXT)) != NULL) + if ((pa = ippFindAttribute(ipp, "printer-alert", IPP_TAG_STRING)) != NULL) report_attr(pa); if ((pam = ippFindAttribute(ipp, "printer-alert-message", @@ -3116,11 +3159,10 @@ report_printer_state(ipp_t *ipp) /* I - IPP response */ if (*ptr < ' ' && *ptr > 0 && *ptr != '\t') { /* - * Substitute "" for the control character; sprintf is safe because - * we always leave 6 chars free at the end... + * Substitute "" for the control character... */ - sprintf(valptr, "<%02X>", *ptr); + snprintf(valptr, sizeof(value) - (size_t)(valptr - value), "<%02X>", *ptr); valptr += 4; } else @@ -3203,7 +3245,8 @@ run_as_user(char *argv[], /* I - Command-line arguments */ const char *device_uri, /* I - Device URI */ int fd) /* I - File to print */ { - const char *auth_negotiate;/* AUTH_NEGOTIATE env var */ + const char *auth_negotiate,/* AUTH_NEGOTIATE env var */ + *content_type; /* [FINAL_]CONTENT_TYPE env vars */ xpc_connection_t conn; /* Connection to XPC service */ xpc_object_t request; /* Request message dictionary */ __block xpc_object_t response; /* Response message dictionary */ @@ -3266,6 +3309,10 @@ run_as_user(char *argv[], /* I - Command-line arguments */ getenv("AUTH_INFO_REQUIRED")); if ((auth_negotiate = getenv("AUTH_NEGOTIATE")) != NULL) xpc_dictionary_set_string(request, "auth-negotiate", auth_negotiate); + if ((content_type = getenv("CONTENT_TYPE")) != NULL) + xpc_dictionary_set_string(request, "content-type", content_type); + if ((content_type = getenv("FINAL_CONTENT_TYPE")) != NULL) + xpc_dictionary_set_string(request, "final-content-type", content_type); xpc_dictionary_set_fd(request, "stdin", fd); xpc_dictionary_set_fd(request, "stderr", 2); xpc_dictionary_set_fd(request, "side-channel", CUPS_SC_FD); @@ -3388,7 +3435,7 @@ sigterm_handler(int sig) /* I - Signal */ { (void)sig; /* remove compiler warnings... */ - write(2, "DEBUG: Got SIGTERM.\n", 20); + backendMessage("DEBUG: Got SIGTERM.\n"); #if defined(HAVE_GSSAPI) && defined(HAVE_XPC) if (child_pid) @@ -3404,7 +3451,7 @@ sigterm_handler(int sig) /* I - Signal */ * Flag that the job should be canceled... */ - write(2, "DEBUG: sigterm_handler: job_canceled = 1.\n", 25); + backendMessage("DEBUG: sigterm_handler: job_canceled = 1.\n"); job_canceled = 1; return; diff --git a/backend/network.c b/backend/network.c index 5af0a8eea..f7ee2fbbe 100644 --- a/backend/network.c +++ b/backend/network.c @@ -258,7 +258,7 @@ backendNetworkSideCB( i < packet.object_value.string.num_bytes && dataptr < (data + sizeof(data) - 3); i ++, dataptr += 2) - sprintf(dataptr, "%02X", packet.object_value.string.bytes[i]); + snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%02X", packet.object_value.string.bytes[i]); datalen += (int)strlen(dataptr); break; diff --git a/backend/org.cups.usb-quirks b/backend/org.cups.usb-quirks index cd684d33f..83f62c165 100644 --- a/backend/org.cups.usb-quirks +++ b/backend/org.cups.usb-quirks @@ -68,7 +68,7 @@ # Canon, Inc. PIXMA iP6000D Printer (https://bugs.launchpad.net/bugs/1160638) 0x04a9 0x1095 unidir -# Canon, Inc. PIXMA iP4200 Printer (Issue #4155) +# Canon, Inc. PIXMA iP4200 Printer (Apple #4155) 0x04a9 0x10a2 unidir # Canon, Inc. PIXMA iP4300 Printer (https://bugs.launchpad.net/bugs/1032385) @@ -86,12 +86,15 @@ # Canon, Inc. MP540 Printer, https://bugzilla.redhat.com/967873 0x04a9 0x1730 unidir -# Canon, Inc. MP550 Printer (Issue #4155) +# Canon, Inc. MP550 Printer (Apple #4155) 0x04a9 0x173d unidir -# Canon, Inc. MP560 Printer (Issue #4155) +# Canon, Inc. MP560 Printer (Apple #4155) 0x04a9 0x173e unidir +# Canon, Inc. PIXMA G1501 Printer (Apple #5831) +0x04a9 0x1796 unidir + # Canon, Inc. MF4150 Printer (https://bugs.launchpad.net/bugs/1160638) 0x04a9 0x26a3 no-reattach @@ -140,7 +143,7 @@ # Samsung ML-2160 Series (https://bugzilla.redhat.com/show_bug.cgi?id=873123) 0x04e8 0x330f unidir -# All Zebra devices (https://bugs.launchpad.net/bugs/1001028) (Issue #5395) +# All Zebra devices (https://bugs.launchpad.net/bugs/1001028) (Apple #5395) 0x0a5f unidir no-reattach # Canon CP-10 @@ -230,75 +233,87 @@ # Lexmark E238 () 0x043d 0x00d7 no-reattach -# Lexmark E238 (Issue #4448) +# Lexmark E238 (Apple #4448) 0x043d 0x009a no-reattach -# Canon MX310 (Issue #4482) +# Canon MX310 (Apple #4482) 0x04a9 0x1728 unidir -# Canon MX320 (Issue #4482) +# Canon MX320 (Apple #4482) 0x04A9 0x1736 unidir -# All Intermec devices (Issue #4553) +# All Intermec devices (Apple #4553) 0x067e no-reattach -# HP LaserJet 1015 (Issue #5617) +# HP LaserJet 1010 (Apple #5789) +0x03f0 0x0c17 delay-close + +# HP LaserJet 1015 (Apple #5617) 0x03f0 0x0e17 delay-close -# HP LaserJet 1150 (Issue #4549) +# HP LaserJet 1150 (Apple #4549) 0x03f0 0x0f17 delay-close -# HP LaserJet 1300 (Issue #4549) +# HP LaserJet 1300 (Apple #4549) 0x03f0 0x1017 delay-close 0x03f0 0x1117 delay-close -# HP LaserJet 1320 (Issue #4549) +# HP LaserJet 1320 (Apple #4549) 0x03f0 0x1d17 delay-close # Canon, Inc. MP530 Printer 0x04a9 0x1712 unidir -# Xerox WorkCentre 3220 (https://bugs.launchpad.net/bugs/1406203, Issue #4789) +# Xerox WorkCentre 3220 (https://bugs.launchpad.net/bugs/1406203, Apple #4789) 0x0924 0x4294 no-reattach -# Lexmark C540n (Issue #4778) +# Lexmark C540n (Apple #4778) 0x043d 0x0139 no-reattach -# Kyocera Ecosys P6026cdn (Issue #4900) +# Kyocera Ecosys P6026cdn (Apple #4900) 0x0482 0x063f no-reattach -# Kyocera Ecosys P6130cdn (Issue #5102) +# Kyocera Ecosys P6130cdn (Apple #5102) 0x0482 0x0677 no-reattach -# Lexmark E260dn (Issue #4994) +# Lexmark E260dn (Apple #4994) 0x043d 0x0123 no-reattach -# HP LaserJet 1160 (Issue #5121) +# HP LaserJet 1160 (Apple #5121) 0x03f0 0x1e17 delay-close -# Canon, Inc. MP280 series (Issue #5221) +# Canon, Inc. MP280 series (Apple #5221) 0x04a9 0x1746 unidir -# Star Micronics printers (Issue #5251) +# Star Micronics printers (Apple #5251) 0x0519 unidir -# Lexmark Optra E310 (Issue #5259) +# Lexmark Optra E310 (Apple #5259) 0x043d 0x000c no-reattach -# HP LaserJet P1102 (Issue #5310) +# HP LaserJet P1102 (Apple #5310) 0x03F0 0x002A no-reattach # Lexmark MS317dn 0x043d 0x0226 no-reattach -# Star TSP743 (Issue #5443) +# Star TSP743 (Apple #5443) 0x0519 0x0001 delay-close -# Lexmark E120n (Issue #5478) +# Lexmark E120n (Apple #5478) 0x043d 0x00cc no-reattach -# All Xerox printers (Issue #5523) +# Lexmark E120n MT4506-100 (Apple #5766) +0x043d 0x00cd no-reattach + +# All Xerox printers (Apple #5523) 0x0924 no-reattach -# Dymo 450 Turbo (Issue #5521) -0x0922 0x0021 unidir +# Citizen CT-S4000 (Apple #5823) +0x2730 0x2008 unidir delay-close + +# All Arkscan label printers (Apple #5867) +0x2d84 unidir no-reattach + +# HP DesignJet 130 (Apple #5838) +0x03f0 0x0314 no-reattach diff --git a/backend/snmp.c b/backend/snmp.c index 66ac884c6..084c6f511 100644 --- a/backend/snmp.c +++ b/backend/snmp.c @@ -154,6 +154,8 @@ static const int UriOID[] = { CUPS_OID_ppmPortServiceNameOrURI, 1, 1, -1 }; 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 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; @@ -422,7 +424,7 @@ alarm_handler(int sig) /* I - Signal number */ #endif /* !HAVE_SIGSET && !HAVE_SIGACTION */ if (DebugLevel) - write(2, "DEBUG: ALARM!\n", 14); + backendMessage("DEBUG: ALARM!\n"); } @@ -969,9 +971,15 @@ read_snmp_response(int fd) /* I - SNMP socket file descriptor */ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, 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, + packet.community, CUPS_ASN1_GET_REQUEST, + DEVICE_ID, HPDeviceIdOID); break; case DEVICE_DESCRIPTION : diff --git a/backend/testbackend.c b/backend/testbackend.c index 6dbd0abee..6412a022b 100644 --- a/backend/testbackend.c +++ b/backend/testbackend.c @@ -19,6 +19,7 @@ #include #include #include +#include "backend-private.h" /* @@ -395,7 +396,7 @@ main(int argc, /* I - Number of command-line args */ data = ps_data; write(1, data, strlen(data)); - write(2, "DEBUG: START\n", 13); + backendMessage("DEBUG: START\n"); timeout = 60.0; while ((bytes = cupsBackChannelRead(buffer, sizeof(buffer), timeout)) > 0) @@ -403,7 +404,7 @@ main(int argc, /* I - Number of command-line args */ write(2, buffer, (size_t)bytes); timeout = 5.0; } - write(2, "\nDEBUG: END\n", 12); + backendMessage("\nDEBUG: END\n"); } exit(0); diff --git a/backend/usb-darwin.c b/backend/usb-darwin.c index 1c412da6f..f0d04ab42 100644 --- a/backend/usb-darwin.c +++ b/backend/usb-darwin.c @@ -1,5 +1,7 @@ /* - * Copyright 2005-2016 Apple Inc. All rights reserved. + * USB backend for macOS. + * + * Copyright © 2005-2021 Apple Inc. All rights reserved. * * IMPORTANT: This Apple software is supplied to you by Apple Computer, * Inc. ("Apple") in consideration of your agreement to the following @@ -288,11 +290,11 @@ static void status_timer_cb(CFRunLoopTimerRef timer, void *info); #define IS_64BIT 1 #define IS_NOT_64BIT 0 -#if defined(__i386__) || defined(__x86_64__) +#if defined(__arm64e__) static pid_t child_pid; /* Child PID */ -static void run_legacy_backend(int argc, char *argv[], int fd) _CUPS_NORETURN; /* Starts child backend process running as a ppc executable */ -#endif /* __i386__ || __x86_64__ */ -static void sigterm_handler(int sig); /* SIGTERM handler */ +static void run_legacy_backend(int argc, char *argv[], int fd) _CUPS_NORETURN; /* Starts child backend process running as a x86_64 executable */ +static void sigterm_handler(int sig); /* SIGTERM handler */ +#endif /* __arm64e__ */ static void sigquit_handler(int sig, siginfo_t *si, void *unused) _CUPS_NORETURN; #ifdef PARSE_PS_ERRORS @@ -357,6 +359,8 @@ print_device(const char *uri, /* I - Device URI */ (void)uri; + (void)argc; + (void)argv; /* * Catch SIGQUIT to determine who is sending it... @@ -436,18 +440,18 @@ print_device(const char *uri, /* I - Device URI */ status = registry_open(&driverBundlePath); -#if defined(__i386__) || defined(__x86_64__) +#if defined(__arm64e__) /* * If we were unable to load the class drivers for this printer it's - * probably because they're ppc or i386. In this case try to run this - * backend as i386 or ppc executables so we can use them... + * probably because they're x86_64 (or older). In this case try to run this + * backend as x86_64 so we can use them... */ if (status == -2) { run_legacy_backend(argc, argv, print_fd); /* Never returns here */ } -#endif /* __i386__ || __x86_64__ */ +#endif /* __arm64e__ */ if (status == -2) { @@ -1510,12 +1514,11 @@ static kern_return_t load_printerdriver(CFStringRef *driverBundlePath) SInt32 score; kern_return_t kr; printer_interface_t interface; - HRESULT res; kr = IOCreatePlugInInterfaceForService(g.printer_obj, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score); if (kr == kIOReturnSuccess) { - if ((res = (*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &interface)) == noErr) + if ((*iodev)->QueryInterface(iodev, USB_INTERFACE_KIND, (LPVOID *) &interface) == noErr) { *driverBundlePath = IORegistryEntryCreateCFProperty(g.printer_obj, kUSBClassDriverProperty, NULL, kNilOptions); @@ -1596,7 +1599,7 @@ static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer, /* This request takes the 0 based configuration index. IOKit returns a 1 based configuration index */ configurationIndex -= 1; - bzero(&request, sizeof(request)); + memset(&request, 0, sizeof(request)); request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface); request.bRequest = kUSBPrintClassGetDeviceID; @@ -1613,14 +1616,14 @@ static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer, if (actualLength > 2 && actualLength <= bufferLength - 2) { - ret = CFStringCreateWithBytes(NULL, (const UInt8 *) &request.pData[2], actualLength - 2, kCFStringEncodingUTF8, false); + ret = CFStringCreateWithBytes(NULL, (const UInt8 *)request.pData + 2, actualLength - 2, kCFStringEncodingUTF8, false); } else if (actualLength > 2) { err = sendRequest(actualLength); if (err == kIOReturnSuccess && request.wLenDone > 0) { actualLength = OSSwapBigToHostInt16(*((UInt16 *)request.pData)); - ret = CFStringCreateWithBytes(NULL, (const UInt8 *) &request.pData[2], actualLength - 2, kCFStringEncodingUTF8, false); + ret = CFStringCreateWithBytes(NULL, (const UInt8 *)request.pData + 2, actualLength - 2, kCFStringEncodingUTF8, false); } } } @@ -1638,7 +1641,7 @@ static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer, IOUSBDevRequestTO request; IOUSBDeviceDescriptor desc; - bzero(&request, sizeof(request)); + memset(&request, 0, sizeof(request)); request.bmRequestType = USBmakebmRequestType( kUSBIn, kUSBStandard, kUSBDevice ); request.bRequest = kUSBRqGetDescriptor; @@ -1667,41 +1670,59 @@ static CFStringRef copy_printer_interface_deviceid(printer_interface_t printer, CFStringAppendFormat(extras, NULL, CFSTR("MDL:%@;"), model); } - if (serial == NULL && desc.iSerialNumber != 0) + if (desc.iSerialNumber != 0) { - serial = copy_printer_interface_indexed_description(printer, desc.iSerialNumber, kUSBLanguageEnglish); - if (serial && CFStringGetLength(serial) > 0) - CFStringAppendFormat(extras, NULL, CFSTR("SERN:%@;"), serial); + // Always look at the USB serial number since some printers + // incorrectly include a bogus static serial number in their + // IEEE-1284 device ID string... + CFStringRef userial = copy_printer_interface_indexed_description(printer, desc.iSerialNumber, kUSBLanguageEnglish); + if (userial && CFStringGetLength(userial) > 0 && (serial == NULL || CFStringCompare(serial, userial, kCFCompareCaseInsensitive) != kCFCompareEqualTo)) + { + if (serial != NULL) + { + // 1284 serial number doesn't match USB serial number, so replace the existing SERN: in device ID + CFRange range = CFStringFind(ret, serial, 0); + CFMutableStringRef deviceIDString = CFStringCreateMutableCopy(NULL, 0, ret); + CFStringReplace(deviceIDString, range, userial); + CFRelease(ret); + ret = deviceIDString; + + CFRelease(serial); + } + else + { + // No 1284 serial number so add SERN: with USB serial number to device ID + CFStringAppendFormat(extras, NULL, CFSTR("SERN:%@;"), userial); + } + serial = userial; + } + else if (userial != NULL) + CFRelease(userial); } if (ret != NULL) { CFStringAppend(extras, ret); CFRelease(ret); - - ret = extras; - } - else - { - ret = extras; } + ret = extras; } } if (ret != NULL) { - /* Remove special characters from the serial number */ - CFRange range = (serial != NULL ? CFStringFind(serial, CFSTR("+"), 0) : CFRangeMake(0, 0)); - if (range.length == 1) - { - range = CFStringFind(ret, serial, 0); + /* Remove special characters from the serial number */ + CFRange range = (serial != NULL ? CFStringFind(serial, CFSTR("+"), 0) : CFRangeMake(0, 0)); + if (range.length == 1) + { + range = CFStringFind(ret, serial, 0); - CFMutableStringRef deviceIDString = CFStringCreateMutableCopy(NULL, 0, ret); - CFRelease(ret); + CFMutableStringRef deviceIDString = CFStringCreateMutableCopy(NULL, 0, ret); + CFRelease(ret); - ret = deviceIDString; - CFStringFindAndReplace(deviceIDString, CFSTR("+"), CFSTR(""), range, 0); - } + ret = deviceIDString; + CFStringFindAndReplace(deviceIDString, CFSTR("+"), CFSTR(""), range, 0); + } } if (manufacturer != NULL) @@ -1728,7 +1749,7 @@ static CFStringRef copy_printer_interface_indexed_description(printer_interface_ UInt8 description[256]; // Max possible descriptor length IOUSBDevRequestTO request; - bzero(description, 2); + memset(description, 0, 2); request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); request.bRequest = kUSBRqGetDescriptor; @@ -1742,7 +1763,7 @@ static CFStringRef copy_printer_interface_indexed_description(printer_interface_ err = (*printer)->ControlRequestTO(printer, 0, &request); if (err != kIOReturnSuccess && err != kIOReturnOverrun) { - bzero(description, request.wLength); + memset(description, 0, request.wLength); // Let's try again full length. Here's why: // On USB 2.0 controllers, we will not get an overrun error. We just get a "babble" error @@ -1775,7 +1796,7 @@ static CFStringRef copy_printer_interface_indexed_description(printer_interface_ request.wValue = (kUSBStringDesc << 8) | index; request.wIndex = language; - bzero(description, length); + memset(description, 0, length); request.wLength = (UInt16)length; request.pData = &description; request.completionTimeout = 0; @@ -1791,7 +1812,7 @@ static CFStringRef copy_printer_interface_indexed_description(printer_interface_ if ((description[0] & 1) != 0) description[0] &= 0xfe; - char buffer[258] = {}; + char buffer[258] = {0}; unsigned int maxLength = sizeof buffer; if (description[0] > 1) { @@ -2053,11 +2074,11 @@ static void setup_cfLanguage(void) } #pragma mark - -#if defined(__i386__) || defined(__x86_64__) +#if defined(__arm64e__) /*! * @function run_legacy_backend * - * @abstract Starts child backend process running as a ppc or i386 executable. + * @abstract Starts child backend process running as a x86_64 executable. * * @result Never returns; always calls exit(). * @@ -2076,18 +2097,14 @@ static void run_legacy_backend(int argc, /* - * If we're running as x86_64 or i386 and couldn't load the class driver - * (because it's ppc or i386), then try to re-exec ourselves in ppc or i386 - * mode to try again. If we don't have a ppc or i386 architecture we may be + * If we're running as ARM and couldn't load the class driver + * (because it's x86_64, i386 or ppc), then try to re-exec ourselves in x86_64 + * mode to try again. If we don't have that architecture we may be * running with the same architecture again so guard against this by setting * and testing an environment variable... */ -# ifdef __x86_64__ - usb_legacy_status = getenv("USB_I386_STATUS"); -# else - usb_legacy_status = getenv("USB_PPC_STATUS"); -# endif /* __x86_64__ */ + usb_legacy_status = getenv("USB_LEGACY_STATUS"); if (!usb_legacy_status) { @@ -2116,21 +2133,13 @@ static void run_legacy_backend(int argc, * Set the environment variable... */ -# ifdef __x86_64__ - setenv("USB_I386_STATUS", "1", false); -# else - setenv("USB_PPC_STATUS", "1", false); -# endif /* __x86_64__ */ + setenv("USB_LEGACY_STATUS", "1", false); /* * Tell the kernel to use the specified CPU architecture... */ -# ifdef __x86_64__ - cpu_type_t cpu = CPU_TYPE_I386; -# else - cpu_type_t cpu = CPU_TYPE_POWERPC; -# endif /* __x86_64__ */ + cpu_type_t cpu = CPU_TYPE_X86_64; size_t ocount = 1; posix_spawnattr_t attrs; @@ -2139,11 +2148,7 @@ static void run_legacy_backend(int argc, posix_spawnattr_setsigdefault(&attrs, &oldmask); if (posix_spawnattr_setbinpref_np(&attrs, 1, &cpu, &ocount) || ocount != 1) { -# ifdef __x86_64__ - perror("DEBUG: Unable to set binary preference to i386"); -# else - perror("DEBUG: Unable to set binary preference to ppc"); -# endif /* __x86_64__ */ + perror("DEBUG: Unable to set binary preference to X86_64"); _cupsLangPrintFilter(stderr, "ERROR", _("Unable to use legacy USB class driver.")); exit(CUPS_BACKEND_STOP); @@ -2217,8 +2222,6 @@ static void run_legacy_backend(int argc, exit(exitstatus); } -#endif /* __i386__ || __x86_64__ */ - /* * 'sigterm_handler()' - SIGTERM handler. @@ -2227,7 +2230,6 @@ static void run_legacy_backend(int argc, static void sigterm_handler(int sig) /* I - Signal */ { -#if defined(__i386__) || defined(__x86_64__) /* * If we started a child process pass the signal on to it... */ @@ -2249,12 +2251,12 @@ sigterm_handler(int sig) /* I - Signal */ _exit(0); else { - write(2, "DEBUG: Child crashed.\n", 22); + backendMessage("DEBUG: Child crashed.\n"); _exit(CUPS_BACKEND_STOP); } } -#endif /* __i386__ || __x86_64__ */ } +#endif /* __arm64e__ */ /* diff --git a/backend/usb-libusb.c b/backend/usb-libusb.c index 393fe65ee..d7c762392 100644 --- a/backend/usb-libusb.c +++ b/backend/usb-libusb.c @@ -1,7 +1,7 @@ /* * LIBUSB interface code for CUPS. * - * Copyright 2007-2019 by Apple Inc. + * Copyright 2007-2020 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more * information. diff --git a/backend/usb-unix.c b/backend/usb-unix.c index 81e20c524..d256a813b 100644 --- a/backend/usb-unix.c +++ b/backend/usb-unix.c @@ -214,21 +214,21 @@ list_devices(void) * for USB printer devices. We get the honor of trying them all... */ - sprintf(device, "/dev/usblp%d", i); + snprintf(device, sizeof(device), "/dev/usblp%d", i); if ((fd = open(device, O_RDWR | O_EXCL)) < 0) { if (errno != ENOENT) continue; - sprintf(device, "/dev/usb/lp%d", i); + snprintf(device, sizeof(device), "/dev/usb/lp%d", i); if ((fd = open(device, O_RDWR | O_EXCL)) < 0) { if (errno != ENOENT) continue; - sprintf(device, "/dev/usb/usblp%d", i); + snprintf(device, sizeof(device), "/dev/usb/usblp%d", i); if ((fd = open(device, O_RDWR | O_EXCL)) < 0) continue; @@ -258,7 +258,7 @@ list_devices(void) for (i = 0; i < 8; i ++) { - sprintf(device, "/dev/usb/printer%d", i); + snprintf(device, sizeof(device), "/dev/usb/printer%d", i); if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0) { @@ -278,11 +278,11 @@ list_devices(void) for (i = 0; i < 8; i ++) { - sprintf(device, "/dev/ulpt%d", i); + snprintf(device, sizeof(device), "/dev/ulpt%d", i); if (!access(device, 0)) printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1); - sprintf(device, "/dev/unlpt%d", i); + snprintf(device, sizeof(device), "/dev/unlpt%d", i); if (!access(device, 0)) printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1); } @@ -344,15 +344,15 @@ open_device(const char *uri, /* I - Device URI */ * for USB printer devices. We get the honor of trying them all... */ - sprintf(device, "/dev/usblp%d", i); + snprintf(device, sizeof(device), "/dev/usblp%d", i); if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT) { - sprintf(device, "/dev/usb/lp%d", i); + snprintf(device, sizeof(device), "/dev/usb/lp%d", i); if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT) { - sprintf(device, "/dev/usb/usblp%d", i); + snprintf(device, sizeof(device), "/dev/usb/usblp%d", i); if ((fd = open(device, O_RDWR | O_EXCL)) < 0 && errno == ENOENT) continue; @@ -440,7 +440,7 @@ open_device(const char *uri, /* I - Device URI */ { for (i = 0, busy = 0; i < 8; i ++) { - sprintf(device, "/dev/usb/printer%d", i); + snprintf(device, sizeof(device), "/dev/usb/printer%d", i); if ((fd = open(device, O_WRONLY | O_EXCL)) >= 0) backendGetDeviceID(fd, device_id, sizeof(device_id), diff --git a/berkeley/lpc.c b/berkeley/lpc.c index 7ab43ea12..7af10354f 100644 --- a/berkeley/lpc.c +++ b/berkeley/lpc.c @@ -21,6 +21,7 @@ static int compare_strings(const char *, const char *, size_t); static void do_command(http_t *, const char *, const char *); static void show_help(const char *); +static void show_prompt(const char *message); static void show_status(http_t *, const char *); @@ -59,7 +60,7 @@ main(int argc, /* I - Number of command-line arguments */ * Do the command prompt thing... */ - _cupsLangPuts(stdout, _("lpc> ")); /* TODO: Need no-newline version */ + show_prompt(_("lpc> ")); while (fgets(line, sizeof(line), stdin) != NULL) { /* @@ -87,7 +88,7 @@ main(int argc, /* I - Number of command-line arguments */ * Nothing left, just show a prompt... */ - _cupsLangPuts(stdout, _("lpc> ")); /* TODO: Need no newline version */ + show_prompt(_("lpc> ")); continue; } @@ -123,7 +124,7 @@ main(int argc, /* I - Number of command-line arguments */ * Put another prompt out to the user... */ - _cupsLangPuts(stdout, _("lpc> ")); /* TODO: Need no newline version */ + show_prompt(_("lpc> ")); } } @@ -200,6 +201,30 @@ show_help(const char *command) /* I - Command to describe or NULL */ } +/* + * 'show_prompt()' - Show a localized prompt message. + */ + +static void +show_prompt(const char *message) /* I - Message string to use */ +{ + ssize_t bytes; /* Number of bytes formatted */ + char output[8192]; /* Message buffer */ + cups_lang_t *lang = cupsLangDefault(); + /* Default language */ + + /* + * Transcode to the destination charset and write the prompt... + */ + + if ((bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)_cupsLangString(lang, message), sizeof(output), lang->encoding)) > 0) + { + fwrite(output, 1, (size_t)bytes, stdout); + fflush(stdout); + } +} + + /* * 'show_status()' - Show printers. */ diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c index f087809f7..57ae4e869 100644 --- a/cgi-bin/admin.c +++ b/cgi-bin/admin.c @@ -1,7 +1,7 @@ /* * Administration CGI for CUPS. * - * Copyright © 2007-2019 by Apple Inc. + * Copyright © 2007-2021 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -50,7 +50,6 @@ static void do_set_sharing(http_t *http); static char *get_option_value(ppd_file_t *ppd, const char *name, char *buffer, size_t bufsize); static double get_points(double number, const char *uval); -static char *get_printer_ppd(const char *uri, char *buffer, size_t bufsize); /* @@ -208,7 +207,7 @@ main(void) * bytes left in the array... */ - sprintf(ptr, "%%%02X", *url & 255); + snprintf(ptr, sizeof(encoded) - (size_t)(ptr - encoded), "%%%02X", *url & 255); ptr += 3; } else @@ -763,6 +762,13 @@ do_am_printer(http_t *http, /* I - HTTP connection */ cgiSetVariable("TEMPLATE_NAME", template); } + + /* + * Set DEVICE_URI to the actual device uri, without make and model from + * html form. + */ + + cgiSetVariable("DEVICE_URI", var); } } @@ -864,7 +870,7 @@ do_am_printer(http_t *http, /* I - HTTP connection */ break; else { - sprintf(baudrate, "%d", baudrates[i]); + snprintf(baudrate, sizeof(baudrate), "%d", baudrates[i]); cgiSetArray("BAUDRATES", i, baudrate); } @@ -1118,9 +1124,7 @@ do_am_printer(http_t *http, /* I - HTTP connection */ if (!file) { var = cgiGetVariable("PPD_NAME"); - if (!strcmp(var, "everywhere")) - get_printer_ppd(cgiGetVariable("DEVICE_URI"), evefile, sizeof(evefile)); - else if (strcmp(var, "__no_change__")) + if (strcmp(var, "__no_change__")) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", NULL, var); } @@ -3728,82 +3732,3 @@ get_points(double number, /* I - Original number */ else /* Points */ return (number); } - - -/* - * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI. - */ - -static char * /* O - Filename or NULL */ -get_printer_ppd(const char *uri, /* I - Printer URI */ - char *buffer, /* I - Filename buffer */ - size_t bufsize) /* I - Size of filename buffer */ -{ - http_t *http; /* Connection to printer */ - ipp_t *request, /* Get-Printer-Attributes request */ - *response; /* Get-Printer-Attributes response */ - char resolved[1024], /* Resolved URI */ - scheme[32], /* URI scheme */ - userpass[256], /* Username:password */ - host[256], /* Hostname */ - resource[256]; /* Resource path */ - int port; /* Port number */ - static const char * const pattrs[] = /* Printer attributes we need */ - { - "all", - "media-col-database" - }; - - - /* - * Connect to the printer... - */ - - if (strstr(uri, "._tcp")) - { - /* - * Resolve URI... - */ - - if (!_httpResolveURI(uri, resolved, sizeof(resolved), _HTTP_RESOLVE_DEFAULT, NULL, NULL)) - { - fprintf(stderr, "ERROR: Unable to resolve \"%s\".\n", uri); - return (NULL); - } - - uri = resolved; - } - - if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) - { - fprintf(stderr, "ERROR: Bad printer URI \"%s\".\n", uri); - return (NULL); - } - - http = httpConnect2(host, port, NULL, AF_UNSPEC, !strcmp(scheme, "ipps") ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL); - if (!http) - { - fprintf(stderr, "ERROR: Unable to connect to \"%s:%d\": %s\n", host, port, cupsLastErrorString()); - return (NULL); - } - - /* - * Send a Get-Printer-Attributes request... - */ - - request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); - ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs); - response = cupsDoRequest(http, request, resource); - - if (!_ppdCreateFromIPP(buffer, bufsize, response)) - fprintf(stderr, "ERROR: Unable to create PPD file: %s\n", strerror(errno)); - - ippDelete(response); - httpClose(http); - - if (buffer[0]) - return (buffer); - else - return (NULL); -} diff --git a/cgi-bin/classes.c b/cgi-bin/classes.c index 78ef08e22..718604ab2 100644 --- a/cgi-bin/classes.c +++ b/cgi-bin/classes.c @@ -362,7 +362,7 @@ show_all_classes(http_t *http, /* I - Connection to server */ if (first < 0) first = 0; - sprintf(val, "%d", count); + snprintf(val, sizeof(val), "%d", count); cgiSetVariable("TOTAL", val); for (i = 0, pclass = (ipp_attribute_t *)cupsArrayIndex(classes, first); @@ -378,13 +378,13 @@ show_all_classes(http_t *http, /* I - Connection to server */ if (first > 0) { - sprintf(val, "%d", first - CUPS_PAGE_MAX); + snprintf(val, sizeof(val), "%d", first - CUPS_PAGE_MAX); cgiSetVariable("PREV", val); } if ((first + CUPS_PAGE_MAX) < count) { - sprintf(val, "%d", first + CUPS_PAGE_MAX); + snprintf(val, sizeof(val), "%d", first + CUPS_PAGE_MAX); cgiSetVariable("NEXT", val); } diff --git a/cgi-bin/help-index.c b/cgi-bin/help-index.c index ce97e47a4..3da1010e6 100644 --- a/cgi-bin/help-index.c +++ b/cgi-bin/help-index.c @@ -579,7 +579,7 @@ helpSearchIndex(help_index_t *hi, /* I - Index */ */ for (; node; node = (help_node_t *)cupsArrayNext(hi->nodes)) - if (section && strcmp(node->section, section)) + if (node->section && section && strcmp(node->section, section)) continue; else if (filename && strcmp(node->filename, filename)) continue; diff --git a/cgi-bin/ipp-var.c b/cgi-bin/ipp-var.c index 8c5a5616d..443f920a5 100644 --- a/cgi-bin/ipp-var.c +++ b/cgi-bin/ipp-var.c @@ -224,7 +224,7 @@ cgiGetIPPObjects(ipp_t *response, /* I - IPP response */ char buf[255]; /* Number buffer */ - sprintf(buf, "%d", attr->values[i].integer); + snprintf(buf, sizeof(buf), "%d", attr->values[i].integer); if (cgiDoSearch(search, buf)) add = 1; @@ -291,7 +291,7 @@ cgiMoveJobs(http_t *http, /* I - Connection to server */ char temp[255]; /* Temporary string */ - sprintf(temp, "%d", job_id); + snprintf(temp, sizeof(temp), "%d", job_id); cgiSetVariable("JOB_ID", temp); } @@ -1441,7 +1441,7 @@ cgiShowJobs(http_t *http, /* I - Connection to server */ cgiSetVariable("SECTION", section); - sprintf(val, "%d", count); + snprintf(val, sizeof(val), "%d", count); cgiSetVariable("TOTAL", val); if (which_jobs) @@ -1469,13 +1469,13 @@ cgiShowJobs(http_t *http, /* I - Connection to server */ if (first > 0) { - sprintf(val, "%d", first - CUPS_PAGE_MAX); + snprintf(val, sizeof(val), "%d", first - CUPS_PAGE_MAX); cgiSetVariable("PREV", val); } if ((first + CUPS_PAGE_MAX) < count) { - sprintf(val, "%d", first + CUPS_PAGE_MAX); + snprintf(val, sizeof(val), "%d", first + CUPS_PAGE_MAX); cgiSetVariable("NEXT", val); } diff --git a/cgi-bin/printers.c b/cgi-bin/printers.c index bbc153e3b..2a33b6832 100644 --- a/cgi-bin/printers.c +++ b/cgi-bin/printers.c @@ -379,7 +379,7 @@ show_all_printers(http_t *http, /* I - Connection to server */ if (first < 0) first = 0; - sprintf(val, "%d", count); + snprintf(val, sizeof(val), "%d", count); cgiSetVariable("TOTAL", val); for (i = 0, printer = (ipp_attribute_t *)cupsArrayIndex(printers, first); @@ -395,13 +395,13 @@ show_all_printers(http_t *http, /* I - Connection to server */ if (first > 0) { - sprintf(val, "%d", first - CUPS_PAGE_MAX); + snprintf(val, sizeof(val), "%d", first - CUPS_PAGE_MAX); cgiSetVariable("PREV", val); } if ((first + CUPS_PAGE_MAX) < count) { - sprintf(val, "%d", first + CUPS_PAGE_MAX); + snprintf(val, sizeof(val), "%d", first + CUPS_PAGE_MAX); cgiSetVariable("NEXT", val); } diff --git a/cgi-bin/template.c b/cgi-bin/template.c index 1972b4ae2..3300a8852 100644 --- a/cgi-bin/template.c +++ b/cgi-bin/template.c @@ -33,7 +33,6 @@ cgiCopyTemplateFile(FILE *out, /* I - Output file */ { FILE *in; /* Input file */ - fprintf(stderr, "DEBUG2: cgiCopyTemplateFile(out=%p, tmpl=\"%s\")\n", out, tmpl ? tmpl : "(null)"); @@ -51,7 +50,7 @@ cgiCopyTemplateFile(FILE *out, /* I - Output file */ if ((in = fopen(tmpl, "r")) == NULL) { fprintf(stderr, "ERROR: Unable to open template file \"%s\" - %s\n", - tmpl ? tmpl : "(null)", strerror(errno)); + tmpl, strerror(errno)); return; } @@ -91,8 +90,6 @@ cgiCopyTemplateLang(const char *tmpl) /* I - Base filename */ * Convert the language to a locale name... */ - locale[0] = '\0'; - if ((lang = getenv("LANG")) != NULL) { locale[0] = '/'; @@ -101,6 +98,10 @@ cgiCopyTemplateLang(const char *tmpl) /* I - Base filename */ if ((locptr = strchr(locale, '.')) != NULL) *locptr = '\0'; /* Strip charset */ } + else + { + locale[0] = '\0'; + } fprintf(stderr, "DEBUG2: lang=\"%s\", locale=\"%s\"...\n", lang ? lang : "(null)", locale); @@ -307,9 +308,9 @@ cgi_copy(FILE *out, /* I - Output file */ */ if (name[1]) - sprintf(outval, "%d", cgiGetSize(name + 1)); + snprintf(outval, sizeof(outval), "%d", cgiGetSize(name + 1)); else - sprintf(outval, "%d", element + 1); + snprintf(outval, sizeof(outval), "%d", element + 1); outptr = outval; } @@ -457,7 +458,7 @@ cgi_copy(FILE *out, /* I - Output file */ continue; else if (ch == '#') { - sprintf(s, "%d", element + 1); + snprintf(s, sizeof(compare) - (size_t)(s - compare), "%d", element + 1); s += strlen(s); } else if (ch == '{') @@ -473,7 +474,7 @@ cgi_copy(FILE *out, /* I - Output file */ *innerptr = '\0'; if (innername[0] == '#') - sprintf(s, "%d", cgiGetSize(innername + 1)); + snprintf(s, sizeof(compare) - (size_t)(s - compare), "%d", cgiGetSize(innername + 1)); else if ((innerptr = strrchr(innername, '-')) != NULL && isdigit(innerptr[1] & 255)) { diff --git a/cgi-bin/var.c b/cgi-bin/var.c index 349a21845..c7289c721 100644 --- a/cgi-bin/var.c +++ b/cgi-bin/var.c @@ -1,7 +1,7 @@ /* * CGI form variable and array functions for CUPS. * - * Copyright © 2007-2019 by Apple Inc. + * Copyright © 2007-2020 by Apple Inc. * Copyright © 1997-2005 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -304,7 +304,7 @@ cgiInitialize(void) if (boundary) boundary += 9; - if (content_type && !strncmp(content_type, "multipart/form-data; ", 21)) + if (!strncmp(content_type, "multipart/form-data; ", 21)) { if (!cgi_initialize_multipart(boundary)) return (0); diff --git a/conf/cgi.types b/conf/cgi.types new file mode 100644 index 000000000..2c39b3f23 --- /dev/null +++ b/conf/cgi.types @@ -0,0 +1 @@ +application/x-httpd-cgi cgi php diff --git a/config-scripts/cups-compiler.m4 b/config-scripts/cups-compiler.m4 index 63ea1f470..604faf1b9 100644 --- a/config-scripts/cups-compiler.m4 +++ b/config-scripts/cups-compiler.m4 @@ -1,7 +1,7 @@ dnl dnl Compiler stuff for CUPS. dnl -dnl Copyright 2007-2018 by Apple Inc. +dnl Copyright 2007-2020 by Apple Inc. dnl Copyright 1997-2007 by Easy Software Products, all rights reserved. dnl dnl Licensed under Apache License v2.0. See the file "LICENSE" for more information. @@ -169,22 +169,20 @@ if test -n "$GCC"; then fi # Add useful warning options for tracking down problems... - WARNING_OPTIONS="-Wall -Wno-format-y2k -Wunused -Wno-unused-result -Wsign-conversion" + WARNING_OPTIONS="-Wall -Wno-format-y2k -Wunused -Wno-unused-result -Wsign-conversion -Wno-unused-but-set-variable -Wno-unused-variable" # Test GCC version for certain warning flags since -Werror # doesn't trigger... gccversion=`$CC --version | head -1 | awk '{print $NF}'` case "$gccversion" in - 1.* | 2.* | 3.* | 4.* | 5.* | 6.* | \(clang-*) - ;; - *) - WARNING_OPTIONS="$WARNING_OPTIONS -Wno-format-truncation -Wno-format-overflow -Wno-tautological-compare" + 7.* | 8.* | 9.*) + WARNING_OPTIONS="$WARNING_OPTIONS -Wno-format-truncation -Wno-tautological-compare" ;; esac # Additional warning options for development testing... if test -d .git; then - WARNING_OPTIONS="-Werror -Wno-error=deprecated-declarations $WARNING_OPTIONS" + WARNING_OPTIONS="-Werror -Wno-error=deprecated-declarations -Wno-unknown-warning-option $WARNING_OPTIONS" fi else # Add vendor-specific compiler options... diff --git a/configure b/configure index e06b17f59..642b3058d 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for CUPS 2.3.2. +# Generated by GNU Autoconf 2.69 for CUPS 2.3.6. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='CUPS' PACKAGE_TARNAME='cups' -PACKAGE_VERSION='2.3.2' -PACKAGE_STRING='CUPS 2.3.2' +PACKAGE_VERSION='2.3.6' +PACKAGE_STRING='CUPS 2.3.6' PACKAGE_BUGREPORT='https://github.com/apple/cups/issues' PACKAGE_URL='https://www.cups.org/' @@ -1467,7 +1467,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures CUPS 2.3.2 to adapt to many kinds of systems. +\`configure' configures CUPS 2.3.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1532,7 +1532,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of CUPS 2.3.2:";; + short | recursive ) echo "Configuration of CUPS 2.3.6:";; esac cat <<\_ACEOF @@ -1713,7 +1713,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -CUPS configure 2.3.2 +CUPS configure 2.3.6 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2177,7 +2177,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by CUPS $as_me 2.3.2, which was +It was created by CUPS $as_me 2.3.6, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2694,7 +2694,7 @@ done ac_config_headers="$ac_config_headers config.h" -CUPS_VERSION="2.3.2" +CUPS_VERSION="2.3.6" CUPS_REVISION="" CUPS_BUILD="cups-$CUPS_VERSION" @@ -6905,22 +6905,20 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi # Add useful warning options for tracking down problems... - WARNING_OPTIONS="-Wall -Wno-format-y2k -Wunused -Wno-unused-result -Wsign-conversion" + WARNING_OPTIONS="-Wall -Wno-format-y2k -Wunused -Wno-unused-result -Wsign-conversion -Wno-unused-but-set-variable -Wno-unused-variable" # Test GCC version for certain warning flags since -Werror # doesn't trigger... gccversion=`$CC --version | head -1 | awk '{print $NF}'` case "$gccversion" in - 1.* | 2.* | 3.* | 4.* | 5.* | 6.* | \(clang-*) - ;; - *) + 7.* | 8.* | 9.*) WARNING_OPTIONS="$WARNING_OPTIONS -Wno-format-truncation -Wno-format-overflow -Wno-tautological-compare" ;; esac # Additional warning options for development testing... if test -d .git; then - WARNING_OPTIONS="-Werror -Wno-error=deprecated-declarations $WARNING_OPTIONS" + WARNING_OPTIONS="-Werror -Wno-error=deprecated-declarations -Wno-unknown-warning-option $WARNING_OPTIONS" fi else # Add vendor-specific compiler options... @@ -10387,7 +10385,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by CUPS $as_me 2.3.2, which was +This file was extended by CUPS $as_me 2.3.6, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -10450,7 +10448,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -CUPS config.status 2.3.2 +CUPS config.status 2.3.6 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index eff353b7e..f8767969d 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ dnl dnl Configuration script for CUPS. dnl -dnl Copyright © 2007-2019 by Apple Inc. +dnl Copyright © 2007-2021 by Apple Inc. dnl Copyright © 1997-2007 by Easy Software Products, all rights reserved. dnl dnl Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -12,7 +12,7 @@ dnl We need at least autoconf 2.60... AC_PREREQ(2.60) dnl Package name and version... -AC_INIT([CUPS], [2.3.2], [https://github.com/apple/cups/issues], [cups], [https://www.cups.org/]) +AC_INIT([CUPS], [2.3.6], [https://github.com/apple/cups/issues], [cups], [https://www.cups.org/]) sinclude(config-scripts/cups-opsys.m4) sinclude(config-scripts/cups-common.m4) diff --git a/cups/auth.c b/cups/auth.c index db45bbba6..bff6d218f 100644 --- a/cups/auth.c +++ b/cups/auth.c @@ -90,6 +90,7 @@ static void cups_gss_printf(OM_uint32 major_status, OM_uint32 minor_status, # define cups_gss_printf(major, minor, message) # endif /* DEBUG */ #endif /* HAVE_GSSAPI */ +static int cups_is_local_connection(http_t *http); static int cups_local_auth(http_t *http); @@ -174,10 +175,10 @@ cupsDoAuthentication( DEBUG_printf(("2cupsDoAuthentication: Trying scheme \"%s\"...", scheme)); #ifdef HAVE_GSSAPI - if (!_cups_strcasecmp(scheme, "Negotiate")) + if (!_cups_strcasecmp(scheme, "Negotiate") && !cups_is_local_connection(http)) { /* - * Kerberos authentication... + * Kerberos authentication to remote server... */ int gss_status; /* Auth status */ @@ -201,7 +202,9 @@ cupsDoAuthentication( } else #endif /* HAVE_GSSAPI */ - if (_cups_strcasecmp(scheme, "Basic") && _cups_strcasecmp(scheme, "Digest")) + if (_cups_strcasecmp(scheme, "Basic") && + _cups_strcasecmp(scheme, "Digest") && + _cups_strcasecmp(scheme, "Negotiate")) { /* * Other schemes not yet supported... @@ -215,7 +218,7 @@ cupsDoAuthentication( * See if we should retry the current username:password... */ - if ((http->digest_tries > 1 || !http->userpass[0]) && (!_cups_strcasecmp(scheme, "Basic") || (!_cups_strcasecmp(scheme, "Digest")))) + if (http->digest_tries > 1 || !http->userpass[0]) { /* * Nope - get a new password from the user... @@ -295,7 +298,7 @@ cupsDoAuthentication( } } - if (http->authstring) + if (http->authstring && http->authstring[0]) { DEBUG_printf(("1cupsDoAuthentication: authstring=\"%s\".", http->authstring)); @@ -327,10 +330,6 @@ _cupsSetNegotiateAuthString( gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; /* Output token */ - - (void)method; - (void)resource; - # ifdef __APPLE__ /* * If the weak-linked GSSAPI/Kerberos library is not present, don't try @@ -447,6 +446,9 @@ _cupsSetNegotiateAuthString( } } } +# else + (void)method; + (void)resource; # endif /* HAVE_GSS_ACQUIRED_CRED_EX_F */ if (major_status == GSS_S_NO_CRED) @@ -559,9 +561,9 @@ cups_auth_find(const char *www_authenticate, /* I - Pointer into WWW-Authenticat * Skip quoted value... */ - www_authenticate ++; - while (*www_authenticate && *www_authenticate != '\"') + do www_authenticate ++; + while (*www_authenticate && *www_authenticate != '\"'); DEBUG_printf(("9cups_auth_find: After quoted: \"%s\"", www_authenticate)); } @@ -916,6 +918,14 @@ cups_gss_printf(OM_uint32 major_status,/* I - Major status code */ # endif /* DEBUG */ #endif /* HAVE_GSSAPI */ +static int /* O - 0 if not a local connection */ + /* 1 if local connection */ +cups_is_local_connection(http_t *http) /* I - HTTP connection to server */ +{ + if (!httpAddrLocalhost(http->hostaddr) && _cups_strcasecmp(http->hostname, "localhost") != 0) + return 0; + return 1; +} /* * 'cups_local_auth()' - Get the local authorization certificate if @@ -958,7 +968,7 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ * See if we are accessing localhost... */ - if (!httpAddrLocalhost(http->hostaddr) && _cups_strcasecmp(http->hostname, "localhost") != 0) + if (!cups_is_local_connection(http)) { DEBUG_puts("8cups_local_auth: Not a local connection!"); return (1); @@ -1032,11 +1042,6 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ } # endif /* HAVE_AUTHORIZATION_H */ -# ifdef HAVE_GSSAPI - if (cups_auth_find(www_auth, "Negotiate")) - return (1); -# endif /* HAVE_GSSAPI */ - # if defined(SO_PEERCRED) && defined(AF_LOCAL) /* * See if we can authenticate using the peer credentials provided over a diff --git a/cups/cups.h b/cups/cups.h index 6d48141e5..bdf9f7a18 100644 --- a/cups/cups.h +++ b/cups/cups.h @@ -1,7 +1,7 @@ /* * API definitions for CUPS. * - * Copyright © 2007-2019 by Apple Inc. + * Copyright © 2007-2022 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products. * * Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -42,10 +42,10 @@ extern "C" { * Constants... */ -# define CUPS_VERSION 2.0302 +# define CUPS_VERSION 2.0306 # define CUPS_VERSION_MAJOR 2 # define CUPS_VERSION_MINOR 3 -# define CUPS_VERSION_PATCH 2 +# define CUPS_VERSION_PATCH 6 # define CUPS_BC_FD 3 /* Back-channel file descriptor for diff --git a/cups/cupspm.md b/cups/cupspm.md index d4d6d7c55..7e03c3d65 100644 --- a/cups/cupspm.md +++ b/cups/cupspm.md @@ -1,8 +1,8 @@ --- title: CUPS Programming Manual author: Michael R Sweet -copyright: Copyright © 2007-2019 by Apple Inc. All Rights Reserved. -version: 2.3.1 +copyright: Copyright © 2007-2022 by Apple Inc. All Rights Reserved. +version: 2.3.6 ... > Please [file issues on Github](https://github.com/apple/cups/issues) to diff --git a/cups/dest.c b/cups/dest.c index cde987a09..984c6bddf 100644 --- a/cups/dest.c +++ b/cups/dest.c @@ -271,7 +271,11 @@ cupsAddDest(const char *name, /* I - Destination name */ if (!cupsGetDest(name, instance, num_dests, *dests)) { if (instance && !cupsGetDest(name, NULL, num_dests, *dests)) - return (num_dests); + { + // Add destination first... + if ((dest = cups_add_dest(name, NULL, &num_dests, dests)) == NULL) + return (num_dests); + } if ((dest = cups_add_dest(name, instance, &num_dests, dests)) == NULL) return (num_dests); @@ -1839,7 +1843,10 @@ cupsGetNamedDest(http_t *http, /* I - Connection to server or @code CUPS_HTT cupsEnumDests(0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_name_cb, &data); if (!data.dest) + { + _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, _("The printer or class does not exist."), 1); return (NULL); + } dest = data.dest; } @@ -3376,7 +3383,7 @@ cups_enum_dests( cups_dest_cb_t cb, /* I - Callback function */ void *user_data) /* I - User data */ { - int i, j, /* Looping vars */ + int i, j, k, /* Looping vars */ num_dests; /* Number of destinations */ cups_dest_t *dests = NULL, /* Destinations */ *dest; /* Current destination */ @@ -3521,17 +3528,31 @@ cups_enum_dests( const char *device_uri; /* Device URI */ #endif /* HAVE_DNSSD || HAVE_AVAHI */ - if ((user_dest = cupsGetDest(dest->name, dest->instance, data.num_dests, data.dests)) != NULL) + if ((user_dest = cupsGetDest(dest->name, NULL, data.num_dests, data.dests)) != NULL) { /* - * Apply user defaults to this destination... + * Apply user defaults to this destination for all instances... */ - for (j = user_dest->num_options, option = user_dest->options; j > 0; j --, option ++) - dest->num_options = cupsAddOption(option->name, option->value, dest->num_options, &dest->options); - } + for (j = user_dest - data.dests; j < data.num_dests; j ++, user_dest ++) + { + if (_cups_strcasecmp(user_dest->name, dest->name)) + { + j = data.num_dests; + break; + } - if (!(*cb)(user_data, i > 1 ? CUPS_DEST_FLAGS_MORE : CUPS_DEST_FLAGS_NONE, dest)) + for (k = dest->num_options, option = dest->options; k > 0; k --, option ++) + user_dest->num_options = cupsAddOption(option->name, option->value, user_dest->num_options, &user_dest->options); + + if (!(*cb)(user_data, i > 1 ? CUPS_DEST_FLAGS_MORE : CUPS_DEST_FLAGS_NONE, user_dest)) + break; + } + + if (j < data.num_dests) + break; + } + else if (!(*cb)(user_data, i > 1 ? CUPS_DEST_FLAGS_MORE : CUPS_DEST_FLAGS_NONE, dest)) break; #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) @@ -3794,25 +3815,45 @@ cups_enum_dests( if ((user_dest = cupsGetDest(dest->name, dest->instance, data.num_dests, data.dests)) != NULL) { /* - * Apply user defaults to this destination... + * Apply user defaults to this destination for all instances... */ - for (j = user_dest->num_options, option = user_dest->options; j > 0; j --, option ++) - dest->num_options = cupsAddOption(option->name, option->value, dest->num_options, &dest->options); - } + for (j = user_dest - data.dests; j < data.num_dests; j ++, user_dest ++) + { + if (_cups_strcasecmp(user_dest->name, dest->name)) + { + j = data.num_dests; + break; + } - if (!strcasecmp(dest->name, data.def_name) && !data.def_instance) - { - DEBUG_printf(("1cups_enum_dests: Setting is_default on discovered \"%s\".", dest->name)); - dest->is_default = 1; + for (k = dest->num_options, option = dest->options; k > 0; k --, option ++) + user_dest->num_options = cupsAddOption(option->name, option->value, user_dest->num_options, &user_dest->options); + + if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, user_dest)) + break; + } + + if (j < data.num_dests) + { + remaining = -1; + break; + } } + else + { + if (!strcasecmp(dest->name, data.def_name) && !data.def_instance) + { + DEBUG_printf(("1cups_enum_dests: Setting is_default on discovered \"%s\".", dest->name)); + dest->is_default = 1; + } - DEBUG_printf(("1cups_enum_dests: Add callback for \"%s\".", device->dest.name)); - if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, dest)) - { - remaining = -1; - break; - } + DEBUG_printf(("1cups_enum_dests: Add callback for \"%s\".", device->dest.name)); + if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, dest)) + { + remaining = -1; + break; + } + } } device->state = _CUPS_DNSSD_ACTIVE; @@ -4183,7 +4224,7 @@ cups_get_dests( * Out of memory! */ - DEBUG_puts("9cups_get_dests: Out of memory!"); + DEBUG_puts("9cups_get_dests: Could not find destination after adding, must be out of memory."); break; } } @@ -4366,5 +4407,13 @@ cups_queue_name( *nameptr++ = '_'; } + /* + * Remove an underscore if it is the last character and isn't the only + * character in the name... + */ + + if (nameptr > (name + 1) && nameptr[-1] == '_') + nameptr --; + *nameptr = '\0'; } diff --git a/cups/getdevices.c b/cups/getdevices.c index de2186f5f..a35540640 100644 --- a/cups/getdevices.c +++ b/cups/getdevices.c @@ -246,20 +246,14 @@ cupsGetDevices( httpBlocking(http, blocking); httpFlush(http); - if (status == HTTP_STATUS_ERROR) - _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(http->error), 0); - else - { - attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT); + attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT); - DEBUG_printf(("cupsGetDevices: status-code=%s, status-message=\"%s\"", - ippErrorString(response->request.status.status_code), - attr ? attr->values[0].string.text : "")); + DEBUG_printf(("cupsGetDevices: status-code=%s, status-message=\"%s\"", + ippErrorString(response->request.status.status_code), + attr ? attr->values[0].string.text : "")); - _cupsSetError(response->request.status.status_code, - attr ? attr->values[0].string.text : - ippErrorString(response->request.status.status_code), 0); - } + _cupsSetError(response->request.status.status_code, + attr ? attr->values[0].string.text : ippErrorString(response->request.status.status_code), 0); ippDelete(response); diff --git a/cups/getifaddrs-internal.h b/cups/getifaddrs-internal.h index 35e98be77..4e20f73d9 100644 --- a/cups/getifaddrs-internal.h +++ b/cups/getifaddrs-internal.h @@ -25,6 +25,7 @@ # include # include # include +# include # define CUPS_SOCAST # endif /* _WIN32 */ diff --git a/cups/hash.c b/cups/hash.c index 4fbb443db..c153c6655 100644 --- a/cups/hash.c +++ b/cups/hash.c @@ -199,7 +199,7 @@ cupsHashData(const char *algorithm, /* I - Algorithm name */ goto too_small; _cupsMD5Init(&state); - _cupsMD5Append(&state, data, datalen); + _cupsMD5Append(&state, data, (int)datalen); _cupsMD5Finish(&state, hash); return (16); diff --git a/cups/http-addr.c b/cups/http-addr.c index 86749c848..8e81c6f7d 100644 --- a/cups/http-addr.c +++ b/cups/http-addr.c @@ -243,7 +243,7 @@ httpAddrListen(http_addr_t *addr, /* I - Address to bind to */ * Listen... */ - if (listen(fd, 5)) + if (listen(fd, 128)) { _cupsSetHTTPError(HTTP_STATUS_ERROR); diff --git a/cups/http-addrlist.c b/cups/http-addrlist.c index 485c6f43d..89b3d92fb 100644 --- a/cups/http-addrlist.c +++ b/cups/http-addrlist.c @@ -238,7 +238,14 @@ httpAddrConnect2( } if (!addrlist && nfds == 0) + { +#ifdef _WIN32 + errno = WSAEHOSTDOWN; +#else + errno = EHOSTDOWN; +#endif // _WIN32 break; + } /* * See if we can connect to any of the addresses so far... @@ -369,6 +376,9 @@ httpAddrConnect2( remaining -= 250; } + if (remaining <= 0) + errno = ETIMEDOUT; + while (nfds > 0) { nfds --; diff --git a/cups/http-support.c b/cups/http-support.c index 63175145e..49557300e 100644 --- a/cups/http-support.c +++ b/cups/http-support.c @@ -840,6 +840,13 @@ httpGetDateTime(const char *s) /* I - Date/time string */ DEBUG_printf(("4httpGetDateTime: day=%d, mon=\"%s\", year=%d, hour=%d, " "min=%d, sec=%d", day, mon, year, hour, min, sec)); + /* + * Check for invalid year (RFC 7231 says it's 4DIGIT) + */ + + if (year > 9999) + return (0); + /* * Convert the month name to a number from 0 to 11. */ diff --git a/cups/http.c b/cups/http.c index 8d69ce31f..43ace18f4 100644 --- a/cups/http.c +++ b/cups/http.c @@ -1,7 +1,7 @@ /* * HTTP routines for CUPS. * - * Copyright © 2007-2019 by Apple Inc. + * Copyright © 2007-2021 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by @@ -2421,6 +2421,7 @@ httpReconnect2(http_t *http, /* I - HTTP connection */ if (_httpTLSStart(http) != 0) { httpAddrClose(NULL, http->fd); + http->fd = -1; return (-1); } @@ -2786,6 +2787,7 @@ _httpUpdate(http_t *http, /* I - HTTP connection */ if (_httpTLSStart(http) != 0) { httpAddrClose(NULL, http->fd); + http->fd = -1; *status = http->status = HTTP_STATUS_ERROR; return (0); diff --git a/cups/http.h b/cups/http.h index 01a0321df..45761a7ca 100644 --- a/cups/http.h +++ b/cups/http.h @@ -346,7 +346,7 @@ typedef enum http_trust_e /**** Level of trust for credentials @since CUPS 2.0/ HTTP_TRUST_CHANGED, /* Credentials have changed */ HTTP_TRUST_EXPIRED, /* Credentials are expired */ HTTP_TRUST_RENEWED, /* Credentials have been renewed */ - HTTP_TRUST_UNKNOWN, /* Credentials are unknown/new */ + HTTP_TRUST_UNKNOWN /* Credentials are unknown/new */ } http_trust_t; typedef enum http_uri_status_e /**** URI separation status @since CUPS 1.2@ ****/ diff --git a/cups/ipp-file.c b/cups/ipp-file.c index 5db5932a4..5483a607d 100644 --- a/cups/ipp-file.c +++ b/cups/ipp-file.c @@ -303,10 +303,7 @@ _ippFileReadToken(_ipp_file_t *f, /* I - File to read from */ * Start of quoted text or regular expression... */ - if (ch == '<') - quote = '>'; - else - quote = ch; + quote = ch; DEBUG_printf(("1_ippFileReadToken: Start of quoted string, quote=%c, pos=%ld", quote, (long)cupsFileTell(f->fp))); } @@ -571,12 +568,10 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ { case IPP_TAG_BOOLEAN : return (ippSetBoolean(ipp, attr, element, !_cups_strcasecmp(value, "true"))); - break; case IPP_TAG_ENUM : case IPP_TAG_INTEGER : return (ippSetInteger(ipp, attr, element, (int)strtol(value, NULL, 0))); - break; case IPP_TAG_DATE : { @@ -690,7 +685,6 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ return (ippSetDate(ipp, attr, element, date)); } - break; case IPP_TAG_RESOLUTION : { @@ -718,7 +712,6 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ else return (ippSetResolution(ipp, attr, element, (ipp_res_t)0, xres, yres)); } - break; case IPP_TAG_RANGE : { @@ -733,7 +726,6 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ return (ippSetRange(ipp, attr, element, lower, upper)); } - break; case IPP_TAG_STRING : valuelen = strlen(value); @@ -774,7 +766,6 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ } else return (ippSetOctetString(ipp, attr, element, value, (int)valuelen)); - break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : @@ -787,7 +778,6 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : return (ippSetString(ipp, attr, element, value)); - break; case IPP_TAG_BEGIN_COLLECTION : { @@ -808,14 +798,11 @@ parse_value(_ipp_file_t *f, /* I - IPP data file */ return (status); } - break; default : report_error(f, v, user_data, "Unsupported value on line %d of \"%s\".", f->linenum, f->filename); return (0); } - - return (1); } diff --git a/cups/ipp-support.c b/cups/ipp-support.c index bfb9dff09..d9e900649 100644 --- a/cups/ipp-support.c +++ b/cups/ipp-support.c @@ -2262,7 +2262,7 @@ ippErrorString(ipp_status_t error) /* I - Error status */ * No, build an "0xxxxx" error string... */ - sprintf(cg->ipp_unknown, "0x%04x", error); + snprintf(cg->ipp_unknown, sizeof(cg->ipp_unknown), "0x%04x", error); return (cg->ipp_unknown); } @@ -2339,7 +2339,7 @@ ippOpString(ipp_op_t op) /* I - Operation ID */ * No, build an "0xxxxx" operation string... */ - sprintf(cg->ipp_unknown, "0x%04x", op); + snprintf(cg->ipp_unknown, sizeof(cg->ipp_unknown), "0x%04x", op); return (cg->ipp_unknown); } diff --git a/cups/ipp-vars.c b/cups/ipp-vars.c index 395b0ebf3..69efbd9aa 100644 --- a/cups/ipp-vars.c +++ b/cups/ipp-vars.c @@ -12,7 +12,7 @@ * Include necessary headers... */ -#include +#include "cups-private.h" #include "ipp-private.h" #include "string-private.h" #include "debug-internal.h" @@ -220,10 +220,22 @@ _ippVarsSet(_ipp_vars_t *v, /* I - IPP variables */ { if (!strcmp(name, "uri")) { - char uri[1024]; /* New printer URI */ - http_uri_status_t uri_status; /* URI status */ + char uri[1024]; /* New printer URI */ + char resolved[1024]; /* Resolved mDNS URI */ - if ((uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, value, v->scheme, sizeof(v->scheme), v->username, sizeof(v->username), v->host, sizeof(v->host), &(v->port), v->resource, sizeof(v->resource))) < HTTP_URI_STATUS_OK) + if (strstr(value, "._tcp")) + { + /* + * Resolve URI... + */ + + if (!_httpResolveURI(value, resolved, sizeof(resolved), _HTTP_RESOLVE_DEFAULT, NULL, NULL)) + return (0); + + value = resolved; + } + + if (httpSeparateURI(HTTP_URI_CODING_ALL, value, v->scheme, sizeof(v->scheme), v->username, sizeof(v->username), v->host, sizeof(v->host), &(v->port), v->resource, sizeof(v->resource)) < HTTP_URI_STATUS_OK) return (0); if (v->username[0]) diff --git a/cups/ipp.c b/cups/ipp.c index 1595b8b61..42cf2fcaf 100644 --- a/cups/ipp.c +++ b/cups/ipp.c @@ -1,7 +1,7 @@ /* * Internet Printing Protocol functions for CUPS. * - * Copyright © 2007-2019 by Apple Inc. + * Copyright © 2007-2021 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -2866,8 +2866,9 @@ ippReadIO(void *src, /* I - Data source */ unsigned char *buffer, /* Data buffer */ string[IPP_MAX_TEXT], /* Small string buffer */ - *bufptr; /* Pointer into buffer */ - ipp_attribute_t *attr; /* Current attribute */ + *bufptr, /* Pointer into buffer */ + *bufend; /* End of buffer */ + ipp_attribute_t *attr = NULL; /* Current attribute */ ipp_tag_t tag; /* Current tag */ ipp_tag_t value_tag; /* Current value tag */ _ipp_value_t *value; /* Current value */ @@ -2900,8 +2901,7 @@ ippReadIO(void *src, /* I - Data source */ if ((*cb)(src, buffer, 8) < 8) { DEBUG_puts("1ippReadIO: Unable to read header."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } /* @@ -2939,8 +2939,7 @@ ippReadIO(void *src, /* I - Data source */ if ((*cb)(src, buffer, 1) < 1) { DEBUG_puts("1ippReadIO: Callback returned EOF/error"); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev)); @@ -2956,11 +2955,10 @@ ippReadIO(void *src, /* I - Data source */ * Read 32-bit "extension" tag... */ - if ((*cb)(src, buffer, 4) < 1) + if ((*cb)(src, buffer, 4) < 4) { DEBUG_puts("1ippReadIO: Callback returned EOF/error"); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } tag = (ipp_tag_t)((((((buffer[0] << 8) | buffer[1]) << 8) | @@ -2974,8 +2972,7 @@ ippReadIO(void *src, /* I - Data source */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP extension tag larger than 0x7FFFFFFF."), 1); DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } } @@ -2994,8 +2991,7 @@ ippReadIO(void *src, /* I - Data source */ { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid group tag."), 1); DEBUG_printf(("1ippReadIO: bad tag 0x%02x.", tag)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } else if (tag < IPP_TAG_UNSUPPORTED_VALUE) { @@ -3003,13 +2999,20 @@ ippReadIO(void *src, /* I - Data source */ * Group tag... Set the current group and continue... */ - if (ipp->curtag == tag) + if (parent) + { + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid group tag."), 1); + DEBUG_printf(("1ippReadIO: bad tag 0x%02x.", tag)); + goto rollback; + } + else if (ipp->curtag == tag) ipp->prev = ippAddSeparator(ipp); else if (ipp->current) ipp->prev = ipp->current; ipp->curtag = tag; ipp->current = NULL; + attr = NULL; DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag, ippTagString(tag), (void *)ipp->prev)); continue; } @@ -3024,8 +3027,7 @@ ippReadIO(void *src, /* I - Data source */ if ((*cb)(src, buffer, 2) < 2) { DEBUG_puts("1ippReadIO: unable to read name length."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } n = (buffer[0] << 8) | buffer[1]; @@ -3034,8 +3036,7 @@ ippReadIO(void *src, /* I - Data source */ { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP name larger than 32767 bytes."), 1); DEBUG_printf(("1ippReadIO: bad name length %d.", n)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } DEBUG_printf(("2ippReadIO: name length=%d", n)); @@ -3044,7 +3045,7 @@ ippReadIO(void *src, /* I - Data source */ { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid named IPP attribute in collection."), 1); DEBUG_puts("1ippReadIO: bad attribute name in collection."); - return (IPP_STATE_ERROR); + goto rollback; } else if (n == 0 && tag != IPP_TAG_MEMBERNAME && tag != IPP_TAG_END_COLLECTION) { @@ -3056,8 +3057,7 @@ ippReadIO(void *src, /* I - Data source */ { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute has no name."), 1); DEBUG_puts("1ippReadIO: Attribute without name and no current."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } attr = ipp->current; @@ -3096,8 +3096,7 @@ ippReadIO(void *src, /* I - Data source */ DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)", value_tag, ippTagString(value_tag), tag, ippTagString(tag))); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } if (value_tag != tag) @@ -3123,8 +3122,7 @@ ippReadIO(void *src, /* I - Data source */ DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)", value_tag, ippTagString(value_tag), tag, ippTagString(tag))); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } if (value_tag == IPP_TAG_INTEGER && tag == IPP_TAG_RANGE) @@ -3146,8 +3144,7 @@ ippReadIO(void *src, /* I - Data source */ DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)", value_tag, ippTagString(value_tag), tag, ippTagString(tag))); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } /* @@ -3155,10 +3152,7 @@ ippReadIO(void *src, /* I - Data source */ */ if ((value = ipp_set_value(ipp, &attr, attr->num_values)) == NULL) - { - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); - } + goto rollback; } else if (tag == IPP_TAG_MEMBERNAME) { @@ -3170,8 +3164,13 @@ ippReadIO(void *src, /* I - Data source */ { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member name is not empty."), 1); DEBUG_puts("1ippReadIO: member name not empty."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; + } + else if (!parent) + { + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member attribute outside of collection."), 1); + DEBUG_puts("1ippReadIO: member attribute outside of collection."); + goto rollback; } if (ipp->current) @@ -3182,8 +3181,7 @@ ippReadIO(void *src, /* I - Data source */ { _cupsSetHTTPError(HTTP_STATUS_ERROR); DEBUG_puts("1ippReadIO: unable to allocate attribute."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev)); @@ -3199,8 +3197,7 @@ ippReadIO(void *src, /* I - Data source */ if ((*cb)(src, buffer, (size_t)n) < n) { DEBUG_puts("1ippReadIO: unable to read name."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } buffer[n] = '\0'; @@ -3213,8 +3210,7 @@ ippReadIO(void *src, /* I - Data source */ { _cupsSetHTTPError(HTTP_STATUS_ERROR); DEBUG_puts("1ippReadIO: unable to allocate attribute."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, ipp->prev=%p", buffer, (void *)ipp->current, (void *)ipp->prev)); @@ -3230,8 +3226,7 @@ ippReadIO(void *src, /* I - Data source */ if ((*cb)(src, buffer, 2) < 2) { DEBUG_puts("1ippReadIO: unable to read value length."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } n = (buffer[0] << 8) | buffer[1]; @@ -3242,8 +3237,7 @@ ippReadIO(void *src, /* I - Data source */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP value larger than 32767 bytes."), 1); DEBUG_printf(("1ippReadIO: bad value length %d.", n)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } switch (tag) @@ -3259,15 +3253,13 @@ ippReadIO(void *src, /* I - Data source */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP enum value not 4 bytes."), 1); DEBUG_printf(("1ippReadIO: bad integer value length %d.", n)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } if ((*cb)(src, buffer, 4) < 4) { DEBUG_puts("1ippReadIO: Unable to read integer value."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | @@ -3285,15 +3277,13 @@ ippReadIO(void *src, /* I - Data source */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP boolean value not 1 byte."), 1); DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } if ((*cb)(src, buffer, 1) < 1) { DEBUG_puts("1ippReadIO: Unable to read boolean value."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } value->boolean = (char)buffer[0]; @@ -3334,8 +3324,7 @@ ippReadIO(void *src, /* I - Data source */ if ((*cb)(src, buffer, (size_t)n) < n) { DEBUG_puts("1ippReadIO: unable to read string value."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } } @@ -3349,15 +3338,13 @@ ippReadIO(void *src, /* I - Data source */ { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP date value not 11 bytes."), 1); DEBUG_printf(("1ippReadIO: bad date value length %d.", n)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } if ((*cb)(src, value->date, 11) < 11) { DEBUG_puts("1ippReadIO: Unable to read date value."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } break; @@ -3367,15 +3354,13 @@ ippReadIO(void *src, /* I - Data source */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP resolution value not 9 bytes."), 1); DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } if ((*cb)(src, buffer, 9) < 9) { DEBUG_puts("1ippReadIO: Unable to read resolution value."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } value->resolution.xres = @@ -3395,15 +3380,13 @@ ippReadIO(void *src, /* I - Data source */ _("IPP rangeOfInteger value not 8 bytes."), 1); DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length " "%d.", n)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } if ((*cb)(src, buffer, 8) < 8) { DEBUG_puts("1ippReadIO: Unable to read range value."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } value->range.lower = @@ -3428,19 +3411,18 @@ ippReadIO(void *src, /* I - Data source */ "minimum 4 bytes."), 1); DEBUG_printf(("1ippReadIO: bad stringWithLanguage value " "length %d.", n)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } if ((*cb)(src, buffer, (size_t)n) < n) { DEBUG_puts("1ippReadIO: Unable to read string w/language " "value."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } bufptr = buffer; + bufend = buffer + n; /* * text-with-language and name-with-language are composite @@ -3454,14 +3436,13 @@ ippReadIO(void *src, /* I - Data source */ n = (bufptr[0] << 8) | bufptr[1]; - if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) || n >= (int)sizeof(string)) + if ((bufptr + 2 + n + 2) > bufend || n >= (int)sizeof(string)) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP language length overflows value."), 1); DEBUG_printf(("1ippReadIO: bad language value length %d.", n)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } else if (n >= IPP_MAX_LANGUAGE) { @@ -3469,8 +3450,7 @@ ippReadIO(void *src, /* I - Data source */ _("IPP language length too large."), 1); DEBUG_printf(("1ippReadIO: bad language value length %d.", n)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } memcpy(string, bufptr + 2, (size_t)n); @@ -3481,13 +3461,12 @@ ippReadIO(void *src, /* I - Data source */ bufptr += 2 + n; n = (bufptr[0] << 8) | bufptr[1]; - if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE)) + if ((bufptr + 2 + n) > bufend) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP string length overflows value."), 1); DEBUG_printf(("1ippReadIO: bad string value length %d.", n)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } bufptr[2 + n] = '\0'; @@ -3507,30 +3486,28 @@ ippReadIO(void *src, /* I - Data source */ _("IPP begCollection value not 0 bytes."), 1); DEBUG_puts("1ippReadIO: begCollection tag with value length " "> 0."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_STATE_ERROR) { DEBUG_puts("1ippReadIO: Unable to read collection value."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } break; case IPP_TAG_END_COLLECTION : - _cupsBufferRelease((char *)buffer); - if (n > 0) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP endCollection value not 0 bytes."), 1); DEBUG_puts("1ippReadIO: endCollection tag with value length " "> 0."); - return (IPP_STATE_ERROR); + goto rollback; } + _cupsBufferRelease((char *)buffer); + DEBUG_puts("1ippReadIO: endCollection tag..."); return (ipp->state = IPP_STATE_DATA); @@ -3545,22 +3522,19 @@ ippReadIO(void *src, /* I - Data source */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP memberName with no attribute."), 1); DEBUG_puts("1ippReadIO: Member name without attribute."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } else if (n == 0) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP memberName value is empty."), 1); DEBUG_puts("1ippReadIO: Empty member name value."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } else if ((*cb)(src, buffer, (size_t)n) < n) { DEBUG_puts("1ippReadIO: Unable to read member name value."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } buffer[n] = '\0'; @@ -3585,8 +3559,7 @@ ippReadIO(void *src, /* I - Data source */ _("IPP octetString length too large."), 1); DEBUG_printf(("1ippReadIO: bad octetString value length %d.", n)); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } value->unknown.length = n; @@ -3597,15 +3570,13 @@ ippReadIO(void *src, /* I - Data source */ { _cupsSetHTTPError(HTTP_STATUS_ERROR); DEBUG_puts("1ippReadIO: Unable to allocate value"); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } if ((*cb)(src, value->unknown.data, (size_t)n) < n) { DEBUG_puts("1ippReadIO: Unable to read unsupported value."); - _cupsBufferRelease((char *)buffer); - return (IPP_STATE_ERROR); + goto rollback; } } else @@ -3633,6 +3604,17 @@ ippReadIO(void *src, /* I - Data source */ _cupsBufferRelease((char *)buffer); return (ipp->state); + + // If we get here, there was an error that required us to roll back the last + // attribute read in order to keep the IPP message valid... + rollback: + + _cupsBufferRelease((char *)buffer); + + if (attr) + ippDeleteAttribute(ipp, attr); + + return (IPP_STATE_ERROR); } diff --git a/cups/options.c b/cups/options.c index 11814c9af..e45858c2c 100644 --- a/cups/options.c +++ b/cups/options.c @@ -603,16 +603,15 @@ _cupsGet1284Values( if (ptr < (value + sizeof(value) - 1)) *ptr++ = *device_id; - if (!*device_id) - break; - while (ptr > value && _cups_isspace(ptr[-1])) ptr --; *ptr = '\0'; - device_id ++; - num_values = cupsAddOption(key, value, num_values, values); + + if (!*device_id) + break; + device_id ++; } return (num_values); diff --git a/cups/ppd-cache.c b/cups/ppd-cache.c index 5965e382b..091f39f3c 100644 --- a/cups/ppd-cache.c +++ b/cups/ppd-cache.c @@ -78,8 +78,11 @@ _cupsConvertOptions( int num_finishings = 0, /* Number of finishing values */ finishings[10]; /* Finishing enum values */ ppd_choice_t *choice; /* Marked choice */ - int finishings_copies = copies; + int finishings_copies = copies, /* Number of copies for finishings */ + job_pages = 0, /* job-pages value */ + number_up = 1; /* number-up value */ + const char *value; /* Option value */ /* @@ -365,6 +368,28 @@ _cupsConvertOptions( * Map finishing options... */ + if (copies != finishings_copies) + { + // Figure out the proper job-pages-per-set value... + if ((value = cupsGetOption("job-pages", num_options, options)) == NULL) + value = cupsGetOption("com.apple.print.PrintSettings.PMTotalBeginPages..n.", num_options, options); + + if (value) + job_pages = atoi(value); + + // Adjust for number-up + if ((value = cupsGetOption("number-up", num_options, options)) != NULL) + number_up = atoi(value); + + job_pages = (job_pages + number_up - 1) / number_up; + + // When duplex printing, raster data will include an extra (blank) page to + // make the total number of pages even. Make sure this is reflected in the + // page count... + if ((job_pages & 1) && (keyword = cupsGetOption("sides", num_options, options)) != NULL && strcmp(keyword, "one-sided")) + job_pages ++; + } + if ((finishing_template = cupsGetOption("cupsFinishingTemplate", num_options, options)) == NULL) finishing_template = cupsGetOption("finishing-template", num_options, options); @@ -376,13 +401,13 @@ _cupsConvertOptions( ippAddCollection(request, IPP_TAG_JOB, "finishings-col", fin_col); ippDelete(fin_col); - if (copies != finishings_copies && (keyword = cupsGetOption("job-impressions", num_options, options)) != NULL) + if (copies != finishings_copies && job_pages > 0) { /* * Send job-pages-per-set attribute to apply finishings correctly... */ - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", atoi(keyword) / finishings_copies); + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", job_pages); } } else @@ -392,13 +417,13 @@ _cupsConvertOptions( { ippAddIntegers(request, IPP_TAG_JOB, IPP_TAG_ENUM, "finishings", num_finishings, finishings); - if (copies != finishings_copies && (keyword = cupsGetOption("job-impressions", num_options, options)) != NULL) + if (copies != finishings_copies && job_pages > 0) { /* * Send job-pages-per-set attribute to apply finishings correctly... */ - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", atoi(keyword) / finishings_copies); + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", job_pages); } } } @@ -3228,7 +3253,7 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 10 -\"\n"); } else - cupsFilePuts(fp, "*cupsManualCopies: true\n"); + cupsFilePuts(fp, "*cupsManualCopies: True\n"); if (is_apple) cupsFilePuts(fp, "*cupsFilter2: \"image/urf image/urf 100 -\"\n"); if (is_pwg) @@ -3620,10 +3645,12 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-source", IPP_TAG_ZERO)) != NULL) pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname)); else - strlcpy(ppdname, "Unknown", sizeof(ppdname)); + ppdname[0] = '\0'; if ((attr = ippFindAttribute(response, "media-source-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1) { + int have_default = ppdname[0] != '\0'; + /* Do we have a default InputSlot? */ static const char * const sources[] = { /* Standard "media-source" strings */ "auto", @@ -3678,21 +3705,31 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ "roll-10" }; - cupsFilePrintf(fp, "*OpenUI *InputSlot: PickOne\n" - "*OrderDependency: 10 AnySetup *InputSlot\n" - "*DefaultInputSlot: %s\n", ppdname); - for (i = 0, count = ippGetCount(attr); i < count; i ++) + cupsFilePuts(fp, "*OpenUI *InputSlot: PickOne\n" + "*OrderDependency: 10 AnySetup *InputSlot\n"); + if (have_default) + cupsFilePrintf(fp, "*DefaultInputSlot: %s\n", ppdname); + + for (i = 0; i < count; i ++) { keyword = ippGetString(attr, i, NULL); pwg_ppdize_name(keyword, ppdname, sizeof(ppdname)); + if (i == 0 && !have_default) + cupsFilePrintf(fp, "*DefaultInputSlot: %s\n", ppdname); + for (j = 0; j < (int)(sizeof(sources) / sizeof(sources[0])); j ++) if (!strcmp(sources[j], keyword)) { snprintf(msgid, sizeof(msgid), "media-source.%s", keyword); + + if ((msgstr = _cupsLangString(lang, msgid)) == msgid || !strcmp(msgid, msgstr)) + if ((msgstr = _cupsMessageLookup(strings, msgid)) == msgid) + msgstr = keyword; + cupsFilePrintf(fp, "*InputSlot %s: \"<>setpagedevice\"\n", ppdname, j); - cupsFilePrintf(fp, "*%s.InputSlot %s/%s: \"\"\n", lang->language, ppdname, _cupsLangString(lang, msgid)); + cupsFilePrintf(fp, "*%s.InputSlot %s/%s: \"\"\n", lang->language, ppdname, msgstr); break; } } @@ -3744,6 +3781,8 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ int wrote_color = 0; const char *default_color = NULL; /* Default */ + cupsFilePrintf(fp, "*%% ColorModel from %s\n", ippGetName(attr)); + for (i = 0, count = ippGetCount(attr); i < count; i ++) { keyword = ippGetString(attr, i, NULL); @@ -3790,6 +3829,11 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ PRINTF_COLOROPTION("RGB", _("Color"), CUPS_CSPACE_SRGB, 8) default_color = "RGB"; + + // Apparently some printers only advertise color support, so make sure + // we also do grayscale for these printers... + if (!ippContainsString(attr, "sgray_8") && !ippContainsString(attr, "black_1") && !ippContainsString(attr, "black_8") && !ippContainsString(attr, "W8") && !ippContainsString(attr, "W8-16")) + PRINTF_COLOROPTION("Gray", _("GrayScale"), CUPS_CSPACE_SW, 8) } else if (!strcasecmp(keyword, "adobe-rgb_16") || !strcmp(keyword, "ADOBERGB48") || !strcmp(keyword, "ADOBERGB24-48")) { @@ -3924,7 +3968,7 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ else strlcpy(ppdname, "Unknown", sizeof(ppdname)); - if ((attr = ippFindAttribute(response, "output-bin-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1) + if ((attr = ippFindAttribute(response, "output-bin-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 0) { ipp_attribute_t *trays = ippFindAttribute(response, "printer-output-tray", IPP_TAG_STRING); /* printer-output-tray attribute, if any */ @@ -5140,6 +5184,8 @@ pwg_unppdize_name(const char *ppd, /* I - PPD keyword */ { char *ptr, /* Pointer into name buffer */ *end; /* End of name buffer */ + int nodash = 1; /* Next char in IPP name cannot be a + dash (first char or after a dash) */ if (_cups_islower(*ppd)) @@ -5151,7 +5197,9 @@ pwg_unppdize_name(const char *ppd, /* I - PPD keyword */ const char *ppdptr; /* Pointer into PPD keyword */ for (ppdptr = ppd + 1; *ppdptr; ppdptr ++) - if (_cups_isupper(*ppdptr) || strchr(dashchars, *ppdptr)) + if (_cups_isupper(*ppdptr) || strchr(dashchars, *ppdptr) || + (*ppdptr == '-' && *(ppdptr - 1) == '-') || + (*ppdptr == '-' && *(ppdptr + 1) == '\0')) break; if (!*ppdptr) @@ -5163,19 +5211,44 @@ pwg_unppdize_name(const char *ppd, /* I - PPD keyword */ for (ptr = name, end = name + namesize - 1; *ppd && ptr < end; ppd ++) { - if (_cups_isalnum(*ppd) || *ppd == '-') + if (_cups_isalnum(*ppd)) + { *ptr++ = (char)tolower(*ppd & 255); - else if (strchr(dashchars, *ppd)) - *ptr++ = '-'; + nodash = 0; + } + else if (*ppd == '-' || strchr(dashchars, *ppd)) + { + if (nodash == 0) + { + *ptr++ = '-'; + nodash = 1; + } + } else + { *ptr++ = *ppd; + nodash = 0; + } - if (!_cups_isupper(*ppd) && _cups_isalnum(*ppd) && - _cups_isupper(ppd[1]) && ptr < end) - *ptr++ = '-'; - else if (!isdigit(*ppd & 255) && isdigit(ppd[1] & 255)) - *ptr++ = '-'; + if (nodash == 0) + { + if (!_cups_isupper(*ppd) && _cups_isalnum(*ppd) && + _cups_isupper(ppd[1]) && ptr < end) + { + *ptr++ = '-'; + nodash = 1; + } + else if (!isdigit(*ppd & 255) && isdigit(ppd[1] & 255)) + { + *ptr++ = '-'; + nodash = 1; + } + } } + /* Remove trailing dashes */ + while (ptr > name && *(ptr - 1) == '-') + ptr --; + *ptr = '\0'; } diff --git a/cups/ppd-mark.c b/cups/ppd-mark.c index 7ec0df473..25797b376 100644 --- a/cups/ppd-mark.c +++ b/cups/ppd-mark.c @@ -307,7 +307,7 @@ cupsMarkOptions( * Look it up in the PPD file... */ - sprintf(s, "%d", j); + snprintf(s, sizeof(s), "%d", j); if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL) continue; diff --git a/cups/ppd-private.h b/cups/ppd-private.h index 7b406c971..11ddae366 100644 --- a/cups/ppd-private.h +++ b/cups/ppd-private.h @@ -35,7 +35,7 @@ extern "C" { * Constants... */ -# define _PPD_CACHE_VERSION 9 /* Version number in cache file */ +# define _PPD_CACHE_VERSION 10 /* Version number in cache file */ /* diff --git a/cups/ppd.c b/cups/ppd.c index ff52df2e1..ac5dbc62b 100644 --- a/cups/ppd.c +++ b/cups/ppd.c @@ -125,6 +125,7 @@ ppdClose(ppd_file_t *ppd) /* I - PPD file record */ free(ppd->lang_encoding); free(ppd->nickname); free(ppd->patches); + free(ppd->emulations); free(ppd->jcl_begin); free(ppd->jcl_end); free(ppd->jcl_ps); @@ -871,15 +872,15 @@ _ppdOpen( ppd_decode(ppd->jcl_ps); /* Decode quoted string */ } else if (!strcmp(keyword, "AccurateScreensSupport")) - ppd->accurate_screens = !strcmp(string, "True"); + ppd->accurate_screens = !strcasecmp(string, "True"); else if (!strcmp(keyword, "ColorDevice")) - ppd->color_device = !strcmp(string, "True"); + ppd->color_device = !strcasecmp(string, "True"); else if (!strcmp(keyword, "ContoneOnly")) - ppd->contone_only = !strcmp(string, "True"); + ppd->contone_only = !strcasecmp(string, "True"); else if (!strcmp(keyword, "cupsFlipDuplex")) - ppd->flip_duplex = !strcmp(string, "True"); + ppd->flip_duplex = !strcasecmp(string, "True"); else if (!strcmp(keyword, "cupsManualCopies")) - ppd->manual_copies = !strcmp(string, "True"); + ppd->manual_copies = !strcasecmp(string, "True"); else if (!strcmp(keyword, "cupsModelNumber")) ppd->model_number = atoi(string); else if (!strcmp(keyword, "cupsColorProfile")) @@ -1496,6 +1497,27 @@ _ppdOpen( goto error; } + if (option && (!_cups_strcasecmp(option->defchoice, "custom") || !_cups_strncasecmp(option->defchoice, "custom.", 7))) + { + /* + * "*DefaultOption: Custom..." may set the default to a custom value + * or (for a very small number of incompatible PPD files) select a + * standard choice for the option, which CUPS renames to "_Custom..." + * to avoid compatibility issues. See which this is... + */ + + char tchoice[PPD_MAX_NAME]; /* Temporary choice name */ + + snprintf(tchoice, sizeof(tchoice), "_%s", option->defchoice); + + if (ppdFindChoice(option, tchoice)) + { + strlcpy(option->defchoice, tchoice, sizeof(option->defchoice)); + + DEBUG_printf(("2_ppdOpen: Reset Default%s to %s...", option->keyword, tchoice)); + } + } + option = NULL; free(string); @@ -1510,6 +1532,27 @@ _ppdOpen( goto error; } + if (option && (!_cups_strcasecmp(option->defchoice, "custom") || !_cups_strncasecmp(option->defchoice, "custom.", 7))) + { + /* + * "*DefaultOption: Custom..." may set the default to a custom value + * or (for a very small number of incompatible PPD files) select a + * standard choice for the option, which CUPS renames to "_Custom..." + * to avoid compatibility issues. See which this is... + */ + + char tchoice[PPD_MAX_NAME]; /* Temporary choice name */ + + snprintf(tchoice, sizeof(tchoice), "_%s", option->defchoice); + + if (ppdFindChoice(option, tchoice)) + { + strlcpy(option->defchoice, tchoice, sizeof(option->defchoice)); + + DEBUG_printf(("2_ppdOpen: Reset Default%s to %s...", option->keyword, tchoice)); + } + } + option = NULL; free(string); @@ -1668,11 +1711,9 @@ _ppdOpen( * Set the default as part of the current option... */ - DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword, string)); - - strlcpy(option->defchoice, string, sizeof(option->defchoice)); + strlcpy(option->defchoice, string, sizeof(option->defchoice)); - DEBUG_printf(("2_ppdOpen: %s is now %s...", keyword, option->defchoice)); + DEBUG_printf(("2_ppdOpen: Set %s to %s...", keyword, option->defchoice)); } else { @@ -1682,11 +1723,27 @@ _ppdOpen( ppd_option_t *toption; /* Temporary option */ - if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL) { - DEBUG_printf(("2_ppdOpen: Setting %s to %s...", keyword, string)); - strlcpy(toption->defchoice, string, sizeof(toption->defchoice)); + if (!_cups_strcasecmp(string, "custom") || !_cups_strncasecmp(string, "custom.", 7)) + { + /* + * "*DefaultOption: Custom..." may set the default to a custom value + * or (for a very small number of incompatible PPD files) select a + * standard choice for the option, which CUPS renames to "_Custom..." + * to avoid compatibility issues. See which this is... + */ + + snprintf(toption->defchoice, sizeof(toption->defchoice), "_%s", string); + if (!ppdFindChoice(toption, toption->defchoice)) + strlcpy(toption->defchoice, string, sizeof(toption->defchoice)); + } + else + { + strlcpy(toption->defchoice, string, sizeof(toption->defchoice)); + } + + DEBUG_printf(("2_ppdOpen: Set %s to %s...", keyword, toption->defchoice)); } } } @@ -1719,8 +1776,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; @@ -2336,8 +2392,16 @@ ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */ * Copy data over... */ + if (!_cups_strcasecmp(spec, "custom") || !_cups_strncasecmp(spec, "custom.", 7)) + { + temp->spec[0] = '_'; + strlcpy(temp->spec + 1, spec, sizeof(temp->spec) - 1); + } + else { + strlcpy(temp->spec, spec, sizeof(temp->spec)); + } + strlcpy(temp->name, name, sizeof(temp->name)); - strlcpy(temp->spec, spec, sizeof(temp->spec)); strlcpy(temp->text, text, sizeof(temp->text)); temp->value = (char *)value; @@ -2840,7 +2904,7 @@ ppd_hash_option(ppd_option_t *option) /* I - Option */ for (hash = option->keyword[0], k = option->keyword + 1; *k;) - hash = 33 * hash + *k++; + hash = (int)(33U * (unsigned)hash) + *k++; return (hash & 511); } diff --git a/cups/pwg-media.c b/cups/pwg-media.c index 00bb2ed61..535db0880 100644 --- a/cups/pwg-media.c +++ b/cups/pwg-media.c @@ -448,13 +448,13 @@ pwgInitSize(pwg_size_t *size, /* I - Size to initialize */ size->width = x_dimension->values[0].integer; size->length = y_dimension->values[0].integer; } - else if (!x_dimension) + else if (!x_dimension) /* x_dimension is missing */ { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Missing x-dimension in media-size."), 1); return (0); } - else if (!y_dimension) + else /* y_dimension must be missing */ { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Missing y-dimension in media-size."), 1); diff --git a/cups/request.c b/cups/request.c index 69a780137..ff967f05a 100644 --- a/cups/request.c +++ b/cups/request.c @@ -395,7 +395,7 @@ cupsGetResponse(http_t *http, /* I - Connection to server or @code CUPS_HTTP ippDelete(response); response = NULL; - http->status = status = HTTP_STATUS_ERROR; + http->status = HTTP_STATUS_ERROR; http->error = EINVAL; } } @@ -422,7 +422,7 @@ cupsGetResponse(http_t *http, /* I - Connection to server or @code CUPS_HTTP if (!cupsDoAuthentication(http, "POST", resource)) httpReconnect2(http, 30000, NULL); else - http->status = status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; + http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; } #ifdef HAVE_SSL diff --git a/cups/snprintf.c b/cups/snprintf.c index 49652e2c4..066252ee7 100644 --- a/cups/snprintf.c +++ b/cups/snprintf.c @@ -1,6 +1,7 @@ /* * snprintf functions for CUPS. * + * Copyright © 2021 by OpenPrinting * Copyright © 2007-2019 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products. * @@ -81,7 +82,8 @@ _cups_vsnprintf(char *buffer, /* O - Output buffer */ format ++; width = va_arg(ap, int); - snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width); + /* Note: Can't use snprintf here since we are implementing this function... */ + sprintf(tptr, "%d", width); tptr += strlen(tptr); } else @@ -113,7 +115,8 @@ _cups_vsnprintf(char *buffer, /* O - Output buffer */ format ++; prec = va_arg(ap, int); - snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec); + /* Note: Can't use snprintf here since we are implementing this function... */ + sprintf(tptr, "%d", prec); tptr += strlen(tptr); } else @@ -171,6 +174,7 @@ _cups_vsnprintf(char *buffer, /* O - Output buffer */ if ((width + 2) > sizeof(temp)) break; + /* Note: Can't use snprintf here since we are implementing this function... */ sprintf(temp, tformat, va_arg(ap, double)); templen = strlen(temp); @@ -202,6 +206,7 @@ _cups_vsnprintf(char *buffer, /* O - Output buffer */ if ((width + 2) > sizeof(temp)) break; + /* Note: Can't use snprintf here since we are implementing this function... */ sprintf(temp, tformat, va_arg(ap, int)); templen = strlen(temp); @@ -226,6 +231,7 @@ _cups_vsnprintf(char *buffer, /* O - Output buffer */ if ((width + 2) > sizeof(temp)) break; + /* Note: Can't use snprintf here since we are implementing this function... */ sprintf(temp, tformat, va_arg(ap, void *)); templen = strlen(temp); @@ -317,7 +323,8 @@ _cups_vsnprintf(char *buffer, /* O - Output buffer */ * Nul-terminate the string and return the number of characters needed. */ - *bufptr = '\0'; + if (bufptr && bufptr < bufend) + *bufptr = '\0'; return (bytes); } diff --git a/cups/testclient.c b/cups/testclient.c index cf945df98..16ac40db7 100644 --- a/cups/testclient.c +++ b/cups/testclient.c @@ -24,7 +24,7 @@ * Constants... */ -#define MAX_CLIENTS 16 /* Maximum number of client threads */ +#define MAX_CLIENTS 100 /* Maximum number of client threads */ /* @@ -44,12 +44,12 @@ typedef struct _client_data_s int grayscale, /* Force grayscale? */ keepfile; /* Keep temporary file? */ ipp_pstate_t printer_state; /* Current printer state */ - char printer_state_reasons[1024]; - /* Current printer-state-reasons */ + char printer_state_reasons[1024]; + /* Current printer-state-reasons */ int job_id; /* Job ID for submitted job */ ipp_jstate_t job_state; /* Current job state */ - char job_state_reasons[1024]; - /* Current job-state-reasons */ + char job_state_reasons[1024]; + /* Current job-state-reasons */ } _client_data_t; @@ -66,12 +66,12 @@ static int verbosity = 0; * Local functions... */ -static const char *make_raster_file(ipp_t *response, int grayscale, char *tempname, size_t tempsize, const char **format); -static void *monitor_printer(_client_data_t *data); +static const char *make_raster_file(ipp_t *response, int grayscale, char *tempname, size_t tempsize, const char **format); +static void *monitor_printer(_client_data_t *data); static void *run_client(_client_data_t *data); -static void show_attributes(const char *title, int request, ipp_t *ipp); -static void show_capabilities(ipp_t *response); -static void usage(void); +static void show_attributes(const char *title, int request, ipp_t *ipp); +static void show_capabilities(ipp_t *response); +static void usage(void); /* @@ -396,15 +396,7 @@ make_raster_file(ipp_t *response, /* I - Printer attributes */ * Figure out the the media, resolution, and color mode... */ - if ((attr = ippFindAttribute(response, "media-default", IPP_TAG_KEYWORD)) != NULL) - { - /* - * Use default media... - */ - - media = pwgMediaForPWG(ippGetString(attr, 0, NULL)); - } - else if ((attr = ippFindAttribute(response, "media-ready", IPP_TAG_KEYWORD)) != NULL) + if ((attr = ippFindAttribute(response, "media-ready", IPP_TAG_KEYWORD)) != NULL) { /* * Use ready media... @@ -417,6 +409,14 @@ make_raster_file(ipp_t *response, /* I - Printer attributes */ else media = pwgMediaForPWG(ippGetString(attr, 0, NULL)); } + else if ((attr = ippFindAttribute(response, "media-default", IPP_TAG_KEYWORD)) != NULL) + { + /* + * Use default media... + */ + + media = pwgMediaForPWG(ippGetString(attr, 0, NULL)); + } else { puts("No default or ready media reported by printer, aborting."); @@ -486,15 +486,15 @@ make_raster_file(ipp_t *response, /* I - Printer attributes */ header.cupsInteger[CUPS_RASTER_PWG_TotalPageCount] = 1; - if (header.cupsWidth > (4 * header.HWResolution[0])) + if (header.cupsWidth > (2 * header.HWResolution[0])) { xoff = header.HWResolution[0] / 2; yoff = header.HWResolution[1] / 2; } else { - xoff = 0; - yoff = 0; + xoff = header.HWResolution[0] / 4; + yoff = header.HWResolution[1] / 4; } xrep = (header.cupsWidth - 2 * xoff) / 140; @@ -603,6 +603,8 @@ make_raster_file(ipp_t *response, /* I - Printer attributes */ for (y = 0; y < header.cupsHeight; y ++) cupsRasterWritePixels(ras, line, header.cupsBytesPerLine); + free(line); + cupsRasterClose(ras); close(fd); @@ -768,11 +770,8 @@ run_client( ipp_attribute_t *attr; /* Attribute in response */ static const char * const pattrs[] = /* Printer attributes we are interested in */ { - "job-template", - "printer-defaults", - "printer-description", - "media-col-database", - "media-col-ready" + "all", + "media-col-database" }; diff --git a/cups/testdest.c b/cups/testdest.c index a65e09960..9b07e7771 100644 --- a/cups/testdest.c +++ b/cups/testdest.c @@ -410,7 +410,6 @@ print_file(http_t *http, /* I - Connection to destination */ { cups_file_t *fp; /* File to print */ int job_id; /* Job ID */ - ipp_status_t status; /* Submission status */ const char *title; /* Title of job */ char buffer[32768]; /* File buffer */ ssize_t bytes; /* Bytes read/to write */ @@ -427,7 +426,7 @@ print_file(http_t *http, /* I - Connection to destination */ else title = filename; - if ((status = cupsCreateDestJob(http, dest, dinfo, &job_id, title, num_options, options)) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED) + if (cupsCreateDestJob(http, dest, dinfo, &job_id, title, num_options, options) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED) { printf("Unable to create job: %s\n", cupsLastErrorString()); cupsFileClose(fp); @@ -454,7 +453,7 @@ print_file(http_t *http, /* I - Connection to destination */ cupsFileClose(fp); - if ((status = cupsFinishDestDocument(http, dest, dinfo)) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED) + if (cupsFinishDestDocument(http, dest, dinfo) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED) { printf("Unable to send document: %s\n", cupsLastErrorString()); return; diff --git a/cups/tls-darwin.c b/cups/tls-darwin.c index b3bd50bf8..0741a320e 100644 --- a/cups/tls-darwin.c +++ b/cups/tls-darwin.c @@ -1,7 +1,8 @@ /* * TLS support code for CUPS on macOS. * - * Copyright © 2007-2019 by Apple Inc. + * Copyright © 2021 by OpenPrinting + * Copyright © 2007-2021 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * * Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -291,7 +292,7 @@ cupsMakeServerCredentials( else tls_selfsigned = ident; - _cupsMutexLock(&tls_mutex); + _cupsMutexUnlock(&tls_mutex); # if 0 /* Someday perhaps SecItemCopyMatching will work for identities, at which point */ CFTypeRef itemKeys[] = { kSecClass, kSecAttrLabel, kSecValueRef }; diff --git a/cups/tls-gnutls.c b/cups/tls-gnutls.c index 329cc0eb4..ffe1aa695 100644 --- a/cups/tls-gnutls.c +++ b/cups/tls-gnutls.c @@ -659,7 +659,7 @@ httpCredentialsString( if (!buffer) return (0); - if (buffer && bufsize > 0) + if (bufsize > 0) *buffer = '\0'; if ((first = (http_credential_t *)cupsArrayFirst(credentials)) != NULL && @@ -939,7 +939,7 @@ http_gnutls_default_path(char *buffer,/* I - Path buffer */ /* Pointer to library globals */ - if (cg->home) + if (cg->home && getuid()) { snprintf(buffer, bufsize, "%s/.cups", cg->home); if (access(buffer, 0)) @@ -1516,8 +1516,7 @@ _httpTLSStart(http_t *http) /* I - Connection to server */ DEBUG_printf(("4_httpTLSStart: Using certificate \"%s\" and private key \"%s\".", crtfile, keyfile)); - if (!status) - status = gnutls_certificate_set_x509_key_file(*credentials, crtfile, keyfile, GNUTLS_X509_FMT_PEM); + status = gnutls_certificate_set_x509_key_file(*credentials, crtfile, keyfile, GNUTLS_X509_FMT_PEM); } if (!status) diff --git a/cups/tls-sspi.c b/cups/tls-sspi.c index ccbdf8aaf..52ded5f21 100644 --- a/cups/tls-sspi.c +++ b/cups/tls-sspi.c @@ -1332,8 +1332,6 @@ http_sspi_client(http_t *http, /* I - Client connection */ SecBufferDesc outBuffer; /* Array of SecBuffer structs */ SecBuffer outBuffers[1]; /* Security package buffer */ int ret = 0; /* Return value */ - char username[1024], /* Current username */ - common_name[1024]; /* CN=username */ DEBUG_printf(("4http_sspi_client(http=%p, hostname=\"%s\")", http, hostname)); @@ -1349,16 +1347,11 @@ http_sspi_client(http_t *http, /* I - Client connection */ * Lookup the client certificate... */ - dwSize = sizeof(username); - GetUserNameA(username, &dwSize); - snprintf(common_name, sizeof(common_name), "CN=%s", username); - - if (!http_sspi_find_credentials(http, L"ClientContainer", common_name)) - if (!http_sspi_make_credentials(http->tls, L"ClientContainer", common_name, _HTTP_MODE_CLIENT, 10)) - { - DEBUG_puts("5http_sspi_client: Unable to get client credentials."); - return (-1); - } + if (!http_sspi_find_credentials(http, L"ClientContainer", NULL)) + { + DEBUG_puts("5http_sspi_client: Unable to get client credentials."); + return (-1); + } /* * Initiate a ClientHello message and generate a token. @@ -1711,48 +1704,55 @@ http_sspi_find_credentials( goto cleanup; } - dwSize = 0; - - if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL)) + if (common_name) { - DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); - ok = FALSE; - goto cleanup; - } + dwSize = 0; - p = (PBYTE)malloc(dwSize); + if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, NULL, &dwSize, NULL)) + { + DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); + ok = FALSE; + goto cleanup; + } - if (!p) - { - DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize)); - ok = FALSE; - goto cleanup; - } + p = (PBYTE)malloc(dwSize); - if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL)) - { - DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); - ok = FALSE; - goto cleanup; - } + if (!p) + { + DEBUG_printf(("5http_sspi_find_credentials: malloc failed for %d bytes.", dwSize)); + ok = FALSE; + goto cleanup; + } - sib.cbData = dwSize; - sib.pbData = p; + if (!CertStrToNameA(X509_ASN_ENCODING, common_name, CERT_OID_NAME_STR, NULL, p, &dwSize, NULL)) + { + DEBUG_printf(("5http_sspi_find_credentials: CertStrToName failed: %s", http_sspi_strerror(sspi->error, sizeof(sspi->error), GetLastError()))); + ok = FALSE; + goto cleanup; + } - storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL); + sib.cbData = dwSize; + sib.pbData = p; - if (!storedContext) - { - DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name)); - ok = FALSE; - goto cleanup; + storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, &sib, NULL); + + if (!storedContext) + { + DEBUG_printf(("5http_sspi_find_credentials: Unable to find credentials for \"%s\".", common_name)); + ok = FALSE; + goto cleanup; + } } ZeroMemory(&SchannelCred, sizeof(SchannelCred)); SchannelCred.dwVersion = SCHANNEL_CRED_VERSION; - SchannelCred.cCreds = 1; - SchannelCred.paCred = &storedContext; + + if (common_name) + { + SchannelCred.cCreds = 1; + SchannelCred.paCred = &storedContext; + } /* * Set supported protocols (can also be overriden in the registry...) @@ -2017,13 +2017,6 @@ http_sspi_make_credentials( SchannelCred.cCreds = 1; SchannelCred.paCred = &storedContext; - /* - * SSPI doesn't seem to like it if grbitEnabledProtocols is set for a client. - */ - - if (mode == _HTTP_MODE_SERVER) - SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1; - /* * Create an SSPI credential. */ diff --git a/cups/tlscheck.c b/cups/tlscheck.c index c88e7d091..4b0be1f83 100644 --- a/cups/tlscheck.c +++ b/cups/tlscheck.c @@ -22,7 +22,7 @@ int main(void) { puts("Sorry, no TLS support compiled in."); return (1); } * Local functions... */ -static void usage(void); +static void usage(void) _CUPS_NORETURN; /* diff --git a/doc/help/cgi.html b/doc/help/cgi.html index 34c6debb3..150bacdbc 100644 --- a/doc/help/cgi.html +++ b/doc/help/cgi.html @@ -1,82 +1,41 @@ - + + - - Using CGI Programs - - - + + Using CGI Programs + + + +

Using CGI Programs

-

Using CGI Programs

+

CUPS provides a dynamic web interface through dedicated CGI programs that are executed when users open special directories on the CUPS server. Each CGI performs administration, class, help, job, and printer functions as directed by the user, but the actual programs that are run and functions that are available are limited to those that were originally designed into the scheduler.

-

CUPS provides a dynamic web interface through dedicated CGI programs that -are executed when users open special directories on the CUPS server. Each CGI -performs administration, class, help, job, and printer functions as directed by -the user, but the actual programs that are run and functions that are available -are limited to those that were originally designed into the scheduler.

+

CUPS also supports CGI scripts/programs for pages you want to provide, although this functionality is disabled by default. The "application/x-httpd-cgi" MIME media type is used to identify CGI content and can be associated with any filename extension. The scheduler requires CGI content to have the execute bit set, not have world or group write permissions, and any CGI scripts need to include a #! line as the first line of a script to identify the script interpreter. For example, a PHP script would look like:

-

CUPS also supports CGI programs and specific scripting languages (Java, Perl, -PHP, and Python) for pages you want to provide. The interpreters for these -languages are currently configured at compile time and are associated with -MIME media types. Table 1 shows the MIME media types that -are reserved for each type of page and are the same as those used by the Apache -web server.

+
+#!/usr/bin/php -fn
+<?php
+...
+?>
+
-
- - - - - - - - - - - - - - - - - - - - - - - - - -
Table 1: CGI MIME Media Types
MIME Media TypeDescription
application/x-httpd-cgiCGI script/program
application/x-httpd-javaJava program
application/x-httpd-perlPerl script
application/x-httpd-phpPHP script
application/x-httpd-pythonPython script
-

Configuring the Server

+

Configuring the Server

-

In order to enable the corresponding type, you must create a -new /etc/cups/cgi.types file which maps the filename -extensions to the appropriate MIME types, for example:

+

In order to enable the corresponding type, you must create a new /etc/cups/cgi.types file which maps the filename extensions you use to the appropriate MIME types. For example, the following will support CGI programs/scripts with the "cgi" extension:

-
+    
 application/x-httpd-cgi cgi
-application/x-httpd-java class
-application/x-httpd-perl pl
-application/x-httpd-php php
-application/x-httpd-python py
-
+
-

CGI scripts/programs (application/x-httpd-cgi) also must be owned by root, have execution permissions, and not have world or group write permissions to be treated as a CGI script or program.

-

Limitations

+

Limitations

-

CUPS implements most of the CGI/1.1 specification, with the -following exceptions:

+

CUPS implements most of the CGI/1.1 specification, with the following exceptions:

-
    - -
  • No PATH_INFO or PATH_TRANSLATED support
  • - -
  • Limited HTTP field support; only the Content-Length (CONTENT_LENGTH), Content-Type (CONTENT_TYPE), Cookie (HTTP_COOKIE), Referrer (HTTP_REFERRER), and User-Agent (HTTP_USER_AGENT) fields are placed in environment variables at this time
  • - -
- - - +
    +
  • No PATH_INFO or PATH_TRANSLATED support
  • +
  • Limited HTTP field support; only the Content-Length (CONTENT_LENGTH), Content-Type (CONTENT_TYPE), Cookie (HTTP_COOKIE), Referrer (HTTP_REFERRER), and User-Agent (HTTP_USER_AGENT) fields are placed in environment variables at this time
  • +
+ + diff --git a/doc/help/cupspm.html b/doc/help/cupspm.html index 9b48cde34..677f2bc3c 100644 --- a/doc/help/cupspm.html +++ b/doc/help/cupspm.html @@ -7,8 +7,8 @@ - - + +