From: Michael R Sweet Date: Wed, 16 Apr 2025 20:50:36 +0000 (-0400) Subject: Fix coverity-detected issues. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d7088f5c548b746e3184191580294d7c031ceb63;p=thirdparty%2Fcups.git Fix coverity-detected issues. --- diff --git a/cups/dnssd.c b/cups/dnssd.c index 7d99f1da09..a269ab81d4 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -3009,20 +3009,19 @@ avahi_resolve_cb( DEBUG_printf("3avahi_resolve_cb(resolver=%p, if_index=%d, protocol=%d, event=%s, name=\"%s\", type=\"%s\", domain=\"%s\", host=\"%s\", address=%p, port=%u, txtrec=%p, flags=%u, resolve=%p)", (void *)resolver, if_index, protocol, avahi_events[event], name, type, domain, host, (void *)address, (unsigned)port, (void *)txtrec, (unsigned)flags, (void *)resolve); - if (!resolver || event != AVAHI_RESOLVER_FOUND) + if (!resolver) return; - (void)resolver; (void)protocol; (void)flags; // Map the addresses "127.0.0.1" (IPv4) and "::1" (IPv6) to "localhost" to work around a well-known Avahi registration bug for local-only services (Issue #970) - if (address->proto == AVAHI_PROTO_INET && address->data.ipv4.address == htonl(0x7f000001)) + if (address && address->proto == AVAHI_PROTO_INET && address->data.ipv4.address == htonl(0x7f000001)) { DEBUG_puts("4avahi_resolve_cb: Mapping 127.0.0.1 to localhost."); host = "localhost"; } - else if (address->proto == AVAHI_PROTO_INET6 && address->data.ipv6.address[0] == 0 && address->data.ipv6.address[1] == 0 && address->data.ipv6.address[2] == 0 && address->data.ipv6.address[3] == 0 && address->data.ipv6.address[4] == 0 && address->data.ipv6.address[5] == 0 && address->data.ipv6.address[6] == 0 && address->data.ipv6.address[7] == 0 && address->data.ipv6.address[8] == 0 && address->data.ipv6.address[9] == 0 && address->data.ipv6.address[10] == 0 && address->data.ipv6.address[11] == 0 && address->data.ipv6.address[12] == 0 && address->data.ipv6.address[13] == 0 && address->data.ipv6.address[14] == 0 && address->data.ipv6.address[15] == 1) + else if (address && address->proto == AVAHI_PROTO_INET6 && address->data.ipv6.address[0] == 0 && address->data.ipv6.address[1] == 0 && address->data.ipv6.address[2] == 0 && address->data.ipv6.address[3] == 0 && address->data.ipv6.address[4] == 0 && address->data.ipv6.address[5] == 0 && address->data.ipv6.address[6] == 0 && address->data.ipv6.address[7] == 0 && address->data.ipv6.address[8] == 0 && address->data.ipv6.address[9] == 0 && address->data.ipv6.address[10] == 0 && address->data.ipv6.address[11] == 0 && address->data.ipv6.address[12] == 0 && address->data.ipv6.address[13] == 0 && address->data.ipv6.address[14] == 0 && address->data.ipv6.address[15] == 1) { DEBUG_puts("4avahi_resolve_cb: Mapping ::1 to localhost."); host = "localhost"; diff --git a/cups/http.c b/cups/http.c index 6fdcec3064..e16c9ac01a 100644 --- a/cups/http.c +++ b/cups/http.c @@ -1886,6 +1886,7 @@ httpPeek(http_t *http, // I - HTTP connection { DEBUG_puts("2httpPeek: Unable to copy decompressor stream."); http->error = ENOMEM; + inflateEnd(&stream); return (-1); } diff --git a/cups/tls-gnutls.c b/cups/tls-gnutls.c index 78dbe60e31..56957ba009 100644 --- a/cups/tls-gnutls.c +++ b/cups/tls-gnutls.c @@ -1742,8 +1742,12 @@ _httpTLSStart(http_t *http) // I - Connection to server *cnptr; // Pointer into common name bool have_creds = false; // Have credentials? + cupsMutexLock(&tls_mutex); + if (!tls_common_name) { + cupsMutexUnlock(&tls_mutex); + if (http->fields[HTTP_FIELD_HOST]) { // Use hostname for TLS upgrade... @@ -1777,9 +1781,9 @@ _httpTLSStart(http_t *http) // I - Connection to server if (hostname[0]) cn = hostname; - } - cupsMutexLock(&tls_mutex); + cupsMutexLock(&tls_mutex); + } if (!cn) cn = tls_common_name; diff --git a/cups/tls-openssl.c b/cups/tls-openssl.c index 5474d57c91..128820b57d 100644 --- a/cups/tls-openssl.c +++ b/cups/tls-openssl.c @@ -1715,8 +1715,12 @@ _httpTLSStart(http_t *http) // I - Connection to server context = SSL_CTX_new(TLS_server_method()); // Find the TLS certificate... + cupsMutexLock(&tls_mutex); + if (!tls_common_name) { + cupsMutexUnlock(&tls_mutex); + if (http->fields[HTTP_FIELD_HOST]) { // Use hostname for TLS upgrade... @@ -1753,9 +1757,9 @@ _httpTLSStart(http_t *http) // I - Connection to server if (hostname[0]) cn = hostname; - } - cupsMutexLock(&tls_mutex); + cupsMutexLock(&tls_mutex); + } if (!cn) cn = tls_common_name; diff --git a/scheduler/ipp.c b/scheduler/ipp.c index a4997f1fe6..a00a7df19e 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -138,10 +138,13 @@ cupsdProcessIPPRequest( ipp_attribute_t *username; /* requesting-user-name attr */ int sub_id; /* Subscription ID */ int valid = 1; /* Valid request? */ - int minor; /* Minor version */ + int major, /* IPP major version */ + minor; /* IPP minor version */ - cupsdLogClient(con, CUPSD_LOG_DEBUG, "%s IPP/%d.%d request_id=%d", ippOpString(ippGetOperation(con->request)), ippGetVersion(con->request, &minor), minor, ippGetRequestId(con->request)); + major = ippGetVersion(con->request, &minor); + + cupsdLogClient(con, CUPSD_LOG_DEBUG, "%s IPP/%d.%d request_id=%d", ippOpString(ippGetOperation(con->request)), major, minor, ippGetRequestId(con->request)); if (LogLevel >= CUPSD_LOG_DEBUG2) { diff --git a/scheduler/job.c b/scheduler/job.c index 8a1b08117c..7b1ab093c8 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -4674,6 +4674,7 @@ load_request_root(void) */ while ((dent = cupsDirRead(dir)) != NULL) + { if (strlen(dent->filename) >= 6 && dent->filename[0] == 'c') { /* @@ -4730,6 +4731,7 @@ load_request_root(void) cupsdDeleteJob(job, CUPSD_JOB_FORCE); } } + } cupsDirClose(dir); } diff --git a/tools/ippevepcl.c b/tools/ippevepcl.c index eb75884af4..bade57351f 100644 --- a/tools/ippevepcl.c +++ b/tools/ippevepcl.c @@ -1,7 +1,7 @@ /* * Generic HP PCL printer command for ippeveprinter/CUPS. * - * Copyright © 2020-2024 by OpenPrinting. + * Copyright © 2020-2025 by OpenPrinting. * Copyright © 2019 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -508,7 +508,11 @@ raster_to_pcl(const char *filename) /* I - File to print (NULL for stdin) */ break; } - line = malloc(header.cupsBytesPerLine); + if ((line = malloc(header.cupsBytesPerLine)) == NULL) + { + fprintf(stderr, "ERROR: Unable to allocate %u bytes for line, aborting.\n", header.cupsBytesPerLine); + break; + } pcl_start_page(&header, page); for (y = 0; y < header.cupsHeight; y ++) diff --git a/tools/ippeveps.c b/tools/ippeveps.c index 75ba2b0e65..9822696c6e 100644 --- a/tools/ippeveps.c +++ b/tools/ippeveps.c @@ -1091,7 +1091,11 @@ raster_to_ps(const char *filename) /* I - Filename */ break; } - line = malloc(header.cupsBytesPerLine); + if ((line = malloc(header.cupsBytesPerLine)) == NULL) + { + fprintf(stderr, "ERROR: Unable to allocate %u bytes for line, aborting.\n", header.cupsBytesPerLine); + break; + } dsc_page(page); diff --git a/xcode/CUPS.xcodeproj/project.pbxproj b/xcode/CUPS.xcodeproj/project.pbxproj index 878f557a7b..44dcb08827 100644 --- a/xcode/CUPS.xcodeproj/project.pbxproj +++ b/xcode/CUPS.xcodeproj/project.pbxproj @@ -71,6 +71,8 @@ buildPhases = ( ); dependencies = ( + 27C3E96E2DB04B5800A6ABBF /* PBXTargetDependency */, + 27C3E9702DB04B5800A6ABBF /* PBXTargetDependency */, 273B1EC2226B3F2600428143 /* PBXTargetDependency */, 273B1EC4226B3F2600428143 /* PBXTargetDependency */, 271287061CC13F8F00E517C7 /* PBXTargetDependency */, @@ -826,6 +828,10 @@ 27B493ED2C8FC36E004C7A73 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 2758FE1C2C8FBD2B0078480C /* libiconv.tbd */; }; 27B493EE2C8FC37B004C7A73 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2758FE182C8F9F5E0078480C /* CoreServices.framework */; }; 27B493EF2C8FC389004C7A73 /* GSS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 27865F092C8FC0A5003D5606 /* GSS.framework */; }; + 27C3E9562DB04AC500A6ABBF /* libcups2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups2.dylib */; }; + 27C3E9622DB04ACE00A6ABBF /* libcups2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups2.dylib */; }; + 27C3E96B2DB04B2900A6ABBF /* cups-oauth.c in Sources */ = {isa = PBXBuildFile; fileRef = 27C3E9682DB04AFB00A6ABBF /* cups-oauth.c */; }; + 27C3E96C2DB04B3600A6ABBF /* cups-x509.c in Sources */ = {isa = PBXBuildFile; fileRef = 27C3E9692DB04AFB00A6ABBF /* cups-x509.c */; }; 27F515462AAFBECF0045EE21 /* raster-testpage.h in Headers */ = {isa = PBXBuildFile; fileRef = 27F515432AAFBECF0045EE21 /* raster-testpage.h */; }; 27F515472AAFBECF0045EE21 /* raster-testpage.h in Headers */ = {isa = PBXBuildFile; fileRef = 27F515432AAFBECF0045EE21 /* raster-testpage.h */; }; 27F515482AAFBECF0045EE21 /* raster-testpage.h in Headers */ = {isa = PBXBuildFile; fileRef = 27F515432AAFBECF0045EE21 /* raster-testpage.h */; }; @@ -2206,6 +2212,34 @@ remoteGlobalIDString = 27A0347A1A8BDB1200650675; remoteInfo = lpadmin; }; + 27C3E9522DB04AC500A6ABBF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 72BF96371333042100B1EAD7 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 72220EAD1333047D00FCA411; + remoteInfo = libcups; + }; + 27C3E95E2DB04ACE00A6ABBF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 72BF96371333042100B1EAD7 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 72220EAD1333047D00FCA411; + remoteInfo = libcups; + }; + 27C3E96D2DB04B5800A6ABBF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 72BF96371333042100B1EAD7 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 27C3E95C2DB04ACE00A6ABBF; + remoteInfo = "cups-oauth"; + }; + 27C3E96F2DB04B5800A6ABBF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 72BF96371333042100B1EAD7 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 27C3E9502DB04AC500A6ABBF; + remoteInfo = "cups-x509"; + }; 720DD6CE1358FD790064AA82 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72BF96371333042100B1EAD7 /* Project object */; @@ -3081,6 +3115,24 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + 27C3E9572DB04AC500A6ABBF /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 27C3E9632DB04ACE00A6ABBF /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; 720DD6C01358FD5F0064AA82 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -3568,6 +3620,10 @@ 278C58E8136B64B000836530 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = ""; }; 279AE6F42395B80F004DD600 /* libpam.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libpam.tbd; path = usr/lib/libpam.tbd; sourceTree = SDKROOT; }; 27A0347B1A8BDB1300650675 /* lpadmin */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lpadmin; sourceTree = BUILT_PRODUCTS_DIR; }; + 27C3E95B2DB04AC500A6ABBF /* cups-x509 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "cups-x509"; sourceTree = BUILT_PRODUCTS_DIR; }; + 27C3E9672DB04ACE00A6ABBF /* cups-oauth */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "cups-oauth"; sourceTree = BUILT_PRODUCTS_DIR; }; + 27C3E9682DB04AFB00A6ABBF /* cups-oauth.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "cups-oauth.c"; sourceTree = ""; }; + 27C3E9692DB04AFB00A6ABBF /* cups-x509.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "cups-x509.c"; sourceTree = ""; }; 27C89C902613E7C300A58F43 /* cups-tls.m4 */ = {isa = PBXFileReference; lastKnownFileType = text; name = "cups-tls.m4"; path = "../config-scripts/cups-tls.m4"; sourceTree = ""; }; 27D3037D134148CB00F022B1 /* libcups2.def */ = {isa = PBXFileReference; lastKnownFileType = text; name = libcups2.def; path = ../cups/libcups2.def; sourceTree = ""; }; 27F515432AAFBECF0045EE21 /* raster-testpage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "raster-testpage.h"; path = "../cups/raster-testpage.h"; sourceTree = ""; }; @@ -4579,6 +4635,22 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 27C3E9552DB04AC500A6ABBF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 27C3E9562DB04AC500A6ABBF /* libcups2.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 27C3E9612DB04ACE00A6ABBF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 27C3E9622DB04ACE00A6ABBF /* libcups2.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 720DD6BF1358FD5F0064AA82 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -5293,6 +5365,8 @@ 276683681337AA00000D33D0 /* cupsctl.c */, 274FF68713333B6E00317ECB /* cupsfilter.c */, 72F75A5B1336F988004BB496 /* cupstestppd.c */, + 27C3E9682DB04AFB00A6ABBF /* cups-oauth.c */, + 27C3E9692DB04AFB00A6ABBF /* cups-x509.c */, 273B1EBD226B3EE300428143 /* ippevecommon.h */, 273B1EBE226B3EE300428143 /* ippevepcl.c */, 726AD701135E8A90002C930D /* ippeveprinter.c */, @@ -5430,6 +5504,8 @@ 2758FDF62C8F9C240078480C /* testoauth */, 2758FE072C8F9C5B0078480C /* testform */, 275CEA422CC840EE008FBB27 /* testclock */, + 27C3E95B2DB04AC500A6ABBF /* cups-x509 */, + 27C3E9672DB04ACE00A6ABBF /* cups-oauth */, ); name = Products; sourceTree = ""; @@ -7063,6 +7139,42 @@ productReference = 27A0347B1A8BDB1300650675 /* lpadmin */; productType = "com.apple.product-type.tool"; }; + 27C3E9502DB04AC500A6ABBF /* cups-x509 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 27C3E9582DB04AC500A6ABBF /* Build configuration list for PBXNativeTarget "cups-x509" */; + buildPhases = ( + 27C3E9532DB04AC500A6ABBF /* Sources */, + 27C3E9552DB04AC500A6ABBF /* Frameworks */, + 27C3E9572DB04AC500A6ABBF /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 27C3E9512DB04AC500A6ABBF /* PBXTargetDependency */, + ); + name = "cups-x509"; + productName = cupsaddsmb; + productReference = 27C3E95B2DB04AC500A6ABBF /* cups-x509 */; + productType = "com.apple.product-type.tool"; + }; + 27C3E95C2DB04ACE00A6ABBF /* cups-oauth */ = { + isa = PBXNativeTarget; + buildConfigurationList = 27C3E9642DB04ACE00A6ABBF /* Build configuration list for PBXNativeTarget "cups-oauth" */; + buildPhases = ( + 27C3E95F2DB04ACE00A6ABBF /* Sources */, + 27C3E9612DB04ACE00A6ABBF /* Frameworks */, + 27C3E9632DB04ACE00A6ABBF /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 27C3E95D2DB04ACE00A6ABBF /* PBXTargetDependency */, + ); + name = "cups-oauth"; + productName = cupsaddsmb; + productReference = 27C3E9672DB04ACE00A6ABBF /* cups-oauth */; + productType = "com.apple.product-type.tool"; + }; 720DD6C11358FD5F0064AA82 /* snmp */ = { isa = PBXNativeTarget; buildConfigurationList = 720DD6CB1358FD600064AA82 /* Build configuration list for PBXNativeTarget "snmp" */; @@ -7873,6 +7985,8 @@ 274FF6281333333600317ECB /* cups-deviced */, 274FF63D1333358B00317ECB /* cups-exec */, 274FF64E133339C400317ECB /* cups-lpd */, + 27C3E95C2DB04ACE00A6ABBF /* cups-oauth */, + 27C3E9502DB04AC500A6ABBF /* cups-x509 */, 274FF67713333B2F00317ECB /* cupsfilter */, 72F75A511336F950004BB496 /* cupstestppd */, 724379461333FEA9009631B9 /* dnssd */, @@ -8547,6 +8661,22 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 27C3E9532DB04AC500A6ABBF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 27C3E96C2DB04B3600A6ABBF /* cups-x509.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 27C3E95F2DB04ACE00A6ABBF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 27C3E96B2DB04B2900A6ABBF /* cups-oauth.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 720DD6BE1358FD5F0064AA82 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -9778,6 +9908,26 @@ target = 27A0347A1A8BDB1200650675 /* lpadmin */; targetProxy = 27A034861A8BDC6900650675 /* PBXContainerItemProxy */; }; + 27C3E9512DB04AC500A6ABBF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 72220EAD1333047D00FCA411 /* libcups2 */; + targetProxy = 27C3E9522DB04AC500A6ABBF /* PBXContainerItemProxy */; + }; + 27C3E95D2DB04ACE00A6ABBF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 72220EAD1333047D00FCA411 /* libcups2 */; + targetProxy = 27C3E95E2DB04ACE00A6ABBF /* PBXContainerItemProxy */; + }; + 27C3E96E2DB04B5800A6ABBF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 27C3E95C2DB04ACE00A6ABBF /* cups-oauth */; + targetProxy = 27C3E96D2DB04B5800A6ABBF /* PBXContainerItemProxy */; + }; + 27C3E9702DB04B5800A6ABBF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 27C3E9502DB04AC500A6ABBF /* cups-x509 */; + targetProxy = 27C3E96F2DB04B5800A6ABBF /* PBXContainerItemProxy */; + }; 720DD6CF1358FD790064AA82 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 72220EAD1333047D00FCA411 /* libcups2 */; @@ -11567,6 +11717,54 @@ }; name = Release; }; + 27C3E9592DB04AC500A6ABBF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "-"; + DEAD_CODE_STRIPPING = YES; + GCC_C_LANGUAGE_STANDARD = c99; + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 27C3E95A2DB04AC500A6ABBF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "-"; + DEAD_CODE_STRIPPING = YES; + GCC_C_LANGUAGE_STANDARD = c99; + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 27C3E9652DB04ACE00A6ABBF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "-"; + DEAD_CODE_STRIPPING = YES; + GCC_C_LANGUAGE_STANDARD = c99; + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 27C3E9662DB04ACE00A6ABBF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "-"; + DEAD_CODE_STRIPPING = YES; + GCC_C_LANGUAGE_STANDARD = c99; + INSTALL_PATH = /usr/bin; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; 720DD6C91358FD5F0064AA82 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -13270,6 +13468,24 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 27C3E9582DB04AC500A6ABBF /* Build configuration list for PBXNativeTarget "cups-x509" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 27C3E9592DB04AC500A6ABBF /* Debug */, + 27C3E95A2DB04AC500A6ABBF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 27C3E9642DB04ACE00A6ABBF /* Build configuration list for PBXNativeTarget "cups-oauth" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 27C3E9652DB04ACE00A6ABBF /* Debug */, + 27C3E9662DB04ACE00A6ABBF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 720DD6CB1358FD600064AA82 /* Build configuration list for PBXNativeTarget "snmp" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/xcode/cups-oauth.c b/xcode/cups-oauth.c new file mode 100644 index 0000000000..aa128f08ef --- /dev/null +++ b/xcode/cups-oauth.c @@ -0,0 +1,546 @@ +// +// OAuth utility for CUPS. +// +// Copyright © 2024-2025 by OpenPrinting. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// +// Usage: cups-oauth [OPTIONS] [COMMAND [ARGUMENT(S)]] +// +// Commands: +// +// authorize [RESOURCE] +// clear [RESOURCE] +// get-access-token [RESOURCE] +// get-client-id +// get-metadata [NAME] +// get-refresh-token [RESOURCE] +// get-user-id [RESOURCE] [NAME] +// set-access-token [RESOURCE] TOKEN +// set-client-data CLIENT-ID CLIENT-SECRET +// +// Options: +// +// --help +// --version +// -a OAUTH-URI +// -s SCOPE(S) +// + +#include +#include + + +// +// Macro for localized text... +// + +# define _(x) x + + +// +// Local functions... +// + +static int do_authorize(const char *oauth_uri, const char *scopes, const char *resource_uri); +static int do_clear(const char *oauth_uri, const char *resource_uri); +static int do_get_access_token(const char *oauth_uri, const char *resource_uri); +static int do_get_client_id(const char *oauth_uri); +static int do_get_metadata(const char *oauth_uri, const char *name); +static int do_get_user_id(const char *oauth_uri, const char *resource_uri, const char *name); +static int do_set_access_token(const char *oauth_uri, const char *resource_uri, const char *token); +static int do_set_client_data(const char *oauth_uri, const char *client_id, const char *client_secret); +static int usage(FILE *out); + + +// +// 'main()' - Main entry. +// + +int // O - Exit status +main(int argc, // I - Number of command-line arguments + char *argv[]) // I - Command-line arguments +{ + int i; // Looping var + const char *opt, // Current option + *oauth_uri = getenv("CUPS_OAUTH_URI"), + // OAuth authorization server URI + *scopes = getenv("CUPS_OAUTH_SCOPES"); + // Scopes + + + // Parse the command-line... + for (i = 1; i < argc; i ++) + { + if (!strcmp(argv[i], "--help")) + { + return (usage(stdout)); + } + else if (!strcmp(argv[i], "--version")) + { + puts(CUPS_SVERSION); + exit(0); + } + else if (!strncmp(argv[i], "--", 2)) + { + _cupsLangPrintf(stderr, _("%s: Unknown option '%s'."), "cups-oauth", argv[i]); + return (usage(stderr)); + } + else if (argv[i][0] == '-' && argv[i][1] != '-') + { + for (opt = argv[i] + 1; *opt; opt ++) + { + switch (*opt) + { + case 'a' : // -a AUTH-URI + i ++; + if (i >= argc) + { + _cupsLangPuts(stderr, _("cups-oauth: Missing Authorization Server URI after '-a'.")); + return (usage(stderr)); + } + + oauth_uri = argv[i]; + break; + + case 's' : // -s SCOPE(S) + i ++; + if (i >= argc) + { + _cupsLangPuts(stderr, _("cups-oauth: Missing scope(s) after '-s'.")); + return (usage(stderr)); + } + + scopes = argv[i]; + break; + + default : + _cupsLangPrintf(stderr, _("%s: Unknown option '-%c'."), "cups-oauth", *opt); + return (usage(stderr)); + } + } + } + else if (!oauth_uri) + { + _cupsLangPuts(stderr, _("cups-oauth: No authorization server specified.")); + return (usage(stderr)); + } + else if (!strcmp(argv[i], "authorize")) + { + // authorize [RESOURCE] + i ++; + return (do_authorize(oauth_uri, scopes, argv[i])); + } + else if (!strcmp(argv[i], "clear")) + { + // clear [RESOURCE] + i ++; + return (do_clear(oauth_uri, argv[i])); + } + else if (!strcmp(argv[i], "get-access-token")) + { + // get-access-token [RESOURCE] + i ++; + return (do_get_access_token(oauth_uri, argv[i])); + } + else if (!strcmp(argv[i], "get-client-id")) + { + // get-client-id + i ++; + return (do_get_client_id(oauth_uri)); + } + else if (!strcmp(argv[i], "get-metadata")) + { + // get-metadata [NAME] + i ++; + return (do_get_metadata(oauth_uri, argv[i])); + } + else if (!strcmp(argv[i], "get-user-id")) + { + // get-user-id [RESOURCE] [NAME] + i ++; + if (i < argc) + { + if (!strncmp(argv[i], "ipp://", 6) || !strncmp(argv[i], "ipps://", 7) || !strncmp(argv[i], "http://", 7) || !strncmp(argv[i], "https://", 8)) + return (do_get_user_id(oauth_uri, argv[i], argv[i + 1])); + else + return (do_get_user_id(oauth_uri, /*resource_uri*/NULL, argv[i])); + } + else + { + return (do_get_user_id(oauth_uri, /*resource_uri*/NULL, /*name*/NULL)); + } + } + else if (!strcmp(argv[i], "set-access-token")) + { + // set-access-token [RESOURCE] TOKEN + i ++; + if (i >= argc) + { + _cupsLangPuts(stderr, _("cups-oauth: Missing resource URI and/or access token.")); + return (usage(stderr)); + } + + return (do_set_access_token(oauth_uri, argv[i], argv[i + 1])); + } + else if (!strcmp(argv[i], "set-client-data")) + { + // set-client-data CLIENT-ID CLIENT-DATA + i ++; + if ((i + 1) >= argc) + { + _cupsLangPuts(stderr, _("cups-oauth: Missing client_id and/or client_secret.")); + return (usage(stderr)); + } + + return (do_set_client_data(oauth_uri, argv[i], argv[i + 1])); + } + else + { + _cupsLangPrintf(stderr, _("cups-oauth: Unknown command '%s'."), argv[i]); + return (usage(stderr)); + } + } + + // If we get this far, show usage... + return (usage(argc == 1 ? stdout : stderr)); +} + + +// +// 'do_authorize()' - Authorize access. +// + +static int // O - Exit status +do_authorize(const char *oauth_uri, // I - Authorization Server URI + const char *scopes, // I - Scope(s) + const char *resource_uri) // I - Resource URI +{ + int status = 1; // Exit status + cups_json_t *metadata; // Server metadata + char *auth_code = NULL, // Authorization code + *access_token = NULL; // Access token + time_t access_expires; // Expiration date + + + // Get the server metadata... + if ((metadata = cupsOAuthGetMetadata(oauth_uri)) == NULL) + { + _cupsLangPrintf(stderr, _("cups-oauth: Unable to get metadata for '%s': %s"), oauth_uri, cupsGetErrorString()); + return (1); + } + + // Authorize... + if ((auth_code = cupsOAuthGetAuthorizationCode(oauth_uri, metadata, resource_uri, scopes, /*redirect_uri*/NULL)) == NULL) + { + _cupsLangPrintf(stderr, _("cups-oauth: Unable to get authorization from '%s': %s"), oauth_uri, cupsGetErrorString()); + goto done; + } + + // Get the access token... + if ((access_token = cupsOAuthGetTokens(oauth_uri, metadata, resource_uri, auth_code, CUPS_OGRANT_AUTHORIZATION_CODE, CUPS_OAUTH_REDIRECT_URI, &access_expires)) == NULL) + { + _cupsLangPrintf(stderr, _("cups-oauth: Unable to get access token from '%s': %s"), oauth_uri, cupsGetErrorString()); + goto done; + } + + // Show access token + puts(access_token); + + status = 0; + + // Clean up and return... + done: + + cupsJSONDelete(metadata); + free(auth_code); + free(access_token); + + return (status); +} + + +// +// 'do_clear()' - Clear authorization information. +// + +static int // O - Exit status +do_clear(const char *oauth_uri, // I - Authorization Server URI + const char *resource_uri) // I - Resource URI +{ + cupsOAuthClearTokens(oauth_uri, resource_uri); + + return (0); +} + + +// +// 'do_get_access_token()' - Get an access token. +// + +static int // O - Exit status +do_get_access_token( + const char *oauth_uri, // I - Authorization Server URI + const char *resource_uri) // I - Resource URI +{ + char *access_token; // Access token + time_t access_expires; // Expiration date + + + if ((access_token = cupsOAuthCopyAccessToken(oauth_uri, resource_uri, &access_expires)) != NULL) + { + puts(access_token); + free(access_token); + return (0); + } + + return (1); +} + + +// +// 'do_get_client_id()' - Get the client ID value. +// + +static int // O - Exit status +do_get_client_id( + const char *oauth_uri) // I - Authorization Server URI +{ + char *client_id; // Client ID + + + if ((client_id = cupsOAuthCopyClientId(oauth_uri, CUPS_OAUTH_REDIRECT_URI)) != NULL) + { + puts(client_id); + free(client_id); + return (0); + } + + return (1); +} + + +// +// 'do_get_metadata()' - Get authorization server metadata. +// + +static int // O - Exit status +do_get_metadata(const char *oauth_uri, // I - Authorization Server URI + const char *name) // I - Field name +{ + cups_json_t *metadata; // Metadata + char *json; // JSON string + + + // Get the metadata... + if ((metadata = cupsOAuthGetMetadata(oauth_uri)) == NULL) + { + _cupsLangPrintf(stderr, _("cups-oauth: Unable to get metadata for '%s': %s"), oauth_uri, cupsGetErrorString()); + return (1); + } + + // Show metadata... + if (name) + { + cups_json_t *value = cupsJSONFind(metadata, name); + // Metadata value + + if (value) + { + switch (cupsJSONGetType(value)) + { + case CUPS_JTYPE_NULL : + puts("null"); + break; + + case CUPS_JTYPE_FALSE : + puts("false"); + break; + + case CUPS_JTYPE_TRUE : + puts("true"); + break; + + case CUPS_JTYPE_NUMBER : + printf("%g\n", cupsJSONGetNumber(value)); + break; + + case CUPS_JTYPE_STRING : + puts(cupsJSONGetString(value)); + break; + + default : + if ((json = cupsJSONExportString(value)) != NULL) + { + puts(json); + free(json); + } + break; + } + + return (0); + } + else + { + return (1); + } + } + else if ((json = cupsJSONExportString(metadata)) != NULL) + { + puts(json); + free(json); + } + + return (0); +} + + +// +// 'do_get_user_id()' - Get user identification. +// + +static int // O - Exit status +do_get_user_id( + const char *oauth_uri, // I - Authorization Server URI + const char *resource_uri, // I - Resource URI + const char *name) // I - Claim name +{ + cups_jwt_t *user_id; // User ID information + cups_json_t *claims; // Claims + char *json, // JSON string + date[256]; // Date + int ret = 0; // Exit status + + + // Get the user_id... + if ((user_id = cupsOAuthCopyUserId(oauth_uri, resource_uri)) == NULL) + { + _cupsLangPrintf(stderr, _("cups-oauth: Unable to get user ID for '%s': %s"), oauth_uri, cupsGetErrorString()); + return (1); + } + + claims = cupsJWTGetClaims(user_id); + + // Show user information... + if (name) + { + cups_json_t *value = cupsJSONFind(claims, name); + // Claim value + + if (value) + { + switch (cupsJSONGetType(value)) + { + case CUPS_JTYPE_NULL : + puts("null"); + break; + + case CUPS_JTYPE_FALSE : + puts("false"); + break; + + case CUPS_JTYPE_TRUE : + puts("true"); + break; + + case CUPS_JTYPE_NUMBER : + if (!strcmp(name, "exp") || !strcmp(name, "iat") || !strcmp(name, "nbf")) + puts(httpGetDateString2((time_t)cupsJSONGetNumber(value), date, sizeof(date))); + else + printf("%g\n", cupsJSONGetNumber(value)); + break; + + case CUPS_JTYPE_STRING : + puts(cupsJSONGetString(value)); + break; + + default : + if ((json = cupsJSONExportString(value)) != NULL) + { + puts(json); + free(json); + } + break; + } + } + else + { + ret = 1; + } + } + else if ((json = cupsJSONExportString(claims)) != NULL) + { + puts(json); + free(json); + } + + cupsJWTDelete(user_id); + + return (ret); +} + + +// +// 'do_set_access_token()' - Set the access token. +// + +static int // O - Exit status +do_set_access_token( + const char *oauth_uri, // I - Authorization Server URI + const char *resource_uri, // I - Resource URI + const char *token) // I - Access token +{ + cupsOAuthSaveTokens(oauth_uri, resource_uri, token, /*access_expires*/time(NULL) + 365 * 86400, /*user_id*/NULL, /*refresh_token*/NULL); + + return (0); +} + + +// +// 'do_set_client_data()' - Save client_id and client_secret values. +// + +static int // O - Exit status +do_set_client_data( + const char *oauth_uri, // I - Authorization Server URI + const char *client_id, // I - Client ID + const char *client_secret) // I - Client secret +{ + cupsOAuthSaveClientData(oauth_uri, CUPS_OAUTH_REDIRECT_URI, client_id, client_secret); + + return (0); +} + + +// +// 'usage()' - Show usage. +// + +static int // O - Exit status +usage(FILE *out) // I - Output file +{ + _cupsLangPuts(out, _("Usage: cups-oauth [OPTIONS] [COMMAND [ARGUMENT(S)]]")); + _cupsLangPuts(out, ""); + _cupsLangPuts(out, _("Commands:")); + _cupsLangPuts(out, ""); + _cupsLangPuts(out, _("authorize [RESOURCE] Authorize access to a resource")); + _cupsLangPuts(out, _("clear [RESOURCE] Clear the authorization for a resource")); + _cupsLangPuts(out, _("get-access-token [RESOURCE] Get the current access token")); + _cupsLangPuts(out, _("get-client-id Get the client ID for the authorization server")); + _cupsLangPuts(out, _("get-metadata [NAME] Get metadata from the authorization server")); + _cupsLangPuts(out, _("get-user-id [RESOURCE] [NAME] Get the authorized user ID")); + _cupsLangPuts(out, _("set-access-token [RESOURCE] TOKEN\n" + " Set the current access token")); + _cupsLangPuts(out, _("set-client-data CLIENT-ID CLIENT-SECRET\n" + " Set the client ID and secret for the authorization server.")); + _cupsLangPuts(out, ""); + _cupsLangPuts(out, _("Options:")); + _cupsLangPuts(out, ""); + _cupsLangPuts(out, _("--help Show this help")); + _cupsLangPuts(out, _("--version Show the program version")); + _cupsLangPuts(out, _("-a OAUTH-URI Specify the OAuth authorization server URL")); + _cupsLangPuts(out, _("-s SCOPE(S) Specify the scope(s) to authorize")); + + return (out == stdout ? 0 : 1); +}